]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge tag 'wireless-drivers-next-for-davem-2016-12-01' of git://git.kernel.org/pub...
authorDavid S. Miller <davem@davemloft.net>
Fri, 2 Dec 2016 18:58:10 +0000 (13:58 -0500)
committerDavid S. Miller <davem@davemloft.net>
Fri, 2 Dec 2016 18:58:10 +0000 (13:58 -0500)
Kalle Valo says:

====================
wireless-drivers-next patches for 4.10

Major changes:

rsi

* filter rx frames
* configure tx power
* make it possible to select antenna
* support 802.11d

brcmfmac

* cleanup of scheduled scan code
* support for bcm43341 chipset with different chip id
* support rev6 of PCIe device interface

ath10k

* add spectral scan support for QCA6174 and QCA9377 families
* show used tx bitrate with 10.4 firmware

wil6210

* add power save mode support
* add abort scan functionality
* add support settings retry limit for short frames

bcma

* add Dell Inspiron 3148
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
1  2 
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/realtek/rtlwifi/core.c

index e8decfaba5b6ed4c3ee6b3280d8cec399571e5f0,6d06ec5cd087fcfc6f928c2689043263f61b8c2a..09ff8b8a644116da3532b756e29b376f64545267
@@@ -337,6 -337,7 +337,7 @@@ struct ath10k_sta 
        u32 nss;
        u32 smps;
        u16 peer_id;
+       struct rate_info txrate;
  
        struct work_struct update_wk;
  
@@@ -450,7 -451,6 +451,7 @@@ struct ath10k_debug 
        u32 pktlog_filter;
        u32 reg_addr;
        u32 nf_cal_period;
 +      void *cal_data;
  
        struct ath10k_fw_crash_data *fw_crash_data;
  };
@@@ -562,6 -562,13 +563,13 @@@ enum ath10k_fw_features 
         */
        ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR = 15,
  
+       /* Firmware allow other BSS mesh broadcast/multicast frames without
+        * creating monitor interface. Appropriate rxfilters are programmed for
+        * mesh vdev by firmware itself. This feature flags will be used for
+        * not creating monitor vdev while configuring mesh node.
+        */
+       ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST = 16,
        /* keep last */
        ATH10K_FW_FEATURE_COUNT,
  };
@@@ -693,6 -700,21 +701,21 @@@ struct ath10k_fw_components 
        struct ath10k_fw_file fw_file;
  };
  
+ struct ath10k_per_peer_tx_stats {
+       u32     succ_bytes;
+       u32     retry_bytes;
+       u32     failed_bytes;
+       u8      ratecode;
+       u8      flags;
+       u16     peer_id;
+       u16     succ_pkts;
+       u16     retry_pkts;
+       u16     failed_pkts;
+       u16     duration;
+       u32     reserved1;
+       u32     reserved2;
+ };
  struct ath10k {
        struct ath_common ath_common;
        struct ieee80211_hw *hw;
  
        struct ath10k_thermal thermal;
        struct ath10k_wow wow;
+       struct ath10k_per_peer_tx_stats peer_tx_stats;
  
        /* NAPI */
        struct net_device napi_dev;
index 717b2fad9a8a513b60fe2eea5aa28aeaf2750da6,db6ddf974d1d3a762024fbb6d63fa0752d014ce6..aa545a1dbdc71931fdd588a05acd01fa8ee9d1d1
@@@ -1167,7 -1167,9 +1167,9 @@@ static bool ath10k_mac_monitor_vdev_is_
                return false;
  
        return ar->monitor ||
-              ar->filter_flags & FIF_OTHER_BSS ||
+              (!test_bit(ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST,
+                         ar->running_fw->fw_file.fw_features) &&
+               (ar->filter_flags & FIF_OTHER_BSS)) ||
               test_bit(ATH10K_CAC_RUNNING, &ar->dev_flags);
  }
  
