Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bda4c30a authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds
Browse files

ipmi: run to completion fixes



The "run_to_completion" mode was somewhat broken.  Locks need to be avoided in
run_to_completion mode, and it shouldn't be used by normal users, just
internally for panic situations.

This patch removes locks in run_to_completion mode and removes the user call
for setting the mode.  The only user was the poweroff code, but it was easily
converted to use the polling interface.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 4ea18425
Loading
Loading
Loading
Loading
+0 −8
Original line number Original line Diff line number Diff line
@@ -1197,13 +1197,6 @@ int ipmi_unregister_for_cmd(ipmi_user_t user,
	return rv;
	return rv;
}
}


void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
{
	ipmi_smi_t intf = user->intf;
	if (intf->handlers)
		intf->handlers->set_run_to_completion(intf->send_info, val);
}

static unsigned char
static unsigned char
ipmb_checksum(unsigned char *data, int size)
ipmb_checksum(unsigned char *data, int size)
{
{
@@ -4190,5 +4183,4 @@ EXPORT_SYMBOL(ipmi_get_my_address);
EXPORT_SYMBOL(ipmi_set_my_LUN);
EXPORT_SYMBOL(ipmi_set_my_LUN);
EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_get_my_LUN);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
EXPORT_SYMBOL(ipmi_free_recv_msg);
EXPORT_SYMBOL(ipmi_free_recv_msg);
+16 −4
Original line number Original line Diff line number Diff line
@@ -99,11 +99,14 @@ static unsigned char ipmi_version;
   allocate them, since we may be in a panic situation.  The whole
   allocate them, since we may be in a panic situation.  The whole
   thing is single-threaded, anyway, so multiple messages are not
   thing is single-threaded, anyway, so multiple messages are not
   required. */
   required. */
static atomic_t dummy_count = ATOMIC_INIT(0);
static void dummy_smi_free(struct ipmi_smi_msg *msg)
static void dummy_smi_free(struct ipmi_smi_msg *msg)
{
{
	atomic_dec(&dummy_count);
}
}
static void dummy_recv_free(struct ipmi_recv_msg *msg)
static void dummy_recv_free(struct ipmi_recv_msg *msg)
{
{
	atomic_dec(&dummy_count);
}
}
static struct ipmi_smi_msg halt_smi_msg =
static struct ipmi_smi_msg halt_smi_msg =
{
{
@@ -152,17 +155,28 @@ static int ipmi_request_wait_for_response(ipmi_user_t user,
	return halt_recv_msg.msg.data[0];
	return halt_recv_msg.msg.data[0];
}
}


/* We are in run-to-completion mode, no completion is desired. */
/* Wait for message to complete, spinning. */
static int ipmi_request_in_rc_mode(ipmi_user_t            user,
static int ipmi_request_in_rc_mode(ipmi_user_t            user,
				   struct ipmi_addr       *addr,
				   struct ipmi_addr       *addr,
				   struct kernel_ipmi_msg *send_msg)
				   struct kernel_ipmi_msg *send_msg)
{
{
	int rv;
	int rv;


	atomic_set(&dummy_count, 2);
	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
	rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
				      &halt_smi_msg, &halt_recv_msg, 0);
				      &halt_smi_msg, &halt_recv_msg, 0);
	if (rv)
	if (rv) {
		atomic_set(&dummy_count, 0);
		return rv;
		return rv;
	}

	/*
	 * Spin until our message is done.
	 */
	while (atomic_read(&dummy_count) > 0) {
		ipmi_poll_interface(user);
		cpu_relax();
	}


	return halt_recv_msg.msg.data[0];
	return halt_recv_msg.msg.data[0];
}
}
@@ -531,9 +545,7 @@ static void ipmi_poweroff_function (void)
		return;
		return;


	/* Use run-to-completion mode, since interrupts may be off. */
	/* Use run-to-completion mode, since interrupts may be off. */
	ipmi_user_set_run_to_completion(ipmi_user, 1);
	specific_poweroff_func(ipmi_user);
	specific_poweroff_func(ipmi_user);
	ipmi_user_set_run_to_completion(ipmi_user, 0);
}
}


