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