forked from rpms/kernel
		
	- linux-2.6-enable-more-pci-autosuspend.patch: Enable more PCI autosuspend
This commit is contained in:
		
							parent
							
								
									72c4be84a6
								
							
						
					
					
						commit
						037ab21c45
					
				| @ -715,6 +715,7 @@ Patch12200: linux-2.6-bluetooth-autosuspend.patch | ||||
| Patch12201: linux-2.6-uvc-autosuspend.patch | ||||
| Patch12202: linux-2.6-qcserial-autosuspend.patch | ||||
| Patch12203: linux-2.6-usb-pci-autosuspend.patch | ||||
| Patch12204: linux-2.6-enable-more-pci-autosuspend.patch | ||||
| 
 | ||||
| # PCI patches to fix problems with _CRS | ||||
| Patch12221: pci-v2-1-4-resources-ensure-alignment-callback-doesn-t-allocate-below-available-start.patch | ||||
| @ -1322,6 +1323,7 @@ ApplyPatch linux-2.6-bluetooth-autosuspend.patch | ||||
| ApplyPatch linux-2.6-uvc-autosuspend.patch | ||||
| ApplyPatch linux-2.6-qcserial-autosuspend.patch | ||||
| ApplyPatch linux-2.6-usb-pci-autosuspend.patch | ||||
| ApplyPatch linux-2.6-enable-more-pci-autosuspend.patch | ||||
| 
 | ||||
| # PCI patches to fix problems with _CRS | ||||
| # ( from https://bugzilla.kernel.org/show_bug.cgi?id=16228#c49 ) | ||||
| @ -1940,6 +1942,9 @@ fi | ||||
| #                 ||     || | ||||
| 
 | ||||
| %changelog | ||||
| * Mon Oct 11 2010 Matthew Garrett <mjg@redhat.com> 2.6.36-0.35.rc7.git1 | ||||
| - linux-2.6-enable-more-pci-autosuspend.patch: Enable more PCI autosuspend | ||||
| 
 | ||||
| * Wed Oct 06 2010 Kyle McMartin <kyle@redhat.com> 2.6.36-0.35.rc7.git0 | ||||
| - Linux 2.6.36-rc7 upstream. | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										560
									
								
								linux-2.6-enable-more-pci-autosuspend.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										560
									
								
								linux-2.6-enable-more-pci-autosuspend.patch
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,560 @@ | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/acpica/aclocal.h.mjg linux-2.6.35.x86_64/drivers/acpi/acpica/aclocal.h
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/acpica/aclocal.h.mjg	2010-10-04 13:52:05.086789354 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/acpica/aclocal.h	2010-10-04 13:52:50.948801001 -0400
 | ||||
