Subject: Re: botch in wi0 on alpha
To: mel kravitz <melk@switchpwr.com>
From: David Young <dyoung@pobox.com>
List: tech-net
Date: 12/22/2003 02:18:42
--W/nzBZO5zC0uMSeA
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sun, Dec 21, 2003 at 09:25:40PM -0600, David Young wrote:
> On Sun, Dec 21, 2003 at 08:28:04AM -0500, mel kravitz wrote:
> > Any one trying to use wi0 (pci card) on alpha with -current
> > (1.6ZG)?  ifconfig wi0 inet xxxy.... will crash the box , as
> > reported: http://mail-index.netbsd.org/port-alpha/2003/05/06/0000.html
> > This is on an AlphaServer 500/333 with  supported card:
> 
> I do not have the docs I need to interpret the machine-check
> exception. Does anyone? My guess is that it indicates either bad
> alignment, or else some bus exception raised by your wi(4) instance---can
> a PCI adapter return the equivalent of EAGAIN or EBUSY?
> 
> wi(4) contains no bus barriers, but lots of code could be sensitive to
> out-of-order reads & writes. I am adding barriers where I think they are
> called for. I will send a patch, soon. If somebody who understands the
> fine points of bus barriers will review my patches, I would appreciate it.

I propose to add the attached bus barriers to wi, just as soon as there
is a way for me to test them. Note that these are no-ops, now.

Dave

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

--W/nzBZO5zC0uMSeA
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=wi-barriers

Index: sys/dev/ic/wi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wi.c,v
retrieving revision 1.148
diff -u -r1.148 wi.c
--- sys/dev/ic/wi.c	7 Dec 2003 05:44:49 -0000	1.148
+++ sys/dev/ic/wi.c	22 Dec 2003 08:08:34 -0000
@@ -241,7 +241,9 @@
 
 	/* Make sure interrupts are disabled. */
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
+	CSR_WBW_2(sc, WI_INT_EN, WI_EVENT_ACK);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
+	CSR_SYNC_2(sc, WI_INT_EN, WI_EVENT_ACK);/* XXX paranoia? */
 
 	sc->sc_invalid = 0;
 
@@ -523,7 +525,9 @@
 
 	if ((ifp->if_flags & IFF_UP) == 0) {
 		CSR_WRITE_2(sc, WI_INT_EN, 0);
+		CSR_WBW_2(sc, WI_INT_EN, WI_EVENT_ACK);	/* XXX paranoia? */
 		CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
+		CSR_SYNC_2(sc, WI_INT_EN, WI_EVENT_ACK);/* XXX paranoia? */
 		return 1;
 	}
 
@@ -531,6 +535,7 @@
 	 * do not disable interrupts.
 	 */
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
+	CSR_WBW_2(sc, WI_INT_EN, WI_INT_EN);
 
 	/* maximum 10 loops per interrupt */
 	for (i = 0; i < 10; i++) {
@@ -542,6 +547,7 @@
 		 * it is updated.
 		 */
 		status = CSR_READ_2(sc, WI_EVENT_STAT);
+		CSR_RBR_2(sc, WI_EVENT_STAT, WI_EVENT_STAT);/* XXX paranoia? */
 		if ((status & WI_INTRS) == 0)
 			break;
 
@@ -568,6 +574,7 @@
 
 	/* re-enable interrupts */
 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
+	CSR_SYNC_2(sc, WI_INT_EN, WI_INT_EN);	/* XXX paranoia? */
 
 	return 1;
 }
@@ -725,6 +732,7 @@
 
 	/* Enable interrupts */
 	CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
+	CSR_SYNC_2(sc, WI_INT_EN, WI_INT_EN);	/* XXX paranoia? */
 
 	if (!wasenabled &&
 	    ic->ic_opmode == IEEE80211_M_HOSTAP &&
@@ -747,7 +755,6 @@
 		if (sc->sc_firmware_type != WI_LUCENT)
 			wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
 	}
