Kyle McMartin 7b2f649
 drivers/acpi/acpica/aclocal.h    |    7 +--
Kyle McMartin 7b2f649
 drivers/acpi/acpica/evgpe.c      |   75 +++++++++++++++-----------------
Kyle McMartin 7b2f649
 drivers/acpi/acpica/evgpeinit.c  |   11 +----
Kyle McMartin 7b2f649
 drivers/acpi/acpica/evgpeutil.c  |    5 +-
Kyle McMartin 7b2f649
 drivers/acpi/acpica/evxface.c    |   23 +++++-----
Kyle McMartin 7b2f649
 drivers/acpi/ec.c                |    2 +-
Kyle McMartin 7b2f649
 drivers/acpi/pci_bind.c          |   86 ++++++++++++++++++++++++++++++++++++++
Kyle McMartin 7b2f649
 drivers/acpi/sleep.c             |    2 +-
Kyle McMartin 7b2f649
 drivers/char/ipmi/ipmi_si_intf.c |    2 +-
Kyle McMartin 7b2f649
 include/acpi/acpixf.h            |    3 +-
Kyle McMartin 7b2f649
 10 files changed, 143 insertions(+), 73 deletions(-)
Kyle McMartin 7b2f649
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
Kyle McMartin 7b2f649
index 2ceb0c0..3663362 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/acpica/aclocal.h
Kyle McMartin 7b2f649
+++ b/drivers/acpi/acpica/aclocal.h
Kyle McMartin 7b2f649
@@ -406,17 +406,16 @@ struct acpi_predefined_data {
Matthew Garrett 037ab21
  *
Matthew Garrett 037ab21
  ****************************************************************************/
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-/* Dispatch info for each GPE -- either a method or handler, cannot be both */
Matthew Garrett 037ab21
+/* Dispatch info for each GPE */
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 struct acpi_handler_info {
Matthew Garrett 037ab21
 	acpi_event_handler address;	/* Address of handler, if any */
Matthew Garrett 037ab21
 	void *context;		/* Context to be passed to handler */
Matthew Garrett 037ab21
-	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
Matthew Garrett 037ab21
 	u8 orig_flags;		/* Original misc info about this GPE */
Kyle McMartin 7b2f649
 	u8 orig_enabled;	/* Set if the GPE was originally enabled */
Matthew Garrett 037ab21
 };
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-union acpi_gpe_dispatch_info {
Matthew Garrett 037ab21
+struct acpi_gpe_dispatch_info {
Matthew Garrett 037ab21
 	struct acpi_namespace_node *method_node;	/* Method node for this GPE level */
Matthew Garrett 037ab21
 	struct acpi_handler_info *handler;
Matthew Garrett 037ab21
 };
Kyle McMartin 7b2f649
@@ -426,7 +425,7 @@ union acpi_gpe_dispatch_info {
Matthew Garrett 037ab21
  * NOTE: Important to keep this struct as small as possible.
Matthew Garrett 037ab21
  */
Matthew Garrett 037ab21
 struct acpi_gpe_event_info {
Matthew Garrett 037ab21
-	union acpi_gpe_dispatch_info dispatch;	/* Either Method or Handler */
Matthew Garrett 037ab21
+	struct acpi_gpe_dispatch_info dispatch;
Matthew Garrett 037ab21
 	struct acpi_gpe_register_info *register_info;	/* Backpointer to register info */
Matthew Garrett 037ab21
 	u8 flags;		/* Misc info about this GPE */
Matthew Garrett 037ab21
 	u8 gpe_number;		/* This GPE */
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
Kyle McMartin 7b2f649
index f226eac..c4b1c4c 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/acpica/evgpe.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/acpica/evgpe.c
Kyle McMartin 7b2f649
@@ -474,9 +474,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
Matthew Garrett 037ab21
 	 * Must check for control method type dispatch one more time to avoid a
Matthew Garrett 037ab21
 	 * race with ev_gpe_install_handler
Matthew Garrett 037ab21
 	 */
Matthew Garrett 037ab21
-	if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
Matthew Garrett 037ab21
-	    ACPI_GPE_DISPATCH_METHOD) {
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
+	if (local_gpe_event_info.flags & ACPI_GPE_DISPATCH_METHOD) {
Matthew Garrett 037ab21
 		/* Allocate the evaluation information block */
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
Kyle McMartin 7b2f649
@@ -575,41 +573,15 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
Matthew Garrett 037ab21
 	}
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	/*
Matthew Garrett 037ab21
-	 * Dispatch the GPE to either an installed handler, or the control method
Matthew Garrett 037ab21
-	 * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
Matthew Garrett 037ab21
-	 * it and do not attempt to run the method. If there is neither a handler
Matthew Garrett 037ab21
-	 * nor a method, we disable this GPE to prevent further such pointless
Matthew Garrett 037ab21
-	 * events from firing.
Matthew Garrett 037ab21
+	 * Dispatch the GPE to either any installed handler or control
Matthew Garrett 037ab21
+	 * method associated with this GPE (_Lxx or _Exx). We invoke
Matthew Garrett 037ab21
+	 * the method first in case it has side effects that would be
Matthew Garrett 037ab21
+	 * interfered with if the handler has already altered hardware
Matthew Garrett 037ab21
+	 * state. If there is neither a handler nor a method, we
Matthew Garrett 037ab21
+	 * disable this GPE to prevent further such pointless events
Matthew Garrett 037ab21
+	 * from firing.
Matthew Garrett 037ab21
 	 */
Matthew Garrett 037ab21
-	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
Matthew Garrett 037ab21
-	case ACPI_GPE_DISPATCH_HANDLER:
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-		/*
Matthew Garrett 037ab21
-		 * Invoke the installed handler (at interrupt level)
Matthew Garrett 037ab21
-		 * Ignore return status for now.
Matthew Garrett 037ab21
-		 * TBD: leave GPE disabled on error?
Matthew Garrett 037ab21
-		 */
Matthew Garrett 037ab21
-		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
Matthew Garrett 037ab21
-								dispatch.
Matthew Garrett 037ab21
-								handler->
Matthew Garrett 037ab21
-								context);
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-		/* It is now safe to clear level-triggered events. */
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
Matthew Garrett 037ab21
-		    ACPI_GPE_LEVEL_TRIGGERED) {
Matthew Garrett 037ab21
-			status = acpi_hw_clear_gpe(gpe_event_info);
Matthew Garrett 037ab21
-			if (ACPI_FAILURE(status)) {
Matthew Garrett 037ab21
-				ACPI_EXCEPTION((AE_INFO, status,
Matthew Garrett 037ab21
-					"Unable to clear GPE[0x%2X]",
Matthew Garrett 037ab21
-						gpe_number));
Matthew Garrett 037ab21
-				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
Matthew Garrett 037ab21
-			}
Matthew Garrett 037ab21
-		}
Matthew Garrett 037ab21
-		break;
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-	case ACPI_GPE_DISPATCH_METHOD:
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
+	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
Matthew Garrett 037ab21
 		/*
Matthew Garrett 037ab21
 		 * Disable the GPE, so it doesn't keep firing before the method has a
Matthew Garrett 037ab21
 		 * chance to run (it runs asynchronously with interrupts enabled).
Kyle McMartin 7b2f649
@@ -634,10 +606,34 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
Matthew Garrett 037ab21
 					"Unable to queue handler for GPE[0x%2X] - event disabled",
Matthew Garrett 037ab21
 					gpe_number));
Matthew Garrett 037ab21
 		}
Matthew Garrett 037ab21
-		break;
Matthew Garrett 037ab21
+	}
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	default:
Matthew Garrett 037ab21
+	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
+		/*
Matthew Garrett 037ab21
+		 * Invoke the installed handler (at interrupt level)
Matthew Garrett 037ab21
+		 * Ignore return status for now.
Matthew Garrett 037ab21
+		 * TBD: leave GPE disabled on error?
Matthew Garrett 037ab21
+		 */
Matthew Garrett 037ab21
+		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
Matthew Garrett 037ab21
+								dispatch.
Matthew Garrett 037ab21
+								handler->
Matthew Garrett 037ab21
+								context);
Kyle McMartin 7b2f649
 
Matthew Garrett 037ab21
+		/* It is now safe to clear level-triggered events. */
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
Matthew Garrett 037ab21
+		    ACPI_GPE_LEVEL_TRIGGERED) {
Matthew Garrett 037ab21
+			status = acpi_hw_clear_gpe(gpe_event_info);
Matthew Garrett 037ab21
+			if (ACPI_FAILURE(status)) {
Matthew Garrett 037ab21
+				ACPI_EXCEPTION((AE_INFO, status,
Matthew Garrett 037ab21
+					"Unable to clear GPE[0x%2X]",
Matthew Garrett 037ab21
+						gpe_number));
Matthew Garrett 037ab21
+				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
Matthew Garrett 037ab21
+			}
Matthew Garrett 037ab21
+		}
Matthew Garrett 037ab21
+	}
Kyle McMartin 7b2f649
+
Matthew Garrett 037ab21
+	if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
Matthew Garrett 037ab21
 		/*
Matthew Garrett 037ab21
 		 * No handler or method to run!
Matthew Garrett 037ab21
 		 * 03/2010: This case should no longer be possible. We will not allow
Kyle McMartin 7b2f649
@@ -658,7 +654,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
Matthew Garrett 037ab21
 					gpe_number));
Matthew Garrett 037ab21
 			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
Matthew Garrett 037ab21
 		}
Matthew Garrett 037ab21
-		break;
Matthew Garrett 037ab21
 	}
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	return_UINT32(ACPI_INTERRUPT_HANDLED);
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
Kyle McMartin 7b2f649
index 2c7def9..9915b52 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/acpica/evgpeinit.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/acpica/evgpeinit.c
Kyle McMartin 7b2f649
@@ -386,16 +386,7 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
Matthew Garrett 037ab21
 		return_ACPI_STATUS(AE_OK);
Matthew Garrett 037ab21
 	}
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
Matthew Garrett 037ab21
-	    ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-		/* If there is already a handler, ignore this GPE method */
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-		return_ACPI_STATUS(AE_OK);
Matthew Garrett 037ab21
-	}
Matthew Garrett 037ab21
-
Matthew Garrett 037ab21
-	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
Matthew Garrett 037ab21
-	    ACPI_GPE_DISPATCH_METHOD) {
Matthew Garrett 037ab21
+	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
Matthew Garrett 037ab21
 		/*
Matthew Garrett 037ab21
 		 * If there is already a method, ignore this method. But check
Matthew Garrett 037ab21
 		 * for a type mismatch (if both the _Lxx AND _Exx exist)
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
Kyle McMartin 7b2f649
index 19a0e51..434ad1b 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/acpica/evgpeutil.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/acpica/evgpeutil.c
Kyle McMartin 7b2f649
@@ -323,12 +323,11 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
Matthew Garrett 037ab21
 								 ACPI_GPE_REGISTER_WIDTH)
Matthew Garrett 037ab21
 								+ j];
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-			if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
Matthew Garrett 037ab21
-			    ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
+			if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
 				ACPI_FREE(gpe_event_info->dispatch.handler);
Matthew Garrett 037ab21
 				gpe_event_info->dispatch.handler = NULL;
Matthew Garrett 037ab21
 				gpe_event_info->flags &=
Matthew Garrett 037ab21
-				    ~ACPI_GPE_DISPATCH_MASK;
Matthew Garrett 037ab21
+				    ~ACPI_GPE_DISPATCH_HANDLER;
Matthew Garrett 037ab21
 			}
Matthew Garrett 037ab21
 		}
Matthew Garrett 037ab21
 	}
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
Kyle McMartin 7b2f649
index 36af222..b097136 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/acpica/evxface.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/acpica/evxface.c
Kyle McMartin 7b2f649
@@ -662,6 +662,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
Matthew Garrett 037ab21
  *                                edge- or level-triggered interrupt.
Matthew Garrett 037ab21
  *              Address         - Address of the handler
Matthew Garrett 037ab21
  *              Context         - Value passed to the handler on each GPE
Matthew Garrett 037ab21
+ *		keep_method	- Whether the existing method should be
Matthew Garrett 037ab21
+ *				  displaced or kept
Matthew Garrett 037ab21
  *
Matthew Garrett 037ab21
  * RETURN:      Status
Matthew Garrett 037ab21
  *
Kyle McMartin 7b2f649
@@ -671,7 +673,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
Matthew Garrett 037ab21
 acpi_status
Matthew Garrett 037ab21
 acpi_install_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 			 u32 gpe_number,
Matthew Garrett 037ab21
-			 u32 type, acpi_event_handler address, void *context)
Matthew Garrett 037ab21
+			 u32 type, acpi_event_handler address, void *context,
Matthew Garrett 037ab21
+			 bool keep_method)
Matthew Garrett 037ab21
 {
Matthew Garrett 037ab21
 	struct acpi_gpe_event_info *gpe_event_info;
Matthew Garrett 037ab21
 	struct acpi_handler_info *handler;
Kyle McMartin 7b2f649
@@ -711,8 +714,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	/* Make sure that there isn't a handler there already */
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
Matthew Garrett 037ab21
-	    ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
+	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
 		status = AE_ALREADY_EXISTS;
Matthew Garrett 037ab21
 		goto free_and_exit;
Matthew Garrett 037ab21
 	}
