ACPI: cpufreq: Switch to QoS requests instead of cpufreq notifier
[linux-2.6-block.git] / drivers / acpi / processor_perflib.c
index ee87cb6f6e5944f2cc843d1b9b56600d7edde6e6..2261713d1aec08ffe2f006ff8fd69c165b32a6de 100644 (file)
@@ -50,57 +50,13 @@ module_param(ignore_ppc, int, 0644);
 MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
                 "limited by BIOS, this should help");
 
-#define PPC_REGISTERED   1
-#define PPC_IN_USE       2
-
-static int acpi_processor_ppc_status;
-
-static int acpi_processor_ppc_notifier(struct notifier_block *nb,
-                                      unsigned long event, void *data)
-{
-       struct cpufreq_policy *policy = data;
-       struct acpi_processor *pr;
-       unsigned int ppc = 0;
-
-       if (ignore_ppc < 0)
-               ignore_ppc = 0;
-
-       if (ignore_ppc)
-               return 0;
-
-       if (event != CPUFREQ_ADJUST)
-               return 0;
-
-       mutex_lock(&performance_mutex);
-
-       pr = per_cpu(processors, policy->cpu);
-       if (!pr || !pr->performance)
-               goto out;
-
-       ppc = (unsigned int)pr->performance_platform_limit;
-
-       if (ppc >= pr->performance->state_count)
-               goto out;
-
-       cpufreq_verify_within_limits(policy, 0,
-                                    pr->performance->states[ppc].
-                                    core_frequency * 1000);
-
-      out:
-       mutex_unlock(&performance_mutex);
-
-       return 0;
-}
-
-static struct notifier_block acpi_ppc_notifier_block = {
-       .notifier_call = acpi_processor_ppc_notifier,
-};
+static bool acpi_processor_ppc_in_use;
 
 static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
 {
        acpi_status status = 0;
        unsigned long long ppc = 0;
-
+       int ret;
 
        if (!pr)
                return -EINVAL;
@@ -112,7 +68,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
        status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
 
        if (status != AE_NOT_FOUND)
-               acpi_processor_ppc_status |= PPC_IN_USE;
+               acpi_processor_ppc_in_use = true;
 
        if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
                ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
@@ -124,6 +80,17 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
 
        pr->performance_platform_limit = (int)ppc;
 
+       if (ppc >= pr->performance->state_count ||
+           unlikely(!dev_pm_qos_request_active(&pr->perflib_req)))
+               return 0;
+
+       ret = dev_pm_qos_update_request(&pr->perflib_req,
+                       pr->performance->states[ppc].core_frequency * 1000);
+       if (ret < 0) {
+               pr_warn("Failed to update perflib freq constraint: CPU%d (%d)\n",
+                       pr->id, ret);
+       }
+
        return 0;
 }
 
@@ -184,23 +151,32 @@ int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
 }
 EXPORT_SYMBOL(acpi_processor_get_bios_limit);
 
-void acpi_processor_ppc_init(void)
+void acpi_processor_ignore_ppc_init(void)
 {
-       if (!cpufreq_register_notifier
-           (&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER))
-               acpi_processor_ppc_status |= PPC_REGISTERED;
-       else
-               printk(KERN_DEBUG
-                      "Warning: Processor Platform Limit not supported.\n");
+       if (ignore_ppc < 0)
+               ignore_ppc = 0;
+}
+
+void acpi_processor_ppc_init(int cpu)
+{
+       struct acpi_processor *pr = per_cpu(processors, cpu);
+       int ret;
+
+       ret = dev_pm_qos_add_request(get_cpu_device(cpu),
+                                    &pr->perflib_req, DEV_PM_QOS_MAX_FREQUENCY,
+                                    INT_MAX);
+       if (ret < 0) {
+               pr_err("Failed to add freq constraint for CPU%d (%d)\n", cpu,
+                      ret);
+               return;
+       }
 }
 
-void acpi_processor_ppc_exit(void)
+void acpi_processor_ppc_exit(int cpu)
 {
-       if (acpi_processor_ppc_status & PPC_REGISTERED)
-               cpufreq_unregister_notifier(&acpi_ppc_notifier_block,
-                                           CPUFREQ_POLICY_NOTIFIER);
+       struct acpi_processor *pr = per_cpu(processors, cpu);
 
-       acpi_processor_ppc_status &= ~PPC_REGISTERED;
+       dev_pm_qos_remove_request(&pr->perflib_req);
 }
 
 static int acpi_processor_get_performance_control(struct acpi_processor *pr)
@@ -477,7 +453,7 @@ int acpi_processor_notify_smm(struct module *calling_module)
        static int is_done = 0;
        int result;
 
-       if (!(acpi_processor_ppc_status & PPC_REGISTERED))
+       if (!acpi_processor_cpufreq_init)
                return -EBUSY;
 
        if (!try_module_get(calling_module))
@@ -513,7 +489,7 @@ int acpi_processor_notify_smm(struct module *calling_module)
         * we can allow the cpufreq driver to be rmmod'ed. */
        is_done = 1;
 
-       if (!(acpi_processor_ppc_status & PPC_IN_USE))
+       if (!acpi_processor_ppc_in_use)
                module_put(calling_module);
 
        return 0;
@@ -742,7 +718,7 @@ acpi_processor_register_performance(struct acpi_processor_performance
 {
        struct acpi_processor *pr;
 
-       if (!(acpi_processor_ppc_status & PPC_REGISTERED))
+       if (!acpi_processor_cpufreq_init)
                return -EINVAL;
 
        mutex_lock(&performance_mutex);