diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci.c | 11 | ||||
-rw-r--r-- | drivers/pci/pci.h | 10 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 58 |
3 files changed, 77 insertions, 2 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cf57d7de3765..9f79dd6d51ab 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -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); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 9cc842b666eb..08d58fc78ee1 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -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; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index de3bbc88fb26..e3c78c39b7e4 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -683,6 +683,33 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id ); +#ifdef CONFIG_ACPI_SLEEP + +/* + * Some VIA systems boot with the abnormal status flag set. This can cause + * the BIOS to re-POST the system on resume rather than passing control + * back to the OS. Clear the flag on boot + */ +static void __devinit quirk_via_abnormal_poweroff(struct pci_dev *dev) +{ + u32 reg; + + acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, + ®); + + if (reg & 0x800) { + printk("Clearing abnormal poweroff flag\n"); + acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, + ACPI_REGISTER_PM1_STATUS, + (u16)0x800); + } +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_abnormal_poweroff); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_abnormal_poweroff); + +#endif + /* * CardBus controllers have a legacy base address that enables them * to respond as i82365 pcmcia controllers. We don't want them to @@ -1391,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 |