Now that wpi(4) does 802.11a, and I'm using my old laptop to test inteldrm(4) diffs, I got annoyed that from time to time wpi(4) craps out and I have to get out of my lazy chair to bring the interface back up. So here's a diff that automatically reinitializes the hardware if this happens.
ok? P.S. I'm planning to make similar changes to the related drivers for other Intel wireless chips once this has been reviewed. Index: if_wpi.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_wpi.c,v retrieving revision 1.115 diff -u -p -r1.115 if_wpi.c --- if_wpi.c 16 Nov 2013 12:46:29 -0000 1.115 +++ if_wpi.c 21 Nov 2013 20:10:21 -0000 @@ -75,7 +75,8 @@ void wpi_radiotap_attach(struct wpi_sof #endif int wpi_detach(struct device *, int); int wpi_activate(struct device *, int); -void wpi_resume(void *, void *); +void wpi_resume(struct wpi_softc *); +void wpi_init_task(void *, void *); int wpi_nic_lock(struct wpi_softc *); int wpi_read_prom_data(struct wpi_softc *, uint32_t, void *, int); int wpi_dma_contig_alloc(bus_dma_tag_t, struct wpi_dma_info *, @@ -189,8 +190,6 @@ wpi_attach(struct device *parent, struct sc->sc_pcitag = pa->pa_tag; sc->sc_dmat = pa->pa_dmat; - task_set(&sc->sc_resume_t, wpi_resume, sc, NULL); - /* * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space (the vendor driver hard-codes it as E0h.) @@ -327,6 +326,7 @@ wpi_attach(struct device *parent, struct wpi_radiotap_attach(sc); #endif timeout_set(&sc->calib_to, wpi_calib_timeout, sc); + task_set(&sc->init_task, wpi_init_task, sc, NULL); return; /* Free allocated memory if something failed during attachment. */ @@ -364,6 +364,7 @@ wpi_detach(struct device *self, int flag int qid; timeout_del(&sc->calib_to); + task_del(systq, &sc->init_task); /* Uninstall interrupt handler. */ if (sc->sc_ih != NULL) @@ -396,7 +397,7 @@ wpi_activate(struct device *self, int ac wpi_stop(ifp, 0); break; case DVACT_RESUME: - task_add(systq, &sc->sc_resume_t); + wpi_resume(sc); break; } @@ -404,24 +405,31 @@ wpi_activate(struct device *self, int ac } void -wpi_resume(void *arg1, void *arg2) +wpi_resume(struct wpi_softc *sc) { - struct wpi_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; pcireg_t reg; - int s; /* Clear device-specific "PCI retry timeout" register (41h). */ reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); reg &= ~0xff00; pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg); + task_add(systq, &sc->init_task); +} + +void +wpi_init_task(void *arg1, void *args2) +{ + struct wpi_softc *sc = arg1; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s; + s = splnet(); while (sc->sc_flags & WPI_FLAG_BUSY) tsleep(&sc->sc_flags, 0, "wpipwr", 0); sc->sc_flags |= WPI_FLAG_BUSY; - if (ifp->if_flags & IFF_UP) + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) wpi_init(ifp); sc->sc_flags &= ~WPI_FLAG_BUSY; @@ -1620,8 +1628,8 @@ wpi_intr(void *arg) printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname); /* Dump firmware error log and stop. */ wpi_fatal_intr(sc); - ifp->if_flags &= ~IFF_UP; wpi_stop(ifp, 1); + task_add(systq, &sc->init_task); return 1; } if ((r1 & (WPI_INT_FH_RX | WPI_INT_SW_RX)) || Index: if_wpivar.h =================================================================== RCS file: /cvs/src/sys/dev/pci/if_wpivar.h,v retrieving revision 1.24 diff -u -p -r1.24 if_wpivar.h --- if_wpivar.h 14 Nov 2013 12:34:30 -0000 1.24 +++ if_wpivar.h 21 Nov 2013 20:10:21 -0000 @@ -166,6 +166,8 @@ struct wpi_softc { struct timeout calib_to; int calib_cnt; + struct task init_task; + struct wpi_fw_info fw; uint32_t errptr; @@ -180,7 +182,6 @@ struct wpi_softc { int8_t maxpwr[IEEE80211_CHAN_MAX]; int sc_tx_timer; - struct task sc_resume_t; #if NBPFILTER > 0 caddr_t sc_drvbpf;