Subject: Re: wpi(4) and transmitter being off
To: Stephen Borrill <netbsd@precedence.co.uk>
From: None <degroote@netbsd.org>
List: tech-net
Date: 08/08/2007 00:24:44
--DocE+STaALJfprDB
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline

On Mon, Aug 06, 2007 at 10:00:49AM +0100, Stephen Borrill wrote:
[snip]
> Yes, spotted that.
>
> After having worked out that "ifconfig wpi0 up" would switch the
> interface into RUNNING iff the transmitter was on, I was able to at least
> print a message at boot time giving a count down asking for the
> transmitter button to be pressed. So it's liveable with (and I'll be
> asking my OEM supplier about enabling the transmitter by default), but
> not ideal.
>
> If we can get the transmitter is on signal, that's going to be great too.
>

Can you test the following patch. It tests the status of the transmitter
when we init the card and improve off->on transition. 

Note the patch is for current. I don't think you will have trouble to run
in on netbsd-4. Just remove the last args to workqueue_enqueue.

Take cares.
-- 
Arnaud Degroote
degroote@netbsd.org

--DocE+STaALJfprDB
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="wpi_rfkill.diff"

Index: if_wpi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wpi.c,v
retrieving revision 1.18
diff -u -r1.18 if_wpi.c
--- if_wpi.c	4 Aug 2007 18:24:24 -0000	1.18
+++ if_wpi.c	7 Aug 2007 22:16:50 -0000
@@ -67,6 +67,8 @@
 
 #include <dev/firmload.h>
 
+#include <sys/workqueue.h>
+
 #include <dev/pci/if_wpireg.h>
 #include <dev/pci/if_wpivar.h>
 
@@ -163,6 +165,7 @@
 static void wpi_hw_config(struct wpi_softc *);
 static int  wpi_init(struct ifnet *);
 static void wpi_stop(struct ifnet *, int);
+static void wpi_restart(struct work *, void*);
 
 CFATTACH_DECL(wpi, sizeof (struct wpi_softc), wpi_match, wpi_attach,
 	wpi_detach, NULL);
@@ -205,6 +208,15 @@
 
 	callout_init(&sc->calib_to, 0);
 
+	error = workqueue_create(&sc->wkq, "wpi_restart", wpi_restart, sc,
+							 0, IPL_NET, 0);
+
+	if (error) {
+		aprint_error("%s : can't create the restart work queue\n",
+					  sc->sc_dev.dv_xname);
+		return;
+	}
+
 	pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof devinfo);
 	revision = PCI_REVISION(pa->pa_class);
 	aprint_normal(": %s (rev. 0x%02x)\n", devinfo, revision);
@@ -1260,7 +1272,6 @@
 		    sc->sc_dev.dv_xname);
 	}
 
-
 fail3: 	firmware_free(dfw,size);
 fail2:	firmware_close(fw);
 fail1:	return error;
@@ -1532,7 +1543,6 @@
 wpi_notif_intr(struct wpi_softc *sc)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ifnet *ifp =  ic->ic_ifp;
 	struct wpi_rx_desc *desc;
 	struct wpi_rx_data *data;
 	uint32_t hw;
@@ -1585,14 +1595,16 @@
 			/* enabled/disabled notification */
 			DPRINTF(("state changed to %x\n", le32toh(*status)));
 
+
 			if (le32toh(*status) & 1) {
 				/* the radio button has to be pushed */
 				aprint_error("%s: Radio transmitter is off\n",
 					sc->sc_dev.dv_xname);
-				/* turn the interface down */
-				ifp->if_flags &= ~IFF_UP;
-				wpi_stop(ifp, 1);
-				return;	/* no further processing */
+				WPI_WRITE(sc, WPI_UCODE_SET, WPI_DISABLE_CMD);
+			} else {
+				aprint_error("%s: Radio transmitter is on\n",
+					sc->sc_dev.dv_xname);
+				workqueue_enqueue(sc->wkq, &sc->wk, NULL);
 			}
 			break;
 		}
@@ -1661,13 +1673,13 @@
 		wpi_stop(sc->sc_ic.ic_ifp, 1);
 		return 1;
 	}
-
+	
 	if (r & WPI_RX_INTR)
 		wpi_notif_intr(sc);
 
 	if (r & WPI_ALIVE_INTR)	/* firmware initialized */
 		wakeup(sc);
-
+	
 	/* re-enable interrupts */
 	if (ifp->if_flags & IFF_UP)
 		WPI_WRITE(sc, WPI_MASK, WPI_INTR_MASK);
@@ -3000,7 +3012,7 @@
 {
 	struct wpi_softc *sc = ifp->if_softc;
 	struct ieee80211com *ic = &sc->sc_ic;
-	uint32_t tmp;
+	uint32_t tmp, rfkill;
 	int qid, ntries, error;
 
 	wpi_stop(ifp,1);
@@ -3025,6 +3037,7 @@
 	WPI_WRITE(sc, WPI_RX_CONFIG, 0xa9601010);
 	wpi_mem_unlock(sc);
 
+
 	/* init Tx rings */
 	wpi_mem_lock(sc);
 	wpi_mem_write(sc, WPI_MEM_MODE, 2); /* bypass mode */
@@ -3063,6 +3076,24 @@
 		goto fail1;
 	}
 
