diff mbox series

[v11,14/21] riscv: Clean up IPI initialization code

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

Commit Message

Sean Anderson May 20, 2020, 6:41 a.m. UTC
The previous IPI code initialized the device whenever the first call was
made to a riscv_*_ipi function. This made it difficult to determine when
the IPI device was initialized. This patch introduces a new function
riscv_init_ipi. It is called once during arch_cpu_init_dm. In SPL, it is
called in spl_invoke_opensbi. Before this point, no riscv_*_ipi functions
should be called.

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Rick Chen <rick@andestech.com>
---

Changes in v11:
- Initialize IPI when used by SPL
Changes in v9:
- Fix type of ret variable in riscv_ipi_init
Changes in v7:
- Split IPI clearing off into its own patch

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/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 ++++++++---------------------------
 common/spl/spl_opensbi.c      |  5 ++++
 7 files changed, 95 insertions(+), 87 deletions(-)

Comments

Rick Chen May 20, 2020, 7:52 a.m. UTC | #1
Hi Sean

> The previous IPI code initialized the device whenever the first call was
> made to a riscv_*_ipi function. This made it difficult to determine when
> the IPI device was initialized. This patch introduces a new function
> riscv_init_ipi. It is called once during arch_cpu_init_dm. In SPL, it is
> called in spl_invoke_opensbi. Before this point, no riscv_*_ipi functions
> should be called.
>
> Signed-off-by: Sean Anderson <seanga2@gmail.com>
> Reviewed-by: Rick Chen <rick@andestech.com>
> ---
>
> Changes in v11:
> - Initialize IPI when used by SPL
> Changes in v9:
> - Fix type of ret variable in riscv_ipi_init
> Changes in v7:
> - Split IPI clearing off into its own patch
>
> 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/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 ++++++++---------------------------
>  common/spl/spl_opensbi.c      |  5 ++++
>  7 files changed, 95 insertions(+), 87 deletions(-)
>
> diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
> index 5804aa8e73..d75a3f045a 100644
> --- a/arch/riscv/cpu/cpu.c
> +++ b/arch/riscv/cpu/cpu.c
> @@ -98,6 +98,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/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..5cf29df670 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)
> +{
> +       long *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 abafca9e5c..d02e2b4c48 100644
> --- a/arch/riscv/lib/sbi_ipi.c
> +++ b/arch/riscv/lib/sbi_ipi.c
> @@ -8,6 +8,11 @@
>  #include <asm/encoding.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;
>         }

Please remove this Sanity check,
https://patchwork.ozlabs.org/project/uboot/patch/20200503024637.327733-15-seanga2@gmail.com/

Thanks,
Rick

>
> @@ -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);
>  }
> diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c
> index e88136e6f3..defddac8f2 100644
> --- a/common/spl/spl_opensbi.c
> +++ b/common/spl/spl_opensbi.c
> @@ -79,6 +79,11 @@ void spl_invoke_opensbi(struct spl_image_info *spl_image)
>         invalidate_icache_all();
>
>  #ifdef CONFIG_SPL_SMP
> +       /* Initialize the IPI before we use it */
> +       ret = riscv_init_ipi();
> +       if (ret)
> +               hang();
> +
>         /*
>          * Start OpenSBI on all secondary harts and wait for acknowledgment.
>          *
> --
> 2.26.2
>
diff mbox series

Patch

diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index 5804aa8e73..d75a3f045a 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -98,6 +98,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/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..5cf29df670 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)
+{
+	long *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 abafca9e5c..d02e2b4c48 100644
--- a/arch/riscv/lib/sbi_ipi.c
+++ b/arch/riscv/lib/sbi_ipi.c
@@ -8,6 +8,11 @@ 
 #include <asm/encoding.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);
 }
diff --git a/common/spl/spl_opensbi.c b/common/spl/spl_opensbi.c
index e88136e6f3..defddac8f2 100644
--- a/common/spl/spl_opensbi.c
+++ b/common/spl/spl_opensbi.c
@@ -79,6 +79,11 @@  void spl_invoke_opensbi(struct spl_image_info *spl_image)
 	invalidate_icache_all();
 
 #ifdef CONFIG_SPL_SMP
+	/* Initialize the IPI before we use it */
+	ret = riscv_init_ipi();
+	if (ret)
+		hang();
+
 	/*
 	 * Start OpenSBI on all secondary harts and wait for acknowledgment.
 	 *