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>
This commit is contained in:
parent
93170516a4
commit
ceb26a6013
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue