3e5e72a
From 9a056a5843ff83db987d6e18625f4a2ee64b5450 Mon Sep 17 00:00:00 2001
3e5e72a
From: Matthew Garrett <mjg@redhat.com>
3e5e72a
Date: Tue, 30 Aug 2011 10:07:24 -0400
3e5e72a
Subject: [PATCH] ACPI: Ensure thermal limits match CPU frequencies
3e5e72a
650d9cd
The ACPI thermal management code supports slowing down a CPU when it's
650d9cd
overheating. Right now that's done by choosing to run it at 100%, 75%, 50%
650d9cd
or 25% of full speed. However, most CPUs do not allow an arbitrary
650d9cd
frequency to be set and so will run at the first frequency below that value.
650d9cd
This doesn't match the intent of the specification, which is to drop the
650d9cd
frequency state by state until the temperature stabalises. Fix this up
650d9cd
so it uses actual frequencies rather than percentages.
650d9cd
650d9cd
Reported by: Gene Snider <snider6982@comcast.net>
650d9cd
Signed-off-by: Matthew Garrett <mjg@redhat.com>
650d9cd
---
3e5e72a
 drivers/acpi/Kconfig             |    1 +
650d9cd
 drivers/acpi/processor_thermal.c |   45 +++++++++++++++++++++----------------
3e5e72a
 2 files changed, 26 insertions(+), 20 deletions(-)
650d9cd
3e5e72a
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
3e5e72a
index de0e3df..7d1bdb5 100644
3e5e72a
--- a/drivers/acpi/Kconfig
3e5e72a
+++ b/drivers/acpi/Kconfig
3e5e72a
@@ -185,6 +185,7 @@ config ACPI_PROCESSOR
3e5e72a
 	tristate "Processor"
3e5e72a
 	select THERMAL
3e5e72a
 	select CPU_IDLE
3e5e72a
+	select CPU_FREQ_TABLE
3e5e72a
 	default y
3e5e72a
 	help
3e5e72a
 	  This driver installs ACPI as the idle handler for Linux and uses
650d9cd
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
650d9cd
index 870550d..1c4eb60 100644
650d9cd
--- a/drivers/acpi/processor_thermal.c
650d9cd
+++ b/drivers/acpi/processor_thermal.c
650d9cd
@@ -52,10 +52,8 @@ ACPI_MODULE_NAME("processor_thermal");
650d9cd
  * _any_ cpufreq driver and not only the acpi-cpufreq driver.
650d9cd
  */
650d9cd
 
650d9cd
-#define CPUFREQ_THERMAL_MIN_STEP 0
650d9cd
-#define CPUFREQ_THERMAL_MAX_STEP 3
650d9cd
 
650d9cd
-static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
650d9cd
+static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_limit_state);
650d9cd
 static unsigned int acpi_thermal_cpufreq_is_init = 0;
650d9cd
 
650d9cd
 static int cpu_has_cpufreq(unsigned int cpu)
650d9cd
@@ -70,19 +68,19 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
650d9cd
 					 unsigned long event, void *data)
650d9cd
 {
650d9cd
 	struct cpufreq_policy *policy = data;
650d9cd
-	unsigned long max_freq = 0;
650d9cd
+	int state = per_cpu(cpufreq_thermal_limit_state, policy->cpu);
650d9cd
+	struct cpufreq_frequency_table *table;
650d9cd
 
650d9cd
 	if (event != CPUFREQ_ADJUST)
650d9cd
-		goto out;
650d9cd
+		return 0;
650d9cd
+
650d9cd
+	table = cpufreq_frequency_get_table(policy->cpu);
650d9cd
 
650d9cd
-	max_freq = (
650d9cd
-	    policy->cpuinfo.max_freq *
650d9cd
-	    (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20)
650d9cd
-	) / 100;
650d9cd
+	if (!table)
650d9cd
+		return 0;
650d9cd
 
650d9cd
-	cpufreq_verify_within_limits(policy, 0, max_freq);
650d9cd
+	cpufreq_verify_within_limits(policy, 0, table[state].frequency);
650d9cd
 
650d9cd
-      out:
650d9cd
 	return 0;
650d9cd
 }
650d9cd
 
650d9cd
@@ -92,10 +90,21 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
650d9cd
 
650d9cd
 static int cpufreq_get_max_state(unsigned int cpu)
650d9cd
 {
650d9cd
+	int count = 0;
650d9cd
+	struct cpufreq_frequency_table *table;
650d9cd
+
650d9cd
 	if (!cpu_has_cpufreq(cpu))
650d9cd
 		return 0;
650d9cd
 
650d9cd
-	return CPUFREQ_THERMAL_MAX_STEP;
650d9cd
+	table = cpufreq_frequency_get_table(cpu);
650d9cd
+
650d9cd
+	if (!table)
650d9cd
+		return 0;
650d9cd
+
650d9cd
+	while (table[count].frequency != CPUFREQ_TABLE_END)
650d9cd
+		count++;
650d9cd
+
650d9cd
+	return count;
650d9cd
 }
650d9cd
 
650d9cd
 static int cpufreq_get_cur_state(unsigned int cpu)
650d9cd
@@ -103,7 +112,7 @@ static int cpufreq_get_cur_state(unsigned int cpu)
650d9cd
 	if (!cpu_has_cpufreq(cpu))
650d9cd
 		return 0;
650d9cd
 
650d9cd
-	return per_cpu(cpufreq_thermal_reduction_pctg, cpu);
650d9cd
+	return per_cpu(cpufreq_thermal_limit_state, cpu);
650d9cd
 }
650d9cd
 
650d9cd
 static int cpufreq_set_cur_state(unsigned int cpu, int state)
650d9cd
@@ -111,7 +120,7 @@ static int cpufreq_set_cur_state(unsigned int cpu, int state)
650d9cd
 	if (!cpu_has_cpufreq(cpu))
650d9cd
 		return 0;
650d9cd
 
650d9cd
-	per_cpu(cpufreq_thermal_reduction_pctg, cpu) = state;
650d9cd
+	per_cpu(cpufreq_thermal_limit_state, cpu) = state;
650d9cd
 	cpufreq_update_policy(cpu);
650d9cd
 	return 0;
650d9cd
 }
650d9cd
@@ -122,7 +131,7 @@ void acpi_thermal_cpufreq_init(void)
650d9cd
 
650d9cd
 	for (i = 0; i < nr_cpu_ids; i++)
650d9cd
 		if (cpu_present(i))
650d9cd
-			per_cpu(cpufreq_thermal_reduction_pctg, i) = 0;
650d9cd
+			per_cpu(cpufreq_thermal_limit_state, i) = 0;
650d9cd
 
650d9cd
 	i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block,
650d9cd
 				      CPUFREQ_POLICY_NOTIFIER);
650d9cd
@@ -170,15 +179,11 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
650d9cd
 	return 0;
650d9cd
 }
650d9cd
 
650d9cd
-/* thermal coolign device callbacks */
650d9cd
+/* thermal cooling device callbacks */
650d9cd
 static int acpi_processor_max_state(struct acpi_processor *pr)
650d9cd
 {
650d9cd
 	int max_state = 0;
650d9cd
 
650d9cd
-	/*
650d9cd
-	 * There exists four states according to
650d9cd
-	 * cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
650d9cd
-	 */
650d9cd
 	max_state += cpufreq_get_max_state(pr->id);
650d9cd
 	if (pr->flags.throttling)
650d9cd
 		max_state += (pr->throttling.state_count -1);
650d9cd
-- 
3e5e72a
1.7.6
650d9cd