diff options
| -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 | ||
