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

mips-gic-timer.c (6341B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
      3
      4#define pr_fmt(fmt) "mips-gic-timer: " fmt
      5
      6#include <linux/clk.h>
      7#include <linux/clockchips.h>
      8#include <linux/cpu.h>
      9#include <linux/init.h>
     10#include <linux/interrupt.h>
     11#include <linux/notifier.h>
     12#include <linux/of_irq.h>
     13#include <linux/percpu.h>
     14#include <linux/sched_clock.h>
     15#include <linux/smp.h>
     16#include <linux/time.h>
     17#include <asm/mips-cps.h>
     18
     19static DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
     20static int gic_timer_irq;
     21static unsigned int gic_frequency;
     22static bool __read_mostly gic_clock_unstable;
     23
     24static void gic_clocksource_unstable(char *reason);
     25
     26static u64 notrace gic_read_count_2x32(void)
     27{
     28	unsigned int hi, hi2, lo;
     29
     30	do {
     31		hi = read_gic_counter_32h();
     32		lo = read_gic_counter_32l();
     33		hi2 = read_gic_counter_32h();
     34	} while (hi2 != hi);
     35
     36	return (((u64) hi) << 32) + lo;
     37}
     38
     39static u64 notrace gic_read_count_64(void)
     40{
     41	return read_gic_counter();
     42}
     43
     44static u64 notrace gic_read_count(void)
     45{
     46	if (mips_cm_is64)
     47		return gic_read_count_64();
     48
     49	return gic_read_count_2x32();
     50}
     51
     52static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
     53{
     54	int cpu = cpumask_first(evt->cpumask);
     55	u64 cnt;
     56	int res;
     57
     58	cnt = gic_read_count();
     59	cnt += (u64)delta;
     60	if (cpu == raw_smp_processor_id()) {
     61		write_gic_vl_compare(cnt);
     62	} else {
     63		write_gic_vl_other(mips_cm_vp_id(cpu));
     64		write_gic_vo_compare(cnt);
     65	}
     66	res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
     67	return res;
     68}
     69
     70static irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
     71{
     72	struct clock_event_device *cd = dev_id;
     73
     74	write_gic_vl_compare(read_gic_vl_compare());
     75	cd->event_handler(cd);
     76	return IRQ_HANDLED;
     77}
     78
     79static struct irqaction gic_compare_irqaction = {
     80	.handler = gic_compare_interrupt,
     81	.percpu_dev_id = &gic_clockevent_device,
     82	.flags = IRQF_PERCPU | IRQF_TIMER,
     83	.name = "timer",
     84};
     85
     86static void gic_clockevent_cpu_init(unsigned int cpu,
     87				    struct clock_event_device *cd)
     88{
     89	cd->name		= "MIPS GIC";
     90	cd->features		= CLOCK_EVT_FEAT_ONESHOT |
     91				  CLOCK_EVT_FEAT_C3STOP;
     92
     93	cd->rating		= 350;
     94	cd->irq			= gic_timer_irq;
     95	cd->cpumask		= cpumask_of(cpu);
     96	cd->set_next_event	= gic_next_event;
     97
     98	clockevents_config_and_register(cd, gic_frequency, 0x300, 0x7fffffff);
     99
    100	enable_percpu_irq(gic_timer_irq, IRQ_TYPE_NONE);
    101}
    102
    103static void gic_clockevent_cpu_exit(struct clock_event_device *cd)
    104{
    105	disable_percpu_irq(gic_timer_irq);
    106}
    107
    108static void gic_update_frequency(void *data)
    109{
    110	unsigned long rate = (unsigned long)data;
    111
    112	clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate);
    113}
    114
    115static int gic_starting_cpu(unsigned int cpu)
    116{
    117	gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device));
    118	return 0;
    119}
    120
    121static int gic_clk_notifier(struct notifier_block *nb, unsigned long action,
    122			    void *data)
    123{
    124	struct clk_notifier_data *cnd = data;
    125
    126	if (action == POST_RATE_CHANGE) {
    127		gic_clocksource_unstable("ref clock rate change");
    128		on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1);
    129	}
    130
    131	return NOTIFY_OK;
    132}
    133
    134static int gic_dying_cpu(unsigned int cpu)
    135{
    136	gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device));
    137	return 0;
    138}
    139
    140static struct notifier_block gic_clk_nb = {
    141	.notifier_call = gic_clk_notifier,
    142};
    143
    144static int gic_clockevent_init(void)
    145{
    146	int ret;
    147
    148	if (!gic_frequency)
    149		return -ENXIO;
    150
    151	ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction);
    152	if (ret < 0) {
    153		pr_err("IRQ %d setup failed (%d)\n", gic_timer_irq, ret);
    154		return ret;
    155	}
    156
    157	cpuhp_setup_state(CPUHP_AP_MIPS_GIC_TIMER_STARTING,
    158			  "clockevents/mips/gic/timer:starting",
    159			  gic_starting_cpu, gic_dying_cpu);
    160	return 0;
    161}
    162
    163static u64 gic_hpt_read(struct clocksource *cs)
    164{
    165	return gic_read_count();
    166}
    167
    168static struct clocksource gic_clocksource = {
    169	.name			= "GIC",
    170	.read			= gic_hpt_read,
    171	.flags			= CLOCK_SOURCE_IS_CONTINUOUS,
    172	.vdso_clock_mode	= VDSO_CLOCKMODE_GIC,
    173};
    174
    175static void gic_clocksource_unstable(char *reason)
    176{
    177	if (gic_clock_unstable)
    178		return;
    179
    180	gic_clock_unstable = true;
    181
    182	pr_info("GIC timer is unstable due to %s\n", reason);
    183
    184	clocksource_mark_unstable(&gic_clocksource);
    185}
    186
    187static int __init __gic_clocksource_init(void)
    188{
    189	unsigned int count_width;
    190	int ret;
    191
    192	/* Set clocksource mask. */
    193	count_width = read_gic_config() & GIC_CONFIG_COUNTBITS;
    194	count_width >>= __ffs(GIC_CONFIG_COUNTBITS);
    195	count_width *= 4;
    196	count_width += 32;
    197	gic_clocksource.mask = CLOCKSOURCE_MASK(count_width);
    198
    199	/* Calculate a somewhat reasonable rating value. */
    200	gic_clocksource.rating = 200 + gic_frequency / 10000000;
    201
    202	ret = clocksource_register_hz(&gic_clocksource, gic_frequency);
    203	if (ret < 0)
    204		pr_warn("Unable to register clocksource\n");
    205
    206	return ret;
    207}
    208
    209static int __init gic_clocksource_of_init(struct device_node *node)
    210{
    211	struct clk *clk;
    212	int ret;
    213
    214	if (!mips_gic_present() || !node->parent ||
    215	    !of_device_is_compatible(node->parent, "mti,gic")) {
    216		pr_warn("No DT definition\n");
    217		return -ENXIO;
    218	}
    219
    220	clk = of_clk_get(node, 0);
    221	if (!IS_ERR(clk)) {
    222		ret = clk_prepare_enable(clk);
    223		if (ret < 0) {
    224			pr_err("Failed to enable clock\n");
    225			clk_put(clk);
    226			return ret;
    227		}
    228
    229		gic_frequency = clk_get_rate(clk);
    230	} else if (of_property_read_u32(node, "clock-frequency",
    231					&gic_frequency)) {
    232		pr_err("Frequency not specified\n");
    233		return -EINVAL;
    234	}
    235	gic_timer_irq = irq_of_parse_and_map(node, 0);
    236	if (!gic_timer_irq) {
    237		pr_err("IRQ not specified\n");
    238		return -EINVAL;
    239	}
    240
    241	ret = __gic_clocksource_init();
    242	if (ret)
    243		return ret;
    244
    245	ret = gic_clockevent_init();
    246	if (!ret && !IS_ERR(clk)) {
    247		if (clk_notifier_register(clk, &gic_clk_nb) < 0)
    248			pr_warn("Unable to register clock notifier\n");
    249	}
    250
    251	/* And finally start the counter */
    252	clear_gic_config(GIC_CONFIG_COUNTSTOP);
    253
    254	/*
    255	 * It's safe to use the MIPS GIC timer as a sched clock source only if
    256	 * its ticks are stable, which is true on either the platforms with
    257	 * stable CPU frequency or on the platforms with CM3 and CPU frequency
    258	 * change performed by the CPC core clocks divider.
    259	 */
    260	if (mips_cm_revision() >= CM_REV_CM3 || !IS_ENABLED(CONFIG_CPU_FREQ)) {
    261		sched_clock_register(mips_cm_is64 ?
    262				     gic_read_count_64 : gic_read_count_2x32,
    263				     64, gic_frequency);
    264	}
    265
    266	return 0;
    267}
    268TIMER_OF_DECLARE(mips_gic_timer, "mti,gic-timer",
    269		       gic_clocksource_of_init);