| @@ -406,16 +406,15 @@ struct acpi_predefined_data {
 | ||||
|   * | ||||
|   ****************************************************************************/ | ||||
|   | ||||
| -/* Dispatch info for each GPE -- either a method or handler, cannot be both */
 | ||||
| +/* Dispatch info for each GPE */
 | ||||
|   | ||||
|  struct acpi_handler_info { | ||||
|  	acpi_event_handler address;	/* Address of handler, if any */ | ||||
|  	void *context;		/* Context to be passed to handler */ | ||||
| -	struct acpi_namespace_node *method_node;	/* Method node for this GPE level (saved) */
 | ||||
|  	u8 orig_flags;		/* Original misc info about this GPE */ | ||||
|  }; | ||||
|   | ||||
| -union acpi_gpe_dispatch_info {
 | ||||
| +struct acpi_gpe_dispatch_info {
 | ||||
|  	struct acpi_namespace_node *method_node;	/* Method node for this GPE level */ | ||||
|  	struct acpi_handler_info *handler; | ||||
|  }; | ||||
| @@ -425,7 +424,7 @@ union acpi_gpe_dispatch_info {
 | ||||
|   * NOTE: Important to keep this struct as small as possible. | ||||
|   */ | ||||
|  struct acpi_gpe_event_info { | ||||
| -	union acpi_gpe_dispatch_info dispatch;	/* Either Method or Handler */
 | ||||
| +	struct acpi_gpe_dispatch_info dispatch;
 | ||||
|  	struct acpi_gpe_register_info *register_info;	/* Backpointer to register info */ | ||||
|  	u8 flags;		/* Misc info about this GPE */ | ||||
|  	u8 gpe_number;		/* This GPE */ | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/acpica/evgpe.c.mjg linux-2.6.35.x86_64/drivers/acpi/acpica/evgpe.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/acpica/evgpe.c.mjg	2010-10-04 13:52:05.088789399 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/acpica/evgpe.c	2010-10-04 13:52:50.950801045 -0400
 | ||||
| @@ -474,9 +474,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_as
 | ||||
|  	 * Must check for control method type dispatch one more time to avoid a | ||||
|  	 * race with ev_gpe_install_handler | ||||
|  	 */ | ||||
| -	if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
 | ||||
| -	    ACPI_GPE_DISPATCH_METHOD) {
 | ||||
| -
 | ||||
| +	if (local_gpe_event_info.flags & ACPI_GPE_DISPATCH_METHOD) {
 | ||||
|  		/* Allocate the evaluation information block */ | ||||
|   | ||||
|  		info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); | ||||
| @@ -575,41 +573,15 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve
 | ||||
|  	} | ||||
|   | ||||
|  	/* | ||||
| -	 * Dispatch the GPE to either an installed handler, or the control method
 | ||||
| -	 * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
 | ||||
| -	 * it and do not attempt to run the method. If there is neither a handler
 | ||||
| -	 * nor a method, we disable this GPE to prevent further such pointless
 | ||||
| -	 * events from firing.
 | ||||
| +	 * Dispatch the GPE to either any installed handler or control
 | ||||
| +	 * method associated with this GPE (_Lxx or _Exx). We invoke
 | ||||
| +	 * the method first in case it has side effects that would be
 | ||||
| +	 * interfered with if the handler has already altered hardware
 | ||||
| +	 * state. If there is neither a handler nor a method, we
 | ||||
| +	 * disable this GPE to prevent further such pointless events
 | ||||
| +	 * from firing.
 | ||||
|  	 */ | ||||
| -	switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
 | ||||
| -	case ACPI_GPE_DISPATCH_HANDLER:
 | ||||
| -
 | ||||
| -		/*
 | ||||
| -		 * Invoke the installed handler (at interrupt level)
 | ||||
| -		 * Ignore return status for now.
 | ||||
| -		 * TBD: leave GPE disabled on error?
 | ||||
| -		 */
 | ||||
| -		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
 | ||||
| -								dispatch.
 | ||||
| -								handler->
 | ||||
| -								context);
 | ||||
| -
 | ||||
| -		/* It is now safe to clear level-triggered events. */
 | ||||
| -
 | ||||
| -		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
 | ||||
| -		    ACPI_GPE_LEVEL_TRIGGERED) {
 | ||||
| -			status = acpi_hw_clear_gpe(gpe_event_info);
 | ||||
| -			if (ACPI_FAILURE(status)) {
 | ||||
| -				ACPI_EXCEPTION((AE_INFO, status,
 | ||||
| -					"Unable to clear GPE[0x%2X]",
 | ||||
| -						gpe_number));
 | ||||
| -				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
 | ||||
| -			}
 | ||||
| -		}
 | ||||
| -		break;
 | ||||
| -
 | ||||
| -	case ACPI_GPE_DISPATCH_METHOD:
 | ||||
| -
 | ||||
| +	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
 | ||||
|  		/* | ||||
|  		 * Disable the GPE, so it doesn't keep firing before the method has a | ||||
|  		 * chance to run (it runs asynchronously with interrupts enabled). | ||||
| @@ -634,10 +606,34 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve
 | ||||
|  					"Unable to queue handler for GPE[0x%2X] - event disabled", | ||||
|  					gpe_number)); | ||||
|  		} | ||||
| -		break;
 | ||||
| +	}
 | ||||
|   | ||||
| -	default:
 | ||||
| +	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
| +		/*
 | ||||
| +		 * Invoke the installed handler (at interrupt level)
 | ||||
| +		 * Ignore return status for now.
 | ||||
| +		 * TBD: leave GPE disabled on error?
 | ||||
| +		 */
 | ||||
| +		(void)gpe_event_info->dispatch.handler->address(gpe_event_info->
 | ||||
| +								dispatch.
 | ||||
| +								handler->
 | ||||
| +								context);
 | ||||
| +
 | ||||
| +		/* It is now safe to clear level-triggered events. */
 | ||||
| +
 | ||||
| +		if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
 | ||||
| +		    ACPI_GPE_LEVEL_TRIGGERED) {
 | ||||
| +			status = acpi_hw_clear_gpe(gpe_event_info);
 | ||||
| +			if (ACPI_FAILURE(status)) {
 | ||||
| +				ACPI_EXCEPTION((AE_INFO, status,
 | ||||
| +					"Unable to clear GPE[0x%2X]",
 | ||||
| +						gpe_number));
 | ||||
| +				return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
 | ||||
| +			}
 | ||||
| +		}
 | ||||
