|
@@ -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)
|