On Mon, Mar 31, 2025 at 10:57:24PM +1000, Nicholas Piggin wrote: > Linux issues this command when booting a powernv machine.
This is good, just a couple of nits. > > Signed-off-by: Nicholas Piggin <npig...@gmail.com> > --- > include/hw/ipmi/ipmi.h | 14 +++++++++++ > hw/ipmi/ipmi_bmc_sim.c | 56 ++++++++++++++++++++++++++++++++++++++++-- > hw/ipmi/ipmi_bt.c | 2 ++ > hw/ipmi/ipmi_kcs.c | 1 + > 4 files changed, 71 insertions(+), 2 deletions(-) > > diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h > index 77a7213ed93..5f01a50cd86 100644 > --- a/include/hw/ipmi/ipmi.h > +++ b/include/hw/ipmi/ipmi.h > @@ -41,6 +41,15 @@ enum ipmi_op { > IPMI_SEND_NMI > }; > > +/* Channel properties */ > +#define IPMI_CHANNEL_IPMB 0x00 > +#define IPMI_CHANNEL_SYSTEM 0x0f > +#define IPMI_CH_MEDIUM_IPMB 0x01 > +#define IPMI_CH_MEDIUM_SYSTEM 0x0c > +#define IPMI_CH_PROTOCOL_IPMB 0x01 > +#define IPMI_CH_PROTOCOL_KCS 0x05 > +#define IPMI_CH_PROTOCOL_BT_15 0x08 I know it's picky, but could you spell out CHANNEL here? > + > #define IPMI_CC_INVALID_CMD 0xc1 > #define IPMI_CC_COMMAND_INVALID_FOR_LUN 0xc2 > #define IPMI_CC_TIMEOUT 0xc3 > @@ -170,6 +179,11 @@ struct IPMIInterfaceClass { > * Return the firmware info for a device. > */ > void (*get_fwinfo)(struct IPMIInterface *s, IPMIFwInfo *info); > + > + /* > + * IPMI channel protocol type number. > + */ > + uint8_t protocol; > }; > > /* > diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c > index 8c3313aa65f..9198f854bd9 100644 > --- a/hw/ipmi/ipmi_bmc_sim.c > +++ b/hw/ipmi/ipmi_bmc_sim.c > @@ -70,6 +70,7 @@ > #define IPMI_CMD_GET_MSG 0x33 > #define IPMI_CMD_SEND_MSG 0x34 > #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 > +#define IPMI_CMD_GET_CHANNEL_INFO 0x42 > > #define IPMI_NETFN_STORAGE 0x0a > > @@ -1033,8 +1034,8 @@ static void send_msg(IPMIBmcSim *ibs, > uint8_t *buf; > uint8_t netfn, rqLun, rsLun, rqSeq; > > - if (cmd[2] != 0) { > - /* We only handle channel 0 with no options */ > + if (cmd[2] != IPMI_CHANNEL_IPMB) { > + /* We only handle channel 0h (IPMB) with no options */ > rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); > return; > } > @@ -1232,6 +1233,56 @@ static void get_watchdog_timer(IPMIBmcSim *ibs, > } > } > > +static void get_channel_info(IPMIBmcSim *ibs, > + uint8_t *cmd, unsigned int cmd_len, > + RspBuffer *rsp) > +{ > + IPMIInterface *s = ibs->parent.intf; > + IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); > + uint8_t ch = cmd[1] & 0x0f; > + > + /* Only define channel 0h (IPMB) and Fh (system interface) */ > + > + if (ch == 0x0e) { /* "This channel" */ > + ch = IPMI_CHANNEL_SYSTEM; > + } > + rsp_buffer_push(rsp, ch); > + > + if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) { > + /* Not supported */ I think that an all zero response is a valid response. I think you should return a IPMI_CC_INVALID_DATA_FIELD instead, right? > + int i; > + for (i = 0; i < 8; i++) { > + rsp_buffer_push(rsp, 0x00); > + } > + return; > + } > + > + if (ch == IPMI_CHANNEL_IPMB) { > + rsp_buffer_push(rsp, IPMI_CH_MEDIUM_IPMB); > + rsp_buffer_push(rsp, IPMI_CH_PROTOCOL_IPMB); > + } else { /* IPMI_CHANNEL_SYSTEM */ > + rsp_buffer_push(rsp, IPMI_CH_MEDIUM_SYSTEM); > + rsp_buffer_push(rsp, k->protocol); > + } > + > + rsp_buffer_push(rsp, 0x00); /* Session-less */ > + > + /* IPMI Vendor ID */ > + rsp_buffer_push(rsp, 0xf2); > + rsp_buffer_push(rsp, 0x1b); > + rsp_buffer_push(rsp, 0x00); Where does this come from? > + > + if (ch == IPMI_CHANNEL_SYSTEM) { > + /* IRQ assigned by ACPI/PnP (XXX?) */ > + rsp_buffer_push(rsp, 0x60); > + rsp_buffer_push(rsp, 0x60); The interrupt should be available. For the isa versions there is a get_fwinfo function pointer that you can fetch this with. For PCI it's more complicated, unfortunately. -corey > + } else { > + /* Reserved */ > + rsp_buffer_push(rsp, 0x00); > + rsp_buffer_push(rsp, 0x00); > + } > +} > + > static void get_sdr_rep_info(IPMIBmcSim *ibs, > uint8_t *cmd, unsigned int cmd_len, > RspBuffer *rsp) > @@ -2028,6 +2079,7 @@ static const IPMICmdHandler app_cmds[] = { > [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, > [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, > [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, > + [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 }, > }; > static const IPMINetfn app_netfn = { > .cmd_nums = ARRAY_SIZE(app_cmds), > diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c > index 583fc64730c..d639c151c4d 100644 > --- a/hw/ipmi/ipmi_bt.c > +++ b/hw/ipmi/ipmi_bt.c > @@ -434,4 +434,6 @@ void ipmi_bt_class_init(IPMIInterfaceClass *iic) > iic->handle_if_event = ipmi_bt_handle_event; > iic->set_irq_enable = ipmi_bt_set_irq_enable; > iic->reset = ipmi_bt_handle_reset; > + /* BT System Interface Format, IPMI v1.5 */ > + iic->protocol = IPMI_CH_PROTOCOL_BT_15; > } > diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c > index c15977cab4c..8af7698286d 100644 > --- a/hw/ipmi/ipmi_kcs.c > +++ b/hw/ipmi/ipmi_kcs.c > @@ -420,4 +420,5 @@ void ipmi_kcs_class_init(IPMIInterfaceClass *iic) > iic->handle_rsp = ipmi_kcs_handle_rsp; > iic->handle_if_event = ipmi_kcs_handle_event; > iic->set_irq_enable = ipmi_kcs_set_irq_enable; > + iic->protocol = IPMI_CH_PROTOCOL_KCS; > } > -- > 2.47.1 >