| +	}
 | ||||
|   | ||||
| +	if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
 | ||||
|  		/* | ||||
|  		 * No handler or method to run! | ||||
|  		 * 03/2010: This case should no longer be possible. We will not allow | ||||
| @@ -658,7 +654,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_eve
 | ||||
|  					gpe_number)); | ||||
|  			return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); | ||||
|  		} | ||||
| -		break;
 | ||||
|  	} | ||||
|   | ||||
|  	return_UINT32(ACPI_INTERRUPT_HANDLED); | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeinit.c.mjg linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeinit.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeinit.c.mjg	2010-10-04 13:52:05.089789421 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeinit.c	2010-10-04 13:52:50.951801067 -0400
 | ||||
| @@ -392,16 +392,7 @@ acpi_ev_match_gpe_method(acpi_handle obj
 | ||||
|  		return_ACPI_STATUS(AE_OK); | ||||
|  	} | ||||
|   | ||||
| -	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
 | ||||
| -	    ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
| -
 | ||||
| -		/* If there is already a handler, ignore this GPE method */
 | ||||
| -
 | ||||
| -		return_ACPI_STATUS(AE_OK);
 | ||||
| -	}
 | ||||
| -
 | ||||
| -	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
 | ||||
| -	    ACPI_GPE_DISPATCH_METHOD) {
 | ||||
| +	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) {
 | ||||
|  		/* | ||||
|  		 * If there is already a method, ignore this method. But check | ||||
|  		 * for a type mismatch (if both the _Lxx AND _Exx exist) | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeutil.c.mjg linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeutil.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeutil.c.mjg	2010-10-04 13:52:05.090789443 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/acpica/evgpeutil.c	2010-10-04 13:52:50.952801089 -0400
 | ||||
| @@ -323,12 +323,11 @@ acpi_ev_delete_gpe_handlers(struct acpi_
 | ||||
|  								 ACPI_GPE_REGISTER_WIDTH) | ||||
|  								+ j]; | ||||
|   | ||||
| -			if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
 | ||||
| -			    ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
| +			if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
|  				ACPI_FREE(gpe_event_info->dispatch.handler); | ||||
|  				gpe_event_info->dispatch.handler = NULL; | ||||
|  				gpe_event_info->flags &= | ||||
| -				    ~ACPI_GPE_DISPATCH_MASK;
 | ||||
| +				    ~ACPI_GPE_DISPATCH_HANDLER;
 | ||||
|  			} | ||||
|  		} | ||||
|  	} | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/acpica/evxface.c.mjg linux-2.6.35.x86_64/drivers/acpi/acpica/evxface.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/acpica/evxface.c.mjg	2010-10-04 13:52:05.092789487 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/acpica/evxface.c	2010-10-04 13:52:50.954801133 -0400
 | ||||
| @@ -662,6 +662,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_ha
 | ||||
|   *                                edge- or level-triggered interrupt. | ||||
|   *              Address         - Address of the handler | ||||
|   *              Context         - Value passed to the handler on each GPE | ||||
| + *		keep_method	- Whether the existing method should be
 | ||||
| + *				  displaced or kept
 | ||||
|   * | ||||
|   * RETURN:      Status | ||||
|   * | ||||
| @@ -671,7 +673,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_ha
 | ||||
|  acpi_status | ||||
|  acpi_install_gpe_handler(acpi_handle gpe_device, | ||||
|  			 u32 gpe_number, | ||||
| -			 u32 type, acpi_event_handler address, void *context)
 | ||||
| +			 u32 type, acpi_event_handler address, void *context,
 | ||||
| +			 bool keep_method)
 | ||||
|  { | ||||
|  	struct acpi_gpe_event_info *gpe_event_info; | ||||
|  	struct acpi_handler_info *handler; | ||||
| @@ -711,8 +714,7 @@ acpi_install_gpe_handler(acpi_handle gpe
 | ||||
|   | ||||
|  	/* Make sure that there isn't a handler there already */ | ||||
|   | ||||
| -	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
 | ||||
| -	    ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
| +	if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
|  		status = AE_ALREADY_EXISTS; | ||||
|  		goto free_and_exit; | ||||
|  	} | ||||
| @@ -721,7 +723,6 @@ acpi_install_gpe_handler(acpi_handle gpe
 | ||||
|   | ||||
|  	handler->address = address; | ||||
|  	handler->context = context; | ||||
| -	handler->method_node = gpe_event_info->dispatch.method_node;
 | ||||
|  	handler->orig_flags = gpe_event_info->flags & | ||||
|  			(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); | ||||
|   | ||||
| @@ -733,17 +734,17 @@ acpi_install_gpe_handler(acpi_handle gpe
 | ||||
|  	 */ | ||||
|   | ||||
|  	if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD) | ||||
| -	    && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE))
 | ||||
