[Skiboot] [PATCH 7/9] astbmc/ipmi: Improve Set Enables handling
Nicholas Piggin
npiggin at gmail.com
Mon Mar 31 23:46:33 AEDT 2025
The IPMI Set Enables command is supposed to do a read-modify-write
operation to change bits if it is not coded specifically for the
system. Since the various BMCs supported by astbmc platform code
(e.g., QEMU and OpenBMC) are a bit different and subject to change,
it's safer to set bits with RMW.
Then bits should be set one by one to help isolate failures. And
the Set Enables command is changed to run synchronously so that
host/BMC behaviour is a bit more deterministic when setting up IPMI.
Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
include/ipmi.h | 1 +
platforms/astbmc/common.c | 73 +++++++++++++++++++++++++++++++--------
2 files changed, 59 insertions(+), 15 deletions(-)
diff --git a/include/ipmi.h b/include/ipmi.h
index d751e7a1f..ff97a4174 100644
--- a/include/ipmi.h
+++ b/include/ipmi.h
@@ -122,6 +122,7 @@
#define IPMI_ERR_MSG_TRUNCATED 0xc6
#define IPMI_REQ_LEN_INVALID_ERR 0xc7
#define IPMI_REQ_LEN_EXCEEDED_ERR 0xc8
+#define IPMI_INVALID_DATA_FIELD 0xcc
#define IPMI_NOT_IN_MY_STATE_ERR 0xd5 /* IPMI 2.0 */
#define IPMI_LOST_ARBITRATION_ERR 0x81
#define IPMI_BUS_ERR 0x82
diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
index 5946058fe..fee94da97 100644
--- a/platforms/astbmc/common.c
+++ b/platforms/astbmc/common.c
@@ -42,25 +42,43 @@ void astbmc_ext_irq_serirq_cpld(unsigned int chip_id)
lpc_all_interrupts(chip_id);
}
-static void astbmc_ipmi_error(struct ipmi_msg *msg)
-{
- prlog(PR_DEBUG, "ASTBMC: error sending msg. cc = %02x\n", msg->cc);
-
- ipmi_free_msg(msg);
-}
-
#define SET_ENABLE_SEL 0x08
#define SET_ENABLE_MSGBUF 0x04
#define SET_ENABLE_RX_MQ_INT 0x01
-static void astbmc_ipmi_setenables(void)
+static bool astbmc_ipmi_enable_bits(uint8_t mask)
{
struct ipmi_msg *msg;
uint8_t data;
- data = SET_ENABLE_SEL | SET_ENABLE_MSGBUF | SET_ENABLE_RX_MQ_INT;
+ memset(&data, 0, sizeof(data));
+
+ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_GET_ENABLES,
+ NULL, NULL, NULL, 0, sizeof(data));
+ if (!msg) {
+ /**
+ * @fwts-label ASTBMCFailedSetEnables
+ * @fwts-advice AST BMC is likely to be non-functional
+ * when accessed from host.
+ */
+ prlog(PR_ERR, "ASTBMC: failed to get enables\n");
+ return false;
+ }
+ ipmi_queue_msg_sync(msg);
+ if (msg->cc != IPMI_CC_NO_ERROR) {
+ ipmi_free_msg(msg);
+ prlog(PR_ERR, "ASTBMC: failed to get enables cc=0x%02x\n", msg->cc);
+ return false;
+ }
+ memcpy(&data, msg->data, sizeof(data));
+ ipmi_free_msg(msg);
+
+ if ((data & mask) == mask)
+ return true; /* Already enabled */
- msg = ipmi_mkmsg_simple(IPMI_SET_ENABLES, &data, sizeof(data));
+ data |= mask;
+ msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, IPMI_SET_ENABLES,
+ NULL, NULL, &data, sizeof(data), 0);
if (!msg) {
/**
* @fwts-label ASTBMCFailedSetEnables
@@ -68,12 +86,37 @@ static void astbmc_ipmi_setenables(void)
* when accessed from host.
*/
prlog(PR_ERR, "ASTBMC: failed to set enables\n");
- return;
+ return false;
+ }
+ ipmi_queue_msg_sync(msg);
+ if (msg->cc != IPMI_CC_NO_ERROR) {
+ ipmi_free_msg(msg);
+ if (msg->cc == IPMI_INVALID_DATA_FIELD) {
+ prlog(PR_INFO, "ASTBMC: unsupported BMC global enable 0x%02x\n", mask);
+ } else {
+ prlog(PR_ERR, "ASTBMC: failed to set enables cc=0x%02x\n", msg->cc);
+ }
+ return false;
}
+ ipmi_free_msg(msg);
- msg->error = astbmc_ipmi_error;
+ return true;
+}
- ipmi_queue_msg(msg);
+static void astbmc_ipmi_setenables(void)
+{
+ /*
+ * OpenBMC's IPMI should have set ENABLE_SEL and RX_MQ_INT. It does
+ * not support MSGBUF, but there is no harm in trying to enable it.
+ * QEMU's ipmi_bmc_sim implementation does support MSGBUF, but it
+ * does not set RX_MQ_INT by default.
+ *
+ * Try to enable one-at-a-time because an implementation may reject
+ * SET_ENABLES if any bits are unsupported.
+ */
+ astbmc_ipmi_enable_bits(SET_ENABLE_RX_MQ_INT);
+ astbmc_ipmi_enable_bits(SET_ENABLE_MSGBUF);
+ astbmc_ipmi_enable_bits(SET_ENABLE_SEL);
}
static int astbmc_fru_init(void)
@@ -152,8 +195,8 @@ void astbmc_init(void)
/* As soon as IPMI is up, inform BMC we are in "S0" */
ipmi_set_power_state(IPMI_PWR_SYS_S0_WORKING, IPMI_PWR_NOCHANGE);
- /* Enable IPMI OEM message interrupts */
- astbmc_ipmi_setenables();
+ /* Enable IPMI OEM message interrupts */
+ astbmc_ipmi_setenables();
ipmi_set_fw_progress_sensor(IPMI_FW_MOTHERBOARD_INIT);
--
2.47.1
More information about the Skiboot
mailing list