summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2011-11-08 18:56:52 +0000
committeradrian <adrian@FreeBSD.org>2011-11-08 18:56:52 +0000
commit913f44bdc8de61877e6a27e18cadc68090255d40 (patch)
tree2a56086b2c5e4aed70307b0d2110fc3b2499fa71
parent5b3fc4fe6ecb66d337f9b4f33c0724b5c8bf0877 (diff)
downloadFreeBSD-src-913f44bdc8de61877e6a27e18cadc68090255d40.zip
FreeBSD-src-913f44bdc8de61877e6a27e18cadc68090255d40.tar.gz
In preparation for supporting 11n TX/RX properly, allow for TX queue draining
and interface resets to be marked as ATH_RESET_DEFAULT, ATH_RESET_FULL, ATH_RESET_NOLOSS. Currently a reset is still a reset - ie, all tx/rx frames in the hardware queues are purged. This means that those frames will be lost to the 11n TX and RX aggregation state tracking, breaking AMPDU sessions. The (eventual) new semantics: * ATH_RESET_DEFAULT: full reset, this is the default for reset situations which I haven't yet figured out what they should be. * ATH_RESET_FULL: A full reset - for things such as channel changes. * ATH_RESET_NOLOSS: Don't flush TX/RX queues - handle pending RX frames and leave TX frames where they are; restart TX DMA from where it was.
-rw-r--r--sys/dev/ath/if_ath.c28
-rw-r--r--sys/dev/ath/if_ath_misc.h2
-rw-r--r--sys/dev/ath/if_ath_sysctl.c8
3 files changed, 21 insertions, 17 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index 37adfa6..6985919 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -184,7 +184,7 @@ static void ath_tx_proc_q0123(void *, int);
static void ath_tx_proc(void *, int);
static void ath_tx_draintxq(struct ath_softc *, struct ath_txq *);
static int ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
-static void ath_draintxq(struct ath_softc *);
+static void ath_draintxq(struct ath_softc *, ATH_RESET_TYPE reset_type);
static void ath_stoprecv(struct ath_softc *);
static int ath_startrecv(struct ath_softc *);
static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *);
@@ -1123,7 +1123,8 @@ ath_vap_delete(struct ieee80211vap *vap)
* the vap state by any frames pending on the tx queues.
*/
ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc); /* stop xmit side */
+ ath_draintxq(sc, ATH_RESET_DEFAULT); /* stop hw xmit side */
+ /* XXX Do all frames from all vaps/nodes need draining here? */
ath_stoprecv(sc); /* stop recv side */
}
@@ -1507,7 +1508,7 @@ ath_fatal_proc(void *arg, int pending)
state[0], state[1] , state[2], state[3],
state[4], state[5]);
}
- ath_reset(ifp);
+ ath_reset(ifp, ATH_RESET_NOLOSS);
}
static void
@@ -1567,7 +1568,7 @@ ath_bmiss_proc(void *arg, int pending)
if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) {
if_printf(ifp, "bb hang detected (0x%x), resetting\n", hangs);
- ath_reset(ifp);
+ ath_reset(ifp, ATH_RESET_NOLOSS);
} else
ieee80211_beacon_miss(ifp->if_l2com);
}
@@ -1747,7 +1748,7 @@ ath_stop_locked(struct ifnet *ifp)
}
ath_hal_intrset(ah, 0);
}
- ath_draintxq(sc);
+ ath_draintxq(sc, ATH_RESET_DEFAULT);
if (!sc->sc_invalid) {
ath_stoprecv(sc);
ath_hal_phydisable(ah);
@@ -1775,7 +1776,7 @@ ath_stop(struct ifnet *ifp)
* to reset or reload hardware state.
*/
int
-ath_reset(struct ifnet *ifp)
+ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type)
{
struct ath_softc *sc = ifp->if_softc;
struct ieee80211com *ic = ifp->if_l2com;
@@ -1783,7 +1784,7 @@ ath_reset(struct ifnet *ifp)
HAL_STATUS status;
ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc); /* stop xmit side */
+ ath_draintxq(sc, reset_type); /* stop xmit side */
ath_stoprecv(sc); /* stop recv side */
ath_settkipmic(sc); /* configure TKIP MIC handling */
/* NB: indicate channel change so we do a full reset */
@@ -1836,7 +1837,8 @@ ath_reset_vap(struct ieee80211vap *vap, u_long cmd)
ath_hal_settxpowlimit(ah, ic->ic_txpowlimit);
return 0;
}
- return ath_reset(ifp);
+ /* XXX? Full or NOLOSS? */
+ return ath_reset(ifp, ATH_RESET_FULL);
}
struct ath_buf *
@@ -2730,7 +2732,7 @@ ath_bstuck_proc(void *arg, int pending)
if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n",
sc->sc_bmisscount);
sc->sc_stats.ast_bstuck++;
- ath_reset(ifp);
+ ath_reset(ifp, ATH_RESET_NOLOSS);
}
/*
@@ -4484,7 +4486,7 @@ ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq)
* Drain the transmit queues and reclaim resources.
*/
static void
-ath_draintxq(struct ath_softc *sc)
+ath_draintxq(struct ath_softc *sc, ATH_RESET_TYPE reset_type)
{
struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
@@ -4636,7 +4638,7 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
* the relevant bits of the h/w.
*/
ath_hal_intrset(ah, 0); /* disable interrupts */
- ath_draintxq(sc); /* clear pending tx frames */
+ ath_draintxq(sc, ATH_RESET_FULL); /* clear pending tx frames */
ath_stoprecv(sc); /* turn off frame recv */
if (!ath_hal_reset(ah, sc->sc_opmode, chan, AH_TRUE, &status)) {
if_printf(ifp, "%s: unable to reset "
@@ -4726,7 +4728,7 @@ ath_calibrate(void *arg)
DPRINTF(sc, ATH_DEBUG_CALIBRATE,
"%s: rfgain change\n", __func__);
sc->sc_stats.ast_per_rfgain++;
- ath_reset(ifp);
+ ath_reset(ifp, ATH_RESET_NOLOSS);
}
/*
* If this long cal is after an idle period, then
@@ -5392,7 +5394,7 @@ ath_watchdog(void *arg)
hangs & 0xff ? "bb" : "mac", hangs);
} else
if_printf(ifp, "device timeout\n");
- ath_reset(ifp);
+ ath_reset(ifp, ATH_RESET_NOLOSS);
ifp->if_oerrors++;
sc->sc_stats.ast_watchdog++;
}
diff --git a/sys/dev/ath/if_ath_misc.h b/sys/dev/ath/if_ath_misc.h
index 35feea2..7c496fc 100644
--- a/sys/dev/ath/if_ath_misc.h
+++ b/sys/dev/ath/if_ath_misc.h
@@ -53,6 +53,6 @@ extern int ath_tx_findrix(const struct ath_softc *sc, uint8_t rate);
extern struct ath_buf * ath_getbuf(struct ath_softc *sc);
extern struct ath_buf * _ath_getbuf_locked(struct ath_softc *sc);
-extern int ath_reset(struct ifnet *);
+extern int ath_reset(struct ifnet *, ATH_RESET_TYPE);
#endif
diff --git a/sys/dev/ath/if_ath_sysctl.c b/sys/dev/ath/if_ath_sysctl.c
index 5da37cf..4778de7 100644
--- a/sys/dev/ath/if_ath_sysctl.c
+++ b/sys/dev/ath/if_ath_sysctl.c
@@ -263,7 +263,8 @@ ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS)
if (error || !req->newptr)
return error;
return !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL :
- (ifp->if_drv_flags & IFF_DRV_RUNNING) ? ath_reset(ifp) : 0;
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) ?
+ ath_reset(ifp, ATH_RESET_NOLOSS) : 0;
}
static int
@@ -295,7 +296,8 @@ ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS)
return 0;
if (!ath_hal_setrfkill(ah, rfkill))
return EINVAL;
- return (ifp->if_drv_flags & IFF_DRV_RUNNING) ? ath_reset(ifp) : 0;
+ return (ifp->if_drv_flags & IFF_DRV_RUNNING) ?
+ ath_reset(ifp, ATH_RESET_FULL) : 0;
}
static int
@@ -428,7 +430,7 @@ ath_sysctl_intmit(SYSCTL_HANDLER_ARGS)
* things in an inconsistent state.
*/
if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
- ath_reset(sc->sc_ifp);
+ ath_reset(sc->sc_ifp, ATH_RESET_NOLOSS);
return 0;
}
OpenPOWER on IntegriCloud