diff options
Diffstat (limited to 'drivers/acpi/processor_idle.c')
| -rw-r--r-- | drivers/acpi/processor_idle.c | 65 |
1 files changed, 23 insertions, 42 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 5dacf41d7cc0..4166090db642 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1357,48 +1357,7 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) return 0; } -void acpi_processor_register_idle_driver(void) -{ - struct acpi_processor *pr; - int ret = -ENODEV; - int cpu; - - /* - * Acpi idle driver is used by all possible CPUs. - * Install the idle handler by the processor power info of one in them. - * Note that we use previously set idle handler will be used on - * platforms that only support C1. - */ - for_each_cpu(cpu, (struct cpumask *)cpu_possible_mask) { - pr = per_cpu(processors, cpu); - if (!pr) - continue; - - ret = acpi_processor_get_power_info(pr); - if (!ret) { - pr->flags.power_setup_done = 1; - acpi_processor_setup_cpuidle_states(pr); - break; - } - } - - if (ret) { - pr_debug("No ACPI power information from any CPUs.\n"); - return; - } - - ret = cpuidle_register_driver(&acpi_idle_driver); - if (ret) { - pr_debug("register %s failed.\n", acpi_idle_driver.name); - return; - } - pr_debug("%s registered with cpuidle.\n", acpi_idle_driver.name); -} - -void acpi_processor_unregister_idle_driver(void) -{ - cpuidle_unregister_driver(&acpi_idle_driver); -} +static int acpi_processor_registered; int acpi_processor_power_init(struct acpi_processor *pr) { @@ -1413,7 +1372,22 @@ int acpi_processor_power_init(struct acpi_processor *pr) if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; + /* + * Install the idle handler if processor power management is supported. + * Note that we use previously set idle handler will be used on + * platforms that only support C1. + */ if (pr->flags.power) { + /* Register acpi_idle_driver if not already registered */ + if (!acpi_processor_registered) { + acpi_processor_setup_cpuidle_states(pr); + retval = cpuidle_register_driver(&acpi_idle_driver); + if (retval) + return retval; + pr_debug("%s registered with cpuidle\n", + acpi_idle_driver.name); + } + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1426,11 +1400,14 @@ int acpi_processor_power_init(struct acpi_processor *pr) */ retval = cpuidle_register_device(dev); if (retval) { + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); per_cpu(acpi_cpuidle_device, pr->id) = NULL; kfree(dev); return retval; } + acpi_processor_registered++; } return 0; } @@ -1444,6 +1421,10 @@ int acpi_processor_power_exit(struct acpi_processor *pr) if (pr->flags.power) { cpuidle_unregister_device(dev); + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + kfree(dev); } |