| +	    && !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE) && !keep_method)
 | ||||
|  		(void)acpi_raw_disable_gpe(gpe_event_info); | ||||
|   | ||||
|  	/* Install the handler */ | ||||
|   | ||||
|  	gpe_event_info->dispatch.handler = handler; | ||||
|   | ||||
| -	/* Setup up dispatch flags to indicate handler (vs. method) */
 | ||||
| +	if (!keep_method)
 | ||||
| +		gpe_event_info->flags &=
 | ||||
| +			~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
 | ||||
|   | ||||
| -	gpe_event_info->flags &=
 | ||||
| -	    ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
 | ||||
|  	gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER); | ||||
|   | ||||
|  	acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | ||||
| @@ -812,8 +813,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_
 | ||||
|   | ||||
|  	/* Make sure that a handler is indeed installed */ | ||||
|   | ||||
| -	if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
 | ||||
| -	    ACPI_GPE_DISPATCH_HANDLER) {
 | ||||
| +	if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER)) {
 | ||||
|  		status = AE_NOT_EXIST; | ||||
|  		goto unlock_and_exit; | ||||
|  	} | ||||
| @@ -829,9 +829,8 @@ acpi_remove_gpe_handler(acpi_handle gpe_
 | ||||
|   | ||||
|  	handler = gpe_event_info->dispatch.handler; | ||||
|   | ||||
| -	/* Restore Method node (if any), set dispatch flags */
 | ||||
| +	/* Set dispatch flags */
 | ||||
|   | ||||
| -	gpe_event_info->dispatch.method_node = handler->method_node;
 | ||||
|  	gpe_event_info->flags &= | ||||
|  		~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); | ||||
|  	gpe_event_info->flags |= handler->orig_flags; | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/ec.c.mjg linux-2.6.35.x86_64/drivers/acpi/ec.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/ec.c.mjg	2010-10-04 13:52:05.094789531 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/ec.c	2010-10-04 13:52:50.955801156 -0400
 | ||||
| @@ -746,7 +746,7 @@ static int ec_install_handlers(struct ac
 | ||||
|  		return 0; | ||||
|  	status = acpi_install_gpe_handler(NULL, ec->gpe, | ||||
|  				  ACPI_GPE_EDGE_TRIGGERED, | ||||
| -				  &acpi_ec_gpe_handler, ec);
 | ||||
| +				  &acpi_ec_gpe_handler, ec, false);
 | ||||
|  	if (ACPI_FAILURE(status)) | ||||
|  		return -ENODEV; | ||||
|   | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/pci_bind.c.mjg linux-2.6.35.x86_64/drivers/acpi/pci_bind.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/pci_bind.c.mjg	2010-10-04 13:52:05.102789707 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/pci_bind.c	2010-10-04 13:52:50.962801311 -0400
 | ||||
| @@ -28,6 +28,7 @@
 | ||||
|  #include <linux/pci.h> | ||||
|  #include <linux/pci-acpi.h> | ||||
|  #include <linux/acpi.h> | ||||
| +#include <linux/list.h>
 | ||||
|  #include <linux/pm_runtime.h> | ||||
|  #include <acpi/acpi_bus.h> | ||||
|  #include <acpi/acpi_drivers.h> | ||||
| @@ -35,6 +36,43 @@
 | ||||
