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