Subject: Re: Proxim wi(4) not quite working, crashes
To: None <current-users@NetBSD.org>
From: David Young <dyoung@pobox.com>
List: current-users
Date: 10/13/2005 21:05:51
--+Z7/5fzWRHDJ0o7Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Thu, Oct 13, 2005 at 09:05:28PM -0400, Greg Troxel wrote:
> I don't know the wi code, but it would seem nice to ignore gracefully
> a stray interrupt if that's doable, just returning from wi_cmd_intr in
> that case.

Greg,

Here are wi patches, derived from FreeBSD, that disregard stray
interrupts.  I haven't touched these patches in a long time.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933

--+Z7/5fzWRHDJ0o7Q
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=wi-invalid

Index: wi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi.c,v
retrieving revision 1.201
diff -u -u -r1.201 wi.c
--- wi.c	26 Jun 2005 21:51:37 -0000	1.201
+++ wi.c	6 Jul 2005 06:42:25 -0000
@@ -515,6 +515,7 @@
 	sc->sc_attached = 1;
 
 	splx(s);
+	ieee80211_announce(ic);
 	return 0;
 }
 
@@ -603,7 +604,7 @@
 	struct ifnet *ifp = &sc->sc_if;
 	u_int16_t status;
 
-	if (sc->sc_enabled == 0 ||
+	if (sc->sc_invalid || !sc->sc_enabled ||
 	    (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0 ||
 	    (ifp->if_flags & IFF_RUNNING) == 0)
 		return 0;
@@ -621,6 +622,8 @@
 
 	/* maximum 10 loops per interrupt */
 	for (i = 0; i < 10; i++) {
+		if (sc->sc_invalid)
+			return 1;
 		status = CSR_READ_2(sc, WI_EVENT_STAT);
 #ifdef WI_DEBUG
 		if (wi_debug > 1) {
@@ -710,6 +713,9 @@
 	int i;
 	int error = 0, wasenabled;
 
+	if (sc->sc_invalid)
+		return ENXIO;
+
 	DPRINTF(("wi_init: enabled %d\n", sc->sc_enabled));
 	wasenabled = sc->sc_enabled;
 	if (!sc->sc_enabled) {
@@ -924,7 +930,10 @@
 STATIC void
 wi_txcmd_wait(struct wi_softc *sc)
 {
-	KASSERT(sc->sc_txcmds == 1);
+#ifdef DIAGNOSTIC
+	if (sc->sc_txcmds < 1)
+		printf("%s: no txcmds outstanding!\n", __func__);
+#endif /* DIAGNOSTIC */
 	if (sc->sc_status & WI_EV_CMD) {
 		sc->sc_status &= ~WI_EV_CMD;
 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
@@ -949,7 +958,7 @@
 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 
 	/* wait for tx command completion (deassoc, deauth) */
-	while (sc->sc_txcmds > 0) {
+	while (!sc->sc_invalid && sc->sc_txcmds > 0) {
 		wi_txcmd_wait(sc);
 		wi_cmd_intr(sc);
 	}
@@ -1229,8 +1238,6 @@
 
 	error = 0;
 	for (i = 0; i < 5; i++) {
-		if (sc->sc_invalid)
-			return ENXIO;
 		DELAY(20*1000);	/* XXX: way too long! */
 		if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
 			break;
@@ -1288,6 +1295,9 @@
 	struct ifreq *ifr = (struct ifreq *)data;
 	int s, error = 0;
 
+	if (sc->sc_invalid)
+		return ENXIO;
+
 	if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
 		return ENXIO;
 
@@ -1309,8 +1319,15 @@
 					wi_write_val(sc, WI_RID_PROMISC, 0);
 			} else
 				error = wi_init(ifp);
-		} else if (sc->sc_enabled)
+		} else if (sc->sc_enabled) {
 			wi_stop(ifp, 1);
+			/* Sometimes the device will come back to
+			 * life after DOWN/UP.  If not, that's ok,
+			 * sc_invalid will be set back to 1 soon
+			 * enough.
+			 */
+			sc->sc_invalid = 0;
+		}
 		break;
 	case SIOCSIFMEDIA:
 	case SIOCGIFMEDIA:
@@ -1394,7 +1411,7 @@
 	u_int16_t val;
 	int rate;
 
-	if (sc->sc_enabled == 0) {
+	if (!sc->sc_enabled || sc->sc_invalid) {
 		imr->ifm_active = IFM_IEEE80211 | IFM_NONE;
 		imr->ifm_status = 0;
 		return;
@@ -1749,7 +1766,10 @@
 	if (wi_debug)
 		printf("%s: %d txcmds outstanding\n", __func__, sc->sc_txcmds);
 #endif
-	KASSERT(sc->sc_txcmds > 0);
+#ifdef DIAGNOSTIC
+	if (sc->sc_txcmds <= 0)
+		printf("%s: no txcmds outstanding, getting out\n", __func__);
+#endif /* DIAGNOSTIC */
 
 	--sc->sc_txcmds;
 
@@ -1775,8 +1795,6 @@
 	cur = sc->sc_txstart;
 	fid = sc->sc_txd[cur].d_fid;
 
-	KASSERT(sc->sc_txcmds == 0);
-
 	if (wi_cmd_start(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
 		printf("%s: xmit failed\n", sc->sc_dev.dv_xname);
 		/* XXX ring might have a hole */
@@ -2619,17 +2638,19 @@
 #endif
 	int i;
 
+	if (sc->sc_invalid)
+		return ENXIO;
+
 	/* 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;
-		if (sc->sc_invalid)
-			return ENXIO;
 		DELAY(1000);	/* 1 m sec */
 	}
 	if (i == 0) {
 		printf("%s: wi_cmd: busy bit won't clear.\n",
 		    sc->sc_dev.dv_xname);
+		sc->sc_invalid = 1;
 		return(ETIMEDOUT);
   	}
 #ifdef WI_HISTOGRAM
@@ -2665,6 +2686,9 @@
 		    sc->sc_txcmds);
 	}
 #endif
+	if (sc->sc_invalid)
+		return ENXIO;
+
 	if (sc->sc_txcmds > 0)
 		wi_txcmd_wait(sc);
 
@@ -2673,8 +2697,6 @@
 
 	if (cmd == WI_CMD_INI) {
 		/* XXX: should sleep here. */
-		if (sc->sc_invalid)
-			return ENXIO;
 		DELAY(100*1000);
 	}
 	rc = wi_cmd_wait(sc, cmd, val0);
@@ -2710,12 +2732,13 @@
 		printf("%s: cmd=%#x, arg=%#x\n", __func__, cmd, val0);
 #endif /* WI_DEBUG */
 
+	if (sc->sc_invalid)
+		return ENXIO;
+
 	/* wait for the cmd completed bit */
 	for (i = 0; i < WI_TIMEOUT; i++) {
 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
 			break;
-		if (sc->sc_invalid)
-			return ENXIO;
 		DELAY(WI_DELAY);
 	}
 
@@ -2739,6 +2762,8 @@
 	if (i == WI_TIMEOUT) {
 		printf("%s: command timed out, cmd=0x%x, arg=0x%x\n",
 		    sc->sc_dev.dv_xname, cmd, val0);
+		if (status == 0xffff)
+			sc->sc_invalid = 1;
 		return ETIMEDOUT;
 	}
 
@@ -2772,10 +2797,10 @@
 			printf("%s: timeout in wi_seek to %x/%x\n",
 			    sc->sc_dev.dv_xname, id, off);
 			sc->sc_bap_off = WI_OFF_ERR;	/* invalidate */
+			if (status == 0xffff)
+				sc->sc_invalid = 1;
 			return ETIMEDOUT;
 		}
-		if (sc->sc_invalid)
-			return ENXIO;
 		DELAY(2);
 	}
 #ifdef WI_HISTOGRAM

--+Z7/5fzWRHDJ0o7Q--