[PATCH v2 2/2] lib: sbi: Clear IPIs before init_warm_startup in non-boot harts
Evgenii Shatokhin
e.shatokhin at yadro.com
Tue Feb 28 08:19:27 PST 2023
On 28.02.2023 07:41, Anup Patel wrote:
> On Wed, Feb 22, 2023 at 2:39 AM Evgenii Shatokhin <e.shatokhin at yadro.com> wrote:
>>
>> Since commit 50d4fde1c5a4 ("lib: Remove redundant sbi_platform_ipi_clear()
>> calls"), the IPI sent from the boot hart in wake_coldboot_harts() is not
>> cleared in the secondary harts until they reach sbi_ipi_init(). However,
>> sbi_hsm_init() and sbi_hsm_hart_wait() are called earlier, so a secondary
>> hart might enter sbi_hsm_hart_wait() with an already pending IPI.
>>
>> sbi_hsm_hart_wait() makes sure the hart leaves the loop only when it is
>> actually ready, so a pending unrelated IPI should not cause safety issues.
>> However, it might be inefficient on certain hardware, because it prevents
>> "wfi" from stalling the hart even if the hardware supports this, making the
>> hart needlessly spin in a "busy-wait" loop.
>>
>> This behaviour can be observed, for example, in a QEMU VM (QEMU 7.2.0) with
>> "-machine virt" running a Linux guest. Inserting delays in
>> sbi_hsm_hart_start() allows reproducing the issue more reliably.
>>
>> The comment in wait_for_coldboot() suggests that the initial IPI is needed
>> in the warm resume path, so let us clear it before init_warm_startup()
>> only.
>>
>> To do this, sbi_ipi_raw_clear() was created similar to sbi_ipi_raw_send().
>>
>> Signed-off-by: Evgenii Shatokhin <e.shatokhin at yadro.com>
>> ---
>> include/sbi/sbi_ipi.h | 2 ++
>> lib/sbi/sbi_init.c | 6 ++++--
>> lib/sbi/sbi_ipi.c | 6 ++++++
>> 3 files changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h
>> index f6ac807..f384e74 100644
>> --- a/include/sbi/sbi_ipi.h
>> +++ b/include/sbi/sbi_ipi.h
>> @@ -77,6 +77,8 @@ void sbi_ipi_process(void);
>>
>> int sbi_ipi_raw_send(u32 target_hart);
>>
>> +void sbi_ipi_raw_clear(u32 target_hart);
>> +
>> const struct sbi_ipi_device *sbi_ipi_get_device(void);
>>
>> void sbi_ipi_set_device(const struct sbi_ipi_device *dev);
>> diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
>> index e353c33..a9a4084 100644
>> --- a/lib/sbi/sbi_init.c
>> +++ b/lib/sbi/sbi_init.c
>> @@ -438,10 +438,12 @@ static void __noreturn init_warmboot(struct sbi_scratch *scratch, u32 hartid)
>> if (hstate < 0)
>> sbi_hart_hang();
>>
>> - if (hstate == SBI_HSM_STATE_SUSPENDED)
>> + if (hstate == SBI_HSM_STATE_SUSPENDED) {
>> init_warm_resume(scratch);
>> - else
>> + } else {
>> + sbi_ipi_raw_clear(hartid);
>
> This effectively does nothing in many cases because for a lot of
> platforms all HARTs enter OpenSBI at the same time and the HARTs
> entering warm boot path will call sbi_ipi_raw_clear() even before
> ipi_dev is provided by platform code.
Right, it would be a no-op then.
However, this is not the case when Linux 6.x boots, e.g. in QEMU with
"-machine virt" or with other platforms which provide "cold" IPI init
callbacks.
Here, the boot hart initializes ipi_dev early. For example, in QEMU with
"-machine virt", it does the following:
init_coldboot() => sbi_ipi_init() => ... => aclint_mswi_cold_init().
Other harts are waiting in sbi_hsm_init() at the moment and will only
call sbi_ipi_init() after they leave sbi_hsm_hart_wait(), etc.
While they are waiting, their previous IPI remains pending. It can be
easily demonstrated if one checks the relevant bits of CSR_MIP in
sbi_hsm_hart_wait() right before the wfi loop. A delay in
sbi_hsm_hart_start(), same as for the first issue, also helps make it
visible.
csr_read(CSR_MIP) & (MIP_MSIP | MIP_MEIP) == 0x8 in my case at that
point. That is, MIP_MSIP bit is set even before the boot hart has send
an IPI to the target hart in sbi_hsm_hart_start(). Not good.
So, sbi_ipi_raw_clear(hartid) really helps in such cases, even if it is
a no-op in other situations.
>
>> init_warm_startup(scratch, hartid);
>> + }
>>
>> sbi_hart_switch_mode(hartid, scratch->next_arg1,
>> scratch->next_addr,
>> diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c
>> index 1bcc2e4..b9f6205 100644
>> --- a/lib/sbi/sbi_ipi.c
>> +++ b/lib/sbi/sbi_ipi.c
>> @@ -217,6 +217,12 @@ int sbi_ipi_raw_send(u32 target_hart)
>> return 0;
>> }
>>
>> +void sbi_ipi_raw_clear(u32 target_hart)
>> +{
>> + if (ipi_dev && ipi_dev->ipi_clear)
>> + ipi_dev->ipi_clear(target_hart);
>> +}
>> +
>> const struct sbi_ipi_device *sbi_ipi_get_device(void)
>> {
>> return ipi_dev;
>> --
>> 2.34.1
>>
>>
>>
>> --
>> opensbi mailing list
>> opensbi at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/opensbi
>
> Regards,
> Anup
>
Regards,
Evgenii
More information about the opensbi
mailing list