+	/* Check the status of transmittor */
+	wpi_mem_lock(sc);
+	rfkill = wpi_mem_read(sc, WPI_MEM_RFKILL);
+	wpi_mem_unlock(sc);
+
+	if (rfkill & 0x1) {
+		aprint_error("%s: Radio transmitter is on\n",
+					 sc->sc_dev.dv_xname); 
+	} else {
+		aprint_error("%s: Radio transmitter is off\n", 
+					  sc->sc_dev.dv_xname);
+		/* 
+		 * Just return, we need to keep the card in a valide state to see the 
+		 * status change of transmitter 
+		 */
+		return 1;
+	}
+
 	/* wait for thermal sensors to calibrate */
 	for (ntries = 0; ntries < 1000; ntries++) {
 		if ((sc->temp = (int)WPI_READ(sc, WPI_TEMPERATURE)) != 0)	
@@ -3113,12 +3144,14 @@
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+	
+	/* reset the on-board processor */
+	WPI_WRITE(sc, WPI_RESET, WPI_NEVO_RESET);
 
 	/* disable interrupts */
 	WPI_WRITE(sc, WPI_MASK, 0);
-	WPI_WRITE(sc, WPI_INTR, WPI_INTR_MASK);
-	WPI_WRITE(sc, WPI_INTR_STATUS, 0xff);
-	WPI_WRITE(sc, WPI_INTR_STATUS, 0x00070000);
+	WPI_WRITE(sc, WPI_INTR, 0xffffffff);
+	WPI_WRITE(sc, WPI_INTR_STATUS, 0xffffffff);
 
 	wpi_mem_lock(sc);
 	wpi_mem_write(sc, WPI_MEM_MODE, 0);
@@ -3144,3 +3177,14 @@
 	tmp = WPI_READ(sc, WPI_RESET);
 	WPI_WRITE(sc, WPI_RESET, tmp | WPI_SW_RESET);
 }
+
+static void
+wpi_restart(struct work * wkp, void *arg) 
+{
+	struct wpi_softc * sc;
+	
+	sc = arg;
+	(void) wkp;
+
+	wpi_init(sc->sc_ic.ic_ifp);
+}
Index: if_wpireg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wpireg.h,v
retrieving revision 1.5
diff -u -r1.5 if_wpireg.h
--- if_wpireg.h	18 Jul 2007 18:49:17 -0000	1.5
+++ if_wpireg.h	7 Aug 2007 22:16:50 -0000
@@ -48,6 +48,8 @@
 #define WPI_GPIO_CTL		0x024
 #define WPI_EEPROM_CTL		0x02c
 #define WPI_EEPROM_STATUS	0x030
+#define WPI_UCODE			0x054
+#define WPI_UCODE_SET		0x058
 #define WPI_UCODE_CLR		0x05c
 #define WPI_TEMPERATURE		0x060
 #define WPI_CHICKEN		0x100
@@ -88,6 +90,7 @@
 #define WPI_MEM_CLOCK2		0x3008
 #define WPI_MEM_POWER		0x300c
 #define WPI_MEM_PCIDEV		0x3010
+#define WPI_MEM_RFKILL		0x3014
 #define WPI_MEM_UCODE_CTL	0x3400
 #define WPI_MEM_UCODE_SRC	0x3404
 #define WPI_MEM_UCODE_DST	0x3408
@@ -136,7 +139,7 @@
 /* possible flags for register WPI_PLL_CTL */
 #define WPI_PLL_INIT		(1 << 24)
 
-/* possible flags for register WPI_UCODE_CLR */
+/* possible flags for register WPI_UCODE_* */
 #define WPI_RADIO_OFF		(1 << 1)
 #define WPI_DISABLE_CMD		(1 << 2)
 
@@ -150,10 +153,11 @@
 /* possible flags for register WPI_INTR_CSR */
 #define WPI_ALIVE_INTR	(1 << 0)
 #define WPI_WAKEUP_INTR	(1 << 1)
+#define WPI_RF_KILL		(1 << 7)
 #define WPI_SW_ERROR	(1 << 25)
-#define WPI_TX_INTR	(1 << 27)
+#define WPI_TX_INTR		(1 << 27)
 #define WPI_HW_ERROR	(1 << 29)
-#define WPI_RX_INTR	(1 << 31)
+#define WPI_RX_INTR		(1 << 31)
 
 #define WPI_INTR_MASK							\
 	(WPI_SW_ERROR | WPI_HW_ERROR | WPI_TX_INTR | WPI_RX_INTR |	\
Index: if_wpivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wpivar.h,v
retrieving revision 1.6
diff -u -r1.6 if_wpivar.h
--- if_wpivar.h	9 Jul 2007 19:38:52 -0000	1.6
+++ if_wpivar.h	7 Aug 2007 22:16:50 -0000
@@ -157,6 +157,9 @@
 	struct callout		calib_to;
 	int			calib_cnt;	
 
+	struct workqueue	*wkq;
+	struct work			wk;
+
 	struct wpi_config	config;
 	int			temp;
 

--DocE+STaALJfprDB--