1/****************************************************************************
2 *
3 * Module Name: tzpolicy.c -
4 *   $Revision: 1.1.1.1 $
5 *
6 ****************************************************************************/
7
8/*
9 *  Copyright (C) 2000, 2001 Andrew Grover
10 *
11 *  This program is free software; you can redistribute it and/or modify
12 *  it under the terms of the GNU General Public License as published by
13 *  the Free Software Foundation; either version 2 of the License, or
14 *  (at your option) any later version.
15 *
16 *  This program is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 *  GNU General Public License for more details.
20 *
21 *  You should have received a copy of the GNU General Public License
22 *  along with this program; if not, write to the Free Software
23 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 */
25
26/*
27 * TBD: 1. Support performance-limit control for non-processor devices
28 *         (those listed in _TZD, e.g. graphics).
29 */
30
31#include <linux/proc_fs.h>
32#include <linux/sysctl.h>
33#include <linux/pm.h>
34
35#include <acpi.h>
36#include <bm.h>
37#include "tz.h"
38
39
40#define _COMPONENT		ACPI_THERMAL
41	MODULE_NAME		("tzpolicy")
42
43
44/****************************************************************************
45 *                                  Globals
46 ****************************************************************************/
47
48void
49tz_policy_run (
50	unsigned long           data);
51
52
53/****************************************************************************
54 *                              Internal Functions
55 ****************************************************************************/
56
57acpi_status
58set_performance_limit (
59	BM_HANDLE               device_handle,
60	u32			flag)
61{
62	acpi_status             status;
63	BM_REQUEST              request;
64
65	request.status = AE_OK;
66	request.handle = device_handle;
67	request.command = PR_COMMAND_SET_PERF_LIMIT;
68	request.buffer.length = sizeof(u32);
69	request.buffer.pointer = &flag;
70
71	status = bm_request(&request);
72
73	if (ACPI_FAILURE(status))
74		return status;
75	else
76		return request.status;
77}
78
79
80/****************************************************************************
81 *
82 * FUNCTION:    tz_policy_critical
83 *
84 * PARAMETERS:
85 *
86 * RETURN:
87 *
88 * DESCRIPTION:
89 *
90 ****************************************************************************/
91
92acpi_status
93tz_policy_critical(
94	TZ_CONTEXT		*tz)
95{
96	FUNCTION_TRACE("tz_policy_critical");
97
98	if (!tz) {
99		return_ACPI_STATUS(AE_BAD_PARAMETER);
100	}
101
102	if (tz->policy.temperature >= tz->policy.thresholds.critical.temperature) {
103		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Critical (S5) threshold reached.\n"));
104		/* TBD:	Need method for shutting down system. */
105	}
106
107	return_ACPI_STATUS(AE_OK);
108}
109
110
111/****************************************************************************
112 *
113 * FUNCTION:    tz_policy_hot
114 *
115 * PARAMETERS:
116 *
117 * RETURN:
118 *
119 * DESCRIPTION:
120 *
121 ****************************************************************************/
122
123acpi_status
124tz_policy_hot(
125	TZ_CONTEXT		*tz)
126{
127	FUNCTION_TRACE("tz_policy_hot");
128
129	if (!tz || !tz->policy.thresholds.hot.is_valid) {
130		return_ACPI_STATUS(AE_BAD_PARAMETER);
131	}
132
133	if (tz->policy.temperature >= tz->policy.thresholds.hot.temperature) {
134		ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Critical (S4) threshold reached.\n"));
135		/* TBD:	Need method for invoking OS-level critical suspend. */
136	}
137
138	return_ACPI_STATUS(AE_OK);
139}
140
141
142/****************************************************************************
143 *
144 * FUNCTION:    tz_policy_passive
145 *
146 * PARAMETERS:
147 *
148 * RETURN:
149 *
150 * DESCRIPTION:
151 *
152 ****************************************************************************/
153
154acpi_status
155tz_policy_passive(
156	TZ_CONTEXT		*tz)
157{
158	TZ_PASSIVE_THRESHOLD	*passive = NULL;
159	static u32		last_temperature = 0;
160	s32			trend = 0;
161	u32			i = 0;
162
163	FUNCTION_TRACE("tz_policy_passive");
164
165	if (!tz || !tz->policy.thresholds.passive.is_valid) {
166		return_ACPI_STATUS(AE_BAD_PARAMETER);
167	}
168
169	passive = &(tz->policy.thresholds.passive);
170
171	if (tz->policy.temperature >= passive->temperature) {
172		/*
173		 * Thermal trend?
174		 * --------------
175		 * Using the passive cooling equation (see the ACPI
176		 * Specification), calculate the current thermal trend
177		 * (a.k.a. performance delta).
178		 */
179		trend = passive->tc1 * (tz->policy.temperature - last_temperature) + passive->tc2 * (tz->policy.temperature - passive->temperature);
180		ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "trend[%d] = TC1[%d]*(temp[%d]-last[%d]) + TC2[%d]*(temp[%d]-passive[%d])\n", trend, passive->tc1, tz->policy.temperature, last_temperature, passive->tc2, tz->policy.temperature, passive->temperature));
181
182		last_temperature = tz->policy.temperature;
183
184		/*
185		 * Heating Up?
186		 * -----------
187		 * Decrease thermal performance limit on all passive
188		 * cooling devices (processors).
189		 */
190		if (trend > 0) {
191			for (i=0; i<passive->devices.count; i++)
192				set_performance_limit(passive->devices.handles[i], PR_PERF_DEC);
193		}
194		/*
195		 * Cooling Off?
196		 * ------------
197		 * Increase thermal performance limit on all passive
198		 * cooling devices (processors).
199		 */
200		else if (trend < 0) {
201			for (i=0; i<passive->devices.count; i++)
202				set_performance_limit(passive->devices.handles[i], PR_PERF_INC);
203		}
204	}
205
206	return_ACPI_STATUS(AE_OK);
207}
208
209
210/****************************************************************************
211 *
212 * FUNCTION:    tz_policy_active
213 *
214 * PARAMETERS:
215 *
216 * RETURN:
217 *
218 * DESCRIPTION:
219 *
220 ****************************************************************************/
221
222acpi_status
223tz_policy_active(
224	TZ_CONTEXT              *tz)
225{
226	acpi_status             status = AE_OK;
227	TZ_ACTIVE_THRESHOLD	*active = NULL;
228	u32                     i,j = 0;
229
230	FUNCTION_TRACE("tz_policy_active");
231
232	if (!tz || !tz->policy.thresholds.active[0].is_valid) {
233		return_ACPI_STATUS(AE_BAD_PARAMETER);
234	}
235
236	for (i=0; i<TZ_MAX_ACTIVE_THRESHOLDS; i++) {
237
238		active = &(tz->policy.thresholds.active[i]);
239		if (!active || !active->is_valid)
240			break;
241
242		/*
243		 * Above Threshold?
244		 * ----------------
245		 * If not already enabled, turn ON all cooling devices
246		 * associated with this active threshold.
247		 */
248		if ((tz->policy.temperature >= active->temperature) && (active->cooling_state != TZ_COOLING_ENABLED)) {
249			for (j = 0; j < active->devices.count; j++) {
250				status = bm_set_device_power_state(active->devices.handles[j], ACPI_STATE_D0);
251				if (ACPI_SUCCESS(status)) {
252					ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Cooling device [%02x] now ON.\n", active->devices.handles[j]));
253				}
254				else {
255					ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to turn ON cooling device [%02x].\n", active->devices.handles[j]));
256				}
257			}
258  			active->cooling_state = TZ_COOLING_ENABLED;
259		}
260		/*
261		 * Below Threshold?
262		 * ----------------
263		 * Turn OFF all cooling devices associated with this
264		 * threshold.  Note that by checking "if not disabled" we
265		 * turn off all cooling devices for thresholds in the
266		 * TZ_COOLING_STATE_UNKNOWN state, useful as a level-set
267		 * during the first pass.
268		 */
269		else if (active->cooling_state != TZ_COOLING_DISABLED) {
270			for (j = 0; j < active->devices.count; j++) {
271				status = bm_set_device_power_state(active->devices.handles[j], ACPI_STATE_D3);
272				if (ACPI_SUCCESS(status)) {
273					ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Cooling device [%02x] now OFF.\n", active->devices.handles[j]));
274				}
275				else {
276					ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Unable to turn OFF cooling device [%02x].\n", active->devices.handles[j]));
277				}
278			}
279			active->cooling_state = TZ_COOLING_DISABLED;
280		}
281	}
282
283	return_ACPI_STATUS(AE_OK);
284}
285
286
287/****************************************************************************
288 *
289 * FUNCTION:    tz_policy_check
290 *
291 * PARAMETERS:
292 *
293 * RETURN:
294 *
295 * DESCRIPTION: Note that this function will get called whenever:
296 *                1. A thermal event occurs.
297 *                2. The polling/sampling time period expires.
298 *
299 ****************************************************************************/
300
301void
302tz_policy_check (
303	void                    *context)
304{
305	acpi_status             status = AE_OK;
306	TZ_CONTEXT              *tz = NULL;
307	TZ_POLICY		*policy = NULL;
308	TZ_THRESHOLDS		*thresholds = NULL;
309	u32                     previous_temperature = 0;
310	u32                     previous_state = 0;
311	u32                     active_index = 0;
312	u32                     i = 0;
313	u32                     sleep_time = 0;
314
315	FUNCTION_TRACE("tz_policy_check");
316
317	if (!context) {
318		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
319		return_VOID;
320	}
321
322	tz = (TZ_CONTEXT*)context;
323	policy = &(tz->policy);
324	thresholds = &(tz->policy.thresholds);
325
326	/*
327	 * Preserve Previous State:
328	 * ------------------------
329	 */
330	previous_temperature = tz->policy.temperature;
331	previous_state = tz->policy.state;
332
333	/*
334	 * Get Temperature:
335	 * ----------------
336	 */
337	status = tz_get_temperature(tz);
338	if (ACPI_FAILURE(status)) {
339		return_VOID;
340	}
341
342	/*
343	 * Calculate State:
344	 * ----------------
345	 */
346	policy->state = TZ_STATE_OK;
347
348	/* Critical? */
349	if (policy->temperature >= thresholds->critical.temperature)
350		policy->state |= TZ_STATE_CRITICAL;
351
352	/* Hot? */
353	if ((thresholds->hot.is_valid) &&  (policy->temperature >= thresholds->hot.temperature))
354		policy->state |= TZ_STATE_CRITICAL;
355
356	/* Passive? */
357	if ((thresholds->passive.is_valid) && (policy->temperature >= thresholds->passive.temperature))
358		policy->state |= TZ_STATE_PASSIVE;
359
360	/* Active? */
361	if (thresholds->active[0].is_valid) {
362		for (i=0; i<TZ_MAX_ACTIVE_THRESHOLDS; i++) {
363			if ((thresholds->active[i].is_valid) && (policy->temperature >= thresholds->active[i].temperature)) {
364				policy->state |= TZ_STATE_ACTIVE;
365				if (i > active_index)
366					active_index = i;
367			}
368		}
369		policy->state |= active_index;
370	}
371
372	/*
373	 * Invoke Policy:
374	 * --------------
375	 * Note that policy must be invoked both when 'going into' a
376	 * policy state (e.g. to allow fans to be turned on) and 'going
377	 * out of' a policy state (e.g. to allow fans to be turned off);
378	 * thus we must preserve the previous state.
379	 */
380	if (policy->state & TZ_STATE_CRITICAL)
381		tz_policy_critical(tz);
382	if (policy->state & TZ_STATE_HOT)
383		tz_policy_hot(tz);
384	if ((policy->state & TZ_STATE_PASSIVE) || (previous_state & TZ_STATE_PASSIVE))
385		tz_policy_passive(tz);
386	if ((policy->state & TZ_STATE_ACTIVE) || (previous_state & TZ_STATE_ACTIVE))
387		tz_policy_active(tz);
388
389	/*
390	 * Calculate Sleep Time:
391	 * ---------------------
392	 * If we're in the passive state, use _TSP's value.  Otherwise
393	 * use _TZP or the OS's default polling frequency.  If no polling
394	 * frequency is specified then we'll wait forever (that is, until
395	 * a thermal event occurs -- e.g. never poll).  Note that _TSP
396	 * and _TZD values are given in 1/10th seconds.
397	 */
398	if (policy->state & TZ_STATE_PASSIVE)
399		sleep_time = thresholds->passive.tsp * 100;
400	else if (policy->polling_freq > 0)
401		sleep_time = policy->polling_freq * 100;
402	else
403		sleep_time = WAIT_FOREVER;
404
405	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Thermal_zone[%02x]: temperature[%d] state[%08x]\n", tz->device_handle, policy->temperature, policy->state));
406	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Scheduling next poll in [%d]ms.\n", sleep_time));
407
408	/*
409	 * Schedule Next Poll:
410	 * -------------------
411	 */
412	if (sleep_time < WAIT_FOREVER) {
413		if (timer_pending(&(policy->timer)))
414			mod_timer(&(policy->timer), (HZ*sleep_time)/1000);
415		else {
416			policy->timer.data = (unsigned long)tz;
417			policy->timer.function = tz_policy_run;
418			policy->timer.expires = jiffies + (HZ*sleep_time)/1000;
419			add_timer(&(policy->timer));
420		}
421	}
422	else {
423		if (timer_pending(&(policy->timer)))
424			del_timer(&(policy->timer));
425	}
426
427	return_VOID;
428}
429
430
431/****************************************************************************
432 *
433 * FUNCTION:    tz_policy_run
434 *
435 * PARAMETERS:
436 *
437 * RETURN:
438 *
439 * DESCRIPTION:
440 *
441 ****************************************************************************/
442
443
444void
445tz_policy_run (
446	unsigned long           data)
447{
448	acpi_status             status = AE_OK;
449
450	FUNCTION_TRACE("tz_policy_run");
451
452	if (!data) {
453		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
454		return_VOID;
455	}
456
457	/*
458	 * Defer to Non-Interrupt Level:
459	 * -----------------------------
460	 * Note that all Linux kernel timers run at interrupt-level (ack!).
461	 */
462	status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,  tz_policy_check, (void*)data);
463	if (ACPI_FAILURE(status)) {
464		ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Error invoking thermal policy.\n"));
465	}
466
467	return_VOID;
468}
469
470
471/****************************************************************************
472 *
473 * FUNCTION:    tz_policy_add_device
474 *
475 * PARAMETERS:
476 *
477 * RETURN:
478 *
479 * DESCRIPTION:
480 *
481 ****************************************************************************/
482
483acpi_status
484tz_policy_add_device (
485	TZ_CONTEXT		*tz)
486{
487	acpi_status             status = AE_OK;
488	TZ_THRESHOLDS           *thresholds = NULL;
489	u32                     i,j = 0;
490
491	FUNCTION_TRACE("tz_policy_add_device");
492
493	if (!tz) {
494		return_ACPI_STATUS(AE_BAD_PARAMETER);
495	}
496
497	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Adding policy for thermal zone [%02x].\n", tz->device_handle));
498
499	/*
500	 * Get Thresholds:
501	 * ---------------
502	 */
503	status = tz_get_thresholds(tz);
504	if (ACPI_FAILURE(status)) {
505		return_ACPI_STATUS(status);
506	}
507
508	/*
509	 * Initialize Policies:
510	 * --------------------
511	 */
512	if (tz->policy.thresholds.passive.is_valid) {
513		for (i=0; i<tz->policy.thresholds.passive.devices.count; i++)
514			set_performance_limit(tz->policy.thresholds.passive.devices.handles[i], PR_PERF_MAX);
515		tz_policy_passive(tz);
516	}
517	if (tz->policy.thresholds.active[0].is_valid)
518		tz_policy_active(tz);
519
520	/*
521	 * Initialize Policy Timer:
522	 * ------------------------
523	 */
524	init_timer(&(tz->policy.timer));
525
526	/*
527	 * Start Policy:
528	 * -------------
529	 * Run an initial check using this zone's policy.
530	 */
531	tz_policy_check(tz);
532
533	return_ACPI_STATUS(AE_OK);
534}
535
536
537/*****************************************************************************
538 *
539 * FUNCTION:    tz_policy_remove_device
540 *
541 * PARAMETERS:
542 *
543 * RETURN:
544 *
545 * DESCRIPTION:
546 *
547 ****************************************************************************/
548
549acpi_status
550tz_policy_remove_device(
551	TZ_CONTEXT		*tz)
552{
553	u32			i = 0;
554
555	FUNCTION_TRACE("tz_remove_device");
556
557	if (!tz) {
558		return_ACPI_STATUS(AE_BAD_PARAMETER);
559	}
560
561	ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing policy for thermal zone [%02x].\n", tz->device_handle));
562
563	/*
564	 * Delete the thermal zone policy timer entry, if exists.
565	 */
566	if (timer_pending(&(tz->policy.timer)))
567		del_timer(&(tz->policy.timer));
568
569	/*
570	 * Reset thermal performance limit on all processors back to max.
571	 */
572	if (tz->policy.thresholds.passive.is_valid) {
573		for (i=0; i<tz->policy.thresholds.passive.devices.count; i++)
574			set_performance_limit(tz->policy.thresholds.passive.devices.handles[i], PR_PERF_MAX);
575	}
576
577	return_ACPI_STATUS(AE_OK);
578}
579