Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
4 : : *
5 : : * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
6 : : * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 : : *
8 : : * This driver fully implements the ACPI thermal policy as described in the
9 : : * ACPI 2.0 Specification.
10 : : *
11 : : * TBD: 1. Implement passive cooling hysteresis.
12 : : * 2. Enhance passive cooling (CPU) states/limit interface to support
13 : : * concepts of 'multiple limiters', upper/lower limits, etc.
14 : : */
15 : :
16 : : #include <linux/kernel.h>
17 : : #include <linux/module.h>
18 : : #include <linux/dmi.h>
19 : : #include <linux/init.h>
20 : : #include <linux/slab.h>
21 : : #include <linux/types.h>
22 : : #include <linux/jiffies.h>
23 : : #include <linux/kmod.h>
24 : : #include <linux/reboot.h>
25 : : #include <linux/device.h>
26 : : #include <linux/thermal.h>
27 : : #include <linux/acpi.h>
28 : : #include <linux/workqueue.h>
29 : : #include <linux/uaccess.h>
30 : : #include <linux/units.h>
31 : :
32 : : #define PREFIX "ACPI: "
33 : :
34 : : #define ACPI_THERMAL_CLASS "thermal_zone"
35 : : #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
36 : : #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
37 : : #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
38 : : #define ACPI_THERMAL_NOTIFY_DEVICES 0x82
39 : : #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
40 : : #define ACPI_THERMAL_NOTIFY_HOT 0xF1
41 : : #define ACPI_THERMAL_MODE_ACTIVE 0x00
42 : :
43 : : #define ACPI_THERMAL_MAX_ACTIVE 10
44 : : #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
45 : :
46 : : #define _COMPONENT ACPI_THERMAL_COMPONENT
47 : : ACPI_MODULE_NAME("thermal");
48 : :
49 : : MODULE_AUTHOR("Paul Diefenbaugh");
50 : : MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
51 : : MODULE_LICENSE("GPL");
52 : :
53 : : static int act;
54 : : module_param(act, int, 0644);
55 : : MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
56 : :
57 : : static int crt;
58 : : module_param(crt, int, 0644);
59 : : MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
60 : :
61 : : static int tzp;
62 : : module_param(tzp, int, 0444);
63 : : MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
64 : :
65 : : static int nocrt;
66 : : module_param(nocrt, int, 0);
67 : : MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
68 : :
69 : : static int off;
70 : : module_param(off, int, 0);
71 : : MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
72 : :
73 : : static int psv;
74 : : module_param(psv, int, 0644);
75 : : MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
76 : :
77 : : static struct workqueue_struct *acpi_thermal_pm_queue;
78 : :
79 : : static int acpi_thermal_add(struct acpi_device *device);
80 : : static int acpi_thermal_remove(struct acpi_device *device);
81 : : static void acpi_thermal_notify(struct acpi_device *device, u32 event);
82 : :
83 : : static const struct acpi_device_id thermal_device_ids[] = {
84 : : {ACPI_THERMAL_HID, 0},
85 : : {"", 0},
86 : : };
87 : : MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
88 : :
89 : : #ifdef CONFIG_PM_SLEEP
90 : : static int acpi_thermal_suspend(struct device *dev);
91 : : static int acpi_thermal_resume(struct device *dev);
92 : : #else
93 : : #define acpi_thermal_suspend NULL
94 : : #define acpi_thermal_resume NULL
95 : : #endif
96 : : static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
97 : :
98 : : static struct acpi_driver acpi_thermal_driver = {
99 : : .name = "thermal",
100 : : .class = ACPI_THERMAL_CLASS,
101 : : .ids = thermal_device_ids,
102 : : .ops = {
103 : : .add = acpi_thermal_add,
104 : : .remove = acpi_thermal_remove,
105 : : .notify = acpi_thermal_notify,
106 : : },
107 : : .drv.pm = &acpi_thermal_pm,
108 : : };
109 : :
110 : : struct acpi_thermal_state {
111 : : u8 critical:1;
112 : : u8 hot:1;
113 : : u8 passive:1;
114 : : u8 active:1;
115 : : u8 reserved:4;
116 : : int active_index;
117 : : };
118 : :
119 : : struct acpi_thermal_state_flags {
120 : : u8 valid:1;
121 : : u8 enabled:1;
122 : : u8 reserved:6;
123 : : };
124 : :
125 : : struct acpi_thermal_critical {
126 : : struct acpi_thermal_state_flags flags;
127 : : unsigned long temperature;
128 : : };
129 : :
130 : : struct acpi_thermal_hot {
131 : : struct acpi_thermal_state_flags flags;
132 : : unsigned long temperature;
133 : : };
134 : :
135 : : struct acpi_thermal_passive {
136 : : struct acpi_thermal_state_flags flags;
137 : : unsigned long temperature;
138 : : unsigned long tc1;
139 : : unsigned long tc2;
140 : : unsigned long tsp;
141 : : struct acpi_handle_list devices;
142 : : };
143 : :
144 : : struct acpi_thermal_active {
145 : : struct acpi_thermal_state_flags flags;
146 : : unsigned long temperature;
147 : : struct acpi_handle_list devices;
148 : : };
149 : :
150 : : struct acpi_thermal_trips {
151 : : struct acpi_thermal_critical critical;
152 : : struct acpi_thermal_hot hot;
153 : : struct acpi_thermal_passive passive;
154 : : struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
155 : : };
156 : :
157 : : struct acpi_thermal_flags {
158 : : u8 cooling_mode:1; /* _SCP */
159 : : u8 devices:1; /* _TZD */
160 : : u8 reserved:6;
161 : : };
162 : :
163 : : struct acpi_thermal {
164 : : struct acpi_device * device;
165 : : acpi_bus_id name;
166 : : unsigned long temperature;
167 : : unsigned long last_temperature;
168 : : unsigned long polling_frequency;
169 : : volatile u8 zombie;
170 : : struct acpi_thermal_flags flags;
171 : : struct acpi_thermal_state state;
172 : : struct acpi_thermal_trips trips;
173 : : struct acpi_handle_list devices;
174 : : struct thermal_zone_device *thermal_zone;
175 : : int tz_enabled;
176 : : int kelvin_offset; /* in millidegrees */
177 : : struct work_struct thermal_check_work;
178 : : };
179 : :
180 : : /* --------------------------------------------------------------------------
181 : : Thermal Zone Management
182 : : -------------------------------------------------------------------------- */
183 : :
184 : 0 : static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
185 : : {
186 : 0 : acpi_status status = AE_OK;
187 : 0 : unsigned long long tmp;
188 : :
189 [ # # ]: 0 : if (!tz)
190 : : return -EINVAL;
191 : :
192 : 0 : tz->last_temperature = tz->temperature;
193 : :
194 : 0 : status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
195 [ # # ]: 0 : if (ACPI_FAILURE(status))
196 : : return -ENODEV;
197 : :
198 : 0 : tz->temperature = tmp;
199 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
200 : 0 : tz->temperature));
201 : :
202 : 0 : return 0;
203 : : }
204 : :
205 : 0 : static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
206 : : {
207 : 0 : acpi_status status = AE_OK;
208 : 0 : unsigned long long tmp;
209 : :
210 [ # # ]: 0 : if (!tz)
211 : : return -EINVAL;
212 : :
213 : 0 : status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
214 [ # # ]: 0 : if (ACPI_FAILURE(status))
215 : : return -ENODEV;
216 : :
217 : 0 : tz->polling_frequency = tmp;
218 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
219 : 0 : tz->polling_frequency));
220 : :
221 : 0 : return 0;
222 : : }
223 : :
224 : 0 : static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
225 : : {
226 : 0 : if (!tz)
227 : : return -EINVAL;
228 : :
229 [ # # ]: 0 : if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
230 : : "_SCP", mode)))
231 : : return -ENODEV;
232 : :
233 : : return 0;
234 : : }
235 : :
236 : : #define ACPI_TRIPS_CRITICAL 0x01
237 : : #define ACPI_TRIPS_HOT 0x02
238 : : #define ACPI_TRIPS_PASSIVE 0x04
239 : : #define ACPI_TRIPS_ACTIVE 0x08
240 : : #define ACPI_TRIPS_DEVICES 0x10
241 : :
242 : : #define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
243 : : #define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
244 : :
245 : : #define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
246 : : ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
247 : : ACPI_TRIPS_DEVICES)
248 : :
249 : : /*
250 : : * This exception is thrown out in two cases:
251 : : * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
252 : : * when re-evaluating the AML code.
253 : : * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
254 : : * We need to re-bind the cooling devices of a thermal zone when this occurs.
255 : : */
256 : : #define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
257 : : do { \
258 : : if (flags != ACPI_TRIPS_INIT) \
259 : : ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
260 : : "ACPI thermal trip point %s changed\n" \
261 : : "Please send acpidump to linux-acpi@vger.kernel.org", str)); \
262 : : } while (0)
263 : :
264 : 0 : static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
265 : : {
266 : 0 : acpi_status status = AE_OK;
267 : 0 : unsigned long long tmp;
268 : 0 : struct acpi_handle_list devices;
269 : 0 : int valid = 0;
270 : 0 : int i;
271 : :
272 : : /* Critical Shutdown */
273 [ # # ]: 0 : if (flag & ACPI_TRIPS_CRITICAL) {
274 : 0 : status = acpi_evaluate_integer(tz->device->handle,
275 : : "_CRT", NULL, &tmp);
276 : 0 : tz->trips.critical.temperature = tmp;
277 : : /*
278 : : * Treat freezing temperatures as invalid as well; some
279 : : * BIOSes return really low values and cause reboots at startup.
280 : : * Below zero (Celsius) values clearly aren't right for sure..
281 : : * ... so lets discard those as invalid.
282 : : */
283 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
284 : 0 : tz->trips.critical.flags.valid = 0;
285 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
286 : 0 : "No critical threshold\n"));
287 [ # # ]: 0 : } else if (tmp <= 2732) {
288 : 0 : pr_warn(FW_BUG "Invalid critical threshold (%llu)\n",
289 : : tmp);
290 : 0 : tz->trips.critical.flags.valid = 0;
291 : : } else {
292 : 0 : tz->trips.critical.flags.valid = 1;
293 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
294 : : "Found critical threshold [%lu]\n",
295 : 0 : tz->trips.critical.temperature));
296 : : }
297 [ # # ]: 0 : if (tz->trips.critical.flags.valid == 1) {
298 [ # # ]: 0 : if (crt == -1) {
299 : 0 : tz->trips.critical.flags.valid = 0;
300 [ # # ]: 0 : } else if (crt > 0) {
301 [ # # ]: 0 : unsigned long crt_k = celsius_to_deci_kelvin(crt);
302 : :
303 : : /*
304 : : * Allow override critical threshold
305 : : */
306 [ # # ]: 0 : if (crt_k > tz->trips.critical.temperature)
307 : 0 : pr_warn(PREFIX "Critical threshold %d C\n",
308 : : crt);
309 : 0 : tz->trips.critical.temperature = crt_k;
310 : : }
311 : : }
312 : : }
313 : :
314 : : /* Critical Sleep (optional) */
315 [ # # ]: 0 : if (flag & ACPI_TRIPS_HOT) {
316 : 0 : status = acpi_evaluate_integer(tz->device->handle,
317 : : "_HOT", NULL, &tmp);
318 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
319 : 0 : tz->trips.hot.flags.valid = 0;
320 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
321 : 0 : "No hot threshold\n"));
322 : : } else {
323 : 0 : tz->trips.hot.temperature = tmp;
324 : 0 : tz->trips.hot.flags.valid = 1;
325 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
326 : : "Found hot threshold [%lu]\n",
327 : 0 : tz->trips.hot.temperature));
328 : : }
329 : : }
330 : :
331 : : /* Passive (optional) */
332 [ # # # # : 0 : if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
# # ]
333 : : (flag == ACPI_TRIPS_INIT)) {
334 : 0 : valid = tz->trips.passive.flags.valid;
335 [ # # ]: 0 : if (psv == -1) {
336 : : status = AE_SUPPORT;
337 [ # # ]: 0 : } else if (psv > 0) {
338 : 0 : tmp = celsius_to_deci_kelvin(psv);
339 : 0 : status = AE_OK;
340 : : } else {
341 : 0 : status = acpi_evaluate_integer(tz->device->handle,
342 : : "_PSV", NULL, &tmp);
343 : : }
344 : :
345 [ # # ]: 0 : if (ACPI_FAILURE(status))
346 : 0 : tz->trips.passive.flags.valid = 0;
347 : : else {
348 : 0 : tz->trips.passive.temperature = tmp;
349 : 0 : tz->trips.passive.flags.valid = 1;
350 [ # # ]: 0 : if (flag == ACPI_TRIPS_INIT) {
351 : 0 : status = acpi_evaluate_integer(
352 : 0 : tz->device->handle, "_TC1",
353 : : NULL, &tmp);
354 [ # # ]: 0 : if (ACPI_FAILURE(status))
355 : 0 : tz->trips.passive.flags.valid = 0;
356 : : else
357 : 0 : tz->trips.passive.tc1 = tmp;
358 : 0 : status = acpi_evaluate_integer(
359 : 0 : tz->device->handle, "_TC2",
360 : : NULL, &tmp);
361 [ # # ]: 0 : if (ACPI_FAILURE(status))
362 : 0 : tz->trips.passive.flags.valid = 0;
363 : : else
364 : 0 : tz->trips.passive.tc2 = tmp;
365 : 0 : status = acpi_evaluate_integer(
366 : 0 : tz->device->handle, "_TSP",
367 : : NULL, &tmp);
368 [ # # ]: 0 : if (ACPI_FAILURE(status))
369 : 0 : tz->trips.passive.flags.valid = 0;
370 : : else
371 : 0 : tz->trips.passive.tsp = tmp;
372 : : }
373 : : }
374 : : }
375 [ # # # # ]: 0 : if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
376 : 0 : memset(&devices, 0, sizeof(struct acpi_handle_list));
377 : 0 : status = acpi_evaluate_reference(tz->device->handle, "_PSL",
378 : : NULL, &devices);
379 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
380 : 0 : pr_warn(PREFIX "Invalid passive threshold\n");
381 : 0 : tz->trips.passive.flags.valid = 0;
382 : : }
383 : : else
384 : 0 : tz->trips.passive.flags.valid = 1;
385 : :
386 [ # # ]: 0 : if (memcmp(&tz->trips.passive.devices, &devices,
387 : : sizeof(struct acpi_handle_list))) {
388 : 0 : memcpy(&tz->trips.passive.devices, &devices,
389 : : sizeof(struct acpi_handle_list));
390 [ # # ]: 0 : ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
391 : : }
392 : : }
393 [ # # ]: 0 : if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
394 [ # # ]: 0 : if (valid != tz->trips.passive.flags.valid)
395 [ # # ]: 0 : ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
396 : : }
397 : :
398 : : /* Active (optional) */
399 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
400 : 0 : char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
401 : 0 : valid = tz->trips.active[i].flags.valid;
402 : :
403 [ # # ]: 0 : if (act == -1)
404 : : break; /* disable all active trip points */
405 : :
406 [ # # # # : 0 : if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
# # ]
407 : : tz->trips.active[i].flags.valid)) {
408 : 0 : status = acpi_evaluate_integer(tz->device->handle,
409 : : name, NULL, &tmp);
410 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
411 : 0 : tz->trips.active[i].flags.valid = 0;
412 [ # # ]: 0 : if (i == 0)
413 : : break;
414 [ # # ]: 0 : if (act <= 0)
415 : : break;
416 [ # # ]: 0 : if (i == 1)
417 : 0 : tz->trips.active[0].temperature =
418 : 0 : celsius_to_deci_kelvin(act);
419 : : else
420 : : /*
421 : : * Don't allow override higher than
422 : : * the next higher trip point
423 : : */
424 : 0 : tz->trips.active[i - 1].temperature =
425 : 0 : (tz->trips.active[i - 2].temperature <
426 : 0 : celsius_to_deci_kelvin(act) ?
427 : : tz->trips.active[i - 2].temperature :
428 : : celsius_to_deci_kelvin(act));
429 : : break;
430 : : } else {
431 : 0 : tz->trips.active[i].temperature = tmp;
432 : 0 : tz->trips.active[i].flags.valid = 1;
433 : : }
434 : : }
435 : :
436 : 0 : name[2] = 'L';
437 [ # # # # ]: 0 : if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
438 : 0 : memset(&devices, 0, sizeof(struct acpi_handle_list));
439 : 0 : status = acpi_evaluate_reference(tz->device->handle,
440 : : name, NULL, &devices);
441 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
442 : 0 : pr_warn(PREFIX "Invalid active%d threshold\n",
443 : : i);
444 : 0 : tz->trips.active[i].flags.valid = 0;
445 : : }
446 : : else
447 : 0 : tz->trips.active[i].flags.valid = 1;
448 : :
449 [ # # ]: 0 : if (memcmp(&tz->trips.active[i].devices, &devices,
450 : : sizeof(struct acpi_handle_list))) {
451 : 0 : memcpy(&tz->trips.active[i].devices, &devices,
452 : : sizeof(struct acpi_handle_list));
453 [ # # ]: 0 : ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
454 : : }
455 : : }
456 [ # # ]: 0 : if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
457 [ # # ]: 0 : if (valid != tz->trips.active[i].flags.valid)
458 [ # # ]: 0 : ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
459 : :
460 [ # # ]: 0 : if (!tz->trips.active[i].flags.valid)
461 : : break;
462 : : }
463 : :
464 [ # # ]: 0 : if (flag & ACPI_TRIPS_DEVICES) {
465 : 0 : memset(&devices, 0, sizeof(devices));
466 : 0 : status = acpi_evaluate_reference(tz->device->handle, "_TZD",
467 : : NULL, &devices);
468 [ # # ]: 0 : if (ACPI_SUCCESS(status)
469 [ # # ]: 0 : && memcmp(&tz->devices, &devices, sizeof(devices))) {
470 : 0 : tz->devices = devices;
471 [ # # ]: 0 : ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
472 : : }
473 : : }
474 : :
475 : 0 : return 0;
476 : : }
477 : :
478 : 0 : static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
479 : : {
480 : 0 : int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
481 : :
482 [ # # ]: 0 : if (ret)
483 : : return ret;
484 : :
485 : 0 : valid = tz->trips.critical.flags.valid |
486 : 0 : tz->trips.hot.flags.valid |
487 : 0 : tz->trips.passive.flags.valid;
488 : :
489 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
490 : 0 : valid |= tz->trips.active[i].flags.valid;
491 : :
492 [ # # ]: 0 : if (!valid) {
493 : 0 : pr_warn(FW_BUG "No valid trip found\n");
494 : 0 : return -ENODEV;
495 : : }
496 : : return 0;
497 : : }
498 : :
499 : 0 : static void acpi_thermal_check(void *data)
500 : : {
501 : 0 : struct acpi_thermal *tz = data;
502 : :
503 : 0 : if (!tz->tz_enabled)
504 : : return;
505 : :
506 : 0 : thermal_zone_device_update(tz->thermal_zone,
507 : : THERMAL_EVENT_UNSPECIFIED);
508 : : }
509 : :
510 : : /* sys I/F for generic thermal sysfs support */
511 : :
512 : 0 : static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
513 : : {
514 : 0 : struct acpi_thermal *tz = thermal->devdata;
515 : 0 : int result;
516 : :
517 [ # # ]: 0 : if (!tz)
518 : : return -EINVAL;
519 : :
520 : 0 : result = acpi_thermal_get_temperature(tz);
521 [ # # ]: 0 : if (result)
522 : : return result;
523 : :
524 : 0 : *temp = deci_kelvin_to_millicelsius_with_offset(tz->temperature,
525 : 0 : tz->kelvin_offset);
526 : 0 : return 0;
527 : : }
528 : :
529 : 0 : static int thermal_get_mode(struct thermal_zone_device *thermal,
530 : : enum thermal_device_mode *mode)
531 : : {
532 : 0 : struct acpi_thermal *tz = thermal->devdata;
533 : :
534 [ # # ]: 0 : if (!tz)
535 : : return -EINVAL;
536 : :
537 : 0 : *mode = tz->tz_enabled ? THERMAL_DEVICE_ENABLED :
538 : : THERMAL_DEVICE_DISABLED;
539 : :
540 : 0 : return 0;
541 : : }
542 : :
543 : 0 : static int thermal_set_mode(struct thermal_zone_device *thermal,
544 : : enum thermal_device_mode mode)
545 : : {
546 : 0 : struct acpi_thermal *tz = thermal->devdata;
547 : 0 : int enable;
548 : :
549 [ # # ]: 0 : if (!tz)
550 : : return -EINVAL;
551 : :
552 : : /*
553 : : * enable/disable thermal management from ACPI thermal driver
554 : : */
555 [ # # ]: 0 : if (mode == THERMAL_DEVICE_ENABLED)
556 : : enable = 1;
557 [ # # ]: 0 : else if (mode == THERMAL_DEVICE_DISABLED) {
558 : 0 : enable = 0;
559 : 0 : pr_warn("thermal zone will be disabled\n");
560 : : } else
561 : : return -EINVAL;
562 : :
563 [ # # ]: 0 : if (enable != tz->tz_enabled) {
564 : 0 : tz->tz_enabled = enable;
565 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
566 : : "%s kernel ACPI thermal control\n",
567 : 0 : tz->tz_enabled ? "Enable" : "Disable"));
568 [ # # ]: 0 : acpi_thermal_check(tz);
569 : : }
570 : : return 0;
571 : : }
572 : :
573 : 0 : static int thermal_get_trip_type(struct thermal_zone_device *thermal,
574 : : int trip, enum thermal_trip_type *type)
575 : : {
576 : 0 : struct acpi_thermal *tz = thermal->devdata;
577 : 0 : int i;
578 : :
579 [ # # ]: 0 : if (!tz || trip < 0)
580 : : return -EINVAL;
581 : :
582 [ # # ]: 0 : if (tz->trips.critical.flags.valid) {
583 [ # # ]: 0 : if (!trip) {
584 : 0 : *type = THERMAL_TRIP_CRITICAL;
585 : 0 : return 0;
586 : : }
587 : 0 : trip--;
588 : : }
589 : :
590 [ # # ]: 0 : if (tz->trips.hot.flags.valid) {
591 [ # # ]: 0 : if (!trip) {
592 : 0 : *type = THERMAL_TRIP_HOT;
593 : 0 : return 0;
594 : : }
595 : 0 : trip--;
596 : : }
597 : :
598 [ # # ]: 0 : if (tz->trips.passive.flags.valid) {
599 [ # # ]: 0 : if (!trip) {
600 : 0 : *type = THERMAL_TRIP_PASSIVE;
601 : 0 : return 0;
602 : : }
603 : 0 : trip--;
604 : : }
605 : :
606 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
607 [ # # ]: 0 : tz->trips.active[i].flags.valid; i++) {
608 [ # # ]: 0 : if (!trip) {
609 : 0 : *type = THERMAL_TRIP_ACTIVE;
610 : 0 : return 0;
611 : : }
612 : 0 : trip--;
613 : : }
614 : :
615 : : return -EINVAL;
616 : : }
617 : :
618 : 0 : static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
619 : : int trip, int *temp)
620 : : {
621 : 0 : struct acpi_thermal *tz = thermal->devdata;
622 : 0 : int i;
623 : :
624 [ # # ]: 0 : if (!tz || trip < 0)
625 : : return -EINVAL;
626 : :
627 [ # # ]: 0 : if (tz->trips.critical.flags.valid) {
628 [ # # ]: 0 : if (!trip) {
629 : 0 : *temp = deci_kelvin_to_millicelsius_with_offset(
630 : 0 : tz->trips.critical.temperature,
631 : 0 : tz->kelvin_offset);
632 : 0 : return 0;
633 : : }
634 : 0 : trip--;
635 : : }
636 : :
637 [ # # ]: 0 : if (tz->trips.hot.flags.valid) {
638 [ # # ]: 0 : if (!trip) {
639 : 0 : *temp = deci_kelvin_to_millicelsius_with_offset(
640 : 0 : tz->trips.hot.temperature,
641 : 0 : tz->kelvin_offset);
642 : 0 : return 0;
643 : : }
644 : 0 : trip--;
645 : : }
646 : :
647 [ # # ]: 0 : if (tz->trips.passive.flags.valid) {
648 [ # # ]: 0 : if (!trip) {
649 : 0 : *temp = deci_kelvin_to_millicelsius_with_offset(
650 : 0 : tz->trips.passive.temperature,
651 : 0 : tz->kelvin_offset);
652 : 0 : return 0;
653 : : }
654 : 0 : trip--;
655 : : }
656 : :
657 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
658 [ # # ]: 0 : tz->trips.active[i].flags.valid; i++) {
659 [ # # ]: 0 : if (!trip) {
660 : 0 : *temp = deci_kelvin_to_millicelsius_with_offset(
661 : 0 : tz->trips.active[i].temperature,
662 : 0 : tz->kelvin_offset);
663 : 0 : return 0;
664 : : }
665 : 0 : trip--;
666 : : }
667 : :
668 : : return -EINVAL;
669 : : }
670 : :
671 : 0 : static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
672 : : int *temperature)
673 : : {
674 : 0 : struct acpi_thermal *tz = thermal->devdata;
675 : :
676 [ # # ]: 0 : if (tz->trips.critical.flags.valid) {
677 : 0 : *temperature = deci_kelvin_to_millicelsius_with_offset(
678 : 0 : tz->trips.critical.temperature,
679 : 0 : tz->kelvin_offset);
680 : 0 : return 0;
681 : : } else
682 : : return -EINVAL;
683 : : }
684 : :
685 : 0 : static int thermal_get_trend(struct thermal_zone_device *thermal,
686 : : int trip, enum thermal_trend *trend)
687 : : {
688 : 0 : struct acpi_thermal *tz = thermal->devdata;
689 : 0 : enum thermal_trip_type type;
690 : 0 : int i;
691 : :
692 [ # # ]: 0 : if (thermal_get_trip_type(thermal, trip, &type))
693 : : return -EINVAL;
694 : :
695 [ # # ]: 0 : if (type == THERMAL_TRIP_ACTIVE) {
696 : 0 : int trip_temp;
697 : 0 : int temp = deci_kelvin_to_millicelsius_with_offset(
698 : 0 : tz->temperature, tz->kelvin_offset);
699 [ # # ]: 0 : if (thermal_get_trip_temp(thermal, trip, &trip_temp))
700 : : return -EINVAL;
701 : :
702 [ # # ]: 0 : if (temp > trip_temp) {
703 : 0 : *trend = THERMAL_TREND_RAISING;
704 : 0 : return 0;
705 : : } else {
706 : : /* Fall back on default trend */
707 : : return -EINVAL;
708 : : }
709 : : }
710 : :
711 : : /*
712 : : * tz->temperature has already been updated by generic thermal layer,
713 : : * before this callback being invoked
714 : : */
715 : 0 : i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
716 : 0 : + (tz->trips.passive.tc2
717 : 0 : * (tz->temperature - tz->trips.passive.temperature));
718 : :
719 [ # # ]: 0 : if (i > 0)
720 : 0 : *trend = THERMAL_TREND_RAISING;
721 [ # # ]: 0 : else if (i < 0)
722 : 0 : *trend = THERMAL_TREND_DROPPING;
723 : : else
724 : 0 : *trend = THERMAL_TREND_STABLE;
725 : : return 0;
726 : : }
727 : :
728 : :
729 : 0 : static int thermal_notify(struct thermal_zone_device *thermal, int trip,
730 : : enum thermal_trip_type trip_type)
731 : : {
732 : 0 : u8 type = 0;
733 : 0 : struct acpi_thermal *tz = thermal->devdata;
734 : :
735 [ # # ]: 0 : if (trip_type == THERMAL_TRIP_CRITICAL)
736 : : type = ACPI_THERMAL_NOTIFY_CRITICAL;
737 [ # # ]: 0 : else if (trip_type == THERMAL_TRIP_HOT)
738 : : type = ACPI_THERMAL_NOTIFY_HOT;
739 : : else
740 : : return 0;
741 : :
742 : 0 : acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
743 [ # # ]: 0 : dev_name(&tz->device->dev), type, 1);
744 : :
745 [ # # # # ]: 0 : if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
746 : 0 : return 1;
747 : :
748 : : return 0;
749 : : }
750 : :
751 : 0 : static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
752 : : struct thermal_cooling_device *cdev,
753 : : bool bind)
754 : : {
755 : 0 : struct acpi_device *device = cdev->devdata;
756 : 0 : struct acpi_thermal *tz = thermal->devdata;
757 : 0 : struct acpi_device *dev;
758 : 0 : acpi_status status;
759 : 0 : acpi_handle handle;
760 : 0 : int i;
761 : 0 : int j;
762 : 0 : int trip = -1;
763 : 0 : int result = 0;
764 : :
765 : 0 : if (tz->trips.critical.flags.valid)
766 : : trip++;
767 : :
768 [ # # ]: 0 : if (tz->trips.hot.flags.valid)
769 : 0 : trip++;
770 : :
771 [ # # ]: 0 : if (tz->trips.passive.flags.valid) {
772 : 0 : trip++;
773 [ # # ]: 0 : for (i = 0; i < tz->trips.passive.devices.count;
774 : 0 : i++) {
775 : 0 : handle = tz->trips.passive.devices.handles[i];
776 : 0 : status = acpi_bus_get_device(handle, &dev);
777 [ # # # # ]: 0 : if (ACPI_FAILURE(status) || dev != device)
778 : 0 : continue;
779 [ # # ]: 0 : if (bind)
780 : 0 : result =
781 : 0 : thermal_zone_bind_cooling_device
782 : : (thermal, trip, cdev,
783 : : THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
784 : : THERMAL_WEIGHT_DEFAULT);
785 : : else
786 : 0 : result =
787 : 0 : thermal_zone_unbind_cooling_device
788 : : (thermal, trip, cdev);
789 [ # # ]: 0 : if (result)
790 : 0 : goto failed;
791 : : }
792 : : }
793 : :
794 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
795 [ # # ]: 0 : if (!tz->trips.active[i].flags.valid)
796 : : break;
797 : 0 : trip++;
798 : 0 : for (j = 0;
799 [ # # ]: 0 : j < tz->trips.active[i].devices.count;
800 : 0 : j++) {
801 : 0 : handle = tz->trips.active[i].devices.handles[j];
802 : 0 : status = acpi_bus_get_device(handle, &dev);
803 [ # # # # ]: 0 : if (ACPI_FAILURE(status) || dev != device)
804 : 0 : continue;
805 [ # # ]: 0 : if (bind)
806 : 0 : result = thermal_zone_bind_cooling_device
807 : : (thermal, trip, cdev,
808 : : THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
809 : : THERMAL_WEIGHT_DEFAULT);
810 : : else
811 : 0 : result = thermal_zone_unbind_cooling_device
812 : : (thermal, trip, cdev);
813 [ # # ]: 0 : if (result)
814 : 0 : goto failed;
815 : : }
816 : : }
817 : :
818 [ # # ]: 0 : for (i = 0; i < tz->devices.count; i++) {
819 : 0 : handle = tz->devices.handles[i];
820 : 0 : status = acpi_bus_get_device(handle, &dev);
821 [ # # # # ]: 0 : if (ACPI_SUCCESS(status) && (dev == device)) {
822 [ # # ]: 0 : if (bind)
823 : 0 : result = thermal_zone_bind_cooling_device
824 : : (thermal, THERMAL_TRIPS_NONE,
825 : : cdev, THERMAL_NO_LIMIT,
826 : : THERMAL_NO_LIMIT,
827 : : THERMAL_WEIGHT_DEFAULT);
828 : : else
829 : 0 : result = thermal_zone_unbind_cooling_device
830 : : (thermal, THERMAL_TRIPS_NONE,
831 : : cdev);
832 [ # # ]: 0 : if (result)
833 : 0 : goto failed;
834 : : }
835 : : }
836 : :
837 : 0 : failed:
838 : 0 : return result;
839 : : }
840 : :
841 : : static int
842 : 0 : acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
843 : : struct thermal_cooling_device *cdev)
844 : : {
845 : 0 : return acpi_thermal_cooling_device_cb(thermal, cdev, true);
846 : : }
847 : :
848 : : static int
849 : 0 : acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
850 : : struct thermal_cooling_device *cdev)
851 : : {
852 : 0 : return acpi_thermal_cooling_device_cb(thermal, cdev, false);
853 : : }
854 : :
855 : : static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
856 : : .bind = acpi_thermal_bind_cooling_device,
857 : : .unbind = acpi_thermal_unbind_cooling_device,
858 : : .get_temp = thermal_get_temp,
859 : : .get_mode = thermal_get_mode,
860 : : .set_mode = thermal_set_mode,
861 : : .get_trip_type = thermal_get_trip_type,
862 : : .get_trip_temp = thermal_get_trip_temp,
863 : : .get_crit_temp = thermal_get_crit_temp,
864 : : .get_trend = thermal_get_trend,
865 : : .notify = thermal_notify,
866 : : };
867 : :
868 : 0 : static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
869 : : {
870 : 0 : int trips = 0;
871 : 0 : int result;
872 : 0 : acpi_status status;
873 : 0 : int i;
874 : :
875 : 0 : if (tz->trips.critical.flags.valid)
876 : : trips++;
877 : :
878 [ # # ]: 0 : if (tz->trips.hot.flags.valid)
879 : 0 : trips++;
880 : :
881 [ # # ]: 0 : if (tz->trips.passive.flags.valid)
882 : 0 : trips++;
883 : :
884 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
885 [ # # ]: 0 : tz->trips.active[i].flags.valid; i++, trips++);
886 : :
887 [ # # ]: 0 : if (tz->trips.passive.flags.valid)
888 : 0 : tz->thermal_zone =
889 : 0 : thermal_zone_device_register("acpitz", trips, 0, tz,
890 : : &acpi_thermal_zone_ops, NULL,
891 : 0 : tz->trips.passive.tsp*100,
892 : 0 : tz->polling_frequency*100);
893 : : else
894 : 0 : tz->thermal_zone =
895 : 0 : thermal_zone_device_register("acpitz", trips, 0, tz,
896 : : &acpi_thermal_zone_ops, NULL,
897 : 0 : 0, tz->polling_frequency*100);
898 [ # # ]: 0 : if (IS_ERR(tz->thermal_zone))
899 : : return -ENODEV;
900 : :
901 : 0 : result = sysfs_create_link(&tz->device->dev.kobj,
902 : : &tz->thermal_zone->device.kobj, "thermal_zone");
903 [ # # ]: 0 : if (result)
904 : : return result;
905 : :
906 : 0 : result = sysfs_create_link(&tz->thermal_zone->device.kobj,
907 : 0 : &tz->device->dev.kobj, "device");
908 [ # # ]: 0 : if (result)
909 : : return result;
910 : :
911 : 0 : status = acpi_bus_attach_private_data(tz->device->handle,
912 : 0 : tz->thermal_zone);
913 [ # # ]: 0 : if (ACPI_FAILURE(status))
914 : : return -ENODEV;
915 : :
916 : 0 : tz->tz_enabled = 1;
917 : :
918 : 0 : dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
919 : : tz->thermal_zone->id);
920 : 0 : return 0;
921 : : }
922 : :
923 : 0 : static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
924 : : {
925 : 0 : sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
926 : 0 : sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
927 : 0 : thermal_zone_device_unregister(tz->thermal_zone);
928 : 0 : tz->thermal_zone = NULL;
929 : 0 : acpi_bus_detach_private_data(tz->device->handle);
930 : 0 : }
931 : :
932 : :
933 : : /* --------------------------------------------------------------------------
934 : : Driver Interface
935 : : -------------------------------------------------------------------------- */
936 : :
937 : 0 : static void acpi_thermal_notify(struct acpi_device *device, u32 event)
938 : : {
939 [ # # ]: 0 : struct acpi_thermal *tz = acpi_driver_data(device);
940 : :
941 : :
942 [ # # ]: 0 : if (!tz)
943 : : return;
944 : :
945 [ # # # # ]: 0 : switch (event) {
946 : : case ACPI_THERMAL_NOTIFY_TEMPERATURE:
947 [ # # ]: 0 : acpi_thermal_check(tz);
948 : : break;
949 : 0 : case ACPI_THERMAL_NOTIFY_THRESHOLDS:
950 : 0 : acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
951 [ # # ]: 0 : acpi_thermal_check(tz);
952 [ # # ]: 0 : acpi_bus_generate_netlink_event(device->pnp.device_class,
953 : : dev_name(&device->dev), event, 0);
954 : 0 : break;
955 : 0 : case ACPI_THERMAL_NOTIFY_DEVICES:
956 : 0 : acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
957 [ # # ]: 0 : acpi_thermal_check(tz);
958 [ # # ]: 0 : acpi_bus_generate_netlink_event(device->pnp.device_class,
959 : : dev_name(&device->dev), event, 0);
960 : 0 : break;
961 : : default:
962 : : ACPI_DEBUG_PRINT((ACPI_DB_INFO,
963 : : "Unsupported event [0x%x]\n", event));
964 : : break;
965 : : }
966 : : }
967 : :
968 : : /*
969 : : * On some platforms, the AML code has dependency about
970 : : * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx.
971 : : * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after
972 : : * /_CRT/_HOT/_PSV/_ACx, or else system will be power off.
973 : : * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0
974 : : * if _TMP has never been evaluated.
975 : : *
976 : : * As this dependency is totally transparent to OS, evaluate
977 : : * all of them once, in the order of _CRT/_HOT/_PSV/_ACx,
978 : : * _TMP, before they are actually used.
979 : : */
980 : 0 : static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
981 : : {
982 : 0 : acpi_handle handle = tz->device->handle;
983 : 0 : unsigned long long value;
984 : 0 : int i;
985 : :
986 : 0 : acpi_evaluate_integer(handle, "_CRT", NULL, &value);
987 : 0 : acpi_evaluate_integer(handle, "_HOT", NULL, &value);
988 : 0 : acpi_evaluate_integer(handle, "_PSV", NULL, &value);
989 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
990 : 0 : char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
991 : 0 : acpi_status status;
992 : :
993 : 0 : status = acpi_evaluate_integer(handle, name, NULL, &value);
994 [ # # ]: 0 : if (status == AE_NOT_FOUND)
995 : : break;
996 : : }
997 : 0 : acpi_evaluate_integer(handle, "_TMP", NULL, &value);
998 : 0 : }
999 : :
1000 : 0 : static int acpi_thermal_get_info(struct acpi_thermal *tz)
1001 : : {
1002 : 0 : int result = 0;
1003 : :
1004 : :
1005 [ # # ]: 0 : if (!tz)
1006 : : return -EINVAL;
1007 : :
1008 : 0 : acpi_thermal_aml_dependency_fix(tz);
1009 : :
1010 : : /* Get trip points [_CRT, _PSV, etc.] (required) */
1011 : 0 : result = acpi_thermal_get_trip_points(tz);
1012 [ # # ]: 0 : if (result)
1013 : : return result;
1014 : :
1015 : : /* Get temperature [_TMP] (required) */
1016 : 0 : result = acpi_thermal_get_temperature(tz);
1017 [ # # ]: 0 : if (result)
1018 : : return result;
1019 : :
1020 : : /* Set the cooling mode [_SCP] to active cooling (default) */
1021 : 0 : result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
1022 : 0 : if (!result)
1023 : 0 : tz->flags.cooling_mode = 1;
1024 : :
1025 : : /* Get default polling frequency [_TZP] (optional) */
1026 [ # # ]: 0 : if (tzp)
1027 : 0 : tz->polling_frequency = tzp;
1028 : : else
1029 : 0 : acpi_thermal_get_polling_frequency(tz);
1030 : :
1031 : : return 0;
1032 : : }
1033 : :
1034 : : /*
1035 : : * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI
1036 : : * handles temperature values with a single decimal place. As a consequence,
1037 : : * some implementations use an offset of 273.1 and others use an offset of
1038 : : * 273.2. Try to find out which one is being used, to present the most
1039 : : * accurate and visually appealing number.
1040 : : *
1041 : : * The heuristic below should work for all ACPI thermal zones which have a
1042 : : * critical trip point with a value being a multiple of 0.5 degree Celsius.
1043 : : */
1044 : 0 : static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
1045 : : {
1046 : 0 : if (tz->trips.critical.flags.valid &&
1047 [ # # ]: 0 : (tz->trips.critical.temperature % 5) == 1)
1048 : 0 : tz->kelvin_offset = 273100;
1049 : : else
1050 : 0 : tz->kelvin_offset = 273200;
1051 : : }
1052 : :
1053 : 0 : static void acpi_thermal_check_fn(struct work_struct *work)
1054 : : {
1055 : 0 : struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
1056 : : thermal_check_work);
1057 [ # # ]: 0 : acpi_thermal_check(tz);
1058 : 0 : }
1059 : :
1060 : 0 : static int acpi_thermal_add(struct acpi_device *device)
1061 : : {
1062 : 0 : int result = 0;
1063 : 0 : struct acpi_thermal *tz = NULL;
1064 : :
1065 : :
1066 [ # # ]: 0 : if (!device)
1067 : : return -EINVAL;
1068 : :
1069 : 0 : tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
1070 [ # # ]: 0 : if (!tz)
1071 : : return -ENOMEM;
1072 : :
1073 : 0 : tz->device = device;
1074 : 0 : strcpy(tz->name, device->pnp.bus_id);
1075 : 0 : strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
1076 : 0 : strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1077 : 0 : device->driver_data = tz;
1078 : :
1079 : 0 : result = acpi_thermal_get_info(tz);
1080 [ # # ]: 0 : if (result)
1081 : 0 : goto free_memory;
1082 : :
1083 [ # # ]: 0 : acpi_thermal_guess_offset(tz);
1084 : :
1085 : 0 : result = acpi_thermal_register_thermal_zone(tz);
1086 [ # # ]: 0 : if (result)
1087 : 0 : goto free_memory;
1088 : :
1089 [ # # ]: 0 : INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
1090 : :
1091 [ # # ]: 0 : pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
1092 : : acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature));
1093 : 0 : goto end;
1094 : :
1095 : 0 : free_memory:
1096 : 0 : kfree(tz);
1097 : : end:
1098 : : return result;
1099 : : }
1100 : :
1101 : 0 : static int acpi_thermal_remove(struct acpi_device *device)
1102 : : {
1103 : 0 : struct acpi_thermal *tz = NULL;
1104 : :
1105 [ # # # # ]: 0 : if (!device || !acpi_driver_data(device))
1106 : : return -EINVAL;
1107 : :
1108 : 0 : flush_workqueue(acpi_thermal_pm_queue);
1109 : 0 : tz = acpi_driver_data(device);
1110 : :
1111 : 0 : acpi_thermal_unregister_thermal_zone(tz);
1112 : 0 : kfree(tz);
1113 : 0 : return 0;
1114 : : }
1115 : :
1116 : : #ifdef CONFIG_PM_SLEEP
1117 : 0 : static int acpi_thermal_suspend(struct device *dev)
1118 : : {
1119 : : /* Make sure the previously queued thermal check work has been done */
1120 : 0 : flush_workqueue(acpi_thermal_pm_queue);
1121 : 0 : return 0;
1122 : : }
1123 : :
1124 : 0 : static int acpi_thermal_resume(struct device *dev)
1125 : : {
1126 : 0 : struct acpi_thermal *tz;
1127 : 0 : int i, j, power_state, result;
1128 : :
1129 [ # # ]: 0 : if (!dev)
1130 : : return -EINVAL;
1131 : :
1132 [ # # ]: 0 : tz = acpi_driver_data(to_acpi_device(dev));
1133 [ # # ]: 0 : if (!tz)
1134 : : return -EINVAL;
1135 : :
1136 [ # # ]: 0 : for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
1137 [ # # ]: 0 : if (!(&tz->trips.active[i]))
1138 : : break;
1139 [ # # ]: 0 : if (!tz->trips.active[i].flags.valid)
1140 : : break;
1141 : 0 : tz->trips.active[i].flags.enabled = 1;
1142 [ # # ]: 0 : for (j = 0; j < tz->trips.active[i].devices.count; j++) {
1143 : 0 : result = acpi_bus_update_power(
1144 : : tz->trips.active[i].devices.handles[j],
1145 : : &power_state);
1146 [ # # # # ]: 0 : if (result || (power_state != ACPI_STATE_D0)) {
1147 : 0 : tz->trips.active[i].flags.enabled = 0;
1148 : 0 : break;
1149 : : }
1150 : : }
1151 : 0 : tz->state.active |= tz->trips.active[i].flags.enabled;
1152 : : }
1153 : :
1154 : 0 : queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
1155 : :
1156 : 0 : return AE_OK;
1157 : : }
1158 : : #endif
1159 : :
1160 : 0 : static int thermal_act(const struct dmi_system_id *d) {
1161 : :
1162 [ # # ]: 0 : if (act == 0) {
1163 : 0 : pr_notice(PREFIX "%s detected: "
1164 : : "disabling all active thermal trip points\n", d->ident);
1165 : 0 : act = -1;
1166 : : }
1167 : 0 : return 0;
1168 : : }
1169 : 0 : static int thermal_nocrt(const struct dmi_system_id *d) {
1170 : :
1171 : 0 : pr_notice(PREFIX "%s detected: "
1172 : : "disabling all critical thermal trip point actions.\n", d->ident);
1173 : 0 : nocrt = 1;
1174 : 0 : return 0;
1175 : : }
1176 : 0 : static int thermal_tzp(const struct dmi_system_id *d) {
1177 : :
1178 [ # # ]: 0 : if (tzp == 0) {
1179 : 0 : pr_notice(PREFIX "%s detected: "
1180 : : "enabling thermal zone polling\n", d->ident);
1181 : 0 : tzp = 300; /* 300 dS = 30 Seconds */
1182 : : }
1183 : 0 : return 0;
1184 : : }
1185 : 0 : static int thermal_psv(const struct dmi_system_id *d) {
1186 : :
1187 [ # # ]: 0 : if (psv == 0) {
1188 : 0 : pr_notice(PREFIX "%s detected: "
1189 : : "disabling all passive thermal trip points\n", d->ident);
1190 : 0 : psv = -1;
1191 : : }
1192 : 0 : return 0;
1193 : : }
1194 : :
1195 : : static const struct dmi_system_id thermal_dmi_table[] __initconst = {
1196 : : /*
1197 : : * Award BIOS on this AOpen makes thermal control almost worthless.
1198 : : * http://bugzilla.kernel.org/show_bug.cgi?id=8842
1199 : : */
1200 : : {
1201 : : .callback = thermal_act,
1202 : : .ident = "AOpen i915GMm-HFS",
1203 : : .matches = {
1204 : : DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1205 : : DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1206 : : },
1207 : : },
1208 : : {
1209 : : .callback = thermal_psv,
1210 : : .ident = "AOpen i915GMm-HFS",
1211 : : .matches = {
1212 : : DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1213 : : DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1214 : : },
1215 : : },
1216 : : {
1217 : : .callback = thermal_tzp,
1218 : : .ident = "AOpen i915GMm-HFS",
1219 : : .matches = {
1220 : : DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
1221 : : DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
1222 : : },
1223 : : },
1224 : : {
1225 : : .callback = thermal_nocrt,
1226 : : .ident = "Gigabyte GA-7ZX",
1227 : : .matches = {
1228 : : DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
1229 : : DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
1230 : : },
1231 : : },
1232 : : {}
1233 : : };
1234 : :
1235 : 11 : static int __init acpi_thermal_init(void)
1236 : : {
1237 : 11 : int result = 0;
1238 : :
1239 : 11 : dmi_check_system(thermal_dmi_table);
1240 : :
1241 [ - + ]: 11 : if (off) {
1242 : 0 : pr_notice(PREFIX "thermal control disabled\n");
1243 : 0 : return -ENODEV;
1244 : : }
1245 : :
1246 : 11 : acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
1247 : : WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
1248 [ + - ]: 11 : if (!acpi_thermal_pm_queue)
1249 : : return -ENODEV;
1250 : :
1251 : 11 : result = acpi_bus_register_driver(&acpi_thermal_driver);
1252 [ - + ]: 11 : if (result < 0) {
1253 : 0 : destroy_workqueue(acpi_thermal_pm_queue);
1254 : 0 : return -ENODEV;
1255 : : }
1256 : :
1257 : : return 0;
1258 : : }
1259 : :
1260 : 0 : static void __exit acpi_thermal_exit(void)
1261 : : {
1262 : 0 : acpi_bus_unregister_driver(&acpi_thermal_driver);
1263 : 0 : destroy_workqueue(acpi_thermal_pm_queue);
1264 : :
1265 : 0 : return;
1266 : : }
1267 : :
1268 : : module_init(acpi_thermal_init);
1269 : : module_exit(acpi_thermal_exit);
|