Kernel offer possibility to change ASPM settings using /sys/module/pcie_aspm/parameters/policy interface. As settings can be changed, we also need to change ath9k hw registers. Patch implement this by monitoring power_off state, and based on that state setup register when pci core inform us about ASPM change. Signed-off-by: Stanislaw Gruszka <sgruszka@xxxxxxxxxx> --- drivers/net/wireless/ath/ath9k/hw-ops.h | 1 + drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/pci.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 0 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index dd9003e..0743e82 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -24,6 +24,7 @@ static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah, bool power_off) { + ah->power_off = power_off; if (ah->aspm_enabled != true) return; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6abf26d..eb736ca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -672,6 +672,7 @@ struct ath_hw { bool sw_mgmt_crypto; bool is_pciexpress; bool aspm_enabled; + bool power_off; bool is_monitoring; bool need_an_top2_fixup; u16 tx_trig_level; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index a92e55f..c46920b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -286,6 +286,34 @@ static void ath_pci_remove(struct pci_dev *pdev) pci_release_region(pdev, 0); } +#ifdef CONFIG_PCIEASPM + +static void ath_pci_aspm_changed(struct pci_dev *pdev, u32 state) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + + spin_lock_irq(&sc->sc_pcu_lock); + + /* + * ASPM settings were changed, we have to configure PCIe PM and SERDES + * registers based on current state of device and new ASPM settings. + */ + if (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { + ah->aspm_enabled = true; + ath9k_hw_configpcipowersave(ah, ah->power_off); + } else { + if (!ah->power_off) + ath9k_hw_configpcipowersave(ah, true); + ah->aspm_enabled = false; + } + + spin_unlock_irq(&sc->sc_pcu_lock); +} + +#endif + #ifdef CONFIG_PM static int ath_pci_suspend(struct device *device) @@ -365,6 +393,9 @@ static struct pci_driver ath_pci_driver = { .id_table = ath_pci_id_table, .probe = ath_pci_probe, .remove = ath_pci_remove, +#ifdef CONFIG_PCIEASPM + .aspm_changed = ath_pci_aspm_changed, +#endif .driver.pm = ATH9K_PM_OPS, }; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html