net: wireless: bcmdhd: Fix compilation warnings
[linux-3.10.git] / drivers / net / wireless / bcmdhd / dhd_custom_sysfs_tegra_scan.c
1 /*
2  * drivers/net/wireless/bcmdhd/dhd_custom_sysfs_tegra_scan.c
3  *
4  * NVIDIA Tegra Sysfs for BCMDHD driver
5  *
6  * Copyright (C) 2014-2015 NVIDIA Corporation. All rights reserved.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  */
18
19 #include "dhd_custom_sysfs_tegra.h"
20 #include "dhd_custom_sysfs_tegra_scan.h"
21
22 int wifi_scan_debug;
23 int wifi_scan_policy_index = -1;
24 struct wifi_scan_policy wifi_scan_policy_list[WIFI_SCAN_POLICY_MAX];
25
26 static DEFINE_SEMAPHORE(wifi_scan_lock);
27 static DEFINE_SEMAPHORE(wifi_scan_read_lock);
28
29 static int
30 wifi_scan_rule__add(const char **bufptr, size_t *countptr,
31         struct wifi_scan_rule *rule)
32 {
33         const char *buf;
34         size_t count;
35         int err, len;
36
37         /* init wifi scan rule */
38         memset(rule, 0, sizeof(*rule));
39
40         /* parse wifi scan rule
41          *
42          * -w wait
43          *    wait time (ms) before executing this rule
44          *    (for scan rule #N, the scan rule will execute at time
45          *    WIFI_SCAN_WORK_SCHEDULE_DELAY_0
46          *    + WIFI_SCAN_WORK_SCHEDULE_DELAY_N * N
47          *    + wait)
48          * -W wait_max wait_tx_netif wait_tx_pktsiz wait_tx_pktcnt
49          *    wait time (ms) or until tx pkt detected before executing this
50          *    rule
51          *    (-W wait is in addition to any -w wait if specified)
52          *    (wait_max is maximum wait time, in case no tx packet matching
53          *    specified size / count is sent)
54          *    (wait_tx_netif is network interface to monitor tx packet,
55          *    0 = primary, 1 = secondary, ...)
56          *    (wait_tx_pktsiz is the size in bytes of the tx packet to wait
57          *    for)
58          *    (wait_tx_pktcnt is the number of tx packets matching specified
59          *    packet size to wait for)
60          * -H home_away_time
61          *    home channel away time (ms)
62          *    (data tx/rx will be blocked while scanning other channel)
63          * -n nprobes
64          *    number of probes for active scanning
65          * -a active_time
66          *    active dwell time (ms)
67          * -p passive_time
68          *    passive dwell time (ms)
69          * -h home_time
70          *    between channel scans, return to home channel for this time (ms)
71          * -c channel_list
72          *    list of channels to scan
73          * --
74          *    separator between scan rules
75          *
76          */
77         err = 0;
78         for (buf = *bufptr, count = *countptr; count > 0; buf++, count--) {
79                 WIFI_SCAN_DEBUG("%s: buf %p count %u\n",
80                         __func__, buf, (unsigned int) count);
81                 if (isspace(*buf))
82                         continue;
83                 if ((*buf != '-') || (count < 2)) {
84                         WIFI_SCAN_DEBUG("%s: parse error"
85                                 " - expected -O -w -W -H -n -a -p -h -c --\n",
86                                 __func__);
87                         return -1;
88                 }
89                 buf++, count--;
90                 switch (*buf) {
91                 case 'O':
92                         buf++, count--;
93                         len = 0;
94                         err = 0;
95                         buf += len, count -= len;
96                         /* adding -O option implies optional scan rule */
97                         rule->flags |= WIFI_SCAN_RULE__FLAGS__OPTIONAL;
98                         break;
99                 case 'w':
100                         buf++, count--;
101                         len = 0;
102                         err = sscanf(buf, " %hd%n",
103                                 &rule->wait, &len);
104                         if ((err < 0) || (len > count)) {
105                                 WIFI_SCAN_DEBUG("%s: invalid"
106                                         " wait (ms)\n",
107                                         __func__);
108                                 return -1;
109                         }
110                         buf += len, count -= len;
111                         /* adding -w option implies time critical scan rule */
112                         rule->flags |= WIFI_SCAN_RULE__FLAGS__TIME_CRITICAL;
113                         continue;
114                 case 'W':
115                         buf++, count--;
116                         len = 0;
117                         err = sscanf(buf, " %hd%n",
118                                 &rule->wait_ms_or_tx_pkt.wait_max, &len);
119                         if ((err < 0) || (len > count)) {
120                                 WIFI_SCAN_DEBUG("%s: invalid"
121                                         " wait_max (ms)\n",
122                                         __func__);
123                                 return -1;
124                         }
125                         buf += len, count -= len;
126                         err = sscanf(buf, " %hd%n",
127                                 &rule->wait_ms_or_tx_pkt.wait_tx_netif, &len);
128                         if ((err < 0) || (len > count)) {
129                                 WIFI_SCAN_DEBUG("%s: invalid"
130                                         " wait_tx_netif\n",
131                                         __func__);
132                                 return -1;
133                         }
134                         buf += len, count -= len;
135                         err = sscanf(buf, " %hd%n",
136                                 &rule->wait_ms_or_tx_pkt.wait_tx_pktsiz, &len);
137                         if ((err < 0) || (len > count)) {
138                                 WIFI_SCAN_DEBUG("%s: invalid"
139                                         " wait_tx_pktsiz\n",
140                                         __func__);
141                                 return -1;
142                         }
143                         buf += len, count -= len;
144                         err = sscanf(buf, " %hd%n",
145                                 &rule->wait_ms_or_tx_pkt.wait_tx_pktcnt, &len);
146                         if ((err < 0) || (len > count)) {
147                                 WIFI_SCAN_DEBUG("%s: invalid"
148                                         " wait_tx_pktcnt\n",
149                                         __func__);
150                                 return -1;
151                         }
152                         buf += len, count -= len;
153                         continue;
154                 case 'H':
155                         buf++, count--;
156                         len = 0;
157                         err = sscanf(buf, " %hd%n",
158                                 &rule->home_away_time, &len);
159                         if ((err < 0) || (len > count)) {
160                                 WIFI_SCAN_DEBUG("%s: invalid"
161                                         " home_away_time (ms)\n",
162                                         __func__);
163                                 return -1;
164                         }
165                         buf += len, count -= len;
166                         continue;
167                 case 'n':
168                         buf++, count--;
169                         len = 0;
170                         err = sscanf(buf, " %hd%n",
171                                 &rule->nprobes, &len);
172                         if ((err < 0) || (len > count)) {
173                                 WIFI_SCAN_DEBUG("%s: invalid"
174                                         " nprobes\n",
175                                         __func__);
176                                 return -1;
177                         }
178                         buf += len, count -= len;
179                         continue;
180                 case 'a':
181                         buf++, count--;
182                         len = 0;
183                         err = sscanf(buf, " %hd%n",
184                                 &rule->active_time, &len);
185                         if ((err < 0) || (len > count)) {
186                                 WIFI_SCAN_DEBUG("%s: invalid"
187                                         " active_time (ms)\n",
188                                         __func__);
189                                 return -1;
190                         }
191                         buf += len, count -= len;
192                         continue;
193                 case 'p':
194                         buf++, count--;
195                         len = 0;
196                         err = sscanf(buf, " %hd%n",
197                                 &rule->passive_time, &len);
198                         if ((err < 0) || (len > count)) {
199                                 WIFI_SCAN_DEBUG("%s: invalid"
200                                         " passive_time (ms)\n",
201                                         __func__);
202                                 return -1;
203                         }
204                         buf += len, count -= len;
205                         continue;
206                 case 'h':
207                         buf++, count--;
208                         len = 0;
209                         err = sscanf(buf, " %hd%n",
210                                 &rule->home_time, &len);
211                         if ((err < 0) || (len > count)) {
212                                 WIFI_SCAN_DEBUG("%s: invalid"
213                                         " home_time (ms)\n",
214                                         __func__);
215                                 return -1;
216                         }
217                         buf += len, count -= len;
218                         continue;
219                 case 'c':
220                         do {
221                                 buf++, count--;
222                                 len = 0;
223                                 err = sscanf(buf, " %hd%n",
224                                         &rule->channel_list[rule->channel_num]
225                                                 .first,
226                                         &len);
227                                 rule->channel_list[rule->channel_num]
228                                         .last
229                                         = rule->channel_list[rule->channel_num]
230                                         .first;
231                                 rule->channel_list[rule->channel_num]
232                                         .repeat
233                                         = 1;
234                                 if ((err < 0) || (len > count)) {
235                                         WIFI_SCAN_DEBUG("%s: invalid"
236                                                 " channel (first)\n",
237                                                 __func__);
238                                         return -1;
239                                 }
240                                 if ((rule->channel_list[rule->channel_num]
241                                         .first < 1)
242                                         ||
243                                         (rule->channel_list[rule->channel_num]
244                                         .first > 200)) {
245                                         WIFI_SCAN_DEBUG("%s: bad value"
246                                                 " channel (first)\n",
247                                                 __func__);
248                                         return -1;
249                                 }
250                                 buf += len, count -= len;
251                                 if (*buf == '-') {
252                                         buf++, count--;
253                                         len = 0;
254                                         err = sscanf(buf, " %hd%n",
255                                                 &rule->channel_list
256                                                         [rule->channel_num]
257                                                         .last,
258                                                 &len);
259                                         if ((err < 0) || (len > count)) {
260                                                 WIFI_SCAN_DEBUG("%s: invalid"
261                                                         " channel (last)\n",
262                                                         __func__);
263                                                 return -1;
264                                         }
265                                         if ((rule->channel_list
266                                                 [rule->channel_num].last <
267                                                 rule->channel_list
268                                                 [rule->channel_num].first) ||
269                                                 (rule->channel_list
270                                                 [rule->channel_num].last >
271                                                 200)) {
272                                                 WIFI_SCAN_DEBUG("%s: bad value"
273                                                         " channel (last)\n",
274                                                         __func__);
275                                                 return -1;
276                                         }
277                                         buf += len, count -= len;
278                                 }
279                                 if (*buf == '*') {
280                                         buf++, count--;
281                                         len = 0;
282                                         err = sscanf(buf, " %hd%n",
283                                                 &rule->channel_list
284                                                         [rule->channel_num]
285                                                         .repeat,
286                                                 &len);
287                                         if ((err < 0) || (len > count)) {
288                                                 WIFI_SCAN_DEBUG("%s: invalid"
289                                                         " channel (repeat)\n",
290                                                         __func__);
291                                                 return -1;
292                                         }
293                                         if ((rule->channel_list
294                                                 [rule->channel_num].repeat <
295                                                 1) ||
296                                                 (rule->channel_list
297                                                 [rule->channel_num].repeat >
298                                                 100)) {
299                                                 WIFI_SCAN_DEBUG("%s: bad value"
300                                                         " channel (repeat)\n",
301                                                         __func__);
302                                                 return -1;
303                                         }
304                                         buf += len, count -= len;
305                                 }
306                                 rule->channel_num++;
307                         } while (*buf == ',');
308                         continue;
309                 case '-':
310                         buf++, count--;
311                         err = -1;
312                         break;
313                 default:
314                         WIFI_SCAN_DEBUG("%s: unknown option -%c\n",
315                                 __func__, *buf);
316                         return -1;
317                 }
318                 if (err < 0)
319                         break;
320         }
321         *bufptr = buf;
322         *countptr = count;
323
324         /* check if empty wifi scan rule (to stop parser) */
325         if (!rule->flags
326          && !rule->wait
327          && !rule->home_away_time
328          && !rule->nprobes
329          && !rule->active_time
330          && !rule->passive_time
331          && !rule->home_time
332          && !rule->channel_num)
333                 return -1;
334         return 0;
335
336 }
337
338 static int
339 wifi_scan_policy__index(const char **bufptr, size_t *countptr, int add)
340 {
341         char name[WIFI_SCAN_POLICY_NAME_SIZE];
342         size_t name_len;
343         int index;
344         int unused_index;
345
346         /* get wifi scan policy name */
347         memset(name, 0, sizeof(name));
348         name_len = 0;
349         if (bufptr && countptr) {
350                 const char *buf = *bufptr;
351                 while (name_len < sizeof(name)) {
352                         if (isalpha(*buf) || (*buf == '_'))
353                                 name[name_len++] = *buf++;
354                         else
355                                 break;
356                 }
357                 *bufptr += name_len;
358                 *countptr -= name_len;
359         }
360         if (name[sizeof(name) - 1] != '\0') {
361                 WIFI_SCAN_DEBUG("%s: wifi scan policy name too long\n",
362                         __func__);
363                 return -1;
364         }
365
366         /* find wifi scan policy with matching name */
367         for (index = 0, unused_index = -1;
368                 index < sizeof(wifi_scan_policy_list)
369                         / sizeof(wifi_scan_policy_list[0]);
370                 index++) {
371                 if (strcmp(wifi_scan_policy_list[index].name, "") == 0) {
372                         if (unused_index == -1)
373                                 unused_index = index;
374                         continue;
375                 }
376                 if (strcmp(wifi_scan_policy_list[index].name, name) == 0) {
377                         WIFI_SCAN_DEBUG("%s: found wifi scan policy"
378                                 " #%d - %s\n",
379                                 __func__, index, name);
380                         return index;
381                 }
382         }
383
384         /* add wifi scan policy with requested name */
385         if (add) {
386                 if (unused_index == -1) {
387                         WIFI_SCAN_DEBUG("%s: cannot add wifi scan policy %s"
388                                 " - table full!\n",
389                                 __func__, name);
390                         return -1;
391                 }
392                 index = unused_index;
393                 memset(&wifi_scan_policy_list[index], 0,
394                         sizeof(wifi_scan_policy_list[index]));
395                 strcpy(wifi_scan_policy_list[index].name, name);
396                 WIFI_SCAN_DEBUG("%s: added new wifi scan policy"
397                         " #%d - %s\n",
398                         __func__, index, name);
399                 return index;
400         }
401         WIFI_SCAN_DEBUG("%s: cannot find wifi scan policy - %s\n",
402                 __func__, name);
403         return -1;
404
405 }
406
407 static void
408 wifi_scan_policy__select(const char *buf, size_t count)
409 {
410         int index;
411
412         /* lock semaphore */
413         if (down_interruptible(&wifi_scan_lock) < 0) {
414                 WIFI_SCAN_DEBUG("%s: cannot lock semaphore\n",
415                         __func__);
416                 return;
417         }
418
419         /* check if wifi scan policy found */
420         index = wifi_scan_policy__index(&buf, &count, 0);
421         if (index < 0) {
422                 WIFI_SCAN_DEBUG("%s: cannot select wifi scan policy\n",
423                         __func__);
424                 up(&wifi_scan_lock);
425                 return;
426         }
427
428         /* select wifi scan policy */
429         wifi_scan_policy_index = index;
430
431         /* unlock semaphore */
432         up(&wifi_scan_lock);
433
434         WIFI_SCAN_DEBUG("%s: selected wifi scan policy #%d\n",
435                 __func__, index);
436
437 }
438
439 static void
440 wifi_scan_policy__add(const char *buf, size_t count)
441 {
442         int index;
443
444         /* lock semaphore */
445         if (down_interruptible(&wifi_scan_lock) < 0) {
446                 WIFI_SCAN_DEBUG("%s: cannot lock semaphore\n",
447                         __func__);
448                 return;
449         }
450
451         /* check if wifi scan policy found / added */
452         index = wifi_scan_policy__index(&buf, &count, 1);
453         if (index < 0) {
454                 WIFI_SCAN_DEBUG("%s: cannot add wifi scan policy\n",
455                         __func__);
456                 up(&wifi_scan_lock);
457                 return;
458         }
459
460         /* add rule(s) to wifi scan policy */
461         for (wifi_scan_policy_list[index].rule_num = 0;
462                 wifi_scan_policy_list[index].rule_num <
463                         sizeof(wifi_scan_policy_list[index].rule_list) /
464                         sizeof(wifi_scan_policy_list[index].rule_list[0]);
465                 wifi_scan_policy_list[index].rule_num++) {
466                 WIFI_SCAN_DEBUG("%s: wifi scan policy #%d rule #%hd\n",
467                         __func__,
468                         index,
469                         wifi_scan_policy_list[index].rule_num);
470                 if (wifi_scan_rule__add(&buf, &count,
471                         &wifi_scan_policy_list[index].rule_list
472                                 [wifi_scan_policy_list[index].rule_num]) < 0)
473                         break;
474         }
475
476         /* unlock semaphore */
477         up(&wifi_scan_lock);
478
479         WIFI_SCAN_DEBUG("%s: added wifi scan policy #%d\n",
480                 __func__, index);
481
482 }
483
484 static void
485 wifi_scan_policy__remove(const char *buf, size_t count)
486 {
487         int index;
488
489         /* lock semaphore */
490         if (down_interruptible(&wifi_scan_lock) < 0) {
491                 WIFI_SCAN_DEBUG("%s: cannot lock semaphore\n",
492                         __func__);
493                 return;
494         }
495
496         /* check if wifi scan policy found */
497         index = wifi_scan_policy__index(&buf, &count, 0);
498         if (index < 0) {
499                 WIFI_SCAN_DEBUG("%s: cannot remove wifi scan policy\n",
500                         __func__);
501                 up(&wifi_scan_lock);
502                 return;
503         }
504
505         /* remove wifi scan policy */
506         if (wifi_scan_policy_index == index) {
507                 wifi_scan_policy_index = -1;
508         }
509         memset(&wifi_scan_policy_list[index], 0,
510                 sizeof(wifi_scan_policy_list[index]));
511
512         /* unlock semaphore */
513         up(&wifi_scan_lock);
514
515         WIFI_SCAN_DEBUG("%s: removed wifi scan policy #%d\n",
516                 __func__, index);
517
518 }
519
520 struct workqueue_struct *wifi_scan_work_queue;
521 struct wifi_scan_work wifi_scan_work_list[WIFI_SCAN_WORK_MAX];
522
523 static atomic_t wifi_scan_work_rules_active = ATOMIC_INIT(0);
524
525 static void
526 wifi_scan_work_func(struct work_struct *work)
527 {
528         unsigned long now
529                 = jiffies;
530         struct delayed_work *dwork
531                 = container_of(work, struct delayed_work, work);
532         struct wifi_scan_work *scan_work
533                 = container_of(dwork, struct wifi_scan_work, dwork);
534         struct wifi_scan_policy *scan_policy;
535         struct wifi_scan_rule *scan_rule;
536         s32 err;
537
538         WIFI_SCAN_DEBUG("%s {\n", __func__);
539
540         /* get current wifi scan policy */
541         scan_policy = &wifi_scan_policy_list[scan_work->scan_policy];
542
543         /* get current wifi scan rule */
544         scan_rule = &scan_policy->rule_list[scan_work->scan_rule];
545
546         /* skip time check if not time critical wifi scan rule */
547         if (!(scan_rule->flags & WIFI_SCAN_RULE__FLAGS__TIME_CRITICAL)) {
548                 WIFI_SCAN_DEBUG("%s: kernel scheduled scan work #%d"
549                         " (non-time critical)"
550                         " (policy %d rule %d)"
551                         " time [%ld-%ld] now %ld jiffies %ld\n",
552                         __func__,
553                         (int) (scan_work - wifi_scan_work_list),
554                         scan_work->scan_policy,
555                         scan_work->scan_rule,
556                         scan_work->jiffies_scheduled_min,
557                         scan_work->jiffies_scheduled_max,
558                         now,
559                         jiffies);
560                 goto skip_time_check;
561         }
562
563         /* check if wifi scan work function was scheduled within specified
564          * time
565          */
566         if (time_before(now, scan_work->jiffies_scheduled_min)) {
567                 WIFI_SCAN_DEBUG("%s: kernel scheduled scan work #%d"
568                         " (policy %d rule %d)"
569                         " before time [%ld-%ld] now %ld jiffies %ld\n",
570                         __func__,
571                         (int) (scan_work - wifi_scan_work_list),
572                         scan_work->scan_policy,
573                         scan_work->scan_rule,
574                         scan_work->jiffies_scheduled_min,
575                         scan_work->jiffies_scheduled_max,
576                         now,
577                         jiffies);
578                 queue_delayed_work(wifi_scan_work_queue,
579                         dwork,
580                         scan_work->jiffies_scheduled_min - now);
581                 return;
582         }
583         if (time_after(now, scan_work->jiffies_scheduled_max)) {
584                 if (--scan_work->schedule_retry < 0) {
585                         WIFI_SCAN_DEBUG("%s: kernel scheduled scan work #%d"
586                                 " (policy %d rule %d)"
587                                 " after time [%ld-%ld] now %ld jiffies %ld\n",
588                                 __func__,
589                                 (int) (scan_work - wifi_scan_work_list),
590                                 scan_work->scan_policy,
591                                 scan_work->scan_rule,
592                                 scan_work->jiffies_scheduled_min,
593                                 scan_work->jiffies_scheduled_max,
594                                 now,
595                                 jiffies);
596                         goto abort_work;
597                 }
598 reschedule:
599                 scan_work->jiffies_scheduled_min
600                         += scan_work->jiffies_reschedule_delta;
601                 scan_work->jiffies_scheduled_max
602                         += scan_work->jiffies_reschedule_delta;
603                 WIFI_SCAN_DEBUG("%s: reschedule scan work #%d"
604                         " (policy %d rule %d)"
605                         " for next time [%ld-%ld] now %ld jiffies %ld\n",
606                         __func__,
607                         (int) (scan_work - wifi_scan_work_list),
608                         scan_work->scan_policy,
609                         scan_work->scan_rule,
610                         scan_work->jiffies_scheduled_min,
611                         scan_work->jiffies_scheduled_max,
612                         now,
613                         jiffies);
614                 queue_delayed_work(wifi_scan_work_queue,
615                         dwork,
616                         scan_work->jiffies_scheduled_min - now);
617                 return;
618         }
619 skip_time_check:
620
621         /* block if "wait for tx" feature specified by scan rule */
622         TEGRA_SCAN_TX_PKT_WAIT(scan_rule)
623
624         /* issue wifi scan request */
625         err = (scan_work->scan)(scan_work->scan_arg.wiphy,
626 #if !defined(WL_CFG80211_P2P_DEV_IF)
627                 scan_work->scan_arg.ndev,
628 #endif
629                 &scan_work->scan_arg.request_and_channels.request);
630         WIFI_SCAN_DEBUG("%s: scan work status %d"
631                 " (policy %d rule %d)"
632                 " time [%ld-%ld] now %ld jiffies %ld\n",
633                 __func__,
634                 err,
635                 scan_work->scan_policy,
636                 scan_work->scan_rule,
637                 scan_work->jiffies_scheduled_min,
638                 scan_work->jiffies_scheduled_max,
639                 now,
640                 jiffies);
641         if (err == -EAGAIN) {
642                 if (--scan_work->schedule_retry >= 0) {
643                         goto reschedule;
644                 }
645         }
646 abort_work:
647
648         WIFI_SCAN_DEBUG("%s }\n", __func__);
649 }
650
651 #define P2P_MAX_CHANNELS_PER_SCAN_WORK 70
652         /* currently manually calculated by reading wl_cfgp2p.c code */
653
654 static void
655 wifi_scan_work_get_max_channel_list_size(struct wiphy *wiphy,
656         struct cfg80211_scan_request *request,
657         int *max_channels_per_scan_work)
658 {
659         struct bcm_cfg80211 *cfg = wiphy_priv(wiphy);
660         bool p2p_ssid = false;
661         struct cfg80211_ssid *ssids;
662         int i;
663
664         WIFI_SCAN_DEBUG("%s: p2p_is_on() %d p2p_scan() %d\n",
665                 __func__,
666                 p2p_is_on(cfg),
667                 p2p_scan(cfg));
668
669         /* for first p2p scan, p2p_is_on() and p2p_scan() values are not
670          * set to indicate p2p, so use scan request p2p ssid to detect
671          */
672         if (request) {          /* scan bss */
673                 ssids = request->ssids;
674                 for (i = 0; i < request->n_ssids; i++) {
675                         if (ssids[i].ssid_len && IS_P2P_SSID
676                                 (ssids[i].ssid, ssids[i].ssid_len)) {
677                                 WIFI_SCAN_DEBUG("%s: p2p_ssid = true\n",
678                                         __func__);
679                                 p2p_ssid = true;
680                                 break;
681                         }
682                 }
683         }
684
685         /* reduce max channels per scan for p2p */
686         if (p2p_ssid || (p2p_is_on(cfg) && p2p_scan(cfg))) {
687                 WIFI_SCAN_DEBUG("%s: P2P SCAN: change max channels per scan"
688                         " - %d -> %d\n",
689                         __func__,
690                         *max_channels_per_scan_work,
691                         P2P_MAX_CHANNELS_PER_SCAN_WORK);
692                 *max_channels_per_scan_work = P2P_MAX_CHANNELS_PER_SCAN_WORK;
693         }
694
695 }
696
697 static void
698 wifi_scan_work_check_channel_list_size(int scan_work_index,
699         int *num_overflow_scan_work,
700         int *num_channels,
701         unsigned short *num_channels_to_add,
702         int max_channels_per_scan_work)
703 {
704         struct wifi_scan_work *scan_work
705                 = &wifi_scan_work_list
706                         [scan_work_index + *num_overflow_scan_work];
707
708         /* check if scan work channel list size is too big */
709         if (*num_channels + *num_channels_to_add <= max_channels_per_scan_work)
710                 return;
711
712         /* finish initializing original scan work
713          * - save channel list size (before overflow occurred)
714          */
715         WIFI_SCAN_DEBUG("%s: scan work #%d"
716                 " - channel list size overflow"
717                 " - %d channel(s)"
718                 " (next %hu channels will go to overflow scan work)\n",
719                 __func__,
720                 (int) (scan_work - wifi_scan_work_list),
721                 *num_channels,
722                 *num_channels_to_add);
723         scan_work->scan_arg.request_and_channels.request.n_channels
724                 = *num_channels;
725
726         /* allocate overflow scan work
727          * - initialize overflow scan work to be same as original scan work
728          *   except that the overflow scan work channel list is empty
729          */
730         if (scan_work_index + *num_overflow_scan_work + 1
731                 >= sizeof(wifi_scan_work_list)
732                 / sizeof(wifi_scan_work_list[0])) {
733                 WIFI_SCAN_DEBUG("%s: cannot allocate overflow scan work:"
734                         " too many scan work(s)\n",
735                         __func__);
736                 *num_channels_to_add = 0;
737                 return;
738         }
739         memcpy(&(scan_work[1].scan_policy),
740                 &(scan_work[0].scan_policy),
741                 sizeof(wifi_scan_work_list[0])
742                 - offsetof(struct wifi_scan_work, scan_policy));
743         memset(&(scan_work[1].scan_arg.request_and_channels.request
744                 .channels[0]),
745                 0,
746                 sizeof(scan_work[1].scan_arg.request_and_channels.request
747                 .channels));
748         (*num_overflow_scan_work)++;
749         *num_channels = 0;
750         scan_work++;
751         scan_work->scan_arg.request_and_channels.request.n_channels
752                 = *num_channels;
753         WIFI_SCAN_DEBUG("%s: overflow scan work #%d"
754                 " - initialized to empty channel list\n",
755                 __func__,
756                 (int) (scan_work - wifi_scan_work_list));
757
758         /* upon return, the caller is expected to save the channel to the
759          * overflow scan work channel list
760          */
761
762 }
763
764 int
765 wifi_scan_request(wl_cfg80211_scan_funcptr_t scan_func,
766         struct wiphy *wiphy,
767         struct net_device *ndev,
768         struct cfg80211_scan_request *request)
769 {
770         struct wifi_scan_work *scan_work
771                 = container_of(request, struct wifi_scan_work,
772                         scan_arg.request_and_channels.request);
773         int max_channels_per_scan_work
774                 = sizeof(wifi_scan_work_list[0].scan_arg.request_and_channels
775                         .channels)
776                 / sizeof(wifi_scan_work_list[0].scan_arg.request_and_channels
777                         .channels[0]);
778         int i, j, k, m, n, x;
779         unsigned long now;
780         int overflow_scan_work;
781         int skipped_scan_rule;
782         int total_scan_rule;
783         unsigned int total_scan_rule_wait;
784         unsigned int msec;
785         struct wifi_scan_policy *scan_policy;
786         struct wifi_scan_rule *scan_rule;
787
788         WIFI_SCAN_DEBUG("%s\n", __func__);
789
790         /* check input */
791         if (!scan_func)
792                 return -1;
793         if (!wiphy)
794                 return -1;
795         if (!ndev)
796                 return -1;
797         if (!request)
798                 return -1;
799
800         /* check if executing scan from scan work(s) */
801         if ((scan_work >= wifi_scan_work_list)
802          && (scan_work - wifi_scan_work_list
803                 < sizeof(wifi_scan_work_list)
804                 / sizeof(wifi_scan_work_list[0]))) {
805                 WIFI_SCAN_DEBUG("%s: executing scan work #%d"
806                         " (policy %d rule %d)\n",
807                         __func__,
808                         (int) (scan_work - wifi_scan_work_list),
809                         scan_work->scan_policy,
810                         scan_work->scan_rule);
811                 /* return 0 to tell calling function to continue processing
812                  * this scan request from the scan work
813                  * - request has substituted scan parameters based on the
814                  *   scan policy's rule
815                  */
816                 return 0;
817         }
818
819         /* check count of wifi scan rules active */
820         if (atomic_read(&wifi_scan_work_rules_active) > 0) {
821                 return -EBUSY;
822         }
823
824         /* lock semaphore */
825         if (down_interruptible(&wifi_scan_lock) < 0) {
826                 WIFI_SCAN_DEBUG("%s: cannot lock semaphore\n",
827                         __func__);
828                 return -EBUSY;
829         }
830
831         /* cancel pending work(s) */
832         for (i = 0; i < sizeof(wifi_scan_work_list)
833                 / sizeof(wifi_scan_work_list[0]); i++) {
834                 cancel_delayed_work_sync(&wifi_scan_work_list[i].dwork);
835         }
836
837         /* adjust max channel per scan, based on wiphy capabilities */
838         wifi_scan_work_get_max_channel_list_size(wiphy,
839                 request,
840                 &max_channels_per_scan_work);
841
842         /* schedule scan work(s) */
843         now = jiffies;
844         overflow_scan_work = 0;
845         skipped_scan_rule = 0;
846         total_scan_rule = 0;
847         total_scan_rule_wait = 0;
848         for (i = 0; i < sizeof(wifi_scan_work_list)
849                 / sizeof(wifi_scan_work_list[0]); i++) {
850                 WIFI_SCAN_DEBUG("%s: scan work #%d\n",
851                         __func__, i);
852                 /* skip overflow scan work(s) from previous iteration
853                  * - overflow scan work(s) are used when a single scan work
854                  *   cannot scan the entire channel list (due to wifi firmware
855                  *   channel list size limitations)
856                  * - overflow scan work(s) are identical to the previous
857                  *   scan work, except that the channel list is different
858                  */
859                 if (overflow_scan_work) {
860                         WIFI_SCAN_DEBUG("%s: scan work #%d -> #%d"
861                                 " - skip overflow_scan_work (%d)\n",
862                                 __func__,
863                                 i,
864                                 i + overflow_scan_work,
865                                 overflow_scan_work);
866                         i += overflow_scan_work;
867                         overflow_scan_work = 0;
868                         i--;
869                         continue;
870                 }
871                 /* initialize scan work */
872                 memset(&wifi_scan_work_list[i].scan_policy,
873                         0,
874                         sizeof(wifi_scan_work_list[i])
875                         - offsetof(struct wifi_scan_work, scan_policy));
876                 /* each scan work will execute one scan rule of current scan
877                  * policy
878                  */
879                 if (wifi_scan_policy_index < 0)
880                         break;
881                 scan_policy = &wifi_scan_policy_list[wifi_scan_policy_index];
882                 if (total_scan_rule >= scan_policy->rule_num)
883                         break;
884                 scan_rule = &scan_policy->rule_list[total_scan_rule];
885                 wifi_scan_work_list[i].scan_policy
886                         = wifi_scan_policy_index;
887                 wifi_scan_work_list[i].scan_rule
888                         = total_scan_rule;
889                 /* if scan rule is optional, then create scan work for it
890                  * only if no preceding scan rule has scan work scheduled
891                  */
892                 if (scan_rule->flags & WIFI_SCAN_RULE__FLAGS__OPTIONAL) {
893                         if (total_scan_rule - skipped_scan_rule == 0) {
894                                 WIFI_SCAN_DEBUG("%s:"
895                                         " WIFI_SCAN_RULE__FLAGS__OPTIONAL"
896                                         " - use optional scan rule because"
897                                         " no preceding scan rule(s) were"
898                                         " enabled\n",
899                                         __func__);
900                                 /* do nothing to use this optional scan rule */
901                         } else {
902                                 WIFI_SCAN_DEBUG("%s:"
903                                         " WIFI_SCAN_RULE__FLAGS__OPTIONAL"
904                                         " - skip optional scan rule because"
905                                         " %d preceding scan rule(s) were"
906                                         " enabled\n",
907                                         __func__,
908                                         total_scan_rule - skipped_scan_rule);
909                                 i--;
910                                 skipped_scan_rule++;
911                                 total_scan_rule++;
912                                 continue;
913                         }
914                 }
915                 /* save original scan request so that cfg80211 can be
916                  * notified after all scan work(s) have completed
917                  */
918                 wifi_scan_work_list[i].original_scan_request = request;
919                 /* schedule scan work
920                  * - always add fixed delay from now
921                  *   (WIFI_SCAN_WORK_SCHEDULE_DELAY_0)
922                  * - stagger each wifi rule execution from previous rule
923                  *   execution
924                  *   (WIFI_SCAN_WORK_SCHEDULE_DELAY_N)
925                  * - add wait time in scan rule
926                  */
927                 wifi_scan_work_list[i].schedule_retry
928                         = WIFI_SCAN_WORK_SCHEDULE_RETRY;
929                 total_scan_rule_wait += scan_rule->wait;
930                 msec = WIFI_SCAN_WORK_SCHEDULE_DELAY_0
931                         + ((total_scan_rule - skipped_scan_rule)
932                                 * WIFI_SCAN_WORK_SCHEDULE_DELAY_N)
933                         + total_scan_rule_wait;
934                 wifi_scan_work_list[i].jiffies_scheduled_min
935                         = now
936                         + msecs_to_jiffies(msec);
937                 msec = WIFI_SCAN_WORK_SCHEDULE_WINDOW;
938                 wifi_scan_work_list[i].jiffies_scheduled_max
939                         = wifi_scan_work_list[i].jiffies_scheduled_min
940                         + msecs_to_jiffies(msec);
941                 msec = WIFI_SCAN_WORK_RESCHEDULE_DELTA;
942                 wifi_scan_work_list[i].jiffies_reschedule_delta
943                         = msecs_to_jiffies(msec);
944                 /* save wireless driver scan function to call from scan work
945                  * function
946                  */
947                 wifi_scan_work_list[i].scan
948                         = scan_func;
949                 wifi_scan_work_list[i].scan_arg.wiphy
950                         = wiphy;
951 #if !defined(WL_CFG80211_P2P_DEV_IF)
952                 wifi_scan_work_list[i].scan_arg.ndev
953                         = ndev;
954 #endif
955                 wifi_scan_work_list[i].scan_arg.request_and_channels.request
956                         = *request;
957                 if (request->flags & NL80211_FEATURE_SCAN_FLUSH) {
958                         /* the original scan request will be split into
959                          * multiple scan work(s)...
960                          * - to achieve same effect as
961                          *   NL80211_FEATURE_SCAN_FLUSH, copy this bit
962                          *   from original scan request for 1st scan work
963                          * - for 2nd and later scan work(s), always clear this
964                          *   bit
965                          */
966                         WIFI_SCAN_DEBUG("%s: original scan request has"
967                                 " NL80211_FEATURE_SCAN_FLUSH flag set\n",
968                                 __func__);
969                         if (total_scan_rule - skipped_scan_rule == 0)
970                                 wifi_scan_work_list[i].scan_arg
971                                         .request_and_channels.request.flags
972                                         |= NL80211_FEATURE_SCAN_FLUSH;
973                         else
974                                 wifi_scan_work_list[i].scan_arg
975                                         .request_and_channels.request.flags
976                                         &= ~(NL80211_FEATURE_SCAN_FLUSH);
977                 }
978                 /* scan work channel list is intersection of channel list
979                  * between
980                  * - original scan request
981                  * - scan rule
982                  */
983                 wifi_scan_work_list[i].scan_arg.request_and_channels.request
984                         .n_channels = 0;
985                 for (m = n = 0; m < request->n_channels; m++) {
986                         unsigned short freq
987                                 = request->channels[m]->center_freq;
988                         int channel
989                                 = (freq > 5000) ? (freq - 5000) / 5
990                                 : (freq == 2484) ? 14
991                                 : (freq > 2407) ? (freq - 2407) / 5
992                                 : 0;
993                         int allowed = 0;
994                         unsigned short channel_repeat = 0;
995                         if (scan_rule->channel_num == 0) {
996                                 allowed = 1;
997                                 channel_repeat = 1;
998                         }
999                         for (j = 0; j < scan_rule->channel_num; j++) {
1000                                 if ((channel >= scan_rule->channel_list[j]
1001                                         .first) &&
1002                                         (channel <= scan_rule->channel_list[j]
1003                                         .last)) {
1004                                         allowed = 1;
1005                                         channel_repeat
1006                                                 = scan_rule->channel_list[j]
1007                                                         .repeat;
1008                                         break;
1009                                 }
1010                         }
1011                         WIFI_SCAN_DEBUG("freq %hu channel %d"
1012                                 " - allowed %d (channel repeat %hd times)\n",
1013                                 freq, channel, allowed, channel_repeat);
1014                         if (!allowed)
1015                                 continue;
1016                         wifi_scan_work_check_channel_list_size(i,
1017                                 &overflow_scan_work, &n, &channel_repeat,
1018                                 max_channels_per_scan_work);
1019                         for (k = 0; k < channel_repeat; k++) {
1020                                 if (n >= sizeof(wifi_scan_work_list
1021                                         [i + overflow_scan_work]
1022                                         .scan_arg
1023                                         .request_and_channels
1024                                         .channels) /
1025                                         sizeof(wifi_scan_work_list
1026                                         [i + overflow_scan_work]
1027                                         .scan_arg
1028                                         .request_and_channels
1029                                         .channels[0])) {
1030                                         WIFI_SCAN_DEBUG("%s:"
1031                                                 " too many channels!\n",
1032                                                 __func__);
1033                                         break;
1034                                 }
1035                                 wifi_scan_work_list[i + overflow_scan_work]
1036                                         .scan_arg
1037                                         .request_and_channels
1038                                         .channels[n++]
1039                                         = request->channels[m];
1040                         }
1041                 }
1042                 wifi_scan_work_list[i + overflow_scan_work]
1043                         .scan_arg.request_and_channels
1044                         .request.n_channels = n;
1045                 /* skip scan rule if original scan request had channels
1046                  * but intersection with scan rule channel list is empty
1047                  * (no channels to scan for this scan work)
1048                  */
1049                 if ((request->n_channels > 0) && (n == 0)) {
1050                         WIFI_SCAN_DEBUG("%s: skip scan rule #%d"
1051                                 " - empty channel list\n",
1052                                 __func__,
1053                                 total_scan_rule);
1054                         wifi_scan_work_list[i].original_scan_request = NULL;
1055                         i--;
1056                         skipped_scan_rule++;
1057                         total_scan_rule++;
1058                         continue;
1059                 }
1060                 /* increment count of wifi scan rules active */
1061                 atomic_inc(&wifi_scan_work_rules_active);
1062                 for (x = 0; x < overflow_scan_work; x++)
1063                         atomic_inc(&wifi_scan_work_rules_active);
1064                 /* schedule delayed work
1065                  * - only first delayed work is queued
1066                  * - after each delayed work completes, the TEGRA_SCAN_DONE()
1067                  *   macro is expected to be executed by the escan handler
1068                  * - TEGRA_SCAN_DONE() macro will schedule next delayed work
1069                  */
1070                 if (total_scan_rule - skipped_scan_rule == 0) {
1071                         queue_delayed_work(wifi_scan_work_queue,
1072                                 &wifi_scan_work_list[i].dwork,
1073                                 wifi_scan_work_list[i].jiffies_scheduled_min
1074                                         - now);
1075                 }
1076                 /* increment count of wifi scan rule(s) added */
1077                 total_scan_rule++;
1078         }
1079
1080         /* unlock semaphore */
1081         up(&wifi_scan_lock);
1082
1083         /* special case - if no scan rule(s) match original scan request
1084          * then complete original scan request without doing any actual
1085          * scanning
1086          * - occurs if the channel list specified in original scan request
1087          *   does not intersect with the channel list in every scan rule
1088          *   of the current scan policy
1089          */
1090         if ((total_scan_rule > 0)
1091                 && (total_scan_rule - skipped_scan_rule == 0)) {
1092                 WIFI_SCAN_DEBUG("%s: no scan rule(s) matching original"
1093                         " scan request"
1094                         " - calling cfg80211_scan_done()"
1095                         " for original request %p\n",
1096                         __func__,
1097                         request);
1098                 cfg80211_scan_done(request, false);
1099                 /* return non-zero value to tell caller to not execute
1100                  * original scan request
1101                  */
1102                 return (total_scan_rule);
1103         }
1104
1105         /* return number of scan work(s) scheduled:
1106          * 0 = no scan policy active or scan policy already active
1107          *     (caller should execute original scan request)
1108          * 1 ... WIFI_SCAN_POLICY_RULE_MAX = scan policy activated
1109          *     (caller should not execute original scan request)
1110          *     (scan work functions will execute scan request part-by-part)
1111          */
1112         return (total_scan_rule - skipped_scan_rule);
1113
1114 }
1115
1116 int
1117 wifi_scan_request_done(struct cfg80211_scan_request *request)
1118 {
1119         struct wifi_scan_work *scan_work
1120                 = container_of(request, struct wifi_scan_work,
1121                         scan_arg.request_and_channels.request);
1122         struct wifi_scan_work *next_scan_work = NULL;
1123         int err = -1;
1124
1125         WIFI_SCAN_DEBUG("%s {\n", __func__);
1126
1127         /* check if scan work done */
1128         if ((scan_work >= wifi_scan_work_list)
1129          && (scan_work - wifi_scan_work_list < sizeof(wifi_scan_work_list)
1130                 / sizeof(wifi_scan_work_list[0]))) {
1131                 WIFI_SCAN_DEBUG("%s: done executing scan work #%d"
1132                         " (policy %d rule %d)\n",
1133                         __func__,
1134                         (int) (scan_work - wifi_scan_work_list),
1135                         scan_work->scan_policy,
1136                         scan_work->scan_rule);
1137                 /* decrement count of wifi scan rules active */
1138                 if (atomic_dec_and_test(&wifi_scan_work_rules_active)) {
1139                         WIFI_SCAN_DEBUG("%s: finished all scan work(s)"
1140                                 " - calling cfg80211_scan_done()"
1141                                 " for original request %p\n",
1142                                 __func__,
1143                                 scan_work->original_scan_request);
1144                         cfg80211_scan_done(scan_work->original_scan_request,
1145                                 false);
1146                 }
1147                 /* get next wifi scan work to be scheduled */
1148                 next_scan_work = scan_work + 1;
1149                 if ((next_scan_work - wifi_scan_work_list >=
1150                         sizeof(wifi_scan_work_list) /
1151                         sizeof(wifi_scan_work_list[0])) ||
1152                         (next_scan_work->original_scan_request
1153                                 != scan_work->original_scan_request)) {
1154                         next_scan_work = NULL;
1155                 }
1156                 /* return index (>= 0) of scan work */
1157                 err = (int) (scan_work - wifi_scan_work_list);
1158         }
1159
1160         /* check if all scan work(s) done */
1161         for (scan_work = wifi_scan_work_list;
1162                 scan_work - wifi_scan_work_list
1163                         < sizeof(wifi_scan_work_list)
1164                         / sizeof(wifi_scan_work_list[0]);
1165                 scan_work++) {
1166                 if (&scan_work->scan_arg.request_and_channels.request
1167                         == request) {
1168                         WIFI_SCAN_DEBUG("%s: TEGRA_SCAN_DONE:"
1169                                 " scan_work #%d (%p)"
1170                                 " - intermediate scan request done\n",
1171                                 __func__,
1172                                 (int) (scan_work - wifi_scan_work_list),
1173                                 scan_work);
1174                         scan_work->original_scan_request = NULL;
1175                 }
1176                 if (scan_work->original_scan_request == request) {
1177                         WIFI_SCAN_DEBUG("%s: TEGRA_SCAN_DONE:"
1178                                 " scan_work #%d (%p)"
1179                                 " - original scan request done\n",
1180                                 __func__,
1181                                 (int) (scan_work - wifi_scan_work_list),
1182                                 scan_work);
1183 #if 0
1184                         if (_aborted_) {
1185                                 pr_err/*WIFI_SCAN_DEBUG*/("%s: TEGRA_SCAN_DONE:"
1186                                         " - abort pending work\n",
1187                                         __func__);
1188                         }
1189 #endif
1190                         cancel_delayed_work(&scan_work->dwork);
1191                         scan_work->original_scan_request = NULL;
1192                         atomic_set(&wifi_scan_work_rules_active, 0);
1193                 }
1194         }
1195
1196         /* schedule next scan work
1197          * - if not time critical, schedule immediately
1198          *   (for optimal performance, no delays between scan works)
1199          * - if time critical and...
1200          *   = current time is before pre-scheduled time, schedule delayed work
1201          *     (must schedule at precise calculated timestamp sometime in the
1202          *     future)
1203          *   = current time is after pre-scheduled time, schedule immediately
1204          *     (already missed desired timestamp, so just run it and let it
1205          *     reschedule itself later at the precise required timestamp)
1206          */
1207         if (next_scan_work) {
1208                 unsigned long int now = jiffies;
1209                 struct wifi_scan_policy *next_scan_policy
1210                         = wifi_scan_policy_list
1211                         + next_scan_work->scan_policy;
1212                 struct wifi_scan_rule *next_scan_rule
1213                         = next_scan_policy->rule_list
1214                         + next_scan_work->scan_rule;
1215                 if (!(next_scan_rule->flags
1216                         & WIFI_SCAN_RULE__FLAGS__TIME_CRITICAL)) {
1217                         WIFI_SCAN_DEBUG("%s: TEGRA_SCAN_DONE:"
1218                                 " - schedule next scan work"
1219                                 " (non-time critical)\n",
1220                                 __func__);
1221                         queue_delayed_work(wifi_scan_work_queue,
1222                                 &next_scan_work->dwork,
1223                                 0);
1224                 } else if (time_before(now,
1225                         next_scan_work->jiffies_scheduled_min)) {
1226                         WIFI_SCAN_DEBUG("%s: TEGRA_SCAN_DONE:"
1227                                 " - schedule next scan work"
1228                                 " (time critical + before)\n",
1229                                 __func__);
1230                         queue_delayed_work(wifi_scan_work_queue,
1231                                 &next_scan_work->dwork,
1232                                 next_scan_work->jiffies_scheduled_min - now);
1233                 } else {
1234                         WIFI_SCAN_DEBUG("%s: TEGRA_SCAN_DONE:"
1235                                 " - schedule next scan work"
1236                                 " (time critical + after)\n",
1237                                 __func__);
1238                         queue_delayed_work(wifi_scan_work_queue,
1239                                 &next_scan_work->dwork,
1240                                 0);
1241                 }
1242         }
1243
1244         /* return -1 if not processed, >= 0 if processed */
1245         WIFI_SCAN_DEBUG("%s }\n", __func__);
1246         return (err);
1247
1248 }
1249
1250 int wifi_scan_pno_time;
1251 int wifi_scan_pno_repeat;
1252 int wifi_scan_pno_freq_expo_max;
1253 int wifi_scan_pno_home_away_time;
1254 int wifi_scan_pno_nprobes;
1255 int wifi_scan_pno_active_time;
1256 int wifi_scan_pno_passive_time;
1257 int wifi_scan_pno_home_time;
1258
1259 int wifi_scan_wait;
1260 DECLARE_WAIT_QUEUE_HEAD(wifi_scan_wait_queue);
1261 atomic_t wifi_scan_wait_tx_netif = ATOMIC_INIT(0);
1262 atomic_t wifi_scan_wait_tx_pktsiz = ATOMIC_INIT(0);
1263 atomic_t wifi_scan_wait_tx_pktcnt = ATOMIC_INIT(0);
1264
1265 void
1266 tegra_sysfs_histogram_scan_work_start(void)
1267 {
1268         int i;
1269
1270 //      pr_info("%s\n", __func__);
1271
1272         if (!wifi_scan_work_queue) {
1273                 wifi_scan_work_queue = create_workqueue("wifi_scan_policy");
1274                 if (!wifi_scan_work_queue) {
1275                         pr_err("%s: cannot create work queue\n",
1276                                 __func__);
1277                         return;
1278                 }
1279                 for (i = 0; i < sizeof(wifi_scan_work_list)
1280                         / sizeof(wifi_scan_work_list[0]); i++) {
1281                         INIT_DELAYED_WORK(&wifi_scan_work_list[i].dwork,
1282                                 wifi_scan_work_func);
1283                 }
1284         }
1285
1286 }
1287
1288 void
1289 tegra_sysfs_histogram_scan_work_stop(void)
1290 {
1291 //      pr_info("%s\n", __func__);
1292 //      cancel_delayed_work_sync(&scan_work);
1293 }
1294
1295 static int tegra_sysfs_histogram_scan_show_pointer = -1;
1296
1297 ssize_t
1298 tegra_sysfs_histogram_scan_show(struct device *dev,
1299         struct device_attribute *attr,
1300         char *buf)
1301 {
1302 #if 0
1303         static int i;
1304
1305 //      pr_info("%s\n", __func__);
1306
1307         if (!i) {
1308                 i++;
1309                 strcpy(buf, "dummy scan!");
1310                 return strlen(buf);
1311         } else {
1312                 i = 0;
1313                 return 0;
1314         }
1315 #else
1316         char *s, *t;
1317         int i, m, n;
1318         struct wifi_scan_policy *scan_policy;
1319         struct wifi_scan_rule *scan_rule;
1320
1321 //      pr_info("%s\n", __func__);
1322
1323         /* lock semaphore */
1324         if (down_interruptible(&wifi_scan_lock) < 0) {
1325                 WIFI_SCAN_DEBUG("%s: cannot lock semaphore\n",
1326                         __func__);
1327                 return 0;
1328         }
1329
1330         /* get/show wifi scan policy(s) */
1331         s = buf;
1332         if (tegra_sysfs_histogram_scan_show_pointer == -1) {
1333                 /* show header */
1334                 snprintf(s,
1335                         PAGE_SIZE - (s - buf),
1336                         "Active scan policy: %d\n"
1337                         "\n",
1338                         wifi_scan_policy_index);
1339                 if (PAGE_SIZE - (s - buf) == strlen(s) + 1) {
1340                         *s = '\0';
1341                         goto abort_show_item;
1342                 }
1343                 s += strlen(s);
1344                 /* set show pointer to next item */
1345                 tegra_sysfs_histogram_scan_show_pointer++;
1346         }
1347         for (i = tegra_sysfs_histogram_scan_show_pointer;
1348                 i < sizeof(wifi_scan_policy_list) /
1349                         sizeof(wifi_scan_policy_list[0]);
1350                 i++) {
1351                 /* show wifi scan policy */
1352                 scan_policy = wifi_scan_policy_list + i;
1353                 snprintf(s,
1354                         PAGE_SIZE - (s - buf),
1355                         "Scan policy #%d\n"
1356                         "  name: \"%-*s\"\n"
1357                         "  rule_num: %hu\n",
1358                         i,
1359                         (int) sizeof(scan_policy->name),
1360                         scan_policy->name,
1361                         scan_policy->rule_num);
1362                 if (PAGE_SIZE - (s - buf) == strlen(s) + 1) {
1363                         *s = '\0';
1364                         goto abort_show_item;
1365                 }
1366                 t = s;
1367                 s += strlen(s);
1368                 for (m = 0; m < scan_policy->rule_num; m++) {
1369                         scan_rule = scan_policy->rule_list + m;
1370                         snprintf(s,
1371                                 PAGE_SIZE - (s - buf),
1372                                 "  rule_list[%d]:\n"
1373                                 "    flags: %04hx\n"
1374                                 "    wait: %hu\n"
1375                                 "    wait_ms_or_tx_pkt\n"
1376                                 "      wait_max %hu\n"
1377                                 "      wait_tx_netif %hu\n"
1378                                 "      wait_tx_pktsiz %hu\n"
1379                                 "      wait_tx_pktcnt %hu\n"
1380                                 "    home_away_time: %hu\n"
1381                                 "    nprobes: %hu\n"
1382                                 "    active_time: %hu\n"
1383                                 "    passive_time: %hu\n"
1384                                 "    home_time: %hu\n"
1385                                 "    channel_num: %hu\n"
1386                                 "    channel_list: ",
1387                                 m,
1388                                 scan_rule->flags,
1389                                 scan_rule->wait,
1390                                 scan_rule->wait_ms_or_tx_pkt.wait_max,
1391                                 scan_rule->wait_ms_or_tx_pkt.wait_tx_netif,
1392                                 scan_rule->wait_ms_or_tx_pkt.wait_tx_pktsiz,
1393                                 scan_rule->wait_ms_or_tx_pkt.wait_tx_pktcnt,
1394                                 scan_rule->home_away_time,
1395                                 scan_rule->nprobes,
1396                                 scan_rule->active_time,
1397                                 scan_rule->passive_time,
1398                                 scan_rule->home_time,
1399                                 scan_rule->channel_num);
1400                         s += strlen(s);
1401                         for (n = 0; n < scan_rule->channel_num; n++) {
1402                                 snprintf(s,
1403                                         PAGE_SIZE - (s - buf),
1404                                         "%hu",
1405                                         scan_rule->channel_list[n].first);
1406                                 s += strlen(s);
1407                                 if (scan_rule->channel_list[n].first !=
1408                                         scan_rule->channel_list[n].last) {
1409                                         snprintf(s,
1410                                                 PAGE_SIZE - (s - buf),
1411                                                 "-%hu",
1412                                                 scan_rule->channel_list[n]
1413                                                         .last);
1414                                         s += strlen(s);
1415                                 }
1416                                 if (scan_rule->channel_list[n].repeat != 1) {
1417                                         snprintf(s,
1418                                                 PAGE_SIZE - (s - buf),
1419                                                 "*%hu",
1420                                                 scan_rule->channel_list[n]
1421                                                         .repeat);
1422                                         s += strlen(s);
1423                                 }
1424                                 snprintf(s,
1425                                         PAGE_SIZE - (s - buf),
1426                                         " ");
1427                                 s += strlen(s);
1428                         }
1429                         snprintf(s,
1430                                 PAGE_SIZE - (s - buf),
1431                                 "\n");
1432                         s += strlen(s);
1433                 }
1434                 if (PAGE_SIZE - (t - buf) == strlen(t) + 1) {
1435                         *t = '\0';
1436                         s = t;
1437                         goto abort_show_item;
1438                 }
1439                 /* set show pointer to next item */
1440                 tegra_sysfs_histogram_scan_show_pointer++;
1441         }
1442
1443         /* get/show wifi pno scan settings */
1444         if (tegra_sysfs_histogram_scan_show_pointer ==
1445                 sizeof(wifi_scan_policy_list) /
1446                 sizeof(wifi_scan_policy_list[0])) {
1447                 /* show trailer */
1448                 snprintf(s,
1449                         PAGE_SIZE - (s - buf),
1450                         "\n"
1451                         "PNO scan settings:\n"
1452                         "  pno_time %d\n"
1453                         "  pno_repeat %d\n"
1454                         "  pno_freq_expo_max %d\n"
1455                         "  wifi_scan_pno_home_away_time %d\n"
1456                         "  wifi_scan_pno_nprobes %d\n"
1457                         "  wifi_scan_pno_active_time %d\n"
1458                         "  wifi_scan_pno_passive_time %d\n"
1459                         "  wifi_scan_pno_home_time %d\n",
1460                         wifi_scan_pno_time,
1461                         wifi_scan_pno_repeat,
1462                         wifi_scan_pno_freq_expo_max,
1463                         wifi_scan_pno_home_away_time,
1464                         wifi_scan_pno_nprobes,
1465                         wifi_scan_pno_active_time,
1466                         wifi_scan_pno_passive_time,
1467                         wifi_scan_pno_home_time);
1468                 if (PAGE_SIZE - (s - buf) == strlen(s) + 1) {
1469                         *s = '\0';
1470                         goto abort_show_item;
1471                 }
1472                 s += strlen(s);
1473                 /* reset show pointer to first item */
1474                 tegra_sysfs_histogram_scan_show_pointer = -1;
1475         }
1476
1477 abort_show_item:
1478         /* unlock semaphore */
1479         up(&wifi_scan_lock);
1480
1481         /* exit */
1482         return (s - buf);
1483
1484 #endif
1485 }
1486
1487 ssize_t
1488 tegra_sysfs_histogram_scan_store(struct device *dev,
1489         struct device_attribute *attr,
1490         const char *buf, size_t count)
1491 {
1492         int a, b, c, skip;
1493
1494 //      pr_info("%s\n", __func__);
1495
1496         if (strncmp(buf, "debug", 5) == 0) {
1497                 wifi_scan_debug = !wifi_scan_debug;
1498         } else if (strncmp(buf, "enable", 6) == 0) {
1499         } else if (strncmp(buf, "disable", 7) == 0) {
1500         } else if (strncmp(buf, "policy ", 7) == 0) {
1501                 wifi_scan_policy__select(buf + 7, count - 7);
1502         } else if (strncmp(buf, "+policy ", 8) == 0) {
1503                 wifi_scan_policy__add(buf + 8, count - 8);
1504         } else if (strncmp(buf, "-policy ", 8) == 0) {
1505                 wifi_scan_policy__remove(buf + 8, count - 8);
1506         } else if (strncmp(buf, "pno ", 4) == 0) {
1507                 if (sscanf(buf + 4, "%d %d %d%n", &a, &b, &c, &skip) < 3) {
1508                         pr_err("%s: invalid pno setting:"
1509                                 " pno <pno_time>"
1510                                 " <pno_repeat> <pno_freq_expo_max>\n",
1511                                 __func__);
1512                         return count;
1513                 }
1514                 buf += 4 + skip;
1515                 wifi_scan_pno_time = a;
1516                 wifi_scan_pno_repeat = b;
1517                 wifi_scan_pno_freq_expo_max = c;
1518 check_pno_arguments_again:
1519                 if (sscanf(buf, " -H %d%n", &a, &skip) >= 1) {
1520                         pr_info("-H %d\n", a);
1521                         wifi_scan_pno_home_away_time = a;
1522                         buf += skip;
1523                         goto check_pno_arguments_again;
1524                 }
1525                 if (sscanf(buf, " -n %d%n", &a, &skip) >= 1) {
1526                         pr_info("-n %d\n", a);
1527                         wifi_scan_pno_nprobes = a;
1528                         buf += skip;
1529                         goto check_pno_arguments_again;
1530                 }
1531                 if (sscanf(buf, " -a %d%n", &a, &skip) >= 1) {
1532                         pr_info("-a %d\n", a);
1533                         wifi_scan_pno_active_time = a;
1534                         buf += skip;
1535                         goto check_pno_arguments_again;
1536                 }
1537                 if (sscanf(buf, " -p %d%n", &a, &skip) >= 1) {
1538                         pr_info("-p %d\n", a);
1539                         wifi_scan_pno_passive_time = a;
1540                         buf += skip;
1541                         goto check_pno_arguments_again;
1542                 }
1543                 if (sscanf(buf, " -h %d%n", &a, &skip) >= 1) {
1544                         pr_info("-h %d\n", a);
1545                         wifi_scan_pno_home_time = a;
1546                         buf += skip;
1547                         goto check_pno_arguments_again;
1548                 }
1549         } else {
1550                 pr_err("%s: unknown command\n", __func__);
1551         }
1552
1553         return count;
1554 }
1555
1556 ssize_t
1557 tegra_debugfs_histogram_scan_read(struct file *filp,
1558         char __user *buff, size_t count, loff_t *offp)
1559 {
1560         static char buf[PAGE_SIZE];
1561         struct device *dev = NULL;
1562         struct device_attribute *attr = NULL;
1563         ssize_t size, chunk;
1564
1565 //      pr_info("%s\n", __func__);
1566
1567         /* lock read semaphore */
1568         if (down_interruptible(&wifi_scan_read_lock) < 0) {
1569                 WIFI_SCAN_DEBUG("%s: cannot lock read semaphore\n",
1570                         __func__);
1571                 return 0;
1572         }
1573
1574         if (offp && (*offp != 0) &&
1575                 (tegra_sysfs_histogram_scan_show_pointer == -1)) {
1576                 up(&wifi_scan_read_lock);
1577                 return 0;
1578         }
1579
1580         for (size = 0; size + PAGE_SIZE <= count; size += chunk) {
1581                 chunk = tegra_sysfs_histogram_scan_show(dev, attr, buf);
1582                 if (chunk <= 0)
1583                         break;
1584                 if (copy_to_user(buff + size, buf, chunk) != 0) {
1585                         pr_err("%s: copy_to_user() failed!\n", __func__);
1586                         break;
1587                 }
1588                 if (offp)
1589                         *offp += chunk;
1590                 if (tegra_sysfs_histogram_scan_show_pointer == -1) {
1591                         size += chunk;
1592                         break;
1593                 }
1594         }
1595
1596         /* unlock read semaphore */
1597         up(&wifi_scan_read_lock);
1598
1599         return size;
1600 }
1601
1602 ssize_t
1603 tegra_debugfs_histogram_scan_write(struct file *filp,
1604         const char __user *buff, size_t count, loff_t *offp)
1605 {
1606 //      pr_info("%s\n", __func__);
1607         return count;
1608 }