diff options
author | Atish Patra <atish.patra@wdc.com> | 2020-05-10 02:47:30 +0300 |
---|---|---|
committer | Anup Patel <anup@brainfault.org> | 2020-05-10 07:44:54 +0300 |
commit | ec0d2a7d7d8b78193375651627aa6f65b9219afe (patch) | |
tree | 4a694ae1b74eb02f5bfb3aa4f2cd35ea93e63f9b | |
parent | 49380244202460aa2fd322dc9a3bdd79b388bf9d (diff) | |
download | opensbi-ec0d2a7d7d8b78193375651627aa6f65b9219afe.tar.xz |
lib: timer: Provide a hart based timer feature
As per the RISC-V specification, time value can be obtained from a time
CSR implemented in hardware or a MMIO based IP block. Qemu virt machine
already supports timer csr while CLINT provides the timer for other
platforms.
Implement a hart specific timer feature that can be detected at runtime.
As CSR based timer implementation are faster than MMIO address based, it
is always preferred over MMIO based one.
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Tested-by: Jonathan Balkind <jbalkind@cs.princeton.edu>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
-rw-r--r-- | include/sbi/sbi_hart.h | 2 | ||||
-rw-r--r-- | lib/sbi/sbi_hart.c | 6 | ||||
-rw-r--r-- | lib/sbi/sbi_timer.c | 29 |
3 files changed, 28 insertions, 9 deletions
diff --git a/include/sbi/sbi_hart.h b/include/sbi/sbi_hart.h index f7870d9..beb61b6 100644 --- a/include/sbi/sbi_hart.h +++ b/include/sbi/sbi_hart.h @@ -20,6 +20,8 @@ enum sbi_hart_features { SBI_HART_HAS_SCOUNTEREN = (1 << 1), /** Hart has M-mode counter enable */ SBI_HART_HAS_MCOUNTEREN = (1 << 2), + /** HART has timer csr implementation in hardware */ + SBI_HART_HAS_TIME = (1 << 3), }; struct sbi_scratch; diff --git a/lib/sbi/sbi_hart.c b/lib/sbi/sbi_hart.c index 10972c8..181cea4 100644 --- a/lib/sbi/sbi_hart.c +++ b/lib/sbi/sbi_hart.c @@ -271,6 +271,12 @@ static void sbi_hart_detect_features(u32 hartid) feature |= SBI_HART_HAS_MCOUNTEREN; } + /* Detect if hart supports time CSR */ + trap.cause = 0; + csr_read_allowed(CSR_TIME, (unsigned long)&trap); + if (!trap.cause) + feature |= SBI_HART_HAS_TIME; + sbi_hart_set_feature(hartid, feature); } diff --git a/lib/sbi/sbi_timer.c b/lib/sbi/sbi_timer.c index 60d9675..4a3ea24 100644 --- a/lib/sbi/sbi_timer.c +++ b/lib/sbi/sbi_timer.c @@ -10,14 +10,16 @@ #include <sbi/riscv_asm.h> #include <sbi/riscv_encoding.h> #include <sbi/sbi_error.h> +#include <sbi/sbi_hart.h> #include <sbi/sbi_platform.h> #include <sbi/sbi_scratch.h> #include <sbi/sbi_timer.h> static unsigned long time_delta_off; +static u64 (*get_time_val)(const struct sbi_platform *plat); #if __riscv_xlen == 32 -u64 get_ticks(void) +static u64 get_ticks(const struct sbi_platform *plat) { u32 lo, hi, tmp; __asm__ __volatile__("1:\n" @@ -29,7 +31,7 @@ u64 get_ticks(void) return ((u64)hi << 32) | lo; } #else -u64 get_ticks(void) +static u64 get_ticks(const struct sbi_platform *plat) { unsigned long n; @@ -40,12 +42,7 @@ u64 get_ticks(void) u64 sbi_timer_value(void) { - const struct sbi_platform *plat = sbi_platform_thishart_ptr(); - - if (sbi_platform_has_timer_value(plat)) - return sbi_platform_timer_value(plat); - else - return get_ticks(); + return get_time_val(sbi_platform_thishart_ptr()); } u64 sbi_timer_virt_value(void) @@ -97,6 +94,8 @@ void sbi_timer_process(void) int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) { u64 *time_delta; + const struct sbi_platform *plat = sbi_platform_ptr(scratch); + int ret; if (cold_boot) { time_delta_off = sbi_scratch_alloc_offset(sizeof(*time_delta), @@ -111,7 +110,19 @@ int sbi_timer_init(struct sbi_scratch *scratch, bool cold_boot) time_delta = sbi_scratch_offset_ptr(scratch, time_delta_off); *time_delta = 0; - return sbi_platform_timer_init(sbi_platform_ptr(scratch), cold_boot); + ret = sbi_platform_timer_init(plat, cold_boot); + if (ret) + return ret; + + if (sbi_hart_has_feature(current_hartid(), SBI_HART_HAS_TIME)) + get_time_val = get_ticks; + else if (sbi_platform_has_timer_value(plat)) + get_time_val = sbi_platform_timer_value; + else + /* There is no method to provide timer value */ + return SBI_ENODEV; + + return 0; } void sbi_timer_exit(struct sbi_scratch *scratch) |