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

cyclone.c (3015B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/module.h>
      3#include <linux/smp.h>
      4#include <linux/time.h>
      5#include <linux/errno.h>
      6#include <linux/timex.h>
      7#include <linux/clocksource.h>
      8#include <linux/io.h>
      9
     10/* IBM Summit (EXA) Cyclone counter code*/
     11#define CYCLONE_CBAR_ADDR 0xFEB00CD0
     12#define CYCLONE_PMCC_OFFSET 0x51A0
     13#define CYCLONE_MPMC_OFFSET 0x51D0
     14#define CYCLONE_MPCS_OFFSET 0x51A8
     15#define CYCLONE_TIMER_FREQ 100000000
     16
     17int use_cyclone;
     18void __init cyclone_setup(void)
     19{
     20	use_cyclone = 1;
     21}
     22
     23static void __iomem *cyclone_mc;
     24
     25static u64 read_cyclone(struct clocksource *cs)
     26{
     27	return (u64)readq((void __iomem *)cyclone_mc);
     28}
     29
     30static struct clocksource clocksource_cyclone = {
     31        .name           = "cyclone",
     32        .rating         = 300,
     33        .read           = read_cyclone,
     34        .mask           = (1LL << 40) - 1,
     35        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
     36};
     37
     38int __init init_cyclone_clock(void)
     39{
     40	u64 __iomem *reg;
     41	u64 base;	/* saved cyclone base address */
     42	u64 offset;	/* offset from pageaddr to cyclone_timer register */
     43	int i;
     44	u32 __iomem *cyclone_timer;	/* Cyclone MPMC0 register */
     45
     46	if (!use_cyclone)
     47		return 0;
     48
     49	printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
     50
     51	/* find base address */
     52	offset = (CYCLONE_CBAR_ADDR);
     53	reg = ioremap(offset, sizeof(u64));
     54	if(!reg){
     55		printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
     56				" register.\n");
     57		use_cyclone = 0;
     58		return -ENODEV;
     59	}
     60	base = readq(reg);
     61	iounmap(reg);
     62	if(!base){
     63		printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
     64				" value.\n");
     65		use_cyclone = 0;
     66		return -ENODEV;
     67	}
     68
     69	/* setup PMCC */
     70	offset = (base + CYCLONE_PMCC_OFFSET);
     71	reg = ioremap(offset, sizeof(u64));
     72	if(!reg){
     73		printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
     74				" register.\n");
     75		use_cyclone = 0;
     76		return -ENODEV;
     77	}
     78	writel(0x00000001,reg);
     79	iounmap(reg);
     80
     81	/* setup MPCS */
     82	offset = (base + CYCLONE_MPCS_OFFSET);
     83	reg = ioremap(offset, sizeof(u64));
     84	if(!reg){
     85		printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
     86				" register.\n");
     87		use_cyclone = 0;
     88		return -ENODEV;
     89	}
     90	writel(0x00000001,reg);
     91	iounmap(reg);
     92
     93	/* map in cyclone_timer */
     94	offset = (base + CYCLONE_MPMC_OFFSET);
     95	cyclone_timer = ioremap(offset, sizeof(u32));
     96	if(!cyclone_timer){
     97		printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
     98				" register.\n");
     99		use_cyclone = 0;
    100		return -ENODEV;
    101	}
    102
    103	/*quick test to make sure its ticking*/
    104	for(i=0; i<3; i++){
    105		u32 old = readl(cyclone_timer);
    106		int stall = 100;
    107		while(stall--) barrier();
    108		if(readl(cyclone_timer) == old){
    109			printk(KERN_ERR "Summit chipset: Counter not counting!"
    110					" DISABLED\n");
    111			iounmap(cyclone_timer);
    112			cyclone_timer = NULL;
    113			use_cyclone = 0;
    114			return -ENODEV;
    115		}
    116	}
    117	/* initialize last tick */
    118	cyclone_mc = cyclone_timer;
    119	clocksource_cyclone.archdata.fsys_mmio = cyclone_timer;
    120	clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ);
    121
    122	return 0;
    123}
    124
    125__initcall(init_cyclone_clock);