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

ia64-acpi-cpufreq.c (7825B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * This file provides the ACPI based P-state support. This
      4 * module works with generic cpufreq infrastructure. Most of
      5 * the code is based on i386 version
      6 * (arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c)
      7 *
      8 * Copyright (C) 2005 Intel Corp
      9 *      Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#include <linux/kernel.h>
     15#include <linux/slab.h>
     16#include <linux/module.h>
     17#include <linux/init.h>
     18#include <linux/cpufreq.h>
     19#include <linux/proc_fs.h>
     20#include <asm/io.h>
     21#include <linux/uaccess.h>
     22#include <asm/pal.h>
     23
     24#include <linux/acpi.h>
     25#include <acpi/processor.h>
     26
     27MODULE_AUTHOR("Venkatesh Pallipadi");
     28MODULE_DESCRIPTION("ACPI Processor P-States Driver");
     29MODULE_LICENSE("GPL");
     30
     31struct cpufreq_acpi_io {
     32	struct acpi_processor_performance	acpi_data;
     33	unsigned int				resume;
     34};
     35
     36struct cpufreq_acpi_req {
     37	unsigned int		cpu;
     38	unsigned int		state;
     39};
     40
     41static struct cpufreq_acpi_io	*acpi_io_data[NR_CPUS];
     42
     43static struct cpufreq_driver acpi_cpufreq_driver;
     44
     45
     46static int
     47processor_set_pstate (
     48	u32	value)
     49{
     50	s64 retval;
     51
     52	pr_debug("processor_set_pstate\n");
     53
     54	retval = ia64_pal_set_pstate((u64)value);
     55
     56	if (retval) {
     57		pr_debug("Failed to set freq to 0x%x, with error 0x%llx\n",
     58		        value, retval);
     59		return -ENODEV;
     60	}
     61	return (int)retval;
     62}
     63
     64
     65static int
     66processor_get_pstate (
     67	u32	*value)
     68{
     69	u64	pstate_index = 0;
     70	s64 	retval;
     71
     72	pr_debug("processor_get_pstate\n");
     73
     74	retval = ia64_pal_get_pstate(&pstate_index,
     75	                             PAL_GET_PSTATE_TYPE_INSTANT);
     76	*value = (u32) pstate_index;
     77
     78	if (retval)
     79		pr_debug("Failed to get current freq with "
     80			"error 0x%llx, idx 0x%x\n", retval, *value);
     81
     82	return (int)retval;
     83}
     84
     85
     86/* To be used only after data->acpi_data is initialized */
     87static unsigned
     88extract_clock (
     89	struct cpufreq_acpi_io *data,
     90	unsigned value)
     91{
     92	unsigned long i;
     93
     94	pr_debug("extract_clock\n");
     95
     96	for (i = 0; i < data->acpi_data.state_count; i++) {
     97		if (value == data->acpi_data.states[i].status)
     98			return data->acpi_data.states[i].core_frequency;
     99	}
    100	return data->acpi_data.states[i-1].core_frequency;
    101}
    102
    103
    104static long
    105processor_get_freq (
    106	void *arg)
    107{
    108	struct cpufreq_acpi_req *req = arg;
    109	unsigned int		cpu = req->cpu;
    110	struct cpufreq_acpi_io	*data = acpi_io_data[cpu];
    111	u32			value;
    112	int			ret;
    113
    114	pr_debug("processor_get_freq\n");
    115	if (smp_processor_id() != cpu)
    116		return -EAGAIN;
    117
    118	/* processor_get_pstate gets the instantaneous frequency */
    119	ret = processor_get_pstate(&value);
    120	if (ret) {
    121		pr_warn("get performance failed with error %d\n", ret);
    122		return ret;
    123	}
    124	return 1000 * extract_clock(data, value);
    125}
    126
    127
    128static long
    129processor_set_freq (
    130	void *arg)
    131{
    132	struct cpufreq_acpi_req *req = arg;
    133	unsigned int		cpu = req->cpu;
    134	struct cpufreq_acpi_io	*data = acpi_io_data[cpu];
    135	int			ret, state = req->state;
    136	u32			value;
    137
    138	pr_debug("processor_set_freq\n");
    139	if (smp_processor_id() != cpu)
    140		return -EAGAIN;
    141
    142	if (state == data->acpi_data.state) {
    143		if (unlikely(data->resume)) {
    144			pr_debug("Called after resume, resetting to P%d\n", state);
    145			data->resume = 0;
    146		} else {
    147			pr_debug("Already at target state (P%d)\n", state);
    148			return 0;
    149		}
    150	}
    151
    152	pr_debug("Transitioning from P%d to P%d\n",
    153		data->acpi_data.state, state);
    154
    155	/*
    156	 * First we write the target state's 'control' value to the
    157	 * control_register.
    158	 */
    159	value = (u32) data->acpi_data.states[state].control;
    160
    161	pr_debug("Transitioning to state: 0x%08x\n", value);
    162
    163	ret = processor_set_pstate(value);
    164	if (ret) {
    165		pr_warn("Transition failed with error %d\n", ret);
    166		return -ENODEV;
    167	}
    168
    169	data->acpi_data.state = state;
    170	return 0;
    171}
    172
    173
    174static unsigned int
    175acpi_cpufreq_get (
    176	unsigned int		cpu)
    177{
    178	struct cpufreq_acpi_req req;
    179	long ret;
    180
    181	req.cpu = cpu;
    182	ret = work_on_cpu(cpu, processor_get_freq, &req);
    183
    184	return ret > 0 ? (unsigned int) ret : 0;
    185}
    186
    187
    188static int
    189acpi_cpufreq_target (
    190	struct cpufreq_policy   *policy,
    191	unsigned int index)
    192{
    193	struct cpufreq_acpi_req req;
    194
    195	req.cpu = policy->cpu;
    196	req.state = index;
    197
    198	return work_on_cpu(req.cpu, processor_set_freq, &req);
    199}
    200
    201static int
    202acpi_cpufreq_cpu_init (
    203	struct cpufreq_policy   *policy)
    204{
    205	unsigned int		i;
    206	unsigned int		cpu = policy->cpu;
    207	struct cpufreq_acpi_io	*data;
    208	unsigned int		result = 0;
    209	struct cpufreq_frequency_table *freq_table;
    210
    211	pr_debug("acpi_cpufreq_cpu_init\n");
    212
    213	data = kzalloc(sizeof(*data), GFP_KERNEL);
    214	if (!data)
    215		return (-ENOMEM);
    216
    217	acpi_io_data[cpu] = data;
    218
    219	result = acpi_processor_register_performance(&data->acpi_data, cpu);
    220
    221	if (result)
    222		goto err_free;
    223
    224	/* capability check */
    225	if (data->acpi_data.state_count <= 1) {
    226		pr_debug("No P-States\n");
    227		result = -ENODEV;
    228		goto err_unreg;
    229	}
    230
    231	if ((data->acpi_data.control_register.space_id !=
    232					ACPI_ADR_SPACE_FIXED_HARDWARE) ||
    233	    (data->acpi_data.status_register.space_id !=
    234					ACPI_ADR_SPACE_FIXED_HARDWARE)) {
    235		pr_debug("Unsupported address space [%d, %d]\n",
    236			(u32) (data->acpi_data.control_register.space_id),
    237			(u32) (data->acpi_data.status_register.space_id));
    238		result = -ENODEV;
    239		goto err_unreg;
    240	}
    241
    242	/* alloc freq_table */
    243	freq_table = kcalloc(data->acpi_data.state_count + 1,
    244	                           sizeof(*freq_table),
    245	                           GFP_KERNEL);
    246	if (!freq_table) {
    247		result = -ENOMEM;
    248		goto err_unreg;
    249	}
    250
    251	/* detect transition latency */
    252	policy->cpuinfo.transition_latency = 0;
    253	for (i=0; i<data->acpi_data.state_count; i++) {
    254		if ((data->acpi_data.states[i].transition_latency * 1000) >
    255		    policy->cpuinfo.transition_latency) {
    256			policy->cpuinfo.transition_latency =
    257			    data->acpi_data.states[i].transition_latency * 1000;
    258		}
    259	}
    260
    261	/* table init */
    262	for (i = 0; i <= data->acpi_data.state_count; i++)
    263	{
    264		if (i < data->acpi_data.state_count) {
    265			freq_table[i].frequency =
    266			      data->acpi_data.states[i].core_frequency * 1000;
    267		} else {
    268			freq_table[i].frequency = CPUFREQ_TABLE_END;
    269		}
    270	}
    271
    272	policy->freq_table = freq_table;
    273
    274	/* notify BIOS that we exist */
    275	acpi_processor_notify_smm(THIS_MODULE);
    276
    277	pr_info("CPU%u - ACPI performance management activated\n", cpu);
    278
    279	for (i = 0; i < data->acpi_data.state_count; i++)
    280		pr_debug("     %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
    281			(i == data->acpi_data.state?'*':' '), i,
    282			(u32) data->acpi_data.states[i].core_frequency,
    283			(u32) data->acpi_data.states[i].power,
    284			(u32) data->acpi_data.states[i].transition_latency,
    285			(u32) data->acpi_data.states[i].bus_master_latency,
    286			(u32) data->acpi_data.states[i].status,
    287			(u32) data->acpi_data.states[i].control);
    288
    289	/* the first call to ->target() should result in us actually
    290	 * writing something to the appropriate registers. */
    291	data->resume = 1;
    292
    293	return (result);
    294
    295 err_unreg:
    296	acpi_processor_unregister_performance(cpu);
    297 err_free:
    298	kfree(data);
    299	acpi_io_data[cpu] = NULL;
    300
    301	return (result);
    302}
    303
    304
    305static int
    306acpi_cpufreq_cpu_exit (
    307	struct cpufreq_policy   *policy)
    308{
    309	struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
    310
    311	pr_debug("acpi_cpufreq_cpu_exit\n");
    312
    313	if (data) {
    314		acpi_io_data[policy->cpu] = NULL;
    315		acpi_processor_unregister_performance(policy->cpu);
    316		kfree(policy->freq_table);
    317		kfree(data);
    318	}
    319
    320	return (0);
    321}
    322
    323
    324static struct cpufreq_driver acpi_cpufreq_driver = {
    325	.verify 	= cpufreq_generic_frequency_table_verify,
    326	.target_index	= acpi_cpufreq_target,
    327	.get 		= acpi_cpufreq_get,
    328	.init		= acpi_cpufreq_cpu_init,
    329	.exit		= acpi_cpufreq_cpu_exit,
    330	.name		= "acpi-cpufreq",
    331	.attr		= cpufreq_generic_attr,
    332};
    333
    334
    335static int __init
    336acpi_cpufreq_init (void)
    337{
    338	pr_debug("acpi_cpufreq_init\n");
    339
    340 	return cpufreq_register_driver(&acpi_cpufreq_driver);
    341}
    342
    343
    344static void __exit
    345acpi_cpufreq_exit (void)
    346{
    347	pr_debug("acpi_cpufreq_exit\n");
    348
    349	cpufreq_unregister_driver(&acpi_cpufreq_driver);
    350}
    351
    352late_initcall(acpi_cpufreq_init);
    353module_exit(acpi_cpufreq_exit);