Skip to content

Commit d5be89a

Browse files
RISC-V: Resurrect the MMIO timer implementation for M-mode systems
The K210 doesn't implement rdtime in M-mode, and since that's where Linux runs in the NOMMU systems that means we can't use rdtime. The K210 is the only system that anyone is currently running NOMMU or M-mode on, so here we're just inlining the timer read directly. This also adds the CLINT driver as an !MMU dependency, as it's currently the only timer driver availiable for these systems and without it we get a build failure for some configurations. Tested-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Palmer Dabbelt <palmerdabbelt@google.com>
1 parent f025d9d commit d5be89a

4 files changed

Lines changed: 71 additions & 0 deletions

File tree

arch/riscv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ config RISCV
3232
select ARCH_WANT_FRAME_POINTERS
3333
select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
3434
select CLONE_BACKWARDS
35+
select CLINT_TIMER if !MMU
3536
select COMMON_CLK
3637
select EDAC_SUPPORT
3738
select GENERIC_ARCH_TOPOLOGY if SMP

arch/riscv/include/asm/clint.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2020 Google, Inc
4+
*/
5+
6+
#ifndef _ASM_RISCV_CLINT_H
7+
#define _ASM_RISCV_CLINT_H
8+
9+
#include <linux/types.h>
10+
#include <asm/mmio.h>
11+
12+
#ifdef CONFIG_RISCV_M_MODE
13+
/*
14+
* This lives in the CLINT driver, but is accessed directly by timex.h to avoid
15+
* any overhead when accessing the MMIO timer.
16+
*
17+
* The ISA defines mtime as a 64-bit memory-mapped register that increments at
18+
* a constant frequency, but it doesn't define some other constraints we depend
19+
* on (most notably ordering constraints, but also some simpler stuff like the
20+
* memory layout). Thus, this is called "clint_time_val" instead of something
21+
* like "riscv_mtime", to signify that these non-ISA assumptions must hold.
22+
*/
23+
extern u64 __iomem *clint_time_val;
24+
#endif
25+
26+
#endif

arch/riscv/include/asm/timex.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,31 @@
1010

1111
typedef unsigned long cycles_t;
1212

13+
#ifdef CONFIG_RISCV_M_MODE
14+
15+
#include <asm/clint.h>
16+
17+
#ifdef CONFIG_64BIT
18+
static inline cycles_t get_cycles(void)
19+
{
20+
return readq_relaxed(clint_time_val);
21+
}
22+
#else /* !CONFIG_64BIT */
23+
static inline u32 get_cycles(void)
24+
{
25+
return readl_relaxed(((u32 *)clint_time_val));
26+
}
27+
#define get_cycles get_cycles
28+
29+
static inline u32 get_cycles_hi(void)
30+
{
31+
return readl_relaxed(((u32 *)clint_time_val) + 1);
32+
}
33+
#define get_cycles_hi get_cycles_hi
34+
#endif /* CONFIG_64BIT */
35+
36+
#else /* CONFIG_RISCV_M_MODE */
37+
1338
static inline cycles_t get_cycles(void)
1439
{
1540
return csr_read(CSR_TIME);
@@ -41,6 +66,8 @@ static inline u64 get_cycles64(void)
4166
}
4267
#endif /* CONFIG_64BIT */
4368

69+
#endif /* !CONFIG_RISCV_M_MODE */
70+
4471
#define ARCH_HAS_READ_CURRENT_TIMER
4572
static inline int read_current_timer(unsigned long *timer_val)
4673
{

drivers/clocksource/timer-clint.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#include <linux/interrupt.h>
2020
#include <linux/of_irq.h>
2121
#include <linux/smp.h>
22+
#include <linux/timex.h>
23+
24+
#ifndef CONFIG_RISCV_M_MODE
25+
#include <asm/clint.h>
26+
#endif
2227

2328
#define CLINT_IPI_OFF 0
2429
#define CLINT_TIMER_CMP_OFF 0x4000
@@ -31,6 +36,10 @@ static u64 __iomem *clint_timer_val;
3136
static unsigned long clint_timer_freq;
3237
static unsigned int clint_timer_irq;
3338

39+
#ifdef CONFIG_RISCV_M_MODE
40+
u64 __iomem *clint_time_val;
41+
#endif
42+
3443
static void clint_send_ipi(const struct cpumask *target)
3544
{
3645
unsigned int cpu;
@@ -184,6 +193,14 @@ static int __init clint_timer_init_dt(struct device_node *np)
184193
clint_timer_val = base + CLINT_TIMER_VAL_OFF;
185194
clint_timer_freq = riscv_timebase;
186195

196+
#ifdef CONFIG_RISCV_M_MODE
197+
/*
198+
* Yes, that's an odd naming scheme. time_val is public, but hopefully
199+
* will die in favor of something cleaner.
200+
*/
201+
clint_time_val = clint_timer_val;
202+
#endif
203+
187204
pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq);
188205

189206
rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq);

0 commit comments

Comments
 (0)