wi0_cmd: busy bit won't clear

Ian Dowse iedowse at maths.tcd.ie
Sun Sep 7 09:43:38 PDT 2003


In message <Pine.GSO.4.10.10309060444110.18871-100000 at pcnet5.pcnet.com>, Daniel
 Eischen writes:
>Hmm, some of us get it in the reverse -- when the machine boots
>with the card in, we get that message.  Removing and reinserting
>the card after boot seems to work better, but perhaps that's
>just my imagination -- I still sometimes have the same problem
>when reinserting the card.

I have found it almost impossible to determine if any particular
change helps or not, as invariably when I do find something that
survives 5 or 10 removal/reinsert cycles, I get the error again a
few days later and the error frequency seems unchanged.

FYI, I use the collection of fairly arbitrary changes in the following
patch. This does not fix the problem, but it shortens the hard hangs
to about 1 second instead of minutes, and I think some of the extra
DELAY() calls help to reduce the frequency of the errors, but that
may just my imagination too (certainly most of them make no difference
whatsoever). The "!= WI_INTERSIL" bit fixes the "bad alloc" errors
by reverting revision 1.142.

Ian

Index: if_wi.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/wi/if_wi.c,v
retrieving revision 1.151
diff -u -r1.151 if_wi.c
--- if_wi.c	5 Sep 2003 22:29:30 -0000	1.151
+++ if_wi.c	7 Sep 2003 16:17:23 -0000
@@ -502,7 +502,7 @@
 	WI_LOCK(sc);
 
 	/* check if device was removed */
-	sc->wi_gone = !bus_child_present(dev);
+	sc->wi_gone |= !bus_child_present(dev);
 
 	wi_stop(ifp, 0);
 
@@ -751,6 +751,7 @@
 	}
 	sc->sc_txcur = sc->sc_txnext = 0;
 
+	DELAY(10000);
 	/* Enable desired port */
 	wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0);
 
@@ -808,10 +809,14 @@
 
 	WI_LOCK(sc);
 
+	DELAY(50000);
+
 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 	if (sc->sc_enabled && !sc->wi_gone) {
 		CSR_WRITE_2(sc, WI_INT_EN, 0);
+		DELAY(10000);
 		wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
+		DELAY(10000);
 		if (disable) {
 #ifdef __NetBSD__
 			if (sc->sc_disable)
@@ -983,7 +988,7 @@
 	int tries;
 	
 	/* Symbol firmware cannot be initialized more than once */
-	if (sc->sc_firmware_type != WI_INTERSIL && sc->sc_reset)
+	if (sc->sc_firmware_type == WI_SYMBOL && sc->sc_reset)
 		return (0);
 	if (sc->sc_firmware_type == WI_SYMBOL)
 		tries = 1;
@@ -1002,12 +1007,15 @@
 		return (error);
 	}
 
+	DELAY(10 * 1000);
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
 
 	/* Calibrate timer. */
 	wi_write_val(sc, WI_RID_TICK_TIME, 8);
 
+	DELAY(10 * 1000);
+
 	return (0);
 #undef WI_INIT_TRIES
 }
@@ -1597,6 +1605,9 @@
 	struct ifnet *ifp = &ic->ic_if;
 	int fid, cur;
 
+	if (sc->wi_gone)
+		return;
+
 	fid = CSR_READ_2(sc, WI_ALLOC_FID);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 
@@ -2363,18 +2374,22 @@
 	int			i, s = 0;
 	static volatile int count  = 0;
 	
+	if (sc->wi_gone)
+		return (ENODEV);
+
 	if (count > 0)
 		panic("Hey partner, hold on there!");
 	count++;
 
 	/* wait for the busy bit to clear */
-	for (i = 500; i > 0; i--) {	/* 5s */
+	for (i = 500; i > 0; i--) {	/* 500ms */
 		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
 			break;
-		DELAY(10*1000);	/* 10 m sec */
+		DELAY(1*1000);	/* 1ms */
 	}
 	if (i == 0) {
 		device_printf(sc->sc_dev, "wi_cmd: busy bit won't clear.\n" );
+		sc->wi_gone = 1;
 		count--;
 		return(ETIMEDOUT);
 	}
@@ -2411,8 +2426,12 @@
 	if (i == WI_TIMEOUT) {
 		device_printf(sc->sc_dev,
 		    "timeout in wi_cmd 0x%04x; event status 0x%04x\n", cmd, s);
+		if (s == 0xffff)
+			sc->wi_gone = 1;
 		return(ETIMEDOUT);
 	}
+	if (cmd == WI_CMD_INI)
+		DELAY(5000);
 	return (0);
 }
 
@@ -2432,6 +2451,8 @@
 			device_printf(sc->sc_dev, "timeout in wi_seek to %x/%x\n",
 			    id, off);
 			sc->sc_bap_off = WI_OFF_ERR;	/* invalidate */
+			if (status == 0xffff)
+				sc->wi_gone = 1;
 			return ETIMEDOUT;
 		}
 		DELAY(1);


More information about the freebsd-mobile mailing list