@@@ -4449,7 -4451,6 +4451,6 @@@ static int ath10k_start(struct ieee8021
                ar->state = ATH10K_STATE_ON;
                break;
        case ATH10K_STATE_RESTARTING:
-               ath10k_halt(ar);
                ar->state = ATH10K_STATE_RESTARTED;
                break;
        case ATH10K_STATE_ON:
@@@ -6976,40 -6977,28 +6977,28 @@@ static void ath10k_sta_rc_update(struc
        ieee80211_queue_work(hw, &arsta->update_wk);
  }
  
- static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
- {
-       /*
-        * FIXME: Return 0 for time being. Need to figure out whether FW
-        * has the API to fetch 64-bit local TSF
-        */
-       return 0;
- }
- static void ath10k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                          u64 tsf)
+ static void ath10k_offset_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, s64 tsf_offset)
  {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
-       u32 tsf_offset, vdev_param = ar->wmi.vdev_param->set_tsf;
+       u32 offset, vdev_param;
        int ret;
  
-       /* Workaround:
-        *
-        * Given tsf argument is entire TSF value, but firmware accepts
-        * only TSF offset to current TSF.
-        *
-        * get_tsf function is used to get offset value, however since
-        * ath10k_get_tsf is not implemented properly, it will return 0 always.
-        * Luckily all the caller functions to set_tsf, as of now, also rely on
-        * get_tsf function to get entire tsf value such get_tsf() + tsf_delta,
-        * final tsf offset value to firmware will be arithmetically correct.
-        */
-       tsf_offset = tsf - ath10k_get_tsf(hw, vif);
+       if (tsf_offset < 0) {
+               vdev_param = ar->wmi.vdev_param->dec_tsf;
+               offset = -tsf_offset;
+       } else {
+               vdev_param = ar->wmi.vdev_param->inc_tsf;
+               offset = tsf_offset;
+       }
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
-                                       vdev_param, tsf_offset);
+                                       vdev_param, offset);
        if (ret && ret != -EOPNOTSUPP)
-               ath10k_warn(ar, "failed to set tsf offset: %d\n", ret);
+               ath10k_warn(ar, "failed to set tsf offset %d cmd %d: %d\n",
+                           offset, vdev_param, ret);
  }
  
  static int ath10k_ampdu_action(struct ieee80211_hw *hw,
@@@ -7474,8 -7463,7 +7463,7 @@@ static const struct ieee80211_ops ath10
        .get_survey                     = ath10k_get_survey,
        .set_bitrate_mask               = ath10k_mac_op_set_bitrate_mask,
        .sta_rc_update                  = ath10k_sta_rc_update,
-       .get_tsf                        = ath10k_get_tsf,
-       .set_tsf                        = ath10k_set_tsf,
+       .offset_tsf                     = ath10k_offset_tsf,
        .ampdu_action                   = ath10k_ampdu_action,
        .get_et_sset_count              = ath10k_debug_get_et_sset_count,
        .get_et_stats                   = ath10k_debug_get_et_stats,
@@@ -8005,7 -7993,7 +7993,8 @@@ int ath10k_mac_register(struct ath10k *
        ieee80211_hw_set(ar->hw, WANT_MONITOR_VIF);
        ieee80211_hw_set(ar->hw, CHANCTX_STA_CSA);
        ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
 +      ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
+       ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
  
        if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags))
                ieee80211_hw_set(ar->hw, SW_CRYPTO_CONTROL);
index 4e238c0bdaf36b53c7a59ce34cb2ab8f30864d65,f28f03a6fbfb3ecd5e129739976576ec32dd5738..ccae3bbe7db24deb3a5656c2ba9556ad6dbf7cfa
@@@ -32,6 -32,7 +32,7 @@@
  #include "fwil_types.h"
  #include "p2p.h"
  #include "btcoex.h"
+ #include "pno.h"
  #include "cfg80211.h"
  #include "feature.h"
  #include "fwil.h"
  #include "common.h"
  
  #define BRCMF_SCAN_IE_LEN_MAX         2048
