Add half/quarter rate 11a channel support:
o change handling of regdomain-related mib knobs so they can be set post-attach: regdomain, countrycode, outdoor, and xchanmode; the hal will not permit changing the regdomain but we expose it for now o on regdomain/countrycode change recalculate the channel list and push it to the net80211 layer (NB: looks to need more tweaking) o setup rate tables for half/quarter rate channels o honor half/quarter rate channel configs when changing channels o honor half/quarter rate channel configs when setting the slot time o use hack/nonstandard channel numbering scheme for the public safety band to avoid overlapping 2.4G channels on dual-band cards o remove setup of ic_sup_rates; the net80211 layer can do this for us and it simplifies handling of half/quarter rate channels Tested only in Public Safety Band with cards that have RF5112.
This commit is contained in:
parent
b0eb2f6935
commit
aaa70f2f6f
@ -170,8 +170,8 @@ static void ath_calibrate(void *);
|
||||
static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
|
||||
static void ath_setup_stationkey(struct ieee80211_node *);
|
||||
static void ath_newassoc(struct ieee80211_node *, int);
|
||||
static int ath_getchannels(struct ath_softc *, u_int cc,
|
||||
HAL_BOOL outdoor, HAL_BOOL xchanmode);
|
||||
static int ath_getchannels(struct ath_softc *,
|
||||
HAL_REG_DOMAIN, HAL_CTRY_CODE, HAL_BOOL, HAL_BOOL);
|
||||
static void ath_led_event(struct ath_softc *, int);
|
||||
static void ath_update_txpow(struct ath_softc *);
|
||||
|
||||
@ -194,15 +194,15 @@ static int ath_calinterval = 30; /* calibrate every 30 secs */
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, calibrate, CTLFLAG_RW, &ath_calinterval,
|
||||
0, "chip calibration interval (secs)");
|
||||
static int ath_outdoor = AH_TRUE; /* outdoor operation */
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, outdoor, CTLFLAG_RD, &ath_outdoor,
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, outdoor, CTLFLAG_RW, &ath_outdoor,
|
||||
0, "outdoor operation");
|
||||
TUNABLE_INT("hw.ath.outdoor", &ath_outdoor);
|
||||
static int ath_xchanmode = AH_TRUE; /* extended channel use */
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, xchanmode, CTLFLAG_RD, &ath_xchanmode,
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, xchanmode, CTLFLAG_RW, &ath_xchanmode,
|
||||
0, "extended channel mode");
|
||||
TUNABLE_INT("hw.ath.xchanmode", &ath_xchanmode);
|
||||
static int ath_countrycode = CTRY_DEFAULT; /* country code */
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, countrycode, CTLFLAG_RD, &ath_countrycode,
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, countrycode, CTLFLAG_RW, &ath_countrycode,
|
||||
0, "country code");
|
||||
TUNABLE_INT("hw.ath.countrycode", &ath_countrycode);
|
||||
static int ath_regdomain = 0; /* regulatory domain */
|
||||
@ -210,11 +210,11 @@ 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,
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, rxbuf, CTLFLAG_RW, &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,
|
||||
SYSCTL_INT(_hw_ath, OID_AUTO, txbuf, CTLFLAG_RW, &ath_txbuf,
|
||||
0, "tx buffers allocated");
|
||||
TUNABLE_INT("hw.ath.txbuf", &ath_txbuf);
|
||||
|
||||
@ -351,8 +351,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
|
||||
* is resposible for filtering this list based on settings
|
||||
* like the phy mode.
|
||||
*/
|
||||
error = ath_getchannels(sc, ath_countrycode,
|
||||
ath_outdoor, ath_xchanmode);
|
||||
error = ath_getchannels(sc, ath_regdomain, ath_countrycode,
|
||||
ath_xchanmode != 0, ath_outdoor != 0);
|
||||
if (error != 0)
|
||||
goto bad;
|
||||
|
||||
@ -364,6 +364,9 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
|
||||
ath_rate_setup(sc, IEEE80211_MODE_11G);
|
||||
ath_rate_setup(sc, IEEE80211_MODE_TURBO_A);
|
||||
ath_rate_setup(sc, IEEE80211_MODE_TURBO_G);
|
||||
ath_rate_setup(sc, IEEE80211_MODE_11A_HALF);
|
||||
ath_rate_setup(sc, IEEE80211_MODE_11A_QUARTER);
|
||||
|
||||
/* NB: setup here so ath_rate_update is happy */
|
||||
ath_setcurmode(sc, IEEE80211_MODE_11A);
|
||||
|
||||
@ -899,6 +902,10 @@ ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan)
|
||||
|
||||
KASSERT(mode < N(modeflags), ("unexpected phy mode %u", mode));
|
||||
KASSERT(modeflags[mode] != 0, ("mode %u undefined", mode));
|
||||
if (IEEE80211_IS_CHAN_HALF(chan))
|
||||
return modeflags[mode] | CHANNEL_HALF;
|
||||
if (IEEE80211_IS_CHAN_QUARTER(chan))
|
||||
return modeflags[mode] | CHANNEL_QUARTER;
|
||||
return modeflags[mode];
|
||||
#undef N
|
||||
}
|
||||
@ -1850,11 +1857,26 @@ ath_setslottime(struct ath_softc *sc)
|
||||
{
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
u_int usec;
|
||||
|
||||
if (ic->ic_flags & IEEE80211_F_SHSLOT)
|
||||
ath_hal_setslottime(ah, HAL_SLOT_TIME_9);
|
||||
if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) {
|
||||
if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan))
|
||||
usec = 13;
|
||||
else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan))
|
||||
usec = 21;
|
||||
else
|
||||
usec = HAL_SLOT_TIME_9;
|
||||
} else if (ic->ic_flags & IEEE80211_F_SHSLOT)
|
||||
usec = HAL_SLOT_TIME_9;
|
||||
else
|
||||
ath_hal_setslottime(ah, HAL_SLOT_TIME_20);
|
||||
usec = HAL_SLOT_TIME_20;
|
||||
|
||||
DPRINTF(sc, ATH_DEBUG_RESET,
|
||||
"%s: chan %u MHz flags 0x%x %s slot, %u usec\n",
|
||||
__func__, ic->ic_curchan->ic_freq, ic->ic_curchan->ic_flags,
|
||||
ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long", usec);
|
||||
|
||||
ath_hal_setslottime(ah, usec);
|
||||
sc->sc_updateslot = OK;
|
||||
}
|
||||
|
||||
@ -4297,6 +4319,12 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
|
||||
* if we're switching; e.g. 11a to 11b/g.
|
||||
*/
|
||||
mode = ieee80211_chan2mode(ic, chan);
|
||||
if (mode == IEEE80211_MODE_11A) {
|
||||
if (IEEE80211_IS_CHAN_HALF(chan))
|
||||
mode = IEEE80211_MODE_11A_HALF;
|
||||
else if (IEEE80211_IS_CHAN_QUARTER(chan))
|
||||
mode = IEEE80211_MODE_11A_QUARTER;
|
||||
}
|
||||
if (mode != sc->sc_curmode)
|
||||
ath_setcurmode(sc, mode);
|
||||
/*
|
||||
@ -4306,8 +4334,7 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
|
||||
if (IEEE80211_IS_CHAN_A(chan))
|
||||
flags = IEEE80211_CHAN_A;
|
||||
/* XXX 11g schizophrenia */
|
||||
else if (IEEE80211_IS_CHAN_G(chan) ||
|
||||
IEEE80211_IS_CHAN_PUREG(chan))
|
||||
else if (IEEE80211_IS_CHAN_ANYG(chan))
|
||||
flags = IEEE80211_CHAN_G;
|
||||
else
|
||||
flags = IEEE80211_CHAN_B;
|
||||
@ -4741,10 +4768,11 @@ ath_newassoc(struct ieee80211_node *ni, int isnew)
|
||||
}
|
||||
|
||||
static int
|
||||
ath_getchannels(struct ath_softc *sc, u_int cc,
|
||||
HAL_BOOL outdoor, HAL_BOOL xchanmode)
|
||||
ath_getchannels(struct ath_softc *sc,
|
||||
HAL_REG_DOMAIN rd, HAL_CTRY_CODE cc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
|
||||
{
|
||||
#define COMPAT (CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE)
|
||||
#define COMPAT \
|
||||
(CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE|CHANNEL_HALF|CHANNEL_QUARTER)
|
||||
#define IS_CHAN_PUBLIC_SAFETY(_c) \
|
||||
(((_c)->channelFlags & CHANNEL_5GHZ) && \
|
||||
((_c)->channel > 4940 && (_c)->channel < 4990))
|
||||
@ -4753,6 +4781,7 @@ ath_getchannels(struct ath_softc *sc, u_int cc,
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
HAL_CHANNEL *chans;
|
||||
int i, ix, nchan;
|
||||
u_int32_t regdomain;
|
||||
|
||||
chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
|
||||
M_TEMP, M_NOWAIT);
|
||||
@ -4761,13 +4790,10 @@ 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;
|
||||
|
||||
ath_hal_getregdomain(ah, &rd);
|
||||
NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) {
|
||||
ath_hal_getregdomain(ah, ®domain);
|
||||
if_printf(ifp, "unable to collect channel list from hal; "
|
||||
"regdomain likely %u country code %u\n", rd, cc);
|
||||
"regdomain likely %u country code %u\n", regdomain, cc);
|
||||
free(chans, M_TEMP);
|
||||
return EINVAL;
|
||||
}
|
||||
@ -4776,6 +4802,7 @@ ath_getchannels(struct ath_softc *sc, u_int cc,
|
||||
* Convert HAL channels to ieee80211 ones and insert
|
||||
* them in the table according to their channel number.
|
||||
*/
|
||||
memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
|
||||
for (i = 0; i < nchan; i++) {
|
||||
HAL_CHANNEL *c = &chans[i];
|
||||
u_int16_t flags;
|
||||
@ -4783,13 +4810,12 @@ ath_getchannels(struct ath_softc *sc, u_int cc,
|
||||
/*
|
||||
* XXX we're not ready to handle the ieee number mapping
|
||||
* for public safety channels as they overlap with any
|
||||
* 2GHz channels; for now use the non-public safety
|
||||
* numbering which is non-overlapping.
|
||||
* 2GHz channels; for now use a non-public safety
|
||||
* numbering that is non-overlapping.
|
||||
*/
|
||||
ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
|
||||
if (IS_CHAN_PUBLIC_SAFETY(c))
|
||||
ix = (c->channel - 4000) / 5;
|
||||
else
|
||||
ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
|
||||
ix += 37; /* XXX */
|
||||
if (ix > IEEE80211_CHAN_MAX) {
|
||||
if_printf(ifp, "bad hal channel %d (%u/%x) ignored\n",
|
||||
ix, c->channel, c->channelFlags);
|
||||
@ -4821,6 +4847,10 @@ ath_getchannels(struct ath_softc *sc, u_int cc,
|
||||
}
|
||||
}
|
||||
free(chans, M_TEMP);
|
||||
ath_hal_getregdomain(ah, &sc->sc_regdomain);
|
||||
ath_hal_getcountrycode(ah, &sc->sc_countrycode);
|
||||
sc->sc_xchanmode = xchanmode;
|
||||
sc->sc_outdoor = outdoor;
|
||||
return 0;
|
||||
#undef IS_CHAN_PUBLIC_SAFETY
|
||||
#undef COMPAT
|
||||
@ -4903,35 +4933,22 @@ 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;
|
||||
|
||||
switch (mode) {
|
||||
case IEEE80211_MODE_11A:
|
||||
rt = ath_hal_getratetable(ah, HAL_MODE_11A);
|
||||
break;
|
||||
case IEEE80211_MODE_11A_HALF:
|
||||
rt = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE);
|
||||
break;
|
||||
case IEEE80211_MODE_11A_QUARTER:
|
||||
rt = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE);
|
||||
break;
|
||||
case IEEE80211_MODE_11B:
|
||||
rt = ath_hal_getratetable(ah, HAL_MODE_11B);
|
||||
break;
|
||||
@ -4951,11 +4968,7 @@ ath_rate_setup(struct ath_softc *sc, u_int mode)
|
||||
return 0;
|
||||
}
|
||||
sc->sc_rates[mode] = rt;
|
||||
if (rt != NULL) {
|
||||
rate_setup(sc, rt, &ic->ic_sup_rates[mode]);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
return (rt != NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5419,19 +5432,46 @@ ath_sysctl_rfsilent(SYSCTL_HANDLER_ARGS)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath_sysctl_countrycode(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct ath_softc *sc = arg1;
|
||||
u_int32_t cc = sc->sc_countrycode;
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
int error;
|
||||
|
||||
error = sysctl_handle_int(oidp, &cc, 0, req);
|
||||
if (error || !req->newptr)
|
||||
return error;
|
||||
error = ath_getchannels(sc, sc->sc_regdomain, cc,
|
||||
sc->sc_outdoor, sc->sc_xchanmode);
|
||||
if (error != 0)
|
||||
return error;
|
||||
ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
|
||||
/* setcurmode? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath_sysctl_regdomain(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct ath_softc *sc = arg1;
|
||||
u_int32_t rd;
|
||||
u_int32_t rd = sc->sc_regdomain;
|
||||
struct ieee80211com *ic = &sc->sc_ic;
|
||||
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;
|
||||
if (!ath_hal_setregdomain(sc->sc_ah, rd))
|
||||
return EINVAL;
|
||||
error = ath_getchannels(sc, rd, sc->sc_countrycode,
|
||||
sc->sc_outdoor, sc->sc_xchanmode);
|
||||
if (error != 0)
|
||||
return error;
|
||||
ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
|
||||
/* setcurmode? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -5469,10 +5509,9 @@ ath_sysctlattach(struct ath_softc *sc)
|
||||
struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
|
||||
struct ath_hal *ah = sc->sc_ah;
|
||||
|
||||
ath_hal_getcountrycode(sc->sc_ah, &sc->sc_countrycode);
|
||||
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
|
||||
"countrycode", CTLFLAG_RD, &sc->sc_countrycode, 0,
|
||||
"EEPROM country code");
|
||||
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
|
||||
"countrycode", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
|
||||
ath_sysctl_countrycode, "I", "country code");
|
||||
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
|
||||
"regdomain", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
|
||||
ath_sysctl_regdomain, "I", "EEPROM regdomain code");
|
||||
|
@ -173,8 +173,9 @@ 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_countrycode;
|
||||
int sc_debug;
|
||||
u_int32_t sc_countrycode;
|
||||
u_int32_t sc_regdomain;
|
||||
void (*sc_recv_mgmt)(struct ieee80211com *,
|
||||
struct mbuf *,
|
||||
struct ieee80211_node *,
|
||||
@ -203,9 +204,13 @@ struct ath_softc {
|
||||
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 */
|
||||
sc_hasclrkey:1, /* CLR key supported */
|
||||
sc_xchanmode: 1,/* extended channel mode */
|
||||
sc_outdoor : 1;/* outdoor operation */
|
||||
/* rate tables */
|
||||
const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX];
|
||||
#define IEEE80211_MODE_11A_HALF (IEEE80211_MODE_MAX+0)
|
||||
#define IEEE80211_MODE_11A_QUARTER (IEEE80211_MODE_MAX+1)
|
||||
const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX+2];
|
||||
const HAL_RATE_TABLE *sc_currates; /* current rate table */
|
||||
enum ieee80211_phymode sc_curmode; /* current phy mode */
|
||||
HAL_OPMODE sc_opmode; /* current operating mode */
|
||||
@ -549,6 +554,11 @@ void ath_intr(void *);
|
||||
#define HAL_TXQ_TXEOLINT_ENABLE TXQ_FLAG_TXEOLINT_ENABLE
|
||||
#define HAL_TXQ_TXURNINT_ENABLE TXQ_FLAG_TXURNINT_ENABLE
|
||||
#endif
|
||||
#if HAL_ABI_VERSION < 0x06102501
|
||||
#define ath_hal_ispublicsafetysku(ah) \
|
||||
(((ah)->ah_regdomain == 0 && (ah)->ah_countryCode == 842) || \
|
||||
(ah)->ah_regdomain == 0x12)
|
||||
#endif
|
||||
|
||||
#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
|
||||
((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
|
||||
|
Loading…
Reference in New Issue
Block a user