riscv: memcpy: check src and dst before copy
[platform/kernel/u-boot.git] / arch / riscv / lib / smp.c
index 7054378..4f073a0 100644 (file)
@@ -8,35 +8,16 @@
 #include <cpu_func.h>
 #include <dm.h>
 #include <asm/barrier.h>
+#include <asm/global_data.h>
 #include <asm/smp.h>
 
 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);
-
-static int send_ipi_many(struct ipi_data *ipi)
+static int send_ipi_many(struct ipi_data *ipi, int wait)
 {
        ofnode node, cpus;
        u32 reg;
-       int ret;
+       int ret, pending;
 
        cpus = ofnode_path("/cpus");
        if (!ofnode_valid(cpus)) {
@@ -46,7 +27,7 @@ static int send_ipi_many(struct ipi_data *ipi)
 
        ofnode_for_each_subnode(node, cpus) {
                /* skip if hart is marked as not available in the device tree */
-               if (!ofnode_is_available(node))
+               if (!ofnode_is_enabled(node))
                        continue;
 
                /* read hart ID of CPU */
@@ -64,21 +45,40 @@ static int send_ipi_many(struct ipi_data *ipi)
                        continue;
                }
 
-#ifndef CONFIG_XIP
+#if !CONFIG_IS_ENABLED(XIP)
+#ifdef CONFIG_AVAILABLE_HARTS
                /* skip if hart is not available */
                if (!(gd->arch.available_harts & (1 << reg)))
                        continue;
 #endif
+#endif
 
                gd->arch.ipi[reg].addr = ipi->addr;
                gd->arch.ipi[reg].arg0 = ipi->arg0;
                gd->arch.ipi[reg].arg1 = ipi->arg1;
 
+               /*
+                * Ensure valid only becomes set when the IPI parameters are
+                * set. An IPI may already be pending on other harts, so we
+                * need a way to signal that the IPI device has been
+                * initialized, and that it is ok to call the function.
+                */
+               __smp_store_release(&gd->arch.ipi[reg].valid, 1);
+
                ret = riscv_send_ipi(reg);
                if (ret) {
                        pr_err("Cannot send IPI to hart %d\n", reg);
                        return ret;
                }
+
+               if (wait) {
+                       pending = 1;
+                       while (pending) {
+                               ret = riscv_get_ipi(reg, &pending);
+                               if (ret)
+                                       return ret;
+                       }
+               }
        }
 
        return 0;
@@ -92,30 +92,37 @@ void handle_ipi(ulong hart)
        if (hart >= CONFIG_NR_CPUS)
                return;
 
-       ret = riscv_clear_ipi(hart);
-       if (ret) {
-               pr_err("Cannot clear IPI of hart %ld\n", hart);
+       /*
+        * If valid is not set, then U-Boot has not requested the IPI. The
+        * IPI device may not be initialized, so all we can do is wait for
+        * U-Boot to initialize it and send an IPI
+        */
+       if (!__smp_load_acquire(&gd->arch.ipi[hart].valid))
                return;
-       }
-
-       __smp_mb();
 
        smp_function = (void (*)(ulong, ulong, ulong))gd->arch.ipi[hart].addr;
        invalidate_icache_all();
 
+       /*
+        * Clear the IPI to acknowledge the request before jumping to the
+        * requested function.
+        */
+       ret = riscv_clear_ipi(hart);
+       if (ret) {
+               pr_err("Cannot clear IPI of hart %ld (error %d)\n", hart, ret);
+               return;
+       }
+
        smp_function(hart, gd->arch.ipi[hart].arg0, gd->arch.ipi[hart].arg1);
 }
 
-int smp_call_function(ulong addr, ulong arg0, ulong arg1)
+int smp_call_function(ulong addr, ulong arg0, ulong arg1, int wait)
 {
-       int ret = 0;
-       struct ipi_data ipi;
-
-       ipi.addr = addr;
-       ipi.arg0 = arg0;
-       ipi.arg1 = arg1;
-
-       ret = send_ipi_many(&ipi);
+       struct ipi_data ipi = {
+               .addr = addr,
+               .arg0 = arg0,
+               .arg1 = arg1,
+       };
 
-       return ret;
+       return send_ipi_many(&ipi, wait);
 }