/* Wait for an IPMI interface to be installed, the first one installed
/* Wait for an IPMI interface to be installed, the first one installed
+19 −24
Original line number Original line Diff line number Diff line
@@ -806,56 +806,53 @@ static void sender(void *send_info,
		return;
		return;
	}
	}


	spin_lock_irqsave(&(smi_info->msg_lock), flags);
#ifdef DEBUG_TIMING
#ifdef DEBUG_TIMING
	do_gettimeofday(&t);
	do_gettimeofday(&t);
	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
#endif


	if (smi_info->run_to_completion) {
	if (smi_info->run_to_completion) {
		/* If we are running to completion, then throw it in
		/*
		   the list and run transactions until everything is
		 * If we are running to completion, then throw it in
		   clear.  Priority doesn't matter here. */
		 * the list and run transactions until everything is
		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
		 * clear.  Priority doesn't matter here.
		 */


		/* We have to release the msg lock and claim the smi
		/*
		   lock in this case, because of race conditions. */
		 * Run to completion means we are single-threaded, no
		spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
		 * need for locks.
		 */
		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));


		spin_lock_irqsave(&(smi_info->si_lock), flags);
		result = smi_event_handler(smi_info, 0);
		result = smi_event_handler(smi_info, 0);
		while (result != SI_SM_IDLE) {
		while (result != SI_SM_IDLE) {
			udelay(SI_SHORT_TIMEOUT_USEC);
			udelay(SI_SHORT_TIMEOUT_USEC);
			result = smi_event_handler(smi_info,
			result = smi_event_handler(smi_info,
						   SI_SHORT_TIMEOUT_USEC);
						   SI_SHORT_TIMEOUT_USEC);
		}
		}
		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
		return;
		return;
	} else {
		if (priority > 0) {
			list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));
		} else {
			list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
		}
	}
	}
	spin_unlock_irqrestore(&(smi_info->msg_lock), flags);


	spin_lock_irqsave(&(smi_info->si_lock), flags);
	spin_lock_irqsave(&smi_info->msg_lock, flags);
	if (priority > 0)
		list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
	else
		list_add_tail(&msg->link, &smi_info->xmit_msgs);
	spin_unlock_irqrestore(&smi_info->msg_lock, flags);

	spin_lock_irqsave(&smi_info->si_lock, flags);
	if ((smi_info->si_state == SI_NORMAL)
	if ((smi_info->si_state == SI_NORMAL)
	    && (smi_info->curr_msg == NULL))
	    && (smi_info->curr_msg == NULL))
	{
	{
		start_next_msg(smi_info);
		start_next_msg(smi_info);
	}
	}
	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
	spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
}


static void set_run_to_completion(void *send_info, int i_run_to_completion)
static void set_run_to_completion(void *send_info, int i_run_to_completion)
{
{
	struct smi_info   *smi_info = send_info;
	struct smi_info   *smi_info = send_info;
	enum si_sm_result result;
	enum si_sm_result result;
	unsigned long     flags;

	spin_lock_irqsave(&(smi_info->si_lock), flags);


	smi_info->run_to_completion = i_run_to_completion;
	smi_info->run_to_completion = i_run_to_completion;
	if (i_run_to_completion) {
	if (i_run_to_completion) {
@@ -866,8 +863,6 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion)
						   SI_SHORT_TIMEOUT_USEC);
						   SI_SHORT_TIMEOUT_USEC);
		}
		}
	}
	}

	spin_unlock_irqrestore(&(smi_info->si_lock), flags);
}
}


static int ipmi_thread(void *data)
static int ipmi_thread(void *data)
+2 −9
Original line number Original line Diff line number Diff line
@@ -368,9 +368,8 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
 * Poll the IPMI interface for the user.  This causes the IPMI code to
 * Poll the IPMI interface for the user.  This causes the IPMI code to
 * do an immediate check for information from the driver and handle
 * do an immediate check for information from the driver and handle
 * anything that is immediately pending.  This will not block in any
 * anything that is immediately pending.  This will not block in any
 * way.  This is useful if you need to implement polling from the user
 * way.  This is useful if you need to spin waiting for something to
 * for things like modifying the watchdog timeout when a panic occurs
 * happen in the IPMI driver.
 * or disabling the watchdog timer on a reboot.
 */
 */
void ipmi_poll_interface(ipmi_user_t user);
void ipmi_poll_interface(ipmi_user_t user);


@@ -421,12 +420,6 @@ int ipmi_unregister_for_cmd(ipmi_user_t user,
int ipmi_get_maintenance_mode(ipmi_user_t user);
int ipmi_get_maintenance_mode(ipmi_user_t user);
int ipmi_set_maintenance_mode(ipmi_user_t user, int mode);
int ipmi_set_maintenance_mode(ipmi_user_t user, int mode);


/*
 * Allow run-to-completion mode to be set for the interface of
 * a specific user.
 */
void ipmi_user_set_run_to_completion(ipmi_user_t user, int val);

/*
/*
 * When the user is created, it will not receive IPMI events by
 * When the user is created, it will not receive IPMI events by
 * default.  The user must set this to TRUE to get incoming events.
 * default.  The user must set this to TRUE to get incoming events.