]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mac80211: allow hardware scan to fall back to software
authorJohannes Berg <johannes.berg@intel.com>
Thu, 18 Oct 2018 08:35:47 +0000 (10:35 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 9 Nov 2018 10:37:04 +0000 (11:37 +0100)
In some cases, like in the rsi driver hardware scan offload, there
may be scenarios in which hardware scan might not be available or
desirable.

Allow drivers to cope with this by letting them fall back to software
scan by returning the special value 1 from the hardware scan method.

Requested-by: Sushant Kumar Mishra <sushant2k1513@gmail.com>
Requested-by: Siva Rebbagondla <siva.rebbagondla@redpinesignals.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/scan.c

index e3d57e7a55cc680706f0c984d9c545dc37b0b1e5..9386cf9fe714eb9bb6237c50805a7ca18a3162d1 100644 (file)
@@ -3239,6 +3239,11 @@ enum ieee80211_reconfig_type {
  *     When the scan finishes, ieee80211_scan_completed() must be called;
  *     note that it also must be called when the scan cannot finish due to
  *     any error unless this callback returned a negative error code.
+ *     This callback is also allowed to return the special return value 1,
+ *     this indicates that hardware scan isn't desirable right now and a
+ *     software scan should be done instead. A driver wishing to use this
+ *     capability must ensure its (hardware) scan capabilities aren't
+ *     advertised as more capable than mac80211's software scan is.
  *     The callback can sleep.
  *
  * @cancel_hw_scan: Ask the low-level tp cancel the active hw scan.
index 5d2a11777718c42c3ba4affb190904d2b7bd61de..95413413f98c9d956cf8c08df222ceb753930e98 100644 (file)
@@ -356,7 +356,7 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
 static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       bool hw_scan = local->ops->hw_scan;
+       bool hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
        bool was_scanning = local->scanning;
        struct cfg80211_scan_request *scan_req;
        struct ieee80211_sub_if_data *scan_sdata;
@@ -606,6 +606,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                                  struct cfg80211_scan_request *req)
 {
        struct ieee80211_local *local = sdata->local;
+       bool hw_scan = local->ops->hw_scan;
        int rc;
 
        lockdep_assert_held(&local->mtx);
@@ -620,7 +621,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                return 0;
        }
 
-       if (local->ops->hw_scan) {
+ again:
+       if (hw_scan) {
                u8 *ies;
 
                local->hw_scan_ies_bufsize = local->scan_ies_len + req->ie_len;
@@ -679,7 +681,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
        else
                memcpy(local->scan_addr, sdata->vif.addr, ETH_ALEN);
 
-       if (local->ops->hw_scan) {
+       if (hw_scan) {
                __set_bit(SCAN_HW_SCANNING, &local->scanning);
        } else if ((req->n_channels == 1) &&
                   (req->channels[0] == local->_oper_chandef.chan)) {
@@ -722,7 +724,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
 
        ieee80211_recalc_idle(local);
 
-       if (local->ops->hw_scan) {
+       if (hw_scan) {
                WARN_ON(!ieee80211_prep_hw_scan(local));
                rc = drv_hw_scan(local, sdata, local->hw_scan_req);
        } else {
@@ -740,6 +742,18 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
                RCU_INIT_POINTER(local->scan_sdata, NULL);
        }
 
+       if (hw_scan && rc == 1) {
+               /*
+                * we can't fall back to software for P2P-GO
+                * as it must update NoA etc.
+                */
+               if (ieee80211_vif_type_p2p(&sdata->vif) ==
+                               NL80211_IFTYPE_P2P_GO)
+                       return -EOPNOTSUPP;
+               hw_scan = false;
+               goto again;
+       }
+
        return rc;
 }