diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/utils/ipi/fdt_ipi_clint.c | 10 | ||||
-rw-r--r-- | lib/utils/sys/clint.c | 142 | ||||
-rw-r--r-- | lib/utils/timer/fdt_timer_clint.c | 9 |
3 files changed, 110 insertions, 51 deletions
diff --git a/lib/utils/ipi/fdt_ipi_clint.c b/lib/utils/ipi/fdt_ipi_clint.c index 05b66c6..c4ac0df 100644 --- a/lib/utils/ipi/fdt_ipi_clint.c +++ b/lib/utils/ipi/fdt_ipi_clint.c @@ -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[] = { diff --git a/lib/utils/sys/clint.c b/lib/utils/sys/clint.c index 22ba088..7a392aa 100644 --- a/lib/utils/sys/clint.c +++ b/lib/utils/sys/clint.c @@ -10,57 +10,70 @@ #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; } diff --git a/lib/utils/timer/fdt_timer_clint.c b/lib/utils/timer/fdt_timer_clint.c index 6aa6929..2f5f283 100644 --- a/lib/utils/timer/fdt_timer_clint.c +++ b/lib/utils/timer/fdt_timer_clint.c @@ -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[] = { |