Subject: Re: wi performance hack
To: Holger Weiss <lists@jhweiss.de>
From: Charles M. Hannum <abuse@spamalicious.com>
List: tech-net
Date: 07/19/2004 16:51:27
--Boundary-00=_Pw/+AxtugKW1N4n
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

Whoops, this time with the actual patch.

--Boundary-00=_Pw/+AxtugKW1N4n
Content-Type: text/x-diff;
  charset="iso-8859-1";
  name="wi.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="wi.diff"

Index: wi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi.c,v
retrieving revision 1.164
diff -u -r1.164 wi.c
--- wi.c	2 Jul 2004 23:41:34 -0000	1.164
+++ wi.c	19 Jul 2004 16:51:18 -0000
@@ -72,8 +72,9 @@
 #include <sys/cdefs.h>
 __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.164 2004/07/02 23:41:34 dyoung Exp $");
 
-#define WI_HERMES_AUTOINC_WAR	/* Work around data write autoinc bug. */
+#undef WI_HERMES_AUTOINC_WAR	/* Work around data write autoinc bug. */
 #define WI_HERMES_STATS_WAR	/* Work around stats counter bug. */
+#undef HISTOGRAM
 
 #include "bpfilter.h"
 
@@ -134,6 +135,7 @@
 
 static void wi_rx_intr(struct wi_softc *);
 static void wi_txalloc_intr(struct wi_softc *);
+static void wi_cmd_intr(struct wi_softc *);
 static void wi_tx_intr(struct wi_softc *);
 static void wi_tx_ex_intr(struct wi_softc *);
 static void wi_info_intr(struct wi_softc *);
@@ -148,6 +150,7 @@
 static void wi_read_nicid(struct wi_softc *);
 static int  wi_write_ssid(struct wi_softc *, int, u_int8_t *, int);
 
+static int  wi_sendcmd(struct wi_softc *, int, int);
 static int  wi_cmd(struct wi_softc *, int, int, int, int);
 static int  wi_seek_bap(struct wi_softc *, int, int);
 static int  wi_read_bap(struct wi_softc *, int, int, void *, int);
@@ -190,7 +193,7 @@
 #endif
 
 #define WI_INTRS	(WI_EV_RX | WI_EV_ALLOC | WI_EV_INFO | \
-			 WI_EV_TX | WI_EV_TX_EXC)
+			 WI_EV_TX | WI_EV_TX_EXC | WI_EV_CMD)
 
 struct wi_card_ident
 wi_card_ident[] = {
@@ -561,6 +564,11 @@
 		if (status & WI_EV_INFO)
 			wi_info_intr(sc);
 
+		CSR_WRITE_2(sc, WI_EVENT_ACK, status);
+
+		if (status & WI_EV_CMD)
+			wi_cmd_intr(sc);
+
 		if ((ifp->if_flags & IFF_OACTIVE) == 0 &&
 		    (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 &&
 		    !IFQ_IS_EMPTY(&ifp->if_snd))
@@ -690,13 +698,14 @@
 	if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
 	    sc->sc_firmware_type == WI_INTERSIL) {
 		wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval);
-		wi_write_val(sc, WI_RID_BASIC_RATE, 0x03);   /* 1, 2 */
-		wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
 		wi_write_val(sc, WI_RID_DTIM_PERIOD, 1);
 	}
 
