linux/drivers/acpi/processor_driver.c
<<
>>
Prefs
   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 || acpi_bus_get_device(pr->handle, &device))
 102                return 0;
 103        /*
 104         * CPU got physically hotplugged and onlined for the first time:
 105         * Initialize missing things.
 106         */
 107        if (pr->flags.need_hotplug_init) {
 108                int ret;
 109
 110                pr_info("Will online and init hotplugged CPU: %d\n",
 111                        pr->id);
 112                pr->flags.need_hotplug_init = 0;
 113                ret = __acpi_processor_start(device);
 114                WARN(ret, "Failed to start CPU: %d\n", pr->id);
 115        } else {
 116                /* Normal CPU soft online event. */
 117                acpi_processor_ppc_has_changed(pr, 0);
 118                acpi_processor_hotplug(pr);
 119                acpi_processor_reevaluate_tstate(pr, false);
 120                acpi_processor_tstate_has_changed(pr);
 121        }
 122        return 0;
 123}
 124
 125static int acpi_soft_cpu_dead(unsigned int cpu)
 126{
 127        struct acpi_processor *pr = per_cpu(processors, cpu);
 128        struct acpi_device *device;
 129
 130        if (!pr || acpi_bus_get_device(pr->handle, &device))
 131                return 0;
 132
 133        acpi_processor_reevaluate_tstate(pr, true);
 134        return 0;
 135}
 136
 137#ifdef CONFIG_ACPI_CPU_FREQ_PSS
 138static int acpi_pss_perf_init(struct acpi_processor *pr,
 139                struct acpi_device *device)
 140{
 141        int result = 0;
 142
 143        acpi_processor_ppc_has_changed(pr, 0);
 144
 145        acpi_processor_get_throttling_info(pr);
 146
 147        if (pr->flags.throttling)
 148                pr->flags.limit = 1;
 149
 150        pr->cdev = thermal_cooling_device_register("Processor", device,
 151                                                   &processor_cooling_ops);
 152        if (IS_ERR(pr->cdev)) {
 153                result = PTR_ERR(pr->cdev);
 154                return result;
 155        }
 156
 157        dev_dbg(&device->dev, "registered as cooling_device%d\n",
 158                pr->cdev->id);
 159
 160        result = sysfs_create_link(&device->dev.kobj,
 161                                   &pr->cdev->device.kobj,
 162                                   "thermal_cooling");
 163        if (result) {
 164                dev_err(&device->dev,
 165                        "Failed to create sysfs link 'thermal_cooling'\n");
 166                goto err_thermal_unregister;
 167        }
 168
 169        result = sysfs_create_link(&pr->cdev->device.kobj,
 170                                   &device->dev.kobj,
 171                                   "device");
 172        if (result) {
 173                dev_err(&pr->cdev->device,
 174                        "Failed to create sysfs link 'device'\n");
 175                goto err_remove_sysfs_thermal;
 176        }
 177
 178        return 0;
 179
 180 err_remove_sysfs_thermal:
 181        sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
 182 err_thermal_unregister:
 183        thermal_cooling_device_unregister(pr->cdev);
 184
 185        return result;
 186}
 187
 188static void acpi_pss_perf_exit(struct acpi_processor *pr,
 189                struct acpi_device *device)
 190{
 191        if (pr->cdev) {
 192                sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
 193                sysfs_remove_link(&pr->cdev->device.kobj, "device");
 194                thermal_cooling_device_unregister(pr->cdev);
 195                pr->cdev = NULL;
 196        }
 197}
 198#else
 199static inline int acpi_pss_perf_init(struct acpi_processor *pr,
 200                struct acpi_device *device)
 201{
 202        return 0;
 203}
 204
 205static inline void acpi_pss_perf_exit(struct acpi_processor *pr,
 206                struct acpi_device *device) {}
 207#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
 208
 209static int __acpi_processor_start(struct acpi_device *device)
 210{
 211        struct acpi_processor *pr = acpi_driver_data(device);
 212        acpi_status status;
 213        int result = 0;
 214
 215        if (!pr)
 216                return -ENODEV;
 217
 218        if (pr->flags.need_hotplug_init)
 219                return 0;
 220
 221        result = acpi_cppc_processor_probe(pr);
 222        if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS))
 223                dev_dbg(&device->dev, "CPPC data invalid or not present\n");
 224
 225        if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
 226                acpi_processor_power_init(pr);
 227
 228        result = acpi_pss_perf_init(pr, device);
 229        if (result)
 230                goto err_power_exit;
 231
 232        status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
 233                                             acpi_processor_notify, device);
 234        if (ACPI_SUCCESS(status))
 235                return 0;
 236
 237        result = -ENODEV;
 238        acpi_pss_perf_exit(pr, device);
 239
 240err_power_exit:
 241        acpi_processor_power_exit(pr);
 242        return result;
 243}
 244
 245static int acpi_processor_start(struct device *dev)
 246{
 247        struct acpi_device *device = ACPI_COMPANION(dev);
 248        int ret;
 249
 250        if (!device)
 251                return -ENODEV;
 252
 253        /* Protect against concurrent CPU hotplug operations */
 254        cpu_hotplug_disable();
 255        ret = __acpi_processor_start(device);
 256        cpu_hotplug_enable();
 257        return ret;
 258}
 259
 260static int acpi_processor_stop(struct device *dev)
 261{
 262        struct acpi_device *device = ACPI_COMPANION(dev);
 263        struct acpi_processor *pr;
 264
 265        if (!device)
 266                return 0;
 267
 268        acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
 269                                   acpi_processor_notify);
 270
 271        pr = acpi_driver_data(device);
 272        if (!pr)
 273                return 0;
 274        acpi_processor_power_exit(pr);
 275
 276        acpi_pss_perf_exit(pr, device);
 277
 278        acpi_cppc_processor_exit(pr);
 279
 280        return 0;
 281}
 282
 283bool acpi_processor_cpufreq_init;
 284
 285static int acpi_processor_notifier(struct notifier_block *nb,
 286                                   unsigned long event, void *data)
 287{
 288        struct cpufreq_policy *policy = data;
 289
 290        if (event == CPUFREQ_CREATE_POLICY) {
 291                acpi_thermal_cpufreq_init(policy);
 292                acpi_processor_ppc_init(policy);
 293        } else if (event == CPUFREQ_REMOVE_POLICY) {
 294                acpi_processor_ppc_exit(policy);
 295                acpi_thermal_cpufreq_exit(policy);
 296        }
 297
 298        return 0;
 299}
 300
 301static struct notifier_block acpi_processor_notifier_block = {
 302        .notifier_call = acpi_processor_notifier,
 303};
 304
 305/*
 306 * We keep the driver loaded even when ACPI is not running.
 307 * This is needed for the powernow-k8 driver, that works even without
 308 * ACPI, but needs symbols from this driver
 309 */
 310static enum cpuhp_state hp_online;
 311static int __init acpi_processor_driver_init(void)
 312{
 313        int result = 0;
 314
 315        if (acpi_disabled)
 316                return 0;
 317
 318        result = driver_register(&acpi_processor_driver);
 319        if (result < 0)
 320                return result;
 321
 322        result = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
 323                                           "acpi/cpu-drv:online",
 324                                           acpi_soft_cpu_online, NULL);
 325        if (result < 0)
 326                goto err;
 327        hp_online = result;
 328        cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead",
 329                                  NULL, acpi_soft_cpu_dead);
 330
 331        if (!cpufreq_register_notifier(&acpi_processor_notifier_block,
 332                                       CPUFREQ_POLICY_NOTIFIER)) {
 333                acpi_processor_cpufreq_init = true;
 334                acpi_processor_ignore_ppc_init();
 335        }
 336
 337        acpi_processor_throttling_init();
 338        return 0;
 339err:
 340        driver_unregister(&acpi_processor_driver);
 341        return result;
 342}
 343
 344static void __exit acpi_processor_driver_exit(void)
 345{
 346        if (acpi_disabled)
 347                return;
 348
 349        if (acpi_processor_cpufreq_init) {
 350                cpufreq_unregister_notifier(&acpi_processor_notifier_block,
 351                                            CPUFREQ_POLICY_NOTIFIER);
 352                acpi_processor_cpufreq_init = false;
 353        }
 354
 355        cpuhp_remove_state_nocalls(hp_online);
 356        cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD);
 357        driver_unregister(&acpi_processor_driver);
 358}
 359
 360module_init(acpi_processor_driver_init);
 361module_exit(acpi_processor_driver_exit);
 362
 363MODULE_ALIAS("processor");
 364