Kyle McMartin 7b2f649
@@ -721,7 +723,6 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	handler->address = address;
Matthew Garrett 037ab21
 	handler->context = context;
Matthew Garrett 037ab21
-	handler->method_node = gpe_event_info->dispatch.method_node;
Matthew Garrett 037ab21
 	handler->orig_flags = gpe_event_info->flags &
Matthew Garrett 037ab21
 			(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
Matthew Garrett 037ab21
 
Kyle McMartin 7b2f649
@@ -732,7 +733,7 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 	 */
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
Kyle McMartin 7b2f649
-	    && gpe_event_info->runtime_count) {
Kyle McMartin 7b2f649
+	    && gpe_event_info->runtime_count && !keep_method) {
Kyle McMartin 7b2f649
 		handler->orig_enabled = 1;
Matthew Garrett 037ab21
 		(void)acpi_raw_disable_gpe(gpe_event_info);
Kyle McMartin 7b2f649
 	}
Kyle McMartin 7b2f649
@@ -741,10 +742,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	gpe_event_info->dispatch.handler = handler;
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	/* Setup up dispatch flags to indicate handler (vs. method) */
Matthew Garrett 037ab21
+	if (!keep_method)
Matthew Garrett 037ab21
+		gpe_event_info->flags &=
Matthew Garrett 037ab21
+			~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	gpe_event_info->flags &=
Matthew Garrett 037ab21
-	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
Matthew Garrett 037ab21
 	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
