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

processor_driver.c (9044B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * processor_driver.c - ACPI Processor Driver
      4 *
      5 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
      6 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
      7 *  Copyright (C) 2004       Dominik Brodowski <linux@brodo.de>
      8 *  Copyright (C) 2004  Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
      9 *  			- Added processor hotplug support
     10 *  Copyright (C) 2013, Intel Corporation
     11 *                      Rafael J. Wysocki <rafael.j.wysocki@intel.com>
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/init.h>
     17#include <linux/cpufreq.h>
     18#include <linux/cpu.h>
     19#include <linux/cpuidle.h>
     20#include <linux/slab.h>
     21#include <linux/acpi.h>
     22
     23#include <acpi/processor.h>
     24
     25#include "internal.h"
     26
     27#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
     28#define ACPI_PROCESSOR_NOTIFY_POWER	0x81
     29#define ACPI_PROCESSOR_NOTIFY_THROTTLING	0x82
     30
     31MODULE_AUTHOR("Paul Diefenbaugh");
     32MODULE_DESCRIPTION("ACPI Processor Driver");
     33MODULE_LICENSE("GPL");
     34
     35static int acpi_processor_start(struct device *dev);
     36static int acpi_processor_stop(struct device *dev);
     37
     38static const struct acpi_device_id processor_device_ids[] = {
     39	{ACPI_PROCESSOR_OBJECT_HID, 0},
     40	{ACPI_PROCESSOR_DEVICE_HID, 0},
     41	{"", 0},
     42};
     43MODULE_DEVICE_TABLE(acpi, processor_device_ids);
     44
     45static struct device_driver acpi_processor_driver = {
     46	.name = "processor",
     47	.bus = &cpu_subsys,
     48	.acpi_match_table = processor_device_ids,
     49	.probe = acpi_processor_start,
     50	.remove = acpi_processor_stop,
     51};
     52
     53static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
     54{
     55	struct acpi_device *device = data;
     56	struct acpi_processor *pr;
     57	int saved;
     58
     59	if (device->handle != handle)
     60		return;
     61
     62	pr = acpi_driver_data(device);
     63	if (!pr)
     64		return;
     65
     66	switch (event) {
     67	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
     68		saved = pr->performance_platform_limit;
     69		acpi_processor_ppc_has_changed(pr, 1);
     70		if (saved == pr->performance_platform_limit)
     71			break;
     72		acpi_bus_generate_netlink_event(device->pnp.device_class,
     73						  dev_name(&device->dev), event,
     74						  pr->performance_platform_limit);
     75		break;
     76	case ACPI_PROCESSOR_NOTIFY_POWER:
     77		acpi_processor_power_state_has_changed(pr);
     78		acpi_bus_generate_netlink_event(device->pnp.device_class,
     79						  dev_name(&device->dev), event, 0);
     80		break;
     81	case ACPI_PROCESSOR_NOTIFY_THROTTLING:
     82		acpi_processor_tstate_has_changed(pr);
     83		acpi_bus_generate_netlink_event(device->pnp.device_class,
     84						  dev_name(&device->dev), event, 0);
     85		break;
     86	default:
     87		acpi_handle_debug(handle, "Unsupported event [0x%x]\n", event);
     88		break;
     89	}
     90
     91	return;
     92}
     93
     94static int __acpi_processor_start(struct acpi_device *device);
     95
     96static int acpi_soft_cpu_online(unsigned int cpu)
     97{
     98	struct acpi_processor *pr = per_cpu(processors, cpu);
     99	struct acpi_device *device;
    100
    101	if (!pr)
    102		return 0;
    103
    104	device = acpi_fetch_acpi_dev(pr->handle);
    105	if (!device)
    106		return 0;
    107
    108	/*
    109	 * CPU got physically hotplugged and onlined for the first time:
    110	 * Initialize missing things.
    111	 */
    112	if (pr->flags.need_hotplug_init) {
    113		int ret;
    114
    115		pr_info("Will online and init hotplugged CPU: %d\n",
    116			pr->id);
    117		pr->flags.need_hotplug_init = 0;
    118		ret = __acpi_processor_start(device);
    119		WARN(ret, "Failed to start CPU: %d\n", pr->id);
    120	} else {
    121		/* Normal CPU soft online event. */
    122		acpi_processor_ppc_has_changed(pr, 0);
    123		acpi_processor_hotplug(pr);
    124		acpi_processor_reevaluate_tstate(pr, false);
    125		acpi_processor_tstate_has_changed(pr);
    126	}
    127	return 0;
    128}
    129
    130static int acpi_soft_cpu_dead(unsigned int cpu)
    131{
    132	struct acpi_processor *pr = per_cpu(processors, cpu);
    133
    134	if (!pr || !acpi_fetch_acpi_dev(pr->handle))
    135		return 0;
    136
    137	acpi_processor_reevaluate_tstate(pr, true);
    138	return 0;
    139}
    140
    141#ifdef CONFIG_ACPI_CPU_FREQ_PSS
    142static int acpi_pss_perf_init(struct acpi_processor *pr,
    143		struct acpi_device *device)
    144{
    145	int result = 0;
    146
    147	acpi_processor_ppc_has_changed(pr, 0);
    148
    149	acpi_processor_get_throttling_info(pr);
    150
    151	if (pr->flags.throttling)
    152		pr->flags.limit = 1;
    153
    154	pr->cdev = thermal_cooling_device_register("Processor", device,
    155						   &processor_cooling_ops);
    156	if (IS_ERR(pr->cdev)) {
    157		result = PTR_ERR(pr->cdev);
    158		return result;
    159	}
    160
    161	dev_dbg(&device->dev, "registered as cooling_device%d\n",
    162		pr->cdev->id);
    163
    164	result = sysfs_create_link(&device->dev.kobj,
    165				   &pr->cdev->device.kobj,
    166				   "thermal_cooling");
    167	if (result) {
    168		dev_err(&device->dev,
    169			"Failed to create sysfs link 'thermal_cooling'\n");
    170		goto err_thermal_unregister;
    171	}
    172
    173	result = sysfs_create_link(&pr->cdev->device.kobj,
    174				   &device->dev.kobj,
    175				   "device");
    176	if (result) {
    177		dev_err(&pr->cdev->device,
    178			"Failed to create sysfs link 'device'\n");
    179		goto err_remove_sysfs_thermal;
    180	}
    181
    182	return 0;
    183
    184 err_remove_sysfs_thermal:
    185	sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
    186 err_thermal_unregister:
    187	thermal_cooling_device_unregister(pr->cdev);
    188
    189	return result;
    190}
    191
    192static void acpi_pss_perf_exit(struct acpi_processor *pr,
    193		struct acpi_device *device)
    194{
    195	if (pr->cdev) {
    196		sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
    197		sysfs_remove_link(&pr->cdev->device.kobj, "device");
    198		thermal_cooling_device_unregister(pr->cdev);
    199		pr->cdev = NULL;
    200	}
    201}
    202#else
    203static inline int acpi_pss_perf_init(struct acpi_processor *pr,
    204		struct acpi_device *device)
    205{
    206	return 0;
    207}
    208
    209static inline void acpi_pss_perf_exit(struct acpi_processor *pr,
    210		struct acpi_device *device) {}
    211#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
    212
    213static int __acpi_processor_start(struct acpi_device *device)
    214{
    215	struct acpi_processor *pr = acpi_driver_data(device);
    216	acpi_status status;
    217	int result = 0;
    218
    219	if (!pr)
    220		return -ENODEV;
    221
    222	if (pr->flags.need_hotplug_init)
    223		return 0;
    224
    225	result = acpi_cppc_processor_probe(pr);
    226	if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS))
    227		dev_dbg(&device->dev, "CPPC data invalid or not present\n");
    228
    229	if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
    230		acpi_processor_power_init(pr);
    231
    232	result = acpi_pss_perf_init(pr, device);
    233	if (result)
    234		goto err_power_exit;
    235
    236	status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
    237					     acpi_processor_notify, device);
    238	if (ACPI_SUCCESS(status))
    239		return 0;
    240
    241	result = -ENODEV;
    242	acpi_pss_perf_exit(pr, device);
    243
    244err_power_exit:
    245	acpi_processor_power_exit(pr);
    246	return result;
    247}
    248
    249static int acpi_processor_start(struct device *dev)
    250{
    251	struct acpi_device *device = ACPI_COMPANION(dev);
    252	int ret;
    253
    254	if (!device)
    255		return -ENODEV;
    256
    257	/* Protect against concurrent CPU hotplug operations */
    258	cpu_hotplug_disable();
    259	ret = __acpi_processor_start(device);
    260	cpu_hotplug_enable();
    261	return ret;
    262}
    263
    264static int acpi_processor_stop(struct device *dev)
    265{
    266	struct acpi_device *device = ACPI_COMPANION(dev);
    267	struct acpi_processor *pr;
    268
    269	if (!device)
    270		return 0;
    271
    272	acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
    273				   acpi_processor_notify);
    274
    275	pr = acpi_driver_data(device);
    276	if (!pr)
    277		return 0;
    278	acpi_processor_power_exit(pr);
    279
    280	acpi_pss_perf_exit(pr, device);
    281
    282	acpi_cppc_processor_exit(pr);
    283
    284	return 0;
    285}
    286
    287bool acpi_processor_cpufreq_init;
    288
    289static int acpi_processor_notifier(struct notifier_block *nb,
    290				   unsigned long event, void *data)
    291{
    292	struct cpufreq_policy *policy = data;
    293
    294	if (event == CPUFREQ_CREATE_POLICY) {
    295		acpi_thermal_cpufreq_init(policy);
    296		acpi_processor_ppc_init(policy);
    297	} else if (event == CPUFREQ_REMOVE_POLICY) {
    298		acpi_processor_ppc_exit(policy);
    299		acpi_thermal_cpufreq_exit(policy);
    300	}
    301
    302	return 0;
    303}
    304
    305static struct notifier_block acpi_processor_notifier_block = {
    306	.notifier_call = acpi_processor_notifier,
    307};
    308
    309/*
    310 * We keep the driver loaded even when ACPI is not running.
    311 * This is needed for the powernow-k8 driver, that works even without
    312 * ACPI, but needs symbols from this driver
    313 */
    314static enum cpuhp_state hp_online;
    315static int __init acpi_processor_driver_init(void)
    316{
    317	int result = 0;
    318
    319	if (acpi_disabled)
    320		return 0;
    321
    322	result = driver_register(&acpi_processor_driver);
    323	if (result < 0)
    324		return result;
    325
    326	result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
    327					   "acpi/cpu-drv:online",
    328					   acpi_soft_cpu_online, NULL);
    329	if (result < 0)
    330		goto err;
    331	hp_online = result;
    332	cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
    333				  NULL, acpi_soft_cpu_dead);
    334
    335	if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
    336				       CPUFREQ_POLICY_NOTIFIER)) {
    337		acpi_processor_cpufreq_init = true;
    338		acpi_processor_ignore_ppc_init();
    339	}
    340
    341	acpi_processor_throttling_init();
    342	return 0;
    343err:
    344	driver_unregister(&acpi_processor_driver);
    345	return result;
    346}
    347
    348static void __exit acpi_processor_driver_exit(void)
    349{
    350	if (acpi_disabled)
    351		return;
    352
    353	if (acpi_processor_cpufreq_init) {
    354		cpufreq_unregister_notifier(&acpi_processor_notifier_block,
    355					    CPUFREQ_POLICY_NOTIFIER);
    356		acpi_processor_cpufreq_init = false;
    357	}
    358
    359	cpuhp_remove_state_nocalls(hp_online);
    360	cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD);
    361	driver_unregister(&acpi_processor_driver);
    362}
    363
    364module_init(acpi_processor_driver_init);
    365module_exit(acpi_processor_driver_exit);
    366
    367MODULE_ALIAS("processor");