[PATCH v3 3/3] lib: sbi: Clear IPIs before init_warm_startup in non-boot harts
Evgenii Shatokhin
e.shatokhin at yadro.com
Thu Mar 9 09:53:54 PST 2023
On 09.03.2023 19:30, Anup Patel wrote:
> On Mon, Mar 6, 2023 at 2:54 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().
>
> As noted before, the sbi_ipi_raw_clear() will not work since secondary
> HARTs might call sbi_ipi_raw_clear() even before platform code has a
> chance to register IPI device ops.
How so? If I understand it correctly, the platform code registers IPI
device ops and sets the IPI device structures when the boot hart calls
sbi_platform_ipi_init() with cold_boot=true from sbi_ipi_init().
So, by the time the secondary harts exit wait_for_coldboot(), IPI device
and ops are already in place and can be used.
sbi_platform_ipi_init() called from those harts with cold_boot == false
only clears pending IPIs and disables certain interrupts, it looks like.
>
> I also recollected why we have this WFI and IPI based coldboot wait logic.
> The rationale of using WFI and IPI based coldboot wait logic was to reduce
> bus traffic from secondary HARTs while the primary HART completes the
> coldboot sequence (i.e. init_coldboot()). Clearly, this WFI and IPI based
> coldboot wait logic will do the intended thing if WFI is a NOP.
>
> I think we can do the following:
> 1) Remove coldboot_lock and coldboot_wait_hmask
> 2) Simplify the loop in wait_for_coldboot() to use
> cpu_relax_loop(100) (or more) to reduce bus traffic
> from secondary HARTs
> 3) Simplify wake_coldboot_harts() to only do
> "__smp_store_release(&coldboot_done, 1);"
>
> Regards,
> Anup
>
> diff --git a/include/sbi/riscv_barrier.h b/include/sbi/riscv_barrier.h
> index 1fba8b8..dd8aa79 100644
> --- a/include/sbi/riscv_barrier.h
> +++ b/include/sbi/riscv_barrier.h
> @@ -40,7 +40,19 @@
> #define smp_wmb() RISCV_FENCE(w,w)
>
> /* CPU relax for busy loop */
> -#define cpu_relax() asm volatile ("" : : : "memory")
> +#define cpu_relax() \
> +do { \
> + long dummy = 0x1; \
> + asm volatile ("div %0, %0, zero" : "=r" (dummy) : : "memory");\
> +} while (0)
> +
> +/* CPU relax loop */
> +#define cpu_relax_loop(__loop_count) \
> +do { \
> + long i; \
> + for (i = 0; i < (__loop_count); i++) \
> + cpu_relax(); \
> +} while (0)
>
> /* clang-format on */
>
Regards,
Evgenii
More information about the opensbi
mailing list