On Thu, Nov 28, 2013 at 09:24:32PM +0100, Mark Kettenis wrote: > 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.
No regressions on: iwn0 at pci3 dev 0 function 0 "Intel Centrino Advanced-N 6200" rev 0x35 and iwn0 at pci2 dev 0 function 0 "Intel WiFi Link 1000" rev 0x00 Suspend/resume still works, wifi comes back as expected. I've never seen fatal firmware errors with either adapter. I don't have iwi so I cannot test that. Diff is OK by me. > 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;