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

ip22-time.c (3633B)


      1/*
      2 * This file is subject to the terms and conditions of the GNU General Public
      3 * License.  See the file "COPYING" in the main directory of this archive
      4 * for more details.
      5 *
      6 * Time operations for IP22 machines. Original code may come from
      7 * Ralf Baechle or David S. Miller (sorry guys, i'm really not sure)
      8 *
      9 * Copyright (C) 2001 by Ladislav Michl
     10 * Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org)
     11 */
     12#include <linux/bcd.h>
     13#include <linux/i8253.h>
     14#include <linux/init.h>
     15#include <linux/irq.h>
     16#include <linux/kernel.h>
     17#include <linux/interrupt.h>
     18#include <linux/kernel_stat.h>
     19#include <linux/time.h>
     20#include <linux/ftrace.h>
     21
     22#include <asm/cpu.h>
     23#include <asm/mipsregs.h>
     24#include <asm/io.h>
     25#include <asm/irq.h>
     26#include <asm/time.h>
     27#include <asm/sgialib.h>
     28#include <asm/sgi/ioc.h>
     29#include <asm/sgi/hpc3.h>
     30#include <asm/sgi/ip22.h>
     31
     32static unsigned long dosample(void)
     33{
     34	u32 ct0, ct1;
     35	u8 msb;
     36
     37	/* Start the counter. */
     38	sgint->tcword = (SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL |
     39			 SGINT_TCWORD_MRGEN);
     40	sgint->tcnt2 = SGINT_TCSAMP_COUNTER & 0xff;
     41	sgint->tcnt2 = SGINT_TCSAMP_COUNTER >> 8;
     42
     43	/* Get initial counter invariant */
     44	ct0 = read_c0_count();
     45
     46	/* Latch and spin until top byte of counter2 is zero */
     47	do {
     48		writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CLAT, &sgint->tcword);
     49		(void) readb(&sgint->tcnt2);
     50		msb = readb(&sgint->tcnt2);
     51		ct1 = read_c0_count();
     52	} while (msb);
     53
     54	/* Stop the counter. */
     55	writeb(SGINT_TCWORD_CNT2 | SGINT_TCWORD_CALL | SGINT_TCWORD_MSWST,
     56	       &sgint->tcword);
     57	/*
     58	 * Return the difference, this is how far the r4k counter increments
     59	 * for every 1/HZ seconds. We round off the nearest 1 MHz of master
     60	 * clock (= 1000000 / HZ / 2).
     61	 */
     62
     63	return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
     64}
     65
     66/*
     67 * Here we need to calibrate the cycle counter to at least be close.
     68 */
     69__init void plat_time_init(void)
     70{
     71	unsigned long r4k_ticks[3];
     72	unsigned long r4k_tick;
     73
     74	/*
     75	 * Figure out the r4k offset, the algorithm is very simple and works in
     76	 * _all_ cases as long as the 8254 counter register itself works ok (as
     77	 * an interrupt driving timer it does not because of bug, this is why
     78	 * we are using the onchip r4k counter/compare register to serve this
     79	 * purpose, but for r4k_offset calculation it will work ok for us).
     80	 * There are other very complicated ways of performing this calculation
     81	 * but this one works just fine so I am not going to futz around. ;-)
     82	 */
     83	printk(KERN_INFO "Calibrating system timer... ");
     84	dosample();	/* Prime cache. */
     85	dosample();	/* Prime cache. */
     86	/* Zero is NOT an option. */
     87	do {
     88		r4k_ticks[0] = dosample();
     89	} while (!r4k_ticks[0]);
     90	do {
     91		r4k_ticks[1] = dosample();
     92	} while (!r4k_ticks[1]);
     93
     94	if (r4k_ticks[0] != r4k_ticks[1]) {
     95		printk("warning: timer counts differ, retrying... ");
     96		r4k_ticks[2] = dosample();
     97		if (r4k_ticks[2] == r4k_ticks[0]
     98		    || r4k_ticks[2] == r4k_ticks[1])
     99			r4k_tick = r4k_ticks[2];
    100		else {
    101			printk("disagreement, using average... ");
    102			r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
    103				   + r4k_ticks[2]) / 3;
    104		}
    105	} else
    106		r4k_tick = r4k_ticks[0];
    107
    108	printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
    109		(int) (r4k_tick / (500000 / HZ)),
    110		(int) (r4k_tick % (500000 / HZ)));
    111
    112	mips_hpt_frequency = r4k_tick * HZ;
    113
    114	if (ip22_is_fullhouse())
    115		setup_pit_timer();
    116}
    117
    118/* Generic SGI handler for (spurious) 8254 interrupts */
    119void __irq_entry indy_8254timer_irq(void)
    120{
    121	int irq = SGI_8254_0_IRQ;
    122	ULONG cnt;
    123	char c;
    124
    125	irq_enter();
    126	kstat_incr_irq_this_cpu(irq);
    127	printk(KERN_ALERT "Oops, got 8254 interrupt.\n");
    128	ArcRead(0, &c, 1, &cnt);
    129	ArcEnterInteractiveMode();
    130	irq_exit();
    131}