ACPI / ACPICA: Avoid crashing if _PRW is defined for the root object
authorRafael J. Wysocki <rjw@sisk.pl>
Sat, 12 Feb 2011 00:39:15 +0000 (01:39 +0100)
committerRafael J. Wysocki <rjw@sisk.pl>
Sat, 12 Feb 2011 00:39:15 +0000 (01:39 +0100)
Some ACPI BIOSes define _PRW for the root object which causes
acpi_setup_gpe_for_wake() to crash when trying to dereference the
bogus device_node pointer.  Avoid the crash by checking if
wake_device is not the root object before attempting to set up the
"implicit notify" mechanism for it.

The problem was introduced by commit bba63a296ffab20e08d9e8252d2f0d99
(ACPICA: Implicit notify support) that added the wake_device argument
to acpi_setup_gpe_for_wake().

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
drivers/acpi/acpica/evxfgpe.c

index e9562a7..3b20a34 100644 (file)
@@ -212,37 +212,40 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Validate wake_device is of type Device */
-
-       device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device);
-       if (device_node->type != ACPI_TYPE_DEVICE) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
        /* Ensure that we have a valid GPE number */
 
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
-       if (gpe_event_info) {
-               /*
-                * If there is no method or handler for this GPE, then the
-                * wake_device will be notified whenever this GPE fires (aka
-                * "implicit notify") Note: The GPE is assumed to be
-                * level-triggered (for windows compatibility).
-                */
-               if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
-                   ACPI_GPE_DISPATCH_NONE) {
-                       gpe_event_info->flags =
-                           (ACPI_GPE_DISPATCH_NOTIFY |
-                            ACPI_GPE_LEVEL_TRIGGERED);
-                       gpe_event_info->dispatch.device_node = device_node;
-               }
+       if (!gpe_event_info) {
+               goto unlock_and_exit;
+       }
+
+       /*
+        * If there is no method or handler for this GPE, then the
+        * wake_device will be notified whenever this GPE fires (aka
+        * "implicit notify") Note: The GPE is assumed to be
+        * level-triggered (for windows compatibility).
+        */
+       if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+             ACPI_GPE_DISPATCH_NONE) && (wake_device != ACPI_ROOT_OBJECT)) {
 
-               gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
-               status = AE_OK;
+               /* Validate wake_device is of type Device */
+
+               device_node = ACPI_CAST_PTR(struct acpi_namespace_node,
+                                           wake_device);
+               if (device_node->type != ACPI_TYPE_DEVICE) {
+                       goto unlock_and_exit;
+               }
+               gpe_event_info->flags = (ACPI_GPE_DISPATCH_NOTIFY |
+                                        ACPI_GPE_LEVEL_TRIGGERED);
+               gpe_event_info->dispatch.device_node = device_node;
        }
 
+       gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+       status = AE_OK;
+
+ unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }