lib: utils: Allow CLINT functions to be used for multiple CLINTs
authorAnup Patel <anup.patel@wdc.com>
Tue, 12 May 2020 13:08:31 +0000 (18:38 +0530)
committerAnup Patel <anup@brainfault.org>
Sat, 23 May 2020 05:06:43 +0000 (10:36 +0530)
We extend CLINT cold init function to have a "struct clint_data *"
parameter pointing to CLINT details. This allows platforms to use
CLINT functions for multiple CLINT instances.

When multiple CLINTs are present, the platform can also provide
one of the CLINT as reference CLINT for other CLINTs. This will
help CLINTs to sync their time value with reference CLINT using
a time_delta computed in warm init function.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
include/sbi_utils/sys/clint.h
lib/utils/ipi/fdt_ipi_clint.c
lib/utils/sys/clint.c
lib/utils/timer/fdt_timer_clint.c
platform/fpga/ariane/platform.c
platform/fpga/openpiton/platform.c
platform/kendryte/k210/platform.c
platform/nuclei/ux600/platform.c
platform/sifive/fu540/platform.c
platform/template/platform.c
platform/thead/c910/platform.c

index a26f148..b07cf62 100644 (file)
 
 #include <sbi/sbi_types.h>
 
+struct clint_data {
+       /* Public details */
+       unsigned long addr;
+       u32 first_hartid;
+       u32 hart_count;
+       bool has_64bit_mmio;
+       /* Private details (initialized and used by CLINT library)*/
+       u32 *ipi;
+       struct clint_data *time_delta_reference;
+       unsigned long time_delta_computed;
+       u64 time_delta;
+       u64 *time_val;
+       u64 *time_cmp;
+       u64 (*time_rd)(volatile u64 *addr);
+       void (*time_wr)(u64 value, volatile u64 *addr);
+};
+
 void clint_ipi_send(u32 target_hart);
 
 void clint_ipi_clear(u32 target_hart);
 
 int clint_warm_ipi_init(void);
 
-int clint_cold_ipi_init(unsigned long base, u32 hart_count);
+int clint_cold_ipi_init(struct clint_data *clint);
 
 u64 clint_timer_value(void);
 
@@ -28,7 +45,7 @@ void clint_timer_event_start(u64 next_event);
 
 int clint_warm_timer_init(void);
 
-int clint_cold_timer_init(unsigned long base, u32 hart_count,
-                         bool has_64bit_mmio);
+int clint_cold_timer_init(struct clint_data *clint,
+                         struct clint_data *reference);
 
 #endif
index 05b66c6..c4ac0df 100644 (file)
@@ -11,6 +11,8 @@
 #include <sbi_utils/ipi/fdt_ipi.h>
 #include <sbi_utils/sys/clint.h>
 
