From 0fae13e67a172f1eebfc5c722c75b7409171deb7 Mon Sep 17 00:00:00 2001 From: adrian Date: Wed, 8 Feb 2017 06:50:59 +0000 Subject: [PATCH] [iwm] Use iwm_mvm_scan_stop_wait to properly abort scans. * Add IWM_FLAG_SCAN_RUNNING to sc->sc_flags to track whether the firmware is currently running a scan, in order to decide wheter iwm_scan_end needs to abort a running scan. * In iwm_scan_end, if the scan is still running, we now abort it, in order to keep the firmware scanning state in sync. * Try to make things a bit simpler, by reacting on the IWM_SCAN_OFFLOAD_COMPLETE and IWM_SCAN_COMPLETE_UMAC notifications, instead of IWM_SCAN_ITERATION_COMPLETE and IWM_SCAN_ITERATION_COMPLETE_UMAC. This should be fine since we always only tell the firmware to do a single scan iteration anyway. Obtained from: DragonflyBSD commit 1f249c981c4e89e7cde1836a75b61cac36dc7ac5 --- sys/dev/iwm/if_iwm.c | 36 ++++++++++++++++++++++++++++++++---- sys/dev/iwm/if_iwmvar.h | 1 + 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index 6a6166fab0f0..b98100bd7321 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -4951,6 +4951,7 @@ iwm_stop(struct iwm_softc *sc) iwm_led_blink_stop(sc); sc->sc_tx_timer = 0; iwm_stop_device(sc); + sc->sc_flags &= ~IWM_FLAG_SCAN_RUNNING; } static void @@ -5475,6 +5476,10 @@ iwm_notif_intr(struct iwm_softc *sc) case IWM_SCAN_OFFLOAD_COMPLETE: { struct iwm_periodic_scan_complete *notif; notif = (void *)pkt->data; + if (sc->sc_flags & IWM_FLAG_SCAN_RUNNING) { + sc->sc_flags &= ~IWM_FLAG_SCAN_RUNNING; + ieee80211_runtask(ic, &sc->sc_es_task); + } break; } @@ -5492,9 +5497,10 @@ iwm_notif_intr(struct iwm_softc *sc) IWM_DPRINTF(sc, IWM_DEBUG_SCAN, "UMAC scan complete, status=0x%x\n", notif->status); -#if 0 /* XXX This would be a duplicate scan end call */ - taskqueue_enqueue(sc->sc_tq, &sc->sc_es_task); -#endif + if (sc->sc_flags & IWM_FLAG_SCAN_RUNNING) { + sc->sc_flags &= ~IWM_FLAG_SCAN_RUNNING; + ieee80211_runtask(ic, &sc->sc_es_task); + } break; } @@ -6254,15 +6260,21 @@ iwm_scan_start(struct ieee80211com *ic) int error; IWM_LOCK(sc); + if (sc->sc_flags & IWM_FLAG_SCAN_RUNNING) { + /* This should not be possible */ + device_printf(sc->sc_dev, + "%s: Previous scan not completed yet\n", __func__); + } if (isset(sc->sc_enabled_capa, IWM_UCODE_TLV_CAPA_UMAC_SCAN)) error = iwm_mvm_umac_scan(sc); else error = iwm_mvm_lmac_scan(sc); if (error != 0) { - device_printf(sc->sc_dev, "could not initiate 2 GHz scan\n"); + device_printf(sc->sc_dev, "could not initiate scan\n"); IWM_UNLOCK(sc); ieee80211_cancel_scan(vap); } else { + sc->sc_flags |= IWM_FLAG_SCAN_RUNNING; iwm_led_blink_start(sc); IWM_UNLOCK(sc); } @@ -6278,7 +6290,23 @@ iwm_scan_end(struct ieee80211com *ic) iwm_led_blink_stop(sc); if (vap->iv_state == IEEE80211_S_RUN) iwm_mvm_led_enable(sc); + if (sc->sc_flags & IWM_FLAG_SCAN_RUNNING) { + /* + * Removing IWM_FLAG_SCAN_RUNNING now, is fine because + * both iwm_scan_end and iwm_scan_start run in the ic->ic_tq + * taskqueue. + */ + sc->sc_flags &= ~IWM_FLAG_SCAN_RUNNING; + iwm_mvm_scan_stop_wait(sc); + } IWM_UNLOCK(sc); + + /* + * Make sure we don't race, if sc_es_task is still enqueued here. + * This is to make sure that it won't call ieee80211_scan_done + * when we have already started the next scan. + */ + taskqueue_cancel(ic->ic_tq, &sc->sc_es_task, NULL); } static void diff --git a/sys/dev/iwm/if_iwmvar.h b/sys/dev/iwm/if_iwmvar.h index c4a28b7befb0..a1b97dcc7dac 100644 --- a/sys/dev/iwm/if_iwmvar.h +++ b/sys/dev/iwm/if_iwmvar.h @@ -415,6 +415,7 @@ struct iwm_softc { #define IWM_FLAG_RFKILL (1 << 3) #define IWM_FLAG_BUSY (1 << 4) #define IWM_FLAG_SCANNING (1 << 5) +#define IWM_FLAG_SCAN_RUNNING (1 << 6) struct intr_config_hook sc_preinit_hook; struct callout sc_watchdog_to;