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;