diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index a0bcb9a024a0..706752a1603a 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -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"); diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h index 40ccb486cd91..f82bd7e2df9c 100644 --- a/sys/dev/ath/if_athvar.h +++ b/sys/dev/ath/if_athvar.h @@ -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)))