blob: b2a9831e9ae01344869780593d9e5c8a015f7a20 [file] [log] [blame]
Abhijit Pradhan49f69432017-03-08 17:27:17 +05301/*
Shashikala Prabhu7517a8d2018-12-13 18:02:45 +05302 * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
Abhijit Pradhan49f69432017-03-08 17:27:17 +05303 * Copyright (c) 2002-2010, Atheros Communications Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/**
19 * DOC: This file contains NOL related functionality, NOL being the non
20 * occupancy list. After radar has been detected in a particular channel,
21 * the channel cannot be used for a period of 30 minutes which is called
22 * the non occupancy. The NOL is basically a list of all the channels that
23 * radar has been detected on. Each channel has a 30 minute timer associated
24 * with it. This file contains the functionality to add a channel to the NOL,
25 * the NOL timer function and the functionality to remove a channel from the
26 * NOL when its time is up.
27 */
28
29#include "../dfs.h"
30#include "../dfs_channel.h"
Abhijit Pradhan49f69432017-03-08 17:27:17 +053031#include "../dfs_ioctl_private.h"
Abhijit Pradhan49f69432017-03-08 17:27:17 +053032#include "../dfs_internal.h"
Arif Hussain8d88af52017-02-26 21:25:42 -080033#include <qdf_time.h>
34#include <wlan_dfs_mlme_api.h>
Shashikala Prabhu7517a8d2018-12-13 18:02:45 +053035#include <wlan_objmgr_vdev_obj.h>
Arif Hussain8d88af52017-02-26 21:25:42 -080036#include <wlan_dfs_utils_api.h>
37#include <wlan_reg_services_api.h>
Vignesh U8785b9d2018-04-20 22:01:25 +053038#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
39#include "../dfs_process_radar_found_ind.h"
40#include "../dfs_partial_offload_radar.h"
41#endif
Abhijit Pradhan49f69432017-03-08 17:27:17 +053042
Vignesh U916926f2018-06-04 14:28:11 +053043void dfs_set_update_nol_flag(struct wlan_dfs *dfs, bool val)
44{
45 dfs->update_nol = val;
46}
47
48bool dfs_get_update_nol_flag(struct wlan_dfs *dfs)
49{
50 return dfs->update_nol;
51}
52
Abhijit Pradhanc5152c72017-06-29 13:27:45 +053053/**
54 * dfs_nol_timeout() - NOL timeout function.
55 *
Shashikala Prabhua072dc52017-11-29 12:03:20 +053056 * Clears the WLAN_CHAN_DFS_RADAR_FOUND flag for the NOL timeout channel.
Abhijit Pradhanc5152c72017-06-29 13:27:45 +053057 */
Priyadarshnee S38da66f2019-10-09 14:33:18 +053058/* Unused function */
59#ifdef CONFIG_CHAN_FREQ_API
60static os_timer_func(dfs_nol_timeout)
61{
62 struct dfs_channel *c = NULL, lc;
63 unsigned long oldest, now;
64 struct wlan_dfs *dfs = NULL;
65 int i;
66 int nchans = 0;
67
68 c = &lc;
69
70 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
71 dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
72
73 now = oldest = qdf_system_ticks();
74 for (i = 0; i < nchans; i++) {
75 dfs_mlme_get_dfs_channels_for_freq
76 (dfs->dfs_pdev_obj,
77 &c->dfs_ch_freq,
78 &c->dfs_ch_flags,
79 &c->dfs_ch_flagext,
80 &c->dfs_ch_ieee,
81 &c->dfs_ch_vhtop_ch_freq_seg1,
82 &c->dfs_ch_vhtop_ch_freq_seg2,
83 &c->dfs_ch_mhz_freq_seg1,
84 &c->dfs_ch_mhz_freq_seg2,
85 i);
86 if (WLAN_IS_CHAN_RADAR(c)) {
87 if (qdf_system_time_after_eq(now,
88 dfs->dfs_nol_event[i] +
89 dfs_get_nol_timeout(dfs))) {
90 c->dfs_ch_flagext &= ~WLAN_CHAN_DFS_RADAR_FOUND;
91 if (c->dfs_ch_flags & WLAN_CHAN_DFS_RADAR) {
92 /*
93 * NB: do this here so we get only one
94 * msg instead of one for every channel
95 * table entry.
96 */
97 dfs_debug(dfs, WLAN_DEBUG_DFS,
98 "radar on channel %u (%u MHz) cleared after timeout",
99 c->dfs_ch_ieee,
100 c->dfs_ch_freq);
101 }
102 } else if (dfs->dfs_nol_event[i] < oldest) {
103 oldest = dfs->dfs_nol_event[i];
104 }
105 }
106 }
107 if (oldest != now) {
108 /* Arrange to process next channel up for a status change. */
109 qdf_timer_mod(&dfs->dfs_nol_timer,
110 dfs_get_nol_timeout(dfs) -
111 qdf_system_ticks_to_msecs(qdf_system_ticks()));
112 }
113}
114#else
115#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530116static os_timer_func(dfs_nol_timeout)
117{
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530118 struct dfs_channel *c = NULL, lc;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530119 unsigned long oldest, now;
120 struct wlan_dfs *dfs = NULL;
121 int i;
122 int nchans = 0;
123
124 c = &lc;
125
126 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
127 dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
128
129 now = oldest = qdf_system_ticks();
130 for (i = 0; i < nchans; i++) {
131 dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
132 &(c->dfs_ch_freq),
133 &(c->dfs_ch_flags),
134 &(c->dfs_ch_flagext),
135 &(c->dfs_ch_ieee),
136 &(c->dfs_ch_vhtop_ch_freq_seg1),
137 &(c->dfs_ch_vhtop_ch_freq_seg2),
138 i);
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530139 if (WLAN_IS_CHAN_RADAR(c)) {
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530140 if (qdf_system_time_after_eq(now,
141 dfs->dfs_nol_event[i] +
142 dfs_get_nol_timeout(dfs))) {
143 c->dfs_ch_flagext &=
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530144 ~WLAN_CHAN_DFS_RADAR_FOUND;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530145 if (c->dfs_ch_flags &
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530146 WLAN_CHAN_DFS_RADAR) {
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530147 /*
148 * NB: do this here so we get only one
149 * msg instead of one for every channel
150 * table entry.
151 */
Abhijit Pradhan77561582017-10-05 17:47:57 +0530152 dfs_debug(dfs, WLAN_DEBUG_DFS,
153 "radar on channel %u (%u MHz) cleared after timeout",
154
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530155 c->dfs_ch_ieee,
156 c->dfs_ch_freq);
157 }
158 } else if (dfs->dfs_nol_event[i] < oldest)
159 oldest = dfs->dfs_nol_event[i];
160 }
161 }
162 if (oldest != now) {
163 /* Arrange to process next channel up for a status change. */
164 qdf_timer_mod(&dfs->dfs_nol_timer,
165 dfs_get_nol_timeout(dfs) -
166 qdf_system_ticks_to_msecs(qdf_system_ticks()));
167 }
168}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530169#endif
170#endif
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530171
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530172/**
173 * dfs_nol_elem_free_work_cb - Free NOL element
174 *
175 * Free the NOL element memory
176 */
177static void dfs_nol_elem_free_work_cb(void *context)
178{
179 struct wlan_dfs *dfs = (struct wlan_dfs *)context;
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530180 struct dfs_nolelem *nol_head;
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530181
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530182 while (true) {
183 WLAN_DFSNOL_LOCK(dfs);
184
185 nol_head = TAILQ_FIRST(&dfs->dfs_nol_free_list);
186 if (nol_head) {
187 TAILQ_REMOVE(&dfs->dfs_nol_free_list, nol_head,
188 nolelem_list);
Priyadarshnee S79a84bd2018-09-05 16:21:52 +0530189 WLAN_DFSNOL_UNLOCK(dfs);
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530190
191 qdf_timer_free(&nol_head->nol_timer);
192 qdf_mem_free(nol_head);
193 } else {
194 WLAN_DFSNOL_UNLOCK(dfs);
195 break;
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530196 }
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530197 }
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530198}
199
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530200void dfs_nol_timer_init(struct wlan_dfs *dfs)
201{
202 qdf_timer_init(NULL,
203 &(dfs->dfs_nol_timer),
204 dfs_nol_timeout,
205 (void *)(dfs),
206 QDF_TIMER_TYPE_WAKE_APPS);
207}
208
209void dfs_nol_attach(struct wlan_dfs *dfs)
210{
Arif Hussain877f3232017-08-09 16:05:03 -0700211 dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530212 dfs_nol_timer_init(dfs);
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530213 qdf_create_work(NULL, &dfs->dfs_nol_elem_free_work,
214 dfs_nol_elem_free_work_cb, dfs);
215 TAILQ_INIT(&dfs->dfs_nol_free_list);
Shaakir Mohamed6f35bb02017-09-15 15:52:21 -0700216 dfs->dfs_use_nol = 1;
Abhijit Pradhan67441612018-01-02 21:46:25 +0530217 WLAN_DFSNOL_LOCK_CREATE(dfs);
218}
219
220void dfs_nol_detach(struct wlan_dfs *dfs)
221{
bingsaa1810a2018-01-18 14:14:41 +0800222 dfs_nol_timer_cleanup(dfs);
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530223 qdf_flush_work(&dfs->dfs_nol_elem_free_work);
224 qdf_destroy_work(NULL, &dfs->dfs_nol_elem_free_work);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530225 WLAN_DFSNOL_LOCK_DESTROY(dfs);
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530226}
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530227
Shashikala Prabhu294c9b62018-08-14 12:28:27 +0530228void dfs_nol_timer_detach(struct wlan_dfs *dfs)
Abhijit Pradhan01abdac2018-07-24 18:03:50 +0530229{
230 qdf_timer_free(&dfs->dfs_nol_timer);
231}
232
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530233/**
234 * dfs_nol_delete() - Delete the given frequency/chwidth from the NOL.
235 * @dfs: Pointer to wlan_dfs structure.
236 * @delfreq: Freq to delete.
237 * @delchwidth: Channel width to delete.
238 */
239static void dfs_nol_delete(struct wlan_dfs *dfs,
240 uint16_t delfreq,
241 uint16_t delchwidth)
242{
243 struct dfs_nolelem *nol, **prev_next;
244
Abhijit Pradhan77561582017-10-05 17:47:57 +0530245 if (!dfs) {
246 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530247 return;
248 }
249
Abhijit Pradhan77561582017-10-05 17:47:57 +0530250 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
251 "remove channel=%d/%d MHz from NOL",
252 delfreq, delchwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530253 prev_next = &(dfs->dfs_nol);
254 nol = dfs->dfs_nol;
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700255 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530256 if (nol->nol_freq == delfreq &&
257 nol->nol_chwidth == delchwidth) {
258 *prev_next = nol->nol_next;
Abhijit Pradhan77561582017-10-05 17:47:57 +0530259 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
260 "removing channel %d/%dMHz from NOL tstamp=%d",
261 nol->nol_freq,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530262 nol->nol_chwidth,
263 (qdf_system_ticks_to_msecs
264 (qdf_system_ticks()) / 1000));
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530265 TAILQ_INSERT_TAIL(&dfs->dfs_nol_free_list,
266 nol, nolelem_list);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530267 nol = *prev_next;
268
269 /* Update the NOL counter. */
270 dfs->dfs_nol_count--;
271
272 /* Be paranoid! */
273 if (dfs->dfs_nol_count < 0) {
Abhijit Pradhan77561582017-10-05 17:47:57 +0530274 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0; eek!");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530275 dfs->dfs_nol_count = 0;
276 }
277
278 } else {
279 prev_next = &(nol->nol_next);
280 nol = nol->nol_next;
281 }
282 }
283}
284
285/**
286 * dfs_remove_from_nol() - Remove the freq from NOL list.
287 *
288 * When NOL times out, this function removes the channel from NOL list.
289 */
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530290#ifdef CONFIG_CHAN_FREQ_API
291static os_timer_func(dfs_remove_from_nol)
292{
293 struct dfs_nolelem *nol_arg;
294 struct wlan_dfs *dfs;
295 uint16_t delfreq;
296 uint16_t delchwidth;
297 uint8_t chan;
298
299 OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
300
301 dfs = nol_arg->nol_dfs;
302 delfreq = nol_arg->nol_freq;
303 delchwidth = nol_arg->nol_chwidth;
304
305 /* Delete the given NOL entry. */
306 DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
307
308 /* Update the wireless stack with the new NOL. */
309 dfs_nol_update(dfs);
310
311 dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
312 chan = utils_dfs_freq_to_chan(delfreq);
313 utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
314 WLAN_EV_NOL_FINISHED);
315 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
316 "remove channel %d from nol", chan);
317 utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
318 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
319 &delfreq, 1, DFS_NOL_RESET);
320 utils_dfs_save_nol(dfs->dfs_pdev_obj);
321}
322#else
323#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530324static os_timer_func(dfs_remove_from_nol)
325{
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530326 struct dfs_nolelem *nol_arg;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530327 struct wlan_dfs *dfs;
328 uint16_t delfreq;
329 uint16_t delchwidth;
Arif Hussaina23b0142017-04-25 23:27:54 -0700330 uint8_t chan;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530331
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530332 OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530333
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530334 dfs = nol_arg->nol_dfs;
335 delfreq = nol_arg->nol_freq;
336 delchwidth = nol_arg->nol_chwidth;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530337
338 /* Delete the given NOL entry. */
Abhijit Pradhan67441612018-01-02 21:46:25 +0530339 DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530340
341 /* Update the wireless stack with the new NOL. */
342 dfs_nol_update(dfs);
343
344 dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
Arif Hussaina23b0142017-04-25 23:27:54 -0700345 chan = utils_dfs_freq_to_chan(delfreq);
phadimanb68fa392018-11-22 16:35:55 +0530346 utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
347 WLAN_EV_NOL_FINISHED);
Abhijit Pradhan77561582017-10-05 17:47:57 +0530348 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
349 "remove channel %d from nol", chan);
Vignesh Mohan242d8de2019-05-21 15:01:07 +0530350 utils_dfs_unmark_precac_nol(dfs->dfs_pdev_obj, chan);
Arif Hussain8d88af52017-02-26 21:25:42 -0800351 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
bings276c0f12018-01-19 14:35:34 +0800352 &chan, 1, DFS_NOL_RESET);
Arif Hussain6dfa7ee2017-10-10 17:03:26 -0700353 utils_dfs_save_nol(dfs->dfs_pdev_obj);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530354}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530355#endif
356#endif
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530357
358void dfs_print_nol(struct wlan_dfs *dfs)
359{
360 struct dfs_nolelem *nol;
361 int i = 0;
362 uint32_t diff_ms, remaining_sec;
363
Abhijit Pradhan77561582017-10-05 17:47:57 +0530364 if (!dfs) {
365 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530366 return;
367 }
368
369 nol = dfs->dfs_nol;
Abhijit Pradhan77561582017-10-05 17:47:57 +0530370 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700371 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530372 diff_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() -
373 nol->nol_start_ticks);
374 diff_ms = (nol->nol_timeout_ms - diff_ms);
375 remaining_sec = diff_ms / 1000; /* Convert to seconds */
Abhijit Pradhan77561582017-10-05 17:47:57 +0530376 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
377 "nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol starttick=%llu",
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530378 i++, nol->nol_freq,
379 nol->nol_chwidth,
380 remaining_sec,
381 (uint64_t)nol->nol_start_ticks);
382 nol = nol->nol_next;
383 }
384}
385
386void dfs_print_nolhistory(struct wlan_dfs *dfs)
387{
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530388 struct dfs_channel *chan_list;
389 int i, j;
390 int nchans;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530391
Abhijit Pradhan77561582017-10-05 17:47:57 +0530392 if (!dfs) {
393 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530394 return;
395 }
396
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530397 nchans = dfs_get_num_chans();
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530398
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530399 chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
400 if (!chan_list)
401 return;
402
403 utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
404 (void *)chan_list, &nchans);
405 if (!nchans) {
406 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
407 qdf_mem_free(chan_list);
408 return;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530409 }
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530410
411 for (i = 0, j = 0; i < nchans; i++, j++)
412 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
413 "nolhistory = %d channel = %d MHz",
414 j, chan_list[i].dfs_ch_freq);
415
416 qdf_mem_free(chan_list);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530417}
418
419void dfs_get_nol(struct wlan_dfs *dfs,
420 struct dfsreq_nolelem *dfs_nol,
421 int *nchan)
422{
423 struct dfs_nolelem *nol;
424
425 *nchan = 0;
426
Abhijit Pradhan77561582017-10-05 17:47:57 +0530427 if (!dfs) {
428 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530429 return;
430 }
431
432 nol = dfs->dfs_nol;
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700433 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530434 dfs_nol[*nchan].nol_freq = nol->nol_freq;
435 dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
436 dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks;
437 dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
438 ++(*nchan);
439 nol = nol->nol_next;
440 }
441}
442
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530443#ifdef CONFIG_CHAN_FREQ_API
444void dfs_set_nol(struct wlan_dfs *dfs,
445 struct dfsreq_nolelem *dfs_nol,
446 int nchan)
447{
448#define TIME_IN_MS 1000
449 uint32_t nol_time_lft_ms;
450 struct dfs_channel chan;
451 int i;
452
453 if (!dfs) {
454 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
455 return;
456 }
457
458 for (i = 0; i < nchan; i++) {
459 nol_time_lft_ms =
460 qdf_system_ticks_to_msecs(qdf_system_ticks() -
461 dfs_nol[i].nol_start_ticks);
462
463 if (nol_time_lft_ms < dfs_nol[i].nol_timeout_ms) {
464 chan.dfs_ch_freq = dfs_nol[i].nol_freq;
465 chan.dfs_ch_flags = 0;
466 chan.dfs_ch_flagext = 0;
467 nol_time_lft_ms =
468 (dfs_nol[i].nol_timeout_ms - nol_time_lft_ms);
469
470 DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
471 (nol_time_lft_ms / TIME_IN_MS));
472 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
473 &chan.dfs_ch_freq,
474 1, DFS_NOL_SET);
475 }
476 }
477#undef TIME_IN_MS
478 dfs_nol_update(dfs);
479}
480#else
481#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530482void dfs_set_nol(struct wlan_dfs *dfs,
483 struct dfsreq_nolelem *dfs_nol,
484 int nchan)
485{
486#define TIME_IN_MS 1000
487 uint32_t nol_time_left_ms;
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530488 struct dfs_channel chan;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530489 int i;
bings276c0f12018-01-19 14:35:34 +0800490 uint8_t chan_num;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530491
Abhijit Pradhan77561582017-10-05 17:47:57 +0530492 if (!dfs) {
493 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530494 return;
495 }
496
497 for (i = 0; i < nchan; i++) {
498 nol_time_left_ms =
499 qdf_system_ticks_to_msecs(qdf_system_ticks() -
500 dfs_nol[i].nol_start_ticks);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530501
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530502 if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
Abhijit Pradhan7dc39002017-05-29 20:43:03 +0530503 chan.dfs_ch_freq = dfs_nol[i].nol_freq;
504 chan.dfs_ch_flags = 0;
505 chan.dfs_ch_flagext = 0;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530506 nol_time_left_ms =
507 (dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530508
509 DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530510 (nol_time_left_ms / TIME_IN_MS));
bings276c0f12018-01-19 14:35:34 +0800511 chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
512 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
513 &chan_num, 1, DFS_NOL_SET);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530514 }
515 }
516#undef TIME_IN_MS
517 dfs_nol_update(dfs);
518}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530519#endif
520#endif
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530521
522void dfs_nol_addchan(struct wlan_dfs *dfs,
523 uint16_t freq,
524 uint32_t dfs_nol_timeout)
525{
526#define TIME_IN_MS 1000
527#define TIME_IN_US (TIME_IN_MS * 1000)
528 struct dfs_nolelem *nol, *elem, *prev;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530529 /* For now, assume all events are 20MHz wide. */
530 int ch_width = 20;
531
Abhijit Pradhan77561582017-10-05 17:47:57 +0530532 if (!dfs) {
533 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530534 return;
535 }
536 nol = dfs->dfs_nol;
537 prev = dfs->dfs_nol;
538 elem = NULL;
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700539 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530540 if ((nol->nol_freq == freq) &&
541 (nol->nol_chwidth == ch_width)) {
542 nol->nol_start_ticks = qdf_system_ticks();
543 nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
544
Abhijit Pradhan77561582017-10-05 17:47:57 +0530545 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
546 "Update OS Ticks for NOL %d MHz / %d MHz",
547 nol->nol_freq, nol->nol_chwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530548
549 qdf_timer_stop(&nol->nol_timer);
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530550 qdf_timer_mod(&nol->nol_timer,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530551 dfs_nol_timeout * TIME_IN_MS);
552 return;
553 }
554 prev = nol;
555 nol = nol->nol_next;
556 }
557
558 /* Add a new element to the NOL. */
559 elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
Abhijit Pradhan77561582017-10-05 17:47:57 +0530560 if (!elem)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530561 goto bad;
562
Abhijit Pradhan93caac72018-03-09 11:42:06 +0530563 qdf_mem_zero(elem, sizeof(*elem));
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530564 elem->nol_dfs = dfs;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530565 elem->nol_freq = freq;
566 elem->nol_chwidth = ch_width;
567 elem->nol_start_ticks = qdf_system_ticks();
568 elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
569 elem->nol_next = NULL;
570 if (prev) {
571 prev->nol_next = elem;
572 } else {
573 /* This is the first element in the NOL. */
574 dfs->dfs_nol = elem;
575 }
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530576
577 qdf_timer_init(NULL,
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530578 &elem->nol_timer, dfs_remove_from_nol,
579 elem, QDF_TIMER_TYPE_WAKE_APPS);
580
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530581 qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530582
583 /* Update the NOL counter. */
584 dfs->dfs_nol_count++;
585
Abhijit Pradhan77561582017-10-05 17:47:57 +0530586 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
587 "new NOL channel %d MHz / %d MHz",
588 elem->nol_freq, elem->nol_chwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530589 return;
590
591bad:
Abhijit Pradhan77561582017-10-05 17:47:57 +0530592 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
593 "failed to allocate memory for nol entry");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530594
595#undef TIME_IN_MS
596#undef TIME_IN_US
597}
598
Abhijit Pradhan67441612018-01-02 21:46:25 +0530599void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530600 uint32_t *nol_chfreq,
601 uint32_t *nol_chwidth,
602 int index)
603{
Abhijit Pradhan67441612018-01-02 21:46:25 +0530604 if (!dfs_nol)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530605 return;
606
Abhijit Pradhan67441612018-01-02 21:46:25 +0530607 *nol_chfreq = dfs_nol[index].nol_freq;
608 *nol_chwidth = dfs_nol[index].nol_chwidth;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530609}
610
611void dfs_nol_update(struct wlan_dfs *dfs)
612{
Abhijit Pradhan67441612018-01-02 21:46:25 +0530613 struct dfsreq_nolelem *dfs_nol;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530614 int nlen;
615
Shashikala Prabhucf7d57c2018-09-17 14:27:47 +0530616 if (!dfs->dfs_nol_count) {
617 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
Priyadarshnee Sb3860802018-10-17 13:18:18 +0530618 dfs_mlme_clist_update(dfs->dfs_pdev_obj, NULL, 0);
Shashikala Prabhucf7d57c2018-09-17 14:27:47 +0530619 return;
620 }
621
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530622 /*
623 * Allocate enough entries to store the NOL. At least on Linux
624 * (don't ask why), if you allocate a 0 entry array, the
625 * returned pointer is 0x10. Make sure you're aware of this
626 * when you start debugging.
627 */
Abhijit Pradhan67441612018-01-02 21:46:25 +0530628 dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
629 sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530630
Madhvapathi Sriramb73fc282019-01-07 09:12:25 +0530631 /*
632 * XXX TODO: if this fails, just schedule a task to retry
633 * updating the NOL at a later stage. That way the NOL
634 * update _DOES_ happen - hopefully the failure was just
635 * temporary.
636 */
637 if (!dfs_nol)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530638 return;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530639
Abhijit Pradhan67441612018-01-02 21:46:25 +0530640 DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530641
642 /* Be suitably paranoid for now. */
643 if (nlen != dfs->dfs_nol_count)
Abhijit Pradhan77561582017-10-05 17:47:57 +0530644 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
645 nlen, dfs->dfs_nol_count);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530646
647 /*
648 * Call the driver layer to have it recalculate the NOL flags
649 * for each driver/umac channel. If the list is empty, pass
650 * NULL instead of dfs_nol. The operating system may have some
651 * special representation for "malloc a 0 byte memory region"
652 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
653 * than a valid allocation (and is likely not NULL so the
654 * pointer doesn't match NULL checks in any later code.
655 */
656 dfs_mlme_clist_update(dfs->dfs_pdev_obj,
657 (nlen > 0) ? dfs_nol : NULL,
658 nlen);
659
660 qdf_mem_free(dfs_nol);
661}
662
Abhijit Pradhan67441612018-01-02 21:46:25 +0530663void dfs_nol_free_list(struct wlan_dfs *dfs)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530664{
665 struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
666
667 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530668 prev = nol;
669 nol = nol->nol_next;
670 qdf_mem_free(prev);
671 /* Update the NOL counter. */
672 dfs->dfs_nol_count--;
673
674 if (dfs->dfs_nol_count < 0) {
Abhijit Pradhan77561582017-10-05 17:47:57 +0530675 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530676 ASSERT(0);
677 }
678 }
Abhijit Pradhan67441612018-01-02 21:46:25 +0530679
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530680 dfs->dfs_nol = NULL;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530681}
682
Abhijit Pradhan67441612018-01-02 21:46:25 +0530683void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
684{
685 struct dfs_nolelem *nol;
Abhijit Pradhan67441612018-01-02 21:46:25 +0530686
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530687 while (true) {
Abhijit Pradhan01abdac2018-07-24 18:03:50 +0530688 WLAN_DFSNOL_LOCK(dfs);
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530689
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530690 nol = dfs->dfs_nol;
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530691 if (nol) {
692 dfs->dfs_nol = nol->nol_next;
693 dfs->dfs_nol_count--;
694 WLAN_DFSNOL_UNLOCK(dfs);
695
696 qdf_timer_free(&nol->nol_timer);
697 qdf_mem_free(nol);
698 } else {
699 WLAN_DFSNOL_UNLOCK(dfs);
700 break;
701 }
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530702 }
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530703}
Abhijit Pradhan67441612018-01-02 21:46:25 +0530704
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530705void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
706{
707 qdf_flush_work(&dfs->dfs_nol_elem_free_work);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530708}
709
Shaakir Mohamed6f35bb02017-09-15 15:52:21 -0700710int dfs_get_use_nol(struct wlan_dfs *dfs)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530711{
Shaakir Mohamed6f35bb02017-09-15 15:52:21 -0700712 return dfs->dfs_use_nol;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530713}
714
715int dfs_get_nol_timeout(struct wlan_dfs *dfs)
716{
717 return dfs->wlan_dfs_nol_timeout;
718}
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530719
720void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
721{
722 struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
723
Abhijit Pradhan67441612018-01-02 21:46:25 +0530724 DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530725}
726
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530727#ifdef CONFIG_CHAN_FREQ_API
728void dfs_clear_nolhistory(struct wlan_dfs *dfs)
729{
730 struct dfs_channel *chan_list;
731 int nchans = 0;
732 bool sta_opmode;
733
734 if (!dfs->dfs_is_stadfs_enabled)
735 return;
736
737 sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
738 if (!sta_opmode)
739 return;
740
741 nchans = dfs_get_num_chans();
742
743 chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
744 if (!chan_list)
745 return;
746
747 utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
748 (void *)chan_list, &nchans);
749 if (!nchans) {
750 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
751 qdf_mem_free(chan_list);
752 return;
753 }
754
755 utils_dfs_reg_update_nol_history_chan_for_freq(dfs->dfs_pdev_obj,
756 (void *)chan_list, nchans,
757 DFS_NOL_HISTORY_RESET);
758
759 qdf_mem_free(chan_list);
760}
761#else
762#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530763void dfs_clear_nolhistory(struct wlan_dfs *dfs)
764{
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530765 struct dfs_channel *chan_list;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530766 int nchans = 0;
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530767 bool sta_opmode;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530768
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530769 if (!dfs->dfs_is_stadfs_enabled)
770 return;
771
772 sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
773 if (!sta_opmode)
774 return;
775
776 nchans = dfs_get_num_chans();
777
778 chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
779 if (!chan_list)
780 return;
781
782 utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
783 (void *)chan_list, &nchans);
784 if (!nchans) {
785 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
786 qdf_mem_free(chan_list);
787 return;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530788 }
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530789
790 utils_dfs_reg_update_nol_history_ch(dfs->dfs_pdev_obj,
791 (void *)chan_list, nchans,
792 DFS_NOL_HISTORY_RESET);
793
794 qdf_mem_free(chan_list);
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530795}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530796#endif
797#endif
Vignesh U8785b9d2018-04-20 22:01:25 +0530798
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530799#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
800 defined(CONFIG_CHAN_FREQ_API)
801void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
802{
803 struct dfs_nolelem *nol;
804 uint16_t freq_list[NUM_CHANNELS_160MHZ];
805 int i, nchans = 0;
806
807 nchans = dfs_get_bonding_channels_for_freq(dfs,
808 &dfs->dfs_radar_found_chan,
809 SEG_ID_PRIMARY,
810 DETECTOR_ID_0,
811 freq_list);
812
813 WLAN_DFSNOL_LOCK(dfs);
814 for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
815 nol = dfs->dfs_nol;
816 while (nol) {
817 if (nol->nol_freq == freq_list[i]) {
818 OS_SET_TIMER(&nol->nol_timer, 0);
819 break;
820 }
821 nol = nol->nol_next;
822 }
823 }
824 WLAN_DFSNOL_UNLOCK(dfs);
825
826 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
827 freq_list, nchans, DFS_NOL_RESET);
828}
829#else
830#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
831 defined(CONFIG_CHAN_NUM_API)
Vignesh U8785b9d2018-04-20 22:01:25 +0530832void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
833{
834 struct dfs_nolelem *nol;
835 uint8_t channels[NUM_CHANNELS_160MHZ];
836 int i, nchans = 0;
837
Vignesh Mohan56a6f312019-06-18 14:23:12 +0530838 nchans = dfs_get_bonding_channels(dfs,
839 &dfs->dfs_radar_found_chan,
840 SEG_ID_PRIMARY,
841 DETECTOR_ID_0,
Vignesh U8785b9d2018-04-20 22:01:25 +0530842 channels);
843
844 WLAN_DFSNOL_LOCK(dfs);
845 for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
846 nol = dfs->dfs_nol;
847 while (nol) {
848 if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
849 channels[i])) {
850 OS_SET_TIMER(&nol->nol_timer, 0);
851 break;
852 }
853 nol = nol->nol_next;
854 }
855 }
856 WLAN_DFSNOL_UNLOCK(dfs);
Abhijit Pradhan45098b92018-06-07 16:24:28 +0530857
858 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
859 channels, nchans, DFS_NOL_RESET);
Vignesh U8785b9d2018-04-20 22:01:25 +0530860}
861#endif
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530862#endif