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