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