iwlwifi: queue user-initiated scan when doing internal scan
[pandora-kernel.git] / drivers / net / wireless / iwlwifi / iwl-scan.c
index d12fd55..b8bcd48 100644 (file)
@@ -265,7 +265,8 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
 EXPORT_SYMBOL(iwl_get_active_dwell_time);
 
 u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                              enum ieee80211_band band)
+                              enum ieee80211_band band,
+                              struct ieee80211_vif *vif)
 {
        u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
@@ -275,7 +276,7 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
                /* If we're associated, we clamp the maximum passive
                 * dwell time to be 98% of the beacon interval (minus
                 * 2 * channel tune time) */
-               passive = priv->beacon_int;
+               passive = vif ? vif->bss_conf.beacon_int : 0;
                if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
                        passive = IWL_PASSIVE_DWELL_BASE;
                passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
@@ -295,7 +296,7 @@ void iwl_init_scan_params(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_init_scan_params);
 
-static int iwl_scan_initiate(struct iwl_priv *priv)
+static int iwl_scan_initiate(struct iwl_priv *priv, struct ieee80211_vif *vif)
 {
        WARN_ON(!mutex_is_locked(&priv->mutex));
 
@@ -307,7 +308,7 @@ static int iwl_scan_initiate(struct iwl_priv *priv)
        if (WARN_ON(!priv->cfg->ops->utils->request_scan))
                return -EOPNOTSUPP;
 
-       priv->cfg->ops->utils->request_scan(priv);
+       priv->cfg->ops->utils->request_scan(priv, vif);
 
        return 0;
 }
@@ -332,7 +333,8 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       if (test_bit(STATUS_SCANNING, &priv->status)) {
+       if (test_bit(STATUS_SCANNING, &priv->status) &&
+           !priv->is_internal_short_scan) {
                IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
                ret = -EAGAIN;
                goto out_unlock;
@@ -347,8 +349,16 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
        /* 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;
 
-       ret = iwl_scan_initiate(priv);
+       /*
+        * If an internal scan is in progress, just set
+        * up the scan_request as per above.
+        */
+       if (priv->is_internal_short_scan)
+               ret = 0;
+       else
+               ret = iwl_scan_initiate(priv, vif);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
@@ -368,13 +378,18 @@ void iwl_internal_short_hw_scan(struct iwl_priv *priv)
        queue_work(priv->workqueue, &priv->start_internal_scan);
 }
 
-static void iwl_bg_start_internal_scan(struct work_struct *work)
+void iwl_bg_start_internal_scan(struct work_struct *work)
 {
        struct iwl_priv *priv =
                container_of(work, struct iwl_priv, start_internal_scan);
 
        mutex_lock(&priv->mutex);
 
+       if (priv->is_internal_short_scan == true) {
+               IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
+               goto unlock;
+       }
+
        if (!iwl_is_ready_rf(priv)) {
                IWL_DEBUG_SCAN(priv, "not ready or exit pending\n");
                goto unlock;
@@ -399,10 +414,11 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
        if (WARN_ON(!priv->cfg->ops->utils->request_scan))
                goto unlock;
 
-       priv->cfg->ops->utils->request_scan(priv);
+       priv->cfg->ops->utils->request_scan(priv, NULL);
  unlock:
        mutex_unlock(&priv->mutex);
 }
+EXPORT_SYMBOL(iwl_bg_start_internal_scan);
 
 void iwl_bg_scan_check(struct work_struct *data)
 {
@@ -431,7 +447,7 @@ EXPORT_SYMBOL(iwl_bg_scan_check);
  */
 
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
-                      const u8 *ies, int ie_len, int left)
+                      const u8 *ta, const u8 *ies, int ie_len, int left)
 {
        int len = 0;
        u8 *pos = NULL;
@@ -444,7 +460,7 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
 
        frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
        memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
-       memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+       memcpy(frame->sa, ta, ETH_ALEN);
        memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
        frame->seq_ctrl = 0;
 
@@ -495,26 +511,41 @@ void iwl_bg_scan_completed(struct work_struct *work)
 {
        struct iwl_priv *priv =
            container_of(work, struct iwl_priv, scan_completed);
+       bool internal = false;
 
        IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
 
        cancel_delayed_work(&priv->scan_check);
 
-       if (!priv->is_internal_short_scan)
-               ieee80211_scan_completed(priv->hw, false);
-       else {
+       mutex_lock(&priv->mutex);
+       if (priv->is_internal_short_scan) {
                priv->is_internal_short_scan = false;
                IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
+               internal = true;
+       } else {
+               priv->scan_request = NULL;
+               priv->scan_vif = NULL;
        }
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
+               goto out;
+
+       if (internal && priv->scan_request)
+               iwl_scan_initiate(priv, priv->scan_vif);
 
        /* Since setting the TXPOWER may have been deferred while
         * performing the scan, fire one off */
-       mutex_lock(&priv->mutex);
        iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ 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 (!internal)
+               ieee80211_scan_completed(priv->hw, false);
 }
 EXPORT_SYMBOL(iwl_bg_scan_completed);