aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/evgpeinit.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-07-07 18:43:36 -0400
committerLen Brown <len.brown@intel.com>2010-07-12 14:17:39 -0400
commit9874647ba1bdf3e1af25e079070a00676f60f2f0 (patch)
tree655caf5c08b5c882ee9a8cf14766faa24f7f1a8a /drivers/acpi/acpica/evgpeinit.c
parente8e18c956152ec9c26c94c6401c174691a8f04e7 (diff)
ACPI / ACPICA: Do not execute _PRW methods during initialization
Currently, during initialization ACPICA walks the entire ACPI namespace in search of any device objects with assciated _PRW methods. All of the _PRW methods found are executed in the process to extract the GPE information returned by them, so that the GPEs in question can be marked as "able to wakeup" (more precisely, the ACPI_GPE_CAN_WAKE flag is set for them). The only purpose of this exercise is to avoid enabling the CAN_WAKE GPEs automatically, even if there are _Lxx/_Exx methods associated with them. However, it is both costly and unnecessary, because the host OS has to execute the _PRW methods anyway to check which devices can wake up the system from sleep states. Moreover, it then uses full information returned by _PRW, including the GPE information, so it can take care of disabling the GPEs if necessary. Remove the code that walks the namespace and executes _PRW from ACPICA and modify comments to reflect that change. Make acpi_bus_set_run_wake_flags() disable GPEs for wakeup devices so that they don't cause spurious wakeup events to be signaled. This not only reduces the complexity of the ACPICA initialization code, but in some cases it should reduce the kernel boot time as well. Unfortunately, for this purpose we need a new ACPICA function, acpi_gpe_can_wake(), to be called by the host OS in order to disable the GPEs that can wake up the system and were previously enabled by acpi_ev_initialize_gpe_block() or acpi_ev_update_gpes() (such a GPE should be disabled only once, because the initialization code enables it only once, but it may be pointed to by _PRW for multiple devices and that's why the additional function is necessary). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/evgpeinit.c')
-rw-r--r--drivers/acpi/acpica/evgpeinit.c235
1 files changed, 17 insertions, 218 deletions
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 8db9e076a53b..3084c5de1bba 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -211,9 +211,7 @@ acpi_status acpi_ev_gpe_initialize(void)
211 * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a 211 * DESCRIPTION: Check for new GPE methods (_Lxx/_Exx) made available as a
212 * result of a Load() or load_table() operation. If new GPE 212 * result of a Load() or load_table() operation. If new GPE
213 * methods have been installed, register the new methods and 213 * methods have been installed, register the new methods and
214 * enable and runtime GPEs that are associated with them. Also, 214 * enable and runtime GPEs that are associated with them.
215 * run any newly loaded _PRW methods in order to discover any
216 * new CAN_WAKE GPEs.
217 * 215 *
218 ******************************************************************************/ 216 ******************************************************************************/
219 217
@@ -223,49 +221,12 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
223 struct acpi_gpe_block_info *gpe_block; 221 struct acpi_gpe_block_info *gpe_block;
224 struct acpi_gpe_walk_info walk_info; 222 struct acpi_gpe_walk_info walk_info;
225 acpi_status status = AE_OK; 223 acpi_status status = AE_OK;
226 u32 new_wake_gpe_count = 0;
227
228 /* We will examine only _PRW/_Lxx/_Exx methods owned by this table */
229
230 walk_info.owner_id = table_owner_id;
231 walk_info.execute_by_owner_id = TRUE;
232 walk_info.count = 0;
233
234 if (acpi_gbl_leave_wake_gpes_disabled) {
235 /*
236 * 1) Run any newly-loaded _PRW methods to find any GPEs that
237 * can now be marked as CAN_WAKE GPEs. Note: We must run the
238 * _PRW methods before we process the _Lxx/_Exx methods because
239 * we will enable all runtime GPEs associated with the new
240 * _Lxx/_Exx methods at the time we process those methods.
241 *
242 * Unlock interpreter so that we can run the _PRW methods.
243 */
244 walk_info.gpe_block = NULL;
245 walk_info.gpe_device = NULL;
246
247 acpi_ex_exit_interpreter();
248
249 status =
250 acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
251 ACPI_UINT32_MAX,
252 ACPI_NS_WALK_NO_UNLOCK,
253 acpi_ev_match_prw_and_gpe, NULL,
254 &walk_info, NULL);
255 if (ACPI_FAILURE(status)) {
256 ACPI_EXCEPTION((AE_INFO, status,
257 "While executing _PRW methods"));
258 }
259
260 acpi_ex_enter_interpreter();
261 new_wake_gpe_count = walk_info.count;
262 }
263 224
264 /* 225 /*
265 * 2) Find any _Lxx/_Exx GPE methods that have just been loaded. 226 * 2) Find any _Lxx/_Exx GPE methods that have just been loaded.
266 * 227 *
267 * Any GPEs that correspond to new _Lxx/_Exx methods and are not 228 * Any GPEs that correspond to new _Lxx/_Exx methods are immediately
268 * marked as CAN_WAKE are immediately enabled. 229 * enabled.
269 * 230 *
270 * Examine the namespace underneath each gpe_device within the 231 * Examine the namespace underneath each gpe_device within the
271 * gpe_block lists. 232 * gpe_block lists.
@@ -275,6 +236,8 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
275 return; 236 return;
276 } 237 }
277 238
239 walk_info.owner_id = table_owner_id;
240 walk_info.execute_by_owner_id = TRUE;
278 walk_info.count = 0; 241 walk_info.count = 0;
279 walk_info.enable_this_gpe = TRUE; 242 walk_info.enable_this_gpe = TRUE;
280 243
@@ -307,10 +270,8 @@ void acpi_ev_update_gpes(acpi_owner_id table_owner_id)
307 gpe_xrupt_info = gpe_xrupt_info->next; 270 gpe_xrupt_info = gpe_xrupt_info->next;
308 } 271 }
309 272
310 if (walk_info.count || new_wake_gpe_count) { 273 if (walk_info.count) {
311 ACPI_INFO((AE_INFO, 274 ACPI_INFO((AE_INFO, "Enabled %u new GPEs", walk_info.count));
312 "Enabled %u new runtime GPEs, added %u new wakeup GPEs",
313 walk_info.count, new_wake_gpe_count));
314 } 275 }
315 276
316 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); 277 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
@@ -386,9 +347,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
386 /* 347 /*
387 * 3) Edge/Level determination is based on the 2nd character 348 * 3) Edge/Level determination is based on the 2nd character
388 * of the method name 349 * of the method name
389 *
390 * NOTE: Default GPE type is RUNTIME only. Later, if a _PRW object is
391 * found that points to this GPE, the ACPI_GPE_CAN_WAKE flag is set.
392 */ 350 */
393 switch (name[1]) { 351 switch (name[1]) {
394 case 'L': 352 case 'L':
@@ -471,23 +429,18 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
471 */ 429 */
472 if (walk_info->enable_this_gpe) { 430 if (walk_info->enable_this_gpe) {
473 431
474 /* Ignore GPEs that can wake the system */ 432 walk_info->count++;
433 gpe_device = walk_info->gpe_device;
475 434
476 if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE) || 435 if (gpe_device == acpi_gbl_fadt_gpe_device) {
477 !acpi_gbl_leave_wake_gpes_disabled) { 436 gpe_device = NULL;
478 walk_info->count++; 437 }
479 gpe_device = walk_info->gpe_device;
480
481 if (gpe_device == acpi_gbl_fadt_gpe_device) {
482 gpe_device = NULL;
483 }
484 438
485 status = acpi_enable_gpe(gpe_device, gpe_number); 439 status = acpi_enable_gpe(gpe_device, gpe_number);
486 if (ACPI_FAILURE(status)) { 440 if (ACPI_FAILURE(status)) {
487 ACPI_EXCEPTION((AE_INFO, status, 441 ACPI_EXCEPTION((AE_INFO, status,
488 "Could not enable GPE 0x%02X", 442 "Could not enable GPE 0x%02X",
489 gpe_number)); 443 gpe_number));
490 }
491 } 444 }
492 } 445 }
493 446
@@ -496,157 +449,3 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
496 name, gpe_number)); 449 name, gpe_number));
497 return_ACPI_STATUS(AE_OK); 450 return_ACPI_STATUS(AE_OK);
498} 451}
499
500/*******************************************************************************
501 *
502 * FUNCTION: acpi_ev_match_prw_and_gpe
503 *
504 * PARAMETERS: Callback from walk_namespace
505 *
506 * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is
507 * not aborted on a single _PRW failure.
508 *
509 * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
510 * Device. Run the _PRW method. If present, extract the GPE
511 * number and mark the GPE as a CAN_WAKE GPE. Allows a
512 * per-owner_id execution if execute_by_owner_id is TRUE in the
513 * walk_info parameter block.
514 *
515 * If walk_info->execute_by_owner_id is TRUE, we only execute _PRWs with that
516 * owner.
517 * If walk_info->gpe_device is NULL, we execute every _PRW found. Otherwise,
518 * we only execute _PRWs that refer to the input gpe_device.
519 *
520 ******************************************************************************/
521
522acpi_status
523acpi_ev_match_prw_and_gpe(acpi_handle obj_handle,
524 u32 level, void *context, void **return_value)
525{
526 struct acpi_gpe_walk_info *walk_info =
527 ACPI_CAST_PTR(struct acpi_gpe_walk_info, context);
528 struct acpi_namespace_node *gpe_device;
529 struct acpi_gpe_block_info *gpe_block;
530 struct acpi_namespace_node *target_gpe_device;
531 struct acpi_namespace_node *prw_node;
532 struct acpi_gpe_event_info *gpe_event_info;
533 union acpi_operand_object *pkg_desc;
534 union acpi_operand_object *obj_desc;
535 u32 gpe_number;
536 acpi_status status;
537
538 ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe);
539
540 /* Check for a _PRW method under this device */
541
542 status = acpi_ns_get_node(obj_handle, METHOD_NAME__PRW,
543 ACPI_NS_NO_UPSEARCH, &prw_node);
544 if (ACPI_FAILURE(status)) {
545 return_ACPI_STATUS(AE_OK);
546 }
547
548 /* Check if requested owner_id matches this owner_id */
549
550 if ((walk_info->execute_by_owner_id) &&
551 (prw_node->owner_id != walk_info->owner_id)) {
552 return_ACPI_STATUS(AE_OK);
553 }
554
555 /* Execute the _PRW */
556
557 status = acpi_ut_evaluate_object(prw_node, NULL,
558 ACPI_BTYPE_PACKAGE, &pkg_desc);
559 if (ACPI_FAILURE(status)) {
560 return_ACPI_STATUS(AE_OK);
561 }
562
563 /* The returned _PRW package must have at least two elements */
564
565 if (pkg_desc->package.count < 2) {
566 goto cleanup;
567 }
568
569 /* Extract pointers from the input context */
570
571 gpe_device = walk_info->gpe_device;
572 gpe_block = walk_info->gpe_block;
573
574 /*
575 * The _PRW object must return a package, we are only interested
576 * in the first element
577 */
578 obj_desc = pkg_desc->package.elements[0];
579
580 if (obj_desc->common.type == ACPI_TYPE_INTEGER) {
581
582 /* Use FADT-defined GPE device (from definition of _PRW) */
583
584 target_gpe_device = NULL;
585 if (gpe_device) {
586 target_gpe_device = acpi_gbl_fadt_gpe_device;
587 }
588
589 /* Integer is the GPE number in the FADT described GPE blocks */
590
591 gpe_number = (u32)obj_desc->integer.value;
592 } else if (obj_desc->common.type == ACPI_TYPE_PACKAGE) {
593
594 /* Package contains a GPE reference and GPE number within a GPE block */
595
596 if ((obj_desc->package.count < 2) ||
597 ((obj_desc->package.elements[0])->common.type !=
598 ACPI_TYPE_LOCAL_REFERENCE) ||
599 ((obj_desc->package.elements[1])->common.type !=
600 ACPI_TYPE_INTEGER)) {
601 goto cleanup;
602 }
603
604 /* Get GPE block reference and decode */
605
606 target_gpe_device =
607 obj_desc->package.elements[0]->reference.node;
608 gpe_number = (u32)obj_desc->package.elements[1]->integer.value;
609 } else {
610 /* Unknown type, just ignore it */
611
612 goto cleanup;
613 }
614
615 /* Get the gpe_event_info for this GPE */
616
617 if (gpe_device) {
618 /*
619 * Is this GPE within this block?
620 *
621 * TRUE if and only if these conditions are true:
622 * 1) The GPE devices match.
623 * 2) The GPE index(number) is within the range of the Gpe Block
624 * associated with the GPE device.
625 */
626 if (gpe_device != target_gpe_device) {
627 goto cleanup;
628 }
629
630 gpe_event_info =
631 acpi_ev_low_get_gpe_info(gpe_number, gpe_block);
632 } else {
633 /* gpe_device is NULL, just match the target_device and gpe_number */
634
635 gpe_event_info =
636 acpi_ev_get_gpe_event_info(target_gpe_device, gpe_number);
637 }
638
639 if (gpe_event_info) {
640 if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
641
642 /* This GPE can wake the system */
643
644 gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
645 walk_info->count++;
646 }
647 }
648
649 cleanup:
650 acpi_ut_remove_reference(pkg_desc);
651 return_ACPI_STATUS(AE_OK);
652}