patch-2.4.6 linux/drivers/acpi/ospm/thermal/tzpolicy.c

Next file: linux/drivers/acpi/parser/Makefile
Previous file: linux/drivers/acpi/ospm/thermal/tz_osl.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/drivers/acpi/ospm/thermal/tzpolicy.c linux/drivers/acpi/ospm/thermal/tzpolicy.c
@@ -0,0 +1,640 @@
+/****************************************************************************
+ *
+ * Module Name: tzpolicy.c -
+ *   $Revision: 27 $
+ *
+ ****************************************************************************/
+
+/*
+ *  Copyright (C) 2000, 2001 Andrew Grover
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * TBD: 1. Move to user-space!
+ *	2. Support ACPI 2.0 items (e.g. _TZD, _HOT).
+ *      3. Support performance-limit control for non-processor devices
+ *         (those listed in _TZD, e.g. graphics).
+ */
+
+/* TBD: Linux specific */
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/pm.h>
+
+#include <acpi.h>
+#include <bm.h>
+#include "tz.h"
+
+
+#define _COMPONENT		ACPI_THERMAL
+	MODULE_NAME		("tzpolicy")
+
+
+/****************************************************************************
+ *                                  Globals
+ ****************************************************************************/
+
+extern int TZP;
+
+void
+tz_policy_run (
+	unsigned long           data);
+
+
+/****************************************************************************
+ *                              Internal Functions
+ ****************************************************************************/
+
+ACPI_STATUS
+set_performance_limit (
+	BM_HANDLE               device_handle,
+	u32			flag)
+{
+	ACPI_STATUS             status;
+	BM_REQUEST              request;
+
+	request.status = AE_OK;
+	request.handle = device_handle;
+	request.command = PR_COMMAND_SET_PERF_LIMIT;
+	request.buffer.length = sizeof(u32);
+	request.buffer.pointer = &flag;
+
+	status = bm_request(&request);
+
+	if (ACPI_FAILURE(status)) {
+		return status;
+	}
+	else {
+		return request.status;
+	}
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    tz_policy_critical
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+tz_policy_critical(
+	TZ_CONTEXT		*tz)
+{
+	if (!tz || !tz->policy.critical.threshold) {
+		return(AE_BAD_PARAMETER);
+	}
+
+	if (tz->policy.temperature >=
+		tz->policy.critical.threshold->temperature) {
+		/* TBD:	Need method for calling 'halt' - OSL function? */
+	}
+
+	return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    tz_policy_passive
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+tz_policy_passive(
+	TZ_CONTEXT		*tz)
+{
+	TZ_PASSIVE_POLICY	*passive = NULL;
+	static u32		last_temperature = 0;
+	s32			trend = 0;
+	u32			i = 0;
+
+	if (!tz || !tz->policy.passive.threshold) {
+		return(AE_BAD_PARAMETER);
+	}
+
+	passive = &(tz->policy.passive);
+
+	if (tz->policy.temperature >= passive->threshold->temperature) {
+		/*
+		 * Thermal trend?
+		 * --------------
+		 * Using the passive cooling equation (see the ACPI
+		 * Specification), calculate the current thermal trend
+		 * (a.k.a. performance delta).
+		 */
+		trend = passive->tc1 *
+			(tz->policy.temperature - last_temperature) +
+			passive->tc2 *
+			(tz->policy.temperature - passive->threshold->temperature);
+
+		last_temperature = tz->policy.temperature;
+
+		/*
+		 * Heating Up?
+		 * -----------
+		 * Decrease thermal performance limit on all passive
+		 * cooling devices (processors).
+		 */
+		if (trend > 0) {
+			for (i=0; i<passive->threshold->cooling_devices.count; i++) {
+				set_performance_limit(
+					passive->threshold->cooling_devices.handles[i],
+					PR_PERF_DEC);
+			}
+		}
+		/*
+		 * Cooling Off?
+		 * ------------
+		 * Increase thermal performance limit on all passive
+		 * cooling devices (processors).
+		 */
+		else if (trend < 0) {
+			for (i=0; i<passive->threshold->cooling_devices.count; i++) {
+				set_performance_limit(
+					passive->threshold->cooling_devices.handles[i],
+					PR_PERF_INC);
+			}
+		}
+	}
+
+	return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    tz_policy_active
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+tz_policy_active(
+	TZ_CONTEXT              *tz)
+{
+	ACPI_STATUS             status = AE_OK;
+	TZ_THRESHOLD            *active = NULL;
+	u32                     i,j = 0;
+
+	if (!tz || !tz->policy.active.threshold) {
+		return(AE_BAD_PARAMETER);
+	}
+
+	for (i = 0; i < TZ_MAX_ACTIVE_THRESHOLDS; i++) {
+
+		active = tz->policy.active.threshold[i];
+		if (!active) {
+			break;
+		}
+
+		/*
+		 * Above Threshold?
+		 * ----------------
+		 * If not already enabled, turn ON all cooling devices
+		 * associated with this active threshold.
+		 */
+		if ((tz->policy.temperature >= active->temperature) &&
+			(active->cooling_state != TZ_COOLING_ENABLED)) {
+
+			for (j = 0; j < active->cooling_devices.count; j++) {
+
+				status = bm_set_device_power_state(
+					active->cooling_devices.handles[j],
+					ACPI_STATE_D0);
+
+				if (ACPI_SUCCESS(status)) {
+				}
+				else {
+				}
+			}
+
+			active->cooling_state = TZ_COOLING_ENABLED;
+		}
+		/*
+		 * Below Threshold?
+		 * ----------------
+		 * Turn OFF all cooling devices associated with this
+		 * threshold.  Note that by checking "if not disabled" we
+		 * turn off all cooling devices for thresholds in the
+		 * TZ_COOLING_STATE_UNKNOWN state, useful as a level-set
+		 * during the first pass.
+		 */
+		else if (active->cooling_state != TZ_COOLING_DISABLED) {
+
+			for (j = 0; j < active->cooling_devices.count; j++) {
+
+				status = bm_set_device_power_state(
+					active->cooling_devices.handles[j],
+					ACPI_STATE_D3);
+
+				if (ACPI_SUCCESS(status)) {
+				}
+				else {
+				}
+			}
+
+			active->cooling_state = TZ_COOLING_DISABLED;
+		}
+	}
+
+	return(AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    tz_policy_check
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Note that this function will get called whenever:
+ *                1. A thermal event occurs.
+ *                2. The polling/sampling time period expires.
+ *
+ ****************************************************************************/
+
+void
+tz_policy_check (
+	void                    *context)
+{
+	ACPI_STATUS             status = AE_OK;
+	TZ_CONTEXT              *tz = NULL;
+	u32                     previous_temperature = 0;
+	u32                     previous_state = 0;
+	u32                     active_index = 0;
+	u32                     i = 0;
+	u32                     sleep_time = 0;
+
+	if (!context) {
+		return;
+	}
+
+	tz = (TZ_CONTEXT*)context;
+
+	/*
+	 * Preserve Previous State:
+	 * ------------------------
+	 */
+	previous_temperature = tz->policy.temperature;
+	previous_state = tz->policy.state;
+
+	/*
+	 * Get Temperature:
+	 * ----------------
+	 */
+	status = tz_get_temperature(tz, &(tz->policy.temperature));
+	if (ACPI_FAILURE(status)) {
+		return;
+	}
+
+	/*
+	 * Calculate State:
+	 * ----------------
+	 */
+	tz->policy.state = TZ_STATE_OK;
+
+	/* Critical? */
+	if ((tz->policy.critical.threshold) &&
+		(tz->policy.temperature >= tz->policy.critical.threshold->temperature)) {
+		tz->policy.state |= TZ_STATE_CRITICAL;
+	}
+
+	/* Passive? */
+	if ((tz->policy.passive.threshold) &&
+		(tz->policy.temperature >= tz->policy.passive.threshold->temperature)) {
+		tz->policy.state |= TZ_STATE_PASSIVE;
+	}
+
+	/* Active? */
+	if (tz->policy.active.threshold[0]) {
+		for (i=0; i<tz->policy.active.threshold_count; i++) {
+			if ((tz->policy.active.threshold[i]) &&
+				(tz->policy.temperature >= tz->policy.active.threshold[i]->temperature)) {
+			    tz->policy.state |= TZ_STATE_ACTIVE;
+			    if (tz->policy.active.threshold[i]->index > active_index) {
+				    active_index = tz->policy.active.threshold[i]->index;
+			    }
+			}
+		}
+		tz->policy.state |= active_index;
+	}
+
+	/*
+	 * Invoke Policy:
+	 * --------------
+	 * Note that policy must be invoked both when 'going into' a
+	 * policy state (e.g. to allow fans to be turned on) and 'going
+	 * out of' a policy state (e.g. to allow fans to be turned off);
+	 * thus we must preserve the previous state.
+	 */
+	if (tz->policy.state & TZ_STATE_CRITICAL) {
+		tz_policy_critical(tz);
+	}
+	if ((tz->policy.state & TZ_STATE_PASSIVE) ||
+		(previous_state & TZ_STATE_PASSIVE)) {
+		tz_policy_passive(tz);
+	}
+	if ((tz->policy.state & TZ_STATE_ACTIVE) ||
+		(previous_state & TZ_STATE_ACTIVE)) {
+		tz_policy_active(tz);
+	}
+
+	/*
+	 * Calculate Sleep Time:
+	 * ---------------------
+	 * If we're in the passive state, use _TSP's value.  Otherwise
+	 * use _TZP or the OS's default polling frequency.  If no polling
+	 * frequency is specified then we'll wait forever (that is, until
+	 * a thermal event occurs -- e.g. never poll).  Note that _TSP
+	 * and _TZD values are given in 1/10th seconds.
+	 */
+	if (tz->policy.state & TZ_STATE_PASSIVE) {
+		sleep_time = tz->policy.passive.tsp * 100;
+	}
+	else if (tz->policy.polling_freq > 0) {
+		sleep_time = tz->policy.polling_freq * 100;
+	}
+	else {
+		sleep_time = WAIT_FOREVER;
+	}
+
+
+	/*
+	 * Schedule Next Poll:
+	 * -------------------
+	 */
+	if (sleep_time < WAIT_FOREVER) {
+		if (timer_pending(&(tz->policy.timer))) {
+			mod_timer(&(tz->policy.timer),
+				(HZ*sleep_time)/1000);
+		}
+		else {
+			tz->policy.timer.data = (u32)tz;
+			tz->policy.timer.function = tz_policy_run;
+			tz->policy.timer.expires =
+				jiffies + (HZ*sleep_time)/1000;
+			add_timer(&(tz->policy.timer));
+		}
+	}
+	else {
+		if (timer_pending(&(tz->policy.timer))) {
+			del_timer(&(tz->policy.timer));
+		}
+	}
+
+	return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    tz_policy_run
+ *
+ * PARAMETERS:
+ *
+ * RETURN:
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+void
+tz_policy_run (
+	unsigned long           data)
+{
+	ACPI_STATUS             status = AE_OK;
+
+	if (!data) {
+		return;
+	}
+
+	/*
+	 * Defer to Non-Interrupt Level:
+	 * -----------------------------
+	 * Note that all Linux kernel timers run at interrupt-level (ack!).
+	 */
+	status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+		tz_policy_check, (void*)data);
+	if (ACPI_FAILURE(status)) {
+	}
+
+	return;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    tz_policy_add_device
+ *
+ * PARAMETERS:
+ *
+ * RETURN:	
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+tz_policy_add_device (
+	TZ_CONTEXT		*tz)
+{
+	ACPI_STATUS             status = AE_OK;
+	TZ_THRESHOLD            *threshold = NULL;
+	u32                     i,j = 0;
+
+	if (!tz) {
+		return(AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * Temperature:
+	 * ------------
+	 * Make sure we can read the zone's current temperature (_TMP).
+	 * If we can't, there's no use in doing any policy (abort).
+	 */
+	status = tz_get_temperature(tz, &(tz->policy.temperature));
+	if (ACPI_FAILURE(status)) {
+		return(status);
+	}
+
+	/*
+	 * Polling Frequency:
+	 * ------------------
+	 * If a _TZP object doesn't exist, use the OS default polling
+	 * frequency.
+	 */
+	status = bm_evaluate_simple_integer(tz->acpi_handle, "_TZP",
+		&(tz->policy.polling_freq));
+	if (ACPI_FAILURE(status)) {
+		tz->policy.polling_freq = TZP;
+	}
+	status = AE_OK;
+
+	/*
+	 * Get Thresholds:
+	 * ---------------
+	 * Get all of the zone's thresholds, parse, and organize for
+	 * later use.
+	 */
+	status = tz_get_thresholds(tz, &(tz->policy.threshold_list));
+	if (ACPI_FAILURE(status)) {
+		return(status);
+	}
+
+	/*
+	 * Initialize Policies:
+	 * --------------------
+	 */
+	for (i = 0; i < tz->policy.threshold_list.count; i++) {
+
+		threshold = &(tz->policy.threshold_list.thresholds[i]);
+
+		switch (threshold->type) {
+
+		case TZ_THRESHOLD_CRITICAL:
+			tz->policy.critical.threshold = threshold;
+			break;
+
+		case TZ_THRESHOLD_PASSIVE:
+
+			/*
+			 * Set thermal performance limit on all processors
+			 * to max.
+			 */
+			for (j=0; j<threshold->cooling_devices.count; j++) {
+				set_performance_limit(
+					threshold->cooling_devices.handles[j],
+					PR_PERF_MAX);
+			}
+
+			/*
+			 * Get passive cooling constants.
+			 */
+			status = bm_evaluate_simple_integer(tz->acpi_handle,
+				"_TC1", &(tz->policy.passive.tc1));
+			if (ACPI_FAILURE(status)) {
+				break;
+			}
+
+			status = bm_evaluate_simple_integer(tz->acpi_handle,
+				"_TC2", &(tz->policy.passive.tc2));
+			if (ACPI_FAILURE(status)) {
+				break;
+			}
+
+			status = bm_evaluate_simple_integer(tz->acpi_handle,
+				"_TSP", &(tz->policy.passive.tsp));
+			if (ACPI_FAILURE(status)) {
+				break;
+			}
+
+			tz->policy.passive.threshold = threshold;
+
+			tz_policy_passive(tz);
+
+			break;
+
+		case TZ_THRESHOLD_ACTIVE:
+			tz->policy.active.threshold[threshold->index] = threshold;
+			tz_policy_active(tz);
+			break;
+		}
+	}
+
+	if (ACPI_FAILURE(status)) {
+		return(status);
+	}
+
+	/*
+	 * Initialize Policy Timer:
+	 * ------------------------
+	 * TBD: Linux-specific - remove when policy moves to user-space.
+	 */
+	init_timer(&(tz->policy.timer));
+
+	/*
+	 * Start Policy:
+	 * -------------
+	 * Run an initial check using this zone's policy.
+	 */
+	tz_policy_check(tz);
+
+	return(status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION:    tz_policy_remove_device
+ *
+ * PARAMETERS:
+ *
+ * RETURN:	
+ *
+ * DESCRIPTION:
+ *
+ ****************************************************************************/
+
+ACPI_STATUS
+tz_policy_remove_device(
+	TZ_CONTEXT		*tz)
+{
+	u32			i = 0;
+
+	if (!tz) {
+		return(AE_BAD_PARAMETER);
+	}
+
+	/*
+	 * Delete the thermal zone policy timer entry, if exists.
+	 */
+	if (timer_pending(&(tz->policy.timer))) {
+		del_timer(&(tz->policy.timer));
+	}
+
+	/*
+	 * Reset thermal performance limit on all processors back to max.
+	 */
+	if (tz->policy.passive.threshold) {
+		for (i=0; i<tz->policy.passive.threshold->cooling_devices.count; i++) {
+			set_performance_limit(
+				tz->policy.passive.threshold->cooling_devices.handles[i],
+				PR_PERF_MAX);
+		}
+	}
+
+	return(AE_OK);
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)