-	if (sc->sc_firmware_type == WI_INTERSIL)
+	if (sc->sc_firmware_type == WI_INTERSIL) {
+		wi_write_val(sc, WI_RID_BASIC_RATE, 0x03);   /* 1, 2 */
+		wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
 		wi_write_val(sc, WI_RID_ALT_RETRY_COUNT, sc->sc_alt_retry);
+	}
 
 	/*
 	 * Initialize promisc mode.
@@ -737,7 +746,11 @@
 			sc->sc_txd[i].d_len = 0;
 		}
 	}
-	sc->sc_txcur = sc->sc_txnext = 0;
+	sc->sc_txqueue = 0;
+	sc->sc_txstart = 0;
+	sc->sc_txalloc = 0;
+	sc->sc_txqueued = 0;
+	sc->sc_txstarted = 0;
 
 	wi_rssdescs_init(&sc->sc_rssd, &sc->sc_rssdfree);
 
@@ -917,7 +930,7 @@
 		return;
 
 	memset(&frmhdr, 0, sizeof(frmhdr));
-	cur = sc->sc_txnext;
+	cur = sc->sc_txqueue;
 	for (;;) {
 		ni = ic->ic_bss;
 		if (sc->sc_txd[cur].d_len != 0 ||
@@ -1061,18 +1074,24 @@
 		}
 		m_freem(m0);
 		sc->sc_txd[cur].d_len = off;
-		if (sc->sc_txcur == cur) {
-			if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
+		if (sc->sc_txqueued++ == 0) {
+			if (cur != sc->sc_txstart) {
+				printf("%s: ring is desynchronized!\n",
+				    sc->sc_dev.dv_xname);
+				fid = sc->sc_txd[sc->sc_txstart].d_fid;
+			}
+			if (wi_sendcmd(sc, WI_CMD_TX | WI_RECLAIM, fid)) {
 				printf("%s: xmit failed\n",
 				    sc->sc_dev.dv_xname);
 				sc->sc_txd[cur].d_len = 0;
 				goto next;
 			}
+			sc->sc_txstarted++;
 			sc->sc_txpending[ni->ni_txrate]++;
 			sc->sc_tx_timer = 5;
 			ifp->if_timer = 1;
 		}
-		sc->sc_txnext = cur = (cur + 1) % WI_NTXBUF;
+		sc->sc_txqueue = cur = (cur + 1) % WI_NTXBUF;
 		SLIST_REMOVE_HEAD(&sc->sc_rssdfree, rd_next);
 		id->id_node = ni;
 		continue;
@@ -1399,7 +1418,6 @@
 
 	/* First read in the frame header */
 	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) {
-		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 		ifp->if_ierrors++;
 		DPRINTF(("wi_rx_intr: read fid %x failed\n", fid));
 		return;
@@ -1414,7 +1432,6 @@
 	status = le16toh(frmhdr.wi_status);
 	if ((status & WI_STAT_ERRSTAT) != 0 &&
 	    ic->ic_opmode != IEEE80211_M_MONITOR) {
-		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 		ifp->if_ierrors++;
 		DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status));
 		return;
@@ -1431,7 +1448,6 @@
 	 */
 	if (off + len > MCLBYTES) {
 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
-			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 			ifp->if_ierrors++;
 			DPRINTF(("wi_rx_intr: oversized packet\n"));
 			return;
@@ -1441,7 +1457,6 @@
 
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
 	if (m == NULL) {
-		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 		ifp->if_ierrors++;
 		DPRINTF(("wi_rx_intr: MGET failed\n"));
 		return;
@@ -1449,7 +1464,6 @@
 	if (off + len > MHLEN) {
 		MCLGET(m, M_DONTWAIT);
 		if ((m->m_flags & M_EXT) == 0) {
-			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
 			m_freem(m);
 			ifp->if_ierrors++;
 			DPRINTF(("wi_rx_intr: MCLGET failed\n"));
@@ -1464,8 +1478,6 @@
 	m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len;
 	m->m_pkthdr.rcvif = ifp;
 
-	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
-
 #if NBPFILTER > 0
 	if (sc->sc_drvbpf) {
 		struct mbuf mb;
@@ -1597,37 +1609,44 @@
 	SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next);
 out:
 	ifp->if_flags &= ~IFF_OACTIVE;
-	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
 }
 
 static void
 wi_txalloc_intr(struct wi_softc *sc)
 {
-	struct ieee80211com *ic = &sc->sc_ic;
-	struct ifnet *ifp = &ic->ic_if;
 	int fid, cur;
 
 	fid = CSR_READ_2(sc, WI_ALLOC_FID);
-	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 
-	cur = sc->sc_txcur;
-	if (sc->sc_txd[cur].d_fid != fid) {
-		printf("%s: bad alloc %x != %x, cur %d nxt %d\n",
+	cur = sc->sc_txalloc;
+	if (sc->sc_txstarted == 0 || sc->sc_txd[cur].d_fid != fid) {
+		printf("%s: bad alloc %x != %x, alloc %d queue %d start %d queued %d started %d\n",
 		    sc->sc_dev.dv_xname, fid, sc->sc_txd[cur].d_fid, cur,
-		    sc->sc_txnext);
+		    sc->sc_txqueue, sc->sc_txstart, sc->sc_txqueued, sc->sc_txstarted);
 		return;
 	}
-	sc->sc_tx_timer = 0;
+	sc->sc_txstarted--;
 	sc->sc_txd[cur].d_len = 0;
-	sc->sc_txcur = cur = (cur + 1) % WI_NTXBUF;
-	if (sc->sc_txd[cur].d_len == 0)
+	sc->sc_txalloc = (cur + 1) % WI_NTXBUF;
+}
+
+static void
+wi_cmd_intr(struct wi_softc *sc)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ifnet *ifp = &ic->ic_if;
+	int cur;
+
+	sc->sc_txstart = cur = (sc->sc_txstart + 1) % WI_NTXBUF;
+	if (--sc->sc_txqueued == 0) {
+		sc->sc_tx_timer = 0;
 		ifp->if_flags &= ~IFF_OACTIVE;
-	else {
-		if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid,
-		    0, 0)) {
+	} else {
+		if (wi_sendcmd(sc, WI_CMD_TX | WI_RECLAIM, sc->sc_txd[cur].d_fid)) {
 			printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
 			sc->sc_txd[cur].d_len = 0;
 		} else {
+			sc->sc_txstarted++;
 			sc->sc_txpending[sc->sc_txd[cur].d_rate]++;
 			sc->sc_tx_timer = 5;
 			ifp->if_timer = 1;
@@ -1687,7 +1706,6 @@
 	SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next);
 out:
 	ifp->if_flags &= ~IFF_OACTIVE;
-	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
 }
 
 static void
@@ -1769,7 +1787,6 @@
 		    le16toh(ltbuf[1]), le16toh(ltbuf[0])));
 		break;
 	}
-	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
 }
 
 static int