Kyle McMartin 7b2f649
@@ -813,8 +814,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	/* Make sure that a handler is indeed installed */
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
Matthew Garrett 037ab21
-	    ACPI_GPE_DISPATCH_HANDLER) {
Matthew Garrett 037ab21
+	if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER)) {
Matthew Garrett 037ab21
 		status = AE_NOT_EXIST;
Matthew Garrett 037ab21
 		goto unlock_and_exit;
Matthew Garrett 037ab21
 	}
Kyle McMartin 7b2f649
@@ -830,9 +830,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	handler = gpe_event_info->dispatch.handler;
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	/* Restore Method node (if any), set dispatch flags */
Matthew Garrett 037ab21
+	/* Set dispatch flags */
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
-	gpe_event_info->dispatch.method_node = handler->method_node;
Matthew Garrett 037ab21
 	gpe_event_info->flags &=
Matthew Garrett 037ab21
 		~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
Matthew Garrett 037ab21
 	gpe_event_info->flags |= handler->orig_flags;
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
Kyle McMartin 7b2f649
index 372ff80..9a39f82 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/ec.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/ec.c
Kyle McMartin 7b2f649
@@ -740,7 +740,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
Matthew Garrett 037ab21
 		return 0;
Matthew Garrett 037ab21
 	status = acpi_install_gpe_handler(NULL, ec->gpe,
Matthew Garrett 037ab21
 				  ACPI_GPE_EDGE_TRIGGERED,
Matthew Garrett 037ab21
-				  &acpi_ec_gpe_handler, ec);
Matthew Garrett 037ab21
+				  &acpi_ec_gpe_handler, ec, false);
Matthew Garrett 037ab21
 	if (ACPI_FAILURE(status))