|  #define _COMPONENT		ACPI_PCI_COMPONENT | ||||
|  ACPI_MODULE_NAME("pci_bind"); | ||||
|   | ||||
| +static LIST_HEAD(acpi_pci_gpe_devs);
 | ||||
| +
 | ||||
| +struct pci_gpe_dev {
 | ||||
| +	struct list_head node;
 | ||||
| +	struct pci_dev *dev;
 | ||||
| +	acpi_handle gpe_device;
 | ||||
| +	int gpe_number;
 | ||||
| +	struct work_struct work;
 | ||||
| +};
 | ||||
| +
 | ||||
| +static void acpi_pci_wake_handler_work(struct work_struct *work)
 | ||||
| +{
 | ||||
| +	struct pci_gpe_dev *gpe_dev = container_of(work, struct pci_gpe_dev,
 | ||||
| +						   work);
 | ||||
| +
 | ||||
| +	pci_check_pme_status(gpe_dev->dev);
 | ||||
| +	pm_runtime_resume(&gpe_dev->dev->dev);
 | ||||
| +	pci_wakeup_event(gpe_dev->dev);
 | ||||
| +	if (gpe_dev->dev->subordinate)
 | ||||
| +		pci_pme_wakeup_bus(gpe_dev->dev->subordinate);
 | ||||
| +}
 | ||||
| +
 | ||||
| +static u32 acpi_pci_wake_handler(void *data)
 | ||||
| +{
 | ||||
| +	long gpe_number = (long) data;
 | ||||
| +	struct pci_gpe_dev *gpe_dev;
 | ||||
| +
 | ||||
| +	list_for_each_entry(gpe_dev, &acpi_pci_gpe_devs, node) {
 | ||||
| +		if (gpe_number != gpe_dev->gpe_number)
 | ||||
| +			continue;
 | ||||
| +
 | ||||
| +		schedule_work(&gpe_dev->work);
 | ||||
| +	}
 | ||||
| +
 | ||||
| +	return ACPI_INTERRUPT_HANDLED;
 | ||||
| +}
 | ||||
| +
 | ||||
