Skip to content

Commit

Permalink
Merge tag 'for-linus-4.0-1' of git://git.code.sf.net/p/openipmi/linux…
Browse files Browse the repository at this point in the history
…-ipmi

Pull late ipmi fixes from Corey Minyard:
 "Some annoying issues in the IPMI driver that would be good to have
  fixed before 4.0 is released.

  These got reported or discovered late, but they will avoid some
  situations that would cause lots of log spam and in one case a
  deadlock"

* tag 'for-linus-4.0-1' of git://git.code.sf.net/p/openipmi/linux-ipmi:
  ipmi_ssif: Use interruptible completion for waiting in the thread
  ipmi/powernv: Fix minor locking bug
  ipmi: Handle BMCs that don't allow clearing the rcv irq bit
  • Loading branch information
torvalds committed Apr 11, 2015
2 parents 3259b12 + d0acf73 commit 545124e
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 10 deletions.
1 change: 1 addition & 0 deletions drivers/char/ipmi/ipmi_powernv.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi)
spin_lock_irqsave(&smi->msg_lock, flags);

if (!smi->cur_msg) {
spin_unlock_irqrestore(&smi->msg_lock, flags);
pr_warn("no current message?\n");
return 0;
}
Expand Down
109 changes: 102 additions & 7 deletions drivers/char/ipmi/ipmi_si_intf.c
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ struct smi_info {
*/
bool supports_event_msg_buff;

/*
* Can we clear the global enables receive irq bit?
*/
bool cannot_clear_recv_irq_bit;

/*
* Did we get an attention that we did not handle?
*/
Expand Down Expand Up @@ -461,6 +466,9 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
* allocate messages, we just leave them in the BMC and run the system
* polled until we can allocate some memory. Once we have some
* memory, we will re-enable the interrupt.
*
* Note that we cannot just use disable_irq(), since the interrupt may
* be shared.
*/
static inline bool disable_si_irq(struct smi_info *smi_info)
{
Expand Down Expand Up @@ -549,20 +557,15 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base,

if (smi_info->supports_event_msg_buff)
enables |= IPMI_BMC_EVT_MSG_BUFF;
else
enables &= ~IPMI_BMC_EVT_MSG_BUFF;

if (smi_info->irq && !smi_info->interrupt_disabled)
if ((smi_info->irq && !smi_info->interrupt_disabled) ||
smi_info->cannot_clear_recv_irq_bit)
enables |= IPMI_BMC_RCV_MSG_INTR;
else
enables &= ~IPMI_BMC_RCV_MSG_INTR;

if (smi_info->supports_event_msg_buff &&
smi_info->irq && !smi_info->interrupt_disabled)

enables |= IPMI_BMC_EVT_MSG_INTR;
else
enables &= ~IPMI_BMC_EVT_MSG_INTR;

*irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR);

Expand Down Expand Up @@ -2900,6 +2903,96 @@ static int try_get_dev_id(struct smi_info *smi_info)
return rv;
}

/*
* Some BMCs do not support clearing the receive irq bit in the global
* enables (even if they don't support interrupts on the BMC). Check
* for this and handle it properly.
*/
static void check_clr_rcv_irq(struct smi_info *smi_info)
{
unsigned char msg[3];
unsigned char *resp;
unsigned long resp_len;
int rv;

resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
if (!resp) {
printk(KERN_WARNING PFX "Out of memory allocating response for"
" global enables command, cannot check recv irq bit"
" handling.\n");
return;
}

msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);

rv = wait_for_msg_done(smi_info);
if (rv) {
printk(KERN_WARNING PFX "Error getting response from get"
" global enables command, cannot check recv irq bit"
" handling.\n");
goto out;
}

resp_len = smi_info->handlers->get_result(smi_info->si_sm,
resp, IPMI_MAX_MSG_LENGTH);

if (resp_len < 4 ||
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD ||
resp[2] != 0) {
printk(KERN_WARNING PFX "Invalid return from get global"
" enables command, cannot check recv irq bit"
" handling.\n");
rv = -EINVAL;
goto out;
}

if ((resp[3] & IPMI_BMC_RCV_MSG_INTR) == 0)
/* Already clear, should work ok. */
goto out;

msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
msg[2] = resp[3] & ~IPMI_BMC_RCV_MSG_INTR;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);

rv = wait_for_msg_done(smi_info);
if (rv) {
printk(KERN_WARNING PFX "Error getting response from set"
" global enables command, cannot check recv irq bit"
" handling.\n");
goto out;
}

resp_len = smi_info->handlers->get_result(smi_info->si_sm,
resp, IPMI_MAX_MSG_LENGTH);

if (resp_len < 3 ||
resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
printk(KERN_WARNING PFX "Invalid return from get global"
" enables command, cannot check recv irq bit"
" handling.\n");
rv = -EINVAL;
goto out;
}

if (resp[2] != 0) {
/*
* An error when setting the event buffer bit means
* clearing the bit is not supported.
*/
printk(KERN_WARNING PFX "The BMC does not support clearing"
" the recv irq bit, compensating, but the BMC needs to"
" be fixed.\n");
smi_info->cannot_clear_recv_irq_bit = true;
}
out:
kfree(resp);
}

static int try_enable_event_buffer(struct smi_info *smi_info)
{
unsigned char msg[3];
Expand Down Expand Up @@ -3395,6 +3488,8 @@ static int try_smi_init(struct smi_info *new_smi)
goto out_err;
}

check_clr_rcv_irq(new_smi);

setup_oem_data_handler(new_smi);
setup_xaction_handlers(new_smi);

Expand Down
8 changes: 5 additions & 3 deletions drivers/char/ipmi/ipmi_ssif.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,11 +468,13 @@ static int ipmi_ssif_thread(void *data)
int result;

/* Wait for something to do */
wait_for_completion(&ssif_info->wake_thread);
init_completion(&ssif_info->wake_thread);

result = wait_for_completion_interruptible(
&ssif_info->wake_thread);
if (ssif_info->stopping)
break;
if (result == -ERESTARTSYS)
continue;
init_completion(&ssif_info->wake_thread);

if (ssif_info->i2c_read_write == I2C_SMBUS_WRITE) {
result = i2c_smbus_write_block_data(
Expand Down

0 comments on commit 545124e

Please sign in to comment.