Fix memory corruption due to race condition in IPMI IRQ handler

This resolves a BMC crash in late IPL (skiboot / initial kernel load)
exclusively observed on Talos II systems.
parent e5e91b09
......@@ -792,6 +792,11 @@ void lpc_slave_isr(void)
}
write_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_IPMI_BT_STATUS, dword);
// Disable IPMI BT IRQ
dword = read_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_CONTROL1);
dword &= ~((1 & AQUILA_LPC_CTL_EN_IPMI_BT_IRQ_MASK) << AQUILA_LPC_CTL_EN_IPMI_BT_IRQ_SHIFT);
write_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_CONTROL1, dword);
// Clear H2B_ATN
dword = 0;
dword |= (1 << IPMI_BT_CTL_H2B_ATN_SHIFT);
......@@ -1231,7 +1236,7 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
uint32_t dword;
static uint8_t unhandled_ipmi_command;
volatile ipmi_response_message_t *response_ptr;
ipmi_response_message_t *response_ptr;
static ipmi_response_message_t response;
static uint8_t request_netfn;
static uint8_t request_lun;
......@@ -1242,6 +1247,15 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
int i;
int irqs_locked = 0;
int key = -1;
if (ipmi_bt_transaction_state != 0) {
// Deactivate interrupts on entering critical section
key = irq_lock();
irqs_locked = 1;
}
#if (WITH_ZEPHYR)
if (ipmi_bt_transaction_state != 0) {
// Temporarily raise service thread priority
......@@ -1565,8 +1579,11 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
}
#if (ENABLE_LPC_FW_CYCLE_DMA)
if (!irqs_locked)
{
// Deactivate interrupts on entering critical section
int key = irq_lock();
key = irq_lock();
}
// Disable DMA engine
dword = read_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_DMA_CONFIG1);
......@@ -1631,8 +1648,11 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
}
write_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_DMA_CONFIG1, dword);
if (!irqs_locked)
{
// Re-activate interupts on exiting critical section
irq_unlock(key);
}
#endif
// Generate response
......@@ -1786,7 +1806,7 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
// Send response
// A full copy is done so as to ensure any potentially sensitive data stored
// in the IPMI BT buffer from a previous request is overwritten
*response_ptr = response;
memcpy(response_ptr, &response, sizeof(ipmi_response_message_t));
// Signal BMC data ready
dword = 0;
......@@ -1804,6 +1824,12 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
if (ENABLE_IPMI_DEBUG) {
printk("[IPMI] Response complete, returning to idle\n");
}
// (Re)enable IPMI BT IRQ
dword = read_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_CONTROL1);
dword |= ((1 & AQUILA_LPC_CTL_EN_IPMI_BT_IRQ_MASK) << AQUILA_LPC_CTL_EN_IPMI_BT_IRQ_SHIFT);
write_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_CONTROL1, dword);
ipmi_bt_transaction_state = 0;
}
break;
......@@ -1812,6 +1838,13 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
break;
}
if (irqs_locked)
{
// Re-activate interupts on exiting critical section
irq_unlock(key);
irqs_locked = 0;
}
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment