1 /*- 2 * Copyright (c) 2001 Michael Smith 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include "opt_acpi.h" 29 #include <sys/param.h> 30 #include <sys/kernel.h> 31 #include <sys/malloc.h> 32 #include <sys/bus.h> 33 34 #include <contrib/dev/acpica/include/acpi.h> 35 #include <contrib/dev/acpica/include/accommon.h> 36 37 #include <dev/acpica/acpivar.h> 38 39 /* 40 * ACPI power resource management. 41 * 42 * Power resource behaviour is slightly complicated by the fact that 43 * a single power resource may provide power for more than one device. 44 * Thus, we must track the device(s) being powered by a given power 45 * resource, and only deactivate it when there are no powered devices. 46 * 47 * Note that this only manages resources for known devices. There is an 48 * ugly case where we may turn off power to a device which is in use because 49 * we don't know that it depends on a given resource. We should perhaps 50 * try to be smarter about this, but a more complete solution would involve 51 * scanning all of the ACPI namespace to find devices we're not currently 52 * aware of, and this raises questions about whether they should be left 53 * on, turned off, etc. 54 */ 55 56 static MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources"); 57 58 /* Hooks for the ACPI CA debugging infrastructure */ 59 #define _COMPONENT ACPI_POWERRES 60 ACPI_MODULE_NAME("POWERRES") 61 62 /* Return values from _STA on a power resource */ 63 #define ACPI_PWR_OFF 0 64 #define ACPI_PWR_ON 1 65 66 /* A relationship between a power resource and a consumer. */ 67 struct acpi_powerreference { 68 struct acpi_powerconsumer *ar_consumer; 69 struct acpi_powerresource *ar_resource; 70 TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */ 71 TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */ 72 }; 73 74 /* A power-managed device. */ 75 struct acpi_powerconsumer { 76 /* Device which is powered */ 77 ACPI_HANDLE ac_consumer; 78 int ac_state; 79 80 struct { 81 bool prx_has; 82 size_t prx_count; 83 ACPI_HANDLE *prx_deps; 84 } ac_prx[ACPI_D_STATE_COUNT]; 85 86 TAILQ_ENTRY(acpi_powerconsumer) ac_link; 87 TAILQ_HEAD(,acpi_powerreference) ac_references; 88 }; 89 90 /* A power resource. */ 91 struct acpi_powerresource { 92 TAILQ_ENTRY(acpi_powerresource) ap_link; 93 TAILQ_HEAD(,acpi_powerreference) ap_references; 94 ACPI_HANDLE ap_resource; 95 UINT64 ap_systemlevel; 96 UINT64 ap_order; 97 }; 98 99 static TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource) 100 acpi_powerresources = TAILQ_HEAD_INITIALIZER(acpi_powerresources); 101 static TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer) 102 acpi_powerconsumers = TAILQ_HEAD_INITIALIZER(acpi_powerconsumers); 103 ACPI_SERIAL_DECL(powerres, "ACPI power resources"); 104 105 static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer); 106 static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer); 107 static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res); 108 #ifdef notyet 109 static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res); 110 #endif /* notyet */ 111 static void acpi_pwr_reference_resource(ACPI_OBJECT *obj, 112 void *arg); 113 static int acpi_pwr_dereference_resource(struct acpi_powerconsumer 114 *pc); 115 static ACPI_STATUS acpi_pwr_switch_power(void); 116 static struct acpi_powerresource 117 *acpi_pwr_find_resource(ACPI_HANDLE res); 118 static struct acpi_powerconsumer 119 *acpi_pwr_find_consumer(ACPI_HANDLE consumer); 120 static ACPI_STATUS acpi_pwr_infer_state(struct acpi_powerconsumer *pc); 121 static ACPI_STATUS acpi_pwr_get_state_locked(ACPI_HANDLE consumer, int *state); 122 123 /* 124 * Register a power resource. 125 * 126 * It's OK to call this if we already know about the resource. 127 */ 128 static ACPI_STATUS 129 acpi_pwr_register_resource(ACPI_HANDLE res) 130 { 131 ACPI_STATUS status; 132 ACPI_BUFFER buf; 133 ACPI_OBJECT *obj; 134 struct acpi_powerresource *rp, *srp; 135 136 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 137 ACPI_SERIAL_ASSERT(powerres); 138 139 rp = NULL; 140 buf.Pointer = NULL; 141 142 /* Look to see if we know about this resource */ 143 if (acpi_pwr_find_resource(res) != NULL) 144 return_ACPI_STATUS (AE_OK); /* already know about it */ 145 146 /* Allocate a new resource */ 147 if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) { 148 status = AE_NO_MEMORY; 149 goto out; 150 } 151 TAILQ_INIT(&rp->ap_references); 152 rp->ap_resource = res; 153 154 /* Get the Power Resource object */ 155 buf.Length = ACPI_ALLOCATE_BUFFER; 156 if (ACPI_FAILURE(status = AcpiEvaluateObject(res, NULL, NULL, &buf))) { 157 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no power resource object\n")); 158 goto out; 159 } 160 obj = buf.Pointer; 161 if (obj->Type != ACPI_TYPE_POWER) { 162 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 163 "questionable power resource object %s\n", 164 acpi_name(res))); 165 status = AE_TYPE; 166 goto out; 167 } 168 rp->ap_systemlevel = obj->PowerResource.SystemLevel; 169 rp->ap_order = obj->PowerResource.ResourceOrder; 170 171 /* Sort the resource into the list */ 172 status = AE_OK; 173 srp = TAILQ_FIRST(&acpi_powerresources); 174 if (srp == NULL || rp->ap_order < srp->ap_order) { 175 TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link); 176 goto done; 177 } 178 TAILQ_FOREACH(srp, &acpi_powerresources, ap_link) { 179 if (rp->ap_order < srp->ap_order) { 180 TAILQ_INSERT_BEFORE(srp, rp, ap_link); 181 goto done; 182 } 183 } 184 TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link); 185 186 done: 187 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 188 "registered power resource %s\n", acpi_name(res))); 189 190 out: 191 if (buf.Pointer != NULL) 192 AcpiOsFree(buf.Pointer); 193 if (ACPI_FAILURE(status) && rp != NULL) 194 free(rp, M_ACPIPWR); 195 return_ACPI_STATUS (status); 196 } 197 198 #ifdef notyet 199 /* 200 * Deregister a power resource. 201 */ 202 static ACPI_STATUS 203 acpi_pwr_deregister_resource(ACPI_HANDLE res) 204 { 205 struct acpi_powerresource *rp; 206 207 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 208 ACPI_SERIAL_ASSERT(powerres); 209 210 rp = NULL; 211 212 /* Find the resource */ 213 if ((rp = acpi_pwr_find_resource(res)) == NULL) 214 return_ACPI_STATUS (AE_BAD_PARAMETER); 215 216 /* Check that there are no consumers referencing this resource */ 217 if (TAILQ_FIRST(&rp->ap_references) != NULL) 218 return_ACPI_STATUS (AE_BAD_PARAMETER); 219 220 /* Pull it off the list and free it */ 221 TAILQ_REMOVE(&acpi_powerresources, rp, ap_link); 222 free(rp, M_ACPIPWR); 223 224 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power resource %s\n", 225 acpi_name(res))); 226 227 return_ACPI_STATUS (AE_OK); 228 } 229 #endif /* notyet */ 230 231 /* 232 * Evaluate the _PRx (power resources each D-state depends on). This also 233 * populates the acpi_powerresources queue with the power resources discovered 234 * during this step. 235 * 236 * ACPI 7.3.8 - 7.3.11 guarantee that _PRx will return the same data each 237 * time they are evaluated. 238 * 239 * If this function fails, acpi_pwr_deregister_consumer() must be called on the 240 * power consumer to free already allocated memory. 241 */ 242 static ACPI_STATUS 243 acpi_pwr_get_power_resources(ACPI_HANDLE consumer, struct acpi_powerconsumer *pc) 244 { 245 ACPI_INTEGER status; 246 ACPI_STRING reslist_name; 247 ACPI_HANDLE reslist_handle; 248 ACPI_STRING reslist_names[] = {"_PR0", "_PR1", "_PR2", "_PR3"}; 249 ACPI_BUFFER reslist; 250 ACPI_OBJECT *reslist_object; 251 ACPI_OBJECT *dep; 252 ACPI_HANDLE *res; 253 254 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 255 ACPI_SERIAL_ASSERT(powerres); 256 257 MPASS(consumer != NULL); 258 259 for (int state = ACPI_STATE_D0; state <= ACPI_STATE_D3_HOT; state++) { 260 pc->ac_prx[state].prx_has = false; 261 pc->ac_prx[state].prx_count = 0; 262 pc->ac_prx[state].prx_deps = NULL; 263 264 reslist_name = reslist_names[state - ACPI_STATE_D0]; 265 if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle))) 266 continue; 267 268 reslist.Pointer = NULL; 269 reslist.Length = ACPI_ALLOCATE_BUFFER; 270 status = AcpiEvaluateObjectTyped(reslist_handle, NULL, NULL, &reslist, 271 ACPI_TYPE_PACKAGE); 272 if (ACPI_FAILURE(status) || reslist.Pointer == NULL) 273 /* 274 * ACPI_ALLOCATE_BUFFER entails everything will be freed on error 275 * by AcpiEvaluateObjectTyped. 276 */ 277 continue; 278 279 reslist_object = (ACPI_OBJECT *)reslist.Pointer; 280 pc->ac_prx[state].prx_has = true; 281 pc->ac_prx[state].prx_count = reslist_object->Package.Count; 282 283 if (reslist_object->Package.Count == 0) { 284 AcpiOsFree(reslist_object); 285 continue; 286 } 287 288 pc->ac_prx[state].prx_deps = mallocarray(pc->ac_prx[state].prx_count, 289 sizeof(*pc->ac_prx[state].prx_deps), M_ACPIPWR, M_NOWAIT); 290 if (pc->ac_prx[state].prx_deps == NULL) { 291 AcpiOsFree(reslist_object); 292 return_ACPI_STATUS (AE_NO_MEMORY); 293 } 294 295 for (size_t i = 0; i < reslist_object->Package.Count; i++) { 296 dep = &reslist_object->Package.Elements[i]; 297 res = dep->Reference.Handle; 298 pc->ac_prx[state].prx_deps[i] = res; 299 300 /* It's fine to attempt to register the same resource twice. */ 301 acpi_pwr_register_resource(res); 302 } 303 AcpiOsFree(reslist_object); 304 } 305 306 return_ACPI_STATUS (AE_OK); 307 } 308 309 /* 310 * Register a power consumer. 311 * 312 * It's OK to call this if we already know about the consumer. 313 */ 314 static ACPI_STATUS 315 acpi_pwr_register_consumer(ACPI_HANDLE consumer) 316 { 317 ACPI_INTEGER status; 318 struct acpi_powerconsumer *pc; 319 320 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 321 ACPI_SERIAL_ASSERT(powerres); 322 323 /* Check to see whether we know about this consumer already */ 324 if (acpi_pwr_find_consumer(consumer) != NULL) 325 return_ACPI_STATUS (AE_OK); 326 327 /* Allocate a new power consumer */ 328 if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) 329 return_ACPI_STATUS (AE_NO_MEMORY); 330 TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link); 331 TAILQ_INIT(&pc->ac_references); 332 pc->ac_consumer = consumer; 333 334 /* 335 * Get all its power resource dependencies, if it has _PRx. We do this now 336 * as an opportunity to populate the acpi_powerresources queue. 337 * 338 * If this fails, immediately deregister it. 339 */ 340 status = acpi_pwr_get_power_resources(consumer, pc); 341 if (ACPI_FAILURE(status)) { 342 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 343 "failed to get power resources for %s\n", 344 acpi_name(consumer))); 345 acpi_pwr_deregister_consumer(consumer); 346 return_ACPI_STATUS (status); 347 } 348 349 /* Find its initial state. */ 350 if (ACPI_FAILURE(acpi_pwr_get_state_locked(consumer, &pc->ac_state))) 351 pc->ac_state = ACPI_STATE_UNKNOWN; 352 353 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power consumer %s\n", 354 acpi_name(consumer))); 355 356 return_ACPI_STATUS (AE_OK); 357 } 358 359 /* 360 * Deregister a power consumer. 361 * 362 * This should only be done once the consumer has been powered off. 363 * (XXX is this correct? Check once implemented) 364 */ 365 static ACPI_STATUS 366 acpi_pwr_deregister_consumer(ACPI_HANDLE consumer) 367 { 368 struct acpi_powerconsumer *pc; 369 370 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 371 ACPI_SERIAL_ASSERT(powerres); 372 373 /* Find the consumer */ 374 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) 375 return_ACPI_STATUS (AE_BAD_PARAMETER); 376 377 /* Make sure the consumer's not referencing anything right now */ 378 if (TAILQ_FIRST(&pc->ac_references) != NULL) 379 return_ACPI_STATUS (AE_BAD_PARAMETER); 380 381 /* Pull the consumer off the list and free it */ 382 TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link); 383 for (size_t i = 0; i < sizeof(pc->ac_prx) / sizeof(*pc->ac_prx); i++) 384 if (pc->ac_prx[i].prx_deps != NULL) 385 free(pc->ac_prx[i].prx_deps, M_ACPIPWR); 386 free(pc, M_ACPIPWR); 387 388 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n", 389 acpi_name(consumer))); 390 391 return_ACPI_STATUS (AE_OK); 392 } 393 394 /* 395 * The _PSC control method isn't required if it's possible to infer the D-state 396 * from the _PRx control methods. (See 7.3.6.) 397 * We can infer that a given D-state has been achieved when all the dependencies 398 * are in the ON state. 399 */ 400 static ACPI_STATUS 401 acpi_pwr_infer_state(struct acpi_powerconsumer *pc) 402 { 403 ACPI_HANDLE *res; 404 uint32_t on; 405 bool all_on = false; 406 407 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 408 ACPI_SERIAL_ASSERT(powerres); 409 410 /* It is important we go from the hottest to the coldest state. */ 411 for ( 412 pc->ac_state = ACPI_STATE_D0; 413 pc->ac_state <= ACPI_STATE_D3_HOT && !all_on; 414 pc->ac_state++ 415 ) { 416 MPASS(pc->ac_state <= sizeof(pc->ac_prx) / sizeof(*pc->ac_prx)); 417 418 if (!pc->ac_prx[pc->ac_state].prx_has) 419 continue; 420 421 all_on = true; 422 423 for (size_t i = 0; i < pc->ac_prx[pc->ac_state].prx_count; i++) { 424 res = pc->ac_prx[pc->ac_state].prx_deps[i]; 425 /* If failure, better to assume D-state is hotter than colder. */ 426 if (ACPI_FAILURE(acpi_GetInteger(res, "_STA", &on))) 427 continue; 428 if (on == 0) { 429 all_on = false; 430 break; 431 } 432 } 433 } 434 435 MPASS(pc->ac_state != ACPI_STATE_D0); 436 437 /* 438 * If none of the power resources required for the shallower D-states are 439 * on, then we can assume it is unpowered (i.e. D3cold). A device is not 440 * required to support D3cold however; in that case, _PR3 is not explicitly 441 * provided. Those devices should default to D3hot instead. 442 * 443 * See comments of first row of table 7.1 in ACPI spec. 444 */ 445 if (!all_on) 446 pc->ac_state = pc->ac_prx[ACPI_STATE_D3_HOT].prx_has ? 447 ACPI_STATE_D3_COLD : ACPI_STATE_D3_HOT; 448 else 449 pc->ac_state--; 450 451 return_ACPI_STATUS (AE_OK); 452 } 453 454 static ACPI_STATUS 455 acpi_pwr_get_state_locked(ACPI_HANDLE consumer, int *state) 456 { 457 struct acpi_powerconsumer *pc; 458 ACPI_HANDLE method_handle; 459 ACPI_STATUS status; 460 ACPI_BUFFER result; 461 ACPI_OBJECT *object = NULL; 462 463 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 464 ACPI_SERIAL_ASSERT(powerres); 465 466 if (consumer == NULL) 467 return_ACPI_STATUS (AE_NOT_FOUND); 468 469 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 470 if (ACPI_FAILURE(status = acpi_pwr_register_consumer(consumer))) 471 goto out; 472 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) 473 panic("acpi added power consumer but can't find it"); 474 } 475 476 status = AcpiGetHandle(consumer, "_PSC", &method_handle); 477 if (ACPI_FAILURE(status)) { 478 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no _PSC object - %s\n", 479 AcpiFormatException(status))); 480 status = acpi_pwr_infer_state(pc); 481 if (ACPI_FAILURE(status)) { 482 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't infer D-state - %s\n", 483 AcpiFormatException(status))); 484 pc->ac_state = ACPI_STATE_UNKNOWN; 485 } 486 goto out; 487 } 488 489 result.Pointer = NULL; 490 result.Length = ACPI_ALLOCATE_BUFFER; 491 status = AcpiEvaluateObjectTyped(method_handle, NULL, NULL, &result, ACPI_TYPE_INTEGER); 492 if (ACPI_FAILURE(status) || result.Pointer == NULL) { 493 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to get state with _PSC - %s\n", 494 AcpiFormatException(status))); 495 pc->ac_state = ACPI_STATE_UNKNOWN; 496 goto out; 497 } 498 499 object = (ACPI_OBJECT *)result.Pointer; 500 pc->ac_state = ACPI_STATE_D0 + object->Integer.Value; 501 status = AE_OK; 502 503 out: 504 if (object != NULL) 505 AcpiOsFree(object); 506 *state = pc->ac_state; 507 return_ACPI_STATUS (status); 508 } 509 510 /* 511 * Get a power consumer's D-state. 512 */ 513 ACPI_STATUS 514 acpi_pwr_get_state(ACPI_HANDLE consumer, int *state) 515 { 516 ACPI_STATUS res; 517 518 ACPI_SERIAL_BEGIN(powerres); 519 res = acpi_pwr_get_state_locked(consumer, state); 520 ACPI_SERIAL_END(powerres); 521 return (res); 522 } 523 524 /* 525 * Set a power consumer to a particular D-state. 526 */ 527 ACPI_STATUS 528 acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) 529 { 530 struct acpi_powerconsumer *pc; 531 ACPI_HANDLE method_handle, reslist_handle, pr0_handle; 532 ACPI_BUFFER reslist_buffer; 533 ACPI_OBJECT *reslist_object; 534 ACPI_STATUS status; 535 char *method_name, *reslist_name = NULL; 536 int new_state; 537 538 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 539 540 /* It's never ok to switch a non-existent consumer. */ 541 if (consumer == NULL) 542 return_ACPI_STATUS (AE_NOT_FOUND); 543 reslist_buffer.Pointer = NULL; 544 reslist_object = NULL; 545 ACPI_SERIAL_BEGIN(powerres); 546 547 /* Find the consumer */ 548 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 549 if (ACPI_FAILURE(status = acpi_pwr_register_consumer(consumer))) 550 goto out; 551 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) 552 panic("acpi added power consumer but can't find it"); 553 } 554 555 /* Stop here if we're already at the target D-state. */ 556 if (pc->ac_state == state) { 557 status = AE_OK; 558 goto out; 559 } 560 561 /* 562 * Check for valid transitions. From D3hot or D3cold, we can only go to D0. 563 * The exception to this is going from D3hot to D3cold or the other way 564 * around. This is because they both use _PS3, so the only difference when 565 * doing these transitions is whether or not the power resources for _PR3 566 * are on for devices which support D3cold, and turning these power 567 * resources on/off is always perfectly fine (ACPI 7.3.11). 568 */ 569 status = AE_BAD_PARAMETER; 570 if (pc->ac_state == ACPI_STATE_D3_HOT && state != ACPI_STATE_D0 && 571 state != ACPI_STATE_D3_COLD) 572 goto out; 573 if (pc->ac_state == ACPI_STATE_D3_COLD && state != ACPI_STATE_D0 && 574 state != ACPI_STATE_D3_HOT) 575 goto out; 576 577 /* Find transition mechanism(s) */ 578 switch (state) { 579 case ACPI_STATE_D0: 580 method_name = "_PS0"; 581 reslist_name = "_PR0"; 582 break; 583 case ACPI_STATE_D1: 584 method_name = "_PS1"; 585 reslist_name = "_PR1"; 586 break; 587 case ACPI_STATE_D2: 588 method_name = "_PS2"; 589 reslist_name = "_PR2"; 590 break; 591 case ACPI_STATE_D3_HOT: 592 method_name = "_PS3"; 593 reslist_name = "_PR3"; 594 break; 595 case ACPI_STATE_D3_COLD: 596 method_name = "_PS3"; 597 reslist_name = NULL; 598 break; 599 default: 600 goto out; 601 } 602 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s %s -> %s\n", 603 acpi_name(consumer), acpi_d_state_to_str(pc->ac_state), 604 acpi_d_state_to_str(state))); 605 606 /* 607 * Verify that this state is supported, ie. one of method or 608 * reslist must be present. We need to do this before we go 609 * dereferencing resources (since we might be trying to go to 610 * a state we don't support). 611 * 612 * Note that if any states are supported, the device has to 613 * support D0 and D3. It's never an error to try to go to 614 * D0. 615 */ 616 if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle))) 617 method_handle = NULL; 618 if (reslist_name == NULL || 619 ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle))) 620 reslist_handle = NULL; 621 if (reslist_handle == NULL && method_handle == NULL) { 622 if (state == ACPI_STATE_D0) { 623 pc->ac_state = ACPI_STATE_D0; 624 status = AE_OK; 625 goto out; 626 } 627 if (state == ACPI_STATE_D3_COLD) 628 state = ACPI_STATE_D3_HOT; 629 if (state != ACPI_STATE_D3_HOT) { 630 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 631 "attempt to set unsupported state %s\n", 632 acpi_d_state_to_str(state))); 633 goto out; 634 } 635 636 /* 637 * Turn off the resources listed in _PR0 to go to D3. If there is 638 * no _PR0 method, this object doesn't support ACPI power states. 639 */ 640 if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) { 641 status = AE_NOT_FOUND; 642 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 643 "device missing _PR0 (desired state was %s)\n", 644 acpi_d_state_to_str(state))); 645 goto out; 646 } 647 reslist_buffer.Length = ACPI_ALLOCATE_BUFFER; 648 status = AcpiEvaluateObject(pr0_handle, NULL, NULL, &reslist_buffer); 649 if (ACPI_FAILURE(status)) { 650 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 651 "can't evaluate _PR0 for device %s, state %s\n", 652 acpi_name(consumer), acpi_d_state_to_str(state))); 653 goto out; 654 } 655 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer; 656 if (!ACPI_PKG_VALID(reslist_object, 1)) { 657 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 658 "invalid package object for state %s\n", 659 acpi_d_state_to_str(state))); 660 status = AE_TYPE; 661 goto out; 662 } 663 AcpiOsFree(reslist_buffer.Pointer); 664 reslist_buffer.Pointer = NULL; 665 reslist_object = NULL; 666 } 667 668 /* 669 * Check that we can actually fetch the list of power resources 670 */ 671 if (reslist_handle != NULL) { 672 reslist_buffer.Length = ACPI_ALLOCATE_BUFFER; 673 status = AcpiEvaluateObject(reslist_handle, NULL, NULL, 674 &reslist_buffer); 675 if (ACPI_FAILURE(status)) { 676 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 677 "can't evaluate resource list %s\n", 678 acpi_name(reslist_handle))); 679 goto out; 680 } 681 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer; 682 if (reslist_object->Type != ACPI_TYPE_PACKAGE) { 683 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 684 "resource list is not ACPI_TYPE_PACKAGE (%d)\n", 685 reslist_object->Type)); 686 status = AE_TYPE; 687 goto out; 688 } 689 } 690 691 /* 692 * Now we are ready to switch, so kill off any current power 693 * resource references. 694 */ 695 acpi_pwr_dereference_resource(pc); 696 697 /* 698 * Add new power resource references, if we have any. Traverse the 699 * package that we got from evaluating reslist_handle, and look up each 700 * of the resources that are referenced. 701 */ 702 if (reslist_object != NULL) { 703 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "referencing %d new resources\n", 704 reslist_object->Package.Count)); 705 acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, 706 pc); 707 } 708 709 /* 710 * If we changed anything in the resource list, we need to run a switch 711 * pass now. 712 */ 713 if (ACPI_FAILURE(status = acpi_pwr_switch_power())) { 714 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 715 "failed to switch resources from %s to %s\n", 716 acpi_name(consumer), acpi_d_state_to_str(state))); 717 718 /* XXX is this appropriate? Should we return to previous state? */ 719 goto out; 720 } 721 722 /* Invoke power state switch method (if present) */ 723 if (method_handle != NULL) { 724 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 725 "invoking state transition method %s\n", 726 acpi_name(method_handle))); 727 status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL); 728 if (ACPI_FAILURE(status)) { 729 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to set state - %s\n", 730 AcpiFormatException(status))); 731 pc->ac_state = ACPI_STATE_UNKNOWN; 732 733 /* XXX Should we return to previous state? */ 734 goto out; 735 } 736 } 737 738 /* 739 * Make sure the transition succeeded. If getting new state failed, 740 * just assume the new state is what we wanted. This was the behaviour 741 * before we were checking D-states. 742 */ 743 if (ACPI_FAILURE(acpi_pwr_get_state_locked(consumer, &new_state))) { 744 printf("%s: failed to get new D-state\n", __func__); 745 pc->ac_state = state; 746 } else { 747 if (new_state != state) 748 printf("%s: new power state %s is not the one requested %s\n", 749 __func__, acpi_d_state_to_str(new_state), 750 acpi_d_state_to_str(state)); 751 pc->ac_state = new_state; 752 } 753 754 /* 755 * We consider the transition successful even if the state we got doesn't 756 * reflect what we set it to. This is because we weren't previously 757 * checking the new state at all, so there might exist buggy platforms on 758 * which suspend would otherwise succeed if we failed here. 759 */ 760 status = AE_OK; 761 762 out: 763 ACPI_SERIAL_END(powerres); 764 if (reslist_buffer.Pointer != NULL) 765 AcpiOsFree(reslist_buffer.Pointer); 766 return_ACPI_STATUS (status); 767 } 768 769 /* Enable or disable a power resource for wake */ 770 ACPI_STATUS 771 acpi_pwr_wake_enable(ACPI_HANDLE consumer, int enable) 772 { 773 ACPI_STATUS status; 774 struct acpi_powerconsumer *pc; 775 struct acpi_prw_data prw; 776 int i; 777 778 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 779 780 if (consumer == NULL) 781 return (AE_BAD_PARAMETER); 782 783 ACPI_SERIAL_BEGIN(powerres); 784 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 785 if (ACPI_FAILURE(status = acpi_pwr_register_consumer(consumer))) 786 goto out; 787 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) 788 panic("acpi wake added power consumer but can't find it"); 789 } 790 791 status = AE_OK; 792 if (acpi_parse_prw(consumer, &prw) != 0) 793 goto out; 794 for (i = 0; i < prw.power_res_count; i++) 795 if (enable) 796 acpi_pwr_reference_resource(&prw.power_res[i], pc); 797 else 798 acpi_pwr_dereference_resource(pc); 799 800 if (prw.power_res_count > 0) 801 acpi_pwr_switch_power(); 802 803 out: 804 ACPI_SERIAL_END(powerres); 805 return (status); 806 } 807 808 /* 809 * Called to create a reference between a power consumer and a power resource 810 * identified in the object. 811 */ 812 static void 813 acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg) 814 { 815 struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg; 816 struct acpi_powerreference *pr; 817 struct acpi_powerresource *rp; 818 ACPI_HANDLE res; 819 ACPI_STATUS status; 820 821 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 822 ACPI_SERIAL_ASSERT(powerres); 823 824 res = acpi_GetReference(NULL, obj); 825 if (res == NULL) { 826 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 827 "can't create a power reference for object type %d\n", 828 obj->Type)); 829 return_VOID; 830 } 831 832 /* Create/look up the resource */ 833 if (ACPI_FAILURE(status = acpi_pwr_register_resource(res))) { 834 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 835 "couldn't register power resource %s - %s\n", 836 obj->String.Pointer, AcpiFormatException(status))); 837 return_VOID; 838 } 839 if ((rp = acpi_pwr_find_resource(res)) == NULL) { 840 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "power resource list corrupted\n")); 841 return_VOID; 842 } 843 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "found power resource %s\n", 844 acpi_name(rp->ap_resource))); 845 846 /* Create a reference between the consumer and resource */ 847 if ((pr = malloc(sizeof(*pr), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) { 848 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 849 "allocation failed for a power consumer reference\n")); 850 return_VOID; 851 } 852 pr->ar_consumer = pc; 853 pr->ar_resource = rp; 854 TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink); 855 TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink); 856 857 return_VOID; 858 } 859 860 static int 861 acpi_pwr_dereference_resource(struct acpi_powerconsumer *pc) 862 { 863 struct acpi_powerreference *pr; 864 int changed; 865 866 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 867 ACPI_SERIAL_ASSERT(powerres); 868 869 changed = 0; 870 while ((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) { 871 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "removing reference to %s\n", 872 acpi_name(pr->ar_resource->ap_resource))); 873 TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink); 874 TAILQ_REMOVE(&pc->ac_references, pr, ar_clink); 875 free(pr, M_ACPIPWR); 876 changed = 1; 877 } 878 879 return (changed); 880 } 881 882 /* 883 * Switch power resources to conform to the desired state. 884 * 885 * Consumers may have modified the power resource list in an arbitrary 886 * fashion; we sweep it in sequence order. 887 */ 888 static ACPI_STATUS 889 acpi_pwr_switch_power(void) 890 { 891 struct acpi_powerresource *rp; 892 ACPI_STATUS status; 893 int cur; 894 895 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 896 ACPI_SERIAL_ASSERT(powerres); 897 898 /* 899 * Sweep the list forwards turning things on. 900 */ 901 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) { 902 if (TAILQ_FIRST(&rp->ap_references) == NULL) { 903 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 904 "%s has no references, not turning on\n", 905 acpi_name(rp->ap_resource))); 906 continue; 907 } 908 909 status = acpi_GetInteger(rp->ap_resource, "_STA", &cur); 910 if (ACPI_FAILURE(status)) { 911 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n", 912 acpi_name(rp->ap_resource), status)); 913 /* XXX is this correct? Always switch if in doubt? */ 914 continue; 915 } 916 917 /* 918 * Switch if required. Note that we ignore the result of the switch 919 * effort; we don't know what to do if it fails, so checking wouldn't 920 * help much. 921 */ 922 if (cur != ACPI_PWR_ON) { 923 status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL); 924 if (ACPI_FAILURE(status)) { 925 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 926 "failed to switch %s on - %s\n", 927 acpi_name(rp->ap_resource), 928 AcpiFormatException(status))); 929 } else { 930 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n", 931 acpi_name(rp->ap_resource))); 932 } 933 } else { 934 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already on\n", 935 acpi_name(rp->ap_resource))); 936 } 937 } 938 939 /* Sweep the list backwards turning things off. */ 940 TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, 941 ap_link) { 942 if (TAILQ_FIRST(&rp->ap_references) != NULL) { 943 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 944 "%s has references, not turning off\n", 945 acpi_name(rp->ap_resource))); 946 continue; 947 } 948 949 status = acpi_GetInteger(rp->ap_resource, "_STA", &cur); 950 if (ACPI_FAILURE(status)) { 951 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n", 952 acpi_name(rp->ap_resource), status)); 953 /* XXX is this correct? Always switch if in doubt? */ 954 continue; 955 } 956 957 /* 958 * Switch if required. Note that we ignore the result of the switch 959 * effort; we don't know what to do if it fails, so checking wouldn't 960 * help much. 961 */ 962 if (cur != ACPI_PWR_OFF) { 963 status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL); 964 if (ACPI_FAILURE(status)) { 965 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, 966 "failed to switch %s off - %s\n", 967 acpi_name(rp->ap_resource), 968 AcpiFormatException(status))); 969 } else { 970 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n", 971 acpi_name(rp->ap_resource))); 972 } 973 } else { 974 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already off\n", 975 acpi_name(rp->ap_resource))); 976 } 977 } 978 979 return_ACPI_STATUS (AE_OK); 980 } 981 982 /* 983 * Find a power resource's control structure. 984 */ 985 static struct acpi_powerresource * 986 acpi_pwr_find_resource(ACPI_HANDLE res) 987 { 988 struct acpi_powerresource *rp; 989 990 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 991 ACPI_SERIAL_ASSERT(powerres); 992 993 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) { 994 if (rp->ap_resource == res) 995 break; 996 } 997 998 return_PTR (rp); 999 } 1000 1001 /* 1002 * Find a power consumer's control structure. 1003 */ 1004 static struct acpi_powerconsumer * 1005 acpi_pwr_find_consumer(ACPI_HANDLE consumer) 1006 { 1007 struct acpi_powerconsumer *pc; 1008 1009 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1010 ACPI_SERIAL_ASSERT(powerres); 1011 1012 TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link) { 1013 if (pc->ac_consumer == consumer) 1014 break; 1015 } 1016 1017 return_PTR (pc); 1018 } 1019