mirror of
https://github.com/freebsd/freebsd-src
synced 2024-09-20 08:44:33 +00:00
[ath] do a cold reset if TSFOOR triggers
TSFOOR happens if a beacon with a given TSF isn't received within the programmed/expected TSF value, plus/minus a fudge range. (OOR == out of range.) If this happens then it could be because the baseband/mac is stuck, or the baseband is deaf. So, do a cold reset and resync the beacon to try and unstick the hardware. It also happens when a bad AP decides to err, slew its TSF because they themselves are resetting and they don't preserve the TSF "well." This has fixed a bunch of weird corner cases on my 2GHz AP radio upstairs here where it occasionally goes deaf due to how much 2GHz noise is up here (and ANI gets a little sideways) and this unsticks the station VAP. For AP modes a hung baseband/mac usually ends up as a stuck beacon and those have been addressed for a long time by just resetting the hardware. But similar hangs in station mode didn't have a similar recovery mechanism. Tested: * AR9380, STA mode, 2GHz/5GHz * AR9580, STA mode, 5GHz * QCA9344 SoC w/ on-board wifi (TL-WDR4300/3600 devices); 2GHz STA mode
This commit is contained in:
parent
51dfae383b
commit
fb3edd4f3f
|
@ -165,6 +165,7 @@ static void ath_parent(struct ieee80211com *);
|
|||
static void ath_fatal_proc(void *, int);
|
||||
static void ath_bmiss_vap(struct ieee80211vap *);
|
||||
static void ath_bmiss_proc(void *, int);
|
||||
static void ath_tsfoor_proc(void *, int);
|
||||
static void ath_key_update_begin(struct ieee80211vap *);
|
||||
static void ath_key_update_end(struct ieee80211vap *);
|
||||
static void ath_update_mcast_hw(struct ath_softc *);
|
||||
|
@ -761,6 +762,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
|
|||
|
||||
TASK_INIT(&sc->sc_rxtask, 0, sc->sc_rx.recv_tasklet, sc);
|
||||
TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc);
|
||||
TASK_INIT(&sc->sc_tsfoortask, 0, ath_tsfoor_proc, sc);
|
||||
TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc);
|
||||
TASK_INIT(&sc->sc_resettask,0, ath_reset_proc, sc);
|
||||
TASK_INIT(&sc->sc_txqtask, 0, ath_txq_sched_tasklet, sc);
|
||||
|
@ -2333,13 +2335,18 @@ ath_intr(void *arg)
|
|||
sc->sc_stats.ast_rxorn++;
|
||||
}
|
||||
if (status & HAL_INT_TSFOOR) {
|
||||
/* out of range beacon - wake the chip up,
|
||||
* but don't modify self-gen frame config */
|
||||
device_printf(sc->sc_dev, "%s: TSFOOR\n", __func__);
|
||||
sc->sc_syncbeacon = 1;
|
||||
/*
|
||||
* out of range beacon - wake the chip up,
|
||||
* but don't modify self-gen frame config.
|
||||
* Do a full reset to clear any potential stuck
|
||||
* PHY/MAC that generated this condition.
|
||||
*/
|
||||
sc->sc_stats.ast_tsfoor++;
|
||||
ATH_LOCK(sc);
|
||||
ath_power_setpower(sc, HAL_PM_AWAKE, 0);
|
||||
ATH_UNLOCK(sc);
|
||||
taskqueue_enqueue(sc->sc_tq, &sc->sc_tsfoortask);
|
||||
device_printf(sc->sc_dev, "%s: TSFOOR\n", __func__);
|
||||
}
|
||||
if (status & HAL_INT_MCI) {
|
||||
ath_btcoex_mci_intr(sc);
|
||||
|
@ -2483,7 +2490,7 @@ ath_bmiss_proc(void *arg, int pending)
|
|||
ath_beacon_miss(sc);
|
||||
|
||||
/*
|
||||
* Do a reset upon any becaon miss event.
|
||||
* Do a reset upon any beacon miss event.
|
||||
*
|
||||
* It may be a non-recognised RX clear hang which needs a reset
|
||||
* to clear.
|
||||
|
@ -2505,6 +2512,39 @@ ath_bmiss_proc(void *arg, int pending)
|
|||
ATH_UNLOCK(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a TSF out of range interrupt in STA mode.
|
||||
*
|
||||
* This may be due to a partially deaf looking radio, so
|
||||
* do a full reset just in case it is indeed deaf and
|
||||
* resync the beacon.
|
||||
*/
|
||||
static void
|
||||
ath_tsfoor_proc(void *arg, int pending)
|
||||
{
|
||||
struct ath_softc *sc = arg;
|
||||
|
||||
DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
|
||||
|
||||
ATH_LOCK(sc);
|
||||
ath_power_set_power_state(sc, HAL_PM_AWAKE);
|
||||
ATH_UNLOCK(sc);
|
||||
|
||||
/*
|
||||
* Do a full reset after any TSFOOR. It's possible that
|
||||
* we've gone deaf or partially deaf (eg due to calibration
|
||||
* failures) and this should clean things up a bit.
|
||||
*/
|
||||
ath_reset(sc, ATH_RESET_NOLOSS, HAL_RESET_FORCE_COLD);
|
||||
|
||||
/* Force a beacon resync, in case they've drifted */
|
||||
sc->sc_syncbeacon = 1;
|
||||
|
||||
ATH_LOCK(sc);
|
||||
ath_power_restore_power_state(sc);
|
||||
ATH_UNLOCK(sc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle TKIP MIC setup to deal hardware that doesn't do MIC
|
||||
* calcs together with WME. If necessary disable the crypto
|
||||
|
|
|
@ -177,6 +177,7 @@ struct ath_stats {
|
|||
u_int32_t ast_tx_nodeq_overflow; /* node sw queue overflow */
|
||||
u_int32_t ast_tx_ldpc; /* TX LDPC frame */
|
||||
u_int32_t ast_tx_stbc; /* TX STBC frame */
|
||||
u_int32_t ast_tsfoor; /* TSFOOR interrupts */
|
||||
u_int32_t ast_pad[10];
|
||||
};
|
||||
|
||||
|
|
|
@ -784,6 +784,7 @@ struct ath_softc {
|
|||
/* recent tx frames/antenna */
|
||||
struct ath_txq *sc_cabq; /* tx q for cab frames */
|
||||
struct task sc_bmisstask; /* bmiss int processing */
|
||||
struct task sc_tsfoortask; /* TSFOOR int processing */
|
||||
struct task sc_bstucktask; /* stuck beacon processing */
|
||||
struct task sc_resettask; /* interface reset task */
|
||||
struct task sc_fataltask; /* fatal task */
|
||||
|
|
Loading…
Reference in a new issue