Index: head/sys/dev/iwm/if_iwm.c =================================================================== --- head/sys/dev/iwm/if_iwm.c +++ head/sys/dev/iwm/if_iwm.c @@ -5064,20 +5064,48 @@ { struct iwm_softc *sc = ic->ic_softc; int startall = 0; + int rfkill = 0; IWM_LOCK(sc); if (ic->ic_nrunning > 0) { if (!(sc->sc_flags & IWM_FLAG_HW_INITED)) { iwm_init(sc); - startall = 1; + rfkill = iwm_check_rfkill(sc); + if (!rfkill) + startall = 1; } } else if (sc->sc_flags & IWM_FLAG_HW_INITED) iwm_stop(sc); IWM_UNLOCK(sc); if (startall) ieee80211_start_all(ic); + else if (rfkill) + taskqueue_enqueue(sc->sc_tq, &sc->sc_rftoggle_task); } +static void +iwm_rftoggle_task(void *arg, int npending __unused) +{ + struct iwm_softc *sc = arg; + struct ieee80211com *ic = &sc->sc_ic; + int rfkill; + + IWM_LOCK(sc); + rfkill = iwm_check_rfkill(sc); + IWM_UNLOCK(sc); + if (rfkill) { + device_printf(sc->sc_dev, + "%s: rfkill switch, disabling interface\n", __func__); + ieee80211_suspend_all(ic); + ieee80211_notify_radio(ic, 0); + } else { + device_printf(sc->sc_dev, + "%s: rfkill cleared, re-enabling interface\n", __func__); + ieee80211_resume_all(ic); + ieee80211_notify_radio(ic, 1); + } +} + /* * The interrupt side of things */ @@ -5814,12 +5842,7 @@ if (r1 & IWM_CSR_INT_BIT_RF_KILL) { handled |= IWM_CSR_INT_BIT_RF_KILL; - if (iwm_check_rfkill(sc)) { - device_printf(sc->sc_dev, - "%s: rfkill switch, disabling interface\n", - __func__); - iwm_stop(sc); - } + taskqueue_enqueue(sc->sc_tq, &sc->sc_rftoggle_task); } /* @@ -6024,7 +6047,17 @@ callout_init_mtx(&sc->sc_watchdog_to, &sc->sc_mtx, 0); callout_init_mtx(&sc->sc_led_blink_to, &sc->sc_mtx, 0); TASK_INIT(&sc->sc_es_task, 0, iwm_endscan_cb, sc); + TASK_INIT(&sc->sc_rftoggle_task, 0, iwm_rftoggle_task, sc); + sc->sc_tq = taskqueue_create("iwm_taskq", M_WAITOK, + taskqueue_thread_enqueue, &sc->sc_tq); + error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "iwm_taskq"); + if (error != 0) { + device_printf(dev, "can't start taskq thread, error %d\n", + error); + goto fail; + } + error = iwm_dev_check(dev); if (error != 0) goto fail; @@ -6590,6 +6623,8 @@ ieee80211_draintask(&sc->sc_ic, &sc->sc_es_task); } iwm_stop_device(sc); + taskqueue_drain_all(sc->sc_tq); + taskqueue_free(sc->sc_tq); if (do_net80211) { IWM_LOCK(sc); iwm_xmit_queue_drain(sc); Index: head/sys/dev/iwm/if_iwmvar.h =================================================================== --- head/sys/dev/iwm/if_iwmvar.h +++ head/sys/dev/iwm/if_iwmvar.h @@ -499,7 +499,9 @@ uint8_t sc_cmd_resp[IWM_CMD_RESP_MAX]; int sc_wantresp; + struct taskqueue *sc_tq; struct task sc_es_task; + struct task sc_rftoggle_task; struct iwm_rx_phy_info sc_last_phy_info; int sc_ampdu_ref;