aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/thermal.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/thermal.c')
-rw-r--r--drivers/acpi/thermal.c325
1 files changed, 184 insertions, 141 deletions
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index c6cfce4c0122..d317da5c6e9c 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -323,173 +323,221 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
323 return 0; 323 return 0;
324} 324}
325 325
326static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) 326#define ACPI_TRIPS_CRITICAL 0x01
327{ 327#define ACPI_TRIPS_HOT 0x02
328 acpi_status status = AE_OK; 328#define ACPI_TRIPS_PASSIVE 0x04
329 int i = 0; 329#define ACPI_TRIPS_ACTIVE 0x08
330#define ACPI_TRIPS_DEVICES 0x10
330 331
332#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
333#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
331 334
332 if (!tz) 335#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
333 return -EINVAL; 336 ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
337 ACPI_TRIPS_DEVICES)
334 338
335 /* Critical Shutdown (required) */ 339/*
336 340 * This exception is thrown out in two cases:
337 status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, 341 * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
338 &tz->trips.critical.temperature); 342 * when re-evaluating the AML code.
339 if (ACPI_FAILURE(status)) { 343 * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
340 tz->trips.critical.flags.valid = 0; 344 * We need to re-bind the cooling devices of a thermal zone when this occurs.
341 ACPI_EXCEPTION((AE_INFO, status, "No critical threshold")); 345 */
342 return -ENODEV; 346#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
343 } else { 347do { \
344 tz->trips.critical.flags.valid = 1; 348 if (flags != ACPI_TRIPS_INIT) \
345 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 349 ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
346 "Found critical threshold [%lu]\n", 350 "ACPI thermal trip point %s changed\n" \
347 tz->trips.critical.temperature)); 351 "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
348 } 352} while (0)
353
354static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
355{
356 acpi_status status = AE_OK;
357 struct acpi_handle_list devices;
358 int valid = 0;
359 int i;
349 360
350 if (tz->trips.critical.flags.valid == 1) { 361 /* Critical Shutdown (required) */
351 if (crt == -1) { 362 if (flag & ACPI_TRIPS_CRITICAL) {
363 status = acpi_evaluate_integer(tz->device->handle,
364 "_CRT", NULL, &tz->trips.critical.temperature);
365 if (ACPI_FAILURE(status)) {
352 tz->trips.critical.flags.valid = 0; 366 tz->trips.critical.flags.valid = 0;
353 } else if (crt > 0) { 367 ACPI_EXCEPTION((AE_INFO, status,
354 unsigned long crt_k = CELSIUS_TO_KELVIN(crt); 368 "No critical threshold"));
355 369 return -ENODEV;
356 /* 370 } else {
357 * Allow override to lower critical threshold 371 tz->trips.critical.flags.valid = 1;
358 */ 372 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
359 if (crt_k < tz->trips.critical.temperature) 373 "Found critical threshold [%lu]\n",
360 tz->trips.critical.temperature = crt_k; 374 tz->trips.critical.temperature));
375 }
376 if (tz->trips.critical.flags.valid == 1) {
377 if (crt == -1) {
378 tz->trips.critical.flags.valid = 0;
379 } else if (crt > 0) {
380 unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
381 /*
382 * Allow override to lower critical threshold
383 */
384 if (crt_k < tz->trips.critical.temperature)
385 tz->trips.critical.temperature = crt_k;
386 }
361 } 387 }
362 } 388 }
363 389
364 /* Critical Sleep (optional) */ 390 /* Critical Sleep (optional) */
365 391 if (flag & ACPI_TRIPS_HOT) {
366 status =
367 acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
368 &tz->trips.hot.temperature);
369 if (ACPI_FAILURE(status)) {
370 tz->trips.hot.flags.valid = 0;
371 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
372 } else {
373 tz->trips.hot.flags.valid = 1;
374 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
375 tz->trips.hot.temperature));
376 }
377
378 /* Passive: Processors (optional) */
379
380 if (psv == -1) {
381 status = AE_SUPPORT;
382 } else if (psv > 0) {
383 tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
384 status = AE_OK;
385 } else {
386 status = acpi_evaluate_integer(tz->device->handle, 392 status = acpi_evaluate_integer(tz->device->handle,
387 "_PSV", NULL, &tz->trips.passive.temperature); 393 "_HOT", NULL, &tz->trips.hot.temperature);
394 if (ACPI_FAILURE(status)) {
395 tz->trips.hot.flags.valid = 0;
396 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
397 "No hot threshold\n"));
398 } else {
399 tz->trips.hot.flags.valid = 1;
400 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
401 "Found hot threshold [%lu]\n",
402 tz->trips.critical.temperature));
403 }
388 } 404 }
389 405
390 if (ACPI_FAILURE(status)) { 406 /* Passive (optional) */
391 tz->trips.passive.flags.valid = 0; 407 if (flag & ACPI_TRIPS_PASSIVE) {
392 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n")); 408 valid = tz->trips.passive.flags.valid;
393 } else { 409 if (psv == -1) {
394 tz->trips.passive.flags.valid = 1; 410 status = AE_SUPPORT;
395 411 } else if (psv > 0) {
396 status = 412 tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
397 acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, 413 status = AE_OK;
398 &tz->trips.passive.tc1); 414 } else {
399 if (ACPI_FAILURE(status)) 415 status = acpi_evaluate_integer(tz->device->handle,
400 tz->trips.passive.flags.valid = 0; 416 "_PSV", NULL, &tz->trips.passive.temperature);
401 417 }
402 status =
403 acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
404 &tz->trips.passive.tc2);
405 if (ACPI_FAILURE(status))
406 tz->trips.passive.flags.valid = 0;
407 418
408 status =
409 acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
410 &tz->trips.passive.tsp);
411 if (ACPI_FAILURE(status)) 419 if (ACPI_FAILURE(status))
412 tz->trips.passive.flags.valid = 0; 420 tz->trips.passive.flags.valid = 0;
413 421 else {
414 status = 422 tz->trips.passive.flags.valid = 1;
415 acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, 423 if (flag == ACPI_TRIPS_INIT) {
416 &tz->trips.passive.devices); 424 status = acpi_evaluate_integer(
425 tz->device->handle, "_TC1",
426 NULL, &tz->trips.passive.tc1);
427 if (ACPI_FAILURE(status))
428 tz->trips.passive.flags.valid = 0;
429 status = acpi_evaluate_integer(
430 tz->device->handle, "_TC2",
431 NULL, &tz->trips.passive.tc2);
432 if (ACPI_FAILURE(status))
433 tz->trips.passive.flags.valid = 0;
434 status = acpi_evaluate_integer(
435 tz->device->handle, "_TSP",
436 NULL, &tz->trips.passive.tsp);
437 if (ACPI_FAILURE(status))
438 tz->trips.passive.flags.valid = 0;
439 }
440 }
441 }
442 if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
443 memset(&devices, 0, sizeof(struct acpi_handle_list));
444 status = acpi_evaluate_reference(tz->device->handle, "_PSL",
445 NULL, &devices);
417 if (ACPI_FAILURE(status)) 446 if (ACPI_FAILURE(status))
418 tz->trips.passive.flags.valid = 0; 447 tz->trips.passive.flags.valid = 0;
419
420 if (!tz->trips.passive.flags.valid)
421 printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
422 else 448 else
423 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 449 tz->trips.passive.flags.valid = 1;
424 "Found passive threshold [%lu]\n",
425 tz->trips.passive.temperature));
426 }
427 450
428 /* Active: Fans, etc. (optional) */ 451 if (memcmp(&tz->trips.passive.devices, &devices,
452 sizeof(struct acpi_handle_list))) {
453 memcpy(&tz->trips.passive.devices, &devices,
454 sizeof(struct acpi_handle_list));
455 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
456 }
457 }
458 if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
459 if (valid != tz->trips.passive.flags.valid)
460 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
461 }
429 462
463 /* Active (optional) */
430 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { 464 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
431
432 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; 465 char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
466 valid = tz->trips.active[i].flags.valid;
433 467
434 if (act == -1) 468 if (act == -1)
435 break; /* disable all active trip points */ 469 break; /* disable all active trip points */
436 470
437 status = acpi_evaluate_integer(tz->device->handle, 471 if (flag & ACPI_TRIPS_ACTIVE) {
438 name, NULL, &tz->trips.active[i].temperature); 472 status = acpi_evaluate_integer(tz->device->handle,
439 473 name, NULL, &tz->trips.active[i].temperature);
440 if (ACPI_FAILURE(status)) { 474 if (ACPI_FAILURE(status)) {
441 if (i == 0) /* no active trip points */ 475 tz->trips.active[i].flags.valid = 0;
476 if (i == 0)
477 break;
478 if (act <= 0)
479 break;
480 if (i == 1)
481 tz->trips.active[0].temperature =
482 CELSIUS_TO_KELVIN(act);
483 else
484 /*
485 * Don't allow override higher than
486 * the next higher trip point
487 */
488 tz->trips.active[i - 1].temperature =
489 (tz->trips.active[i - 2].temperature <
490 CELSIUS_TO_KELVIN(act) ?
491 tz->trips.active[i - 2].temperature :
492 CELSIUS_TO_KELVIN(act));
442 break; 493 break;
443 if (act <= 0) /* no override requested */ 494 } else
444 break; 495 tz->trips.active[i].flags.valid = 1;
445 if (i == 1) { /* 1 trip point */
446 tz->trips.active[0].temperature =
447 CELSIUS_TO_KELVIN(act);
448 } else { /* multiple trips */
449 /*
450 * Don't allow override higher than
451 * the next higher trip point
452 */
453 tz->trips.active[i - 1].temperature =
454 (tz->trips.active[i - 2].temperature <
455 CELSIUS_TO_KELVIN(act) ?
456 tz->trips.active[i - 2].temperature :
457 CELSIUS_TO_KELVIN(act));
458 }
459 break;
460 } 496 }
461 497
462 name[2] = 'L'; 498 name[2] = 'L';
463 status = 499 if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
464 acpi_evaluate_reference(tz->device->handle, name, NULL, 500 memset(&devices, 0, sizeof(struct acpi_handle_list));
465 &tz->trips.active[i].devices); 501 status = acpi_evaluate_reference(tz->device->handle,
466 if (ACPI_SUCCESS(status)) { 502 name, NULL, &devices);
467 tz->trips.active[i].flags.valid = 1; 503 if (ACPI_FAILURE(status))
468 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 504 tz->trips.active[i].flags.valid = 0;
469 "Found active threshold [%d]:[%lu]\n", 505 else
470 i, tz->trips.active[i].temperature)); 506 tz->trips.active[i].flags.valid = 1;
471 } else 507
472 ACPI_EXCEPTION((AE_INFO, status, 508 if (memcmp(&tz->trips.active[i].devices, &devices,
473 "Invalid active threshold [%d]", i)); 509 sizeof(struct acpi_handle_list))) {
510 memcpy(&tz->trips.active[i].devices, &devices,
511 sizeof(struct acpi_handle_list));
512 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
513 }
514 }
515 if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
516 if (valid != tz->trips.active[i].flags.valid)
517 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
518
519 if (!tz->trips.active[i].flags.valid)
520 break;
521 }
522
523 if (flag & ACPI_TRIPS_DEVICES) {
524 memset(&devices, 0, sizeof(struct acpi_handle_list));
525 status = acpi_evaluate_reference(tz->device->handle, "_TZD",
526 NULL, &devices);
527 if (memcmp(&tz->devices, &devices,
528 sizeof(struct acpi_handle_list))) {
529 memcpy(&tz->devices, &devices,
530 sizeof(struct acpi_handle_list));
531 ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
532 }
474 } 533 }
475 534
476 return 0; 535 return 0;
477} 536}
478 537
479static int acpi_thermal_get_devices(struct acpi_thermal *tz) 538static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
480{ 539{
481 acpi_status status = AE_OK; 540 return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
482
483
484 if (!tz)
485 return -EINVAL;
486
487 status =
488 acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
489 if (ACPI_FAILURE(status))
490 return -ENODEV;
491
492 return 0;
493} 541}
494 542
495static int acpi_thermal_critical(struct acpi_thermal *tz) 543static int acpi_thermal_critical(struct acpi_thermal *tz)
@@ -1453,15 +1501,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
1453 acpi_thermal_check(tz); 1501 acpi_thermal_check(tz);
1454 break; 1502 break;
1455 case ACPI_THERMAL_NOTIFY_THRESHOLDS: 1503 case ACPI_THERMAL_NOTIFY_THRESHOLDS:
1456 acpi_thermal_get_trip_points(tz); 1504 acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
1457 acpi_thermal_check(tz); 1505 acpi_thermal_check(tz);
1458 acpi_bus_generate_proc_event(device, event, 0); 1506 acpi_bus_generate_proc_event(device, event, 0);
1459 acpi_bus_generate_netlink_event(device->pnp.device_class, 1507 acpi_bus_generate_netlink_event(device->pnp.device_class,
1460 device->dev.bus_id, event, 0); 1508 device->dev.bus_id, event, 0);
1461 break; 1509 break;
1462 case ACPI_THERMAL_NOTIFY_DEVICES: 1510 case ACPI_THERMAL_NOTIFY_DEVICES:
1463 if (tz->flags.devices) 1511 acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
1464 acpi_thermal_get_devices(tz); 1512 acpi_thermal_check(tz);
1465 acpi_bus_generate_proc_event(device, event, 0); 1513 acpi_bus_generate_proc_event(device, event, 0);
1466 acpi_bus_generate_netlink_event(device->pnp.device_class, 1514 acpi_bus_generate_netlink_event(device->pnp.device_class,
1467 device->dev.bus_id, event, 0); 1515 device->dev.bus_id, event, 0);
@@ -1504,11 +1552,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
1504 else 1552 else
1505 acpi_thermal_get_polling_frequency(tz); 1553 acpi_thermal_get_polling_frequency(tz);
1506 1554
1507 /* Get devices in this thermal zone [_TZD] (optional) */
1508 result = acpi_thermal_get_devices(tz);
1509 if (!result)
1510 tz->flags.devices = 1;
1511
1512 return 0; 1555 return 0;
1513} 1556}
1514 1557