Matthew Garrett 037ab21
 		return -ENODEV;
Matthew Garrett 037ab21
 
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
Kyle McMartin 7b2f649
index 2ef0409..8b3cc6a 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/pci_bind.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/pci_bind.c
Matthew Garrett 037ab21
@@ -28,6 +28,7 @@
Matthew Garrett 037ab21
 #include <linux/pci.h>
Matthew Garrett 037ab21
 #include <linux/pci-acpi.h>
Matthew Garrett 037ab21
 #include <linux/acpi.h>
Matthew Garrett 037ab21
+#include <linux/list.h>
Matthew Garrett 037ab21
 #include <linux/pm_runtime.h>
Matthew Garrett 037ab21
 #include <acpi/acpi_bus.h>
Matthew Garrett 037ab21
 #include <acpi/acpi_drivers.h>
Matthew Garrett 037ab21
@@ -35,6 +36,43 @@
Matthew Garrett 037ab21
 #define _COMPONENT		ACPI_PCI_COMPONENT
Matthew Garrett 037ab21
 ACPI_MODULE_NAME("pci_bind");
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
+static LIST_HEAD(acpi_pci_gpe_devs);
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+struct pci_gpe_dev {
Matthew Garrett 037ab21
+	struct list_head node;
Matthew Garrett 037ab21
+	struct pci_dev *dev;
Matthew Garrett 037ab21
+	acpi_handle gpe_device;
Matthew Garrett 037ab21
+	int gpe_number;
Matthew Garrett 037ab21
+	struct work_struct work;
Matthew Garrett 037ab21
+};
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+static void acpi_pci_wake_handler_work(struct work_struct *work)
Matthew Garrett 037ab21
+{
Matthew Garrett 037ab21
+	struct pci_gpe_dev *gpe_dev = container_of(work, struct pci_gpe_dev,
Matthew Garrett 037ab21
+						   work);
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+	pci_check_pme_status(gpe_dev->dev);
Matthew Garrett 037ab21
+	pm_runtime_resume(&gpe_dev->dev->dev);
Matthew Garrett 037ab21
+	pci_wakeup_event(gpe_dev->dev);
Matthew Garrett 037ab21
+	if (gpe_dev->dev->subordinate)
Matthew Garrett 037ab21
+		pci_pme_wakeup_bus(gpe_dev->dev->subordinate);
Matthew Garrett 037ab21
+}
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+static u32 acpi_pci_wake_handler(void *data)
Matthew Garrett 037ab21
+{
Matthew Garrett 037ab21
+	long gpe_number = (long) data;
Matthew Garrett 037ab21
+	struct pci_gpe_dev *gpe_dev;
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+	list_for_each_entry(gpe_dev, &acpi_pci_gpe_devs, node) {
Matthew Garrett 037ab21
+		if (gpe_number != gpe_dev->gpe_number)
Matthew Garrett 037ab21
+			continue;
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+		schedule_work(&gpe_dev->work);
Matthew Garrett 037ab21
+	}
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+	return ACPI_INTERRUPT_HANDLED;
Matthew Garrett 037ab21
+}
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
 static int acpi_pci_unbind(struct acpi_device *device)
Matthew Garrett 037ab21
 {
Matthew Garrett 037ab21
 	struct pci_dev *dev;
Kyle McMartin 7b2f649
@@ -43,6 +81,30 @@ static int acpi_pci_unbind(struct acpi_device *device)
Matthew Garrett 037ab21
 	if (!dev)
Matthew Garrett 037ab21
 		goto out;
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
+	if (device->wakeup.flags.valid) {
Matthew Garrett 037ab21
+		struct pci_gpe_dev *gpe_dev;
Matthew Garrett 037ab21
+		struct pci_gpe_dev *tmp;
Matthew Garrett 037ab21
+		int gpe_count = 0;
Matthew Garrett 037ab21
+		int gpe_number = device->wakeup.gpe_number;
Matthew Garrett 037ab21
+		acpi_handle gpe_device = device->wakeup.gpe_device;
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+		list_for_each_entry_safe(gpe_dev, tmp, &acpi_pci_gpe_devs, node) {
Matthew Garrett 037ab21
+			if (gpe_dev->dev == dev) {
Matthew Garrett 037ab21
+				flush_work(&gpe_dev->work);
Matthew Garrett 037ab21
+				list_del(&gpe_dev->node);
Matthew Garrett 037ab21
+				kfree(gpe_dev);
Matthew Garrett 037ab21
+			} else if (gpe_dev->gpe_number == gpe_number &&
Matthew Garrett 037ab21
+				   gpe_dev->gpe_device == gpe_device) {
Matthew Garrett 037ab21
+				gpe_count++;
Matthew Garrett 037ab21
+			}
Matthew Garrett 037ab21
+		}
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+		if (gpe_count == 0) {
Matthew Garrett 037ab21
+			acpi_remove_gpe_handler(gpe_device, gpe_number,
Matthew Garrett 037ab21
+						&acpi_pci_wake_handler);
Matthew Garrett 037ab21
+		}
Matthew Garrett 037ab21
+	}
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
 	device_set_run_wake(&dev->dev, false);
Matthew Garrett 037ab21
 	pci_acpi_remove_pm_notifier(device);
Matthew Garrett 037ab21
 
Kyle McMartin 7b2f649
@@ -71,6 +133,30 @@ static int acpi_pci_bind(struct acpi_device *device)
Matthew Garrett 037ab21
 		return 0;
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 	pci_acpi_add_pm_notifier(device, dev);
Matthew Garrett 037ab21
+	if (device->wakeup.flags.valid) {
Matthew Garrett 037ab21
+		struct pci_gpe_dev *gpe_dev;
Matthew Garrett 037ab21
+		acpi_handle gpe_device = device->wakeup.gpe_device;
Matthew Garrett 037ab21
+		long gpe_number = device->wakeup.gpe_number;
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+		gpe_dev = kmalloc(sizeof(struct pci_gpe_dev), GFP_KERNEL);
Matthew Garrett 037ab21
+		if (gpe_dev) {
Matthew Garrett 037ab21
+			gpe_dev->dev = dev;
Matthew Garrett 037ab21
+			gpe_dev->gpe_device = gpe_device;
Matthew Garrett 037ab21
+			gpe_dev->gpe_number = gpe_number;
Matthew Garrett 037ab21
+			INIT_WORK(&gpe_dev->work, acpi_pci_wake_handler_work);
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
+			acpi_install_gpe_handler(gpe_device, gpe_number,
Matthew Garrett 037ab21
+						 ACPI_GPE_LEVEL_TRIGGERED,
Matthew Garrett 037ab21
+						 &acpi_pci_wake_handler,
Matthew Garrett 037ab21
+						 (void *)gpe_number,
Matthew Garrett 037ab21
+						 true);
Matthew Garrett 037ab21
+			acpi_gpe_can_wake(device->wakeup.gpe_device,
Matthew Garrett 037ab21
+					  device->wakeup.gpe_number);
Matthew Garrett 037ab21
+			device->wakeup.flags.run_wake = 1;
Matthew Garrett 037ab21
+			list_add_tail(&gpe_dev->node, &acpi_pci_gpe_devs);
Matthew Garrett 037ab21
+		}
Matthew Garrett 037ab21
+	}
Matthew Garrett 037ab21
+
Matthew Garrett 037ab21
 	if (device->wakeup.flags.run_wake)
Matthew Garrett 037ab21
 		device_set_run_wake(&dev->dev, true);
Matthew Garrett 037ab21
 
Kyle McMartin 7b2f649
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
Kyle McMartin 7b2f649
index 721d93b..b0ddef6 100644
Kyle McMartin 7b2f649
--- a/drivers/acpi/sleep.c
Kyle McMartin 7b2f649
+++ b/drivers/acpi/sleep.c
Kyle McMartin 7b2f649
@@ -643,7 +643,7 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p)
Kyle McMartin 7b2f649
 			if (acpi_target_sleep_state != ACPI_STATE_S0 ||
Kyle McMartin 7b2f649
 			    status != AE_NOT_FOUND)
