[PATCH] RISC-V: Allow drivers to provide custom read_cycles64 for M-mode kernel

Anup Patel anup.patel at wdc.com
Fri Sep 4 12:21:21 EDT 2020


The TIME CSR is usually not present on most RISC-V systems so the
M-mode firmware will emulate the TIME CSR for the S-mode (MMU) kernel
whereas the M-mode (NoMMU) kernel will have to use MMIO clocksource.

Currently, the get_cycles() implementation in asm/timex.h does not
consider the above fact so we provide alternate implementation of
the get_cycles() for the M-mode (NoMMU) kernel which expects drivers
to provide custom MMIO based read_cycles64() method.

Fixes: 2bc3fc877aa9 ("RISC-V: Remove CLINT related code from timer
and arch")
Signed-off-by: Anup Patel <anup.patel at wdc.com>
---
 arch/riscv/include/asm/timex.h    | 27 +++++++++++++++++++++++++++
 arch/riscv/kernel/time.c          |  3 +++
 drivers/clocksource/timer-clint.c |  2 ++
 3 files changed, 32 insertions(+)

diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h
index a3fb85d505d4..94019b35c050 100644
--- a/arch/riscv/include/asm/timex.h
+++ b/arch/riscv/include/asm/timex.h
@@ -10,6 +10,31 @@
 
 typedef unsigned long cycles_t;
 
+extern u64 (*riscv_read_cycles64)(void);
+
+static inline void riscv_set_read_cycles64(u64 (*read_fn)(void))
+{
+	riscv_read_cycles64 = read_fn;
+}
+
+#ifdef CONFIG_RISCV_M_MODE
+
+static inline cycles_t get_cycles(void)
+{
+	if (riscv_read_cycles64)
+		return riscv_read_cycles64();
+	return 0;
+}
+
+static inline u64 get_cycles64(void)
+{
+	if (riscv_read_cycles64)
+		return riscv_read_cycles64();
+	return 0;
+}
+
+#else /* CONFIG_RISCV_M_MODE */
+
 static inline cycles_t get_cycles(void)
 {
 	return csr_read(CSR_TIME);
@@ -41,6 +66,8 @@ static inline u64 get_cycles64(void)
 }
 #endif /* CONFIG_64BIT */
 
+#endif /* !CONFIG_RISCV_M_MODE */
+
 #define ARCH_HAS_READ_CURRENT_TIMER
 static inline int read_current_timer(unsigned long *timer_val)
 {
diff --git a/arch/riscv/kernel/time.c b/arch/riscv/kernel/time.c
index 4d3a1048ad8b..c9453ab3d5e9 100644
--- a/arch/riscv/kernel/time.c
+++ b/arch/riscv/kernel/time.c
@@ -12,6 +12,9 @@
 unsigned long riscv_timebase;
 EXPORT_SYMBOL_GPL(riscv_timebase);
 
+u64 (*riscv_read_cycles64)(void);
+EXPORT_SYMBOL_GPL(riscv_read_cycles64);
+
 void __init time_init(void)
 {
 	struct device_node *cpu;
diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c
index 8eeafa82c03d..43e31bfd6d23 100644
--- a/drivers/clocksource/timer-clint.c
+++ b/drivers/clocksource/timer-clint.c
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/of_irq.h>
 #include <linux/smp.h>
+#include <linux/timex.h>
 
 #define CLINT_IPI_OFF		0
 #define CLINT_TIMER_CMP_OFF	0x4000
@@ -211,6 +212,7 @@ static int __init clint_timer_init_dt(struct device_node *np)
 	}
 
 	riscv_set_ipi_ops(&clint_ipi_ops);
+	riscv_set_read_cycles64(clint_get_cycles64);
 	clint_clear_ipi();
 
 	return 0;
-- 
2.25.1




More information about the linux-riscv mailing list