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 11 Aug 2007 15:53:02 -0000 @@ -67,6 +67,8 @@ #include +#include + #include #include @@ -79,6 +81,7 @@ #define DPRINTFN(n, x) #endif + /* * Supported rates for 802.11a/b/g modes (in 500Kbps unit). */ @@ -163,6 +166,10 @@ 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*); + +static int wpi_sysctl_handler(SYSCTLFN_PROTO); +static int wpi_root_num; CFATTACH_DECL(wpi, sizeof (struct wpi_softc), wpi_match, wpi_attach, wpi_detach, NULL); @@ -198,13 +205,23 @@ bus_space_handle_t memh; pci_intr_handle_t ih; pcireg_t data; - int error, ac, revision; + int error, ac, revision, rc, wpi_nodenum; + const struct sysctlnode * node; sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; 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); @@ -377,6 +394,34 @@ ieee80211_announce(ic); + /* wpi sysctl setup */ + + sc->wpi_rfkill = -1; + + if ((rc = sysctl_createv(&sc->wpi_clog, 0, NULL, &node, + 0, CTLTYPE_NODE, sc->sc_dev.dv_xname, + SYSCTL_DESCR("wpi per-controller controls"), + NULL, 0, NULL, 0, CTL_HW, wpi_root_num, CTL_CREATE, + CTL_EOL)) != 0) { + aprint_error("%s: couldn't create sysctl node\n", + sc->sc_dev.dv_xname); + goto fail5; + } + + wpi_nodenum = node->sysctl_num; + + if ((rc = sysctl_createv(&sc->wpi_clog, 0, NULL, &node, + CTLFLAG_READONLY, + CTLTYPE_INT, "wpi_hw_transmitter", + SYSCTL_DESCR("wpi hw transmitter status"), + wpi_sysctl_handler, 0, sc, + 0, CTL_HW, wpi_root_num, wpi_nodenum, CTL_CREATE, + CTL_EOL)) != 0) { + aprint_error("%s: couldn't create sysctl node\n", + sc->sc_dev.dv_xname); + goto fail5; + } + return; fail5: wpi_free_tx_ring(sc, &sc->svcq); @@ -420,6 +465,8 @@ bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz); + workqueue_destroy(sc->wkq); + return 0; } @@ -1260,7 +1307,6 @@ sc->sc_dev.dv_xname); } - fail3: firmware_free(dfw,size); fail2: firmware_close(fw); fail1: return error; @@ -1589,10 +1635,14 @@ /* 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 */ + ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + WPI_WRITE(sc, WPI_UCODE_SET, WPI_DISABLE_CMD); + sc->wpi_rfkill = 0; + } else { + aprint_error("%s: Radio transmitter is on\n", + sc->sc_dev.dv_xname); + sc->wpi_rfkill = 1; + workqueue_enqueue(sc->wkq, &sc->wk, NULL); } break; } @@ -1661,13 +1711,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 +3050,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); @@ -3063,6 +3113,26 @@ 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); + sc->wpi_rfkill = 1; + } else { + aprint_error("%s: Radio transmitter is off\n", + sc->sc_dev.dv_xname); + sc->wpi_rfkill = 0; + /* + * 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 +3183,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 +3216,88 @@ 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); +} + +static int +wpi_sysctl_handler(SYSCTLFN_ARGS) +{ + int error, rfkill; + struct sysctlnode node; + struct ifnet *ifp; + struct wpi_softc *sc; + + node = *rnode; + sc = node.sysctl_data; + ifp = sc->sc_ic.ic_ifp; + + /* + * If the card is currently down, we don't have the current status of the + * hardware transmitter. We need to up it to get the status of the + * transmitter + */ + + if ((ifp->if_flags & IFF_UP) == 0) { + ifp->if_flags |= IFF_UP; + wpi_init(ifp); + wpi_stop(ifp,1); + ifp->if_flags &= ~IFF_UP; + } + + rfkill = sc->wpi_rfkill; + + node.sysctl_data = &rfkill; + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + return error; +} + +/* + * Set up sysctl(3) MIB, hw.wpi.* - Individual controllers will be + * set up in wpi_attach() + */ +SYSCTL_SETUP(sysctl_wpi, "sysctl wpi subtree setup") +{ + int rc; + const struct sysctlnode *node; + + if ((rc = sysctl_createv(clog, 0, NULL, NULL, + 0, CTLTYPE_NODE, "hw", NULL, + NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) { + goto err; + } + + if ((rc = sysctl_createv(clog, 0, NULL, &node, + 0, CTLTYPE_NODE, "wpi", + SYSCTL_DESCR("wpi interface controls"), + NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) { + goto err; + } + + wpi_root_num = node->sysctl_num; +¦ +#ifdef WPI_DEBUG + if ((rc = sysctl_createv(clog, 0, NULL, &node, + CTLFLAG_READWRITE, + CTLTYPE_INT, "debug", + SYSCTL_DESCR("wpi debug level"), + NULL, 0, &wpi_debug, 0, CTL_HW, wpi_root_num, CTL_CREATE, + CTL_EOL)) != 0) { + goto err; + } +#endif + + return; + +err: + aprint_error("%s: syctl_createv failed (rc = %d)\n", __func__, rc); +} + 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 11 Aug 2007 15:53:02 -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 11 Aug 2007 15:53:02 -0000 @@ -157,6 +157,9 @@ struct callout calib_to; int calib_cnt; + struct workqueue *wkq; + struct work wk; + struct wpi_config config; int temp; @@ -186,4 +189,7 @@ #define sc_txtap sc_txtapu.th int sc_txtap_len; #endif + + struct sysctllog *wpi_clog; + int wpi_rfkill; };