mac80211: brcmfmac: backport scheduled scan cleanup and chip support
[librecmc/librecmc.git] / package / kernel / mac80211 / patches / 357-0006-brcmfmac-make-internal-escan-more-generic.patch
1 From fa85b30a908455ff25def3a5f319aad272ef4862 Mon Sep 17 00:00:00 2001
2 From: Arend Van Spriel <arend.vanspriel@broadcom.com>
3 Date: Wed, 23 Nov 2016 10:25:25 +0000
4 Subject: [PATCH] brcmfmac: make internal escan more generic
5
6 For scheduled scan we initiate an escan in firmware to obtain more
7 info missing from the scheduled scan notification we get from firmware.
8 For upcoming functionality this is also required so make it a bit
9 more generic.
10
11 Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
12 Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
13 Reviewed-by: Franky Lin <franky.lin@broadcom.com>
14 Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
15 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
16 ---
17  .../broadcom/brcm80211/brcmfmac/cfg80211.c         | 187 ++++++++++++---------
18  .../broadcom/brcm80211/brcmfmac/cfg80211.h         |   4 +-
19  2 files changed, 109 insertions(+), 82 deletions(-)
20
21 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
22 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
23 @@ -757,12 +757,12 @@ s32 brcmf_notify_escan_complete(struct b
24         brcmf_scan_config_mpc(ifp, 1);
25  
26         /*
27 -        * e-scan can be initiated by scheduled scan
28 +        * e-scan can be initiated internally
29          * which takes precedence.
30          */
31 -       if (cfg->sched_escan) {
32 +       if (cfg->internal_escan) {
33                 brcmf_dbg(SCAN, "scheduled scan completed\n");
34 -               cfg->sched_escan = false;
35 +               cfg->internal_escan = false;
36                 if (!aborted)
37                         cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
38         } else if (scan_request) {
39 @@ -3013,7 +3013,7 @@ void brcmf_abort_scanning(struct brcmf_c
40         struct escan_info *escan = &cfg->escan_info;
41  
42         set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
43 -       if (cfg->scan_request) {
44 +       if (cfg->internal_escan || cfg->scan_request) {
45                 escan->escan_state = WL_ESCAN_STATE_IDLE;
46                 brcmf_notify_escan_complete(cfg, escan->ifp, true, true);
47         }
48 @@ -3036,7 +3036,7 @@ static void brcmf_escan_timeout(unsigned
49         struct brcmf_cfg80211_info *cfg =
50                         (struct brcmf_cfg80211_info *)data;
51  
52 -       if (cfg->scan_request) {
53 +       if (cfg->internal_escan || cfg->scan_request) {
54                 brcmf_err("timer expired\n");
55                 schedule_work(&cfg->escan_timeout_work);
56         }
57 @@ -3119,7 +3119,7 @@ brcmf_cfg80211_escan_handler(struct brcm
58                 if (brcmf_p2p_scan_finding_common_channel(cfg, bss_info_le))
59                         goto exit;
60  
61 -               if (!cfg->scan_request) {
62 +               if (!cfg->internal_escan && !cfg->scan_request) {
63                         brcmf_dbg(SCAN, "result without cfg80211 request\n");
64                         goto exit;
65                 }
66 @@ -3165,7 +3165,7 @@ brcmf_cfg80211_escan_handler(struct brcm
67                 cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
68                 if (brcmf_p2p_scan_finding_common_channel(cfg, NULL))
69                         goto exit;
70 -               if (cfg->scan_request) {
71 +               if (cfg->internal_escan || cfg->scan_request) {
72                         brcmf_inform_bss(cfg);
73                         aborted = status != BRCMF_E_STATUS_SUCCESS;
74                         brcmf_notify_escan_complete(cfg, ifp, aborted, false);
75 @@ -3190,6 +3190,73 @@ static void brcmf_init_escan(struct brcm
76                   brcmf_cfg80211_escan_timeout_worker);
77  }
78  
79 +static struct cfg80211_scan_request *
80 +brcmf_alloc_internal_escan_request(struct wiphy *wiphy, u32 n_netinfo) {
81 +       struct cfg80211_scan_request *req;
82 +       size_t req_size;
83 +
84 +       req_size = sizeof(*req) +
85 +                  n_netinfo * sizeof(req->channels[0]) +
86 +                  n_netinfo * sizeof(*req->ssids);
87 +
88 +       req = kzalloc(req_size, GFP_KERNEL);
89 +       if (req) {
90 +               req->wiphy = wiphy;
91 +               req->ssids = (void *)(&req->channels[0]) +
92 +                            n_netinfo * sizeof(req->channels[0]);
93 +       }
94 +       return req;
95 +}
96 +
97 +static int brcmf_internal_escan_add_info(struct cfg80211_scan_request *req,
98 +                                        u8 *ssid, u8 ssid_len, u8 channel)
99 +{
100 +       struct ieee80211_channel *chan;
101 +       enum nl80211_band band;
102 +       int freq;
103 +
104 +       if (channel <= CH_MAX_2G_CHANNEL)
105 +               band = NL80211_BAND_2GHZ;
106 +       else
107 +               band = NL80211_BAND_5GHZ;
108 +
109 +       freq = ieee80211_channel_to_frequency(channel, band);
110 +       if (!freq)
111 +               return -EINVAL;
112 +
113 +       chan = ieee80211_get_channel(req->wiphy, freq);
114 +       if (!chan)
115 +               return -EINVAL;
116 +
117 +       req->channels[req->n_channels++] = chan;
118 +       memcpy(req->ssids[req->n_ssids].ssid, ssid, ssid_len);
119 +       req->ssids[req->n_ssids++].ssid_len = ssid_len;
120 +
121 +       return 0;
122 +}
123 +
124 +static int brcmf_start_internal_escan(struct brcmf_if *ifp,
125 +                                     struct cfg80211_scan_request *request)
126 +{
127 +       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
128 +       int err;
129 +
130 +       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
131 +               /* Abort any on-going scan */
132 +               brcmf_abort_scanning(cfg);
133 +       }
134 +
135 +       set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
136 +       cfg->escan_info.run = brcmf_run_escan;
137 +       err = brcmf_do_escan(ifp, request);
138 +       if (err) {
139 +               clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
140 +               return err;
141 +       }
142 +       cfg->internal_escan = true;
143 +       return 0;
144 +}
145 +
146  /* PFN result doesn't have all the info which are required by the supplicant
147   * (For e.g IEs) Do a target Escan so that sched scan results are reported
148   * via wl_inform_single_bss in the required format. Escan does require the
149 @@ -3203,12 +3270,8 @@ brcmf_notify_sched_scan_results(struct b
150         struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
151         struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
152         struct cfg80211_scan_request *request = NULL;
153 -       struct cfg80211_ssid *ssid = NULL;
154 -       struct ieee80211_channel *channel = NULL;
155         struct wiphy *wiphy = cfg_to_wiphy(cfg);
156 -       int err = 0;
157 -       int channel_req = 0;
158 -       int band = 0;
159 +       int i, err = 0;
160         struct brcmf_pno_scanresults_le *pfn_result;
161         u32 result_count;
162         u32 status;
163 @@ -3234,83 +3297,47 @@ brcmf_notify_sched_scan_results(struct b
164          */
165         WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
166         brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
167 -       if (result_count > 0) {
168 -               int i;
169 -
170 -               request = kzalloc(sizeof(*request), GFP_KERNEL);
171 -               ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
172 -               channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
173 -               if (!request || !ssid || !channel) {
174 -                       err = -ENOMEM;
175 -                       goto out_err;
176 -               }
177 +       if (!result_count) {
178 +               brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
179 +               goto out_err;
180 +       }
181 +       request = brcmf_alloc_internal_escan_request(wiphy,
182 +                                                    result_count);
183 +       if (!request) {
184 +               err = -ENOMEM;
185 +               goto out_err;
186 +       }
187  
188 -               request->wiphy = wiphy;
189 -               data += sizeof(struct brcmf_pno_scanresults_le);
190 -               netinfo_start = (struct brcmf_pno_net_info_le *)data;
191 -
192 -               for (i = 0; i < result_count; i++) {
193 -                       netinfo = &netinfo_start[i];
194 -                       if (!netinfo) {
195 -                               brcmf_err("Invalid netinfo ptr. index: %d\n",
196 -                                         i);
197 -                               err = -EINVAL;
198 -                               goto out_err;
199 -                       }
200 +       data += sizeof(struct brcmf_pno_scanresults_le);
201 +       netinfo_start = (struct brcmf_pno_net_info_le *)data;
202  
203 -                       brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
204 -                                 netinfo->SSID, netinfo->channel);
205 -                       memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
206 -                       ssid[i].ssid_len = netinfo->SSID_len;
207 -                       request->n_ssids++;
208 -
209 -                       channel_req = netinfo->channel;
210 -                       if (channel_req <= CH_MAX_2G_CHANNEL)
211 -                               band = NL80211_BAND_2GHZ;
212 -                       else
213 -                               band = NL80211_BAND_5GHZ;
214 -                       channel[i].center_freq =
215 -                               ieee80211_channel_to_frequency(channel_req,
216 -                                                              band);
217 -                       channel[i].band = band;
218 -                       channel[i].flags |= IEEE80211_CHAN_NO_HT40;
219 -                       request->channels[i] = &channel[i];
220 -                       request->n_channels++;
221 -               }
222 -
223 -               /* assign parsed ssid array */
224 -               if (request->n_ssids)
225 -                       request->ssids = &ssid[0];
226 -
227 -               if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
228 -                       /* Abort any on-going scan */
229 -                       brcmf_abort_scanning(cfg);
230 +       for (i = 0; i < result_count; i++) {
231 +               netinfo = &netinfo_start[i];
232 +               if (!netinfo) {
233 +                       brcmf_err("Invalid netinfo ptr. index: %d\n",
234 +                                 i);
235 +                       err = -EINVAL;
236 +                       goto out_err;
237                 }
238  
239 -               set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
240 -               cfg->escan_info.run = brcmf_run_escan;
241 -               err = brcmf_do_escan(ifp, request);
242 -               if (err) {
243 -                       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
244 +               brcmf_dbg(SCAN, "SSID:%.32s Channel:%d\n",
245 +                         netinfo->SSID, netinfo->channel);
246 +               err = brcmf_internal_escan_add_info(request,
247 +                                                   netinfo->SSID,
248 +                                                   netinfo->SSID_len,
249 +                                                   netinfo->channel);
250 +               if (err)
251                         goto out_err;
252 -               }
253 -               cfg->sched_escan = true;
254 -               cfg->scan_request = request;
255 -       } else {
256 -               brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
257 -               goto out_err;
258         }
259  
260 -       kfree(ssid);
261 -       kfree(channel);
262 -       kfree(request);
263 -       return 0;
264 +       err = brcmf_start_internal_escan(ifp, request);
265 +       if (!err)
266 +               goto free_req;
267  
268  out_err:
269 -       kfree(ssid);
270 -       kfree(channel);
271 -       kfree(request);
272         cfg80211_sched_scan_stopped(wiphy);
273 +free_req:
274 +       kfree(request);
275         return err;
276  }
277  
278 @@ -3405,7 +3432,7 @@ static int brcmf_cfg80211_sched_scan_sto
279  
280         brcmf_dbg(SCAN, "enter\n");
281         brcmf_pno_clean(ifp);
282 -       if (cfg->sched_escan)
283 +       if (cfg->internal_escan)
284                 brcmf_notify_escan_complete(cfg, ifp, true, true);
285         return 0;
286  }
287 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
288 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h
289 @@ -271,7 +271,7 @@ struct brcmf_cfg80211_wowl {
290   * @pub: common driver information.
291   * @channel: current channel.
292   * @active_scan: current scan mode.
293 - * @sched_escan: e-scan for scheduled scan support running.
294 + * @internal_escan: indicates internally initiated e-scan is running.
295   * @ibss_starter: indicates this sta is ibss starter.
296   * @pwr_save: indicate whether dongle to support power save mode.
297   * @dongle_up: indicate whether dongle up or not.
298 @@ -303,7 +303,7 @@ struct brcmf_cfg80211_info {
299         struct brcmf_pub *pub;
300         u32 channel;
301         bool active_scan;
302 -       bool sched_escan;
303 +       bool internal_escan;
304         bool ibss_starter;
305         bool pwr_save;
306         bool dongle_up;