diff options
author | Zhang Rui <rui.zhang@intel.com> | 2008-01-17 02:51:25 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-02-01 23:12:19 -0500 |
commit | ce44e19701ac1de004815c225585ff617c5948b4 (patch) | |
tree | 11a9af7a8c0b001a93e68db824b96e49662397d8 /drivers/acpi | |
parent | 3f655ef8c439e0775ffb7d1ead5d1d4f060e1f8b (diff) |
ACPI: ACPI thermal zone handle notification correctly
Change the ACPI thermal action upon notification 0x81 and 0x82.
According to the ACPI spec, we should:
re-evaluate _PSV and _ACx methods upon notification 0x81
re-evaluate _PSL and _ALx and _TZD upon notificaiton 0x82.
But the current code re-evaluates all the trip points for 0x81 while
only re-evaluates _TZD for 0x82.
Fix this violation of ACPI spec.
TODO: devices in _PSL, _ALx and _TZD may change after a notification 0x82.
At this time, we need to re-bind the cooling devices with the thermal zone.
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Thomas Sujith <sujith.thomas@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/thermal.c | 325 |
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 | ||
326 | static 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 { | 347 | do { \ |
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 | |||
354 | static 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 | ||
479 | static int acpi_thermal_get_devices(struct acpi_thermal *tz) | 538 | static 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 | ||
495 | static int acpi_thermal_critical(struct acpi_thermal *tz) | 543 | static 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 | ||