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