Date: Fri, 19 Nov 2004 22:11:56 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 65472 for review Message-ID: <200411192211.iAJMBumw085359@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=65472 Change 65472 by sam@sam_ebb on 2004/11/19 22:11:41 o cleanup tx queue setup to not use the number of h/w queues but instead fall back to using a single data queue if we cannot allocate sufficient queues for all the AC's o correct problems cleaning up tx q state during failure in attach o tx power support o correct TXDESCINT setup to use 802.11 packet type and not hal packet type (some management frames were not being marked 'cuz they mappy to a normal packet) o add sysctl's for futzing with tp scale factor and per-packet tpc Affected files ... .. //depot/projects/wifi/sys/dev/ath/if_ath.c#24 edit .. //depot/projects/wifi/sys/dev/ath/if_athvar.h#8 edit Differences ... ==== //depot/projects/wifi/sys/dev/ath/if_ath.c#24 (text+ko) ==== @@ -132,9 +132,10 @@ struct ieee80211_node *ni, int subtype, int rssi, u_int32_t rstamp); static void ath_rx_proc(void *, int); -static struct ath_txq *ath_txq_setup(struct ath_softc *, int qtype, - int subtype, const char *typename); +static struct ath_txq *ath_txq_setup(struct ath_softc*, int qtype, int subtype); static int ath_tx_setup(struct ath_softc *, int, int); +static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *); +static void ath_tx_cleanup(struct ath_softc *); static int ath_tx_start(struct ath_softc *, struct ieee80211_node *, struct ath_buf *, struct mbuf *); static void ath_tx_proc_q0(void *, int); @@ -153,6 +154,7 @@ static int ath_getchannels(struct ath_softc *, u_int cc, HAL_BOOL outdoor, HAL_BOOL xchanmode); static void ath_update_led(struct ath_softc *); +static void ath_update_txpow(struct ath_softc *); static int ath_rate_setup(struct ath_softc *, u_int mode); static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); @@ -248,7 +250,6 @@ struct ath_hal *ah; HAL_STATUS status; int error = 0, i; - u_int32_t numqs; DPRINTF(sc, ATH_DEBUG_ANY, "%s: devid 0x%x\n", __func__, devid); @@ -377,39 +378,36 @@ error = EIO; goto bad2; } - sc->sc_cabq = ath_txq_setup(sc, HAL_TX_QUEUE_CAB, 0, "CAB"); + sc->sc_cabq = ath_txq_setup(sc, HAL_TX_QUEUE_CAB, 0); if (sc->sc_cabq == NULL) { if_printf(ifp, "unable to setup CAB xmit queue!\n"); error = EIO; goto bad2; } - (void) ath_hal_getnumtxqueues(ah, &numqs); - if (numqs < 5) { - int qnum; - /* + /* NB: insure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { + if_printf(ifp, "unable to setup xmit queue for %s traffic!\n", + acnames[WME_AC_BK]); + error = EIO; + goto bad2; + } + if (!ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) || + !ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) || + !ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) { + /* * Not enough hardware tx queues to properly do WME; * just punt and assign them all to the same h/w queue. * We could do a better job of this if, for example, - * we allocate queues when we switch from station - * to AP mode. + * we allocate queues when we switch from station to + * AP mode. */ - if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) { - error = EIO; - goto bad2; - } - qnum = sc->sc_txq[WME_AC_BK].axq_qnum; - sc->sc_ac2q[WME_AC_BE] = &sc->sc_txq[qnum]; - sc->sc_ac2q[WME_AC_VI] = &sc->sc_txq[qnum]; - sc->sc_ac2q[WME_AC_VO] = &sc->sc_txq[qnum]; - } else { - /* NB: insure BK queue is h/w queue 0 */ - if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK) || - !ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) || - !ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) || - !ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) { - error = EIO; - goto bad2; - } + if (sc->sc_ac2q[WME_AC_VI] != NULL) + ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_VI]); + if (sc->sc_ac2q[WME_AC_BE] != NULL) + ath_tx_cleanupq(sc, sc->sc_ac2q[WME_AC_BE]); + sc->sc_ac2q[WME_AC_BE] = sc->sc_ac2q[WME_AC_BK]; + sc->sc_ac2q[WME_AC_VI] = sc->sc_ac2q[WME_AC_BK]; + sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK]; } /* @@ -470,7 +468,6 @@ | IEEE80211_C_MONITOR /* monitor mode */ | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | IEEE80211_C_SHSLOT /* short slot time supported */ - | IEEE80211_C_TXPMGT /* transmit power control */ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ ; /* @@ -497,6 +494,15 @@ sc->sc_splitmic = 1; } /* + * TPC support can be done either with a global cap or + * per-packet support. The latter is not available on + * all parts. We're a bit pedantic here as all parts + * support a global cap. + */ + sc->sc_hastpc = ath_hal_hastpc(ah); + if (sc->sc_hastpc || ath_hal_hastxpowlimit(ah)) + ic->ic_caps |= IEEE80211_C_TXPMGT; + /* * Indicate we need the 802.11 header padded to a * 32-bit boundary for 4-address and QoS frames. */ @@ -515,7 +521,7 @@ * Not all chips have the VEOL support we want to * use with IBSS beacons; check here for it. */ - sc->sc_hasveol = ath_hal_veolsupported(ah); + sc->sc_hasveol = ath_hal_hasveol(ah); /* get mac address from hardware */ ath_hal_getmac(ah, ic->ic_myaddr); @@ -546,14 +552,7 @@ ath_announce(sc); return 0; bad2: - if (ATH_TXQ_SETUP(sc, WME_AC_BK)) - ATH_TXQ_LOCK_DESTROY(&sc->sc_txq[WME_AC_BK]); - if (ATH_TXQ_SETUP(sc, WME_AC_BE)) - ATH_TXQ_LOCK_DESTROY(&sc->sc_txq[WME_AC_BE]); - if (ATH_TXQ_SETUP(sc, WME_AC_VI)) - ATH_TXQ_LOCK_DESTROY(&sc->sc_txq[WME_AC_VI]); - if (ATH_TXQ_SETUP(sc, WME_AC_VO)) - ATH_TXQ_LOCK_DESTROY(&sc->sc_txq[WME_AC_VO]); + ath_tx_cleanup(sc); ath_desc_free(sc); bad: if (ah) @@ -566,33 +565,30 @@ ath_detach(struct ath_softc *sc) { struct ifnet *ifp = &sc->sc_if; - int i; DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags %x\n", __func__, ifp->if_flags); ath_stop(ifp); bpfdetach(ifp); - /* - * NB: Must do this before detaching the hal to insure - * callbacks into the driver to delete global key - * entries can be handled. + /* + * NB: the order of these is important: + * o call the 802.11 layer before detaching the hal to + * insure callbacks into the driver to delete global + * key cache entries can be handled + * o reclaim the tx queue data structures after calling + * the 802.11 layer as we'll get called back to reclaim + * node state and potentially want to use them + * o to cleanup the tx queues the hal is called, so detach + * it last + * Other than that, it's straightforward... */ ieee80211_ifdetach(&sc->sc_ic); ath_rate_detach(sc->sc_rc); ath_desc_free(sc); + ath_tx_cleanup(sc); ath_hal_detach(sc->sc_ah); - /* - * NB: can't reclaim these until after ieee80211_ifdetach - * returns because we'll get called back to reclaim node - * state and potentially want to use them. - */ - ATH_TXBUF_LOCK_DESTROY(sc); - for (i = 0; i < HAL_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ATH_TXQ_LOCK_DESTROY(&sc->sc_txq[i]); - return 0; } @@ -834,6 +830,12 @@ } /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath_update_txpow(sc); + + /* * Setup the hardware after reset: the key cache * is filled as needed and the receive engine is * set going. Frame transmit is handled entirely @@ -981,6 +983,7 @@ if (!ath_hal_reset(ah, ic->ic_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 */ if (ath_startrecv(sc) != 0) /* restart recv */ if_printf(ifp, "%s: unable to start recv logic\n", __func__); /* @@ -1670,7 +1673,7 @@ , m->m_len + IEEE80211_CRC_LEN /* frame length */ , sizeof(struct ieee80211_frame)/* header length */ , HAL_PKT_TYPE_BEACON /* Atheros packet type */ - , MIN(ni->ni_txpower,60) /* txpower XXX */ + , ni->ni_txpower /* txpower XXX */ , rate, 1 /* series 0 rate/tries */ , HAL_TXKEYIX_INVALID /* no encryption */ , 0 /* antenna mode */ @@ -2580,7 +2583,7 @@ * Setup a h/w transmit queue. */ static struct ath_txq * -ath_txq_setup(struct ath_softc *sc, int qtype, int subtype, const char *typename) +ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) { #define N(a) (sizeof(a)/sizeof(a[0])) struct ath_hal *ah = sc->sc_ah; @@ -2607,9 +2610,10 @@ qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; qnum = ath_hal_setuptxqueue(ah, qtype, &qi); if (qnum == -1) { - device_printf(sc->sc_dev, - "Unable to setup hardware queue for %s traffic!\n", - typename); + /* + * NB: don't print a message, this happens + * ormally on parts with too few tx queues + */ return NULL; } if (qnum >= N(sc->sc_txq)) { @@ -2653,7 +2657,7 @@ ac, N(sc->sc_ac2q)); return 0; } - txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype, acnames[ac]); + txq = ath_txq_setup(sc, HAL_TX_QUEUE_DATA, haltype); if (txq != NULL) { sc->sc_ac2q[ac] = txq; return 1; @@ -2662,6 +2666,32 @@ #undef N } +/* + * Reclaim resources for a setup queue. + */ +static void +ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) +{ + + ath_hal_releasetxqueue(sc->sc_ah, txq->axq_qnum); + ATH_TXQ_LOCK_DESTROY(txq); + sc->sc_txqsetup &= ~(1<<txq->axq_qnum); +} + +/* + * Reclaim all tx queue resources. + */ +static void +ath_tx_cleanup(struct ath_softc *sc) +{ + int i; + + ATH_TXBUF_LOCK_DESTROY(sc); + for (i = 0; i < HAL_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->sc_txq[i]); +} + static int ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf, struct mbuf *m0) @@ -2809,6 +2839,7 @@ } an = ATH_NODE(ni); + flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ /* * Calculate Atheros packet type from IEEE80211 packet header, * setup for rate calculations, and select h/w transmit queue. @@ -2832,6 +2863,7 @@ txrate = an->an_tx_mgtrate; /* NB: force all management frames to highest queue */ txq = sc->sc_ac2q[WME_AC_VO]; + flags |= HAL_TXDESC_INTREQ; /* force interrupt */ break; case IEEE80211_FC0_TYPE_CTL: atype = HAL_PKT_TYPE_PSPOLL; /* stop setting of duration */ @@ -2843,6 +2875,7 @@ txrate = an->an_tx_mgtrate; /* NB: force all ctl frames to highest queue */ txq = sc->sc_ac2q[WME_AC_VO]; + flags |= HAL_TXDESC_INTREQ; /* force interrupt */ break; case IEEE80211_FC0_TYPE_DATA: atype = HAL_PKT_TYPE_NORMAL; /* default */ @@ -2881,7 +2914,6 @@ /* * Calculate miscellaneous flags. */ - flags = HAL_TXDESC_CLRDMASK; /* XXX needed for crypto errs */ if (ismcast) { flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ sc->sc_stats.ast_tx_noack++; @@ -2983,7 +3015,7 @@ if (iswep) sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP; sc->sc_tx_th.wt_rate = ni->ni_rates.rs_rates[ni->ni_txrate]; - sc->sc_tx_th.wt_txpower = MIN(ni->ni_txpower,60); + sc->sc_tx_th.wt_txpower = ni->ni_txpower; sc->sc_tx_th.wt_antenna = sc->sc_txantenna; bpf_mtap2(sc->sc_drvbpf, @@ -3005,8 +3037,9 @@ * NB: use >= to deal with sc_txintrperiod changing * dynamically through sysctl. */ - if (atype != HAL_PKT_TYPE_NORMAL || - ++txq->axq_intrcnt >= sc->sc_txintrperiod) { + if (flags & HAL_TXDESC_INTREQ) { + txq->axq_intrcnt = 0; + } else if (++txq->axq_intrcnt >= sc->sc_txintrperiod) { flags |= HAL_TXDESC_INTREQ; txq->axq_intrcnt = 0; } @@ -3019,7 +3052,7 @@ , pktlen /* packet length */ , hdrlen /* header length */ , atype /* Atheros packet type */ - , MIN(ni->ni_txpower,60)/* txpower */ + , ni->ni_txpower /* txpower */ , txrate, try0 /* series 0 rate/tries */ , keyix /* key cache index */ , sc->sc_txantenna /* antenna mode */ @@ -3466,6 +3499,7 @@ return EIO; } sc->sc_curchan = hchan; + ath_update_txpow(sc); /* update tx power state */ /* * Re-enable rx framework. @@ -3739,6 +3773,26 @@ } } +static void +ath_update_txpow(struct ath_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + u_int32_t txpow; + + if (sc->sc_curtxpow != ic->ic_txpowlimit) { + ath_hal_settxpowlimit(ah, ic->ic_txpowlimit); + /* read back in case value is clamped */ + ath_hal_gettxpowlimit(ah, &txpow); + ic->ic_txpowlimit = sc->sc_curtxpow = txpow; + } + /* + * Fetch max tx power level for status requests. + */ + ath_hal_getmaxtxpow(sc->sc_ah, &txpow); + ic->ic_bss->ni_txpower = txpow; +} + static int ath_rate_setup(struct ath_softc *sc, u_int mode) { @@ -3863,9 +3917,8 @@ ath_reset(ifp); ifp->if_oerrors++; sc->sc_stats.ast_watchdog++; - return; - } - ifp->if_timer = 1; + } else + ifp->if_timer = 1; } ieee80211_watchdog(ic); } @@ -4109,6 +4162,34 @@ return !ath_hal_setdiag(sc->sc_ah, diag) ? EINVAL : 0; } +static int +ath_sysctl_tpscale(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + struct ifnet *ifp = &sc->sc_if; + u_int32_t scale; + int error; + + ath_hal_gettpscale(sc->sc_ah, &scale); + error = sysctl_handle_int(oidp, &scale, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_settpscale(sc->sc_ah, scale) ? EINVAL : ath_reset(ifp); +} + +static int +ath_sysctl_tpc(SYSCTL_HANDLER_ARGS) +{ + struct ath_softc *sc = arg1; + u_int tpc = ath_hal_gettpc(sc->sc_ah); + int error; + + error = sysctl_handle_int(oidp, &tpc, 0, req); + if (error || !req->newptr) + return error; + return !ath_hal_settpc(sc->sc_ah, tpc) ? EINVAL : 0; +} + static void ath_sysctlattach(struct ath_softc *sc) { @@ -4160,6 +4241,13 @@ SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "diag", CTLTYPE_INT | CTLFLAG_RW, sc, 0, ath_sysctl_diag, "I", "h/w diagnostic control"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "tpscale", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + ath_sysctl_tpscale, "I", "tx power scaling"); + if (sc->sc_hastpc) + 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"); } static void ==== //depot/projects/wifi/sys/dev/ath/if_athvar.h#8 (text+ko) ==== @@ -156,11 +156,13 @@ sc_needmib : 1, /* enable MIB stats intr */ sc_hasdiversity : 1,/* rx diversity available */ sc_diversity : 1,/* enable rx diversity */ - sc_hasveol : 1; /* tx VEOL support */ + sc_hasveol : 1, /* tx VEOL support */ + sc_hastpc : 1; /* per-packet TPC support */ /* 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 */ + 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 */ u_int8_t sc_hwmap[32]; /* h/w rate ix to IEEE table */ @@ -351,8 +353,6 @@ ((*(_ah)->ah_resetTxQueue)((_ah), (_q))) #define ath_hal_releasetxqueue(_ah, _q) \ ((*(_ah)->ah_releaseTxQueue)((_ah), (_q))) -#define ath_hal_hasveol(_ah) \ - ((*(_ah)->ah_hasVEOL)((_ah))) #define ath_hal_getrfgain(_ah) \ ((*(_ah)->ah_getRfGain)((_ah))) #define ath_hal_getdefantenna(_ah) \ @@ -401,8 +401,26 @@ ath_hal_setcapability(_ah, HAL_CAP_DIAG, 0, _v, NULL) #define ath_hal_getnumtxqueues(_ah, _pv) \ (ath_hal_getcapability(_ah, HAL_CAP_NUM_TXQUEUES, 0, _pv) == HAL_OK) -#define ath_hal_veolsupported(_ah) \ +#define ath_hal_hasveol(_ah) \ (ath_hal_getcapability(_ah, HAL_CAP_VEOL, 0, NULL) == HAL_OK) +#define ath_hal_hastxpowlimit(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 0, NULL) == HAL_OK) +#define ath_hal_settxpowlimit(_ah, _pow) \ + ((*(_ah)->ah_setTxPowerLimit)((_ah), (_pow))) +#define ath_hal_gettxpowlimit(_ah, _ppow) \ + (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 1, _ppow) == HAL_OK) +#define ath_hal_getmaxtxpow(_ah, _ppow) \ + (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 2, _ppow) == HAL_OK) +#define ath_hal_gettpscale(_ah, _scale) \ + (ath_hal_getcapability(_ah, HAL_CAP_TXPOW, 3, _scale) == HAL_OK) +#define ath_hal_settpscale(_ah, _v) \ + ath_hal_setcapability(_ah, HAL_CAP_TXPOW, 3, _v, NULL) +#define ath_hal_hastpc(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_TPC, 0, NULL) == HAL_OK) +#define ath_hal_gettpc(_ah) \ + (ath_hal_getcapability(_ah, HAL_CAP_TPC, 1, NULL) == HAL_OK) +#define ath_hal_settpc(_ah, _v) \ + ath_hal_setcapability(_ah, HAL_CAP_TPC, 1, _v, NULL) #define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200411192211.iAJMBumw085359>