Kyle McMartin 7b2f649
 				d_max = d_min;
Matthew Garrett 037ab21
-		} else if (d_max < d_min) {
Matthew Garrett 037ab21
+		} else if (ACPI_SUCCESS(status) && d_max < d_min) {
Matthew Garrett 037ab21
 			/* Warn the user of the broken DSDT */
Matthew Garrett 037ab21
 			printk(KERN_WARNING "ACPI: Wrong value from %s\n",
Matthew Garrett 037ab21
 				acpi_method);
Kyle McMartin 7b2f649
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
Kyle McMartin 7b2f649
index 035da9e..62a48b2 100644
Kyle McMartin 7b2f649
--- a/drivers/char/ipmi/ipmi_si_intf.c
Kyle McMartin 7b2f649
+++ b/drivers/char/ipmi/ipmi_si_intf.c
Kyle McMartin 7b2f649
@@ -1970,7 +1970,7 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
Matthew Garrett 037ab21
 					  info->irq,
Matthew Garrett 037ab21
 					  ACPI_GPE_LEVEL_TRIGGERED,
Matthew Garrett 037ab21
 					  &ipmi_acpi_gpe,
Matthew Garrett 037ab21
-					  info);
Matthew Garrett 037ab21
+					  info, false);
Matthew Garrett 037ab21
 	if (status != AE_OK) {
Matthew Garrett 037ab21
 		dev_warn(info->dev, "%s unable to claim ACPI GPE %d,"
Matthew Garrett 037ab21
 			 " running polled\n", DEVICE_NAME, info->irq);
Kyle McMartin 7b2f649
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
Kyle McMartin 7b2f649
index 53b7cfd..740eb7e 100644
Kyle McMartin 7b2f649
--- a/include/acpi/acpixf.h
Kyle McMartin 7b2f649
+++ b/include/acpi/acpixf.h
Kyle McMartin 7b2f649
@@ -258,7 +258,8 @@ acpi_remove_address_space_handler(acpi_handle device,
Matthew Garrett 037ab21
 acpi_status
Matthew Garrett 037ab21
 acpi_install_gpe_handler(acpi_handle gpe_device,
Matthew Garrett 037ab21
 			 u32 gpe_number,
Matthew Garrett 037ab21
-			 u32 type, acpi_event_handler address, void *context);
Matthew Garrett 037ab21
+			 u32 type, acpi_event_handler address, void *context,
Matthew Garrett 037ab21
+			 bool keep_method);
Matthew Garrett 037ab21
 
Matthew Garrett 037ab21
 acpi_status
Matthew Garrett 037ab21
 acpi_remove_gpe_handler(acpi_handle gpe_device,