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;