| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * processor_driver.c - ACPI Processor Driver |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * - Added processor hotplug support |
|---|
| 9 | 10 | * Copyright (C) 2013, Intel Corporation |
|---|
| 10 | 11 | * 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 | 12 | */ |
|---|
| 26 | 13 | |
|---|
| 27 | 14 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 297 | 284 | return 0; |
|---|
| 298 | 285 | } |
|---|
| 299 | 286 | |
|---|
| 287 | +bool acpi_processor_cpufreq_init; |
|---|
| 288 | + |
|---|
| 289 | +static 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 | + |
|---|
| 305 | +static struct notifier_block acpi_processor_notifier_block = { |
|---|
| 306 | + .notifier_call = acpi_processor_notifier, |
|---|
| 307 | +}; |
|---|
| 308 | + |
|---|
| 300 | 309 | /* |
|---|
| 301 | 310 | * We keep the driver loaded even when ACPI is not running. |
|---|
| 302 | 311 | * This is needed for the powernow-k8 driver, that works even without |
|---|
| .. | .. |
|---|
| 323 | 332 | cpuhp_setup_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD, "acpi/cpu-drv:dead", |
|---|
| 324 | 333 | NULL, acpi_soft_cpu_dead); |
|---|
| 325 | 334 | |
|---|
| 326 | | - acpi_thermal_cpufreq_init(); |
|---|
| 327 | | - acpi_processor_ppc_init(); |
|---|
| 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 | + |
|---|
| 328 | 341 | acpi_processor_throttling_init(); |
|---|
| 329 | 342 | return 0; |
|---|
| 330 | 343 | err: |
|---|
| .. | .. |
|---|
| 337 | 350 | if (acpi_disabled) |
|---|
| 338 | 351 | return; |
|---|
| 339 | 352 | |
|---|
| 340 | | - acpi_processor_ppc_exit(); |
|---|
| 341 | | - acpi_thermal_cpufreq_exit(); |
|---|
| 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 | + |
|---|
| 342 | 359 | cpuhp_remove_state_nocalls(hp_online); |
|---|
| 343 | 360 | cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD); |
|---|
| 344 | 361 | driver_unregister(&acpi_processor_driver); |
|---|