PERFORCE change 65472 for review
Sam Leffler
sam at FreeBSD.org
Fri Nov 19 14:11:58 PST 2004
http://perforce.freebsd.org/chv.cgi?CH=65472
Change 65472 by sam at 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)))
More information about the p4-projects
mailing list