summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2012-03-25 03:14:31 +0000
committeradrian <adrian@FreeBSD.org>2012-03-25 03:14:31 +0000
commit27ff2217e7492c343d1b4d582cf7f6184ee614d2 (patch)
treee8fb23947c1734c0cb8b706de1ce618c5eb23147 /sys/dev
parent2acdb6a872bf31d86f5d08f522dcdf2a0e290626 (diff)
downloadFreeBSD-src-27ff2217e7492c343d1b4d582cf7f6184ee614d2.zip
FreeBSD-src-27ff2217e7492c343d1b4d582cf7f6184ee614d2.tar.gz
Add the new channel width change field to the ath(4) driver.
This is not entirely correct as it simply resets the channel, flushing whatever is in the TX/RX queue. This can and will break aggregation BAW tracking. But the alternative (HT40 frames being sent with the hardware in HT20 mode) is even worse. There's still a small window between the htinfo being received (and the ni_chw field being updated) which could cause problems. I'll look at fleshing this out in follow-up commits. PR: kern/166286
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ath/if_ath.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index fc01e53..c886bc0 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -199,6 +199,7 @@ static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *);
static void ath_scan_start(struct ieee80211com *);
static void ath_scan_end(struct ieee80211com *);
static void ath_set_channel(struct ieee80211com *);
+static void ath_update_chw(struct ieee80211com *);
static void ath_calibrate(void *);
static int ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void ath_setup_stationkey(struct ieee80211_node *);
@@ -794,6 +795,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ic->ic_scan_start = ath_scan_start;
ic->ic_scan_end = ath_scan_end;
ic->ic_set_channel = ath_set_channel;
+ ic->ic_update_chw = ath_update_chw;
/* 802.11n specific - but just override anyway */
sc->sc_addba_request = ic->ic_addba_request;
@@ -5717,6 +5719,31 @@ ath_scan_end(struct ieee80211com *ic)
sc->sc_curaid);
}
+/*
+ * For now, just do a channel change.
+ *
+ * Later, we'll go through the hard slog of suspending tx/rx, changing rate
+ * control state and resetting the hardware without dropping frames out
+ * of the queue.
+ *
+ * The unfortunate trouble here is making absolutely sure that the
+ * channel width change has propagated enough so the hardware
+ * absolutely isn't handed bogus frames for it's current operating
+ * mode. (Eg, 40MHz frames in 20MHz mode.) Since TX and RX can and
+ * does occur in parallel, we need to make certain we've blocked
+ * any further ongoing TX (and RX, that can cause raw TX)
+ * before we do this.
+ */
+static void
+ath_update_chw(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+
+ DPRINTF(sc, ATH_DEBUG_STATE, "%s: called\n", __func__);
+ ath_set_channel(ic);
+}
+
static void
ath_set_channel(struct ieee80211com *ic)
{
OpenPOWER on IntegriCloud