From 21bc42ab852549f4a547d18d77e0e4d1b24ffd96 Mon Sep 17 00:00:00 2001
From: Len Brown <len.brown@intel.com>
Date: Tue, 4 Sep 2007 12:49:22 -0400
Subject: ACPI: thermal: use round_jiffies when thermal zone polling is enabled

Properly functioning systems do not use thermal zone polling,
they use event-based notification.

However, some users enable periodic thermal zone polling
to work around bugs on their platforms, and at least one
platform exists with a real _TZP that requests polling.

While thermal zone polling (_TZP) is specified in units to 0.1 seconds,
it actually has a maximum granularity of 1 second.  Thus, we can safely
round up the _TZP timeout to occur on the next 1-second boundary.
This will batch it with other 1-second-granularity timers in the
system and thus potentially extend processor idle duration.

Note that the same timer is used both for _TZP
and for passive processor thermal throttling.
We can not round up the timeout when it is used
for passive thermal throttling.

Also, we can not make this a deferrable timer,
as temperature is just as relevant during idle
as it is during non-idle.

Signed-off-by: Len Brown <len.brown@intel.com>
---
 drivers/acpi/thermal.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

(limited to 'drivers/acpi')

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index bc6d5866ef98..15d5fdc66a96 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -711,6 +711,7 @@ static void acpi_thermal_check(void *data)
 	int result = 0;
 	struct acpi_thermal *tz = data;
 	unsigned long sleep_time = 0;
+	unsigned long timeout_jiffies = 0;
 	int i = 0;
 	struct acpi_thermal_state state;
 
@@ -787,10 +788,13 @@ static void acpi_thermal_check(void *data)
 	 * a thermal event occurs).  Note that _TSP and _TZD values are
 	 * given in 1/10th seconds (we must covert to milliseconds).
 	 */
-	if (tz->state.passive)
+	if (tz->state.passive) {
 		sleep_time = tz->trips.passive.tsp * 100;
-	else if (tz->polling_frequency > 0)
+		timeout_jiffies =  jiffies + (HZ * sleep_time) / 1000;
+	} else if (tz->polling_frequency > 0) {
 		sleep_time = tz->polling_frequency * 100;
+		timeout_jiffies =  round_jiffies(jiffies + (HZ * sleep_time) / 1000);
+	}
 
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
 			  tz->name, tz->temperature, sleep_time));
@@ -804,12 +808,11 @@ static void acpi_thermal_check(void *data)
 			del_timer(&(tz->timer));
 	} else {
 		if (timer_pending(&(tz->timer)))
-			mod_timer(&(tz->timer),
-					jiffies + (HZ * sleep_time) / 1000);
+			mod_timer(&(tz->timer), timeout_jiffies);
 		else {
 			tz->timer.data = (unsigned long)tz;
 			tz->timer.function = acpi_thermal_run;
-			tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+			tz->timer.expires = timeout_jiffies;
 			add_timer(&(tz->timer));
 		}
 	}
-- 
cgit v1.2.3


From 6e2157858ac94530fddbf19dc59ab6b392baf1f3 Mon Sep 17 00:00:00 2001
From: Alexey Starikovskiy <astarikovskiy@suse.de>
Date: Sat, 1 Sep 2007 00:11:59 +0400
Subject: ACPI: Thermal: Drop concurrent thermal checks

Fix for #3686, where get_temperature() may cause thermal notify, which
causes one more get_temperature().

Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
---
 drivers/acpi/thermal.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

(limited to 'drivers/acpi')

diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 15d5fdc66a96..69ec73b0239d 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -195,6 +195,7 @@ struct acpi_thermal {
 	struct acpi_thermal_trips trips;
 	struct acpi_handle_list devices;
 	struct timer_list timer;
+	struct mutex lock;
 };
 
 static const struct file_operations acpi_thermal_state_fops = {
@@ -721,11 +722,15 @@ static void acpi_thermal_check(void *data)
 		return;
 	}
 
+	/* Check if someone else is already running */
+	if (!mutex_trylock(&tz->lock))
+		return;
+
 	state = tz->state;
 
 	result = acpi_thermal_get_temperature(tz);
 	if (result)
-		return;
+		goto unlock;
 
 	memset(&tz->state, 0, sizeof(tz->state));
 
@@ -816,8 +821,8 @@ static void acpi_thermal_check(void *data)
 			add_timer(&(tz->timer));
 		}
 	}
-
-	return;
+      unlock:
+	mutex_unlock(&tz->lock);
 }
 
 /* --------------------------------------------------------------------------
@@ -1254,7 +1259,7 @@ static int acpi_thermal_add(struct acpi_device *device)
 	strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
 	acpi_driver_data(device) = tz;
-
+	mutex_init(&tz->lock);
 	result = acpi_thermal_get_info(tz);
 	if (result)
 		goto end;
@@ -1324,7 +1329,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
 	}
 
 	acpi_thermal_remove_fs(device);
-
+	mutex_destroy(&tz->lock);
 	kfree(tz);
 	return 0;
 }
-- 
cgit v1.2.3