cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

timer-riscv.c (4618B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2012 Regents of the University of California
      4 * Copyright (C) 2017 SiFive
      5 *
      6 * All RISC-V systems have a timer attached to every hart.  These timers can
      7 * either be read from the "time" and "timeh" CSRs, and can use the SBI to
      8 * setup events, or directly accessed using MMIO registers.
      9 */
     10#include <linux/clocksource.h>
     11#include <linux/clockchips.h>
     12#include <linux/cpu.h>
     13#include <linux/delay.h>
     14#include <linux/irq.h>
     15#include <linux/irqdomain.h>
     16#include <linux/module.h>
     17#include <linux/sched_clock.h>
     18#include <linux/io-64-nonatomic-lo-hi.h>
     19#include <linux/interrupt.h>
     20#include <linux/of_irq.h>
     21#include <clocksource/timer-riscv.h>
     22#include <asm/smp.h>
     23#include <asm/sbi.h>
     24#include <asm/timex.h>
     25
     26static int riscv_clock_next_event(unsigned long delta,
     27		struct clock_event_device *ce)
     28{
     29	csr_set(CSR_IE, IE_TIE);
     30	sbi_set_timer(get_cycles64() + delta);
     31	return 0;
     32}
     33
     34static unsigned int riscv_clock_event_irq;
     35static DEFINE_PER_CPU(struct clock_event_device, riscv_clock_event) = {
     36	.name			= "riscv_timer_clockevent",
     37	.features		= CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP,
     38	.rating			= 100,
     39	.set_next_event		= riscv_clock_next_event,
     40};
     41
     42/*
     43 * It is guaranteed that all the timers across all the harts are synchronized
     44 * within one tick of each other, so while this could technically go
     45 * backwards when hopping between CPUs, practically it won't happen.
     46 */
     47static unsigned long long riscv_clocksource_rdtime(struct clocksource *cs)
     48{
     49	return get_cycles64();
     50}
     51
     52static u64 notrace riscv_sched_clock(void)
     53{
     54	return get_cycles64();
     55}
     56
     57static struct clocksource riscv_clocksource = {
     58	.name		= "riscv_clocksource",
     59	.rating		= 300,
     60	.mask		= CLOCKSOURCE_MASK(64),
     61	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
     62	.read		= riscv_clocksource_rdtime,
     63};
     64
     65static int riscv_timer_starting_cpu(unsigned int cpu)
     66{
     67	struct clock_event_device *ce = per_cpu_ptr(&riscv_clock_event, cpu);
     68
     69	ce->cpumask = cpumask_of(cpu);
     70	ce->irq = riscv_clock_event_irq;
     71	clockevents_config_and_register(ce, riscv_timebase, 100, 0x7fffffff);
     72
     73	enable_percpu_irq(riscv_clock_event_irq,
     74			  irq_get_trigger_type(riscv_clock_event_irq));
     75	return 0;
     76}
     77
     78static int riscv_timer_dying_cpu(unsigned int cpu)
     79{
     80	disable_percpu_irq(riscv_clock_event_irq);
     81	return 0;
     82}
     83
     84void riscv_cs_get_mult_shift(u32 *mult, u32 *shift)
     85{
     86	*mult = riscv_clocksource.mult;
     87	*shift = riscv_clocksource.shift;
     88}
     89EXPORT_SYMBOL_GPL(riscv_cs_get_mult_shift);
     90
     91/* called directly from the low-level interrupt handler */
     92static irqreturn_t riscv_timer_interrupt(int irq, void *dev_id)
     93{
     94	struct clock_event_device *evdev = this_cpu_ptr(&riscv_clock_event);
     95
     96	csr_clear(CSR_IE, IE_TIE);
     97	evdev->event_handler(evdev);
     98
     99	return IRQ_HANDLED;
    100}
    101
    102static int __init riscv_timer_init_dt(struct device_node *n)
    103{
    104	int cpuid, hartid, error;
    105	struct device_node *child;
    106	struct irq_domain *domain;
    107
    108	hartid = riscv_of_processor_hartid(n);
    109	if (hartid < 0) {
    110		pr_warn("Not valid hartid for node [%pOF] error = [%d]\n",
    111			n, hartid);
    112		return hartid;
    113	}
    114
    115	cpuid = riscv_hartid_to_cpuid(hartid);
    116	if (cpuid < 0) {
    117		pr_warn("Invalid cpuid for hartid [%d]\n", hartid);
    118		return cpuid;
    119	}
    120
    121	if (cpuid != smp_processor_id())
    122		return 0;
    123
    124	domain = NULL;
    125	child = of_get_compatible_child(n, "riscv,cpu-intc");
    126	if (!child) {
    127		pr_err("Failed to find INTC node [%pOF]\n", n);
    128		return -ENODEV;
    129	}
    130	domain = irq_find_host(child);
    131	of_node_put(child);
    132	if (!domain) {
    133		pr_err("Failed to find IRQ domain for node [%pOF]\n", n);
    134		return -ENODEV;
    135	}
    136
    137	riscv_clock_event_irq = irq_create_mapping(domain, RV_IRQ_TIMER);
    138	if (!riscv_clock_event_irq) {
    139		pr_err("Failed to map timer interrupt for node [%pOF]\n", n);
    140		return -ENODEV;
    141	}
    142
    143	pr_info("%s: Registering clocksource cpuid [%d] hartid [%d]\n",
    144	       __func__, cpuid, hartid);
    145	error = clocksource_register_hz(&riscv_clocksource, riscv_timebase);
    146	if (error) {
    147		pr_err("RISCV timer register failed [%d] for cpu = [%d]\n",
    148		       error, cpuid);
    149		return error;
    150	}
    151
    152	sched_clock_register(riscv_sched_clock, 64, riscv_timebase);
    153
    154	error = request_percpu_irq(riscv_clock_event_irq,
    155				    riscv_timer_interrupt,
    156				    "riscv-timer", &riscv_clock_event);
    157	if (error) {
    158		pr_err("registering percpu irq failed [%d]\n", error);
    159		return error;
    160	}
    161
    162	error = cpuhp_setup_state(CPUHP_AP_RISCV_TIMER_STARTING,
    163			 "clockevents/riscv/timer:starting",
    164			 riscv_timer_starting_cpu, riscv_timer_dying_cpu);
    165	if (error)
    166		pr_err("cpu hp setup state failed for RISCV timer [%d]\n",
    167		       error);
    168	return error;
    169}
    170
    171TIMER_OF_DECLARE(riscv_timer, "riscv", riscv_timer_init_dt);