|  static int acpi_pci_unbind(struct acpi_device *device) | ||||
|  { | ||||
|  	struct pci_dev *dev; | ||||
| @@ -43,6 +81,30 @@ static int acpi_pci_unbind(struct acpi_d
 | ||||
|  	if (!dev) | ||||
|  		goto out; | ||||
|   | ||||
| +	if (device->wakeup.flags.valid) {
 | ||||
| +		struct pci_gpe_dev *gpe_dev;
 | ||||
| +		struct pci_gpe_dev *tmp;
 | ||||
| +		int gpe_count = 0;
 | ||||
| +		int gpe_number = device->wakeup.gpe_number;
 | ||||
| +		acpi_handle gpe_device = device->wakeup.gpe_device;
 | ||||
| +
 | ||||
| +		list_for_each_entry_safe(gpe_dev, tmp, &acpi_pci_gpe_devs, node) {
 | ||||
| +			if (gpe_dev->dev == dev) {
 | ||||
| +				flush_work(&gpe_dev->work);
 | ||||
| +				list_del(&gpe_dev->node);
 | ||||
| +				kfree(gpe_dev);
 | ||||
| +			} else if (gpe_dev->gpe_number == gpe_number &&
 | ||||
| +				   gpe_dev->gpe_device == gpe_device) {
 | ||||
| +				gpe_count++;
 | ||||
| +			}
 | ||||
| +		}
 | ||||
| +
 | ||||
| +		if (gpe_count == 0) {
 | ||||
| +			acpi_remove_gpe_handler(gpe_device, gpe_number,
 | ||||
| +						&acpi_pci_wake_handler);
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
|  	device_set_run_wake(&dev->dev, false); | ||||
|  	pci_acpi_remove_pm_notifier(device); | ||||
|   | ||||
| @@ -71,6 +133,30 @@ static int acpi_pci_bind(struct acpi_dev
 | ||||
|  		return 0; | ||||
|   | ||||
|  	pci_acpi_add_pm_notifier(device, dev); | ||||
| +	if (device->wakeup.flags.valid) {
 | ||||
| +		struct pci_gpe_dev *gpe_dev;
 | ||||
| +		acpi_handle gpe_device = device->wakeup.gpe_device;
 | ||||
| +		long gpe_number = device->wakeup.gpe_number;
 | ||||
| +
 | ||||
| +		gpe_dev = kmalloc(sizeof(struct pci_gpe_dev), GFP_KERNEL);
 | ||||
| +		if (gpe_dev) {
 | ||||
| +			gpe_dev->dev = dev;
 | ||||
| +			gpe_dev->gpe_device = gpe_device;
 | ||||
| +			gpe_dev->gpe_number = gpe_number;
 | ||||
| +			INIT_WORK(&gpe_dev->work, acpi_pci_wake_handler_work);
 | ||||
| +
 | ||||
| +			acpi_install_gpe_handler(gpe_device, gpe_number,
 | ||||
| +						 ACPI_GPE_LEVEL_TRIGGERED,
 | ||||
| +						 &acpi_pci_wake_handler,
 | ||||
| +						 (void *)gpe_number,
 | ||||
| +						 true);
 | ||||
| +			acpi_gpe_can_wake(device->wakeup.gpe_device,
 | ||||
| +					  device->wakeup.gpe_number);
 | ||||
| +			device->wakeup.flags.run_wake = 1;
 | ||||
| +			list_add_tail(&gpe_dev->node, &acpi_pci_gpe_devs);
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
|  	if (device->wakeup.flags.run_wake) | ||||
|  		device_set_run_wake(&dev->dev, true); | ||||
|   | ||||
| diff -up linux-2.6.35.x86_64/drivers/acpi/sleep.c.mjg linux-2.6.35.x86_64/drivers/acpi/sleep.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/acpi/sleep.c.mjg	2010-10-04 13:52:05.103789729 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/acpi/sleep.c	2010-10-04 13:52:50.963801333 -0400
 | ||||
| @@ -631,9 +631,9 @@ int acpi_pm_device_sleep_state(struct de
 | ||||
|  		acpi_method[3] = 'W'; | ||||
|  		status = acpi_evaluate_integer(handle, acpi_method, NULL, | ||||
|  						&d_max); | ||||
| -		if (ACPI_FAILURE(status)) {
 | ||||
| +		if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
 | ||||
|  			d_max = d_min; | ||||
| -		} else if (d_max < d_min) {
 | ||||
| +		} else if (ACPI_SUCCESS(status) && d_max < d_min) {
 | ||||
|  			/* Warn the user of the broken DSDT */ | ||||
|  			printk(KERN_WARNING "ACPI: Wrong value from %s\n", | ||||
|  				acpi_method); | ||||
| diff -up linux-2.6.35.x86_64/drivers/char/ipmi/ipmi_si_intf.c.mjg linux-2.6.35.x86_64/drivers/char/ipmi/ipmi_si_intf.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/char/ipmi/ipmi_si_intf.c.mjg	2010-10-04 13:52:05.097789597 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/char/ipmi/ipmi_si_intf.c	2010-10-04 13:52:50.958801223 -0400
 | ||||
| @@ -1959,7 +1959,7 @@ static int acpi_gpe_irq_setup(struct smi
 | ||||
|  					  info->irq, | ||||
|  					  ACPI_GPE_LEVEL_TRIGGERED, | ||||
|  					  &ipmi_acpi_gpe, | ||||
| -					  info);
 | ||||
| +					  info, false);
 | ||||
|  	if (status != AE_OK) { | ||||
|  		dev_warn(info->dev, "%s unable to claim ACPI GPE %d," | ||||
|  			 " running polled\n", DEVICE_NAME, info->irq); | ||||
| diff -up linux-2.6.35.x86_64/drivers/pci/pci.c.mjg linux-2.6.35.x86_64/drivers/pci/pci.c
 | ||||
| --- linux-2.6.35.x86_64/drivers/pci/pci.c.mjg	2010-10-04 13:52:05.105789773 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/pci/pci.c	2010-10-04 13:52:50.965801377 -0400
 | ||||
| @@ -38,6 +38,19 @@ EXPORT_SYMBOL(pci_pci_problems);
 | ||||
|   | ||||
|  unsigned int pci_pm_d3_delay; | ||||
|   | ||||
| +static void pci_pme_list_scan(struct work_struct *work);
 | ||||
| +
 | ||||
| +static LIST_HEAD(pci_pme_list);
 | ||||
| +static DEFINE_MUTEX(pci_pme_list_mutex);
 | ||||
| +static DECLARE_DELAYED_WORK(pci_pme_work, pci_pme_list_scan);
 | ||||
| +
 | ||||
| +struct pci_pme_device {
 | ||||
| +	struct list_head list;
 | ||||
| +	struct pci_dev *dev;
 | ||||
| +};
 | ||||
| +
 | ||||
| +#define PME_TIMEOUT 1000 /* How long between PME checks */
 | ||||
| +
 | ||||
|  static void pci_dev_d3_sleep(struct pci_dev *dev) | ||||
|  { | ||||
|  	unsigned int delay = dev->d3_delay; | ||||
| @@ -1331,6 +1344,32 @@ bool pci_pme_capable(struct pci_dev *dev
 | ||||
|  	return !!(dev->pme_support & (1 << state)); | ||||
|  } | ||||
|   | ||||
| +static void pci_pme_list_scan(struct work_struct *work)
 | ||||
| +{
 | ||||
| +	struct pci_pme_device *pme_dev;
 | ||||
| +
 | ||||
| +	mutex_lock(&pci_pme_list_mutex);
 | ||||
| +	if (!list_empty(&pci_pme_list)) {
 | ||||
| +		list_for_each_entry(pme_dev, &pci_pme_list, list)
 | ||||
| +			pci_pme_wakeup(pme_dev->dev, NULL);
 | ||||
| +		schedule_delayed_work(&pci_pme_work, msecs_to_jiffies(PME_TIMEOUT));
 | ||||
| +	}
 | ||||
| +	mutex_unlock(&pci_pme_list_mutex);
 | ||||
| +}
 | ||||
| +
 | ||||
| +/**
 | ||||
| + * pci_external_pme - is a device an external PCI PME source?
 | ||||
| + * @dev: PCI device to check
 | ||||
| + *
 | ||||
| + */
 | ||||
| +
 | ||||
| +static bool pci_external_pme(struct pci_dev *dev)
 | ||||
| +{
 | ||||
| +	if (pci_is_pcie(dev) || dev->bus->number == 0)
 | ||||
| +		return false;
 | ||||
| +	return true;
 | ||||
| +}
 | ||||
| +
 | ||||
|  /** | ||||
|   * pci_pme_active - enable or disable PCI device's PME# function | ||||
|   * @dev: PCI device to handle. | ||||
| @@ -1354,6 +1393,44 @@ void pci_pme_active(struct pci_dev *dev,
 | ||||
|   | ||||
|  	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); | ||||
|   | ||||
| +	/* PCI (as opposed to PCIe) PME requires that the device have
 | ||||
| +	   its PME# line hooked up correctly. Not all hardware vendors
 | ||||
| +	   do this, so the PME never gets delivered and the device
 | ||||
| +	   remains asleep. The easiest way around this is to
 | ||||
| +	   periodically walk the list of suspended devices and check
 | ||||
| +	   whether any have their PME flag set. The assumption is that
 | ||||
| +	   we'll wake up often enough anyway that this won't be a huge
 | ||||
| +	   hit, and the power savings from the devices will still be a
 | ||||
| +	   win. */
 | ||||
| +
 | ||||
| +	if (pci_external_pme(dev)) {
 | ||||
| +		struct pci_pme_device *pme_dev;
 | ||||
| +		if (enable) {
 | ||||
| +			pme_dev = kmalloc(sizeof(struct pci_pme_device),
 | ||||
| +					  GFP_KERNEL);
 | ||||
| +			if (!pme_dev)
 | ||||
| +				goto out;
 | ||||
| +			pme_dev->dev = dev;
 | ||||
| +			mutex_lock(&pci_pme_list_mutex);
 | ||||
| +			list_add(&pme_dev->list, &pci_pme_list);
 | ||||
| +			if (list_is_singular(&pci_pme_list))
 | ||||
| +				schedule_delayed_work(&pci_pme_work,
 | ||||
| +						      msecs_to_jiffies(PME_TIMEOUT));
 | ||||
| +			mutex_unlock(&pci_pme_list_mutex);
 | ||||
| +		} else {
 | ||||
| +			mutex_lock(&pci_pme_list_mutex);
 | ||||
| +			list_for_each_entry(pme_dev, &pci_pme_list, list) {
 | ||||
| +				if (pme_dev->dev == dev) {
 | ||||
| +					list_del(&pme_dev->list);
 | ||||
| +					kfree(pme_dev);
 | ||||
| +					break;
 | ||||
| +				}
 | ||||
| +			}
 | ||||
| +			mutex_unlock(&pci_pme_list_mutex);
 | ||||
| +		}
 | ||||
| +	}
 | ||||
| +
 | ||||
| +out:
 | ||||
|  	dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n", | ||||
|  			enable ? "enabled" : "disabled"); | ||||
|  } | ||||
| diff -up linux-2.6.35.x86_64/drivers/pci/pci.h.mjg linux-2.6.35.x86_64/drivers/pci/pci.h
 | ||||
| --- linux-2.6.35.x86_64/drivers/pci/pci.h.mjg	2010-10-04 13:52:05.100789663 -0400
 | ||||
| +++ linux-2.6.35.x86_64/drivers/pci/pci.h	2010-10-04 13:52:50.960801267 -0400
 | ||||
| @@ -63,11 +63,8 @@ struct pci_platform_pm_ops {
 | ||||
|  extern int pci_set_platform_pm(struct pci_platform_pm_ops *ops); | ||||
|  extern void pci_update_current_state(struct pci_dev *dev, pci_power_t state); | ||||
|  extern void pci_disable_enabled_device(struct pci_dev *dev); | ||||
| -extern bool pci_check_pme_status(struct pci_dev *dev);
 | ||||
|  extern int pci_finish_runtime_suspend(struct pci_dev *dev); | ||||
| -extern void pci_wakeup_event(struct pci_dev *dev);
 | ||||
|  extern int __pci_pme_wakeup(struct pci_dev *dev, void *ign); | ||||
| -extern void pci_pme_wakeup_bus(struct pci_bus *bus);
 | ||||
|  extern void pci_pm_init(struct pci_dev *dev); | ||||
|  extern void platform_pci_wakeup_init(struct pci_dev *dev); | ||||
|  extern void pci_allocate_cap_save_buffers(struct pci_dev *dev); | ||||
| diff -up linux-2.6.35.x86_64/include/acpi/acpixf.h.mjg linux-2.6.35.x86_64/include/acpi/acpixf.h
 | ||||
| --- linux-2.6.35.x86_64/include/acpi/acpixf.h.mjg	2010-10-04 13:52:05.099789641 -0400
 | ||||
| +++ linux-2.6.35.x86_64/include/acpi/acpixf.h	2010-10-04 13:52:50.959801245 -0400
 | ||||
| @@ -253,7 +253,8 @@ acpi_remove_address_space_handler(acpi_h
 | ||||
|  acpi_status | ||||
|  acpi_install_gpe_handler(acpi_handle gpe_device, | ||||
|  			 u32 gpe_number, | ||||
| -			 u32 type, acpi_event_handler address, void *context);
 | ||||
| +			 u32 type, acpi_event_handler address, void *context,
 | ||||
| +			 bool keep_method);
 | ||||
|   | ||||
|  acpi_status | ||||
|  acpi_remove_gpe_handler(acpi_handle gpe_device, | ||||
| diff -up linux-2.6.35.x86_64/include/linux/pci.h.mjg linux-2.6.35.x86_64/include/linux/pci.h
 | ||||
| --- linux-2.6.35.x86_64/include/linux/pci.h.mjg	2010-10-04 13:52:05.101789685 -0400
 | ||||
| +++ linux-2.6.35.x86_64/include/linux/pci.h	2010-10-04 13:52:50.962801311 -0400
 | ||||
| @@ -819,6 +819,9 @@ pci_power_t pci_target_state(struct pci_
 | ||||
|  int pci_prepare_to_sleep(struct pci_dev *dev); | ||||
|  int pci_back_from_sleep(struct pci_dev *dev); | ||||
|  bool pci_dev_run_wake(struct pci_dev *dev); | ||||
| +bool pci_check_pme_status(struct pci_dev *dev);
 | ||||
| +void pci_wakeup_event(struct pci_dev *dev);
 | ||||
| +void pci_pme_wakeup_bus(struct pci_bus *bus);
 | ||||
|   | ||||
|  static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, | ||||
|  				  bool enable) | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user