Source
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2012 Regents of the University of California
* Copyright (C) 2017 SiFive
*/
/*
* All RISC-V systems have a timer attached to every hart. These timers can be
* read by the 'rdcycle' pseudo instruction, and can use the SBI to setup
* events. In order to abstract the architecture-specific timer reading and
* setting functions away from the clock event insertion code, we provide
* function pointers to the clockevent subsystem that perform two basic
* operations: rdtime() reads the timer on the current CPU, and
* next_event(delta) sets the next timer event to 'delta' cycles in the future.
* As the timers are inherently a per-cpu resource, these callbacks perform
* operations on the current hart. There is guaranteed to be exactly one timer
* per hart on all RISC-V systems.
*/
static int riscv_clock_next_event(unsigned long delta,
struct clock_event_device *ce)
{
csr_set(sie, SIE_STIE);
sbi_set_timer(get_cycles64() + delta);
return 0;
}
static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
.name = "riscv_timer_clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT,
.rating = 100,
.set_next_event = riscv_clock_next_event,
};
/*
* It is guaranteed that all the timers across all the harts are synchronized
* within one tick of each other, so while this could technically go
* backwards when hopping between CPUs, practically it won't happen.
*/
static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs)
{
return get_cycles64();
}
static u64 riscv_sched_clock(void)
{
return get_cycles64();
}
static DEFINE_PER_CPU(struct clocksource, riscv_clocksource) = {
.name = "riscv_clocksource",
.rating = 300,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.read = riscv_clocksource_rdtime,