Just committed the wpi(4) version I mailed out last week. And here is the version for iwi(4) and iwn(4) as promised. I believe both suffer from the problem, although I think it is a long time ago since my iwn(4) had issues.
Please test if you can still suspend and resume with this diff, and if you are experiencing fatal firmware errors, check whether it does indeed help to keep your wireless interface working. Index: if_iwi.c =================================================================== RCS file: /home/cvs/src/sys/dev/pci/if_iwi.c,v retrieving revision 1.114 diff -u -p -r1.114 if_iwi.c --- if_iwi.c 14 Nov 2013 12:39:14 -0000 1.114 +++ if_iwi.c 28 Nov 2013 20:19:27 -0000 @@ -74,7 +74,8 @@ const struct pci_matchid iwi_devices[] = int iwi_match(struct device *, void *, void *); void iwi_attach(struct device *, struct device *, void *); int iwi_activate(struct device *, int); -void iwi_resume(void *, void *); +void iwi_resume(struct iwi_softc *); +void iwi_init_task(void *, void *); int iwi_alloc_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); void iwi_reset_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); void iwi_free_cmd_ring(struct iwi_softc *, struct iwi_cmd_ring *); @@ -174,8 +175,6 @@ iwi_attach(struct device *parent, struct sc->sc_pct = pa->pa_pc; sc->sc_pcitag = pa->pa_tag; - task_set(&sc->sc_resume_t, iwi_resume, sc, NULL); - /* clear device specific PCI configuration register 0x41 */ data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); data &= ~0x0000ff00; @@ -326,6 +325,7 @@ iwi_attach(struct device *parent, struct sc->sc_txtap.wt_ihdr.it_present = htole32(IWI_TX_RADIOTAP_PRESENT); #endif + task_set(&sc->init_task, iwi_init_task, sc, NULL); return; fail: while (--ac >= 0) @@ -345,7 +345,7 @@ iwi_activate(struct device *self, int ac iwi_stop(ifp, 0); break; case DVACT_RESUME: - task_add(systq, &sc->sc_resume_t); + iwi_resume(sc); break; } @@ -353,24 +353,31 @@ iwi_activate(struct device *self, int ac } void -iwi_resume(void *arg1, void *arg2) +iwi_resume(struct iwi_softc *sc) { - struct iwi_softc *sc = arg1; - struct ifnet *ifp = &sc->sc_ic.ic_if; pcireg_t data; - int s; /* clear device specific PCI configuration register 0x41 */ data = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40); data &= ~0x0000ff00; pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, data); + task_add(systq, &sc->init_task); +} + +void +iwi_init_task(void *arg1, void *arg2) +{ + struct iwi_softc *sc = arg1; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s; + s = splnet(); while (sc->sc_flags & IWI_FLAG_BUSY) tsleep(&sc->sc_flags, 0, "iwipwr", 0); sc->sc_flags |= IWI_FLAG_BUSY; - if (ifp->if_flags & IFF_UP) + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) iwi_init(ifp); sc->sc_flags &= ~IWI_FLAG_BUSY; @@ -1159,8 +1166,8 @@ iwi_intr(void *arg) if (r & IWI_INTR_FATAL_ERROR) { printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname); - ifp->if_flags &= ~IFF_UP; iwi_stop(ifp, 1); + task_add(systq, &sc->init_task); return 1; } Index: if_iwivar.h =================================================================== RCS file: /home/cvs/src/sys/dev/pci/if_iwivar.h,v retrieving revision 1.24 diff -u -p -r1.24 if_iwivar.h --- if_iwivar.h 14 Nov 2013 12:39:14 -0000 1.24 +++ if_iwivar.h 28 Nov 2013 20:17:43 -0000 @@ -112,9 +112,9 @@ struct iwi_softc { pcitag_t sc_pcitag; bus_size_t sc_sz; - int sc_tx_timer; + struct task init_task; - struct task sc_resume_t; + int sc_tx_timer; #if NBPFILTER > 0 caddr_t sc_drvbpf; Index: if_iwn.c =================================================================== RCS file: /home/cvs/src/sys/dev/pci/if_iwn.c,v retrieving revision 1.125 diff -u -p -r1.125 if_iwn.c --- if_iwn.c 14 Nov 2013 12:40:00 -0000 1.125 +++ if_iwn.c 28 Nov 2013 20:15:56 -0000 @@ -105,7 +105,8 @@ void iwn_radiotap_attach(struct iwn_sof #endif int iwn_detach(struct device *, int); int iwn_activate(struct device *, int); -void iwn_resume(void *, void *); +void iwn_resume(struct iwn_softc *); +void iwn_init_task(void *, void *); int iwn_nic_lock(struct iwn_softc *); int iwn_eeprom_lock(struct iwn_softc *); int iwn_init_otprom(struct iwn_softc *); @@ -309,8 +310,6 @@ iwn_attach(struct device *parent, struct sc->sc_pcitag = pa->pa_tag; sc->sc_dmat = pa->pa_dmat; - task_set(&sc->sc_resume_t, iwn_resume, sc, NULL); - /* * Get the offset of the PCI Express Capability Structure in PCI * Configuration Space. @@ -524,6 +523,7 @@ iwn_attach(struct device *parent, struct iwn_radiotap_attach(sc); #endif timeout_set(&sc->calib_to, iwn_calib_timeout, sc); + task_set(&sc->init_task, iwn_init_task, sc, NULL); return; /* Free allocated memory if something failed during attachment. */ @@ -686,6 +686,7 @@ iwn_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) @@ -721,7 +722,7 @@ iwn_activate(struct device *self, int ac iwn_stop(ifp, 0); break; case DVACT_RESUME: - task_add(systq, &sc->sc_resume_t); + iwn_resume(sc); break; } @@ -729,24 +730,31 @@ iwn_activate(struct device *self, int ac } void -iwn_resume(void *arg1, void *arg2) +iwn_resume(struct iwn_softc *sc) { - struct iwn_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); if (reg & 0xff00) pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00); + task_add(systq, &sc->init_task); +} + +void +iwn_init_task(void *arg1, void *arg2) +{ + struct iwn_softc *sc = arg1; + struct ifnet *ifp = &sc->sc_ic.ic_if; + int s; + s = splnet(); while (sc->sc_flags & IWN_FLAG_BUSY) tsleep(&sc->sc_flags, 0, "iwnpwr", 0); sc->sc_flags |= IWN_FLAG_BUSY; - if (ifp->if_flags & IFF_UP) + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP) iwn_init(ifp); sc->sc_flags &= ~IWN_FLAG_BUSY; @@ -2593,8 +2601,8 @@ iwn_intr(void *arg) printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname); /* Dump firmware error log and stop. */ iwn_fatal_intr(sc); - ifp->if_flags &= ~IFF_UP; iwn_stop(ifp, 1); + task_add(systq, &sc->init_task); return 1; } if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || Index: if_iwnvar.h =================================================================== RCS file: /home/cvs/src/sys/dev/pci/if_iwnvar.h,v retrieving revision 1.25 diff -u -p -r1.25 if_iwnvar.h --- if_iwnvar.h 14 Nov 2013 12:40:00 -0000 1.25 +++ if_iwnvar.h 28 Nov 2013 20:03:02 -0000 @@ -251,6 +251,8 @@ struct iwn_softc { int calib_cnt; struct iwn_calib_state calib; + struct task init_task; + struct iwn_fw_info fw; struct iwn_calib_info calibcmd[5]; uint32_t errptr; @@ -287,7 +289,6 @@ struct iwn_softc { uint8_t chainmask; int sc_tx_timer; - struct task sc_resume_t; #if NBPFILTER > 0 caddr_t sc_drvbpf;