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

time.c (4873B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Common time service routines for LoongArch machines.
      4 *
      5 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
      6 */
      7#include <linux/clockchips.h>
      8#include <linux/delay.h>
      9#include <linux/export.h>
     10#include <linux/init.h>
     11#include <linux/interrupt.h>
     12#include <linux/kernel.h>
     13#include <linux/sched_clock.h>
     14#include <linux/spinlock.h>
     15
     16#include <asm/cpu-features.h>
     17#include <asm/loongarch.h>
     18#include <asm/time.h>
     19
     20u64 cpu_clock_freq;
     21EXPORT_SYMBOL(cpu_clock_freq);
     22u64 const_clock_freq;
     23EXPORT_SYMBOL(const_clock_freq);
     24
     25static DEFINE_RAW_SPINLOCK(state_lock);
     26static DEFINE_PER_CPU(struct clock_event_device, constant_clockevent_device);
     27
     28static void constant_event_handler(struct clock_event_device *dev)
     29{
     30}
     31
     32irqreturn_t constant_timer_interrupt(int irq, void *data)
     33{
     34	int cpu = smp_processor_id();
     35	struct clock_event_device *cd;
     36
     37	/* Clear Timer Interrupt */
     38	write_csr_tintclear(CSR_TINTCLR_TI);
     39	cd = &per_cpu(constant_clockevent_device, cpu);
     40	cd->event_handler(cd);
     41
     42	return IRQ_HANDLED;
     43}
     44
     45static int constant_set_state_oneshot(struct clock_event_device *evt)
     46{
     47	unsigned long timer_config;
     48
     49	raw_spin_lock(&state_lock);
     50
     51	timer_config = csr_read64(LOONGARCH_CSR_TCFG);
     52	timer_config |= CSR_TCFG_EN;
     53	timer_config &= ~CSR_TCFG_PERIOD;
     54	csr_write64(timer_config, LOONGARCH_CSR_TCFG);
     55
     56	raw_spin_unlock(&state_lock);
     57
     58	return 0;
     59}
     60
     61static int constant_set_state_oneshot_stopped(struct clock_event_device *evt)
     62{
     63	unsigned long timer_config;
     64
     65	raw_spin_lock(&state_lock);
     66
     67	timer_config = csr_read64(LOONGARCH_CSR_TCFG);
     68	timer_config &= ~CSR_TCFG_EN;
     69	csr_write64(timer_config, LOONGARCH_CSR_TCFG);
     70
     71	raw_spin_unlock(&state_lock);
     72
     73	return 0;
     74}
     75
     76static int constant_set_state_periodic(struct clock_event_device *evt)
     77{
     78	unsigned long period;
     79	unsigned long timer_config;
     80
     81	raw_spin_lock(&state_lock);
     82
     83	period = const_clock_freq / HZ;
     84	timer_config = period & CSR_TCFG_VAL;
     85	timer_config |= (CSR_TCFG_PERIOD | CSR_TCFG_EN);
     86	csr_write64(timer_config, LOONGARCH_CSR_TCFG);
     87
     88	raw_spin_unlock(&state_lock);
     89
     90	return 0;
     91}
     92
     93static int constant_set_state_shutdown(struct clock_event_device *evt)
     94{
     95	return 0;
     96}
     97
     98static int constant_timer_next_event(unsigned long delta, struct clock_event_device *evt)
     99{
    100	unsigned long timer_config;
    101
    102	delta &= CSR_TCFG_VAL;
    103	timer_config = delta | CSR_TCFG_EN;
    104	csr_write64(timer_config, LOONGARCH_CSR_TCFG);
    105
    106	return 0;
    107}
    108
    109static unsigned long __init get_loops_per_jiffy(void)
    110{
    111	unsigned long lpj = (unsigned long)const_clock_freq;
    112
    113	do_div(lpj, HZ);
    114
    115	return lpj;
    116}
    117
    118static long init_timeval;
    119
    120void sync_counter(void)
    121{
    122	/* Ensure counter begin at 0 */
    123	csr_write64(-init_timeval, LOONGARCH_CSR_CNTC);
    124}
    125
    126int constant_clockevent_init(void)
    127{
    128	unsigned int irq;
    129	unsigned int cpu = smp_processor_id();
    130	unsigned long min_delta = 0x600;
    131	unsigned long max_delta = (1UL << 48) - 1;
    132	struct clock_event_device *cd;
    133	static int timer_irq_installed = 0;
    134
    135	irq = EXCCODE_TIMER - EXCCODE_INT_START;
    136
    137	cd = &per_cpu(constant_clockevent_device, cpu);
    138
    139	cd->name = "Constant";
    140	cd->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_PERCPU;
    141
    142	cd->irq = irq;
    143	cd->rating = 320;
    144	cd->cpumask = cpumask_of(cpu);
    145	cd->set_state_oneshot = constant_set_state_oneshot;
    146	cd->set_state_oneshot_stopped = constant_set_state_oneshot_stopped;
    147	cd->set_state_periodic = constant_set_state_periodic;
    148	cd->set_state_shutdown = constant_set_state_shutdown;
    149	cd->set_next_event = constant_timer_next_event;
    150	cd->event_handler = constant_event_handler;
    151
    152	clockevents_config_and_register(cd, const_clock_freq, min_delta, max_delta);
    153
    154	if (timer_irq_installed)
    155		return 0;
    156
    157	timer_irq_installed = 1;
    158
    159	sync_counter();
    160
    161	if (request_irq(irq, constant_timer_interrupt, IRQF_PERCPU | IRQF_TIMER, "timer", NULL))
    162		pr_err("Failed to request irq %d (timer)\n", irq);
    163
    164	lpj_fine = get_loops_per_jiffy();
    165	pr_info("Constant clock event device register\n");
    166
    167	return 0;
    168}
    169
    170static u64 read_const_counter(struct clocksource *clk)
    171{
    172	return drdtime();
    173}
    174
    175static u64 native_sched_clock(void)
    176{
    177	return read_const_counter(NULL);
    178}
    179
    180static struct clocksource clocksource_const = {
    181	.name = "Constant",
    182	.rating = 400,
    183	.read = read_const_counter,
    184	.mask = CLOCKSOURCE_MASK(64),
    185	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
    186	.vdso_clock_mode = VDSO_CLOCKMODE_CPU,
    187};
    188
    189int __init constant_clocksource_init(void)
    190{
    191	int res;
    192	unsigned long freq = const_clock_freq;
    193
    194	res = clocksource_register_hz(&clocksource_const, freq);
    195
    196	sched_clock_register(native_sched_clock, 64, freq);
    197
    198	pr_info("Constant clock source device register\n");
    199
    200	return res;
    201}
    202
    203void __init time_init(void)
    204{
    205	if (!cpu_has_cpucfg)
    206		const_clock_freq = cpu_clock_freq;
    207	else
    208		const_clock_freq = calc_const_freq();
    209
    210	init_timeval = drdtime() - csr_read64(LOONGARCH_CSR_CNTC);
    211
    212	constant_clockevent_init();
    213	constant_clocksource_init();
    214}