Has anybody tried this diff?

On Mon, Aug 14, 2017 at 09:07:37AM +0200, Stefan Sperling wrote:
> This diff makes iwm_stop() always run in a process context.
> I want iwm_stop() to be able to sleep so that it can wait for asynchronous
> driver tasks, and perhaps even wait for firmware commands, in the future.
> 
> If the interrupt handler detects a fatal condition, instead of calling
> iwm_stop() directly, defer to the init task. The init task looks at flags
> to understand what happened and restarts or stops the device as appropriate.
> 
> I found that toggling the RF kill switch can trigger a fatal firmware error.
> Hence I am letting the interrupt handler check RF kill before checking for
> fatal firmware error. Provides better error reporting when the kill switch
> is used.
> 
> During suspend, bring the device down during the QUIESCE stage which
> is allowed to sleep.
> 
> dhclient/down/scan in a loop still works (as far as it always has, with
> various errors reported in dmesg). Suspend/resume still works.
> 
> ok?
> 
> Index: if_iwm.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
> retrieving revision 1.211
> diff -u -p -r1.211 if_iwm.c
> --- if_iwm.c  13 Aug 2017 18:08:03 -0000      1.211
> +++ if_iwm.c  14 Aug 2017 06:44:59 -0000
> @@ -6517,6 +6517,7 @@ iwm_stop(struct ifnet *ifp)
>       sc->sc_flags &= ~IWM_FLAG_BINDING_ACTIVE;
>       sc->sc_flags &= ~IWM_FLAG_STA_ACTIVE;
>       sc->sc_flags &= ~IWM_FLAG_TE_ACTIVE;
> +     sc->sc_flags &= ~IWM_FLAG_HW_ERR;
>  
>       sc->sc_newstate(ic, IEEE80211_S_INIT, -1);
>  
> @@ -7169,7 +7170,6 @@ int
>  iwm_intr(void *arg)
>  {
>       struct iwm_softc *sc = arg;
> -     struct ifnet *ifp = IC2IFP(&sc->sc_ic);
>       int handled = 0;
>       int r1, r2, rv = 0;
>       int isperiodic = 0;
> @@ -7218,6 +7218,15 @@ iwm_intr(void *arg)
>       /* ignored */
>       handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/));
>  
> +     if (r1 & IWM_CSR_INT_BIT_RF_KILL) {
> +             handled |= IWM_CSR_INT_BIT_RF_KILL;
> +             if (iwm_check_rfkill(sc)) {
> +                     task_add(systq, &sc->init_task);
> +                     rv = 1;
> +                     goto out;
> +             }
> +     }
> +
>       if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
>  #ifdef IWM_DEBUG
>               int i;
> @@ -7238,7 +7247,6 @@ iwm_intr(void *arg)
>  #endif
>  
>               printf("%s: fatal firmware error\n", DEVNAME(sc));
> -             iwm_stop(ifp);
>               task_add(systq, &sc->init_task);
>               rv = 1;
>               goto out;
> @@ -7248,7 +7256,8 @@ iwm_intr(void *arg)
>       if (r1 & IWM_CSR_INT_BIT_HW_ERR) {
>               handled |= IWM_CSR_INT_BIT_HW_ERR;
>               printf("%s: hardware error, stopping device \n", DEVNAME(sc));
> -             iwm_stop(ifp);
> +             sc->sc_flags |= IWM_FLAG_HW_ERR;
> +             task_add(systq, &sc->init_task);
>               rv = 1;
>               goto out;
>       }
> @@ -7262,13 +7271,6 @@ iwm_intr(void *arg)
>               wakeup(&sc->sc_fw);
>       }
>  
> -     if (r1 & IWM_CSR_INT_BIT_RF_KILL) {
> -             handled |= IWM_CSR_INT_BIT_RF_KILL;
> -             if (iwm_check_rfkill(sc) && (ifp->if_flags & IFF_UP)) {
> -                     iwm_stop(ifp);
> -             }
> -     }
> -
>       if (r1 & IWM_CSR_INT_BIT_RX_PERIODIC) {
>               handled |= IWM_CSR_INT_BIT_RX_PERIODIC;
>               IWM_WRITE(sc, IWM_CSR_INT, IWM_CSR_INT_BIT_RX_PERIODIC);
> @@ -7739,23 +7741,27 @@ iwm_init_task(void *arg1)
>  {
>       struct iwm_softc *sc = arg1;
>       struct ifnet *ifp = &sc->sc_ic.ic_if;
> -     int s;
> +     int s = splnet();
>       int generation = sc->sc_generation;
> +     int fatal = (sc->sc_flags & (IWM_FLAG_HW_ERR | IWM_FLAG_RFKILL));
>  
>       rw_enter_write(&sc->ioctl_rwl);
>       if (generation != sc->sc_generation) {
>               rw_exit(&sc->ioctl_rwl);
> +             splx(s);
>               return;
>       }
> -     s = splnet();
>  
>       if (ifp->if_flags & IFF_RUNNING)
>               iwm_stop(ifp);
> -     if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
> +     else if (sc->sc_flags & IWM_FLAG_HW_ERR)
> +             sc->sc_flags &= ~IWM_FLAG_HW_ERR;
> +
> +     if (!fatal && (ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
>               iwm_init(ifp);
>  
> -     splx(s);
>       rw_exit(&sc->ioctl_rwl);
> +     splx(s);
>  }
>  
>  int
> @@ -7778,9 +7784,12 @@ iwm_activate(struct device *self, int ac
>       int err = 0;
>  
>       switch (act) {
> -     case DVACT_SUSPEND:
> -             if (ifp->if_flags & IFF_RUNNING)
> +     case DVACT_QUIESCE:
> +             if (ifp->if_flags & IFF_RUNNING) {
> +                     rw_enter_write(&sc->ioctl_rwl);
>                       iwm_stop(ifp);
> +                     rw_exit(&sc->ioctl_rwl);
> +             }
>               break;
>       case DVACT_RESUME:
>               err = iwm_resume(sc);
> Index: if_iwmvar.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/if_iwmvar.h,v
> retrieving revision 1.33
> diff -u -p -r1.33 if_iwmvar.h
> --- if_iwmvar.h       13 Aug 2017 15:34:54 -0000      1.33
> +++ if_iwmvar.h       14 Aug 2017 06:00:16 -0000
> @@ -286,6 +286,7 @@ struct iwm_rx_ring {
>  #define IWM_FLAG_BINDING_ACTIVE      0x10    /* MAC->PHY binding added to 
> firmware */
>  #define IWM_FLAG_STA_ACTIVE  0x20    /* AP added to firmware station table */
>  #define IWM_FLAG_TE_ACTIVE   0x40    /* time event is scheduled */
> +#define IWM_FLAG_HW_ERR              0x80    /* hardware error occurred */
>  
>  struct iwm_ucode_status {
>       uint32_t uc_error_event_table;
> 

Reply via email to