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 (5992B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Time related functions for Hexagon architecture
      4 *
      5 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
      6 */
      7
      8#include <linux/init.h>
      9#include <linux/clockchips.h>
     10#include <linux/clocksource.h>
     11#include <linux/interrupt.h>
     12#include <linux/err.h>
     13#include <linux/platform_device.h>
     14#include <linux/ioport.h>
     15#include <linux/of.h>
     16#include <linux/of_address.h>
     17#include <linux/of_irq.h>
     18#include <linux/module.h>
     19
     20#include <asm/hexagon_vm.h>
     21
     22#define TIMER_ENABLE		BIT(0)
     23
     24/*
     25 * For the clocksource we need:
     26 *	pcycle frequency (600MHz)
     27 * For the loops_per_jiffy we need:
     28 *	thread/cpu frequency (100MHz)
     29 * And for the timer, we need:
     30 *	sleep clock rate
     31 */
     32
     33cycles_t	pcycle_freq_mhz;
     34cycles_t	thread_freq_mhz;
     35cycles_t	sleep_clk_freq;
     36
     37/*
     38 * 8x50 HDD Specs 5-8.  Simulator co-sim not fixed until
     39 * release 1.1, and then it's "adjustable" and probably not defaulted.
     40 */
     41#define RTOS_TIMER_INT		3
     42#define RTOS_TIMER_REGS_ADDR	0xAB000000UL
     43
     44static struct resource rtos_timer_resources[] = {
     45	{
     46		.start	= RTOS_TIMER_REGS_ADDR,
     47		.end	= RTOS_TIMER_REGS_ADDR+PAGE_SIZE-1,
     48		.flags	= IORESOURCE_MEM,
     49	},
     50};
     51
     52static struct platform_device rtos_timer_device = {
     53	.name		= "rtos_timer",
     54	.id		= -1,
     55	.num_resources	= ARRAY_SIZE(rtos_timer_resources),
     56	.resource	= rtos_timer_resources,
     57};
     58
     59/*  A lot of this stuff should move into a platform specific section.  */
     60struct adsp_hw_timer_struct {
     61	u32 match;   /*  Match value  */
     62	u32 count;
     63	u32 enable;  /*  [1] - CLR_ON_MATCH_EN, [0] - EN  */
     64	u32 clear;   /*  one-shot register that clears the count  */
     65};
     66
     67/*  Look for "TCX0" for related constants.  */
     68static __iomem struct adsp_hw_timer_struct *rtos_timer;
     69
     70static u64 timer_get_cycles(struct clocksource *cs)
     71{
     72	return (u64) __vmgettime();
     73}
     74
     75static struct clocksource hexagon_clocksource = {
     76	.name		= "pcycles",
     77	.rating		= 250,
     78	.read		= timer_get_cycles,
     79	.mask		= CLOCKSOURCE_MASK(64),
     80	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
     81};
     82
     83static int set_next_event(unsigned long delta, struct clock_event_device *evt)
     84{
     85	/*  Assuming the timer will be disabled when we enter here.  */
     86
     87	iowrite32(1, &rtos_timer->clear);
     88	iowrite32(0, &rtos_timer->clear);
     89
     90	iowrite32(delta, &rtos_timer->match);
     91	iowrite32(TIMER_ENABLE, &rtos_timer->enable);
     92	return 0;
     93}
     94
     95#ifdef CONFIG_SMP
     96/*  Broadcast mechanism  */
     97static void broadcast(const struct cpumask *mask)
     98{
     99	send_ipi(mask, IPI_TIMER);
    100}
    101#endif
    102
    103/* XXX Implement set_state_shutdown() */
    104static struct clock_event_device hexagon_clockevent_dev = {
    105	.name		= "clockevent",
    106	.features	= CLOCK_EVT_FEAT_ONESHOT,
    107	.rating		= 400,
    108	.irq		= RTOS_TIMER_INT,
    109	.set_next_event = set_next_event,
    110#ifdef CONFIG_SMP
    111	.broadcast	= broadcast,
    112#endif
    113};
    114
    115#ifdef CONFIG_SMP
    116static DEFINE_PER_CPU(struct clock_event_device, clock_events);
    117
    118void setup_percpu_clockdev(void)
    119{
    120	int cpu = smp_processor_id();
    121	struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
    122	struct clock_event_device *dummy_clock_dev =
    123		&per_cpu(clock_events, cpu);
    124
    125	memcpy(dummy_clock_dev, ce_dev, sizeof(*dummy_clock_dev));
    126	INIT_LIST_HEAD(&dummy_clock_dev->list);
    127
    128	dummy_clock_dev->features = CLOCK_EVT_FEAT_DUMMY;
    129	dummy_clock_dev->cpumask = cpumask_of(cpu);
    130
    131	clockevents_register_device(dummy_clock_dev);
    132}
    133
    134/*  Called from smp.c for each CPU's timer ipi call  */
    135void ipi_timer(void)
    136{
    137	int cpu = smp_processor_id();
    138	struct clock_event_device *ce_dev = &per_cpu(clock_events, cpu);
    139
    140	ce_dev->event_handler(ce_dev);
    141}
    142#endif /* CONFIG_SMP */
    143
    144static irqreturn_t timer_interrupt(int irq, void *devid)
    145{
    146	struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
    147
    148	iowrite32(0, &rtos_timer->enable);
    149	ce_dev->event_handler(ce_dev);
    150
    151	return IRQ_HANDLED;
    152}
    153
    154/*
    155 * time_init_deferred - called by start_kernel to set up timer/clock source
    156 *
    157 * Install the IRQ handler for the clock, setup timers.
    158 * This is done late, as that way, we can use ioremap().
    159 *
    160 * This runs just before the delay loop is calibrated, and
    161 * is used for delay calibration.
    162 */
    163void __init time_init_deferred(void)
    164{
    165	struct resource *resource = NULL;
    166	struct clock_event_device *ce_dev = &hexagon_clockevent_dev;
    167	unsigned long flag = IRQF_TIMER | IRQF_TRIGGER_RISING;
    168
    169	ce_dev->cpumask = cpu_all_mask;
    170
    171	if (!resource)
    172		resource = rtos_timer_device.resource;
    173
    174	/*  ioremap here means this has to run later, after paging init  */
    175	rtos_timer = ioremap(resource->start, resource_size(resource));
    176
    177	if (!rtos_timer) {
    178		release_mem_region(resource->start, resource_size(resource));
    179	}
    180	clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000);
    181
    182	/*  Note: the sim generic RTOS clock is apparently really 18750Hz  */
    183
    184	/*
    185	 * Last arg is some guaranteed seconds for which the conversion will
    186	 * work without overflow.
    187	 */
    188	clockevents_calc_mult_shift(ce_dev, sleep_clk_freq, 4);
    189
    190	ce_dev->max_delta_ns = clockevent_delta2ns(0x7fffffff, ce_dev);
    191	ce_dev->max_delta_ticks = 0x7fffffff;
    192	ce_dev->min_delta_ns = clockevent_delta2ns(0xf, ce_dev);
    193	ce_dev->min_delta_ticks = 0xf;
    194
    195#ifdef CONFIG_SMP
    196	setup_percpu_clockdev();
    197#endif
    198
    199	clockevents_register_device(ce_dev);
    200	if (request_irq(ce_dev->irq, timer_interrupt, flag, "rtos_timer", NULL))
    201		pr_err("Failed to register rtos_timer interrupt\n");
    202}
    203
    204void __init time_init(void)
    205{
    206	late_time_init = time_init_deferred;
    207}
    208
    209void __delay(unsigned long cycles)
    210{
    211	unsigned long long start = __vmgettime();
    212
    213	while ((__vmgettime() - start) < cycles)
    214		cpu_relax();
    215}
    216EXPORT_SYMBOL(__delay);
    217
    218/*
    219 * This could become parametric or perhaps even computed at run-time,
    220 * but for now we take the observed simulator jitter.
    221 */
    222static long long fudgefactor = 350;  /* Maybe lower if kernel optimized. */
    223
    224void __udelay(unsigned long usecs)
    225{
    226	unsigned long long start = __vmgettime();
    227	unsigned long long finish = (pcycle_freq_mhz * usecs) - fudgefactor;
    228
    229	while ((__vmgettime() - start) < finish)
    230		cpu_relax(); /*  not sure how this improves readability  */
    231}
    232EXPORT_SYMBOL(__udelay);