From b581a7f9c3abc6c7afacd021747543d32ff17adb Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Dec 2010 22:34:01 +0100 Subject: ACPI: Execute _PRW for devices reported as inactive or not present If a device is reported as inactive or not present by its _STA control method, acpi_bus_check_add() skips it without evaluating its _PRW method. This leads to a problem when the device's _PRW method points to a GPE, because in that case the GPE may be enabled by ACPICA during the subsequent acpi_update_gpes() call which, in turn, may cause a GPE storm to appear. To avoid this issue, make acpi_bus_check_add() evaluate _PRW for inactive or not present devices and register the wakeup GPE information returned by them, so that acpi_update_gpes() does not enable their GPEs unnecessarily. Signed-off-by: Rafael J. Wysocki Reported-by: Matthew Garrett Signed-off-by: Len Brown --- drivers/acpi/scan.c | 97 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 37 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2b6c21d86b98..29ef505c487b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -705,54 +705,85 @@ static int acpi_bus_get_perf_flags(struct acpi_device *device) } static acpi_status -acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, - union acpi_object *package) +acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, + struct acpi_device_wakeup *wakeup) { - int i = 0; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *package = NULL; union acpi_object *element = NULL; + acpi_status status; + int i = 0; - if (!device || !package || (package->package.count < 2)) + if (!wakeup) return AE_BAD_PARAMETER; + /* _PRW */ + status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); + return status; + } + + package = (union acpi_object *)buffer.pointer; + + if (!package || (package->package.count < 2)) { + status = AE_BAD_DATA; + goto out; + } + element = &(package->package.elements[0]); - if (!element) - return AE_BAD_PARAMETER; + if (!element) { + status = AE_BAD_DATA; + goto out; + } if (element->type == ACPI_TYPE_PACKAGE) { if ((element->package.count < 2) || (element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) - || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) - return AE_BAD_DATA; - device->wakeup.gpe_device = + || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { + status = AE_BAD_DATA; + goto out; + } + wakeup->gpe_device = element->package.elements[0].reference.handle; - device->wakeup.gpe_number = + wakeup->gpe_number = (u32) element->package.elements[1].integer.value; } else if (element->type == ACPI_TYPE_INTEGER) { - device->wakeup.gpe_number = element->integer.value; - } else - return AE_BAD_DATA; + wakeup->gpe_device = NULL; + wakeup->gpe_number = element->integer.value; + } else { + status = AE_BAD_DATA; + goto out; + } element = &(package->package.elements[1]); if (element->type != ACPI_TYPE_INTEGER) { - return AE_BAD_DATA; + status = AE_BAD_DATA; + goto out; } - device->wakeup.sleep_state = element->integer.value; + wakeup->sleep_state = element->integer.value; if ((package->package.count - 2) > ACPI_MAX_HANDLES) { - return AE_NO_MEMORY; + status = AE_NO_MEMORY; + goto out; } - device->wakeup.resources.count = package->package.count - 2; - for (i = 0; i < device->wakeup.resources.count; i++) { + wakeup->resources.count = package->package.count - 2; + for (i = 0; i < wakeup->resources.count; i++) { element = &(package->package.elements[i + 2]); - if (element->type != ACPI_TYPE_LOCAL_REFERENCE) - return AE_BAD_DATA; + if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { + status = AE_BAD_DATA; + goto out; + } - device->wakeup.resources.handles[i] = element->reference.handle; + wakeup->resources.handles[i] = element->reference.handle; } - acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number); + acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number); - return AE_OK; + out: + kfree(buffer.pointer); + + return status; } static void acpi_bus_set_run_wake_flags(struct acpi_device *device) @@ -787,26 +818,15 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) { acpi_status status = 0; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *package = NULL; int psw_error; - /* _PRW */ - status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); - goto end; - } - - package = (union acpi_object *)buffer.pointer; - status = acpi_bus_extract_wakeup_device_power_package(device, package); + status = acpi_bus_extract_wakeup_device_power_package(device->handle, + &device->wakeup); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); goto end; } - kfree(buffer.pointer); - device->wakeup.flags.valid = 1; device->wakeup.prepare_count = 0; acpi_bus_set_run_wake_flags(device); @@ -1351,6 +1371,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, struct acpi_bus_ops *ops = context; int type; unsigned long long sta; + struct acpi_device_wakeup wakeup; struct acpi_device *device; acpi_status status; int result; @@ -1360,8 +1381,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, return AE_OK; if (!(sta & ACPI_STA_DEVICE_PRESENT) && - !(sta & ACPI_STA_DEVICE_FUNCTIONING)) + !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { + acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); return AE_CTRL_DEPTH; + } /* * We may already have an acpi_device from a previous enumeration. If -- cgit v1.2.2 From cde44d1740bcb3dcfecbf792a71826431e61686e Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 24 Dec 2010 21:43:16 -0500 Subject: Revert "ACPI battery: update status upon sysfs query" This reverts commit 3138b32d5e0998ba3cbd1c74bdc1887d74c5279b. as it caused a crash upon battery removal: https://bugzilla.kernel.org/show_bug.cgi?id=25302 Signed-off-by: Len Brown --- drivers/acpi/battery.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 9fb9d5ac939d..95649d373071 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -130,8 +130,6 @@ struct acpi_battery { unsigned long flags; }; -static int acpi_battery_update(struct acpi_battery *battery); - #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); inline int acpi_battery_present(struct acpi_battery *battery) @@ -186,9 +184,6 @@ static int acpi_battery_get_property(struct power_supply *psy, int ret = 0; struct acpi_battery *battery = to_acpi_battery(psy); - if (acpi_battery_update(battery)) - return -ENODEV; - if (acpi_battery_present(battery)) { /* run battery update only if it is present */ acpi_battery_get_state(battery); -- cgit v1.2.2 From 5acdb1af907d5908b4942d425c0983f353dd8fc5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 26 Dec 2010 12:47:06 +0100 Subject: ACPI / ACPICA: Disable GPEs during initialization GPEs with corresponding _Lxx/_Exx control methods need to be disabled during initialization in case they have been enabled by the BIOS, so that they don't fire up until they are enabled by acpi_update_gpes(). References: https://bugzilla.kernel.org/show_bug.cgi?id=25412 Signed-off-by: Rafael J. Wysocki Signed-off-by: Len Brown --- drivers/acpi/acpica/evgpeinit.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index 2c7def95f721..4c8dea513b66 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -408,6 +408,9 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle, return_ACPI_STATUS(AE_OK); } + /* Disable the GPE in case it's been enabled already. */ + (void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); + /* * Add the GPE information from above to the gpe_event_info block for * use during dispatch of this GPE. -- cgit v1.2.2