[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

wi(4) fixes



The following diff, relative to OpenBSD 3.4 (-current will require
simple hand-patching for one hunk), makes HostAP work on Prism cards
with newer firmware (1.7.0 and higher) and fixes some timing issues
that caused some prism-based cards to be unstable.

If you have been having intermittent problems with a wireless card
that uses the wi(4) driver I would be interested in hearing whether
or not this helps things.  I'm especially interested in hearing
about native PCI-based cards (ie: not using a host adapter) since
I don't own any of that type.

 - todd

Index: sys/dev/ic/if_wi.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wi.c,v
retrieving revision 1.98
diff -u -r1.98 if_wi.c
--- sys/dev/ic/if_wi.c	6 Sep 2003 20:53:57 -0000	1.98
+++ sys/dev/ic/if_wi.c	2 Mar 2004 15:50:30 -0000
@@ -188,6 +188,8 @@
 	struct ifnet		*ifp;
 	int			error;
 
+	sc->wi_cmd_count = 500;
+
 	wi_reset(sc);
 
 	/* Read the station address. */
@@ -264,6 +266,9 @@
 		break;
 	case WI_INTERSIL:
 		sc->wi_flags |= WI_FLAGS_HAS_ROAMING;
+		/* older prism firmware is slow so crank the count */
+		if (sc->sc_sta_firmware_ver < 10000)
+			sc->wi_cmd_count = 5000;
 		if (sc->sc_sta_firmware_ver >= 800) {
 #ifndef SMALL_KERNEL
 			sc->wi_flags |= WI_FLAGS_HAS_HOSTAP;
@@ -472,7 +477,7 @@
 	struct ether_header	*eh;
 	struct mbuf		*m;
 	caddr_t			olddata;
-	u_int16_t		msg_type;
+	u_int16_t		ftype;
 	int			maxlen;
 	int			id;
 
@@ -581,8 +586,8 @@
 			return;
 		}
 
-		/* Stash message type in host byte order for later use */
-		msg_type = letoh16(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE;
+		/* Stash frame type in host byte order for later use */
+		ftype = letoh16(rx_frame.wi_frame_ctl) & WI_FCTL_FTYPE;
 
 		MGETHDR(m, M_DONTWAIT, MT_DATA);
 		if (m == NULL) {
@@ -605,7 +610,7 @@
 		maxlen = MCLBYTES - (m->m_data - olddata);
 		m->m_pkthdr.rcvif = ifp;
 
-		if (msg_type == WI_STAT_MGMT &&
+		if (ftype == WI_FTYPE_MGMT &&
 		    sc->wi_ptype == WI_PORTTYPE_HOSTAP) {
 
 			u_int16_t rxlen = letoh16(rx_frame.wi_dat_len);
@@ -643,7 +648,7 @@
 			return;
 		}
 
-		switch (msg_type) {
+		switch (letoh16(rx_frame.wi_status) & WI_RXSTAT_MSG_TYPE) {
 		case WI_STAT_1042:
 		case WI_STAT_TUNNEL:
 		case WI_STAT_WMP_MSG:
@@ -877,10 +882,15 @@
 	int			i, s = 0;
 
 	/* Wait for the busy bit to clear. */
-	for (i = 0; i < WI_TIMEOUT; i++) {
+	for (i = sc->wi_cmd_count; i--; DELAY(1000)) {
 		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
 			break;
-		DELAY(10);
+	}
+	if (i < 0) {
+		if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
+			printf(WI_PRT_FMT ": wi_cmd_io: busy bit won't clear\n",
+			    WI_PRT_ARG(sc));
+		return(ETIMEDOUT);
 	}
 
 	CSR_WRITE_2(sc, WI_PARAM0, val0);
@@ -888,7 +898,7 @@
 	CSR_WRITE_2(sc, WI_PARAM2, val2);
 	CSR_WRITE_2(sc, WI_COMMAND, cmd);
 
-	for (i = WI_TIMEOUT; i--; DELAY(10)) {
+	for (i = WI_TIMEOUT; i--; DELAY(WI_DELAY)) {
 		/*
 		 * Wait for 'command complete' bit to be
 		 * set in the event status register.
@@ -898,18 +908,19 @@
 			/* Ack the event and read result code. */
 			s = CSR_READ_2(sc, WI_STATUS);
 			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
-#ifdef foo
-			if ((s & WI_CMD_CODE_MASK) != (cmd & WI_CMD_CODE_MASK))
-				return(EIO);
-#endif
 			if (s & WI_STAT_CMD_RESULT)
 				return(EIO);
 			break;
 		}
 	}
 
-	if (i < 0)
+	if (i < 0) {
+		if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
+			printf(WI_PRT_FMT
+			    ": timeout in wi_cmd 0x%04x; event status 0x%04x\n",
+			    WI_PRT_ARG(sc), cmd, s);
 		return(ETIMEDOUT);
+	}
 
 	return(0);
 }
@@ -918,17 +929,26 @@
 wi_reset(sc)
 	struct wi_softc		*sc;
 {
+	int error, tries = 3;
+
 	DPRINTF(WID_RESET, ("wi_reset: sc %p\n", sc));
 
 	/* Symbol firmware cannot be initialized more than once. */
-	if (sc->sc_firmware_type == WI_SYMBOL &&
-	    (sc->wi_flags & WI_FLAGS_INITIALIZED))
-		return;
+	if (sc->sc_firmware_type == WI_SYMBOL) {
+		if (sc->wi_flags & WI_FLAGS_INITIALIZED)
+			return;
+		tries = 1;
+	}
 
-	if (wi_cmd(sc, WI_CMD_INI, 0, 0, 0))
+	for (; tries--; DELAY(WI_DELAY * 1000)) {
+		if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0)
+			break;
+	}
+	if (tries < 0) {
 		printf(WI_PRT_FMT ": init failed\n", WI_PRT_ARG(sc));
-	else
-		sc->wi_flags |= WI_FLAGS_INITIALIZED;
+		return;
+	}
+	sc->wi_flags |= WI_FLAGS_INITIALIZED;
 
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
@@ -1217,7 +1237,7 @@
 	CSR_WRITE_2(sc, selreg, id);
 	CSR_WRITE_2(sc, offreg, off);
 
-	for (i = WI_TIMEOUT; i--; DELAY(10))
+	for (i = WI_TIMEOUT; i--; DELAY(1))
 		if (!(CSR_READ_2(sc, offreg) & (WI_OFF_BUSY|WI_OFF_ERR)))
 			break;
 
@@ -1309,7 +1329,7 @@
 		return(ENOMEM);
 	}
 
-	for (i = WI_TIMEOUT; i--; DELAY(10)) {
+	for (i = WI_TIMEOUT; i--; DELAY(1)) {
 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
 			break;
 	}
Index: sys/dev/ic/if_wi_hostap.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wi_hostap.c,v
retrieving revision 1.26
diff -u -r1.26 if_wi_hostap.c
--- sys/dev/ic/if_wi_hostap.c	15 Aug 2003 20:32:17 -0000	1.26
+++ sys/dev/ic/if_wi_hostap.c	2 Mar 2004 15:49:50 -0000
@@ -1109,11 +1109,18 @@
 	struct wihap_sta_info	*sta;
 	int			mcast, s;
 
-	/* TODS flag must be set. */
-	if (!(rxfrm->wi_frame_ctl & htole16(WI_FCTL_TODS))) {
+	/*
+	 * TODS flag must be set.  However, Lucent cards set NULLFUNC but
+	 * not TODS when probing an AP to see if it is alive after it has
+	 * been down for a while.  We accept these probe packets and send a
+	 * disassoc packet later on if the station is not already associated.
+	 */
+	if (!(rxfrm->wi_frame_ctl & htole16(WI_FCTL_TODS)) &&
+	    !(rxfrm->wi_frame_ctl & WI_STYPE_NULLFUNC)) {
 		if (ifp->if_flags & IFF_DEBUG)
-			printf("wihap_data_input: no TODS src=%s\n",
-			    ether_sprintf(rxfrm->wi_addr2));
+			printf("wihap_data_input: no TODS src=%s, fctl=0x%x\n",
+			    ether_sprintf(rxfrm->wi_addr2),
+			    letoh16(rxfrm->wi_frame_ctl));
 		m_freem(m);
 		return (1);
 	}
Index: sys/dev/ic/if_wi_ieee.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wi_ieee.h,v
retrieving revision 1.17
diff -u -r1.17 if_wi_ieee.h
--- sys/dev/ic/if_wi_ieee.h	24 Aug 2003 12:23:57 -0000	1.17
+++ sys/dev/ic/if_wi_ieee.h	2 Mar 2004 15:49:50 -0000
@@ -131,6 +131,15 @@
 #define WI_STYPE_CTL_CFEND	0x00E0
 #define WI_STYPE_CTL_CFENDACK	0x00F0
 
+#define WI_STYPE_DATA		0x0000
+#define WI_STYPE_DATA_CFACK	0x0010
+#define WI_STYPE_DATA_CFPOLL	0x0020
+#define WI_STYPE_DATA_CFACKPOLL	0x0030
+#define WI_STYPE_NULLFUNC	0x0040
+#define WI_STYPE_CFACK		0x0050
+#define WI_STYPE_CFPOLL		0x0060
+#define WI_STYPE_CFACKPOLL	0x0070
+
 struct wi_mgmt_hdr {
 	u_int16_t		frame_ctl;
 	u_int16_t		duration;
Index: sys/dev/ic/if_wireg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wireg.h,v
retrieving revision 1.32
diff -u -r1.32 if_wireg.h
--- sys/dev/ic/if_wireg.h	25 Jun 2003 17:38:55 -0000	1.32
+++ sys/dev/ic/if_wireg.h	2 Mar 2004 15:49:53 -0000
@@ -34,7 +34,8 @@
  *	From: if_wireg.h,v 1.8.2.2 2001/08/25 00:48:25 nsayer Exp $
  */
 
-#define WI_TIMEOUT	50000	/* 10x XXX just a guess at a good value.  */
+#define WI_DELAY	5
+#define WI_TIMEOUT	(500000/WI_DELAY)	/* 500ms */
 
 #define WI_PORT0	0
 #define WI_PORT1	1
Index: sys/dev/ic/if_wivar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/if_wivar.h,v
retrieving revision 1.21
diff -u -r1.21 if_wivar.h
--- sys/dev/ic/if_wivar.h	6 Sep 2003 20:53:57 -0000	1.21
+++ sys/dev/ic/if_wivar.h	2 Mar 2004 15:49:53 -0000
@@ -51,6 +51,7 @@
 	int			wi_tx_mgmt_id;
 	int			wi_flags;
 	int			wi_if_flags;
+	int			wi_cmd_count;
 	u_int16_t		wi_procframe;
 	u_int16_t		wi_ptype;
 	u_int16_t		wi_portnum;