Skip to content

Commit

Permalink
RISC-V: Resurrect the MMIO timer implementation for M-mode systems
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Palmer Dabbelt <[email protected]>
  • Loading branch information
palmer-dabbelt committed Sep 19, 2020
1 parent f025d9d commit d5be89a
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 0 deletions.
1 change: 1 addition & 0 deletions arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ config RISCV
select ARCH_WANT_FRAME_POINTERS
select ARCH_WANT_HUGE_PMD_SHARE if 64BIT
select CLONE_BACKWARDS
select CLINT_TIMER if !MMU
select COMMON_CLK
select EDAC_SUPPORT
select GENERIC_ARCH_TOPOLOGY if SMP
Expand Down
26 changes: 26 additions & 0 deletions arch/riscv/include/asm/clint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2020 Google, Inc
*/

#ifndef _ASM_RISCV_CLINT_H
#define _ASM_RISCV_CLINT_H

#include <linux/types.h>
#include <asm/mmio.h>

#ifdef CONFIG_RISCV_M_MODE
/*
* This lives in the CLINT driver, but is accessed directly by timex.h to avoid
* any overhead when accessing the MMIO timer.
*
* The ISA defines mtime as a 64-bit memory-mapped register that increments at
* a constant frequency, but it doesn't define some other constraints we depend
* on (most notably ordering constraints, but also some simpler stuff like the
* memory layout). Thus, this is called "clint_time_val" instead of something
* like "riscv_mtime", to signify that these non-ISA assumptions must hold.
*/
extern u64 __iomem *clint_time_val;
#endif

#endif
27 changes: 27 additions & 0 deletions arch/riscv/include/asm/timex.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,31 @@

typedef unsigned long cycles_t;

#ifdef CONFIG_RISCV_M_MODE

#include <asm/clint.h>

#ifdef CONFIG_64BIT
static inline cycles_t get_cycles(void)
{
return readq_relaxed(clint_time_val);
}
#else /* !CONFIG_64BIT */
static inline u32 get_cycles(void)
{
return readl_relaxed(((u32 *)clint_time_val));
}
#define get_cycles get_cycles

static inline u32 get_cycles_hi(void)
{
return readl_relaxed(((u32 *)clint_time_val) + 1);
}
#define get_cycles_hi get_cycles_hi
#endif /* CONFIG_64BIT */

#else /* CONFIG_RISCV_M_MODE */

static inline cycles_t get_cycles(void)
{
return csr_read(CSR_TIME);
Expand Down Expand Up @@ -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)
{
Expand Down
17 changes: 17 additions & 0 deletions drivers/clocksource/timer-clint.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/smp.h>
#include <linux/timex.h>

#ifndef CONFIG_RISCV_M_MODE
#include <asm/clint.h>
#endif

#define CLINT_IPI_OFF 0
#define CLINT_TIMER_CMP_OFF 0x4000
Expand All @@ -31,6 +36,10 @@ static u64 __iomem *clint_timer_val;
static unsigned long clint_timer_freq;
static unsigned int clint_timer_irq;

#ifdef CONFIG_RISCV_M_MODE
u64 __iomem *clint_time_val;
#endif

static void clint_send_ipi(const struct cpumask *target)
{
unsigned int cpu;
Expand Down Expand Up @@ -184,6 +193,14 @@ static int __init clint_timer_init_dt(struct device_node *np)
clint_timer_val = base + CLINT_TIMER_VAL_OFF;
clint_timer_freq = riscv_timebase;

#ifdef CONFIG_RISCV_M_MODE
/*
* Yes, that's an odd naming scheme. time_val is public, but hopefully
* will die in favor of something cleaner.
*/
clint_time_val = clint_timer_val;
#endif

pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq);

rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq);
Expand Down

0 comments on commit d5be89a

Please sign in to comment.