diff options
author | Felix Fietkau <nbd@openwrt.org> | 2012-10-03 21:07:51 +0200 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-10-05 16:26:17 -0400 |
commit | ceb26a6013b962b82f644189ea29d802490fc8fc (patch) | |
tree | 72b22bf99cd0848df867d821231e52be36a40cbe | |
parent | 93170516a4d64319ffcc43bc9dd61f12775bd297 (diff) |
ath9k: improve suspend/resume reliability
Ensure that drv_start() always returns true, as a failing hw start usually
eventually leads to crashes when there's still a station entry present.
Call a power-on reset after a resume and after a hw reset failure to bring
the hardware back to life again.
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/pci.c | 4 |
4 files changed, 13 insertions, 10 deletions
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f9a6ec5cf470..8e1559aba495 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1450,9 +1450,14 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); + if (!ah->reset_power_on) + type = ATH9K_RESET_POWER_ON; + switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); + if (!ret) + ah->reset_power_on = true; break; case ATH9K_RESET_WARM: case ATH9K_RESET_COLD: diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 566a4ce4f156..dbc1b7a4cbfd 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -741,6 +741,7 @@ struct ath_hw { u32 rfkill_polarity; u32 ah_flags; + bool reset_power_on; bool htc_reset_init; enum nl80211_iftype opmode; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 31ab82e3ba85..e2fe713235dc 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -639,8 +639,7 @@ static int ath9k_start(struct ieee80211_hw *hw) ath_err(common, "Unable to reset hardware; reset status %d (freq %u MHz)\n", r, curchan->center_freq); - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; + ah->reset_power_on = false; } /* Setup our intr mask. */ @@ -665,11 +664,8 @@ static int ath9k_start(struct ieee80211_hw *hw) clear_bit(SC_OP_INVALID, &sc->sc_flags); sc->sc_ah->is_monitoring = false; - if (!ath_complete_reset(sc, false)) { - r = -EIO; - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; - } + if (!ath_complete_reset(sc, false)) + ah->reset_power_on = false; if (ah->led_pin >= 0) { ath9k_hw_cfg_output(ah, ah->led_pin, @@ -688,12 +684,11 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) common->bus_ops->extn_synch_en(common); -mutex_unlock: mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); - return r; + return 0; } static void ath9k_tx(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index 270abf720f3e..f088f4bf9a26 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -326,7 +326,8 @@ static int ath_pci_resume(struct device *device) struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u32 val; /* @@ -339,6 +340,7 @@ static int ath_pci_resume(struct device *device) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ath_pci_aspm_init(common); + ah->reset_power_on = false; return 0; } |