diff mbox series

[v6,13/19] riscv: Fix race conditions when initializing IPI

Message ID 20200305181308.944595-14-seanga2@gmail.com
State Superseded
Delegated to: Andes
Headers show
Series riscv: Add Sipeed Maix support | expand

Commit Message

Sean Anderson March 5, 2020, 6:13 p.m. UTC
The IPI code could have race conditions in several places.
* Several harts could race on the value of gd->arch->clint/plic
* Non-boot harts could race with the main hart on the DM subsystem In
  addition, if an IPI was pending when U-Boot started, it would cause the
  IPI handler to jump to address 0.

To address these problems, a new function riscv_init_ipi is introduced. It
is called once during arch_cpu_init_dm. Before this point, no riscv_*_ipi
functions may be called. Access is synchronized by gd->arch->ipi_ready.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
---

Changes in v6:
- Fix some formatting
- Clear IPIs before enabling interrupts instead of using a ipi_ready flag
- Only print messages on error in smp code

Changes in v5:
- New

 arch/riscv/cpu/cpu.c          |  6 ++++
 arch/riscv/cpu/start.S        |  2 ++
 arch/riscv/include/asm/smp.h  | 43 +++++++++++++++++++++++++++
 arch/riscv/lib/andes_plic.c   | 34 ++++++++-------------
 arch/riscv/lib/sbi_ipi.c      |  5 ++++
 arch/riscv/lib/sifive_clint.c | 33 +++++++--------------
 arch/riscv/lib/smp.c          | 56 ++++++++---------------------------
 7 files changed, 92 insertions(+), 87 deletions(-)

Comments

Rick Chen March 10, 2020, 8:20 a.m. UTC | #1
Hi Sean

> The IPI code could have race conditions in several places.
> * Several harts could race on the value of gd->arch->clint/plic
> * Non-boot harts could race with the main hart on the DM subsystem In
>   addition, if an IPI was pending when U-Boot started, it would cause the
>   IPI handler to jump to address 0.
>
> To address these problems, a new function riscv_init_ipi is introduced. It
> is called once during arch_cpu_init_dm. Before this point, no riscv_*_ipi
> functions may be called. Access is synchronized by gd->arch->ipi_ready.
>
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> ---
>

> Can you try to clear mip/sip in startup flow before secondary_hart_loop:
> Maybe it can help to overcome the problem of calling riscv_clear_ipi()
> before riscv_init_ipi() that you added.

How is the verified result about trying to clear mip/sip in startup flow ?
I have asked you twice in v5, but you still have no response about it.

[PATCH v5 27/33] riscv: Fix race conditions when initializing IPI
https://patchwork.ozlabs.org/patch/1246864/#2377119

Thanks
Rick



> Changes in v6:
> - Fix some formatting
> - Clear IPIs before enabling interrupts instead of using a ipi_ready flag
> - Only print messages on error in smp code
>
> Changes in v5:
> - New
>
>  arch/riscv/cpu/cpu.c          |  6 ++++
>  arch/riscv/cpu/start.S        |  2 ++
>  arch/riscv/include/asm/smp.h  | 43 +++++++++++++++++++++++++++
>  arch/riscv/lib/andes_plic.c   | 34 ++++++++-------------
>  arch/riscv/lib/sbi_ipi.c      |  5 ++++
>  arch/riscv/lib/sifive_clint.c | 33 +++++++--------------
>  arch/riscv/lib/smp.c          | 56 ++++++++---------------------------
>  7 files changed, 92 insertions(+), 87 deletions(-)
>
> diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
> index e457f6acbf..f851374255 100644
> --- a/arch/riscv/cpu/cpu.c
> +++ b/arch/riscv/cpu/cpu.c
> @@ -96,6 +96,12 @@ int arch_cpu_init_dm(void)
>                         csr_write(CSR_SATP, 0);
>         }
>
> +#ifdef CONFIG_SMP
> +       ret = riscv_init_ipi();
> +       if (ret)
> +               return ret;
> +#endif
> +
>         return 0;
>  }
>
> diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
> index 6b3ff99c38..e8740c8568 100644
> --- a/arch/riscv/cpu/start.S
> +++ b/arch/riscv/cpu/start.S
> @@ -67,6 +67,8 @@ _start:
>  #else
>         li      t0, SIE_SSIE
>  #endif
> +       /* Clear any pending IPIs */
> +       csrc    MODE_PREFIX(ip), t0
>         csrs    MODE_PREFIX(ie), t0
>  #endif
>
> diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
> index 74de92ed13..1b428856b2 100644
> --- a/arch/riscv/include/asm/smp.h
> +++ b/arch/riscv/include/asm/smp.h
> @@ -51,4 +51,47 @@ void handle_ipi(ulong hart);
>   */
>  int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait);
>
> +/**
> + * riscv_init_ipi() - Initialize inter-process interrupt (IPI) driver
> + *
> + * Platform code must provide this function. This function is called once after
> + * the cpu driver is initialized. No other riscv_*_ipi() calls will be made
> + * before this function is called.
> + *
> + * @return 0 if OK, -ve on error
> + */
> +int riscv_init_ipi(void);
> +
> +/**
> + * riscv_send_ipi() - Send inter-processor interrupt (IPI)
> + *
> + * Platform code must provide this function.
> + *
> + * @hart: Hart ID of receiving hart
> + * @return 0 if OK, -ve on error
> + */
> +int riscv_send_ipi(int hart);
> +
> +/**
> + * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
> + *
> + * Platform code must provide this function.
> + *
> + * @hart: Hart ID of hart to be cleared
> + * @return 0 if OK, -ve on error
> + */
> +int riscv_clear_ipi(int hart);
> +
> +/**
> + * riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
> + *
> + * Platform code must provide this function.
> + *
> + * @hart: Hart ID of hart to be checked
> + * @pending: Pointer to variable with result of the check,
> + *           1 if IPI is pending, 0 otherwise
> + * @return 0 if OK, -ve on error
> + */
> +int riscv_get_ipi(int hart, int *pending);
> +
>  #endif
> diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
> index 20529ab3eb..8484f76386 100644
> --- a/arch/riscv/lib/andes_plic.c
> +++ b/arch/riscv/lib/andes_plic.c
> @@ -30,20 +30,6 @@
>  #define SEND_IPI_TO_HART(hart)  (0x80 >> (hart))
>
>  DECLARE_GLOBAL_DATA_PTR;
> -static int init_plic(void);
> -
> -#define PLIC_BASE_GET(void)                                            \
> -       do {                                                            \
> -               long *ret;                                              \
> -                                                                       \
> -               if (!gd->arch.plic) {                                   \
> -                       ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \
> -                       if (IS_ERR(ret))                                \
> -                               return PTR_ERR(ret);                    \
> -                       gd->arch.plic = ret;                            \
> -                       init_plic();                                    \
> -               }                                                       \
> -       } while (0)
>
>  static int enable_ipi(int hart)
>  {
> @@ -93,13 +79,21 @@ static int init_plic(void)
>         return -ENODEV;
>  }
>
> +int riscv_init_ipi(void)
> +{
> +       int ret = syscon_get_first_range(RISCV_SYSCON_PLIC);
> +
> +       if (IS_ERR(ret))
> +               return PTR_ERR(ret);
> +       gd->arch.plic = ret;
> +
> +       return init_plic();
> +}
> +
>  int riscv_send_ipi(int hart)
>  {
> -       unsigned int ipi;
> +       unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
>
> -       PLIC_BASE_GET();
> -
> -       ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
>         writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic,
>                                 gd->arch.boot_hart));
>
> @@ -110,8 +104,6 @@ int riscv_clear_ipi(int hart)
>  {
>         u32 source_id;
>
> -       PLIC_BASE_GET();
> -
>         source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart));
>         writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart));
>
> @@ -120,8 +112,6 @@ int riscv_clear_ipi(int hart)
>
>  int riscv_get_ipi(int hart, int *pending)
>  {
> -       PLIC_BASE_GET();
> -
>         *pending = readl((void __iomem *)PENDING_REG(gd->arch.plic,
>                                                      gd->arch.boot_hart));
>         *pending = !!(*pending & SEND_IPI_TO_HART(hart));
> diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c
> index 9a698ce74e..310d1bd2a4 100644
> --- a/arch/riscv/lib/sbi_ipi.c
> +++ b/arch/riscv/lib/sbi_ipi.c
> @@ -7,6 +7,11 @@
>  #include <common.h>
>  #include <asm/sbi.h>
>
> +int riscv_init_ipi(void)
> +{
> +       return 0;
> +}
> +
>  int riscv_send_ipi(int hart)
>  {
>         ulong mask;
> diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
> index 5e0d25720b..78fc6c868d 100644
> --- a/arch/riscv/lib/sifive_clint.c
> +++ b/arch/riscv/lib/sifive_clint.c
> @@ -24,22 +24,8 @@
>
>  DECLARE_GLOBAL_DATA_PTR;
>
> -#define CLINT_BASE_GET(void)                                           \
> -       do {                                                            \
> -               long *ret;                                              \
> -                                                                       \
> -               if (!gd->arch.clint) {                                  \
> -                       ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \
> -                       if (IS_ERR(ret))                                \
> -                               return PTR_ERR(ret);                    \
> -                       gd->arch.clint = ret;                           \
> -               }                                                       \
> -       } while (0)
> -
>  int riscv_get_time(u64 *time)
>  {
> -       CLINT_BASE_GET();
> -
>         *time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
>
>         return 0;
> @@ -47,17 +33,24 @@ int riscv_get_time(u64 *time)
>
>  int riscv_set_timecmp(int hart, u64 cmp)
>  {
> -       CLINT_BASE_GET();
> -
>         writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
>
>         return 0;
>  }
>
> +int riscv_init_ipi(void)
> +{
> +       long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
> +
> +       if (IS_ERR(ret))
> +               return PTR_ERR(ret);
> +       gd->arch.clint = ret;
> +
> +       return 0;
> +}
> +
>  int riscv_send_ipi(int hart)
>  {
> -       CLINT_BASE_GET();
> -
>         writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
>
>         return 0;
> @@ -65,8 +58,6 @@ int riscv_send_ipi(int hart)
>
>  int riscv_clear_ipi(int hart)
>  {
> -       CLINT_BASE_GET();
> -
>         writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
>
>         return 0;
> @@ -74,8 +65,6 @@ int riscv_clear_ipi(int hart)
>
>  int riscv_get_ipi(int hart, int *pending)
>  {
> -       CLINT_BASE_GET();
> -
>         *pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
>
>         return 0;
> diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
> index 17adb35730..fe992eb00f 100644
> --- a/arch/riscv/lib/smp.c
> +++ b/arch/riscv/lib/smp.c
> @@ -12,38 +12,6 @@
>
>  DECLARE_GLOBAL_DATA_PTR;
>
> -/**
> - * riscv_send_ipi() - Send inter-processor interrupt (IPI)
> - *
> - * Platform code must provide this function.
> - *
> - * @hart: Hart ID of receiving hart
> - * @return 0 if OK, -ve on error
> - */
> -extern int riscv_send_ipi(int hart);
> -
> -/**
> - * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
> - *
> - * Platform code must provide this function.
> - *
> - * @hart: Hart ID of hart to be cleared
> - * @return 0 if OK, -ve on error
> - */
> -extern int riscv_clear_ipi(int hart);
> -
> -/**
> - * riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
> - *
> - * Platform code must provide this function.
> - *
> - * @hart: Hart ID of hart to be checked
> - * @pending: Pointer to variable with result of the check,
> - *           1 if IPI is pending, 0 otherwise
> - * @return 0 if OK, -ve on error
> - */
> -extern int riscv_get_ipi(int hart, int *pending);
> -
>  static int send_ipi_many(struct ipi_data *ipi, int wait)
>  {
>         ofnode node, cpus;
> @@ -114,7 +82,6 @@ void handle_ipi(ulong hart)
>                 return;
>
>         __smp_mb();
> -
>         smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
>         invalidate_icache_all();
>
> @@ -124,7 +91,13 @@ void handle_ipi(ulong hart)
>          */
>         ret = riscv_clear_ipi(hart);
>         if (ret) {
> -               pr_err("Cannot clear IPI of hart %ld\n", hart);
> +               pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret);
> +               return;
> +       }
> +
> +       /* Sanity check */
> +       if (!smp_function) {
> +               pr_err("smp_function is NULL on hart %ld\n", hart);
>                 return;
>         }
>
> @@ -133,14 +106,11 @@ void handle_ipi(ulong hart)
>
>  int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
>  {
> -       int ret = 0;
> -       struct ipi_data ipi;
> +       struct ipi_data ipi = {
> +               .addr = addr,
> +               .arg0 = arg0,
> +               .arg1 = arg1,
> +       };
>
> -       ipi.addr = addr;
> -       ipi.arg0 = arg0;
> -       ipi.arg1 = arg1;
> -
> -       ret = send_ipi_many(&ipi, wait);
> -
> -       return ret;
> +       return send_ipi_many(&ipi, wait);
>  }
> --
> 2.25.0
>
Sean Anderson March 10, 2020, 1:16 p.m. UTC | #2
On 3/10/20 4:20 AM, Rick Chen wrote:
> Hi Sean
> 
>> The IPI code could have race conditions in several places.
>> * Several harts could race on the value of gd->arch->clint/plic
>> * Non-boot harts could race with the main hart on the DM subsystem In
>>   addition, if an IPI was pending when U-Boot started, it would cause the
>>   IPI handler to jump to address 0.
>>
>> To address these problems, a new function riscv_init_ipi is introduced. It
>> is called once during arch_cpu_init_dm. Before this point, no riscv_*_ipi
>> functions may be called. Access is synchronized by gd->arch->ipi_ready.
>>
>> Signed-off-by: Sean Anderson <seanga2@gmail.com>
>> ---
>>
> 
>> Can you try to clear mip/sip in startup flow before secondary_hart_loop:
>> Maybe it can help to overcome the problem of calling riscv_clear_ipi()
>> before riscv_init_ipi() that you added.
> 
> How is the verified result about trying to clear mip/sip in startup flow ?
> I have asked you twice in v5, but you still have no response about it.
> 
> [PATCH v5 27/33] riscv: Fix race conditions when initializing IPI
> https://patchwork.ozlabs.org/patch/1246864/#2377119
> 
> Thanks
> Rick

I managed to get it working, and this patch incorporates that change.
However, I forgot to update the commit message. The original issue I had
was related to an accidental change to my config, and not to the
clearing of MIP.

--Sean
Rick Chen March 11, 2020, 1:33 a.m. UTC | #3
Hi Sean

> On 3/10/20 4:20 AM, Rick Chen wrote:
> > Hi Sean
> >
> >> The IPI code could have race conditions in several places.
> >> * Several harts could race on the value of gd->arch->clint/plic
> >> * Non-boot harts could race with the main hart on the DM subsystem In
> >>   addition, if an IPI was pending when U-Boot started, it would cause the
> >>   IPI handler to jump to address 0.
> >>
> >> To address these problems, a new function riscv_init_ipi is introduced. It
> >> is called once during arch_cpu_init_dm. Before this point, no riscv_*_ipi
> >> functions may be called. Access is synchronized by gd->arch->ipi_ready.
> >>
> >> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> >> ---
> >>
> >
> >> Can you try to clear mip/sip in startup flow before secondary_hart_loop:
> >> Maybe it can help to overcome the problem of calling riscv_clear_ipi()
> >> before riscv_init_ipi() that you added.
> >
> > How is the verified result about trying to clear mip/sip in startup flow ?
> > I have asked you twice in v5, but you still have no response about it.
> >
> > [PATCH v5 27/33] riscv: Fix race conditions when initializing IPI
> > https://patchwork.ozlabs.org/patch/1246864/#2377119
> >
> > Thanks
> > Rick
>
> I managed to get it working, and this patch incorporates that change.
> However, I forgot to update the commit message. The original issue I had
> was related to an accidental change to my config, and not to the
> clearing of MIP.

So it is not a race condition issue, right ?

Maybe you shall split this into two patchs as below

patch 1
riscv: Clear pending ipi in start code
Describe that it can how and what it help to fix the problem you
encounter more detail
e.g.
(Perhaps the prior stage sends an IPI but does not clear it) ...

patch 2
riscv: refine ipi initialize code flow
Describe that your motivation and intention more detail
e.g.
I think the macro approach is a bit confusing,
since it's unclear at first glance what function
will be initializing the clint/plic.
Given U-Boot's otherwise completely SMP-unsafe design,
I think it's better to be explicit and conservative in these areas.

It can help us to roll back and debug in the future.

Thanks,
Rick

>
> --Sean
Sean Anderson March 17, 2020, 7:27 p.m. UTC | #4
On 3/10/20 9:33 PM, Rick Chen wrote:
> Hi Sean
> 
>> On 3/10/20 4:20 AM, Rick Chen wrote:
>>> Hi Sean
>>>
>>>> The IPI code could have race conditions in several places.
>>>> * Several harts could race on the value of gd->arch->clint/plic
>>>> * Non-boot harts could race with the main hart on the DM subsystem In
>>>>   addition, if an IPI was pending when U-Boot started, it would cause the
>>>>   IPI handler to jump to address 0.
>>>>
>>>> To address these problems, a new function riscv_init_ipi is introduced. It
>>>> is called once during arch_cpu_init_dm. Before this point, no riscv_*_ipi
>>>> functions may be called. Access is synchronized by gd->arch->ipi_ready.
>>>>
>>>> Signed-off-by: Sean Anderson <seanga2@gmail.com>
>>>> ---
>>>>
>>>
>>>> Can you try to clear mip/sip in startup flow before secondary_hart_loop:
>>>> Maybe it can help to overcome the problem of calling riscv_clear_ipi()
>>>> before riscv_init_ipi() that you added.
>>>
>>> How is the verified result about trying to clear mip/sip in startup flow ?
>>> I have asked you twice in v5, but you still have no response about it.
>>>
>>> [PATCH v5 27/33] riscv: Fix race conditions when initializing IPI
>>> https://patchwork.ozlabs.org/patch/1246864/#2377119
>>>
>>> Thanks
>>> Rick
>>
>> I managed to get it working, and this patch incorporates that change.
>> However, I forgot to update the commit message. The original issue I had
>> was related to an accidental change to my config, and not to the
>> clearing of MIP.
> 
> So it is not a race condition issue, right ?

It is sort of a race condition? If the IP CSR is not cleared, then we
can have a race condition.

> 
> Maybe you shall split this into two patchs as below
> 
> patch 1
> riscv: Clear pending ipi in start code
> Describe that it can how and what it help to fix the problem you
> encounter more detail
> e.g.
> (Perhaps the prior stage sends an IPI but does not clear it) ...
> 
> patch 2
> riscv: refine ipi initialize code flow
> Describe that your motivation and intention more detail
> e.g.
> I think the macro approach is a bit confusing,
> since it's unclear at first glance what function
> will be initializing the clint/plic.
> Given U-Boot's otherwise completely SMP-unsafe design,
> I think it's better to be explicit and conservative in these areas.
> 
> It can help us to roll back and debug in the future.
> 
> Thanks,
> Rick

This will be split in the next revision.

>>
>> --Sean
diff mbox series

Patch

diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index e457f6acbf..f851374255 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -96,6 +96,12 @@  int arch_cpu_init_dm(void)
 			csr_write(CSR_SATP, 0);
 	}
 
+#ifdef CONFIG_SMP
+	ret = riscv_init_ipi();
+	if (ret)
+		return ret;
+#endif
+
 	return 0;
 }
 
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 6b3ff99c38..e8740c8568 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -67,6 +67,8 @@  _start:
 #else
 	li	t0, SIE_SSIE
 #endif
+	/* Clear any pending IPIs */
+	csrc	MODE_PREFIX(ip), t0
 	csrs	MODE_PREFIX(ie), t0
 #endif
 
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 74de92ed13..1b428856b2 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -51,4 +51,47 @@  void handle_ipi(ulong hart);
  */
 int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait);
 
+/**
+ * riscv_init_ipi() - Initialize inter-process interrupt (IPI) driver
+ *
+ * Platform code must provide this function. This function is called once after
+ * the cpu driver is initialized. No other riscv_*_ipi() calls will be made
+ * before this function is called.
+ *
+ * @return 0 if OK, -ve on error
+ */
+int riscv_init_ipi(void);
+
+/**
+ * riscv_send_ipi() - Send inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of receiving hart
+ * @return 0 if OK, -ve on error
+ */
+int riscv_send_ipi(int hart);
+
+/**
+ * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of hart to be cleared
+ * @return 0 if OK, -ve on error
+ */
+int riscv_clear_ipi(int hart);
+
+/**
+ * riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
+ *
+ * Platform code must provide this function.
+ *
+ * @hart: Hart ID of hart to be checked
+ * @pending: Pointer to variable with result of the check,
+ *           1 if IPI is pending, 0 otherwise
+ * @return 0 if OK, -ve on error
+ */
+int riscv_get_ipi(int hart, int *pending);
+
 #endif
diff --git a/arch/riscv/lib/andes_plic.c b/arch/riscv/lib/andes_plic.c
index 20529ab3eb..8484f76386 100644
--- a/arch/riscv/lib/andes_plic.c
+++ b/arch/riscv/lib/andes_plic.c
@@ -30,20 +30,6 @@ 
 #define SEND_IPI_TO_HART(hart)  (0x80 >> (hart))
 
 DECLARE_GLOBAL_DATA_PTR;
-static int init_plic(void);
-
-#define PLIC_BASE_GET(void)						\
-	do {								\
-		long *ret;						\
-									\
-		if (!gd->arch.plic) {					\
-			ret = syscon_get_first_range(RISCV_SYSCON_PLIC); \
-			if (IS_ERR(ret))				\
-				return PTR_ERR(ret);			\
-			gd->arch.plic = ret;				\
-			init_plic();					\
-		}							\
-	} while (0)
 
 static int enable_ipi(int hart)
 {
@@ -93,13 +79,21 @@  static int init_plic(void)
 	return -ENODEV;
 }
 
+int riscv_init_ipi(void)
+{
+	int ret = syscon_get_first_range(RISCV_SYSCON_PLIC);
+
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+	gd->arch.plic = ret;
+
+	return init_plic();
+}
+
 int riscv_send_ipi(int hart)
 {
-	unsigned int ipi;
+	unsigned int ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
 
-	PLIC_BASE_GET();
-
-	ipi = (SEND_IPI_TO_HART(hart) << (8 * gd->arch.boot_hart));
 	writel(ipi, (void __iomem *)PENDING_REG(gd->arch.plic,
 				gd->arch.boot_hart));
 
@@ -110,8 +104,6 @@  int riscv_clear_ipi(int hart)
 {
 	u32 source_id;
 
-	PLIC_BASE_GET();
-
 	source_id = readl((void __iomem *)CLAIM_REG(gd->arch.plic, hart));
 	writel(source_id, (void __iomem *)CLAIM_REG(gd->arch.plic, hart));
 
@@ -120,8 +112,6 @@  int riscv_clear_ipi(int hart)
 
 int riscv_get_ipi(int hart, int *pending)
 {
-	PLIC_BASE_GET();
-
 	*pending = readl((void __iomem *)PENDING_REG(gd->arch.plic,
 						     gd->arch.boot_hart));
 	*pending = !!(*pending & SEND_IPI_TO_HART(hart));
diff --git a/arch/riscv/lib/sbi_ipi.c b/arch/riscv/lib/sbi_ipi.c
index 9a698ce74e..310d1bd2a4 100644
--- a/arch/riscv/lib/sbi_ipi.c
+++ b/arch/riscv/lib/sbi_ipi.c
@@ -7,6 +7,11 @@ 
 #include <common.h>
 #include <asm/sbi.h>
 
+int riscv_init_ipi(void)
+{
+	return 0;
+}
+
 int riscv_send_ipi(int hart)
 {
 	ulong mask;
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
index 5e0d25720b..78fc6c868d 100644
--- a/arch/riscv/lib/sifive_clint.c
+++ b/arch/riscv/lib/sifive_clint.c
@@ -24,22 +24,8 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#define CLINT_BASE_GET(void)						\
-	do {								\
-		long *ret;						\
-									\
-		if (!gd->arch.clint) {					\
-			ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \
-			if (IS_ERR(ret))				\
-				return PTR_ERR(ret);			\
-			gd->arch.clint = ret;				\
-		}							\
-	} while (0)
-
 int riscv_get_time(u64 *time)
 {
-	CLINT_BASE_GET();
-
 	*time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
 
 	return 0;
@@ -47,17 +33,24 @@  int riscv_get_time(u64 *time)
 
 int riscv_set_timecmp(int hart, u64 cmp)
 {
-	CLINT_BASE_GET();
-
 	writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
 
 	return 0;
 }
 
+int riscv_init_ipi(void)
+{
+	long *ret = syscon_get_first_range(RISCV_SYSCON_CLINT);
+
+	if (IS_ERR(ret))
+		return PTR_ERR(ret);
+	gd->arch.clint = ret;
+
+	return 0;
+}
+
 int riscv_send_ipi(int hart)
 {
-	CLINT_BASE_GET();
-
 	writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
 
 	return 0;
@@ -65,8 +58,6 @@  int riscv_send_ipi(int hart)
 
 int riscv_clear_ipi(int hart)
 {
-	CLINT_BASE_GET();
-
 	writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
 
 	return 0;
@@ -74,8 +65,6 @@  int riscv_clear_ipi(int hart)
 
 int riscv_get_ipi(int hart, int *pending)
 {
-	CLINT_BASE_GET();
-
 	*pending = readl((void __iomem *)MSIP_REG(gd->arch.clint, hart));
 
 	return 0;
diff --git a/arch/riscv/lib/smp.c b/arch/riscv/lib/smp.c
index 17adb35730..fe992eb00f 100644
--- a/arch/riscv/lib/smp.c
+++ b/arch/riscv/lib/smp.c
@@ -12,38 +12,6 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/**
- * riscv_send_ipi() - Send inter-processor interrupt (IPI)
- *
- * Platform code must provide this function.
- *
- * @hart: Hart ID of receiving hart
- * @return 0 if OK, -ve on error
- */
-extern int riscv_send_ipi(int hart);
-
-/**
- * riscv_clear_ipi() - Clear inter-processor interrupt (IPI)
- *
- * Platform code must provide this function.
- *
- * @hart: Hart ID of hart to be cleared
- * @return 0 if OK, -ve on error
- */
-extern int riscv_clear_ipi(int hart);
-
-/**
- * riscv_get_ipi() - Get status of inter-processor interrupt (IPI)
- *
- * Platform code must provide this function.
- *
- * @hart: Hart ID of hart to be checked
- * @pending: Pointer to variable with result of the check,
- *           1 if IPI is pending, 0 otherwise
- * @return 0 if OK, -ve on error
- */
-extern int riscv_get_ipi(int hart, int *pending);
-
 static int send_ipi_many(struct ipi_data *ipi, int wait)
 {
 	ofnode node, cpus;
@@ -114,7 +82,6 @@  void handle_ipi(ulong hart)
 		return;
 
 	__smp_mb();
-
 	smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
 	invalidate_icache_all();
 
@@ -124,7 +91,13 @@  void handle_ipi(ulong hart)
 	 */
 	ret = riscv_clear_ipi(hart);
 	if (ret) {
-		pr_err("Cannot clear IPI of hart %ld\n", hart);
+		pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret);
+		return;
+	}
+
+	/* Sanity check */
+	if (!smp_function) {
+		pr_err("smp_function is NULL on hart %ld\n", hart);
 		return;
 	}
 
@@ -133,14 +106,11 @@  void handle_ipi(ulong hart)
 
 int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
 {
-	int ret = 0;
-	struct ipi_data ipi;
+	struct ipi_data ipi = {
+		.addr = addr,
+		.arg0 = arg0,
+		.arg1 = arg1,
+	};
 
-	ipi.addr = addr;
-	ipi.arg0 = arg0;
-	ipi.arg1 = arg1;
-
-	ret = send_ipi_many(&ipi, wait);
-
-	return ret;
+	return send_ipi_many(&ipi, wait);
 }