diff options
Diffstat (limited to 'drivers/acpi/acpica/evgpeblk.c')
-rw-r--r-- | drivers/acpi/acpica/evgpeblk.c | 143 |
1 files changed, 76 insertions, 67 deletions
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index fa47e3522abe..85ded1f2540d 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -51,7 +51,7 @@ ACPI_MODULE_NAME("evgpeblk") /* Local prototypes */ static acpi_status -acpi_ev_save_method_info(acpi_handle obj_handle, +acpi_ev_match_gpe_method(acpi_handle obj_handle, u32 level, void *obj_desc, void **return_value); static acpi_status @@ -104,9 +104,7 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) while (gpe_block) { if ((&gpe_block->event_info[0] <= gpe_event_info) && - (&gpe_block->event_info[((acpi_size) - gpe_block-> - register_count) * 8] > + (&gpe_block->event_info[gpe_block->gpe_count] > gpe_event_info)) { return (TRUE); } @@ -229,7 +227,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /******************************************************************************* * - * FUNCTION: acpi_ev_save_method_info + * FUNCTION: acpi_ev_match_gpe_method * * PARAMETERS: Callback from walk_namespace * @@ -241,8 +239,7 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, * information for quick lookup during GPE dispatch * * The name of each GPE control method is of the form: - * "_Lxx" or "_Exx" - * Where: + * "_Lxx" or "_Exx", where: * L - means that the GPE is level triggered * E - means that the GPE is edge triggered * xx - is the GPE number [in HEX] @@ -250,9 +247,11 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, ******************************************************************************/ static acpi_status -acpi_ev_save_method_info(acpi_handle obj_handle, +acpi_ev_match_gpe_method(acpi_handle obj_handle, u32 level, void *obj_desc, void **return_value) { + struct acpi_namespace_node *method_node = + ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle); struct acpi_gpe_block_info *gpe_block = (void *)obj_desc; struct acpi_gpe_event_info *gpe_event_info; u32 gpe_number; @@ -262,21 +261,25 @@ acpi_ev_save_method_info(acpi_handle obj_handle, ACPI_FUNCTION_TRACE(ev_save_method_info); /* - * _Lxx and _Exx GPE method support + * Match and decode the _Lxx and _Exx GPE method names * - * 1) Extract the name from the object and convert to a string + * 1) Extract the method name and null terminate it */ - ACPI_MOVE_32_TO_32(name, - &((struct acpi_namespace_node *)obj_handle)->name. - integer); + ACPI_MOVE_32_TO_32(name, &method_node->name.integer); name[ACPI_NAME_SIZE] = 0; + /* 2) Name must begin with an underscore */ + + if (name[0] != '_') { + return_ACPI_STATUS(AE_OK); /* Ignore this method */ + } + /* - * 2) Edge/Level determination is based on the 2nd character + * 3) Edge/Level determination is based on the 2nd character * of the method name * - * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE - * if a _PRW object is found that points to this GPE. + * NOTE: Default GPE type is RUNTIME only. Later, if a _PRW object is + * found that points to this GPE, the ACPI_GPE_CAN_WAKE flag is set. */ switch (name[1]) { case 'L': @@ -288,7 +291,7 @@ acpi_ev_save_method_info(acpi_handle obj_handle, break; default: - /* Unknown method type, just ignore it! */ + /* Unknown method type, just ignore it */ ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Ignoring unknown GPE method type: %s " @@ -296,7 +299,7 @@ acpi_ev_save_method_info(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } - /* Convert the last two characters of the name to the GPE Number */ + /* 4) The last two characters of the name are the hex GPE Number */ gpe_number = ACPI_STRTOUL(&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { @@ -311,28 +314,22 @@ acpi_ev_save_method_info(acpi_handle obj_handle, /* Ensure that we have a valid GPE number for this GPE block */ - if ((gpe_number < gpe_block->block_base_number) || - (gpe_number >= (gpe_block->block_base_number + - (gpe_block->register_count * 8)))) { + gpe_event_info = acpi_ev_low_get_gpe_info(gpe_number, gpe_block); + if (!gpe_event_info) { /* - * Not valid for this GPE block, just ignore it. However, it may be - * valid for a different GPE block, since GPE0 and GPE1 methods both - * appear under \_GPE. + * This gpe_number is not valid for this GPE block, just ignore it. + * However, it may be valid for a different GPE block, since GPE0 + * and GPE1 methods both appear under \_GPE. */ return_ACPI_STATUS(AE_OK); } /* - * Now we can add this information to the gpe_event_info block for use - * during dispatch of this GPE. + * Add the GPE information from above to the gpe_event_info block for + * use during dispatch of this GPE. */ - gpe_event_info = - &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - - gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD); - - gpe_event_info->dispatch.method_node = - (struct acpi_namespace_node *)obj_handle; + gpe_event_info->flags = (u8)(type | ACPI_GPE_DISPATCH_METHOD); + gpe_event_info->dispatch.method_node = method_node; ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", @@ -351,7 +348,7 @@ acpi_ev_save_method_info(acpi_handle obj_handle, * * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a * Device. Run the _PRW method. If present, extract the GPE - * number and mark the GPE as a WAKE GPE. + * number and mark the GPE as a CAN_WAKE GPE. * ******************************************************************************/ @@ -377,7 +374,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, ACPI_BTYPE_PACKAGE, &pkg_desc); if (ACPI_FAILURE(status)) { - /* Ignore all errors from _PRW, we don't want to abort the subsystem */ + /* Ignore all errors from _PRW, we don't want to abort the walk */ return_ACPI_STATUS(AE_OK); } @@ -439,13 +436,13 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, * 2) The GPE index(number) is within the range of the Gpe Block * associated with the GPE device. */ - if ((gpe_device == target_gpe_device) && - (gpe_number >= gpe_block->block_base_number) && - (gpe_number < gpe_block->block_base_number + - (gpe_block->register_count * 8))) { - gpe_event_info = &gpe_block->event_info[gpe_number - - gpe_block-> - block_base_number]; + if (gpe_device != target_gpe_device) { + goto cleanup; + } + + gpe_event_info = acpi_ev_low_get_gpe_info(gpe_number, gpe_block); + if (gpe_event_info) { + /* This GPE can wake the system */ gpe_event_info->flags |= ACPI_GPE_CAN_WAKE; } @@ -705,8 +702,7 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) acpi_os_release_lock(acpi_gbl_gpe_lock, flags); } - acpi_current_gpe_count -= - gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH; + acpi_current_gpe_count -= gpe_block->gpe_count; /* Free the gpe_block */ @@ -760,9 +756,7 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) * Allocate the GPE event_info block. There are eight distinct GPEs * per register. Initialization to zeros is sufficient. */ - gpe_event_info = ACPI_ALLOCATE_ZEROED(((acpi_size) gpe_block-> - register_count * - ACPI_GPE_REGISTER_WIDTH) * + gpe_event_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block->gpe_count * sizeof(struct acpi_gpe_event_info)); if (!gpe_event_info) { @@ -897,6 +891,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, /* Initialize the new GPE block */ gpe_block->node = gpe_device; + gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH); gpe_block->register_count = register_count; gpe_block->block_base_number = gpe_block_base_number; @@ -925,7 +920,7 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device, ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, - acpi_ev_save_method_info, NULL, + acpi_ev_match_gpe_method, NULL, gpe_block, NULL); /* Return the new block */ @@ -938,14 +933,13 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n", (u32) gpe_block->block_base_number, (u32) (gpe_block->block_base_number + - ((gpe_block->register_count * - ACPI_GPE_REGISTER_WIDTH) - 1)), + (gpe_block->gpe_count - 1)), gpe_device->name.ascii, gpe_block->register_count, interrupt_number)); /* Update global count of currently available GPEs */ - acpi_current_gpe_count += register_count * ACPI_GPE_REGISTER_WIDTH; + acpi_current_gpe_count += gpe_block->gpe_count; return_ACPI_STATUS(AE_OK); } @@ -969,10 +963,13 @@ acpi_status acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, struct acpi_gpe_block_info *gpe_block) { + acpi_status status; struct acpi_gpe_event_info *gpe_event_info; struct acpi_gpe_walk_info gpe_info; u32 wake_gpe_count; u32 gpe_enabled_count; + u32 gpe_index; + u32 gpe_number; u32 i; u32 j; @@ -998,50 +995,62 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, gpe_info.gpe_block = gpe_block; gpe_info.gpe_device = gpe_device; - acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + status = acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_match_prw_and_gpe, NULL, &gpe_info, NULL); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "While executing _PRW methods")); + } } /* - * Enable all GPEs that have a corresponding method and aren't + * Enable all GPEs that have a corresponding method and are not * capable of generating wakeups. Any other GPEs within this block - * must be enabled via the acpi_enable_gpe() interface. + * must be enabled via the acpi_enable_gpe interface. */ wake_gpe_count = 0; gpe_enabled_count = 0; - if (gpe_device == acpi_gbl_fadt_gpe_device) + + if (gpe_device == acpi_gbl_fadt_gpe_device) { gpe_device = NULL; + } for (i = 0; i < gpe_block->register_count; i++) { for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { - acpi_status status; - acpi_size gpe_index; - int gpe_number; /* Get the info block for this particular GPE */ - gpe_index = (acpi_size)i * ACPI_GPE_REGISTER_WIDTH + j; + + gpe_index = (i * ACPI_GPE_REGISTER_WIDTH) + j; gpe_event_info = &gpe_block->event_info[gpe_index]; if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) { wake_gpe_count++; - if (acpi_gbl_leave_wake_gpes_disabled) + if (acpi_gbl_leave_wake_gpes_disabled) { continue; + } } - if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) + /* Ignore GPEs that have no corresponding _Lxx/_Exx method */ + + if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)) { continue; + } + + /* Enable this GPE */ gpe_number = gpe_index + gpe_block->block_base_number; status = acpi_enable_gpe(gpe_device, gpe_number, - ACPI_GPE_TYPE_RUNTIME); - if (ACPI_FAILURE(status)) - ACPI_ERROR((AE_INFO, - "Failed to enable GPE %02X\n", + ACPI_GPE_TYPE_RUNTIME); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Could not enable GPE 0x%02X", gpe_number)); - else - gpe_enabled_count++; + continue; + } + + gpe_enabled_count++; } } |