@@ -2195,46 +2212,46 @@
 wi_write_txrate(struct wi_softc *sc, int rate)
 {
 	u_int16_t hwrate;
-	int i;
-
-	rate = (rate & IEEE80211_RATE_VAL) / 2;
 
-	/* rate: 0, 1, 2, 5, 11 */
+	/* rate: 0, 2, 4, 11, 22 */
 	switch (sc->sc_firmware_type) {
 	case WI_LUCENT:
-		switch (rate) {
-		case 0:
+		switch (rate & IEEE80211_RATE_VAL) {
+		case 2:
+			hwrate = 1;
+			break;
+		case 4:
+			hwrate = 2;
+			break;
+		default:
 			hwrate = 3;	/* auto */
 			break;
-		case 5:
+		case 11:
 			hwrate = 4;
 			break;
-		case 11:
+		case 22:
 			hwrate = 5;
 			break;
-		default:
-			hwrate = rate;
-			break;
 		}
 		break;
 	default:
-		/* Choose a bit according to this table.
-		 *
-		 * bit | data rate
-		 * ----+-------------------
-		 * 0   | 1Mbps
-		 * 1   | 2Mbps
-		 * 2   | 5.5Mbps
-		 * 3   | 11Mbps
-		 */
-		for (i = 8; i > 0; i >>= 1) {
-			if (rate >= i)
-				break;
+		switch (rate & IEEE80211_RATE_VAL) {
+		case 2:
+			hwrate = 1;
+			break;
+		case 4:
+			hwrate = 2;
+			break;
+		case 11:
+			hwrate = 4;
+			break;
+		case 22:
+			hwrate = 8;
+			break;
+		default:
+			hwrate = 15;	/* auto */
+			break;
 		}
-		if (i == 0)
-			hwrate = 0xf;	/* auto */
-		else
-			hwrate = i;
 		break;
 	}
 
@@ -2360,21 +2377,83 @@
 
 /* Must be called at proper protection level! */
 static int
+wi_sendcmd(struct wi_softc *sc, int cmd, int val0)
+{
+#ifdef HISTOGRAM
+	static int hist3[11];
+	static int hist3count;
+#endif
+	int i;
+
+	/* wait for the busy bit to clear */
+	for (i = 500; i > 0; i--) {	/* 5s */
+		if ((CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY) == 0)
+			break;
+		DELAY(1000);	/* 1 m sec */
+	}
+	if (i == 0) {
+		printf("%s: wi_sendcmd: busy bit won't clear.\n",
+		    sc->sc_dev.dv_xname);
+		return(ETIMEDOUT);
+  	}
+#ifdef HISTOGRAM
+	if (i > 490)
+		hist3[500 - i]++;
+	else
+		hist3[10]++;
+	if (++hist3count == 1000) {
+		hist3count = 0;
+		printf("%s: hist3: %d %d %d %d %d %d %d %d %d %d %d\n",
+		    sc->sc_dev.dv_xname,
+		    hist3[0], hist3[1], hist3[2], hist3[3], hist3[4],
+		    hist3[5], hist3[6], hist3[7], hist3[8], hist3[9],
+		    hist3[10]);
+	}
+#endif
+	CSR_WRITE_2(sc, WI_PARAM0, val0);
+	CSR_WRITE_2(sc, WI_PARAM1, 0);
+	CSR_WRITE_2(sc, WI_PARAM2, 0);
+	CSR_WRITE_2(sc, WI_COMMAND, cmd);
+
+	return 0;
+}
+
+static int
 wi_cmd(struct wi_softc *sc, int cmd, int val0, int val1, int val2)
 {
+#ifdef HISTOGRAM
+	static int hist1[11];
+	static int hist1count;
+	static int hist2[11];
+	static int hist2count;
+#endif
 	int i, status;
 
 	/* wait for the busy bit to clear */
 	for (i = 500; i > 0; i--) {	/* 5s */
 		if ((CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY) == 0)
 			break;
-		DELAY(10*1000);	/* 10 m sec */
+		DELAY(1000);	/* 1 m sec */
 	}
 	if (i == 0) {
 		printf("%s: wi_cmd: busy bit won't clear.\n",
 		    sc->sc_dev.dv_xname);
 		return(ETIMEDOUT);
   	}
+#ifdef HISTOGRAM
+	if (i > 490)
+		hist1[500 - i]++;
+	else
+		hist1[10]++;
+	if (++hist1count == 1000) {
+		hist1count = 0;
+		printf("%s: hist1: %d %d %d %d %d %d %d %d %d %d %d\n",
+		    sc->sc_dev.dv_xname,
+		    hist1[0], hist1[1], hist1[2], hist1[3], hist1[4],
+		    hist1[5], hist1[6], hist1[7], hist1[8], hist1[9],
+		    hist1[10]);
+	}
+#endif
 	CSR_WRITE_2(sc, WI_PARAM0, val0);
 	CSR_WRITE_2(sc, WI_PARAM1, val1);
 	CSR_WRITE_2(sc, WI_PARAM2, val2);
@@ -2390,6 +2469,20 @@
 			break;
 		DELAY(WI_DELAY);
 	}
+#ifdef HISTOGRAM
+	if (i < 100)
+		hist2[i/10]++;
+	else
+		hist2[10]++;
+	if (++hist2count == 1000) {
+		hist2count = 0;
+		printf("%s: hist2: %d %d %d %d %d %d %d %d %d %d %d\n",
+		    sc->sc_dev.dv_xname,
+		    hist2[0], hist2[1], hist2[2], hist2[3], hist2[4],
+		    hist2[5], hist2[6], hist2[7], hist2[8], hist2[9],
+		    hist2[10]);
+	}
+#endif
 
 	status = CSR_READ_2(sc, WI_STATUS);
 
@@ -2413,6 +2506,10 @@
 static int
 wi_seek_bap(struct wi_softc *sc, int id, int off)
 {
+#ifdef HISTOGRAM
+	static int hist4[11];
+	static int hist4count;
+#endif
 	int i, status;
 
 	CSR_WRITE_2(sc, WI_SEL0, id);
@@ -2430,6 +2527,20 @@
 		}
 		DELAY(1);
 	}
+#ifdef HISTOGRAM
+	if (i < 10)
+		hist4[i]++;
+	else
+		hist4[10]++;
+	if (++hist4count == 1000) {
+		hist4count = 0;
+		printf("%s: hist4: %d %d %d %d %d %d %d %d %d %d %d\n",
+		    sc->sc_dev.dv_xname,
+		    hist4[0], hist4[1], hist4[2], hist4[3], hist4[4],
+		    hist4[5], hist4[6], hist4[7], hist4[8], hist4[9],
+		    hist4[10]);
+	}
+#endif
 	if (status & WI_OFF_ERR) {
 		printf("%s: failed in wi_seek to %x/%x\n",
 		    sc->sc_dev.dv_xname, id, off);
Index: wivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wivar.h,v
retrieving revision 1.43
diff -u -r1.43 wivar.h
--- wivar.h	10 Feb 2004 00:59:38 -0000	1.43
+++ wivar.h	19 Jul 2004 16:51:18 -0000
@@ -128,8 +128,11 @@
 		int				d_len;
 		int				d_rate;
 	}			sc_txd[WI_NTXBUF];
-	int			sc_txnext;
-	int			sc_txcur;
+	int			sc_txqueue;	/* where to queue next packet */
+	int			sc_txstart;	/* next packet to start */
+	int			sc_txalloc;	/* next packet to allocate */
+	int			sc_txqueued;	/* packets currently queued */
+	int			sc_txstarted;	/* packets currently started */
 	struct wi_rssdesc 	sc_rssd[WI_NTXRSS];
 	wi_rssdescq_t		sc_rssdfree;
 	int			sc_tx_timer;

--Boundary-00=_Pw/+AxtugKW1N4n--