+static struct clint_data clint_ipi;
+
 static int ipi_clint_cold_init(void *fdt, int nodeoff,
                               const struct fdt_match *match)
 {
@@ -26,7 +28,13 @@ static int ipi_clint_cold_init(void *fdt, int nodeoff,
        if (rc)
                return rc;
 
-       return clint_cold_ipi_init(addr, max_hartid + 1);
+       /* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
+       clint_ipi.addr = addr;
+       clint_ipi.first_hartid = 0;
+       clint_ipi.hart_count = max_hartid + 1;
+       clint_ipi.has_64bit_mmio = TRUE;
+
+       return clint_cold_ipi_init(&clint_ipi);
 }
 
 static const struct fdt_match ipi_clint_match[] = {
index 22ba088..7a392aa 100644 (file)
 #include <sbi/riscv_asm.h>
 #include <sbi/riscv_atomic.h>
 #include <sbi/riscv_io.h>
+#include <sbi/sbi_error.h>
+#include <sbi/sbi_hartmask.h>
 #include <sbi_utils/sys/clint.h>
 
-static u32 clint_ipi_hart_count;
-static volatile void *clint_ipi_base;
-static volatile u32 *clint_ipi;
+#define CLINT_IPI_OFF          0
+#define CLINT_TIME_CMP_OFF     0x4000
+#define CLINT_TIME_VAL_OFF     0xbff8
+
+static struct clint_data *clint_ipi_hartid2data[SBI_HARTMASK_MAX_BITS];
 
 void clint_ipi_send(u32 target_hart)
 {
-       if (clint_ipi_hart_count <= target_hart)
+       struct clint_data *clint;
+
+       if (SBI_HARTMASK_MAX_BITS <= target_hart)
+               return;
+       clint = clint_ipi_hartid2data[target_hart];
+       if (!clint)
                return;
 
        /* Set CLINT IPI */
-       writel(1, &clint_ipi[target_hart]);
+       writel(1, &clint->ipi[target_hart - clint->first_hartid]);
 }
 
 void clint_ipi_clear(u32 target_hart)
 {
-       if (clint_ipi_hart_count <= target_hart)
+       struct clint_data *clint;
+
+       if (SBI_HARTMASK_MAX_BITS <= target_hart)
+               return;
+       clint = clint_ipi_hartid2data[target_hart];
+       if (!clint)
                return;
 
        /* Clear CLINT IPI */
-       writel(0, &clint_ipi[target_hart]);
+       writel(0, &clint->ipi[target_hart - clint->first_hartid]);
 }
 
 int clint_warm_ipi_init(void)
 {
-       u32 hartid = current_hartid();
-
-       if (!clint_ipi_base)
-               return -1;
-
-       /* Clear CLINT IPI */
-       clint_ipi_clear(hartid);
+       /* Clear CLINT IPI for current HART */
+       clint_ipi_clear(current_hartid());
 
        return 0;
 }
 
-int clint_cold_ipi_init(unsigned long base, u32 hart_count)
+int clint_cold_ipi_init(struct clint_data *clint)
 {
-       /* Figure-out CLINT IPI register address */
-       clint_ipi_hart_count = hart_count;
-       clint_ipi_base       = (void *)base;
-       clint_ipi            = (u32 *)clint_ipi_base;
+       u32 i;
+
+       if (!clint)
+               return SBI_EINVAL;
+
+       /* Initialize private data */
+       clint->ipi = (void *)clint->addr;
+
+       /* Update IPI hartid table */
+       for (i = 0; i < clint->hart_count; i++)
+               clint_ipi_hartid2data[clint->first_hartid + i] = clint;
 
        return 0;
 }
 
-static u32 clint_time_hart_count;
-static volatile void *clint_time_base;
-static volatile u64 *clint_time_val;
-static volatile u64 *clint_time_cmp;
+static struct clint_data *clint_timer_hartid2data[SBI_HARTMASK_MAX_BITS];
 
 #if __riscv_xlen != 32
 static u64 clint_time_rd64(volatile u64 *addr)
@@ -94,66 +107,97 @@ static void clint_time_wr32(u64 value, volatile u64 *addr)
        writel_relaxed(value >> 32, (void *)(addr) + 0x04);
 }
 
-static u64 (*clint_time_rd)(volatile u64 *addr) = clint_time_rd32;
-static void (*clint_time_wr)(u64 value, volatile u64 *addr) = clint_time_wr32;
-
 u64 clint_timer_value(void)
 {
+       struct clint_data *clint = clint_timer_hartid2data[current_hartid()];
+
        /* Read CLINT Time Value */
-       return clint_time_rd(clint_time_val);
+       return clint->time_rd(clint->time_val) + clint->time_delta;
 }
 
 void clint_timer_event_stop(void)
 {
        u32 target_hart = current_hartid();
-
-       if (clint_time_hart_count <= target_hart)
-               return;
+       struct clint_data *clint = clint_timer_hartid2data[target_hart];
 
        /* Clear CLINT Time Compare */
-       clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
+       clint->time_wr(-1ULL,
+                       &clint->time_cmp[target_hart - clint->first_hartid]);
 }
 
 void clint_timer_event_start(u64 next_event)
 {
        u32 target_hart = current_hartid();
-
-       if (clint_time_hart_count <= target_hart)
-               return;
+       struct clint_data *clint = clint_timer_hartid2data[target_hart];
 
        /* Program CLINT Time Compare */
-       clint_time_wr(next_event, &clint_time_cmp[target_hart]);
+       clint->time_wr(next_event - clint->time_delta,
+                      &clint->time_cmp[target_hart - clint->first_hartid]);
 }
 
 int clint_warm_timer_init(void)
 {
+       u64 v1, v2, mv;
        u32 target_hart = current_hartid();
-
-       if (clint_time_hart_count <= target_hart || !clint_time_base)
-               return -1;
+       struct clint_data *reference;
+       struct clint_data *clint = clint_timer_hartid2data[target_hart];
+
+       if (!clint)
+               return SBI_ENODEV;
+
+       /*
+        * Compute delta if reference available
+        *
+        * We deliberately compute time_delta in warm init so that time_delta
+        * is computed on a HART which is going to use given CLINT. We use
+        * atomic flag timer_delta_computed to ensure that only one HART does
+        * time_delta computation.
+        */
+       if (clint->time_delta_reference) {
+               reference = clint->time_delta_reference;
+               if (!atomic_raw_xchg_ulong(&clint->time_delta_computed, 1)) {
+                       v1 = clint->time_rd(clint->time_val);
+                       mv = reference->time_rd(reference->time_val);
+                       v2 = clint->time_rd(clint->time_val);
+                       clint->time_delta = mv - ((v1 / 2) + (v2 / 2));
+               }
+       }
 
        /* Clear CLINT Time Compare */
-       clint_time_wr(-1ULL, &clint_time_cmp[target_hart]);
+       clint->time_wr(-1ULL,
+                      &clint->time_cmp[target_hart - clint->first_hartid]);
 
        return 0;
 }
 
