diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index cc6d41d..ce9c983 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -195,6 +196,8 @@ static const struct ieee80211_rate ath5k_rates[] = { static int __devinit ath5k_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void __devexit ath5k_pci_remove(struct pci_dev *pdev); +static void __ath5k_disable_aspm(struct pci_dev *pdev, u16 state); +static void ath5k_disable_aspm(struct pci_dev *pdev, u16 state); #ifdef CONFIG_PM static int ath5k_pci_suspend(struct device *dev); static int ath5k_pci_resume(struct device *dev); @@ -424,6 +427,47 @@ module_exit(exit_ath5k_pci); * PCI Initialization * \********************/ +#ifdef CONFIG_PCIEASPM +static void __ath5k_disable_aspm(struct pci_dev *pdev, u16 state) +{ + pci_disable_link_state(pdev, state); +} +#else +static void __ath5k_disable_aspm(struct pci_dev *pdev, u16 state) +{ + int pos; + u16 reg16; + + /* + * Both device and parent should have the same ASPM setting. + * Disable ASPM in downstream component first and then upstream. + */ + pos = pci_pcie_cap(pdev); + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~state; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + if (!pdev->bus->self) + return; + + pos = pci_pcie_cap(pdev->bus->self); + pci_read_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~state; + pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16); +} +#endif +static void ath5k_disable_aspm(struct pci_dev *pdev, u16 state) +{ + if (!pdev->is_pcie) + return; + + dev_info(&pdev->dev, "Disabling ASPM %s%s\n", + (state & PCIE_LINK_STATE_L0S) ? "L0s " : "", + (state & PCIE_LINK_STATE_L1) ? "L1" : ""); + + __ath5k_disable_aspm(pdev, state); +} + static const char * ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val) { @@ -473,6 +517,8 @@ ath5k_pci_probe(struct pci_dev *pdev, int ret; u8 csz; + ath5k_disable_aspm(pdev, PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S); + ret = pci_enable_device(pdev); if (ret) { dev_err(&pdev->dev, "can't enable device\n"); @@ -725,6 +771,8 @@ static int ath5k_pci_resume(struct device *dev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath5k_softc *sc = hw->priv; + ath5k_disable_aspm(pdev, PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S); + /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep