From 1e9460c68fd0756bfb6122f7061546f2f11583a9 Mon Sep 17 00:00:00 2001 From: sam Date: Fri, 24 Feb 2006 19:51:11 +0000 Subject: [PATCH] MFC ath changes up to and including the v0.9.16.16 hal import Approved by: re (scottl, mux) --- sys/dev/ath/ath_rate/amrr/amrr.c | 5 +- sys/dev/ath/ath_rate/onoe/onoe.c | 5 +- sys/dev/ath/ath_rate/sample/sample.c | 308 ++++++----- sys/dev/ath/ath_rate/sample/sample.h | 56 +- sys/dev/ath/if_ath.c | 737 +++++++++++++++++++++------ sys/dev/ath/if_athioctl.h | 2 + sys/dev/ath/if_athvar.h | 107 +++- 7 files changed, 871 insertions(+), 349 deletions(-) diff --git a/sys/dev/ath/ath_rate/amrr/amrr.c b/sys/dev/ath/ath_rate/amrr/amrr.c index 18a3fa5c3bbe..abae54967fbe 100644 --- a/sys/dev/ath/ath_rate/amrr/amrr.c +++ b/sys/dev/ath/ath_rate/amrr/amrr.c @@ -210,9 +210,6 @@ ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); ni->ni_txrate = rate; - /* XXX management/control frames always go at the lowest speed */ - an->an_tx_mgtrate = rt->info[0].rateCode; - an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble; /* * Before associating a node has no rate set setup * so we can't calculate any transmit codes to use. @@ -253,7 +250,7 @@ ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) /* NB: only do this if we didn't already do it above */ amn->amn_tx_rate3 = rt->info[0].rateCode; amn->amn_tx_rate3sp = - an->an_tx_mgtrate | rt->info[0].shortPreamble; + amn->amn_tx_rate3 | rt->info[0].shortPreamble; } else { amn->amn_tx_rate3 = amn->amn_tx_rate3sp = 0; } diff --git a/sys/dev/ath/ath_rate/onoe/onoe.c b/sys/dev/ath/ath_rate/onoe/onoe.c index 3cf8073d9ad1..dc4fada185bc 100644 --- a/sys/dev/ath/ath_rate/onoe/onoe.c +++ b/sys/dev/ath/ath_rate/onoe/onoe.c @@ -194,9 +194,6 @@ ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) (ni->ni_rates.rs_rates[rate] & IEEE80211_RATE_VAL) / 2 : 0); ni->ni_txrate = rate; - /* XXX management/control frames always go at the lowest speed */ - an->an_tx_mgtrate = rt->info[0].rateCode; - an->an_tx_mgtratesp = an->an_tx_mgtrate | rt->info[0].shortPreamble; /* * Before associating a node has no rate set setup * so we can't calculate any transmit codes to use. @@ -243,7 +240,7 @@ ath_rate_update(struct ath_softc *sc, struct ieee80211_node *ni, int rate) /* NB: only do this if we didn't already do it above */ on->on_tx_rate3 = rt->info[0].rateCode; on->on_tx_rate3sp = - an->an_tx_mgtrate | rt->info[0].shortPreamble; + on->on_tx_rate3 | rt->info[0].shortPreamble; } else { on->on_tx_rate3 = on->on_tx_rate3sp = 0; } diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c index 7acdc5cfe447..c8a1cf7d9096 100644 --- a/sys/dev/ath/ath_rate/sample/sample.c +++ b/sys/dev/ath/ath_rate/sample/sample.c @@ -78,7 +78,7 @@ __FBSDID("$FreeBSD$"); #define SAMPLE_DEBUG #ifdef SAMPLE_DEBUG enum { - ATH_DEBUG_RATE = 0x00000010, /* rate control */ + ATH_DEBUG_RATE = 0x00000010 /* rate control */ }; #define DPRINTF(sc, _fmt, ...) do { \ if (sc->sc_debug & ATH_DEBUG_RATE) \ @@ -108,13 +108,17 @@ enum { * The difference between the algorithm in the thesis and the one in this * file is that the one in this file uses a ewma instead of a window. * + * Also, this implementation tracks the average transmission time for + * a few different packet sizes independently for each link. */ #define STALE_FAILURE_TIMEOUT_MS 10000 +#define MIN_SWITCH_MS 1000 static void ath_rate_ctl_reset(struct ath_softc *, struct ieee80211_node *); -static __inline int size_to_bin(int size) +static __inline int +size_to_bin(int size) { int x = 0; for (x = 0; x < NUM_PACKET_SIZE_BINS; x++) { @@ -124,11 +128,13 @@ static __inline int size_to_bin(int size) } return NUM_PACKET_SIZE_BINS-1; } -static __inline int bin_to_size(int index) { +static __inline int +bin_to_size(int index) { return packet_size_bins[index]; } -static __inline int rate_to_ndx(struct sample_node *sn, int rate) { +static __inline int +rate_to_ndx(struct sample_node *sn, int rate) { int x = 0; for (x = 0; x < sn->num_rates; x++) { if (sn->rates[x].rate == rate) { @@ -138,28 +144,11 @@ static __inline int rate_to_ndx(struct sample_node *sn, int rate) { return -1; } -/* - * Setup rate codes for management/control frames. We force - * all such frames to the lowest rate. - */ -static void -ath_rate_setmgtrates(struct ath_softc *sc, struct ath_node *an) -{ - const HAL_RATE_TABLE *rt = sc->sc_currates; - - /* setup rates for management frames */ - /* XXX management/control frames always go at lowest speed */ - an->an_tx_mgtrate = rt->info[0].rateCode; - an->an_tx_mgtratesp = an->an_tx_mgtrate - | rt->info[0].shortPreamble; -} - void ath_rate_node_init(struct ath_softc *sc, struct ath_node *an) { DPRINTF(sc, "%s:\n", __func__); /* NB: assumed to be zero'd by caller */ - ath_rate_setmgtrates(sc, an); } void @@ -185,6 +174,15 @@ static __inline int best_rate_ndx(struct sample_node *sn, int size_bin, !sn->stats[size_bin][x].packets_acked)) { continue; } + + /* 9 megabits never works better than 12 */ + if (sn->rates[x].rate == 18) + continue; + + /* don't use a bit-rate that has been failing */ + if (sn->stats[size_bin][x].successive_failures > 3) + continue; + if (!best_rate_tt || best_rate_tt > tt) { best_rate_tt = tt; best_rate_ndx = x; @@ -194,11 +192,10 @@ static __inline int best_rate_ndx(struct sample_node *sn, int size_bin, } /* - * pick a ndx s.t. the perfect_tx_time - * is less than the best bit-rate's average_tx_time - * and the ndx has not had four successive failures. + * pick a good "random" bit-rate to sample other than the current one */ -static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin) +static __inline int +pick_sample_ndx(struct sample_node *sn, int size_bin) { int x = 0; int current_ndx = 0; @@ -213,24 +210,38 @@ static __inline int pick_sample_ndx(struct sample_node *sn, int size_bin) current_tt = sn->stats[size_bin][current_ndx].average_tx_time; for (x = 0; x < sn->num_rates; x++) { - int ndx = (sn->last_sample_ndx[size_bin] + 1 + x) % sn->num_rates; - /* - * clear any stale stuff out. - */ - if (ticks - sn->stats[size_bin][ndx].last_tx > ((hz * STALE_FAILURE_TIMEOUT_MS)/1000)) { - sn->stats[size_bin][ndx].average_tx_time = sn->stats[size_bin][ndx].perfect_tx_time; - sn->stats[size_bin][ndx].successive_failures = 0; - sn->stats[size_bin][ndx].tries = 0; - sn->stats[size_bin][ndx].total_packets = 0; - sn->stats[size_bin][ndx].packets_acked = 0; - } + int ndx = (sn->last_sample_ndx[size_bin]+1+x) % sn->num_rates; - if (ndx != current_ndx && - sn->stats[size_bin][ndx].perfect_tx_time < current_tt && - sn->stats[size_bin][ndx].successive_failures < 4) { - sn->last_sample_ndx[size_bin] = ndx; - return ndx; - } + /* don't sample the current bit-rate */ + if (ndx == current_ndx) + continue; + + /* this bit-rate is always worse than the current one */ + if (sn->stats[size_bin][ndx].perfect_tx_time > current_tt) + continue; + + /* rarely sample bit-rates that fail a lot */ + if (ticks - sn->stats[size_bin][ndx].last_tx < ((hz * STALE_FAILURE_TIMEOUT_MS)/1000) && + sn->stats[size_bin][ndx].successive_failures > 3) + continue; + + /* don't sample more than 2 indexes higher + * for rates higher than 11 megabits + */ + if (sn->rates[ndx].rate > 22 && ndx > current_ndx + 2) + continue; + + /* 9 megabits never works better than 12 */ + if (sn->rates[ndx].rate == 18) + continue; + + /* if we're using 11 megabits, only sample up to 12 megabits + */ + if (sn->rates[current_ndx].rate == 22 && ndx > current_ndx + 1) + continue; + + sn->last_sample_ndx[size_bin] = ndx; + return ndx; } return current_ndx; } @@ -243,11 +254,10 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, struct sample_node *sn = ATH_NODE_SAMPLE(an); struct sample_softc *ssc = ATH_SOFTC_SAMPLE(sc); struct ieee80211com *ic = &sc->sc_ic; - int ndx, size_bin, mrr, best_ndx; + int ndx, size_bin, mrr, best_ndx, change_rates; unsigned average_tx_time; - mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT) && - !(frameLen > ic->ic_rtsthreshold); + mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT); size_bin = size_to_bin(frameLen); best_ndx = best_rate_ndx(sn, size_bin, !mrr); @@ -256,57 +266,14 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, } else { average_tx_time = 0; } + if (sn->static_rate_ndx != -1) { ndx = sn->static_rate_ndx; *try0 = ATH_TXMAXTRY; } else { - ndx = 0; *try0 = mrr ? 2 : ATH_TXMAXTRY; - - DPRINTF(sc, "%s: %s size %d mrr %d packets_sent %d best_ndx %d " - "sample tt %d packets since %d\n" - , __func__, ether_sprintf(an->an_node.ni_macaddr) - , packet_size_bins[size_bin] - , mrr - , sn->packets_sent[size_bin] - , best_ndx - , sn->sample_tt[size_bin] - , sn->packets_since_sample[size_bin] - ); - if (!sn->packets_sent[size_bin]) { - /* no packets sent */ - if (best_ndx == -1) { - ndx = sn->num_rates - 1; - if (sc->sc_curmode != IEEE80211_MODE_11B) { - for (; ndx >= 0 && sn->rates[ndx].rate > 72; ndx--) - ; - - } - } else { - ndx = best_ndx; - } - } else if (best_ndx == -1) { - /* no packet has succeeded yet */ - if (mrr) { - /* - * no packet has succeeded, try the - * highest bitrate that hasn't failed - */ - for (ndx = sn->num_rates-1; ndx >= 0; ndx--) { - if (sn->stats[size_bin][ndx].successive_failures == 0) { - break; - } - } - } else { - ndx = sn->num_rates - 1; - if (sc->sc_curmode != IEEE80211_MODE_11B) { - for (; ndx >= 0 && sn->rates[ndx].rate > 72; ndx--) - ; - - } - } - } else if (sn->sample_tt[size_bin] < (sn->packets_since_sample[size_bin]*ssc->ath_sample_rate/100) * average_tx_time && - sn->packets_since_sample[size_bin] > 15) { + + if (sn->sample_tt[size_bin] < average_tx_time * (sn->packets_since_sample[size_bin]*ssc->ath_sample_rate/100)) { /* * we want to limit the time measuring the performance * of other bit-rates to ath_sample_rate% of the @@ -314,13 +281,6 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, */ ndx = pick_sample_ndx(sn, size_bin); if (ndx != sn->current_rate[size_bin]) { - DPRINTF(sc, "%s: %s size %d last sample tt %d sampling %d packets since %d\n", - __func__, - ether_sprintf(an->an_node.ni_macaddr), - packet_size_bins[size_bin], - sn->sample_tt[size_bin], - sn->rates[ndx].rate, - sn->packets_since_sample[size_bin]); sn->current_sample_ndx[size_bin] = ndx; } else { sn->current_sample_ndx[size_bin] = -1; @@ -328,19 +288,37 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, sn->packets_since_sample[size_bin] = 0; } else { + change_rates = 0; + if (!sn->packets_sent[size_bin] || best_ndx == -1) { + /* no packet has been sent successfully yet */ + for (ndx = sn->num_rates-1; ndx > 0; ndx--) { + /* + * pick the highest rate <= 36 Mbps + * that hasn't failed. + */ + if (sn->rates[ndx].rate <= 72 && + sn->stats[size_bin][ndx].successive_failures == 0) { + break; + } + } + change_rates = 1; + best_ndx = ndx; + } else if (sn->packets_sent[size_bin] < 20) { + /* let the bit-rate switch quickly during the first few packets */ + change_rates = 1; + } else if (ticks - ((hz*MIN_SWITCH_MS)/1000) > sn->ticks_since_switch[size_bin]) { + /* 2 seconds have gone by */ + change_rates = 1; + } else if (average_tx_time * 2 < sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time) { + /* the current bit-rate is twice as slow as the best one */ + change_rates = 1; + } + sn->packets_since_sample[size_bin]++; - /* - * don't switch bit-rates every packet. only - * switch during the first few packets we send - * or after 100 packets, or if the current - * bit-rate begins to perform twice as bad as - * another one. - */ - if (sn->packets_sent[size_bin] < 20 || - ticks - ((hz*2000)/1000) > sn->jiffies_since_switch[size_bin] || - average_tx_time * 2 < sn->stats[size_bin][sn->current_rate[size_bin]].average_tx_time ) { - if (sn->packets_sent[size_bin] > 20) { - DPRINTF(sc, "%s: %s size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mmr %d\n", + + if (change_rates) { + if (best_ndx != sn->current_rate[size_bin]) { + DPRINTF(sc, "%s: %s size %d switch rate %d (%d/%d) -> %d (%d/%d) after %d packets mrr %d\n", __func__, ether_sprintf(an->an_node.ni_macaddr), packet_size_bins[size_bin], @@ -355,17 +333,22 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, } sn->packets_since_switch[size_bin] = 0; sn->current_rate[size_bin] = best_ndx; - sn->jiffies_since_switch[size_bin] = ticks; + sn->ticks_since_switch[size_bin] = ticks; } ndx = sn->current_rate[size_bin]; sn->packets_since_switch[size_bin]++; + if (size_bin == 0) { + /* + * set the visible txrate for this node + * to the rate of small packets + */ + an->an_node.ni_txrate = ndx; + } } - } - if (ndx < 0) { - ndx = 0; - } + KASSERT(ndx >= 0 && ndx < sn->num_rates, ("ndx is %d", ndx)); + *rix = sn->rates[ndx].rix; if (shortPreamble) { *txrate = sn->rates[ndx].shortPreambleRateCode; @@ -373,7 +356,6 @@ ath_rate_findrate(struct ath_softc *sc, struct ath_node *an, *txrate = sn->rates[ndx].rateCode; } sn->packets_sent[size_bin]++; - an->an_node.ni_txrate = ndx; } void @@ -382,28 +364,17 @@ ath_rate_setupxtxdesc(struct ath_softc *sc, struct ath_node *an, { struct sample_node *sn = ATH_NODE_SAMPLE(an); int rateCode = -1; - int frame_size, size_bin, best_ndx, ndx; + int frame_size = 0; + int size_bin = 0; + int ndx = 0; - frame_size = ds->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */ - KASSERT(frame_size != 0, ("no frame size")); - size_bin = size_to_bin(frame_size); - best_ndx = best_rate_ndx(sn, size_bin, 0); - - if (best_ndx == -1 || !sn->stats[size_bin][best_ndx].packets_acked) { - /* - * no packet has succeeded, so also try at the - * lowest bitate. - */ - ndx = 0; - } else { - /* - * we're trying a different bit-rate, and it could be lossy, - * so if it fails try at the best bit-rate. - */ - ndx = best_ndx; + size_bin = size_to_bin(frame_size); // TODO: it's correct that frame_size alway 0 ? + ndx = sn->current_rate[size_bin]; /* retry at the current bit-rate */ + + if (!sn->stats[size_bin][ndx].packets_acked) { + ndx = 0; /* use the lowest bit-rate */ } - KASSERT(0 <= ndx && ndx < IEEE80211_RATE_MAXSIZE, - ("invalid ndx %d", ndx)); + if (shortPreamble) { rateCode = sn->rates[ndx].shortPreambleRateCode; } else { @@ -461,17 +432,6 @@ update_stats(struct ath_softc *sc, struct ath_node *an, short_tries-1, MIN(tries3 + tries_so_far, tries) - tries_so_far - 1); } -#ifdef SAMPLE_DEBUG - if (short_tries + tries > 3 || status) { - DPRINTF(sc, "%s: %s size %d rate %d ndx %d tries (%d/%d) tries0 %d tt %d avg_tt %d perfect_tt %d status %d\n", - __func__, ether_sprintf(an->an_node.ni_macaddr), - size, - rate, ndx0, short_tries, tries, tries0, tt, - sn->stats[size_bin][ndx0].average_tx_time, - sn->stats[size_bin][ndx0].perfect_tx_time, - status); - } -#endif /* SAMPLE_DEBUG */ if (sn->stats[size_bin][ndx0].total_packets < (100 / (100 - ssc->ath_smoothing_rate))) { /* just average the first few packets */ int avg_tx = sn->stats[size_bin][ndx0].average_tx_time; @@ -485,16 +445,17 @@ update_stats(struct ath_softc *sc, struct ath_node *an, } if (status) { - /* - * this packet failed - count this as a failure - * for larger packets also, since we assume - * if a small packet fails at a lower bit-rate - * then a larger one will also. - */ int y; - for (y = size_bin; y < NUM_PACKET_SIZE_BINS; y++) { + sn->stats[size_bin][ndx0].successive_failures++; + for (y = size_bin+1; y < NUM_PACKET_SIZE_BINS; y++) { + /* also say larger packets failed since we + * assume if a small packet fails at a lower + * bit-rate then a larger one will also. + */ sn->stats[y][ndx0].successive_failures++; sn->stats[y][ndx0].last_tx = ticks; + sn->stats[y][ndx0].tries += tries; + sn->stats[y][ndx0].total_packets++; } } else { sn->stats[size_bin][ndx0].packets_acked++; @@ -521,10 +482,12 @@ void ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, const struct ath_desc *ds, const struct ath_desc *ds0) { + struct ieee80211com *ic = &sc->sc_ic; struct sample_node *sn = ATH_NODE_SAMPLE(an); const struct ar5212_desc *ads = (const struct ar5212_desc *)&ds->ds_ctl0; int final_rate, short_tries, long_tries, frame_size; int ndx = -1; + int mrr; final_rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate; short_tries = ds->ds_txstat.ts_shortretry + 1; @@ -543,6 +506,8 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, return; } + mrr = sc->sc_mrretry && !(ic->ic_flags & IEEE80211_F_USEPROT); + if (sc->sc_mrretry && ds->ds_txstat.ts_status) { /* this packet failed */ DPRINTF(sc, "%s: %s size %d rate/try %d/%d %d/%d %d/%d %d/%d status %s retries (%d/%d)\n", @@ -562,7 +527,7 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, long_tries); } - if (!(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) { + if (!mrr || !(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) { /* only one rate was used */ ndx = rate_to_ndx(sn, final_rate); DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d/%d\n", @@ -625,7 +590,7 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an, ndx2, tries2, ndx3, tries3, short_tries, ds->ds_txstat.ts_longretry + 1, - ds->ds_txstat.ts_status); + long_tries > tries0); } if (tries1 && finalTSIdx > 0) { @@ -689,8 +654,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) * A fixed rate is to be used; ic_fixed_rate is an * index into the supported rate set. Convert this * to the index into the negotiated rate set for - * the node. We know the rate is there because the - * rate set is checked when the station associates. + * the node. */ const struct ieee80211_rateset *rs = &ic->ic_sup_rates[ic->ic_curmode]; @@ -701,7 +665,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) ; KASSERT(srate >= 0, ("fixed rate %d not in rate set", ic->ic_fixed_rate)); - sn->static_rate_ndx = srate; + sn->static_rate_ndx = srate; } DPRINTF(sc, "%s: %s size 1600 rate/tt", __func__, ether_sprintf(ni->ni_macaddr)); @@ -710,6 +674,11 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) for (x = 0; x < ni->ni_rates.rs_nrates; x++) { sn->rates[x].rate = ni->ni_rates.rs_rates[x] & IEEE80211_RATE_VAL; sn->rates[x].rix = sc->sc_rixmap[sn->rates[x].rate]; + if (sn->rates[x].rix == 0xff) { + DPRINTF(sc, "%s: ignore bogus rix at %d\n", + __func__, x); + continue; + } sn->rates[x].rateCode = rt->info[sn->rates[x].rix].rateCode; sn->rates[x].shortPreambleRateCode = rt->info[sn->rates[x].rix].rateCode | @@ -727,6 +696,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) { int size = bin_to_size(y); + int ndx = 0; sn->packets_sent[y] = 0; sn->current_sample_ndx[y] = -1; sn->last_sample_ndx[y] = 0; @@ -744,7 +714,27 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni) 0, 0); sn->stats[y][x].average_tx_time = sn->stats[y][x].perfect_tx_time; } + + /* set the initial rate */ + for (ndx = sn->num_rates-1; ndx > 0; ndx--) { + if (sn->rates[ndx].rate <= 72) { + break; + } + } + sn->current_rate[y] = ndx; } + + DPRINTF(sc, "%s: %s %d rates %d%sMbps (%dus)- %d%sMbps (%dus)\n", + __func__, ether_sprintf(ni->ni_macaddr), + sn->num_rates, + sn->rates[0].rate/2, sn->rates[0].rate % 0x1 ? ".5" : "", + sn->stats[1][0].perfect_tx_time, + sn->rates[sn->num_rates-1].rate/2, + sn->rates[sn->num_rates-1].rate % 0x1 ? ".5" : "", + sn->stats[1][sn->num_rates-1].perfect_tx_time + ); + + ni->ni_txrate = sn->current_rate[0]; #undef RATE } diff --git a/sys/dev/ath/ath_rate/sample/sample.h b/sys/dev/ath/ath_rate/sample/sample.h index c97d23a56e85..231b15f2dc69 100644 --- a/sys/dev/ath/ath_rate/sample/sample.h +++ b/sys/dev/ath/ath_rate/sample/sample.h @@ -90,7 +90,7 @@ struct sample_node { int current_rate[NUM_PACKET_SIZE_BINS]; int packets_since_switch[NUM_PACKET_SIZE_BINS]; - unsigned jiffies_since_switch[NUM_PACKET_SIZE_BINS]; + unsigned ticks_since_switch[NUM_PACKET_SIZE_BINS]; int packets_since_sample[NUM_PACKET_SIZE_BINS]; unsigned sample_tt[NUM_PACKET_SIZE_BINS]; @@ -186,8 +186,8 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, int length, int rix, int short_retries, int long_retries) { const HAL_RATE_TABLE *rt = sc->sc_currates; + int rts, cts; - /* pg 205 ieee.802.11.pdf */ unsigned t_slot = 20; unsigned t_difs = 50; unsigned t_sifs = 10; @@ -196,16 +196,43 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, int x = 0; int cw = WIFI_CW_MIN; int cix = rt->info[rix].controlRate; - int rts = 0; - int cts = 0; KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); - if (rt->info[rix].phy == IEEE80211_T_OFDM) { - t_slot = 9; - t_sifs = 9; - t_difs = 28; + if (!rt->info[rix].rateKbps) { + printf("rix %d (%d) bad ratekbps %d mode %u", + rix, rt->info[rix].dot11Rate, + rt->info[rix].rateKbps, + sc->sc_curmode); + + return 0; } + /* + * XXX getting mac/phy level timings should be fixed for turbo + * rates, and there is probably a way to get this from the + * hal... + */ + switch (rt->info[rix].phy) { + case IEEE80211_T_OFDM: + t_slot = 9; + t_sifs = 16; + t_difs = 28; + /* fall through */ + case IEEE80211_T_TURBO: + t_slot = 9; + t_sifs = 8; + t_difs = 28; + break; + case IEEE80211_T_DS: + /* fall through to default */ + default: + /* pg 205 ieee.802.11.pdf */ + t_slot = 20; + t_difs = 50; + t_sifs = 10; + } + + rts = cts = 0; if ((ic->ic_flags & IEEE80211_F_USEPROT) && rt->info[rix].phy == IEEE80211_T_OFDM) { @@ -218,13 +245,22 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, } - if (length > ic->ic_rtsthreshold) { + if (0 /*length > ic->ic_rtsthreshold */) { rts = 1; } if (rts || cts) { int ctsrate = rt->info[cix].rateCode; int ctsduration = 0; + + if (!rt->info[cix].rateKbps) { + printf("cix %d (%d) bad ratekbps %d mode %u", + cix, rt->info[cix].dot11Rate, + rt->info[cix].rateKbps, + sc->sc_curmode); + return 0; + } + ctsrate |= rt->info[cix].shortPreamble; if (rts) /* SIFS + CTS */ ctsduration += rt->info[cix].spAckDuration; @@ -238,7 +274,7 @@ static unsigned calc_usecs_unicast_packet(struct ath_softc *sc, tt += (short_retries + 1) * ctsduration; } tt += t_difs; - tt += (long_retries+1)*(t_sifs + rt->info[cix].spAckDuration); + tt += (long_retries+1)*(t_sifs + rt->info[rix].spAckDuration); tt += (long_retries+1)*ath_hal_computetxtime(sc->sc_ah, rt, length, rix, AH_TRUE); for (x = 0; x <= short_retries + long_retries; x++) { diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index 734f2cf39279..f24773f2819f 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -60,6 +60,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include @@ -85,6 +87,10 @@ __FBSDID("$FreeBSD$"); #include #include /* XXX for softled */ +#ifdef ATH_TX99_DIAG +#include +#endif + /* unaligned little endian access */ #define LE_READ_2(p) \ ((u_int16_t) \ @@ -111,6 +117,7 @@ static int ath_ioctl(struct ifnet *, u_long, caddr_t); static void ath_fatal_proc(void *, int); static void ath_rxorn_proc(void *, int); static void ath_bmiss_proc(void *, int); +static void ath_radar_proc(void *, int); static int ath_key_alloc(struct ieee80211com *, const struct ieee80211_key *, ieee80211_keyix *, ieee80211_keyix *); @@ -200,6 +207,15 @@ static int ath_regdomain = 0; /* regulatory domain */ SYSCTL_INT(_hw_ath, OID_AUTO, regdomain, CTLFLAG_RD, &ath_regdomain, 0, "regulatory domain"); +static int ath_rxbuf = ATH_RXBUF; /* # rx buffers to allocate */ +SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RD, &ath_rxbuf, + 0, "rx buffers allocated"); +TUNABLE_INT("hw.ath.rxbuf", &ath_rxbuf); +static int ath_txbuf = ATH_TXBUF; /* # tx buffers to allocate */ +SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RD, &ath_txbuf, + 0, "tx buffers allocated"); +TUNABLE_INT("hw.ath.txbuf", &ath_txbuf); + #ifdef AR_DEBUG static int ath_debug = 0; SYSCTL_INT(_hw_ath, OID_AUTO, debug, CTLFLAG_RW, &ath_debug, @@ -224,6 +240,8 @@ enum { ATH_DEBUG_STATE = 0x00040000, /* 802.11 state transitions */ ATH_DEBUG_NODE = 0x00080000, /* node management */ ATH_DEBUG_LED = 0x00100000, /* led management */ + ATH_DEBUG_FF = 0x00200000, /* fast frames */ + ATH_DEBUG_DFS = 0x00400000, /* DFS processing */ ATH_DEBUG_FATAL = 0x80000000, /* fatal errors */ ATH_DEBUG_ANY = 0xffffffff }; @@ -365,14 +383,22 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) } callout_init(&sc->sc_scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0); callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE); + callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE); ATH_TXBUF_LOCK_INIT(sc); + sc->sc_tq = taskqueue_create("ath_taskq", M_NOWAIT, + taskqueue_thread_enqueue, &sc->sc_tq, &sc->sc_tqproc); + /* XXX return error */ + kthread_create(taskqueue_thread_loop, &sc->sc_tq, &sc->sc_tqproc, + 0, 0, "%s taskq", ifp->if_xname); + TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, sc); TASK_INIT(&sc->sc_rxorntask, 0, ath_rxorn_proc, sc); TASK_INIT(&sc->sc_fataltask, 0, ath_fatal_proc, sc); TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc); - TASK_INIT(&sc->sc_bstucktask, 0, ath_bstuck_proc, sc); + TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc); + TASK_INIT(&sc->sc_radartask, 0, ath_radar_proc, sc); /* * Allocate hardware transmit queues: one queue for @@ -488,6 +514,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) IEEE80211_C_IBSS /* ibss, nee adhoc, mode */ | IEEE80211_C_HOSTAP /* hostap mode */ | IEEE80211_C_MONITOR /* monitor mode */ + | IEEE80211_C_AHDEMO /* adhoc demo mode */ | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_SHSLOT /* short slot time supported */ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ @@ -560,6 +587,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc) /* call MI attach routine. */ ieee80211_ifattach(ic); + sc->sc_opmode = ic->ic_opmode; /* override default methods */ ic->ic_node_alloc = ath_node_alloc; sc->sc_node_free = ic->ic_node_free; @@ -624,6 +652,11 @@ ath_detach(struct ath_softc *sc) * Other than that, it's straightforward... */ ieee80211_ifdetach(&sc->sc_ic); +#ifdef ATH_TX99_DIAG + if (sc->sc_tx99 != NULL) + sc->sc_tx99->detach(sc->sc_tx99); +#endif + taskqueue_free(sc->sc_tq); ath_rate_detach(sc->sc_rc); ath_desc_free(sc); ath_tx_cleanup(sc); @@ -721,11 +754,11 @@ ath_intr(void *arg) */ sc->sc_stats.ast_hardware++; ath_hal_intrset(ah, 0); /* disable intr's until reset */ - taskqueue_enqueue(taskqueue_swi, &sc->sc_fataltask); + taskqueue_enqueue(sc->sc_tq, &sc->sc_fataltask); } else if (status & HAL_INT_RXORN) { sc->sc_stats.ast_rxorn++; ath_hal_intrset(ah, 0); /* disable intr's until reset */ - taskqueue_enqueue(taskqueue_swi, &sc->sc_rxorntask); + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxorntask); } else { if (status & HAL_INT_SWBA) { /* @@ -751,12 +784,12 @@ ath_intr(void *arg) ath_hal_updatetxtriglevel(ah, AH_TRUE); } if (status & HAL_INT_RX) - taskqueue_enqueue(taskqueue_swi, &sc->sc_rxtask); + taskqueue_enqueue(sc->sc_tq, &sc->sc_rxtask); if (status & HAL_INT_TX) - taskqueue_enqueue(taskqueue_swi, &sc->sc_txtask); + taskqueue_enqueue(sc->sc_tq, &sc->sc_txtask); if (status & HAL_INT_BMISS) { sc->sc_stats.ast_bmiss++; - taskqueue_enqueue(taskqueue_swi, &sc->sc_bmisstask); + taskqueue_enqueue(sc->sc_tq, &sc->sc_bmisstask); } if (status & HAL_INT_MIB) { sc->sc_stats.ast_mib++; @@ -769,8 +802,7 @@ ath_intr(void *arg) * Let the hal handle the event. We assume it will * clear whatever condition caused the interrupt. */ - ath_hal_mibevent(ah, - &ATH_NODE(sc->sc_ic.ic_bss)->an_halstats); + ath_hal_mibevent(ah, &sc->sc_halstats); ath_hal_intrset(ah, sc->sc_imask); } } @@ -806,15 +838,47 @@ ath_bmiss_proc(void *arg, int pending) KASSERT(ic->ic_opmode == IEEE80211_M_STA, ("unexpect operating mode %u", ic->ic_opmode)); if (ic->ic_state == IEEE80211_S_RUN) { + u_int64_t lastrx = sc->sc_lastrx; + u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah); + u_int bmisstimeout = + ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024; + + DPRINTF(sc, ATH_DEBUG_BEACON, + "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n", + __func__, (unsigned long long) tsf, + (unsigned long long)(tsf - lastrx), + (unsigned long long) lastrx, bmisstimeout); /* - * Rather than go directly to scan state, try to - * reassociate first. If that fails then the state - * machine will drop us into scanning after timing - * out waiting for a probe response. + * Workaround phantom bmiss interrupts by sanity-checking + * the time of our last rx'd frame. If it is within the + * beacon miss interval then ignore the interrupt. If it's + * truly a bmiss we'll get another interrupt soon and that'll + * be dispatched up for processing. */ - NET_LOCK_GIANT(); - ieee80211_new_state(ic, IEEE80211_S_ASSOC, -1); - NET_UNLOCK_GIANT(); + if (tsf - lastrx > bmisstimeout) { + NET_LOCK_GIANT(); + ieee80211_beacon_miss(ic); + NET_UNLOCK_GIANT(); + } else + sc->sc_stats.ast_bmiss_phantom++; + } +} + +static void +ath_radar_proc(void *arg, int pending) +{ + struct ath_softc *sc = arg; + struct ifnet *ifp = sc->sc_ifp; + struct ath_hal *ah = sc->sc_ah; + HAL_CHANNEL hchan; + + if (ath_hal_procdfs(ah, &hchan)) { + if_printf(ifp, "radar detected on channel %u/0x%x/0x%x\n", + hchan.channel, hchan.channelFlags, hchan.privFlags); + /* + * Initiate channel change. + */ + /* XXX not yet */ } } @@ -828,7 +892,7 @@ ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan) CHANNEL_B, /* IEEE80211_MODE_11B */ CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 0, /* IEEE80211_MODE_FH */ - CHANNEL_T, /* IEEE80211_MODE_TURBO_A */ + CHANNEL_ST, /* IEEE80211_MODE_TURBO_A */ CHANNEL_108G /* IEEE80211_MODE_TURBO_G */ }; enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan); @@ -867,7 +931,7 @@ ath_init(void *arg) */ sc->sc_curchan.channel = ic->ic_curchan->ic_freq; sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan); - if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status)) { + if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) { if_printf(ifp, "unable to reset hardware; hal status %u\n", status); goto done; @@ -883,6 +947,8 @@ ath_init(void *arg) * state cached in the driver. */ sc->sc_diversity = ath_hal_getdiversity(ah); + sc->sc_calinterval = 1; + sc->sc_caltries = 0; /* * Setup the hardware after reset: the key cache @@ -919,6 +985,11 @@ ath_init(void *arg) * immediately call back to us to send mgmt frames. */ ath_chan_change(sc, ic->ic_curchan); +#ifdef ATH_TX99_DIAG + if (sc->sc_tx99 != NULL) + sc->sc_tx99->start(sc->sc_tx99); + else +#endif if (ic->ic_opmode != IEEE80211_M_MONITOR) { if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL) ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); @@ -955,6 +1026,10 @@ ath_stop_locked(struct ifnet *ifp) * Note that some of this work is not possible if the * hardware is gone (invalid). */ +#ifdef ATH_TX99_DIAG + if (sc->sc_tx99 != NULL) + sc->sc_tx99->stop(sc->sc_tx99); +#endif ieee80211_new_state(ic, IEEE80211_S_INIT, -1); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; ifp->if_timer = 0; @@ -995,7 +1070,7 @@ ath_stop(struct ifnet *ifp) * (and system). This varies by chip and is mostly an * issue with newer parts that go to sleep more quickly. */ - ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP, 0); + ath_hal_setpower(sc->sc_ah, HAL_PM_FULL_SLEEP); } ATH_UNLOCK(sc); } @@ -1028,19 +1103,21 @@ ath_reset(struct ifnet *ifp) ath_draintxq(sc); /* stop xmit side */ ath_stoprecv(sc); /* stop recv side */ /* NB: indicate channel change so we do a full reset */ - if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_TRUE, &status)) + if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status)) if_printf(ifp, "%s: unable to reset hardware; hal status %u\n", __func__, status); ath_update_txpow(sc); /* update tx power state */ sc->sc_diversity = ath_hal_getdiversity(ah); - if (ath_startrecv(sc) != 0) /* restart recv */ - if_printf(ifp, "%s: unable to start recv logic\n", __func__); + sc->sc_calinterval = 1; + sc->sc_caltries = 0; /* * We may be doing a reset in response to an ioctl * that changes the channel so update any state that * might change as a result. */ ath_chan_change(sc, c); + if (ath_startrecv(sc) != 0) /* restart recv */ + if_printf(ifp, "%s: unable to start recv logic\n", __func__); if (ic->ic_state == IEEE80211_S_RUN) ath_beacon_config(sc); /* restart beacons */ ath_hal_intrset(ah, sc->sc_imask); @@ -1073,7 +1150,7 @@ ath_start(struct ifnet *ifp) STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); ATH_TXBUF_UNLOCK(sc); if (bf == NULL) { - DPRINTF(sc, ATH_DEBUG_ANY, "%s: out of xmit buffers\n", + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n", __func__); sc->sc_stats.ast_tx_qstop++; ifp->if_drv_flags |= IFF_DRV_OACTIVE; @@ -1089,9 +1166,10 @@ ath_start(struct ifnet *ifp) * No data frames go out unless we're associated. */ if (ic->ic_state != IEEE80211_S_RUN) { - DPRINTF(sc, ATH_DEBUG_ANY, - "%s: ignore data packet, state %u\n", - __func__, ic->ic_state); + DPRINTF(sc, ATH_DEBUG_XMIT, + "%s: discard data packet, state %s\n", + __func__, + ieee80211_state_name[ic->ic_state]); sc->sc_stats.ast_tx_discard++; ATH_TXBUF_LOCK(sc); STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); @@ -1147,7 +1225,7 @@ ath_start(struct ifnet *ifp) */ m = ieee80211_encap(ic, m, ni); if (m == NULL) { - DPRINTF(sc, ATH_DEBUG_ANY, + DPRINTF(sc, ATH_DEBUG_XMIT, "%s: encapsulation failure\n", __func__); sc->sc_stats.ast_tx_encap++; @@ -1209,6 +1287,18 @@ ath_media_change(struct ifnet *ifp) error = ieee80211_media_change(ifp); if (error == ENETRESET) { + struct ath_softc *sc = ifp->if_softc; + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_opmode == IEEE80211_M_AHDEMO) { + /* + * Adhoc demo mode is just ibss mode w/o beacons + * (mostly). The hal knows nothing about it; + * tell it we're operating in ibss mode. + */ + sc->sc_opmode = HAL_M_IBSS; + } else + sc->sc_opmode = ic->ic_opmode; if (IS_UP(ifp)) ath_init(ifp->if_softc); /* XXX lose error */ error = 0; @@ -1602,12 +1692,13 @@ ath_key_update_end(struct ieee80211com *ic) static u_int32_t ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state) { +#define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR) struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; struct ifnet *ifp = sc->sc_ifp; u_int32_t rfilt; - rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYERR) + rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE) | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; if (ic->ic_opmode != IEEE80211_M_STA) rfilt |= HAL_RX_FILTER_PROBEREQ; @@ -1619,6 +1710,7 @@ ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state) state == IEEE80211_S_SCAN) rfilt |= HAL_RX_FILTER_BEACON; return rfilt; +#undef RX_FILTER_PRESERVE } static void @@ -1646,7 +1738,7 @@ ath_mode_init(struct ath_softc *sc) * * XXX should get from lladdr instead of arpcom but that's more work */ - IEEE80211_ADDR_COPY(ic->ic_myaddr, IFP2ENADDR(ifp)); + IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp)); ath_hal_setmac(ah, ic->ic_myaddr); /* calculate and install multicast filter */ @@ -1724,7 +1816,7 @@ ath_beaconq_setup(struct ath_hal *ah) qi.tqi_cwmin = HAL_TXQ_USEDEFAULT; qi.tqi_cwmax = HAL_TXQ_USEDEFAULT; /* NB: for dynamic turbo, don't enable any other interrupts */ - qi.tqi_qflags = TXQ_FLAG_TXDESCINT_ENABLE; + qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE; return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi); } @@ -1823,10 +1915,10 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) struct ieee80211com *ic = ni->ni_ic; struct mbuf *m = bf->bf_m; struct ath_hal *ah = sc->sc_ah; - struct ath_node *an = ATH_NODE(ni); struct ath_desc *ds; int flags, antenna; - u_int8_t rate; + const HAL_RATE_TABLE *rt; + u_int8_t rix, rate; DPRINTF(sc, ATH_DEBUG_BEACON, "%s: m %p len %u\n", __func__, m, m->m_len); @@ -1858,10 +1950,11 @@ ath_beacon_setup(struct ath_softc *sc, struct ath_buf *bf) * Calculate rate code. * XXX everything at min xmit rate */ + rix = sc->sc_minrateix; + rt = sc->sc_currates; + rate = rt->info[rix].rateCode; if (USE_SHPREAMBLE(ic)) - rate = an->an_tx_mgtratesp; - else - rate = an->an_tx_mgtrate; + rate |= rt->info[rix].shortPreamble; ath_hal_setuptxdesc(ah, ds , m->m_len + IEEE80211_CRC_LEN /* frame length */ , sizeof(struct ieee80211_frame)/* header length */ @@ -1923,7 +2016,7 @@ ath_beacon_proc(void *arg, int pending) "%s: missed %u consecutive beacons\n", __func__, sc->sc_bmisscount); if (sc->sc_bmisscount > 3) /* NB: 3 is a guess */ - taskqueue_enqueue(taskqueue_swi, &sc->sc_bstucktask); + taskqueue_enqueue(sc->sc_tq, &sc->sc_bstucktask); return; } if (sc->sc_bmisscount != 0) { @@ -2000,7 +2093,7 @@ ath_beacon_proc(void *arg, int pending) * Enable the CAB queue before the beacon queue to * insure cab frames are triggered by this beacon. */ - if (sc->sc_boff.bo_tim[4] & 1) /* NB: only at DTIM */ + if (ncabq != 0 && (sc->sc_boff.bo_tim[4] & 1)) /* NB: only at DTIM */ ath_hal_txstart(ah, sc->sc_cabq->axq_qnum); ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); ath_hal_txstart(ah, sc->sc_bhalq); @@ -2064,11 +2157,14 @@ ath_beacon_free(struct ath_softc *sc) static void ath_beacon_config(struct ath_softc *sc) { -#define TSF_TO_TU(_h,_l) (((_h) << 22) | ((_l) >> 10)) +#define TSF_TO_TU(_h,_l) \ + ((((u_int32_t)(_h)) << 22) | (((u_int32_t)(_l)) >> 10)) +#define FUDGE 2 struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; - u_int32_t nexttbtt, intval; + u_int32_t nexttbtt, intval, tsftu; + u_int64_t tsf; /* extract tstamp from last beacon and convert to TU */ nexttbtt = TSF_TO_TU(LE_READ_4(ni->ni_tstamp.data + 4), @@ -2083,8 +2179,6 @@ ath_beacon_config(struct ath_softc *sc) __func__, nexttbtt, intval, ni->ni_intval); if (ic->ic_opmode == IEEE80211_M_STA) { HAL_BEACON_STATE bs; - u_int64_t tsf; - u_int32_t tsftu; int dtimperiod, dtimcount; int cfpperiod, cfpcount; @@ -2100,13 +2194,12 @@ ath_beacon_config(struct ath_softc *sc) dtimcount = 0; /* XXX? */ cfpperiod = 1; /* NB: no PCF support yet */ cfpcount = 0; -#define FUDGE 2 /* * Pull nexttbtt forward to reflect the current * TSF and calculate dtim+cfp state for the result. */ tsf = ath_hal_gettsf64(ah); - tsftu = TSF_TO_TU((u_int32_t)(tsf>>32), (u_int32_t)tsf) + FUDGE; + tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; do { nexttbtt += intval; if (--dtimcount < 0) { @@ -2115,7 +2208,6 @@ ath_beacon_config(struct ath_softc *sc) cfpcount = cfpperiod - 1; } } while (nexttbtt < tsftu); -#undef FUDGE memset(&bs, 0, sizeof(bs)); bs.bs_intval = intval; bs.bs_nexttbtt = nexttbtt; @@ -2197,6 +2289,17 @@ ath_beacon_config(struct ath_softc *sc) intval |= HAL_BEACON_ENA; if (!sc->sc_hasveol) sc->sc_imask |= HAL_INT_SWBA; + if ((intval & HAL_BEACON_RESET_TSF) == 0) { + /* + * Pull nexttbtt forward to reflect + * the current TSF. + */ + tsf = ath_hal_gettsf64(ah); + tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE; + do { + nexttbtt += intval; + } while (nexttbtt < tsftu); + } ath_beaconq_config(sc); } else if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* @@ -2217,6 +2320,8 @@ ath_beacon_config(struct ath_softc *sc) if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) ath_beacon_proc(sc, 0); } + sc->sc_syncbeacon = 0; +#undef FUDGE #undef TSF_TO_TU } @@ -2377,12 +2482,12 @@ ath_desc_alloc(struct ath_softc *sc) int error; error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, - "rx", ATH_RXBUF, 1); + "rx", ath_rxbuf, 1); if (error != 0) return error; error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, - "tx", ATH_TXBUF, ATH_TXDESC); + "tx", ath_txbuf, ATH_TXDESC); if (error != 0) { ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); return error; @@ -2424,9 +2529,6 @@ ath_node_alloc(struct ieee80211_node_table *nt) return NULL; } an->an_avgrssi = ATH_RSSI_DUMMY_MARKER; - an->an_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - an->an_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - an->an_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; ath_rate_node_init(sc, an); DPRINTF(sc, ATH_DEBUG_NODE, "%s: an %p\n", __func__, an); @@ -2490,7 +2592,6 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) sc->sc_stats.ast_rx_nombuf++; return ENOMEM; } - bf->bf_m = m; m->m_pkthdr.len = m->m_len = m->m_ext.ext_size; error = bus_dmamap_load_mbuf_sg(sc->sc_dmat, @@ -2502,10 +2603,12 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) "%s: bus_dmamap_load_mbuf_sg failed; error %d\n", __func__, error); sc->sc_stats.ast_rx_busdma++; + m_freem(m); return error; } KASSERT(bf->bf_nseg == 1, ("multi-segment packet; nseg %u", bf->bf_nseg)); + bf->bf_m = m; } bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREREAD); @@ -2527,6 +2630,7 @@ ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) ds = bf->bf_desc; ds->ds_link = bf->bf_daddr; /* link to self */ ds->ds_data = bf->bf_segs[0].ds_addr; + ds->ds_vdata = mtod(m, void *); /* for radar */ ath_hal_setuprxdesc(ah, ds , m->m_len /* buffer size */ , 0 @@ -2569,7 +2673,15 @@ ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m, switch (subtype) { case IEEE80211_FC0_SUBTYPE_BEACON: /* update rssi statistics for use by the hal */ - ATH_RSSI_LPF(ATH_NODE(ni)->an_halstats.ns_avgbrssi, rssi); + ATH_RSSI_LPF(sc->sc_halstats.ns_avgbrssi, rssi); + if (sc->sc_syncbeacon && + ni == ic->ic_bss && ic->ic_state == IEEE80211_S_RUN) { + /* + * Resync beacon timers using the tsf of the beacon + * frame we just received. + */ + ath_beacon_config(sc); + } /* fall thru... */ case IEEE80211_FC0_SUBTYPE_PROBE_RESP: if (ic->ic_opmode == IEEE80211_M_IBSS && @@ -2663,7 +2775,7 @@ ath_rx_proc(void *arg, int npending) struct mbuf *m; struct ieee80211_node *ni; struct ath_node *an; - int len, type; + int len, type, ngood; u_int phyerr; HAL_STATUS status; int16_t nf; @@ -2672,6 +2784,7 @@ ath_rx_proc(void *arg, int npending) NET_LOCK_GIANT(); /* XXX */ DPRINTF(sc, ATH_DEBUG_RX_PROC, "%s: pending %u\n", __func__, npending); + ngood = 0; nf = ath_hal_getchannoise(ah, &sc->sc_curchan); tsf = ath_hal_gettsf64(ah); do { @@ -2680,16 +2793,22 @@ ath_rx_proc(void *arg, int npending) if_printf(ifp, "%s: no buffer!\n", __func__); break; } + m = bf->bf_m; + if (m == NULL) { /* NB: shouldn't happen */ + /* + * If mbuf allocation failed previously there + * will be no mbuf; try again to re-populate it. + */ + /* XXX make debug msg */ + if_printf(ifp, "%s: no mbuf!\n", __func__); + STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); + goto rx_next; + } ds = bf->bf_desc; if (ds->ds_link == bf->bf_daddr) { /* NB: never process the self-linked entry at the end */ break; } - m = bf->bf_m; - if (m == NULL) { /* NB: shouldn't happen */ - if_printf(ifp, "%s: no mbuf!\n", __func__); - continue; - } /* XXX sync descriptor memory */ /* * Must provide the virtual address of the current @@ -2846,6 +2965,7 @@ rx_accept: */ an = ATH_NODE(ni); ATH_RSSI_LPF(an->an_avgrssi, ds->ds_rxstat.rs_rssi); + ATH_RSSI_LPF(sc->sc_halstats.ns_avgrssi, ds->ds_rxstat.rs_rssi); /* * Send frame up for processing. */ @@ -2878,12 +2998,24 @@ rx_accept: } else if (ticks - sc->sc_ledevent >= sc->sc_ledidle) ath_led_event(sc, ATH_LED_POLL); } + /* + * Arrange to update the last rx timestamp only for + * frames from our ap when operating in station mode. + * This assumes the rx key is always setup when associated. + */ + if (ic->ic_opmode == IEEE80211_M_STA && + ds->ds_rxstat.rs_keyix != HAL_RXKEYIX_INVALID) + ngood++; rx_next: STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); } while (ath_rxbuf_init(sc, bf) == 0); /* rx signal state monitoring */ - ath_hal_rxmonitor(ah, &ATH_NODE(ic->ic_bss)->an_halstats); + ath_hal_rxmonitor(ah, &sc->sc_halstats, &sc->sc_curchan); + if (ath_hal_radar_event(ah)) + taskqueue_enqueue(sc->sc_tq, &sc->sc_radartask); + if (ngood) + sc->sc_lastrx = tsf; NET_UNLOCK_GIANT(); /* XXX */ #undef PA2DESC @@ -2917,7 +3049,7 @@ ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) * up in which case the top half of the kernel may backup * due to a lack of tx descriptors. */ - qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; + qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE; qnum = ath_hal_setuptxqueue(ah, qtype, &qi); if (qnum == -1) { /* @@ -3134,6 +3266,20 @@ bad: return NULL; } +/* + * Return h/w rate index for an IEEE rate (w/o basic rate bit). + */ +static int +ath_tx_findrix(const HAL_RATE_TABLE *rt, int rate) +{ + int i; + + for (i = 0; i < rt->rateCount; i++) + if ((rt->info[i].dot11Rate & IEEE80211_RATE_VAL) == rate) + return i; + return 0; /* NB: lowest rate */ +} + static int ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, struct mbuf *m0) @@ -3142,7 +3288,8 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf struct ath_hal *ah = sc->sc_ah; struct ifnet *ifp = sc->sc_ifp; const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams; - int i, error, iswep, ismcast, keyix, hdrlen, pktlen, try0; + int i, error, iswep, ismcast, ismrr; + int keyix, hdrlen, pktlen, try0; u_int8_t rix, txrate, ctsrate; u_int8_t cix = 0xff; /* NB: silence compiler */ struct ath_desc *ds, *ds0; @@ -3190,7 +3337,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf * Adjust the packet + header lengths for the crypto * additions and calculate the h/w key index. When * a s/w mic is done the frame will have had any mic - * added to it prior to entry so skb->len above will + * added to it prior to entry so m0->m_pkthdr.len above will * account for it. Otherwise we need to add it to the * packet length. */ @@ -3284,6 +3431,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf an = ATH_NODE(ni); flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ + ismrr = 0; /* default no multi-rate retry*/ /* * Calculate Atheros packet type from IEEE80211 packet header, * setup for rate calculations, and select h/w transmit queue. @@ -3299,12 +3447,11 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf atype = HAL_PKT_TYPE_ATIM; else atype = HAL_PKT_TYPE_NORMAL; /* XXX */ - rix = 0; /* XXX lowest rate */ - try0 = ATH_TXMAXTRY; + rix = sc->sc_minrateix; + txrate = rt->info[rix].rateCode; if (shortPreamble) - txrate = an->an_tx_mgtratesp; - else - txrate = an->an_tx_mgtrate; + txrate |= rt->info[rix].shortPreamble; + try0 = ATH_TXMGTTRY; /* NB: force all management frames to highest queue */ if (ni->ni_flags & IEEE80211_NODE_QOS) { /* NB: force all management frames to highest queue */ @@ -3315,12 +3462,11 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf break; case IEEE80211_FC0_TYPE_CTL: atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */ - rix = 0; /* XXX lowest rate */ - try0 = ATH_TXMAXTRY; + rix = sc->sc_minrateix; + txrate = rt->info[rix].rateCode; if (shortPreamble) - txrate = an->an_tx_mgtratesp; - else - txrate = an->an_tx_mgtrate; + txrate |= rt->info[rix].shortPreamble; + try0 = ATH_TXMGTTRY; /* NB: force all ctl frames to highest queue */ if (ni->ni_flags & IEEE80211_NODE_QOS) { /* NB: force all ctl frames to highest queue */ @@ -3332,22 +3478,35 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf case IEEE80211_FC0_TYPE_DATA: atype = HAL_PKT_TYPE_NORMAL; /* default */ /* - * Data frames; consult the rate control module. + * Data frames: multicast frames go out at a fixed rate, + * otherwise consult the rate control module for the + * rate to use. */ - ath_rate_findrate(sc, an, shortPreamble, pktlen, - &rix, &try0, &txrate); - sc->sc_txrate = txrate; /* for LED blinking */ - /* - * Default all non-QoS traffic to the background queue. - */ - if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { - pri = M_WME_GETAC(m0); - if (cap->cap_wmeParams[pri].wmep_noackPolicy) { - flags |= HAL_TXDESC_NOACK; - sc->sc_stats.ast_tx_noack++; + if (ismcast) { + /* + * Check mcast rate setting in case it's changed. + * XXX move out of fastpath + */ + if (ic->ic_mcast_rate != sc->sc_mcastrate) { + sc->sc_mcastrix = + ath_tx_findrix(rt, ic->ic_mcast_rate); + sc->sc_mcastrate = ic->ic_mcast_rate; } - } else - pri = WME_AC_BE; + rix = sc->sc_mcastrix; + txrate = rt->info[rix].rateCode; + if (shortPreamble) + txrate |= rt->info[rix].shortPreamble; + try0 = 1; + } else { + ath_rate_findrate(sc, an, shortPreamble, pktlen, + &rix, &try0, &txrate); + sc->sc_txrate = txrate; /* for LED blinking */ + if (try0 != ATH_TXMAXTRY) + ismrr = 1; + } + pri = M_WME_GETAC(m0); + if (cap->cap_wmeParams[pri].wmep_noackPolicy) + flags |= HAL_TXDESC_NOACK; break; default: if_printf(ifp, "bogus frame type 0x%x (%s)\n", @@ -3373,12 +3532,13 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf */ if (ismcast) { flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ - sc->sc_stats.ast_tx_noack++; } else if (pktlen > ic->ic_rtsthreshold) { flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */ cix = rt->info[rix].controlRate; sc->sc_stats.ast_tx_rts++; } + if (flags & HAL_TXDESC_NOACK) /* NB: avoid double counting */ + sc->sc_stats.ast_tx_noack++; /* * If 802.11g protection is enabled, determine whether @@ -3455,7 +3615,8 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf /* * Must disable multi-rate retry when using RTS/CTS. */ - try0 = ATH_TXMAXTRY; + ismrr = 0; + try0 = ATH_TXMGTTRY; /* XXX */ } else ctsrate = 0; @@ -3526,7 +3687,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf * when the hardware supports multi-rate retry and * we don't use it. */ - if (try0 != ATH_TXMAXTRY) + if (ismrr) ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix); /* @@ -3584,7 +3745,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf /* * Process completed xmit descriptors from the specified queue. */ -static void +static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hal *ah = sc->sc_ah; @@ -3593,13 +3754,14 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) struct ath_desc *ds, *ds0; struct ieee80211_node *ni; struct ath_node *an; - int sr, lr, pri; + int sr, lr, pri, nacked; HAL_STATUS status; DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: tx queue %u head %p link %p\n", __func__, txq->axq_qnum, (caddr_t)(uintptr_t) ath_hal_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); + nacked = 0; for (;;) { ATH_TXQ_LOCK(txq); txq->axq_intrcnt = 0; /* reset periodic desc intr count */ @@ -3635,7 +3797,7 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) sc->sc_stats.ast_tx_altrate++; sc->sc_stats.ast_tx_rssi = ds->ds_txstat.ts_rssi; - ATH_RSSI_LPF(an->an_halstats.ns_avgtxrssi, + ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi, ds->ds_txstat.ts_rssi); pri = M_WME_GETAC(bf->bf_m); if (pri >= WME_AC_VO) @@ -3657,8 +3819,15 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) * Hand the descriptor to the rate control algorithm. */ if ((ds->ds_txstat.ts_status & HAL_TXERR_FILT) == 0 && - (bf->bf_flags & HAL_TXDESC_NOACK) == 0) + (bf->bf_flags & HAL_TXDESC_NOACK) == 0) { + /* + * If frame was ack'd update the last rx time + * used to workaround phantom bmiss interrupts. + */ + if (ds->ds_txstat.ts_status == 0) + nacked++; ath_rate_tx_complete(sc, an, ds, ds0); + } /* * Reclaim reference to node. * @@ -3679,6 +3848,14 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); ATH_TXBUF_UNLOCK(sc); } + return nacked; +} + +static __inline int +txqactive(struct ath_hal *ah, int qnum) +{ + /* XXX not yet */ + return 1; } /* @@ -3691,7 +3868,10 @@ ath_tx_proc_q0(void *arg, int npending) struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; - ath_tx_processq(sc, &sc->sc_txq[0]); + if (txqactive(sc->sc_ah, 0) && ath_tx_processq(sc, &sc->sc_txq[0])) + sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); + if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) + ath_tx_processq(sc, sc->sc_cabq); ath_tx_processq(sc, sc->sc_cabq); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_tx_timer = 0; @@ -3711,15 +3891,24 @@ ath_tx_proc_q0123(void *arg, int npending) { struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; + int nacked; /* * Process each active queue. */ - ath_tx_processq(sc, &sc->sc_txq[0]); - ath_tx_processq(sc, &sc->sc_txq[1]); - ath_tx_processq(sc, &sc->sc_txq[2]); - ath_tx_processq(sc, &sc->sc_txq[3]); - ath_tx_processq(sc, sc->sc_cabq); + nacked = 0; + if (txqactive(sc->sc_ah, 0)) + nacked += ath_tx_processq(sc, &sc->sc_txq[0]); + if (txqactive(sc->sc_ah, 1)) + nacked += ath_tx_processq(sc, &sc->sc_txq[1]); + if (txqactive(sc->sc_ah, 2)) + nacked += ath_tx_processq(sc, &sc->sc_txq[2]); + if (txqactive(sc->sc_ah, 3)) + nacked += ath_tx_processq(sc, &sc->sc_txq[3]); + if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum)) + ath_tx_processq(sc, sc->sc_cabq); + if (nacked) + sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_tx_timer = 0; @@ -3738,15 +3927,17 @@ ath_tx_proc(void *arg, int npending) { struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; - int i; + int i, nacked; /* * Process each active queue. */ - /* XXX faster to read ISR_S0_S and ISR_S1_S to determine q's? */ + nacked = 0; for (i = 0; i < HAL_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_processq(sc, &sc->sc_txq[i]); + if (ATH_TXQ_SETUP(sc, i) && txqactive(sc->sc_ah, i)) + nacked += ath_tx_processq(sc, &sc->sc_txq[i]); + if (nacked) + sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah); ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; sc->sc_tx_timer = 0; @@ -3939,6 +4130,42 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan) htole16(flags); } +/* + * Poll for a channel clear indication; this is required + * for channels requiring DFS and not previously visited + * and/or with a recent radar detection. + */ +static void +ath_dfswait(void *arg) +{ + struct ath_softc *sc = arg; + struct ath_hal *ah = sc->sc_ah; + HAL_CHANNEL hchan; + + ath_hal_radar_wait(ah, &hchan); + DPRINTF(sc, ATH_DEBUG_DFS, "%s: radar_wait %u/%x/%x\n", + __func__, hchan.channel, hchan.channelFlags, hchan.privFlags); + + if (hchan.privFlags & CHANNEL_INTERFERENCE) { + if_printf(sc->sc_ifp, + "channel %u/0x%x/0x%x has interference\n", + hchan.channel, hchan.channelFlags, hchan.privFlags); + return; + } + if ((hchan.privFlags & CHANNEL_DFS) == 0) { + /* XXX should not happen */ + return; + } + if (hchan.privFlags & CHANNEL_DFS_CLEAR) { + sc->sc_curchan.privFlags |= CHANNEL_DFS_CLEAR; + sc->sc_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if_printf(sc->sc_ifp, + "channel %u/0x%x/0x%x marked clear\n", + hchan.channel, hchan.channelFlags, hchan.privFlags); + } else + callout_reset(&sc->sc_dfs_ch, 2 * hz, ath_dfswait, sc); +} + /* * Set/change channels. If the channel is really being changed, * it's done by reseting the chip. To accomplish this we must @@ -3960,12 +4187,14 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) hchan.channel = chan->ic_freq; hchan.channelFlags = ath_chan2flags(ic, chan); - DPRINTF(sc, ATH_DEBUG_RESET, "%s: %u (%u MHz) -> %u (%u MHz)\n", + DPRINTF(sc, ATH_DEBUG_RESET, + "%s: %u (%u MHz, hal flags 0x%x) -> %u (%u MHz, hal flags 0x%x)\n", __func__, - ath_hal_mhz2ieee(sc->sc_curchan.channel, + ath_hal_mhz2ieee(ah, sc->sc_curchan.channel, sc->sc_curchan.channelFlags), - sc->sc_curchan.channel, - ath_hal_mhz2ieee(hchan.channel, hchan.channelFlags), hchan.channel); + sc->sc_curchan.channel, sc->sc_curchan.channelFlags, + ath_hal_mhz2ieee(ah, hchan.channel, hchan.channelFlags), + hchan.channel, hchan.channelFlags); if (hchan.channel != sc->sc_curchan.channel || hchan.channelFlags != sc->sc_curchan.channelFlags) { HAL_STATUS status; @@ -3979,22 +4208,25 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) ath_hal_intrset(ah, 0); /* disable interrupts */ ath_draintxq(sc); /* clear pending tx frames */ ath_stoprecv(sc); /* turn off frame recv */ - if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) { - if_printf(ic->ic_ifp, "ath_chan_set: unable to reset " - "channel %u (%u Mhz)\n", - ieee80211_chan2ieee(ic, chan), chan->ic_freq); + if (!ath_hal_reset(ah, sc->sc_opmode, &hchan, AH_TRUE, &status)) { + if_printf(ic->ic_ifp, "%s: unable to reset " + "channel %u (%u Mhz, flags 0x%x hal flags 0x%x)\n", + __func__, ieee80211_chan2ieee(ic, chan), + chan->ic_freq, chan->ic_flags, hchan.channelFlags); return EIO; } sc->sc_curchan = hchan; ath_update_txpow(sc); /* update tx power state */ sc->sc_diversity = ath_hal_getdiversity(ah); + sc->sc_calinterval = 1; + sc->sc_caltries = 0; /* * Re-enable rx framework. */ if (ath_startrecv(sc) != 0) { if_printf(ic->ic_ifp, - "ath_chan_set: unable to restart recv logic\n"); + "%s: unable to restart recv logic\n", __func__); return EIO; } @@ -4005,6 +4237,25 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan) ic->ic_ibss_chan = chan; ath_chan_change(sc, chan); + /* + * Handle DFS required waiting period to determine + * if channel is clear of radar traffic. + */ + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { +#define DFS_AND_NOT_CLEAR(_c) \ + (((_c)->privFlags & (CHANNEL_DFS | CHANNEL_DFS_CLEAR)) == CHANNEL_DFS) + if (DFS_AND_NOT_CLEAR(&sc->sc_curchan)) { + if_printf(sc->sc_ifp, + "wait for DFS clear channel signal\n"); + /* XXX stop sndq */ + sc->sc_ifp->if_drv_flags |= IFF_DRV_OACTIVE; + callout_reset(&sc->sc_dfs_ch, + 2 * hz, ath_dfswait, sc); + } else + callout_stop(&sc->sc_dfs_ch); +#undef DFS_NOT_CLEAR + } + /* * Re-enable interrupts. */ @@ -4032,21 +4283,21 @@ ath_calibrate(void *arg) { struct ath_softc *sc = arg; struct ath_hal *ah = sc->sc_ah; + HAL_BOOL iqCalDone; sc->sc_stats.ast_per_cal++; - DPRINTF(sc, ATH_DEBUG_CALIBRATE, "%s: channel %u/%x\n", - __func__, sc->sc_curchan.channel, sc->sc_curchan.channelFlags); - if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) { /* * Rfgain is out of bounds, reset the chip * to load new gain values. */ + DPRINTF(sc, ATH_DEBUG_CALIBRATE, + "%s: rfgain change\n", __func__); sc->sc_stats.ast_per_rfgain++; ath_reset(sc->sc_ifp); } - if (!ath_hal_calibrate(ah, &sc->sc_curchan)) { + if (!ath_hal_calibrate(ah, &sc->sc_curchan, &iqCalDone)) { DPRINTF(sc, ATH_DEBUG_ANY, "%s: calibration of channel %u failed\n", __func__, sc->sc_curchan.channel); @@ -4056,7 +4307,30 @@ ath_calibrate(void *arg) * Calibrate noise floor data again in case of change. */ ath_hal_process_noisefloor(ah); - callout_reset(&sc->sc_cal_ch, ath_calinterval * hz, ath_calibrate, sc); + /* + * Poll more frequently when the IQ calibration is in + * progress to speedup loading the final settings. + * We temper this aggressive polling with an exponential + * back off after 4 tries up to ath_calinterval. + */ + if (iqCalDone || sc->sc_calinterval >= ath_calinterval) { + sc->sc_caltries = 0; + sc->sc_calinterval = ath_calinterval; + } else if (sc->sc_caltries > 4) { + sc->sc_caltries = 0; + sc->sc_calinterval <<= 1; + if (sc->sc_calinterval > ath_calinterval) + sc->sc_calinterval = ath_calinterval; + } + KASSERT(0 < sc->sc_calinterval && sc->sc_calinterval <= ath_calinterval, + ("bad calibration interval %u", sc->sc_calinterval)); + + DPRINTF(sc, ATH_DEBUG_CALIBRATE, + "%s: next +%u (%siqCalDone tries %u)\n", __func__, + sc->sc_calinterval, iqCalDone ? "" : "!", sc->sc_caltries); + sc->sc_caltries++; + callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, + ath_calibrate, sc); } static int @@ -4083,6 +4357,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) callout_stop(&sc->sc_scan_ch); callout_stop(&sc->sc_cal_ch); + callout_stop(&sc->sc_dfs_ch); ath_hal_setledstate(ah, leds[nstate]); /* set LED */ if (nstate == IEEE80211_S_INIT) { @@ -4156,6 +4431,17 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) error = ath_beacon_alloc(sc, ni); if (error != 0) goto bad; + /* + * If joining an adhoc network defer beacon timer + * configuration to the next beacon frame so we + * have a current TSF to use. Otherwise we're + * starting an ibss/bss so there's no need to delay. + */ + if (ic->ic_opmode == IEEE80211_M_IBSS && + ic->ic_bss->ni_tstamp.tsf != 0) + sc->sc_syncbeacon = 1; + else + ath_beacon_config(sc); break; case IEEE80211_M_STA: /* @@ -4165,6 +4451,12 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) sc->sc_hasclrkey && ni->ni_ucastkey.wk_keyix == IEEE80211_KEYIX_NONE) ath_setup_stationkey(ni); + /* + * Defer beacon timer configuration to the next + * beacon frame so we have a current TSF to use + * (any TSF collected when scanning is likely old). + */ + sc->sc_syncbeacon = 1; break; default: break; @@ -4176,9 +4468,11 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) */ ath_hal_process_noisefloor(ah); /* - * Configure the beacon and sleep timers. + * Reset rssi stats; maybe not the best place... */ - ath_beacon_config(sc); + sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; } else { ath_hal_intrset(ah, sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS)); @@ -4194,7 +4488,7 @@ done: */ if (nstate == IEEE80211_S_RUN) { /* start periodic recalibration timer */ - callout_reset(&sc->sc_cal_ch, ath_calinterval * hz, + callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz, ath_calibrate, sc); } else if (nstate == IEEE80211_S_SCAN) { /* start ap/neighbor scan timer */ @@ -4261,6 +4555,7 @@ static int ath_getchannels(struct ath_softc *sc, u_int cc, HAL_BOOL outdoor, HAL_BOOL xchanmode) { +#define COMPAT (CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE) struct ieee80211com *ic = &sc->sc_ic; struct ifnet *ifp = sc->sc_ifp; struct ath_hal *ah = sc->sc_ah; @@ -4274,6 +4569,7 @@ ath_getchannels(struct ath_softc *sc, u_int cc, return ENOMEM; } if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, + NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) { u_int32_t rd; @@ -4290,23 +4586,42 @@ ath_getchannels(struct ath_softc *sc, u_int cc, */ for (i = 0; i < nchan; i++) { HAL_CHANNEL *c = &chans[i]; - ix = ath_hal_mhz2ieee(c->channel, c->channelFlags); + u_int16_t flags; + + ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags); if (ix > IEEE80211_CHAN_MAX) { - if_printf(ifp, "bad hal channel %u (%u/%x) ignored\n", + if_printf(ifp, "bad hal channel %d (%u/%x) ignored\n", ix, c->channel, c->channelFlags); continue; } - /* NB: flags are known to be compatible */ + if (ix < 0) { + /* XXX can't handle stuff <2400 right now */ + if (bootverbose) + if_printf(ifp, "hal channel %d (%u/%x) " + "cannot be handled; ignored\n", + ix, c->channel, c->channelFlags); + continue; + } + /* + * Calculate net80211 flags; most are compatible + * but some need massaging. Note the static turbo + * conversion can be removed once net80211 is updated + * to understand static vs. dynamic turbo. + */ + flags = c->channelFlags & COMPAT; + if (c->channelFlags & CHANNEL_STURBO) + flags |= IEEE80211_CHAN_TURBO; if (ic->ic_channels[ix].ic_freq == 0) { ic->ic_channels[ix].ic_freq = c->channel; - ic->ic_channels[ix].ic_flags = c->channelFlags; + ic->ic_channels[ix].ic_flags = flags; } else { /* channels overlap; e.g. 11g and 11b */ - ic->ic_channels[ix].ic_flags |= c->channelFlags; + ic->ic_channels[ix].ic_flags |= flags; } } free(chans, M_TEMP); return 0; +#undef COMPAT } static void @@ -4386,51 +4701,59 @@ ath_update_txpow(struct ath_softc *sc) ic->ic_bss->ni_txpower = txpow; } +static void +rate_setup(struct ath_softc *sc, + const HAL_RATE_TABLE *rt, struct ieee80211_rateset *rs) +{ + int i, maxrates; + + if (rt->rateCount > IEEE80211_RATE_MAXSIZE) { + DPRINTF(sc, ATH_DEBUG_ANY, + "%s: rate table too small (%u > %u)\n", + __func__, rt->rateCount, IEEE80211_RATE_MAXSIZE); + maxrates = IEEE80211_RATE_MAXSIZE; + } else + maxrates = rt->rateCount; + for (i = 0; i < maxrates; i++) + rs->rs_rates[i] = rt->info[i].dot11Rate; + rs->rs_nrates = maxrates; +} + static int ath_rate_setup(struct ath_softc *sc, u_int mode) { struct ath_hal *ah = sc->sc_ah; struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; - struct ieee80211_rateset *rs; - int i, maxrates; switch (mode) { case IEEE80211_MODE_11A: - sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A); + rt = ath_hal_getratetable(ah, HAL_MODE_11A); break; case IEEE80211_MODE_11B: - sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11B); + rt = ath_hal_getratetable(ah, HAL_MODE_11B); break; case IEEE80211_MODE_11G: - sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11G); + rt = ath_hal_getratetable(ah, HAL_MODE_11G); break; case IEEE80211_MODE_TURBO_A: - sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_TURBO); + /* XXX until static/dynamic turbo is fixed */ + rt = ath_hal_getratetable(ah, HAL_MODE_TURBO); break; case IEEE80211_MODE_TURBO_G: - sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_108G); + rt = ath_hal_getratetable(ah, HAL_MODE_108G); break; default: DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid mode %u\n", __func__, mode); return 0; } - rt = sc->sc_rates[mode]; - if (rt == NULL) - return 0; - if (rt->rateCount > IEEE80211_RATE_MAXSIZE) { - DPRINTF(sc, ATH_DEBUG_ANY, - "%s: rate table too small (%u > %u)\n", - __func__, rt->rateCount, IEEE80211_RATE_MAXSIZE); - maxrates = IEEE80211_RATE_MAXSIZE; + sc->sc_rates[mode] = rt; + if (rt != NULL) { + rate_setup(sc, rt, &ic->ic_sup_rates[mode]); + return 1; } else - maxrates = rt->rateCount; - rs = &ic->ic_sup_rates[mode]; - for (i = 0; i < maxrates; i++) - rs->rs_rates[i] = rt->info[i].dot11Rate; - rs->rs_nrates = maxrates; - return 1; + return 0; } static void @@ -4497,9 +4820,19 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) /* * All protection frames are transmited at 2Mb/s for * 11g, otherwise at 1Mb/s. - * XXX select protection rate index from rate table. */ - sc->sc_protrix = (mode == IEEE80211_MODE_11G ? 1 : 0); + if (mode == IEEE80211_MODE_11G) + sc->sc_protrix = ath_tx_findrix(rt, 2*2); + else + sc->sc_protrix = ath_tx_findrix(rt, 2*1); + /* rate index used to send management frames */ + sc->sc_minrateix = 0; + /* + * Setup multicast rate state. + */ + /* XXX layering violation */ + sc->sc_mcastrix = ath_tx_findrix(rt, sc->sc_ic.ic_mcast_rate); + sc->sc_mcastrate = sc->sc_ic.ic_mcast_rate; /* NB: caller is responsible for reseting rate control state */ #undef N } @@ -4512,7 +4845,7 @@ ath_printrxbuf(struct ath_buf *bf, int done) int i; for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { - printf("R%d (%p %p) %08x %08x %08x %08x %08x %08x %c\n", + printf("R%d (%p %p) L:%08x D:%08x %08x %08x %08x %08x %c\n", i, ds, (struct ath_desc *)bf->bf_daddr + i, ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, @@ -4528,7 +4861,7 @@ ath_printtxbuf(struct ath_buf *bf, int done) int i; for (i = 0, ds = bf->bf_desc; i < bf->bf_nseg; i++, ds++) { - printf("T%d (%p %p) %08x %08x %08x %08x %08x %08x %08x %08x %c\n", + printf("T%d (%p %p) L:%08x D:%08x %08x %08x %08x %08x %08x %08x %c\n", i, ds, (struct ath_desc *)bf->bf_daddr + i, ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, @@ -4833,6 +5166,86 @@ ath_sysctl_tpc(SYSCTL_HANDLER_ARGS) return !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0; } +static int +ath_sysctl_rfkill(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + struct ath_hal *ah = sc->sc_ah; + u_int rfkill = ath_hal_getrfkill(ah); + int error; + + error = sysctl_handle_int(oidp, &rfkill, 0, req); + if (error || !req->newptr) + return error; + if (rfkill == ath_hal_getrfkill(ah)) /* unchanged */ + return 0; + if (!ath_hal_setrfkill(ah, rfkill) || ath_reset(sc->sc_ifp) != 0) + return EINVAL; + else + return 0; +} + +static int +ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int rfsilent; + int error; + + ath_hal_getrfsilent(sc->sc_ah, &rfsilent); + error = sysctl_handle_int(oidp, &rfsilent, 0, req); + if (error || !req->newptr) + return error; + if (!ath_hal_setrfsilent(sc->sc_ah, rfsilent)) + return EINVAL; + sc->sc_rfsilentpin = rfsilent & 0x1c; + sc->sc_rfsilentpol = (rfsilent & 0x2) != 0; + return 0; +} + +static int +ath_sysctl_regdomain(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int32_t rd; + int error; + + if (!ath_hal_getregdomain(sc->sc_ah, &rd)) + return EINVAL; + error = sysctl_handle_int(oidp, &rd, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_setregdomain(sc->sc_ah, rd) ? EINVAL : 0; +} + +static int +ath_sysctl_tpack(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int32_t tpack; + int error; + + ath_hal_gettpack(sc->sc_ah, &tpack); + error = sysctl_handle_int(oidp, &tpack, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_settpack(sc->sc_ah, tpack) ? EINVAL : 0; +} + +static int +ath_sysctl_tpcts(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int32_t tpcts; + int error; + + ath_hal_gettpcts(sc->sc_ah, &tpcts); + error = sysctl_handle_int(oidp, &tpcts, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_settpcts(sc->sc_ah, tpcts) ? EINVAL : 0; +} + static void ath_sysctlattach(struct ath_softc *sc) { @@ -4844,10 +5257,9 @@ ath_sysctlattach(struct ath_softc *sc) SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "countrycode", CTLFLAG_RD, &sc->sc_countrycode, 0, "EEPROM country code"); - ath_hal_getregdomain(sc->sc_ah, &sc->sc_regdomain); - SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, - "regdomain", CTLFLAG_RD, &sc->sc_regdomain, 0, - "EEPROM regdomain code"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "regdomain", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_regdomain, "I", "EEPROM regdomain code"); sc->sc_debug = ath_debug; SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->sc_debug, 0, @@ -4894,10 +5306,25 @@ ath_sysctlattach(struct ath_softc *sc) SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tpscale", CTLTYPE_INT | CTLFLAG_RW, sc, 0, ath_sysctl_tpscale, "I", "tx power scaling"); - if (ath_hal_hastpc(ah)) + if (ath_hal_hastpc(ah)) { SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tpc", CTLTYPE_INT | CTLFLAG_RW, sc, 0, ath_sysctl_tpc, "I", "enable/disable per-packet TPC"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "tpack", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_tpack, "I", "tx power for ack frames"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "tpcts", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_tpcts, "I", "tx power for cts frames"); + } + if (ath_hal_hasrfsilent(ah)) { + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_rfsilent, "I", "h/w RF silent config"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "rfkill", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_rfkill, "I", "enable/disable RF kill switch"); + } sc->sc_monpass = HAL_RXERR_DECRYPT | HAL_RXERR_MIC; SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "monpass", CTLFLAG_RW, &sc->sc_monpass, 0, @@ -4976,5 +5403,9 @@ ath_announce(struct ath_softc *sc) sc->sc_cabq->axq_qnum); if_printf(ifp, "Use hw queue %u for beacons\n", sc->sc_bhalq); } + if (ath_rxbuf != ATH_RXBUF) + if_printf(ifp, "using %u rx buffers\n", ath_rxbuf); + if (ath_txbuf != ATH_TXBUF) + if_printf(ifp, "using %u tx buffers\n", ath_txbuf); #undef HAL_MODE_DUALBAND } diff --git a/sys/dev/ath/if_athioctl.h b/sys/dev/ath/if_athioctl.h index 31e66971ffac..7184a11badec 100644 --- a/sys/dev/ath/if_athioctl.h +++ b/sys/dev/ath/if_athioctl.h @@ -46,6 +46,7 @@ struct ath_stats { u_int32_t ast_watchdog; /* device reset by watchdog */ u_int32_t ast_hardware; /* fatal hardware error interrupts */ u_int32_t ast_bmiss; /* beacon miss interrupts */ + u_int32_t ast_bmiss_phantom;/* beacon miss interrupts */ u_int32_t ast_bstuck; /* beacon stuck interrupts */ u_int32_t ast_rxorn; /* rx overrun interrupts */ u_int32_t ast_rxeol; /* rx eol interrupts */ @@ -105,6 +106,7 @@ struct ath_stats { u_int32_t ast_ant_txswitch;/* tx antenna switches */ u_int32_t ast_ant_rx[8]; /* rx frames with antenna */ u_int32_t ast_ant_tx[8]; /* tx frames with antenna */ + u_int32_t ast_pad[32]; }; #define SIOCGATHSTATS _IOWR('i', 137, struct ifreq) diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 7203e3142ae6..71a99d9d91ae 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -51,10 +51,15 @@ #define ATH_TIMEOUT 1000 +#ifndef ATH_RXBUF #define ATH_RXBUF 40 /* number of RX buffers */ +#endif +#ifndef ATH_TXBUF #define ATH_TXBUF 100 /* number of TX buffers */ +#endif #define ATH_TXDESC 10 /* number of descriptors per buffer */ #define ATH_TXMAXTRY 11 /* max number of transmit attempts */ +#define ATH_TXMGTTRY 4 /* xmit attempts for mgt/ctl frames */ #define ATH_TXINTR_PERIOD 5 /* max number of batched tx descriptors */ #define ATH_BEACON_AIFS_DEFAULT 0 /* default aifs for ap beacon q */ @@ -75,10 +80,7 @@ /* driver-specific node state */ struct ath_node { struct ieee80211_node an_node; /* base class */ - u_int8_t an_tx_mgtrate; /* h/w rate for management/ctl frames */ - u_int8_t an_tx_mgtratesp;/* short preamble h/w rate for " " */ u_int32_t an_avgrssi; /* average rssi over all rx frames */ - HAL_NODE_STATS an_halstats; /* rssi statistics used by hal */ /* variable-length rate control state follows */ }; #define ATH_NODE(ni) ((struct ath_node *)(ni)) @@ -140,11 +142,14 @@ struct ath_txq { u_int32_t *axq_link; /* link ptr in last TX desc */ STAILQ_HEAD(, ath_buf) axq_q; /* transmit queue */ struct mtx axq_lock; /* lock on q and link */ + char axq_name[12]; /* e.g. "ath0_txq4" */ }; -#define ATH_TXQ_LOCK_INIT(_sc, _tq) \ - mtx_init(&(_tq)->axq_lock, \ - device_get_nameunit((_sc)->sc_dev), "xmit q", MTX_DEF) +#define ATH_TXQ_LOCK_INIT(_sc, _tq) do { \ + snprintf((_tq)->axq_name, sizeof((_tq)->axq_name), "%s_txq%u", \ + device_get_nameunit((_sc)->sc_dev), (_tq)->axq_qnum); \ + mtx_init(&(_tq)->axq_lock, (_tq)->axq_name, "ath_txq", MTX_DEF); \ +} while (0); #define ATH_TXQ_LOCK_DESTROY(_tq) mtx_destroy(&(_tq)->axq_lock) #define ATH_TXQ_LOCK(_tq) mtx_lock(&(_tq)->axq_lock) #define ATH_TXQ_UNLOCK(_tq) mtx_unlock(&(_tq)->axq_lock) @@ -159,11 +164,13 @@ struct ath_txq { (_tq)->axq_depth--; \ } while (0) +struct taskqueue; +struct ath_tx99; + struct ath_softc { struct ifnet *sc_ifp; /* interface common */ struct ath_stats sc_stats; /* interface statistics */ struct ieee80211com sc_ic; /* IEEE 802.11 common */ - int sc_regdomain; int sc_countrycode; int sc_debug; void (*sc_recv_mgmt)(struct ieee80211com *, @@ -178,8 +185,11 @@ struct ath_softc { bus_space_handle_t sc_sh; /* bus space handle */ bus_dma_tag_t sc_dmat; /* bus DMA tag */ struct mtx sc_mtx; /* master lock (recursive) */ + struct taskqueue *sc_tq; /* private task queue */ + struct proc *sc_tqproc; struct ath_hal *sc_ah; /* Atheros HAL */ struct ath_ratectrl *sc_rc; /* tx rate control support */ + struct ath_tx99 *sc_tx99; /* tx99 adjunct state */ void (*sc_setdefantenna)(struct ath_softc *, u_int); unsigned int sc_invalid : 1, /* disable hardware accesses */ sc_mrretry : 1, /* multi-rate retry support */ @@ -191,11 +201,13 @@ struct ath_softc { sc_ledstate: 1, /* LED on/off state */ sc_blinking: 1, /* LED blink operation active */ sc_mcastkey: 1, /* mcast key cache search */ + sc_syncbeacon:1,/* sync/resync beacon timers */ sc_hasclrkey:1; /* CLR key supported */ /* rate tables */ const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX]; const HAL_RATE_TABLE *sc_currates; /* current rate table */ enum ieee80211_phymode sc_curmode; /* current phy mode */ + HAL_OPMODE sc_opmode; /* current operating mode */ u_int16_t sc_curtxpow; /* current tx power limit */ HAL_CHANNEL sc_curchan; /* current h/w channel */ u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */ @@ -206,7 +218,10 @@ struct ath_softc { u_int16_t ledon; /* softled on time */ u_int16_t ledoff; /* softled off time */ } sc_hwmap[32]; /* h/w rate ix mappings */ + u_int8_t sc_minrateix; /* min h/w rate index */ + u_int8_t sc_mcastrix; /* mcast h/w rate index */ u_int8_t sc_protrix; /* protection rate index */ + u_int sc_mcastrate; /* ieee rate for mcastrateix */ u_int sc_txantenna; /* tx antenna (fixed or auto) */ HAL_INT sc_imask; /* interrupt mask copy */ u_int sc_keymax; /* size of key cache */ @@ -221,6 +236,9 @@ struct ath_softc { u_int16_t sc_ledoff; /* off time for current blink */ struct callout sc_ledtimer; /* led off timer */ + u_int sc_rfsilentpin; /* GPIO pin for rfkill int */ + u_int sc_rfsilentpol; /* pin setting for rfkill on */ + struct bpf_if *sc_drvbpf; union { struct ath_tx_radiotap_header th; @@ -241,12 +259,15 @@ struct ath_softc { u_int32_t *sc_rxlink; /* link ptr in last RX desc */ struct task sc_rxtask; /* rx int processing */ struct task sc_rxorntask; /* rxorn int processing */ + struct task sc_radartask; /* radar processing */ u_int8_t sc_defant; /* current default antenna */ u_int8_t sc_rxotherant; /* rx's on non-default antenna*/ + u_int64_t sc_lastrx; /* tsf at last rx'd frame */ struct ath_descdma sc_txdma; /* TX descriptors */ ath_bufhead sc_txbuf; /* transmit buffer */ struct mtx sc_txbuflock; /* txbuf lock */ + char sc_txname[12]; /* e.g. "ath0_buf" */ int sc_tx_timer; /* transmit timeout */ u_int sc_txqsetup; /* h/w queues setup */ u_int sc_txintrperiod;/* tx interrupt batching */ @@ -270,7 +291,11 @@ struct ath_softc { } sc_updateslot; /* slot time update fsm */ struct callout sc_cal_ch; /* callout handle for cals */ + int sc_calinterval; /* current polling interval */ + int sc_caltries; /* cals at current interval */ + HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */ struct callout sc_scan_ch; /* callout handle for scan */ + struct callout sc_dfs_ch; /* callout handle for dfs */ }; #define sc_tx_th u_tx_rt.th #define sc_rx_th u_rx_rt.th @@ -285,9 +310,11 @@ struct ath_softc { #define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<sc_txbuflock, \ - device_get_nameunit((_sc)->sc_dev), "xmit buf q", MTX_DEF) +#define ATH_TXBUF_LOCK_INIT(_sc) do { \ + snprintf((_sc)->sc_txname, sizeof((_sc)->sc_txname), "%s_buf", \ + device_get_nameunit((_sc)->sc_dev)); \ + mtx_init(&(_sc)->sc_txbuflock, (_sc)->sc_txname, "ath_buf", MTX_DEF); \ +} while (0) #define ATH_TXBUF_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_txbuflock) #define ATH_TXBUF_LOCK(_sc) mtx_lock(&(_sc)->sc_txbuflock) #define ATH_TXBUF_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_txbuflock) @@ -324,8 +351,8 @@ void ath_intr(void *); ((*(_ah)->ah_getPendingInterrupts)((_ah), (_pmask))) #define ath_hal_updatetxtriglevel(_ah, _inc) \ ((*(_ah)->ah_updateTxTrigLevel)((_ah), (_inc))) -#define ath_hal_setpower(_ah, _mode, _sleepduration) \ - ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE, (_sleepduration))) +#define ath_hal_setpower(_ah, _mode) \ + ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE)) #define ath_hal_keycachesize(_ah) \ ((*(_ah)->ah_getKeyCacheSize)((_ah))) #define ath_hal_keyreset(_ah, _ix) \ @@ -366,8 +393,8 @@ void ath_intr(void *); ((*(_ah)->ah_startTxDma)((_ah), (_q))) #define ath_hal_setchannel(_ah, _chan) \ ((*(_ah)->ah_setChannel)((_ah), (_chan))) -#define ath_hal_calibrate(_ah, _chan) \ - ((*(_ah)->ah_perCalibration)((_ah), (_chan))) +#define ath_hal_calibrate(_ah, _chan, _iqcal) \ + ((*(_ah)->ah_perCalibration)((_ah), (_chan), (_iqcal))) #define ath_hal_setledstate(_ah, _state) \ ((*(_ah)->ah_setLedState)((_ah), (_state))) #define ath_hal_beaconinit(_ah, _nextb, _bperiod) \ @@ -409,8 +436,8 @@ void ath_intr(void *); ((*(_ah)->ah_getDefAntenna)((_ah))) #define ath_hal_setdefantenna(_ah, _ant) \ ((*(_ah)->ah_setDefAntenna)((_ah), (_ant))) -#define ath_hal_rxmonitor(_ah, _arg) \ - ((*(_ah)->ah_rxMonitor)((_ah), (_arg))) +#define ath_hal_rxmonitor(_ah, _arg, _chan) \ + ((*(_ah)->ah_rxMonitor)((_ah), (_arg), (_chan))) #define ath_hal_mibevent(_ah, _stats) \ ((*(_ah)->ah_procMibEvent)((_ah), (_stats))) #define ath_hal_setslottime(_ah, _us) \ @@ -432,7 +459,9 @@ void ath_intr(void *); #define ath_hal_ciphersupported(_ah, _cipher) \ (ath_hal_getcapability(_ah, HAL_CAP_CIPHER, _cipher, NULL) == HAL_OK) #define ath_hal_getregdomain(_ah, _prd) \ - ath_hal_getcapability(_ah, HAL_CAP_REG_DMN, 0, (_prd)) + (ath_hal_getcapability(_ah, HAL_CAP_REG_DMN, 0, (_prd)) == HAL_OK) +#define ath_hal_setregdomain(_ah, _rd) \ + ((*(_ah)->ah_setRegulatoryDomain)((_ah), (_rd), NULL)) #define ath_hal_getcountrycode(_ah, _pcc) \ (*(_pcc) = (_ah)->ah_countryCode) #define ath_hal_tkipsplit(_ah) \ @@ -481,6 +510,24 @@ void ath_intr(void *); #else #define ath_hal_getmcastkeysearch(_ah) 0 #endif +#define ath_hal_hasrfsilent(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 0, NULL) == HAL_OK) +#define ath_hal_getrfkill(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 1, NULL) == HAL_OK) +#define ath_hal_setrfkill(_ah, _onoff) \ + ath_hal_setcapability(_ah, HAL_CAP_RFSILENT, 1, _onoff, NULL) +#define ath_hal_getrfsilent(_ah, _prfsilent) \ + (ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 2, _prfsilent) == HAL_OK) +#define ath_hal_setrfsilent(_ah, _rfsilent) \ + ath_hal_setcapability(_ah, HAL_CAP_RFSILENT, 2, _rfsilent, NULL) +#define ath_hal_gettpack(_ah, _ptpack) \ + (ath_hal_getcapability(_ah, HAL_CAP_TPC_ACK, 0, _ptpack) == HAL_OK) +#define ath_hal_settpack(_ah, _tpack) \ + ath_hal_setcapability(_ah, HAL_CAP_TPC_ACK, 0, _tpack, NULL) +#define ath_hal_gettpcts(_ah, _ptpcts) \ + (ath_hal_getcapability(_ah, HAL_CAP_TPC_CTS, 0, _ptpcts) == HAL_OK) +#define ath_hal_settpcts(_ah, _tpcts) \ + ath_hal_setcapability(_ah, HAL_CAP_TPC_CTS, 0, _tpcts, NULL) #if HAL_ABI_VERSION < 0x05120700 #define ath_hal_process_noisefloor(_ah) #define ath_hal_getchannoise(_ah, _c) (-96) @@ -490,17 +537,24 @@ void ath_intr(void *); #define ath_hal_getchannoise(_ah, _c) \ ((*(_ah)->ah_getChanNoise)((_ah), (_c))) #endif +#if HAL_ABI_VERSION < 0x05122200 +#define HAL_TXQ_TXOKINT_ENABLE TXQ_FLAG_TXOKINT_ENABLE +#define HAL_TXQ_TXERRINT_ENABLE TXQ_FLAG_TXERRINT_ENABLE +#define HAL_TXQ_TXDESCINT_ENABLE TXQ_FLAG_TXDESCINT_ENABLE +#define HAL_TXQ_TXEOLINT_ENABLE TXQ_FLAG_TXEOLINT_ENABLE +#define HAL_TXQ_TXURNINT_ENABLE TXQ_FLAG_TXURNINT_ENABLE +#endif #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq))) #define ath_hal_rxprocdesc(_ah, _ds, _dspa, _dsnext) \ - ((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext))) + ((*(_ah)->ah_procRxDesc)((_ah), (_ds), (_dspa), (_dsnext), 0)) #define ath_hal_setuptxdesc(_ah, _ds, _plen, _hlen, _atype, _txpow, \ _txr0, _txtr0, _keyix, _ant, _flags, \ _rtsrate, _rtsdura) \ ((*(_ah)->ah_setupTxDesc)((_ah), (_ds), (_plen), (_hlen), (_atype), \ (_txpow), (_txr0), (_txtr0), (_keyix), (_ant), \ - (_flags), (_rtsrate), (_rtsdura))) + (_flags), (_rtsrate), (_rtsdura), 0, 0, 0)) #define ath_hal_setupxtxdesc(_ah, _ds, \ _txr1, _txtr1, _txr2, _txtr2, _txr3, _txtr3) \ ((*(_ah)->ah_setupXTxDesc)((_ah), (_ds), \ @@ -509,10 +563,25 @@ void ath_intr(void *); ((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last), (_ds0))) #define ath_hal_txprocdesc(_ah, _ds) \ ((*(_ah)->ah_procTxDesc)((_ah), (_ds))) +#define ath_hal_gettxintrtxqs(_ah, _txqs) \ + ((*(_ah)->ah_getTxIntrQueue)((_ah), (_txqs))) #define ath_hal_gpioCfgOutput(_ah, _gpio) \ ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio))) #define ath_hal_gpioset(_ah, _gpio, _b) \ ((*(_ah)->ah_gpioSet)((_ah), (_gpio), (_b))) +#define ath_hal_gpioget(_ah, _gpio) \ + ((*(_ah)->ah_gpioGet)((_ah), (_gpio))) +#define ath_hal_gpiosetintr(_ah, _gpio, _b) \ + ((*(_ah)->ah_gpioSetIntr)((_ah), (_gpio), (_b))) + +#define ath_hal_radar_event(_ah) \ + ((*(_ah)->ah_radarHaveEvent)((_ah))) +#define ath_hal_procdfs(_ah, _chan) \ + ((*(_ah)->ah_processDfs)((_ah), (_chan))) +#define ath_hal_checknol(_ah, _chan, _nchans) \ + ((*(_ah)->ah_dfsNolCheck)((_ah), (_chan), (_nchans))) +#define ath_hal_radar_wait(_ah, _chan) \ + ((*(_ah)->ah_radarWait)((_ah), (_chan))) #endif /* _DEV_ATH_ATHVAR_H */