[PATCH] PCI: PCIE power management quirk
When changing power states from D0->DX and then from DX->D0, some Intel PCIE chipsets will cause a device reset to occur. This will cause problems for any D State other than D3, since any state information that the driver will expect to be present coming from a D1 or D2 state will have been cleared. This patch addes a flag to the pci_dev structure to indicate that devices should not use states D1 or D2, and will set that flag for the affected chipsets. This patch also modifies pci_set_power_state() so that when a device driver tries to set the power state on a device that is downstream from an affected chipset, or on one of the affected devices it only allows state changes to or from D0 & D3. In addition, this patch allows the delay time between D3->D0 to be changed via a quirk. These chipsets also need additional time to change states beyond the normal 10ms. Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
		
							parent
							
								
									6f0312fd7e
								
							
						
					
					
						commit
						ffadcc2ff4
					
				| @ -19,6 +19,7 @@ | ||||
| #include <asm/dma.h>	/* isa_dma_bridge_buggy */ | ||||
| #include "pci.h" | ||||
| 
 | ||||
| unsigned int pci_pm_d3_delay = 10; | ||||
| 
 | ||||
| /**
 | ||||
|  * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children | ||||
| @ -313,6 +314,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | ||||
| 	} else if (dev->current_state == state) | ||||
| 		return 0;        /* we're already there */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If the device or the parent bridge can't support PCI PM, ignore | ||||
| 	 * the request if we're doing anything besides putting it into D0 | ||||
| 	 * (which would only happen on boot). | ||||
| 	 */ | ||||
| 	if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* find PCI PM capability in list */ | ||||
| 	pm = pci_find_capability(dev, PCI_CAP_ID_PM); | ||||
| 	 | ||||
| @ -363,7 +372,7 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) | ||||
| 	/* Mandatory power management transition delays */ | ||||
| 	/* see PCI PM 1.1 5.6.1 table 18 */ | ||||
| 	if (state == PCI_D3hot || dev->current_state == PCI_D3hot) | ||||
| 		msleep(10); | ||||
| 		msleep(pci_pm_d3_delay); | ||||
| 	else if (state == PCI_D2 || dev->current_state == PCI_D2) | ||||
| 		udelay(200); | ||||
| 
 | ||||
|  | ||||
| @ -47,7 +47,7 @@ extern int pci_msi_quirk; | ||||
| #else | ||||
| #define pci_msi_quirk 0 | ||||
| #endif | ||||
| 
 | ||||
| extern unsigned int pci_pm_d3_delay; | ||||
| #ifdef CONFIG_PCI_MSI | ||||
| void disable_msi_mode(struct pci_dev *dev, int pos, int type); | ||||
| void pci_no_msi(void); | ||||
| @ -66,7 +66,15 @@ static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; } | ||||
| static inline void pci_restore_msi_state(struct pci_dev *dev) {} | ||||
| static inline void pci_restore_msix_state(struct pci_dev *dev) {} | ||||
| #endif | ||||
| static inline int pci_no_d1d2(struct pci_dev *dev) | ||||
| { | ||||
| 	unsigned int parent_dstates = 0; | ||||
| 
 | ||||
| 	if (dev->bus->self) | ||||
| 		parent_dstates = dev->bus->self->no_d1d2; | ||||
| 	return (dev->no_d1d2 || parent_dstates); | ||||
| 
 | ||||
| } | ||||
| extern int pcie_mch_quirk; | ||||
| extern struct device_attribute pci_dev_attrs[]; | ||||
| extern struct class_device_attribute class_device_attr_cpuaffinity; | ||||
|  | ||||
| @ -1418,6 +1418,37 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXH_0,	quirk_pc | ||||
| DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXH_1,	quirk_pcie_pxh); | ||||
| DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_PXHV,	quirk_pcie_pxh); | ||||
| 
 | ||||
| /*
 | ||||
|  * Some Intel PCI Express chipsets have trouble with downstream | ||||
|  * device power management. | ||||
|  */ | ||||
| static void quirk_intel_pcie_pm(struct pci_dev * dev) | ||||
| { | ||||
| 	pci_pm_d3_delay = 120; | ||||
| 	dev->no_d1d2 = 1; | ||||
| } | ||||
| 
 | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25e2, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25e3, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25e4, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25e5, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25e6, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25e7, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25f7, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25f8, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25f9, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x25fa, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2601, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2602, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2603, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2604, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2605, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2606, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2607, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2608, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x2609, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260a, quirk_intel_pcie_pm); | ||||
| DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	0x260b, quirk_intel_pcie_pm); | ||||
| 
 | ||||
| /*
 | ||||
|  * Fixup the cardbus bridges on the IBM Dock II docking station | ||||
|  | ||||
| @ -161,6 +161,7 @@ struct pci_dev { | ||||
| 	unsigned int	is_enabled:1;	/* pci_enable_device has been called */ | ||||
| 	unsigned int	is_busmaster:1; /* device is busmaster */ | ||||
| 	unsigned int	no_msi:1;	/* device may not use msi */ | ||||
| 	unsigned int	no_d1d2:1;   /* only allow d0 or d3 */ | ||||
| 	unsigned int	block_ucfg_access:1;	/* userspace config space access is blocked */ | ||||
| 	unsigned int	broken_parity_status:1;	/* Device generates false positive parity */ | ||||
| 	unsigned int 	msi_enabled:1; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user