diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-scan.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-scan.c | 127 |
1 files changed, 74 insertions, 53 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 7727f0966d31..6bd14bc33478 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -324,19 +324,68 @@ void iwl_init_scan_params(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_init_scan_params); -static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif) +static int __must_check iwl_scan_initiate(struct iwl_priv *priv, + struct ieee80211_vif *vif, + bool internal, + enum nl80211_band band) { + int ret; + lockdep_assert_held(&priv->mutex); - IWL_DEBUG_INFO(priv, "Starting scan...\n"); + if (WARN_ON(!priv->cfg->ops->utils->request_scan)) + return -EOPNOTSUPP; + + cancel_delayed_work(&priv->scan_check); + + if (!iwl_is_ready(priv)) { + IWL_WARN(priv, "request scan called when driver not ready.\n"); + return -EIO; + } + + if (test_bit(STATUS_SCAN_HW, &priv->status)) { + IWL_DEBUG_INFO(priv, + "Multiple concurrent scan requests in parallel.\n"); + return -EBUSY; + } + + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n"); + return -EIO; + } + + if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + IWL_DEBUG_HC(priv, "Scan request while abort pending.\n"); + return -EBUSY; + } + + if (iwl_is_rfkill(priv)) { + IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n"); + return -EIO; + } + + if (!test_bit(STATUS_READY, &priv->status)) { + IWL_DEBUG_HC(priv, "Scan request while uninitialized.\n"); + return -EBUSY; + } + + IWL_DEBUG_INFO(priv, "Starting %sscan...\n", + internal ? "internal short " : ""); + set_bit(STATUS_SCANNING, &priv->status); - priv->is_internal_short_scan = false; + priv->is_internal_short_scan = internal; priv->scan_start = jiffies; + priv->scan_band = band; - if (WARN_ON(!priv->cfg->ops->utils->request_scan)) - return -EOPNOTSUPP; + ret = priv->cfg->ops->utils->request_scan(priv, vif); + if (ret) { + clear_bit(STATUS_SCANNING, &priv->status); + priv->is_internal_short_scan = false; + return ret; + } - priv->cfg->ops->utils->request_scan(priv, vif); + queue_delayed_work(priv->workqueue, &priv->scan_check, + IWL_SCAN_CHECK_WATCHDOG); return 0; } @@ -355,12 +404,6 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, mutex_lock(&priv->mutex); - if (!iwl_is_ready_rf(priv)) { - ret = -EIO; - IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n"); - goto out_unlock; - } - if (test_bit(STATUS_SCANNING, &priv->status) && !priv->is_internal_short_scan) { IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); @@ -368,14 +411,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, goto out_unlock; } - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); - ret = -EAGAIN; - goto out_unlock; - } - /* mac80211 will only ask for one band at a time */ - priv->scan_band = req->channels[0]->band; priv->scan_request = req; priv->scan_vif = vif; @@ -386,7 +422,8 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, if (priv->is_internal_short_scan) ret = 0; else - ret = iwl_scan_initiate(priv, vif); + ret = iwl_scan_initiate(priv, vif, false, + req->channels[0]->band); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -418,31 +455,13 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) goto unlock; } - if (!iwl_is_ready_rf(priv)) { - IWL_DEBUG_SCAN(priv, "not ready or exit pending\n"); - goto unlock; - } - if (test_bit(STATUS_SCANNING, &priv->status)) { IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); goto unlock; } - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); - goto unlock; - } - - priv->scan_band = priv->band; - - IWL_DEBUG_SCAN(priv, "Start internal short scan...\n"); - set_bit(STATUS_SCANNING, &priv->status); - priv->is_internal_short_scan = true; - - if (WARN_ON(!priv->cfg->ops->utils->request_scan)) - goto unlock; - - priv->cfg->ops->utils->request_scan(priv, NULL); + if (iwl_scan_initiate(priv, NULL, true, priv->band)) + IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); unlock: mutex_unlock(&priv->mutex); } @@ -536,7 +555,6 @@ static void iwl_bg_scan_completed(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, scan_completed); bool internal = false; - bool scan_completed = false; struct iwl_rxon_context *ctx; IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); @@ -549,16 +567,27 @@ static void iwl_bg_scan_completed(struct work_struct *work) IWL_DEBUG_SCAN(priv, "internal short scan completed\n"); internal = true; } else if (priv->scan_request) { - scan_completed = true; priv->scan_request = NULL; priv->scan_vif = NULL; + ieee80211_scan_completed(priv->hw, false); } if (test_bit(STATUS_EXIT_PENDING, &priv->status)) goto out; - if (internal && priv->scan_request) - iwl_scan_initiate(priv, priv->scan_vif); + if (internal && priv->scan_request) { + int err = iwl_scan_initiate(priv, priv->scan_vif, false, + priv->scan_request->channels[0]->band); + + if (err) { + IWL_DEBUG_SCAN(priv, + "failed to initiate pending scan: %d\n", err); + priv->scan_request = NULL; + priv->scan_vif = NULL; + ieee80211_scan_completed(priv->hw, true); + } else + goto out; + } /* Since setting the TXPOWER may have been deferred while * performing the scan, fire one off */ @@ -571,19 +600,11 @@ static void iwl_bg_scan_completed(struct work_struct *work) for_each_context(priv, ctx) iwlcore_commit_rxon(priv, ctx); - out: if (priv->cfg->ops->hcmd->set_pan_params) priv->cfg->ops->hcmd->set_pan_params(priv); + out: mutex_unlock(&priv->mutex); - - /* - * Do not hold mutex here since this will cause mac80211 to call - * into driver again into functions that will attempt to take - * mutex. - */ - if (scan_completed) - ieee80211_scan_completed(priv->hw, false); } void iwl_setup_scan_deferred_work(struct iwl_priv *priv) |