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

sc520_freq.c (2841B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *	sc520_freq.c: cpufreq driver for the AMD Elan sc520
      4 *
      5 *	Copyright (C) 2005 Sean Young <sean@mess.org>
      6 *
      7 *	Based on elanfreq.c
      8 *
      9 *	2005-03-30: - initial revision
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/init.h>
     17
     18#include <linux/delay.h>
     19#include <linux/cpufreq.h>
     20#include <linux/timex.h>
     21#include <linux/io.h>
     22
     23#include <asm/cpu_device_id.h>
     24#include <asm/msr.h>
     25
     26#define MMCR_BASE	0xfffef000	/* The default base address */
     27#define OFFS_CPUCTL	0x2   /* CPU Control Register */
     28
     29static __u8 __iomem *cpuctl;
     30
     31static struct cpufreq_frequency_table sc520_freq_table[] = {
     32	{0, 0x01,	100000},
     33	{0, 0x02,	133000},
     34	{0, 0,	CPUFREQ_TABLE_END},
     35};
     36
     37static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu)
     38{
     39	u8 clockspeed_reg = *cpuctl;
     40
     41	switch (clockspeed_reg & 0x03) {
     42	default:
     43		pr_err("error: cpuctl register has unexpected value %02x\n",
     44		       clockspeed_reg);
     45		fallthrough;
     46	case 0x01:
     47		return 100000;
     48	case 0x02:
     49		return 133000;
     50	}
     51}
     52
     53static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state)
     54{
     55
     56	u8 clockspeed_reg;
     57
     58	local_irq_disable();
     59
     60	clockspeed_reg = *cpuctl & ~0x03;
     61	*cpuctl = clockspeed_reg | sc520_freq_table[state].driver_data;
     62
     63	local_irq_enable();
     64
     65	return 0;
     66}
     67
     68/*
     69 *	Module init and exit code
     70 */
     71
     72static int sc520_freq_cpu_init(struct cpufreq_policy *policy)
     73{
     74	struct cpuinfo_x86 *c = &cpu_data(0);
     75
     76	/* capability check */
     77	if (c->x86_vendor != X86_VENDOR_AMD ||
     78	    c->x86 != 4 || c->x86_model != 9)
     79		return -ENODEV;
     80
     81	/* cpuinfo and default policy values */
     82	policy->cpuinfo.transition_latency = 1000000; /* 1ms */
     83	policy->freq_table = sc520_freq_table;
     84
     85	return 0;
     86}
     87
     88
     89static struct cpufreq_driver sc520_freq_driver = {
     90	.get	= sc520_freq_get_cpu_frequency,
     91	.verify	= cpufreq_generic_frequency_table_verify,
     92	.target_index = sc520_freq_target,
     93	.init	= sc520_freq_cpu_init,
     94	.name	= "sc520_freq",
     95	.attr	= cpufreq_generic_attr,
     96};
     97
     98static const struct x86_cpu_id sc520_ids[] = {
     99	X86_MATCH_VENDOR_FAM_MODEL(AMD, 4, 9, NULL),
    100	{}
    101};
    102MODULE_DEVICE_TABLE(x86cpu, sc520_ids);
    103
    104static int __init sc520_freq_init(void)
    105{
    106	int err;
    107
    108	if (!x86_match_cpu(sc520_ids))
    109		return -ENODEV;
    110
    111	cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
    112	if (!cpuctl) {
    113		pr_err("sc520_freq: error: failed to remap memory\n");
    114		return -ENOMEM;
    115	}
    116
    117	err = cpufreq_register_driver(&sc520_freq_driver);
    118	if (err)
    119		iounmap(cpuctl);
    120
    121	return err;
    122}
    123
    124
    125static void __exit sc520_freq_exit(void)
    126{
    127	cpufreq_unregister_driver(&sc520_freq_driver);
    128	iounmap(cpuctl);
    129}
    130
    131
    132MODULE_LICENSE("GPL");
    133MODULE_AUTHOR("Sean Young <sean@mess.org>");
    134MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU");
    135
    136module_init(sc520_freq_init);
    137module_exit(sc520_freq_exit);
    138