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) ...@@ -792,6 +792,11 @@ void lpc_slave_isr(void)
} }
write_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_IPMI_BT_STATUS, dword); 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 // Clear H2B_ATN
dword = 0; dword = 0;
dword |= (1 << IPMI_BT_CTL_H2B_ATN_SHIFT); dword |= (1 << IPMI_BT_CTL_H2B_ATN_SHIFT);
...@@ -1231,7 +1236,7 @@ static int process_host_to_bmc_ipmi_bt_transactions(void) ...@@ -1231,7 +1236,7 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
uint32_t dword; uint32_t dword;
static uint8_t unhandled_ipmi_command; 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 ipmi_response_message_t response;
static uint8_t request_netfn; static uint8_t request_netfn;
static uint8_t request_lun; static uint8_t request_lun;
...@@ -1242,6 +1247,15 @@ static int process_host_to_bmc_ipmi_bt_transactions(void) ...@@ -1242,6 +1247,15 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
int i; 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 (WITH_ZEPHYR)
if (ipmi_bt_transaction_state != 0) { if (ipmi_bt_transaction_state != 0) {
// Temporarily raise service thread priority // Temporarily raise service thread priority
...@@ -1565,8 +1579,11 @@ static int process_host_to_bmc_ipmi_bt_transactions(void) ...@@ -1565,8 +1579,11 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
} }
#if (ENABLE_LPC_FW_CYCLE_DMA) #if (ENABLE_LPC_FW_CYCLE_DMA)
// Deactivate interrupts on entering critical section if (!irqs_locked)
int key = irq_lock(); {
// Deactivate interrupts on entering critical section
key = irq_lock();
}
// Disable DMA engine // Disable DMA engine
dword = read_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_DMA_CONFIG1); 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) ...@@ -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); write_aquila_register(HOSTLPCSLAVE_BASE, AQUILA_LPC_REG_DMA_CONFIG1, dword);
// Re-activate interupts on exiting critical section if (!irqs_locked)
irq_unlock(key); {
// Re-activate interupts on exiting critical section
irq_unlock(key);
}
#endif #endif
// Generate response // Generate response
...@@ -1786,7 +1806,7 @@ static int process_host_to_bmc_ipmi_bt_transactions(void) ...@@ -1786,7 +1806,7 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
// Send response // Send response
// A full copy is done so as to ensure any potentially sensitive data stored // 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 // 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 // Signal BMC data ready
dword = 0; dword = 0;
...@@ -1804,6 +1824,12 @@ static int process_host_to_bmc_ipmi_bt_transactions(void) ...@@ -1804,6 +1824,12 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
if (ENABLE_IPMI_DEBUG) { if (ENABLE_IPMI_DEBUG) {
printk("[IPMI] Response complete, returning to idle\n"); 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; ipmi_bt_transaction_state = 0;
} }
break; break;
...@@ -1812,6 +1838,13 @@ static int process_host_to_bmc_ipmi_bt_transactions(void) ...@@ -1812,6 +1838,13 @@ static int process_host_to_bmc_ipmi_bt_transactions(void)
break; break;
} }
if (irqs_locked)
{
// Re-activate interupts on exiting critical section
irq_unlock(key);
irqs_locked = 0;
}
return 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