- #define BRCMF_PNO_VERSION             2
- #define BRCMF_PNO_TIME                        30
- #define BRCMF_PNO_REPEAT              4
- #define BRCMF_PNO_FREQ_EXPO_MAX               3
- #define BRCMF_PNO_MAX_PFN_COUNT               16
- #define BRCMF_PNO_ENABLE_ADAPTSCAN_BIT        6
- #define BRCMF_PNO_HIDDEN_BIT          2
- #define BRCMF_PNO_WPA_AUTH_ANY                0xFFFFFFFF
- #define BRCMF_PNO_SCAN_COMPLETE               1
- #define BRCMF_PNO_SCAN_INCOMPLETE     0
  
  #define WPA_OUI                               "\x00\x50\xF2"  /* WPA OUI */
  #define WPA_OUI_TYPE                  1
@@@ -414,24 -405,23 +405,24 @@@ static int brcmf_vif_change_validate(st
                                     struct brcmf_cfg80211_vif *vif,
                                     enum nl80211_iftype new_type)
  {
 -      int iftype_num[NUM_NL80211_IFTYPES];
        struct brcmf_cfg80211_vif *pos;
        bool check_combos = false;
        int ret = 0;
 +      struct iface_combination_params params = {
 +              .num_different_channels = 1,
 +      };
  
 -      memset(&iftype_num[0], 0, sizeof(iftype_num));
        list_for_each_entry(pos, &cfg->vif_list, list)
                if (pos == vif) {
 -                      iftype_num[new_type]++;
 +                      params.iftype_num[new_type]++;
                } else {
                        /* concurrent interfaces so need check combinations */
                        check_combos = true;
 -                      iftype_num[pos->wdev.iftype]++;
 +                      params.iftype_num[pos->wdev.iftype]++;
                }
  
        if (check_combos)
 -              ret = cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
 +              ret = cfg80211_check_combinations(cfg->wiphy, &params);
  
        return ret;
  }
  static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg,
                                  enum nl80211_iftype new_type)
  {
 -      int iftype_num[NUM_NL80211_IFTYPES];
        struct brcmf_cfg80211_vif *pos;
 +      struct iface_combination_params params = {
 +              .num_different_channels = 1,
 +      };
  
 -      memset(&iftype_num[0], 0, sizeof(iftype_num));
        list_for_each_entry(pos, &cfg->vif_list, list)
 -              iftype_num[pos->wdev.iftype]++;
 +              params.iftype_num[pos->wdev.iftype]++;
  
 -      iftype_num[new_type]++;
 -      return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num);
 +      params.iftype_num[new_type]++;
 +      return cfg80211_check_combinations(cfg->wiphy, &params);
  }
  
  static void convert_key_from_CPU(struct brcmf_wsec_key *key,
@@@ -768,12 -757,12 +759,12 @@@ s32 brcmf_notify_escan_complete(struct 
        brcmf_scan_config_mpc(ifp, 1);
  
        /*
-        * e-scan can be initiated by scheduled scan
+        * e-scan can be initiated internally
         * which takes precedence.
         */
-       if (cfg->sched_escan) {
+       if (cfg->internal_escan) {
                brcmf_dbg(SCAN, "scheduled scan completed\n");
-               cfg->sched_escan = false;
+               cfg->internal_escan = false;
                if (!aborted)
                        cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
        } else if (scan_request) {
@@@ -1091,9 -1080,9 +1082,9 @@@ exit
  }
  
  static s32
- brcmf_do_escan(struct brcmf_cfg80211_info *cfg, struct wiphy *wiphy,
-              struct brcmf_if *ifp, struct cfg80211_scan_request *request)
+ brcmf_do_escan(struct brcmf_if *ifp, struct cfg80211_scan_request *request)
  {
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 err;
        u32 passive_scan;
        struct brcmf_scan_results *results;
  
        brcmf_dbg(SCAN, "Enter\n");
        escan->ifp = ifp;
-       escan->wiphy = wiphy;
+       escan->wiphy = cfg->wiphy;
        escan->escan_state = WL_ESCAN_STATE_SCANNING;
        passive_scan = cfg->active_scan ? 0 : 1;
        err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
@@@ -1181,7 -1170,7 +1172,7 @@@ brcmf_cfg80211_escan(struct wiphy *wiph
                if (err)
                        goto scan_out;
  
-               err = brcmf_do_escan(cfg, wiphy, vif->ifp, request);
+               err = brcmf_do_escan(vif->ifp, request);
                if (err)
                        goto scan_out;
        } else {
@@@ -3024,7 -3013,7 +3015,7 @@@ void brcmf_abort_scanning(struct brcmf_
        struct escan_info *escan = &cfg->escan_info;
  
        set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
-       if (cfg->scan_request) {
+       if (cfg->internal_escan || cfg->scan_request) {
                escan->escan_state = WL_ESCAN_STATE_IDLE;
                brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
        }
@@@ -3047,7 -3036,7 +3038,7 @@@ static void brcmf_escan_timeout(unsigne
        struct brcmf_cfg80211_info *cfg =
                        (struct brcmf_cfg80211_info *)data;
  
-       if (cfg->scan_request) {
+       if (cfg->internal_escan || cfg->scan_request) {
                brcmf_err("timer expired\n");
                schedule_work(&cfg->escan_timeout_work);
        }
@@@ -3130,7 -3119,7 +3121,7 @@@ brcmf_cfg80211_escan_handler(struct brc
                if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
                        goto exit;
  
-               if (!cfg->scan_request) {
+               if (!cfg->internal_escan && !cfg->scan_request) {
                        brcmf_dbg(SCAN, "result without cfg80211 request\n");
                        goto exit;
                }
                cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
                if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
                        goto exit;
-               if (cfg->scan_request) {
+               if (cfg->internal_escan || cfg->scan_request) {
                        brcmf_inform_bss(cfg);
                        aborted = status != BRCMF_E_STATUS_SUCCESS;
                        brcmf_notify_escan_complete(cfg, ifp, aborted, false);
@@@ -3201,6 -3190,95 +3192,95 @@@ static void brcmf_init_escan(struct brc
                  brcmf_cfg80211_escan_timeout_worker);
  }
  
+ static struct cfg80211_scan_request *
+ brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
+       struct cfg80211_scan_request *req;
+       size_t req_size;
+       req_size = sizeof(*req) +
+                  n_netinfo * sizeof(req->channels[0]) +
+                  n_netinfo * sizeof(*req->ssids);
+       req = kzalloc(req_size, GFP_KERNEL);
+       if (req) {
+               req->wiphy = wiphy;
+               req->ssids = (void *)(&req->channels[0]) +
+                            n_netinfo * sizeof(req->channels[0]);
+       }
+       return req;
+ }
+ static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
+                                        u8 *ssid, u8 ssid_len, u8 channel)
+ {
+       struct ieee80211_channel *chan;
+       enum nl80211_band band;
+       int freq;
+       if (channel <= CH_MAX_2G_CHANNEL)
+               band = NL80211_BAND_2GHZ;
+       else
+               band = NL80211_BAND_5GHZ;
+       freq = ieee80211_channel_to_frequency(channel, band);
+       if (!freq)
+               return -EINVAL;
+       chan = ieee80211_get_channel(req->wiphy, freq);
+       if (!chan)
+               return -EINVAL;
+       req->channels[req->n_channels++] = chan;
+       memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
+       req->ssids[req->n_ssids++].ssid_len = ssid_len;
+       return 0;
+ }
+ static int brcmf_start_internal_escan(struct brcmf_if *ifp,
+                                     struct cfg80211_scan_request *request)
+ {
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+       int err;
+       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+               /* Abort any on-going scan */
+               brcmf_abort_scanning(cfg);
+       }
+       set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+       cfg->escan_info.run = brcmf_run_escan;
+       err = brcmf_do_escan(ifp, request);
+       if (err) {
+               clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
+               return err;
+       }
+       cfg->internal_escan = true;
+       return 0;
+ }
+ static struct brcmf_pno_net_info_le *
+ brcmf_get_netinfo_array(struct brcmf_pno_scanresults_le *pfn_v1)
+ {
+       struct brcmf_pno_scanresults_v2_le *pfn_v2;
+       struct brcmf_pno_net_info_le *netinfo;
+       switch (pfn_v1->version) {
+       default:
+               WARN_ON(1);
+               /* fall-thru */
+       case cpu_to_le32(1):
+               netinfo = (struct brcmf_pno_net_info_le *)(pfn_v1 + 1);
+               break;
+       case cpu_to_le32(2):
+               pfn_v2 = (struct brcmf_pno_scanresults_v2_le *)pfn_v1;
+               netinfo = (struct brcmf_pno_net_info_le *)(pfn_v2 + 1);
+               break;
+       }
+       return netinfo;
+ }
  /* PFN result doesn't have all the info which are required by the supplicant
   * (For e.g IEs) Do a target Escan so that sched scan results are reported
   * via wl_inform_single_bss in the required format. Escan does require the
@@@ -3214,12 -3292,8 +3294,8 @@@ brcmf_notify_sched_scan_results(struct 
        struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
        struct cfg80211_scan_request *request = NULL;
-       struct cfg80211_ssid *ssid = NULL;
-       struct ieee80211_channel *channel = NULL;
        struct wiphy *wiphy = cfg_to_wiphy(cfg);
-       int err = 0;
-       int channel_req = 0;
-       int band = 0;
+       int i, err = 0;
        struct brcmf_pno_scanresults_le *pfn_result;
        u32 result_count;
        u32 status;
         */
        WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
        brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
-       if (result_count > 0) {
-               int i;
-               request = kzalloc(sizeof(*request), GFP_KERNEL);
-               ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
-               channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
-               if (!request || !ssid || !channel) {
-                       err = -ENOMEM;
-                       goto out_err;
-               }
-               request->wiphy = wiphy;
-               data += sizeof(struct brcmf_pno_scanresults_le);
-               netinfo_start = (struct brcmf_pno_net_info_le *)data;
-               for (i = 0; i < result_count; i++) {
-                       netinfo = &netinfo_start[i];
-                       if (!netinfo) {
-                               brcmf_err("Invalid netinfo ptr. index: %d\n",
-                                         i);
-                               err = -EINVAL;
-                               goto out_err;
-                       }
-                       brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
-                                 netinfo->SSID, netinfo->channel);
-                       memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
-                       ssid[i].ssid_len = netinfo->SSID_len;
-                       request->n_ssids++;
-                       channel_req = netinfo->channel;
-                       if (channel_req <= CH_MAX_2G_CHANNEL)
-                               band = NL80211_BAND_2GHZ;
-                       else
-                               band = NL80211_BAND_5GHZ;
-                       channel[i].center_freq =
-                               ieee80211_channel_to_frequency(channel_req,
-                                                              band);
-                       channel[i].band = band;
-                       channel[i].flags |= IEEE80211_CHAN_NO_HT40;
-                       request->channels[i] = &channel[i];
-                       request->n_channels++;
-               }
-               /* assign parsed ssid array */
-               if (request->n_ssids)
-                       request->ssids = &ssid[0];
-               if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-                       /* Abort any on-going scan */
-                       brcmf_abort_scanning(cfg);
-               }
-               set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
-               cfg->escan_info.run = brcmf_run_escan;
-               err = brcmf_do_escan(cfg, wiphy, ifp, request);
-               if (err) {
-                       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
-                       goto out_err;
-               }
-               cfg->sched_escan = true;
-               cfg->scan_request = request;
-       } else {
+       if (!result_count) {
                brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
                goto out_err;
        }
-       kfree(ssid);
-       kfree(channel);
-       kfree(request);
-       return 0;
- out_err:
-       kfree(ssid);
-       kfree(channel);
-       kfree(request);
-       cfg80211_sched_scan_stopped(wiphy);
-       return err;
- }
- static int brcmf_dev_pno_clean(struct net_device *ndev)
- {
-       int ret;
-       /* Disable pfn */
-       ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
-       if (ret == 0) {
-               /* clear pfn */
-               ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
-                                              NULL, 0);
-       }
-       if (ret < 0)
-               brcmf_err("failed code %d\n", ret);
-       return ret;
- }
- static int brcmf_dev_pno_config(struct brcmf_if *ifp,
-                               struct cfg80211_sched_scan_request *request)
- {
-       struct brcmf_pno_param_le pfn_param;
-       struct brcmf_pno_macaddr_le pfn_mac;
-       s32 err;
-       u8 *mac_mask;
-       int i;
-       memset(&pfn_param, 0, sizeof(pfn_param));
-       pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
-       /* set extra pno params */
-       pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
-       pfn_param.repeat = BRCMF_PNO_REPEAT;
-       pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
-       /* set up pno scan fr */
-       pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
-       err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
-                                      sizeof(pfn_param));
-       if (err) {
-               brcmf_err("pfn_set failed, err=%d\n", err);
-               return err;
+       request = brcmf_alloc_internal_escan_request(wiphy,
+                                                    result_count);
+       if (!request) {
+               err = -ENOMEM;
+               goto out_err;
        }
  
-       /* Find out if mac randomization should be turned on */
-       if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
-               return 0;
+       data += sizeof(struct brcmf_pno_scanresults_le);
+       netinfo_start = brcmf_get_netinfo_array(pfn_result);
  
-       pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
-       pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
+       for (i = 0; i < result_count; i++) {
+               netinfo = &netinfo_start[i];
+               if (!netinfo) {
+                       brcmf_err("Invalid netinfo ptr. index: %d\n",
+                                 i);
+                       err = -EINVAL;
+                       goto out_err;
+               }
  
-       memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
-       mac_mask = request->mac_addr_mask;
-       for (i = 0; i < ETH_ALEN; i++) {
-               pfn_mac.mac[i] &= mac_mask[i];
-               pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
+               brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
+                         netinfo->SSID, netinfo->channel);
+               err = brcmf_internal_escan_add_info(request,
+                                                   netinfo->SSID,
+                                                   netinfo->SSID_len,
+                                                   netinfo->channel);
+               if (err)
+                       goto out_err;
        }
-       /* Clear multi bit */
-       pfn_mac.mac[0] &= 0xFE;
-       /* Set locally administered */
-       pfn_mac.mac[0] |= 0x02;
  
-       err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
-                                      sizeof(pfn_mac));
-       if (err)
-               brcmf_err("pfn_macaddr failed, err=%d\n", err);
+       err = brcmf_start_internal_escan(ifp, request);
+       if (!err)
+               goto free_req;
  
+ out_err:
+       cfg80211_sched_scan_stopped(wiphy);
+ free_req:
+       kfree(request);
        return err;
  }
  
  static int
  brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
                                struct net_device *ndev,
-                               struct cfg80211_sched_scan_request *request)
+                               struct cfg80211_sched_scan_request *req)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
-       struct brcmf_pno_net_param_le pfn;
-       int i;
-       int ret = 0;
  
        brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
-                 request->n_match_sets, request->n_ssids);
-       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-               brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
-               return -EAGAIN;
-       }
+                 req->n_match_sets, req->n_ssids);
        if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
                brcmf_err("Scanning suppressed: status (%lu)\n",
                          cfg->scan_status);
                return -EAGAIN;
        }
  
