Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ceb26a60 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

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: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 93170516
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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:
+1 −0
Original line number Diff line number Diff line
@@ -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;
+4 −9
Original line number Diff line number Diff line
@@ -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,
+3 −1
Original line number Diff line number Diff line
@@ -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;
}