Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/tzmon/tzmon.c
+++ new/usr/src/uts/i86pc/io/tzmon/tzmon.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Solaris x86 ACPI ThermalZone Monitor
29 29 */
30 30
31 31
32 32 #include <sys/errno.h>
33 33 #include <sys/conf.h>
34 34 #include <sys/modctl.h>
35 35 #include <sys/open.h>
36 36 #include <sys/stat.h>
37 37 #include <sys/ddi.h>
38 38 #include <sys/sunddi.h>
39 39 #include <sys/ksynch.h>
40 40 #include <sys/uadmin.h>
41 41 #include <sys/acpi/acpi.h>
42 42 #include <sys/acpica.h>
43 43 #include <sys/sdt.h>
44 44
45 45 #include "tzmon.h"
46 46
47 47
48 48 #define TZMON_ENUM_TRIP_POINTS 1
49 49 #define TZMON_ENUM_DEV_LISTS 2
50 50 #define TZMON_ENUM_ALL (TZMON_ENUM_TRIP_POINTS | TZMON_ENUM_DEV_LISTS)
51 51
52 52 /*
53 53 * TZ_TASKQ_NAME_LEN is precisely the length of the string "AcpiThermalMonitor"
54 54 * plus a two-digit instance number plus a NULL. If the taskq name is changed
55 55 * (particularly if it is lengthened), then this value needs to change.
56 56 */
57 57 #define TZ_TASKQ_NAME_LEN 21
58 58
59 59 /*
60 60 * Kelvin to Celsius conversion
61 61 * The formula for converting degrees Kelvin to degrees Celsius is
62 62 * C = K - 273.15 (we round to 273.2). The unit for thermal zone
63 63 * temperatures is tenths of a degree Kelvin. Use tenth of a degree
64 64 * to convert, then make a whole number out of it.
65 65 */
66 66 #define K_TO_C(temp) (((temp) - 2732) / 10)
67 67
68 68
69 69 /* cb_ops or dev_ops forward declarations */
70 70 static int tzmon_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
71 71 void *arg, void **result);
72 72 static int tzmon_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
73 73 static int tzmon_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
74 74
75 75 /* other forward declarations */
76 76 static void tzmon_notify_zone(ACPI_HANDLE obj, UINT32 val, void *ctx);
77 77 static void tzmon_eval_int(ACPI_HANDLE obj, char *method, int *rv);
78 78 static thermal_zone_t *tzmon_alloc_zone();
79 79 static void tzmon_free_zone_list();
80 80 static void tzmon_discard_buffers(thermal_zone_t *tzp);
81 81 static void tzmon_enumerate_zone(ACPI_HANDLE obj, thermal_zone_t *tzp,
82 82 int enum_flag);
83 83 static ACPI_STATUS tzmon_zone_callback(ACPI_HANDLE obj, UINT32 nest,
84 84 void *ctx, void **rv);
85 85 static void tzmon_find_zones(void);
86 86 static void tzmon_monitor(void *ctx);
87 87 static void tzmon_set_power_device(ACPI_HANDLE dev, int on_off, char *tz_name);
88 88 static void tzmon_set_power(ACPI_BUFFER devlist, int on_off, char *tz_name);
89 89 static void tzmon_eval_zone(thermal_zone_t *tzp);
90 90 static void tzmon_do_shutdown(void);
91 91
92 92 extern void halt(char *);
93 93
94 94 static struct cb_ops tzmon_cb_ops = {
95 95 nodev, /* no open routine */
96 96 nodev, /* no close routine */
97 97 nodev, /* not a block driver */
98 98 nodev, /* no print routine */
99 99 nodev, /* no dump routine */
100 100 nodev, /* no read routine */
101 101 nodev, /* no write routine */
102 102 nodev, /* no ioctl routine */
103 103 nodev, /* no devmap routine */
104 104 nodev, /* no mmap routine */
105 105 nodev, /* no segmap routine */
106 106 nochpoll, /* no chpoll routine */
107 107 ddi_prop_op,
108 108 0, /* not a STREAMS driver */
109 109 D_NEW | D_MP, /* safe for multi-thread/multi-processor */
110 110 };
111 111
112 112 static struct dev_ops tzmon_ops = {
113 113 DEVO_REV, /* devo_rev */
114 114 0, /* devo_refcnt */
115 115 tzmon_getinfo, /* devo_getinfo */
116 116 nulldev, /* devo_identify */
117 117 nulldev, /* devo_probe */
118 118 tzmon_attach, /* devo_attach */
119 119 tzmon_detach, /* devo_detach */
120 120 nodev, /* devo_reset */
121 121 &tzmon_cb_ops, /* devo_cb_ops */
122 122 (struct bus_ops *)0, /* devo_bus_ops */
123 123 NULL, /* devo_power */
124 124 ddi_quiesce_not_needed, /* devo_quiesce */
125 125 };
126 126
↓ open down ↓ |
126 lines elided |
↑ open up ↑ |
127 127 extern struct mod_ops mod_driverops;
128 128
129 129 static struct modldrv modldrv = {
130 130 &mod_driverops,
131 131 "ACPI Thermal Zone Monitor",
132 132 &tzmon_ops,
133 133 };
134 134
135 135 static struct modlinkage modlinkage = {
136 136 MODREV_1, /* MODREV_1 indicated by manual */
137 - (void *)&modldrv,
138 - NULL, /* termination of list of linkage structures */
137 + { (void *)&modldrv, NULL }
139 138 };
140 139
141 140 /* globals for this module */
142 141 static dev_info_t *tzmon_dip;
143 142 static thermal_zone_t *zone_list;
144 143 static int zone_count;
145 144 static kmutex_t zone_list_lock;
146 145 static kcondvar_t zone_list_condvar;
147 146
148 147
149 148 /*
150 149 * _init, _info, and _fini support loading and unloading the driver.
151 150 */
152 151 int
153 152 _init(void)
154 153 {
155 154 return (mod_install(&modlinkage));
156 155 }
157 156
158 157
159 158 int
160 159 _info(struct modinfo *modinfop)
161 160 {
162 161 return (mod_info(&modlinkage, modinfop));
163 162 }
164 163
165 164
166 165 int
167 166 _fini(void)
168 167 {
169 168 return (mod_remove(&modlinkage));
170 169 }
171 170
172 171
173 172 static int
174 173 tzmon_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
175 174 {
176 175 if (cmd != DDI_ATTACH)
177 176 return (DDI_FAILURE);
178 177
179 178 if (tzmon_dip != NULL)
180 179 return (DDI_FAILURE);
181 180
182 181 /*
183 182 * Check to see if ACPI CA services are available
184 183 */
185 184 if (AcpiSubsystemStatus() != AE_OK)
186 185 return (DDI_FAILURE);
187 186
188 187 mutex_init(&zone_list_lock, NULL, MUTEX_DRIVER, NULL);
189 188 cv_init(&zone_list_condvar, NULL, CV_DRIVER, NULL);
190 189
191 190 tzmon_find_zones();
192 191 mutex_enter(&zone_list_lock);
193 192 if (zone_count < 1) {
194 193 mutex_exit(&zone_list_lock);
195 194 mutex_destroy(&zone_list_lock);
196 195 cv_destroy(&zone_list_condvar);
197 196 return (DDI_FAILURE);
198 197 }
199 198 mutex_exit(&zone_list_lock);
200 199
201 200 if (ddi_create_minor_node(dip, ddi_get_name(dip), S_IFCHR, 0,
202 201 DDI_PSEUDO, 0) == DDI_FAILURE) {
203 202 tzmon_free_zone_list();
204 203 mutex_destroy(&zone_list_lock);
205 204 cv_destroy(&zone_list_condvar);
206 205 return (DDI_FAILURE);
207 206 }
208 207
209 208 tzmon_dip = dip;
210 209
211 210 ddi_report_dev(dip);
212 211
213 212 return (DDI_SUCCESS);
214 213 }
215 214
216 215
217 216 /*ARGSUSED*/
218 217 static int
219 218 tzmon_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
220 219 {
221 220 int error;
222 221
223 222 switch (infocmd) {
224 223 case DDI_INFO_DEVT2DEVINFO:
225 224 *result = tzmon_dip;
226 225 if (tzmon_dip == NULL)
227 226 error = DDI_FAILURE;
228 227 else
229 228 error = DDI_SUCCESS;
230 229 break;
231 230 case DDI_INFO_DEVT2INSTANCE:
232 231 *result = 0;
233 232 error = DDI_SUCCESS;
234 233 break;
235 234 default:
236 235 *result = NULL;
237 236 error = DDI_FAILURE;
238 237 }
239 238
240 239 return (error);
241 240 }
242 241
243 242
244 243 static int
245 244 tzmon_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
246 245 {
247 246 thermal_zone_t *tzp = zone_list;
248 247
249 248 if (cmd != DDI_DETACH)
250 249 return (DDI_FAILURE);
251 250
252 251 /* free allocated thermal zone name(s) */
253 252 while (tzp != NULL) {
254 253 AcpiOsFree(tzp->zone_name);
255 254 tzp = tzp->next;
256 255 }
257 256
258 257 /* discard zone list assets */
259 258 tzmon_free_zone_list();
260 259
261 260 ddi_remove_minor_node(dip, NULL);
262 261 tzmon_dip = NULL;
263 262
264 263 mutex_destroy(&zone_list_lock);
265 264 cv_destroy(&zone_list_condvar);
266 265
267 266 return (DDI_SUCCESS);
268 267 }
269 268
270 269
271 270 /*
272 271 * tzmon_notify_zone
273 272 * Thermal zone notification handler.
274 273 */
275 274 static void
276 275 tzmon_notify_zone(ACPI_HANDLE obj, UINT32 val, void *ctx)
277 276 {
278 277 thermal_zone_t *tzp = (thermal_zone_t *)ctx;
279 278
280 279 switch (val) {
281 280 case 0x80: /* Thermal Zone status changed */
282 281 tzmon_eval_zone(tzp);
283 282 break;
284 283 case 0x81: /* Thermal Zone trip points changed */
285 284 tzmon_enumerate_zone(obj, tzp, TZMON_ENUM_TRIP_POINTS);
286 285 break;
287 286 case 0x82: /* Device Lists changed */
288 287 tzmon_enumerate_zone(obj, tzp, TZMON_ENUM_DEV_LISTS);
289 288 break;
290 289 case 0x83: /* Thermal Relationship Table changed */
291 290 /* not handling _TRT objects, so not handling this event */
292 291 DTRACE_PROBE1(trt__change, char *, (char *)tzp->zone_name);
293 292 break;
294 293 default:
295 294 break;
296 295 }
297 296 }
298 297
299 298
300 299 /*
301 300 * tzmon_eval_int
302 301 * Evaluate the object/method as an integer.
303 302 */
304 303 static void
305 304 tzmon_eval_int(ACPI_HANDLE obj, char *method, int *rv)
306 305 {
307 306
308 307 if (acpica_eval_int(obj, method, rv) != AE_OK)
309 308 *rv = -1;
310 309 }
311 310
312 311
313 312 /*
314 313 * tzmon_alloc_zone
315 314 * Allocate memory for the zone structure and initialize it lock mutex.
316 315 */
317 316 static thermal_zone_t *
318 317 tzmon_alloc_zone()
319 318 {
320 319 thermal_zone_t *tzp;
321 320
322 321 tzp = kmem_zalloc(sizeof (thermal_zone_t), KM_SLEEP);
323 322 mutex_init(&tzp->lock, NULL, MUTEX_DRIVER, NULL);
324 323
325 324 return (tzp);
326 325 }
327 326
328 327
329 328 /*
330 329 * tzmon_free_zone_list
331 330 * Free the zone list, either because attach failed or detach initiated.
332 331 */
333 332 static void
334 333 tzmon_free_zone_list()
335 334 {
336 335 thermal_zone_t *tzp = zone_list;
337 336
338 337 while (tzp != NULL) {
339 338 thermal_zone_t *next;
340 339
341 340 mutex_enter(&tzp->lock);
342 341
343 342 /*
344 343 * Remove the notify handler for the zone. Not much to
345 344 * do if this fails (since we are on our way out), so
346 345 * just ignore failure.
347 346 */
348 347 (void) AcpiRemoveNotifyHandler(tzp->obj, ACPI_DEVICE_NOTIFY,
349 348 tzmon_notify_zone);
350 349
351 350 /* Shut down monitor thread, if running */
352 351 if (tzp->taskq != NULL) {
353 352 tzp->polling_period = 0;
354 353 cv_broadcast(&zone_list_condvar);
355 354
356 355 /* Drop mutex to allow the thread to run */
357 356 mutex_exit(&tzp->lock);
358 357 ddi_taskq_destroy(tzp->taskq);
359 358 mutex_enter(&tzp->lock);
360 359 }
361 360
362 361 tzmon_discard_buffers(tzp);
363 362 mutex_exit(&tzp->lock);
364 363 mutex_destroy(&tzp->lock);
365 364
366 365 next = tzp->next;
367 366 kmem_free(tzp, sizeof (thermal_zone_t));
368 367 tzp = next;
369 368 }
370 369 }
371 370
372 371
373 372 static void
374 373 tzmon_discard_buffers(thermal_zone_t *tzp)
375 374 {
376 375 int level;
377 376
378 377 for (level = 0; level < TZ_NUM_LEVELS; level++) {
379 378 if (tzp->al[level].Pointer != NULL)
380 379 AcpiOsFree(tzp->al[level].Pointer);
381 380 }
382 381
383 382 if (tzp->psl.Pointer != NULL)
384 383 AcpiOsFree(tzp->psl.Pointer);
385 384 }
386 385
387 386
388 387 /*
389 388 * tzmon_enumerate_zone
390 389 * Enumerates the contents of a thermal zone and updates passed-in
391 390 * thermal_zone or creates a new one if tzp is NULL. Newly-created
392 391 * zones are linked into the global zone_list.
393 392 */
394 393 static void
395 394 tzmon_enumerate_zone(ACPI_HANDLE obj, thermal_zone_t *tzp, int enum_flag)
396 395 {
397 396 ACPI_STATUS status;
398 397 ACPI_BUFFER zone_name;
399 398 int level;
400 399 int instance;
401 400 char abuf[5];
402 401
403 402 /*
404 403 * Newly-created zones and existing zones both require
405 404 * some individual attention.
406 405 */
407 406 if (tzp == NULL) {
408 407 /* New zone required */
409 408 tzp = tzmon_alloc_zone();
410 409 mutex_enter(&zone_list_lock);
411 410 tzp->next = zone_list;
412 411 zone_list = tzp;
413 412
414 413 /*
415 414 * It is exceedingly unlikely that instance will exceed 99.
416 415 * However, if it does, this will cause problems when
417 416 * creating the taskq for this thermal zone.
418 417 */
419 418 instance = zone_count;
420 419 zone_count++;
421 420 mutex_exit(&zone_list_lock);
422 421 mutex_enter(&tzp->lock);
423 422 tzp->obj = obj;
424 423
425 424 /*
426 425 * Set to a low level. Will get set to the actual
427 426 * current power level when the thread monitor polls
428 427 * the current temperature.
429 428 */
430 429 tzp->current_level = 0;
431 430
432 431 /* Get the zone name in case we need to display it later */
433 432 zone_name.Length = ACPI_ALLOCATE_BUFFER;
434 433 zone_name.Pointer = NULL;
435 434
436 435 status = AcpiGetName(obj, ACPI_FULL_PATHNAME, &zone_name);
437 436 ASSERT(status == AE_OK);
438 437
439 438 tzp->zone_name = zone_name.Pointer;
440 439
441 440 status = AcpiInstallNotifyHandler(obj, ACPI_DEVICE_NOTIFY,
442 441 tzmon_notify_zone, (void *)tzp);
443 442 ASSERT(status == AE_OK);
444 443 } else {
445 444 /* Existing zone - toss out allocated items */
446 445 mutex_enter(&tzp->lock);
447 446 ASSERT(tzp->obj == obj);
448 447
449 448 if (enum_flag & TZMON_ENUM_DEV_LISTS)
450 449 tzmon_discard_buffers(tzp);
451 450 }
452 451
453 452 if (enum_flag & TZMON_ENUM_TRIP_POINTS) {
454 453 for (level = 0; level < TZ_NUM_LEVELS; level++) {
455 454 (void) snprintf(abuf, 5, "_AC%d", level);
456 455 tzmon_eval_int(obj, abuf, &tzp->ac[level]);
457 456
458 457 }
459 458
460 459 tzmon_eval_int(obj, "_CRT", &tzp->crt);
461 460 tzmon_eval_int(obj, "_HOT", &tzp->hot);
462 461 tzmon_eval_int(obj, "_PSV", &tzp->psv);
463 462 }
464 463
465 464 if (enum_flag & TZMON_ENUM_DEV_LISTS) {
466 465 for (level = 0; level < TZ_NUM_LEVELS; level++) {
467 466 if (tzp->ac[level] == -1) {
468 467 tzp->al[level].Length = 0;
469 468 tzp->al[level].Pointer = NULL;
470 469 } else {
471 470 (void) snprintf(abuf, 5, "_AL%d", level);
472 471 tzp->al[level].Length = ACPI_ALLOCATE_BUFFER;
473 472 tzp->al[level].Pointer = NULL;
474 473 if (AcpiEvaluateObjectTyped(obj, abuf, NULL,
475 474 &tzp->al[level], ACPI_TYPE_PACKAGE) !=
476 475 AE_OK) {
477 476 DTRACE_PROBE2(alx__missing, int, level,
478 477 char *, (char *)tzp->zone_name);
479 478
480 479 tzp->al[level].Length = 0;
481 480 tzp->al[level].Pointer = NULL;
482 481 }
483 482 }
484 483 }
485 484
486 485 tzp->psl.Length = ACPI_ALLOCATE_BUFFER;
487 486 tzp->psl.Pointer = NULL;
488 487 (void) AcpiEvaluateObjectTyped(obj, "_PSL", NULL, &tzp->psl,
489 488 ACPI_TYPE_PACKAGE);
490 489 }
491 490
492 491 tzmon_eval_int(obj, "_TC1", &tzp->tc1);
493 492 tzmon_eval_int(obj, "_TC2", &tzp->tc2);
494 493 tzmon_eval_int(obj, "_TSP", &tzp->tsp);
495 494 tzmon_eval_int(obj, "_TZP", &tzp->tzp);
496 495
497 496 if (tzp->tzp == 0) {
498 497 tzp->polling_period = 0;
499 498 } else {
500 499 if (tzp->tzp < 0)
501 500 tzp->polling_period = TZ_DEFAULT_PERIOD;
502 501 else
503 502 tzp->polling_period = tzp->tzp/10;
504 503
505 504 /* start monitor thread if needed */
506 505 if (tzp->taskq == NULL) {
507 506 char taskq_name[TZ_TASKQ_NAME_LEN];
508 507
509 508 (void) snprintf(taskq_name, TZ_TASKQ_NAME_LEN,
510 509 "AcpiThermalMonitor%02d", instance);
511 510 tzp->taskq = ddi_taskq_create(tzmon_dip,
512 511 taskq_name, 1, TASKQ_DEFAULTPRI, 0);
513 512 if (tzp->taskq == NULL) {
514 513 tzp->polling_period = 0;
515 514 cmn_err(CE_WARN, "tzmon: could not create "
516 515 "monitor thread for thermal zone %s - "
517 516 "monitor by notify only",
518 517 (char *)tzp->zone_name);
519 518 } else {
520 519 (void) ddi_taskq_dispatch(tzp->taskq,
521 520 tzmon_monitor, tzp, DDI_SLEEP);
522 521 }
523 522 }
524 523 }
525 524
526 525 mutex_exit(&tzp->lock);
527 526 }
528 527
529 528
530 529 /*
531 530 * tzmon_zone_callback
532 531 * Enumerate the thermal zone if it has a _TMP (current thermal zone
533 532 * operating temperature) method.
534 533 */
535 534 /*ARGSUSED*/
536 535 static ACPI_STATUS
537 536 tzmon_zone_callback(ACPI_HANDLE obj, UINT32 nest, void *ctx, void **rv)
538 537 {
539 538 ACPI_HANDLE tmpobj;
540 539
541 540 /*
542 541 * We get both ThermalZone() and Scope(\_TZ) objects here;
543 542 * look for _TMP (without which a zone is invalid) to pick
544 543 * between them (and ignore invalid zones)
545 544 */
546 545 if (AcpiGetHandle(obj, "_TMP", &tmpobj) == AE_OK) {
547 546 tzmon_enumerate_zone(obj, NULL, TZMON_ENUM_ALL);
548 547 }
549 548
550 549 return (AE_OK);
551 550 }
552 551
553 552
554 553 /*
555 554 * tzmon_find_zones
556 555 * Find all of the thermal zones by calling a ACPICA function that
557 556 * walks the ACPI namespace and invokes a callback for each thermal
558 557 * object found.
559 558 */
560 559 static void
561 560 tzmon_find_zones()
562 561 {
563 562 ACPI_STATUS status;
564 563 int retval;
565 564
566 565 status = AcpiWalkNamespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
567 566 8, tzmon_zone_callback, NULL, NULL, (void **)&retval);
568 567
569 568 ASSERT(status == AE_OK);
570 569 }
571 570
572 571
573 572 /*
574 573 * tzmon_monitor
575 574 * Run as a separate thread, this wakes according to polling period and
576 575 * checks particular objects in the thermal zone. One instance per
577 576 * thermal zone.
578 577 */
579 578 static void
580 579 tzmon_monitor(void *ctx)
581 580 {
582 581 thermal_zone_t *tzp = (thermal_zone_t *)ctx;
583 582 clock_t ticks;
584 583
585 584 do {
586 585 /* Check out the zone */
587 586 tzmon_eval_zone(tzp);
588 587
589 588 /* Go back to sleep */
590 589 mutex_enter(&tzp->lock);
591 590 ticks = drv_usectohz(tzp->polling_period * 1000000);
592 591 if (ticks > 0)
593 592 (void) cv_reltimedwait(&zone_list_condvar,
594 593 &tzp->lock, ticks, TR_CLOCK_TICK);
595 594 mutex_exit(&tzp->lock);
596 595 } while (ticks > 0);
597 596 }
598 597
599 598
600 599 /*
601 600 * tzmon_set_power_device
602 601 */
603 602 static void
604 603 tzmon_set_power_device(ACPI_HANDLE dev, int on_off, char *tz_name)
605 604 {
606 605 ACPI_BUFFER rb;
607 606 ACPI_OBJECT *pr0;
608 607 ACPI_STATUS status;
609 608 int i;
610 609
611 610 rb.Length = ACPI_ALLOCATE_BUFFER;
612 611 rb.Pointer = NULL;
613 612 status = AcpiEvaluateObjectTyped(dev, "_PR0", NULL, &rb,
614 613 ACPI_TYPE_PACKAGE);
615 614 if (status != AE_OK) {
616 615 DTRACE_PROBE2(alx__error, int, 2, char *, tz_name);
617 616 return;
618 617 }
619 618
620 619 pr0 = ((ACPI_OBJECT *)rb.Pointer);
621 620 for (i = 0; i < pr0->Package.Count; i++) {
622 621 status = AcpiEvaluateObject(
623 622 pr0->Package.Elements[i].Reference.Handle,
624 623 on_off ? "_ON" : "_OFF", NULL, NULL);
625 624 if (status != AE_OK) {
626 625 DTRACE_PROBE2(alx__error, int, 4, char *, tz_name);
627 626 }
628 627 }
629 628
630 629 AcpiOsFree(rb.Pointer);
631 630 }
632 631
633 632
634 633 /*
635 634 * tzmon_set_power
636 635 * Turn on or turn off all devices in the supplied list.
637 636 */
638 637 static void
639 638 tzmon_set_power(ACPI_BUFFER devlist, int on_off, char *tz_name)
640 639 {
641 640 ACPI_OBJECT *devs;
642 641 int i;
643 642
644 643 devs = ((ACPI_OBJECT *)devlist.Pointer);
645 644 if (devs->Type != ACPI_TYPE_PACKAGE) {
646 645 DTRACE_PROBE2(alx__error, int, 1, char *, tz_name);
647 646 return;
648 647 }
649 648
650 649 for (i = 0; i < devs->Package.Count; i++)
651 650 tzmon_set_power_device(
652 651 devs->Package.Elements[i].Reference.Handle, on_off,
653 652 tz_name);
654 653 }
655 654
656 655
657 656 /*
658 657 * tzmon_eval_zone
659 658 * Evaluate the current conditions within the thermal zone.
660 659 */
661 660 static void
662 661 tzmon_eval_zone(thermal_zone_t *tzp)
663 662 {
664 663 int tmp, new_level, level;
665 664
666 665 mutex_enter(&tzp->lock);
667 666
668 667 /* get the current temperature from ACPI */
669 668 tzmon_eval_int(tzp->obj, "_TMP", &tmp);
670 669 DTRACE_PROBE4(tz__temp, int, tmp, int, tzp->crt, int, tzp->hot,
671 670 char *, (char *)tzp->zone_name);
672 671
673 672 /* _HOT handling */
674 673 if (tzp->hot > 0 && tmp >= tzp->hot) {
675 674 cmn_err(CE_WARN,
676 675 "tzmon: Thermal zone (%s) is too hot (%d C); "
677 676 "initiating shutdown\n",
678 677 (char *)tzp->zone_name, K_TO_C(tmp));
679 678
680 679 tzmon_do_shutdown();
681 680 }
682 681
683 682 /* _CRT handling */
684 683 if (tzp->crt > 0 && tmp >= tzp->crt) {
685 684 cmn_err(CE_WARN,
686 685 "tzmon: Thermal zone (%s) is critically hot (%d C); "
687 686 "initiating rapid shutdown\n",
688 687 (char *)tzp->zone_name, K_TO_C(tmp));
689 688
690 689 /* shut down (fairly) immediately */
691 690 mdboot(A_REBOOT, AD_HALT, NULL, B_FALSE);
692 691 }
693 692
694 693 /*
695 694 * use the temperature to determine whether the thermal zone
696 695 * is at a new active cooling threshold level
697 696 */
698 697 for (level = 0, new_level = -1; level < TZ_NUM_LEVELS; level++) {
699 698 if (tzp->ac[level] >= 0 && (tmp >= tzp->ac[level])) {
700 699 new_level = level;
701 700 break;
702 701 }
703 702 }
704 703
705 704 /*
706 705 * if the active cooling threshold has changed, turn off the
707 706 * devices associated with the old one and turn on the new one
708 707 */
709 708 if (tzp->current_level != new_level) {
710 709 if ((tzp->current_level >= 0) &&
711 710 (tzp->al[tzp->current_level].Length != 0))
712 711 tzmon_set_power(tzp->al[tzp->current_level], 0,
713 712 (char *)tzp->zone_name);
714 713
715 714 if ((new_level >= 0) &&
716 715 (tzp->al[new_level].Length != 0))
717 716 tzmon_set_power(tzp->al[new_level], 1,
718 717 (char *)tzp->zone_name);
719 718
720 719 tzp->current_level = new_level;
721 720 }
722 721
723 722 mutex_exit(&tzp->lock);
724 723 }
725 724
726 725
727 726 /*
728 727 * tzmon_do_shutdown
729 728 * Initiates shutdown by sending a SIGPWR signal to init.
730 729 */
731 730 static void
732 731 tzmon_do_shutdown(void)
733 732 {
734 733 proc_t *initpp;
735 734
736 735 mutex_enter(&pidlock);
737 736 initpp = prfind(P_INITPID);
738 737 mutex_exit(&pidlock);
739 738
740 739 /* if we can't find init, just halt */
741 740 if (initpp == NULL) {
742 741 mdboot(A_REBOOT, AD_HALT, NULL, B_FALSE);
743 742 }
744 743
745 744 /* graceful shutdown with inittab and all getting involved */
746 745 psignal(initpp, SIGPWR);
747 746 }
↓ open down ↓ |
599 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX