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