[Skiboot] [PATCH 3/4] ipmi: flush the ipmi message queue before booting a kernel

Stewart Smith stewart at flamingspork.com
Mon May 15 06:44:16 AEST 2023



> On May 13, 2023, at 05:12, Nicholas Piggin <npiggin at gmail.com> wrote:
> 
> Bring ipmi to a consistent state before booting a kernel by flushing
> all outstanding messages. The OS may not start kicking the IPMI state
> machine for some time.
> 
> For example, without this change, when booting in QEMU, the IPMI command
> issued by ipmi_wdt_final_reset() to disable the watchdog is not sent to
> the BMC before the OS boots, effectively leaving the watchdog enabled
> until the OS begins to drive OPAL pollers.

Hah, that could be awkward and unpredictable for a payload to have to do a thing within a time.

Nice catch :)

Reviewed-by: Stewart Smith <stewart at flamingspork.com <mailto:stewart at flamingspork.com>>

> 
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
> ---
> core/ipmi.c                | 11 ++++++++++-
> hw/bt.c                    |  7 ++++++-
> hw/fsp/fsp-ipmi.c          | 12 ++++++++++--
> include/ipmi.h             |  7 ++++++-
> platforms/astbmc/common.c  |  6 ++++++
> platforms/ibm-fsp/common.c |  6 ++++++
> 6 files changed, 44 insertions(+), 5 deletions(-)
> 
> diff --git a/core/ipmi.c b/core/ipmi.c
> index 59aa95fc..673aa0c9 100644
> --- a/core/ipmi.c
> +++ b/core/ipmi.c
> @@ -159,7 +159,7 @@ void ipmi_cmd_done(uint8_t cmd, uint8_t netfn, uint8_t cc, struct ipmi_msg *msg)
> 
> void ipmi_queue_msg_sync(struct ipmi_msg *msg)
> {
> -	void (*poll)(void) = msg->backend->poll;
> +	bool (*poll)(void) = msg->backend->poll;
> 
> 	if (!ipmi_present())
> 		return;
> @@ -192,6 +192,15 @@ void ipmi_queue_msg_sync(struct ipmi_msg *msg)
> 	}
> }
> 
> +void ipmi_flush(void)
> +{
> +	if (!ipmi_present())
> +		return;
> +
> +	while (ipmi_backend->poll())
> +		time_wait_ms(10);
> +}
> +
> static void ipmi_read_event_complete(struct ipmi_msg *msg)
> {
> 	prlog(PR_DEBUG, "IPMI read event %02x complete: %d bytes. cc: %02x\n",
> diff --git a/hw/bt.c b/hw/bt.c
> index 5016feab..1912cd3a 100644
> --- a/hw/bt.c
> +++ b/hw/bt.c
> @@ -519,9 +519,14 @@ static void bt_poll(struct timer *t __unused, void *data __unused,
> 		       bt.irq_ok ? TIMER_POLL : msecs_to_tb(BT_DEFAULT_POLL_MS));
> }
> 
> -static void bt_ipmi_poll(void)
> +static bool bt_ipmi_poll(void)
> {
> +	if (!lpc_ok())
> +		return false;
> +
> 	bt_poll(NULL, NULL, mftb());
> +
> +	return bt.queue_len > 0;
> }
> 
> static void bt_add_msg(struct bt_msg *bt_msg)
> diff --git a/hw/fsp/fsp-ipmi.c b/hw/fsp/fsp-ipmi.c
> index e368c282..9e600f3f 100644
> --- a/hw/fsp/fsp-ipmi.c
> +++ b/hw/fsp/fsp-ipmi.c
> @@ -243,14 +243,22 @@ static int fsp_ipmi_dequeue_msg(struct ipmi_msg *ipmi_msg)
> 	return 0;
> }
> 
> +
> +static bool fsp_ipmi_poll(void)
> +{
> +	/* fsp_opal_poll poller checks command responses */
> +	opal_run_pollers();
> +
> +	return !list_empty(&fsp_ipmi.msg_queue);
> +}
> +
> static struct ipmi_backend fsp_ipmi_backend = {
> 	.alloc_msg	= fsp_ipmi_alloc_msg,
> 	.free_msg	= fsp_ipmi_free_msg,
> 	.queue_msg	= fsp_ipmi_queue_msg,
> 	.queue_msg_head	= fsp_ipmi_queue_msg_head,
> 	.dequeue_msg	= fsp_ipmi_dequeue_msg,
> -	/* FIXME if ever use ipmi_queue_msg_sync on FSP */
> -	.poll           = NULL,
> +	.poll           = fsp_ipmi_poll,
> };
> 
> static bool fsp_ipmi_rr_notify(uint32_t cmd_sub_mod,
> diff --git a/include/ipmi.h b/include/ipmi.h
> index 3e629ba4..5b7efd1e 100644
> --- a/include/ipmi.h
> +++ b/include/ipmi.h
> @@ -178,8 +178,10 @@ struct ipmi_backend {
> 	 *
> 	 * So, ensure we have a way to drive any state machines that an IPMI
> 	 * backend may neeed to crank to ensure forward progress.
> +	 *
> +	 * This returns true while there are any messages queued.
> 	 */
> -	void (*poll)(void);
> +	bool (*poll)(void);
> };
> 
> extern struct ipmi_backend *ipmi_backend;
> @@ -220,6 +222,9 @@ void ipmi_queue_msg_sync(struct ipmi_msg *msg);
> /* Removes the message from the list, queued previously */
> int ipmi_dequeue_msg(struct ipmi_msg *msg);
> 
> +/* Polls the backend until all queued messages are completed */
> +void ipmi_flush(void);
> +
> /* Process a completed message */
> void ipmi_cmd_done(uint8_t cmd, uint8_t netfn, uint8_t cc, struct ipmi_msg *msg);
> 
> diff --git a/platforms/astbmc/common.c b/platforms/astbmc/common.c
> index 9ce22b38..bfbba2d5 100644
> --- a/platforms/astbmc/common.c
> +++ b/platforms/astbmc/common.c
> @@ -504,6 +504,12 @@ void astbmc_exit(void)
> 	ipmi_wdt_final_reset();
> 
> 	ipmi_set_boot_count();
> +
> +	/*
> +	 * Booting into an OS that may not call back into skiboot for
> +	 * some time. Ensure all IPMI messages are processed first.
> +	 */
> +	ipmi_flush();
> }
> 
> static const struct bmc_sw_config bmc_sw_ami = {
> diff --git a/platforms/ibm-fsp/common.c b/platforms/ibm-fsp/common.c
> index 4a723b25..f289d1f2 100644
> --- a/platforms/ibm-fsp/common.c
> +++ b/platforms/ibm-fsp/common.c
> @@ -186,6 +186,12 @@ void ibm_fsp_exit(void)
> 
> 	/* Clear SRCs on the op-panel when Linux starts */
> 	op_panel_clear_src();
> +
> +	/*
> +	 * Booting into an OS that may not call back into skiboot for
> +	 * some time. Ensure all IPMI messages are processed first.
> +	 */
> +	ipmi_flush();
> }
> 
> int64_t ibm_fsp_cec_reboot(void)
> -- 
> 2.40.1
> 
> _______________________________________________
> Skiboot mailing list
> Skiboot at lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/skiboot/attachments/20230514/ed094adc/attachment-0001.htm>


More information about the Skiboot mailing list