[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;