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

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

ath9k: fix false positives in the baseband hang check



ath9k_hw_check_alive() occasionally returns false, as the hardware
is still processing data in a specific state. Fix this issue by
repeating the test a few times with longer delay inbetween attempts.
This gets rid of excessive hardware resets that appear frequently on
some AR9132 based devices, but could also happen on AR9280.

Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Reported-by: default avatarBjörn Smedman <bjorn.smedman@venatech.se>
Cc: stable@kernel.org
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 54bd5006
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -428,6 +428,7 @@ int ath_beaconq_config(struct ath_softc *sc);


#define ATH_PAPRD_TIMEOUT	100 /* msecs */
#define ATH_PAPRD_TIMEOUT	100 /* msecs */


void ath_hw_check(struct work_struct *work);
void ath_paprd_calibrate(struct work_struct *work);
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
void ath_ani_calibrate(unsigned long data);


@@ -562,6 +563,7 @@ struct ath_softc {
	spinlock_t sc_pm_lock;
	spinlock_t sc_pm_lock;
	struct mutex mutex;
	struct mutex mutex;
	struct work_struct paprd_work;
	struct work_struct paprd_work;
	struct work_struct hw_check_work;
	struct completion paprd_complete;
	struct completion paprd_complete;


	u32 intrstatus;
	u32 intrstatus;
+1 −0
Original line number Original line Diff line number Diff line
@@ -718,6 +718,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
			goto error_world;
			goto error_world;
	}
	}


	INIT_WORK(&sc->hw_check_work, ath_hw_check);
	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
	INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
	INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
	INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
	INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
+25 −2
Original line number Original line Diff line number Diff line
@@ -515,6 +515,25 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
		ath_tx_node_cleanup(sc, an);
		ath_tx_node_cleanup(sc, an);
}
}


void ath_hw_check(struct work_struct *work)
{
	struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
	int i;

	ath9k_ps_wakeup(sc);

	for (i = 0; i < 3; i++) {
		if (ath9k_hw_check_alive(sc->sc_ah))
			goto out;

		msleep(1);
	}
	ath_reset(sc, false);

out:
	ath9k_ps_restore(sc);
}

void ath9k_tasklet(unsigned long data)
void ath9k_tasklet(unsigned long data)
{
{
	struct ath_softc *sc = (struct ath_softc *)data;
	struct ath_softc *sc = (struct ath_softc *)data;
@@ -526,13 +545,15 @@ void ath9k_tasklet(unsigned long data)


	ath9k_ps_wakeup(sc);
	ath9k_ps_wakeup(sc);


	if ((status & ATH9K_INT_FATAL) ||
	if (status & ATH9K_INT_FATAL) {
	    !ath9k_hw_check_alive(ah)) {
		ath_reset(sc, false);
		ath_reset(sc, false);
		ath9k_ps_restore(sc);
		ath9k_ps_restore(sc);
		return;
		return;
	}
	}


	if (!ath9k_hw_check_alive(ah))
		ieee80211_queue_work(sc->hw, &sc->hw_check_work);

	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
		rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
		rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
			  ATH9K_INT_RXORN);
			  ATH9K_INT_RXORN);
@@ -1253,6 +1274,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)


	cancel_delayed_work_sync(&sc->tx_complete_work);
	cancel_delayed_work_sync(&sc->tx_complete_work);
	cancel_work_sync(&sc->paprd_work);
	cancel_work_sync(&sc->paprd_work);
	cancel_work_sync(&sc->hw_check_work);


	if (!sc->num_sec_wiphy) {
	if (!sc->num_sec_wiphy) {
		cancel_delayed_work_sync(&sc->wiphy_work);
		cancel_delayed_work_sync(&sc->wiphy_work);
@@ -1976,6 +1998,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
	sc->sc_flags |= SC_OP_SCANNING;
	sc->sc_flags |= SC_OP_SCANNING;
	del_timer_sync(&common->ani.timer);
	del_timer_sync(&common->ani.timer);
	cancel_work_sync(&sc->paprd_work);
	cancel_work_sync(&sc->paprd_work);
	cancel_work_sync(&sc->hw_check_work);
	cancel_delayed_work_sync(&sc->tx_complete_work);
	cancel_delayed_work_sync(&sc->tx_complete_work);
	mutex_unlock(&sc->mutex);
	mutex_unlock(&sc->mutex);
}
}