-       if (!request->n_ssids || !request->n_match_sets) {
-               brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
-                         request->n_ssids);
+       if (req->n_match_sets <= 0) {
+               brcmf_dbg(SCAN, "invalid number of matchsets specified: %d\n",
+                         req->n_match_sets);
                return -EINVAL;
        }
  
-       if (request->n_ssids > 0) {
-               for (i = 0; i < request->n_ssids; i++) {
-                       /* Active scan req for ssids */
-                       brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
-                                 request->ssids[i].ssid);
-                       /* match_set ssids is a supert set of n_ssid list,
-                        * so we need not add these set separately.
-                        */
-               }
-       }
-       if (request->n_match_sets > 0) {
-               /* clean up everything */
-               ret = brcmf_dev_pno_clean(ndev);
-               if  (ret < 0) {
-                       brcmf_err("failed error=%d\n", ret);
-                       return ret;
-               }
-               /* configure pno */
-               if (brcmf_dev_pno_config(ifp, request))
-                       return -EINVAL;
-               /* configure each match set */
-               for (i = 0; i < request->n_match_sets; i++) {
-                       struct cfg80211_ssid *ssid;
-                       u32 ssid_len;
-                       ssid = &request->match_sets[i].ssid;
-                       ssid_len = ssid->ssid_len;
-                       if (!ssid_len) {
-                               brcmf_err("skip broadcast ssid\n");
-                               continue;
-                       }
-                       pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
-                       pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
-                       pfn.wsec = cpu_to_le32(0);
-                       pfn.infra = cpu_to_le32(1);
-                       pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
-                       pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
-                       memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
-                       ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
-                                                      sizeof(pfn));
-                       brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
-                                 ret == 0 ? "set" : "failed", ssid->ssid);
-               }
-               /* Enable the PNO */
-               if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
-                       brcmf_err("PNO enable failed!! ret=%d\n", ret);
-                       return -EINVAL;
-               }
-       } else {
-               return -EINVAL;
-       }
-       return 0;
+       return brcmf_pno_start_sched_scan(ifp, req);
  }
  
  static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
                                          struct net_device *ndev)
  {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+       struct brcmf_if *ifp = netdev_priv(ndev);
  
        brcmf_dbg(SCAN, "enter\n");
-       brcmf_dev_pno_clean(ndev);
-       if (cfg->sched_escan)
-               brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
+       brcmf_pno_clean(ifp);
+       if (cfg->internal_escan)
+               brcmf_notify_escan_complete(cfg, ifp, true, true);
        return 0;
  }
  
@@@ -4518,7 -4424,7 +4426,7 @@@ brcmf_cfg80211_start_ap(struct wiphy *w
        /* store current 11d setting */
        if (brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY,
                                  &ifp->vif->is_11d)) {
 -              supports_11d = false;
 +              is_11d = supports_11d = false;
        } else {
                country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
                                              settings->beacon.tail_len,
@@@ -6428,6 -6334,7 +6336,7 @@@ static void brcmf_wiphy_pno_params(stru
        wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
        wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
        wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
+       wiphy->max_sched_scan_plan_interval = BRCMF_PNO_SCHED_SCAN_MAX_PERIOD;
        wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
  }
  
index e89681d2f83acdd5cf8d610ce8baf7dfd21a1cb7,f90ff0a01c3658d6d99903e3d9795cc5390cd019..2caa4ad04dba4a6e66a02b74173ab1b016ca7af1
@@@ -111,7 -111,7 +111,7 @@@ static void rtl_fw_do_work(const struc
                        if (!err)
                                goto found_alt;
                }
 -              pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
 +              pr_err("Selected firmware is not available\n");
                rtlpriv->max_fw_size = 0;
                return;
        }
@@@ -1150,10 -1150,8 +1150,8 @@@ static void rtl_op_bss_info_changed(str
                } else {
                        mstatus = RT_MEDIA_DISCONNECT;
  
-                       if (mac->link_state == MAC80211_LINKED) {
-                               rtlpriv->enter_ps = false;
-                               schedule_work(&rtlpriv->works.lps_change_work);
-                       }
+                       if (mac->link_state == MAC80211_LINKED)
+                               rtl_lps_leave(hw);
                        if (ppsc->p2p_ps_info.p2p_ps_mode > P2P_PS_NONE)
                                rtl_p2p_ps_cmd(hw, P2P_PS_DISABLE);
                        mac->link_state = MAC80211_NOLINK;
@@@ -1431,8 -1429,7 +1429,7 @@@ static void rtl_op_sw_scan_start(struc
        }
  
        if (mac->link_state == MAC80211_LINKED) {
-               rtlpriv->enter_ps = false;
-               schedule_work(&rtlpriv->works.lps_change_work);
+               rtl_lps_leave(hw);
                mac->link_state = MAC80211_LINKED_SCANNING;
        } else {
                rtl_ips_nic_on(hw);