[PATCH 1/1] lib: sbi: relax scoldboot_lock spinlock

Damien Le Moal Damien.LeMoal at wdc.com
Thu Aug 13 23:11:56 EDT 2020


On Thu, 2020-08-13 at 20:39 -0400, Sean Anderson wrote:
> On 8/13/20 8:32 PM, Atish Patra wrote:
> > On Thu, Aug 13, 2020 at 3:52 PM Heinrich Schuchardt <xypron.glpk at gmx.de> wrote:
> > > On 14.08.20 00:25, Atish Patra wrote:
> > > > > > Probably, the hart executing warmboot invokes sbi_platform_ipi_clear
> > > > > > even before sbi_ipi_init is being called from the hart running coldboot.
> > > > > There are two calls to sbi_ipi_init(). Is only the one in coldboot relevant?
> > > > > 
> > > > Yes. That actually setups the clint base address.
> > > > 
> > > > > Do you mean something like:
> > > > > 
> > > > No. I meant like this.
> > > > 
> > > > +#define UART_BASE 0x38000000ULL
> > > > +static void sbi_print_early(char ch) {
> > > > +    int32_t r;
> > > > +    do {
> > > > +      __asm__ __volatile__ (
> > > > +        "amoor.w %0, %2, %1\n"
> > > > +        : "=r" (r), "+A" (*(uint32_t*)(UART_BASE))
> > > > +        : "r" (ch));
> > > > +    } while (r < 0);
> > > > +}
> > > > +
> > > >  static void sbi_boot_prints(struct sbi_scratch *scratch, u32 hartid)
> > > >  {
> > > >         int xlen;
> > > > @@ -112,6 +123,8 @@ static void wait_for_coldboot(struct sbi_scratch
> > > > *scratch, u32 hartid)
> > > >                         wfi();
> > > >                         cmip = csr_read(CSR_MIP);
> > > >                  } while (!(cmip & MIP_MSIP));
> > > > +               sbi_print_early('T');
> > > > +               sbi_printf("mip value %lx\n", cmip);
> > > >                 spin_lock(&coldboot_lock);
> > > >         };
> > > > 
> > > > 
> > > > Note: sbi_printf may not work if sbi_console_init from the cold boot
> > > > path is not invoked.
> > > > That's why I added a "sbi_print_early".  If sbi_printf doesn't work,
> > > > please remove it.
> > > > 
> > > > Thanks for your time in figuring out the issue with Kendryte.
> > > > Unfortunately, I can't test these changes as I don't have
> > > > a kendryte board at home.
> > > > 
> > > > 
> > > 
> > > This now booted to U-Boot. The extra time for printing was enough to
> > > break the livelock:
> > > 
> > Thanks again for verification.
> > 
> > > TTTTTTTTTT
> > 
> > This confirms that MSIP bit is set even if there was no IPI sent and MIP was
> > cleared in fw_base.S [1]. I guess there is a hardware bug with Kendryte where
> > MSIP is not getting reset properly.
> 
> Hm, perhaps MIP is level-based, so the CLINT itself needs to be
> acknowledged before MIP will be disabled.
> 
> > [1] https://github.com/riscv/opensbi/blob/master/firmware/fw_base.S#L370
> > 
> > If that's the case, we can convert coldboot_done to an atomic variable
> > as suggested by
> 
> I think this is the best course of action in general. All the harts are
> just waiting around, so there's no need for an interrupt here.

The following works for me. However, the sbi_ecall_console_puts() call
in test_main() for the test FW_PAYLOAD does not work. Individual calls
to sbi_ecall_console_putc() do work, but not the full string. It looks
like the string is broken, so the data section may be broken... Digging
into that.
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index a7fb848..9692cd9 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -84,69 +84,18 @@ static void sbi_boot_prints(struct sbi_scratch
*scratch, u32 hartid)
        sbi_hart_pmp_dump(scratch);
 }
 
-static spinlock_t coldboot_lock = SPIN_LOCK_INITIALIZER;
-static unsigned long coldboot_done = 0;
-static struct sbi_hartmask coldboot_wait_hmask = { 0 };
+static atomic_t coldboot_done = ATOMIC_INITIALIZER(0);
 
-static void wait_for_coldboot(struct sbi_scratch *scratch, u32 hartid)
+static inline void wait_for_coldboot(struct sbi_scratch *scratch, u32
hartid)
 {
-       unsigned long saved_mie, cmip;
-       const struct sbi_platform *plat = sbi_platform_ptr(scratch);
-
-       /* Save MIE CSR */
-       saved_mie = csr_read(CSR_MIE);
-
-       /* Set MSIE bit to receive IPI */
-       csr_set(CSR_MIE, MIP_MSIP);
-
-       /* Acquire coldboot lock */
-       spin_lock(&coldboot_lock);
-
-       /* Mark current HART as waiting */
-       sbi_hartmask_set_hart(hartid, &coldboot_wait_hmask);
-
-       /* Wait for coldboot to finish using WFI */
-       while (!coldboot_done) {
-               spin_unlock(&coldboot_lock);
-               do {
-                       wfi();
-                       cmip = csr_read(CSR_MIP);
-                } while (!(cmip & MIP_MSIP));
-               spin_lock(&coldboot_lock);
-       };
-
-       /* Unmark current HART as waiting */
-       sbi_hartmask_clear_hart(hartid, &coldboot_wait_hmask);
-
-       /* Release coldboot lock */
-       spin_unlock(&coldboot_lock);
-
-       /* Restore MIE CSR */
-       csr_write(CSR_MIE, saved_mie);
-
-       /* Clear current HART IPI */
-       sbi_platform_ipi_clear(plat, hartid);
+       /* Wait for coldboot to finish */
+       while (!atomic_read(&coldboot_done)) {};
 }
-static void wake_coldboot_harts(struct sbi_scratch *scratch, u32
hartid)
+static inline void wake_coldboot_harts(struct sbi_scratch *scratch,
u32 hartid)
 {
-       const struct sbi_platform *plat = sbi_platform_ptr(scratch);
-
-       /* Acquire coldboot lock */
-       spin_lock(&coldboot_lock);
-
        /* Mark coldboot done */
-       coldboot_done = 1;
-
-       /* Send an IPI to all HARTs waiting for coldboot */
-       for (int i = 0; i <= sbi_scratch_last_hartid(); i++) {
-               if ((i != hartid) &&
-                   sbi_hartmask_test_hart(i, &coldboot_wait_hmask))
-                       sbi_platform_ipi_send(plat, i);
-       }
-
-       /* Release coldboot lock */
-       spin_unlock(&coldboot_lock);
+       atomic_write(&coldboot_done, 1);
 }
 
 static unsigned long init_count_offset;


> 
--Sean


-- 
Damien Le Moal
Western Digital Research


More information about the opensbi mailing list