From: Matthew Garrett <mjg@redhat.com> Date: Wed, 4 Mar 2009 11:36:49 +0000 Subject: [acpi] donot evaluate _PPC until _PSS has been evaluated Message-id: 20090304113649.GA28600@srcf.ucam.org O-Subject: [RHEL 5.4 PATCH] Do not evaluate _PPC until _PSS has been evaluated Bugzilla: 469105 RH-Acked-by: Prarit Bhargava <prarit@redhat.com> Some Thinkpads report a limited range of frequencies until the processor init functions have been called. We therefore need to avoid calling the _PPC method until the associated _PSS methods have been evaluated. This prevents inappropriate limiting of the system CPU frequency. Fixes 469105 diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 2f62eb2..473a5b7 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -61,10 +61,21 @@ static DEFINE_MUTEX(performance_mutex); * policy is adjusted accordingly. */ +/* ignore_ppc: + * -1 > cpufreq low level drivers not initialized > _PSS, etc. not called yet + * ignore _PPC + * 0 > cpufreq low level drivers initialized > consider _PPC values + * 1 > ignore _PPC totally > forced by user through boot param + */ +static int ignore_ppc = -1; +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 = 0; +static int acpi_processor_ppc_status; static int acpi_processor_ppc_notifier(struct notifier_block *nb, unsigned long event, void *data) @@ -73,6 +84,14 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, struct acpi_processor *pr; unsigned int ppc = 0; + if (event == CPUFREQ_START && ignore_ppc < 0) { + ignore_ppc = 0; + return 0; + } + + if (ignore_ppc) + return 0; + mutex_lock(&performance_mutex); if (event != CPUFREQ_INCOMPATIBLE) @@ -131,7 +150,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) int acpi_processor_ppc_has_changed(struct acpi_processor *pr) { - int ret = acpi_processor_get_platform_limit(pr); + int ret; + + if (ignore_ppc) + return 0; + + ret = acpi_processor_get_platform_limit(pr); + if (ret < 0) return (ret); else @@ -322,10 +347,6 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr) if (result) return result; - result = acpi_processor_get_platform_limit(pr); - if (result) - return result; - return 0; } diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3c90283..47442d4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -736,6 +736,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) goto err_out; } + blocking_notifier_call_chain(&cpufreq_policy_notifier_list, + CPUFREQ_START, policy); + #ifdef CONFIG_SMP for_each_cpu_mask(j, policy->cpus) { if (cpu == j) @@ -887,7 +890,6 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev) } cpufreq_cpu_data[cpu] = NULL; - #ifdef CONFIG_SMP /* if this isn't the CPU which is the parent of the kobj, we * only need to unlink, put and exit diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bf9ccbf..92e06e5 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -96,6 +96,7 @@ struct cpufreq_policy { #define CPUFREQ_ADJUST (0) #define CPUFREQ_INCOMPATIBLE (1) #define CPUFREQ_NOTIFY (2) +#define CPUFREQ_START (3) #define CPUFREQ_SHARED_TYPE_NONE (0) /* None */ #define CPUFREQ_SHARED_TYPE_HW (1) /* HW does needed coordination */