-
  out:
 	if (error) {
 		printf("%s: interface not running\n", sc->sc_dev.dv_xname);
@@ -775,6 +782,7 @@
 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 	if (!sc->sc_invalid) {
 		CSR_WRITE_2(sc, WI_INT_EN, 0);
+		CSR_SYNC_2(sc, WI_INT_EN, WI_INT_EN);
 		wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
 	}
 
@@ -1130,7 +1138,9 @@
 		return error;
 	}
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
+	CSR_WBW_2(sc, WI_INT_EN, WI_EVENT_ACK);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, ~0);
+	CSR_SYNC_2(sc, WI_INT_EN, WI_EVENT_ACK);
 
 	/* Calibrate timer. */
 	wi_write_val(sc, WI_RID_TICK_TIME, 0);
@@ -1461,10 +1471,12 @@
 	u_int32_t rstamp;
 
 	fid = CSR_READ_2(sc, WI_RX_FID);
+	CSR_RBW_2(sc, WI_RX_FID, WI_EVENT_ACK);
 
 	/* 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);
+		CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 		ifp->if_ierrors++;
 		DPRINTF(("wi_rx_intr: read fid %x failed\n", fid));
 		return;
@@ -1480,6 +1492,7 @@
 	if ((status & WI_STAT_ERRSTAT) != 0 &&
 	    ic->ic_opmode != IEEE80211_M_MONITOR) {
 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
+		CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 		ifp->if_ierrors++;
 		DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status));
 		return;
@@ -1497,6 +1510,7 @@
 	if (off + len > MCLBYTES) {
 		if (ic->ic_opmode != IEEE80211_M_MONITOR) {
 			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
+			CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 			ifp->if_ierrors++;
 			DPRINTF(("wi_rx_intr: oversized packet\n"));
 			return;
@@ -1507,6 +1521,7 @@
 	MGETHDR(m, M_DONTWAIT, MT_DATA);
 	if (m == NULL) {
 		CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
+		CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 		ifp->if_ierrors++;
 		DPRINTF(("wi_rx_intr: MGET failed\n"));
 		return;
@@ -1515,6 +1530,7 @@
 		MCLGET(m, M_DONTWAIT);
 		if ((m->m_flags & M_EXT) == 0) {
 			CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
+			CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 			m_freem(m);
 			ifp->if_ierrors++;
 			DPRINTF(("wi_rx_intr: MCLGET failed\n"));
@@ -1530,6 +1546,7 @@
 	m->m_pkthdr.rcvif = ifp;
 
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 
 #if NBPFILTER > 0
 	if (sc->sc_drvbpf) {
@@ -1596,6 +1613,8 @@
 	u_int16_t status;
 
 	fid = CSR_READ_2(sc, WI_TX_CMP_FID);
+	CSR_RBW_2(sc, WI_TX_CMP_FID, WI_EVENT_ACK);
+
 	/* Read in the frame header */
 	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
 		printf("wi_tx_ex_intr: read fid %x failed\n", fid);
@@ -1651,6 +1670,7 @@
 	ifp->if_flags &= ~IFF_OACTIVE;
 bad_header:
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX_EXC);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 }
 
 static void
@@ -1661,6 +1681,7 @@
 	int fid, cur;
 
 	fid = CSR_READ_2(sc, WI_ALLOC_FID);
+	CSR_RBW_2(sc, WI_ALLOC_FID, WI_EVENT_ACK);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 
 	cur = sc->sc_txcur;
@@ -1700,6 +1721,8 @@
 	int fid;
 
 	fid = CSR_READ_2(sc, WI_TX_CMP_FID);
+	CSR_RBW_2(sc, WI_TX_CMP_FID, WI_EVENT_ACK);
+
 	/* Read in the frame header */
 	if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) {
 		printf("wi_tx_intr: read fid %x failed\n", fid);
@@ -1729,6 +1752,7 @@
 	ifp->if_flags &= ~IFF_OACTIVE;
 out:
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_TX);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 }
 
 static void