-int clint_cold_timer_init(unsigned long base, u32 hart_count,
-                         bool has_64bit_mmio)
+int clint_cold_timer_init(struct clint_data *clint,
+                         struct clint_data *reference)
 {
-       /* Figure-out CLINT Time register address */
-       clint_time_hart_count           = hart_count;
-       clint_time_base                 = (void *)base;
-       clint_time_val                  = (u64 *)(clint_time_base + 0xbff8);
-       clint_time_cmp                  = (u64 *)(clint_time_base + 0x4000);
+       u32 i;
+
+       if (!clint)
+               return SBI_EINVAL;
+
+       /* Initialize private data */
+       clint->time_delta_reference = reference;
+       clint->time_delta_computed = 0;
+       clint->time_delta = 0;
+       clint->time_val = (u64 *)((void *)clint->addr + CLINT_TIME_VAL_OFF);
+       clint->time_cmp = (u64 *)((void *)clint->addr + CLINT_TIME_CMP_OFF);
+       clint->time_rd = clint_time_rd32;
+       clint->time_wr = clint_time_wr32;
 
        /* Override read/write accessors for 64bit MMIO */
 #if __riscv_xlen != 32
-       if (has_64bit_mmio) {
-               clint_time_rd           = clint_time_rd64;
-               clint_time_wr           = clint_time_wr64;
+       if (clint->has_64bit_mmio) {
+               clint->time_rd = clint_time_rd64;
+               clint->time_wr = clint_time_wr64;
        }
 #endif
 
+       /* Update timer hartid table */
+       for (i = 0; i < clint->hart_count; i++)
+               clint_timer_hartid2data[clint->first_hartid + i] = clint;
+
        return 0;
 }
index 6aa6929..2f5f283 100644 (file)
@@ -11,6 +11,8 @@
 #include <sbi_utils/timer/fdt_timer.h>
 #include <sbi_utils/sys/clint.h>
 
+static struct clint_data clint_timer;
+
 static int timer_clint_cold_init(void *fdt, int nodeoff,
                                  const struct fdt_match *match)
 {
@@ -27,7 +29,12 @@ static int timer_clint_cold_init(void *fdt, int nodeoff,
                return rc;
 
        /* TODO: We should figure-out CLINT has_64bit_mmio from DT node */
-       return clint_cold_timer_init(addr, max_hartid + 1, TRUE);
+       clint_timer.addr = addr;
+       clint_timer.first_hartid = 0;
+       clint_timer.hart_count = max_hartid + 1;
+       clint_timer.has_64bit_mmio = TRUE;
+
+       return clint_cold_timer_init(&clint_timer, NULL);
 }
 
 static const struct fdt_match timer_clint_match[] = {
index 275f2ce..a4d437e 100644 (file)
 #define ARIANE_PLIC_ADDR                       0xc000000
 #define ARIANE_PLIC_NUM_SOURCES                        3
 #define ARIANE_HART_COUNT                      1
-#define ARIANE_CLINT_ADDR 0x2000000
+#define ARIANE_CLINT_ADDR                      0x2000000
 
 static struct plic_data plic = {
        .addr = ARIANE_PLIC_ADDR,
        .num_src = ARIANE_PLIC_NUM_SOURCES,
 };
 
+static struct clint_data clint = {
+       .addr = ARIANE_CLINT_ADDR,
+       .first_hartid = 0,
+       .hart_count = ARIANE_HART_COUNT,
+       .has_64bit_mmio = TRUE,
+};
+
 /*
  * Ariane platform early initialization.
  */
@@ -116,8 +123,7 @@ static int ariane_ipi_init(bool cold_boot)
        int ret;
 
        if (cold_boot) {
-               ret = clint_cold_ipi_init(ARIANE_CLINT_ADDR,
-                                         ARIANE_HART_COUNT);
+               ret = clint_cold_ipi_init(&clint);
                if (ret)
                        return ret;
        }
@@ -133,8 +139,7 @@ static int ariane_timer_init(bool cold_boot)
        int ret;
 
        if (cold_boot) {
-               ret = clint_cold_timer_init(ARIANE_CLINT_ADDR,
-                                           ARIANE_HART_COUNT, TRUE);
+               ret = clint_cold_timer_init(&clint, NULL);
                if (ret)
                        return ret;
        }
index e56ee51..095004d 100644 (file)
@@ -35,7 +35,13 @@ static struct plic_data plic = {
        .addr = OPENPITON_DEFAULT_PLIC_ADDR,
        .num_src = OPENPITON_DEFAULT_PLIC_NUM_SOURCES,
 };
-static unsigned long clint_addr = OPENPITON_DEFAULT_CLINT_ADDR;
+
+static struct clint_data clint = {
+       .addr = OPENPITON_DEFAULT_CLINT_ADDR,
+       .first_hartid = 0,
+       .hart_count = OPENPITON_DEFAULT_HART_COUNT,
+       .has_64bit_mmio = TRUE,
+};
 
 /*
  * OpenPiton platform early initialization.
@@ -45,7 +51,7 @@ static int openpiton_early_init(bool cold_boot)
        void *fdt;
        struct platform_uart_data uart_data;
        struct plic_data plic_data;
-       unsigned long clint_data;
+       unsigned long clint_addr;
        int rc;
 
        if (!cold_boot)
@@ -60,9 +66,9 @@ static int openpiton_early_init(bool cold_boot)
        if (!rc)
                plic = plic_data;
 
-       rc = fdt_parse_compat_addr(fdt, &clint_data, "riscv,clint0");
+       rc = fdt_parse_compat_addr(fdt, &clint_addr, "riscv,clint0");
        if (!rc)
-               clint_addr = clint_data;
+               clint.addr = clint_addr;
 
        return 0;
 }
@@ -143,8 +149,7 @@ static int openpiton_ipi_init(bool cold_boot)
        int ret;
 
        if (cold_boot) {
-               ret = clint_cold_ipi_init(clint_addr,
-                                         OPENPITON_DEFAULT_HART_COUNT);
+               ret = clint_cold_ipi_init(&clint);
                if (ret)
                        return ret;
        }
@@ -160,8 +165,7 @@ static int openpiton_timer_init(bool cold_boot)
        int ret;
 
        if (cold_boot) {
-               ret = clint_cold_timer_init(clint_addr,
-                                           OPENPITON_DEFAULT_HART_COUNT, TRUE);
+               ret = clint_cold_timer_init(&clint, NULL);
                if (ret)
                        return ret;
        }
index db2186a..ef0f18f 100644 (file)
@@ -22,6 +22,13 @@ static struct plic_data plic = {
        .num_src = K210_PLIC_NUM_SOURCES,
 };
 
+static struct clint_data clint = {
+       .addr = K210_CLINT_BASE_ADDR,
+       .first_hartid = 0,
+       .hart_count = K210_HART_COUNT,
+       .has_64bit_mmio = TRUE,
+};
+
 static u32 k210_get_clk_freq(void)
 {
        u32 clksel0, pll0;
@@ -76,8 +83,7 @@ static int k210_ipi_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_ipi_init(K210_CLINT_BASE_ADDR,
-                                        K210_HART_COUNT);
+               rc = clint_cold_ipi_init(&clint);
                if (rc)
                        return rc;
        }
@@ -90,8 +96,7 @@ static int k210_timer_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_timer_init(K210_CLINT_BASE_ADDR,
-                                          K210_HART_COUNT, TRUE);
+               rc = clint_cold_timer_init(&clint, NULL);
                if (rc)
                        return rc;
        }
index f999c99..ad4ba2b 100644 (file)
@@ -48,6 +48,13 @@ static struct plic_data plic = {
        .num_src = UX600_PLIC_NUM_SOURCES,
 };
 
+static struct clint_data clint = {
+       .addr = UX600_CLINT_TIMER_ADDR,
+       .first_hartid = 0,
+       .hart_count = UX600_HART_COUNT,
+       .has_64bit_mmio = TRUE,
+};
+
 static void ux600_modify_dt(void *fdt)
 {
        fdt_fixups(fdt);
@@ -92,7 +99,7 @@ static int ux600_ipi_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_ipi_init(UX600_CLINT_TIMER_ADDR, UX600_HART_COUNT);
+               rc = clint_cold_ipi_init(&clint);
                if (rc)
                        return rc;
        }
@@ -105,8 +112,7 @@ static int ux600_timer_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_timer_init(UX600_CLINT_TIMER_ADDR,
-                                          UX600_HART_COUNT, TRUE);
+               rc = clint_cold_timer_init(&clint, NULL);
                if (rc)
                        return rc;
        }
index 7a62fc3..48d887f 100644 (file)
@@ -51,6 +51,13 @@ static struct plic_data plic = {
        .num_src = FU540_PLIC_NUM_SOURCES,
 };
 
+static struct clint_data clint = {
+       .addr = FU540_CLINT_ADDR,
+       .first_hartid = 0,
+       .hart_count = FU540_HART_COUNT,
+       .has_64bit_mmio = TRUE,
+};
+
 static void fu540_modify_dt(void *fdt)
 {
        fdt_cpu_fixup(fdt);
@@ -107,7 +114,7 @@ static int fu540_ipi_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_ipi_init(FU540_CLINT_ADDR, FU540_HART_COUNT);
+               rc = clint_cold_ipi_init(&clint);
                if (rc)
                        return rc;
        }
@@ -125,8 +132,7 @@ static int fu540_timer_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_timer_init(FU540_CLINT_ADDR,
-                                          FU540_HART_COUNT, TRUE);
+               rc = clint_cold_timer_init(&clint, NULL);
                if (rc)
                        return rc;
        }
index c845380..9cd750e 100644 (file)
 #include <sbi_utils/serial/uart8250.h>
 #include <sbi_utils/sys/clint.h>
 
-#define PLATFORM_PLIC_ADDR                     0xc000000
-#define PLATFORM_PLIC_NUM_SOURCES              128
-#define PLATFORM_HART_COUNT                    4
-#define PLATFORM_CLINT_ADDR                    0x2000000
+#define PLATFORM_PLIC_ADDR             0xc000000
+#define PLATFORM_PLIC_NUM_SOURCES      128
+#define PLATFORM_HART_COUNT            4
+#define PLATFORM_CLINT_ADDR            0x2000000
 #define PLATFORM_UART_ADDR             0x09000000
 #define PLATFORM_UART_INPUT_FREQ       10000000
 #define PLATFORM_UART_BAUDRATE         115200
@@ -30,6 +30,13 @@ static struct plic_data plic = {
        .num_src = PLATFORM_PLIC_NUM_SOURCES,
 };
 
+static struct clint_data clint = {
+       .addr = PLATFORM_CLINT_ADDR,
+       .first_hartid = 0,
+       .hart_count = PLATFORM_HART_COUNT,
+       .has_64bit_mmio = TRUE,
+};
+
 /*
  * Platform early initialization.
  */
@@ -100,8 +107,7 @@ static int platform_ipi_init(bool cold_boot)
 
        /* Example if the generic CLINT driver is used */
        if (cold_boot) {
-               ret = clint_cold_ipi_init(PLATFORM_CLINT_ADDR,
-                                         PLATFORM_HART_COUNT);
+               ret = clint_cold_ipi_init(&clint, NULL);
                if (ret)
                        return ret;
        }
@@ -136,8 +142,7 @@ static int platform_timer_init(bool cold_boot)
 
        /* Example if the generic CLINT driver is used */
        if (cold_boot) {
-               ret = clint_cold_timer_init(PLATFORM_CLINT_ADDR,
-                                           PLATFORM_HART_COUNT, TRUE);
+               ret = clint_cold_timer_init(&clint);
                if (ret)
                        return ret;
        }
index 82f910a..df7658a 100644 (file)
 
 static struct c910_regs_struct c910_regs;
 
+static struct clint_data clint = {
+       .addr = 0, /* Updated at cold boot time */
+       .first_hartid = 0,
+       .hart_count = C910_HART_COUNT,
+       .has_64bit_mmio = FALSE,
+};
+
 static int c910_early_init(bool cold_boot)
 {
        if (cold_boot) {
@@ -78,7 +85,8 @@ static int c910_ipi_init(bool cold_boot)
        int rc;
 
        if (cold_boot) {
-               rc = clint_cold_ipi_init(c910_regs.clint_base_addr, C910_HART_COUNT);
+               clint.addr = c910_regs.clint_base_addr;
+               rc = clint_cold_ipi_init(&clint);
                if (rc)
                        return rc;
        }
@@ -91,8 +99,8 @@ static int c910_timer_init(bool cold_boot)
        int ret;
 
        if (cold_boot) {
-               ret = clint_cold_timer_init(c910_regs.clint_base_addr,
-                                       C910_HART_COUNT, FALSE);
+               clint.addr = c910_regs.clint_base_addr;
+               ret = clint_cold_timer_init(&clint, NULL);
                if (ret)
                        return ret;
        }