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

Commit 968bf7cc authored by Corey Minyard's avatar Corey Minyard
Browse files

ipmi: Fix handling of BMC flags



The handling of BMC flags wasn't quite right in a few places, mainly
around enabling and disabling interrupts in the BMC.  Clean up the
code and fix the handling of the flags.

Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent 3d9e5df5
Loading
Loading
Loading
Loading
+68 −37
Original line number Original line Diff line number Diff line
@@ -328,7 +328,10 @@ static void deliver_recv_msg(struct smi_info *smi_info,
			     struct ipmi_smi_msg *msg)
			     struct ipmi_smi_msg *msg)
{
{
	/* Deliver the message to the upper layer. */
	/* Deliver the message to the upper layer. */
	if (smi_info->intf)
		ipmi_smi_msg_received(smi_info->intf, msg);
		ipmi_smi_msg_received(smi_info->intf, msg);
	else
		ipmi_free_smi_msg(msg);
}
}


static void return_hosed_msg(struct smi_info *smi_info, int cCode)
static void return_hosed_msg(struct smi_info *smi_info, int cCode)
@@ -436,6 +439,32 @@ static void start_clear_flags(struct smi_info *smi_info)
	smi_info->si_state = SI_CLEARING_FLAGS;
	smi_info->si_state = SI_CLEARING_FLAGS;
}
}


static void start_getting_msg_queue(struct smi_info *smi_info)
{
	smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
	smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
	smi_info->curr_msg->data_size = 2;

	smi_info->handlers->start_transaction(
		smi_info->si_sm,
		smi_info->curr_msg->data,
		smi_info->curr_msg->data_size);
	smi_info->si_state = SI_GETTING_MESSAGES;
}

static void start_getting_events(struct smi_info *smi_info)
{
	smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
	smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
	smi_info->curr_msg->data_size = 2;

	smi_info->handlers->start_transaction(
		smi_info->si_sm,
		smi_info->curr_msg->data,
		smi_info->curr_msg->data_size);
	smi_info->si_state = SI_GETTING_EVENTS;
}

static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
{
{
	smi_info->last_timeout_jiffies = jiffies;
	smi_info->last_timeout_jiffies = jiffies;
@@ -449,22 +478,45 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
 * polled until we can allocate some memory.  Once we have some
 * polled until we can allocate some memory.  Once we have some
 * memory, we will re-enable the interrupt.
 * memory, we will re-enable the interrupt.
 */
 */
static inline void disable_si_irq(struct smi_info *smi_info)
static inline bool disable_si_irq(struct smi_info *smi_info)
{
{
	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
		start_disable_irq(smi_info);
		start_disable_irq(smi_info);
		smi_info->interrupt_disabled = true;
		smi_info->interrupt_disabled = true;
		if (!atomic_read(&smi_info->stop_operation))
		return true;
			smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
	}
	}
	return false;
}
}


static inline void enable_si_irq(struct smi_info *smi_info)
static inline bool enable_si_irq(struct smi_info *smi_info)
{
{
	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
		start_enable_irq(smi_info);
		start_enable_irq(smi_info);
		smi_info->interrupt_disabled = false;
		smi_info->interrupt_disabled = false;
		return true;
	}
	return false;
}

/*
 * Allocate a message.  If unable to allocate, start the interrupt
 * disable process and return NULL.  If able to allocate but
 * interrupts are disabled, free the message and return NULL after
 * starting the interrupt enable process.
 */
static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
{
	struct ipmi_smi_msg *msg;

	msg = ipmi_alloc_smi_msg();
	if (!msg) {
		if (!disable_si_irq(smi_info))
			smi_info->si_state = SI_NORMAL;
	} else if (enable_si_irq(smi_info)) {
		ipmi_free_smi_msg(msg);
		msg = NULL;
	}
	}
	return msg;
}
}


static void handle_flags(struct smi_info *smi_info)
static void handle_flags(struct smi_info *smi_info)
@@ -476,45 +528,22 @@ static void handle_flags(struct smi_info *smi_info)


		start_clear_flags(smi_info);
		start_clear_flags(smi_info);
		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
		if (smi_info->intf)
			ipmi_smi_watchdog_pretimeout(smi_info->intf);
			ipmi_smi_watchdog_pretimeout(smi_info->intf);
	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
		/* Messages available. */
		/* Messages available. */
		smi_info->curr_msg = ipmi_alloc_smi_msg();
		smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
		if (!smi_info->curr_msg) {
		if (!smi_info->curr_msg)
			disable_si_irq(smi_info);
			smi_info->si_state = SI_NORMAL;
			return;
			return;
		}
		enable_si_irq(smi_info);

		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
		smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
		smi_info->curr_msg->data_size = 2;


		smi_info->handlers->start_transaction(
		start_getting_msg_queue(smi_info);
			smi_info->si_sm,
			smi_info->curr_msg->data,
			smi_info->curr_msg->data_size);
		smi_info->si_state = SI_GETTING_MESSAGES;
	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
		/* Events available. */
		/* Events available. */
		smi_info->curr_msg = ipmi_alloc_smi_msg();
		smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
		if (!smi_info->curr_msg) {
		if (!smi_info->curr_msg)
			disable_si_irq(smi_info);
			smi_info->si_state = SI_NORMAL;
			return;
			return;
		}
		enable_si_irq(smi_info);

		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
		smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
		smi_info->curr_msg->data_size = 2;


		smi_info->handlers->start_transaction(
		start_getting_events(smi_info);
			smi_info->si_sm,
			smi_info->curr_msg->data,
			smi_info->curr_msg->data_size);
		smi_info->si_state = SI_GETTING_EVENTS;
	} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
	} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
		   smi_info->oem_data_avail_handler) {
		   smi_info->oem_data_avail_handler) {
		if (smi_info->oem_data_avail_handler(smi_info))
		if (smi_info->oem_data_avail_handler(smi_info))
@@ -709,7 +738,9 @@ static void handle_transaction_done(struct smi_info *smi_info)
				 "Maybe ok, but ipmi might run very slowly.\n");
				 "Maybe ok, but ipmi might run very slowly.\n");
		} else
		} else
			smi_info->interrupt_disabled = false;
			smi_info->interrupt_disabled = false;
		smi_info->si_state = SI_NORMAL;

		/* We enabled interrupts, flags may be pending. */
		handle_flags(smi_info);
		break;
		break;
	}
	}