@@ -1742,6 +1766,7 @@
 	u_int32_t *ptr;
 
 	fid = CSR_READ_2(sc, WI_INFO_FID);
+	CSR_RBW_2(sc, WI_INFO_FID, WI_EVENT_ACK);
 	wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf));
 
 	switch (le16toh(ltbuf[1])) {
@@ -1811,6 +1836,7 @@
 		break;
 	}
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_INFO);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 }
 
 static int
@@ -2407,6 +2433,7 @@
 
 	/* wait for the busy bit to clear */
 	for (i = 500; i > 0; i--) {	/* 5s */
+		CSR_RBR_2(sc, WI_COMMAND, WI_COMMAND);	/* XXX paranoia? */
 		if ((CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY) == 0)
 			break;
 		DELAY(10*1000);	/* 10 m sec */
@@ -2419,7 +2446,11 @@
 	CSR_WRITE_2(sc, WI_PARAM0, val0);
 	CSR_WRITE_2(sc, WI_PARAM1, val1);
 	CSR_WRITE_2(sc, WI_PARAM2, val2);
+
+	/* Note that WI_COMMAND < WI_PARAM0 < WI_PARAM1 < WI_PARAM2. */
+	CSR_WBW_2(sc, WI_COMMAND, WI_PARAM2);
 	CSR_WRITE_2(sc, WI_COMMAND, cmd);
+	CSR_WBR_2(sc, WI_COMMAND, WI_EVENT_STAT);
 
 	if (cmd == WI_CMD_INI) {
 		/* XXX: should sleep here. */
@@ -2429,13 +2460,16 @@
 	for (i = 0; i < WI_TIMEOUT; i++) {
 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
 			break;
+		CSR_RBR_2(sc, WI_EVENT_STAT, WI_EVENT_STAT); /* XXX paranoia? */
 		DELAY(WI_DELAY);
 	}
 
 	status = CSR_READ_2(sc, WI_STATUS);
+	CSR_RBW_2(sc, WI_STATUS, WI_EVENT_ACK);
 
 	/* Ack the command */
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 
 	if (i == WI_TIMEOUT) {
 		printf("%s: command timed out, cmd=0x%x, arg=0x%x\n",
@@ -2456,11 +2490,16 @@
 {
 	int i, status;
 
+	/* finish pending I/O before seeking. */
+	CSR_WBW_2(sc, WI_SEL0, WI_DATA0);
 	CSR_WRITE_2(sc, WI_SEL0, id);
+	CSR_WBW_2(sc, WI_SEL0, WI_OFF0);	/* XXX paranoia? */
 	CSR_WRITE_2(sc, WI_OFF0, off);
+	CSR_WBR_2(sc, WI_SEL0, WI_OFF0);
 
 	for (i = 0; ; i++) {
 		status = CSR_READ_2(sc, WI_OFF0);
+		CSR_RBR_2(sc, WI_OFF0, WI_OFF0);	/* XXX paranoia? */
 		if ((status & WI_OFF_BUSY) == 0)
 			break;
 		if (i == WI_TIMEOUT) {
@@ -2534,11 +2573,13 @@
 	 */
 	if ((sc->sc_flags & WI_FLAGS_BUG_AUTOINC) && (id & 0xf000) == 0) {
 		CSR_WRITE_2(sc, WI_DATA0, 0x1234);
+		CSR_WBW_2(sc, WI_DATA0, WI_DATA0);
 		CSR_WRITE_2(sc, WI_DATA0, 0x5678);
 		wi_seek_bap(sc, id, sc->sc_bap_off);
 		sc->sc_bap_off = WI_OFF_ERR;	/* invalidate */
 		if (CSR_READ_2(sc, WI_DATA0) != 0x1234 ||
-		    CSR_READ_2(sc, WI_DATA0) != 0x5678) {
+		    (CSR_RBR_2(sc, WI_DATA0, WI_DATA0),
+		     CSR_READ_2(sc, WI_DATA0)) != 0x5678) {
 			printf("%s: detect auto increment bug, try again\n",
 			    sc->sc_dev.dv_xname);
 			goto again;
@@ -2589,6 +2630,7 @@
 	for (i = 0; i < WI_TIMEOUT; i++) {
 		if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_ALLOC)
 			break;
+		CSR_RBR_2(sc, WI_EVENT_STAT, WI_EVENT_STAT);
 		if (i == WI_TIMEOUT) {
 			printf("%s: timeout in alloc\n", sc->sc_dev.dv_xname);
 			return ETIMEDOUT;
@@ -2596,6 +2638,7 @@
 		DELAY(1);
 	}
 	*idp = CSR_READ_2(sc, WI_ALLOC_FID);
+	CSR_RBW_2(sc, WI_ALLOC_FID, WI_EVENT_ACK);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_ALLOC);
 	return 0;
 }
Index: sys/dev/ic/wivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wivar.h,v
retrieving revision 1.41
diff -u -r1.41 wivar.h
--- sys/dev/ic/wivar.h	7 Dec 2003 05:44:49 -0000	1.41
+++ sys/dev/ic/wivar.h	22 Dec 2003 08:08:34 -0000
@@ -248,6 +248,63 @@
 			(sc->sc_pci? reg * 2: reg))
 #endif
 
+/* bus_space(9) lied? */
+#ifndef BUS_SPACE_BARRIER_SYNC
+#define BUS_SPACE_BARRIER_SYNC (BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
+#endif
+
+#ifndef BUS_SPACE_BARRIER_READ_BEFORE_READ
+#define BUS_SPACE_BARRIER_READ_BEFORE_READ BUS_SPACE_BARRIER_READ
+#endif
+
+#ifndef BUS_SPACE_BARRIER_READ_BEFORE_WRITE
+#define BUS_SPACE_BARRIER_READ_BEFORE_WRITE BUS_SPACE_BARRIER_READ
+#endif
+
+#ifndef BUS_SPACE_BARRIER_WRITE_BEFORE_READ
+#define BUS_SPACE_BARRIER_WRITE_BEFORE_READ BUS_SPACE_BARRIER_WRITE
+#endif
+
+#ifndef BUS_SPACE_BARRIER_WRITE_BEFORE_WRITE
+#define BUS_SPACE_BARRIER_WRITE_BEFORE_WRITE BUS_SPACE_BARRIER_WRITE
+#endif
+
+/*
+ * CSR bus barrier
+ *
+ * Complete outstanding read and/or write ops on [reg0, reg1]
+ * ([reg1, reg0]) before starting new ops on the same region. See
+ * acceptable bus_space_barrier(9) for the flag definitions.
+ */
+#define CSR_BARRIER_2(sc, reg0, reg1, flags)			\
+	bus_space_barrier(sc->sc_iot, sc->sc_ioh,		\
+	    (sc->sc_pci ? 2 : 1) * MIN(reg0, reg1),		\
+	    (sc->sc_pci ? 2 : 1) *				\
+	        (MAX(reg0, reg1) - MIN(reg0, reg1)) + 2, flags)
+
+/*
+ * Barrier convenience macros.
+ */
+/* sync */
+#define CSR_SYNC_2(sc, reg0, reg1)				\
+	CSR_BARRIER_2(sc, reg0, reg1, BUS_SPACE_BARRIER_SYNC)
+
+/* write-before-write */
+#define CSR_WBW_2(sc, reg0, reg1)				\
+	CSR_BARRIER_2(sc, reg0, reg1, BUS_SPACE_BARRIER_WRITE_BEFORE_WRITE)
+
+/* write-before-read */
+#define CSR_WBR_2(sc, reg0, reg1)				\
+	CSR_BARRIER_2(sc, reg0, reg1, BUS_SPACE_BARRIER_WRITE_BEFORE_READ)
+
+/* read-before-read */
+#define CSR_RBR_2(sc, reg0, reg1)				\
+	CSR_BARRIER_2(sc, reg0, reg1, BUS_SPACE_BARRIER_READ_BEFORE_READ)
+
+/* read-before-read */
+#define CSR_RBW_2(sc, reg0, reg1)				\
+	CSR_BARRIER_2(sc, reg0, reg1, BUS_SPACE_BARRIER_READ_BEFORE_WRITE)
+
 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
 #define bus_space_write_stream_2	bus_space_write_2
 #define bus_space_write_multi_stream_2	bus_space_write_multi_2
Index: sys/dev/pci/if_wi_pci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wi_pci.c,v
retrieving revision 1.30
diff -u -r1.30 if_wi_pci.c
--- sys/dev/pci/if_wi_pci.c	14 Dec 2003 10:04:33 -0000	1.30
+++ sys/dev/pci/if_wi_pci.c	22 Dec 2003 08:08:34 -0000
@@ -175,17 +175,23 @@
 
 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
 	    WI_PCI_COR, WI_COR_SOFT_RESET);
+	bus_space_barrier(sc->sc_iot, sc->sc_ioh, WI_PCI_COR, 2,
+	    BUS_SPACE_BARRIER_SYNC);
 	DELAY(250*1000); /* 1/4 second */
 
 	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
 	    WI_PCI_COR, WI_COR_CLEAR);
+	bus_space_barrier(sc->sc_iot, sc->sc_ioh, WI_PCI_COR, 2,
+	    BUS_SPACE_BARRIER_SYNC);
 	DELAY(500*1000); /* 1/2 second */
 
 	/* wait 2 seconds for firmware to complete initialization. */
 
-	for (i = 200000; i--; DELAY(10))
+	for (i = 200000; i--; DELAY(10)) {
 		if (!(CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
 			break;
+		CSR_RBR_2(sc, WI_COMMAND, WI_COMMAND);
+	}
  
 	if (i < 0) {
 		printf("%s: PCI reset timed out\n", sc->sc_dev.dv_xname);
@@ -329,7 +335,9 @@
 	sc->sc_ioh = ioh;
 	/* Make sure interrupts are disabled. */
 	CSR_WRITE_2(sc, WI_INT_EN, 0);
+	CSR_WBW_2(sc, WI_INT_EN, WI_EVENT_ACK);
 	CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 
 	if (wpp->wpp_chip == CHIP_PLX_OTHER) {
 		uint32_t command;
Index: sys/dev/pcmcia/if_wi_pcmcia.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pcmcia/if_wi_pcmcia.c,v
retrieving revision 1.38
diff -u -r1.38 if_wi_pcmcia.c
--- sys/dev/pcmcia/if_wi_pcmcia.c	7 Dec 2003 05:44:49 -0000	1.38
+++ sys/dev/pcmcia/if_wi_pcmcia.c	22 Dec 2003 08:08:34 -0000
@@ -612,25 +612,37 @@
 		CSR_WRITE_2(sc, WI_PARAM0, WI_AUX_KEY0);
 		CSR_WRITE_2(sc, WI_PARAM1, WI_AUX_KEY1);
 		CSR_WRITE_2(sc, WI_PARAM2, WI_AUX_KEY2);
+		/* Note: WI_PARAM0 < WI_PARAM1 < WI_PARAM2 < WI_CNTL. */
+		CSR_WBW_2(sc, WI_PARAM0, WI_CNTL);
 		CSR_WRITE_2(sc, WI_CNTL, WI_CNTL_AUX_ENA_CNTL);
+		/* no use tsleep'ing until after the register is written. */
+		CSR_SYNC_2(sc, WI_CNTL, WI_CNTL);
 	}
 
 	/* issue read EEPROM command: XXX copied from wi_cmd() */
 	CSR_WRITE_2(sc, WI_PARAM0, 0);
 	CSR_WRITE_2(sc, WI_PARAM1, 0);
 	CSR_WRITE_2(sc, WI_PARAM2, 0);
+	/* Note: WI_COMMAND < WI_PARAM0 < WI_PARAM1 < WI_PARAM2. */
+	CSR_WBW_2(sc, WI_COMMAND, WI_PARAM2);
 	CSR_WRITE_2(sc, WI_COMMAND, WI_CMD_READEE);
+	CSR_WBR_2(sc, WI_COMMAND, WI_EVENT_STAT);
         for (i = 0; i < WI_TIMEOUT; i++) {
                 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
                         break;
+		CSR_RBR_2(sc, WI_EVENT_STAT, WI_EVENT_STAT);/* XXX paranoia? */
                 DELAY(1);
         }
         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
+	CSR_WBR_2(sc, WI_EVENT_ACK, WI_EVENT_STAT);
 
 	CSR_WRITE_2(sc, WI_AUX_PAGE, WI_SBCF_PDIADDR / WI_AUX_PGSZ);
+	CSR_WBW_2(sc, WI_AUX_PAGE, WI_AUX_OFFSET);
 	CSR_WRITE_2(sc, WI_AUX_OFFSET, WI_SBCF_PDIADDR % WI_AUX_PGSZ);
+	CSR_WBR_2(sc, WI_AUX_DATA, WI_AUX_OFFSET);
 	CSR_READ_MULTI_STREAM_2(sc, WI_AUX_DATA,
 	    (u_int16_t *)ebuf, sizeof(ebuf) / 2);
+	CSR_RBW_2(sc, WI_AUX_DATA, WI_AUX_PAGE);
 	if (GETLE16(ebuf) > sizeof(ebuf))
 		return EIO;
 	if (wi_pcmcia_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf)))
@@ -667,9 +679,12 @@
 		addr = GETLE32(p);	p += 4;
 		len  = GETLE16(p);	p += 2;
 		CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
+		CSR_WBW_2(sc, WI_AUX_PAGE, WI_AUX_OFFSET);
 		CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
+		CSR_WBW_2(sc, WI_AUX_OFFSET, WI_AUX_DATA);
 		CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
 		    (const u_int16_t *)p, len / 2);
+		CSR_WBW_2(sc, WI_AUX_PAGE, WI_AUX_DATA);
 		p += len;
 	}
 	
@@ -690,9 +705,12 @@
 			if (eid != id)
 				continue;
 			CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
+			CSR_WBW_2(sc, WI_AUX_PAGE, WI_AUX_OFFSET);
 			CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
+			CSR_WBW_2(sc, WI_AUX_OFFSET, WI_AUX_DATA);
 			CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
 			    (const u_int16_t *)q, len / 2);
+			CSR_WBW_2(sc, WI_AUX_OFFSET, WI_AUX_PAGE);
 			break;
 		}
 	}
@@ -707,12 +725,16 @@
 	u_int16_t hcr;
 
 	CSR_WRITE_2(sc, WI_COR, WI_COR_RESET);
+	/* no use tsleep'ing until after the register is written */
+	CSR_SYNC_2(sc, WI_COR, WI_COR);
 	tsleep(sc, PWAIT, "wiinit", 1);
 	hcr = CSR_READ_2(sc, WI_HCR);
 	hcr = (hcr & WI_HCR_4WIRE) | (mode & ~WI_HCR_4WIRE);
 	CSR_WRITE_2(sc, WI_HCR, hcr);
+	CSR_SYNC_2(sc, WI_HCR, WI_HCR);
 	tsleep(sc, PWAIT, "wiinit", 1);
 	CSR_WRITE_2(sc, WI_COR, WI_COR_IOMODE);
+	CSR_SYNC_2(sc, WI_COR, WI_COR);
 	tsleep(sc, PWAIT, "wiinit", 1);
 	return 0;
 }

--W/nzBZO5zC0uMSeA--