From 95c97b5941542a4dedb22649adea98e25a88923e Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 20 Nov 2014 07:19:44 -0600 Subject: ipmi: Check the BT interrupt enable periodically On a reset, the BMC may reset the BT enable in the processor registers (different than the global enables in the BMC). Check it periodically and fix it if necessary. Signed-off-by: Corey Minyard Tested-by: Tony Rex Tested-by: Magnus Johansson E --- drivers/char/ipmi/ipmi_si_intf.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'drivers/char') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4a894afc5a2e..90c7fdf95419 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -536,7 +536,8 @@ static void handle_flags(struct smi_info *smi_info) #define GLOBAL_ENABLES_MASK (IPMI_BMC_EVT_MSG_BUFF | IPMI_BMC_RCV_MSG_INTR | \ IPMI_BMC_EVT_MSG_INTR) -static u8 current_global_enables(struct smi_info *smi_info, u8 base) +static u8 current_global_enables(struct smi_info *smi_info, u8 base, + bool *irq_on) { u8 enables = 0; @@ -557,9 +558,27 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base) else enables &= ~IPMI_BMC_EVT_MSG_INTR; + *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR); + return enables; } +static void check_bt_irq(struct smi_info *smi_info, bool irq_on) +{ + u8 irqstate = smi_info->io.inputb(&smi_info->io, IPMI_BT_INTMASK_REG); + + irqstate &= IPMI_BT_INTMASK_ENABLE_IRQ_BIT; + + if ((bool)irqstate == irq_on) + return; + + if (irq_on) + smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, + IPMI_BT_INTMASK_ENABLE_IRQ_BIT); + else + smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG, 0); +} + static void handle_transaction_done(struct smi_info *smi_info) { struct ipmi_smi_msg *msg; @@ -708,6 +727,7 @@ static void handle_transaction_done(struct smi_info *smi_info) { unsigned char msg[4]; u8 enables; + bool irq_on; /* We got the flags from the SMI, now handle them. */ smi_info->handlers->get_result(smi_info->si_sm, msg, 4); @@ -719,7 +739,10 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->si_state = SI_NORMAL; break; } - enables = current_global_enables(smi_info, 0); + enables = current_global_enables(smi_info, 0, &irq_on); + if (smi_info->si_type == SI_BT) + /* BT has its own interrupt enable bit. */ + check_bt_irq(smi_info, irq_on); if (enables != (msg[3] & GLOBAL_ENABLES_MASK)) { /* Enables are not correct, fix them. */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); -- cgit v1.2.2