blob: dcf828262631d9d9ea0e801ea8eef03df4db88bd [file] [log] [blame]
Abhijit Pradhan49f69432017-03-08 17:27:17 +05301/*
Vignesh Mohan86eba592019-10-23 17:34:14 +05302 * Copyright (c) 2016-2020 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
Stephen Hines5b4ca182017-01-26 00:43:34 -080018/* Suppress -Waddress-of-packed-member for new toolchain update.
19 * Bug: http://b/33566695
20 */
21#if __clang_major__ >= 4
22#pragma clang diagnostic ignored "-Waddress-of-packed-member"
23#endif
24
Abhijit Pradhan49f69432017-03-08 17:27:17 +053025/**
26 * DOC: This file contains NOL related functionality, NOL being the non
27 * occupancy list. After radar has been detected in a particular channel,
28 * the channel cannot be used for a period of 30 minutes which is called
29 * the non occupancy. The NOL is basically a list of all the channels that
30 * radar has been detected on. Each channel has a 30 minute timer associated
31 * with it. This file contains the functionality to add a channel to the NOL,
32 * the NOL timer function and the functionality to remove a channel from the
33 * NOL when its time is up.
34 */
35
36#include "../dfs.h"
37#include "../dfs_channel.h"
Abhijit Pradhan49f69432017-03-08 17:27:17 +053038#include "../dfs_ioctl_private.h"
Abhijit Pradhan49f69432017-03-08 17:27:17 +053039#include "../dfs_internal.h"
Arif Hussain8d88af52017-02-26 21:25:42 -080040#include <qdf_time.h>
41#include <wlan_dfs_mlme_api.h>
Shashikala Prabhu7517a8d2018-12-13 18:02:45 +053042#include <wlan_objmgr_vdev_obj.h>
Arif Hussain8d88af52017-02-26 21:25:42 -080043#include <wlan_dfs_utils_api.h>
44#include <wlan_reg_services_api.h>
Vignesh U8785b9d2018-04-20 22:01:25 +053045#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
46#include "../dfs_process_radar_found_ind.h"
47#include "../dfs_partial_offload_radar.h"
48#endif
Abhijit Pradhan49f69432017-03-08 17:27:17 +053049
Vignesh U916926f2018-06-04 14:28:11 +053050void dfs_set_update_nol_flag(struct wlan_dfs *dfs, bool val)
51{
52 dfs->update_nol = val;
53}
54
55bool dfs_get_update_nol_flag(struct wlan_dfs *dfs)
56{
57 return dfs->update_nol;
58}
59
Abhijit Pradhanc5152c72017-06-29 13:27:45 +053060/**
61 * dfs_nol_timeout() - NOL timeout function.
62 *
Shashikala Prabhua072dc52017-11-29 12:03:20 +053063 * Clears the WLAN_CHAN_DFS_RADAR_FOUND flag for the NOL timeout channel.
Abhijit Pradhanc5152c72017-06-29 13:27:45 +053064 */
Priyadarshnee S38da66f2019-10-09 14:33:18 +053065/* Unused function */
66#ifdef CONFIG_CHAN_FREQ_API
67static os_timer_func(dfs_nol_timeout)
68{
69 struct dfs_channel *c = NULL, lc;
70 unsigned long oldest, now;
71 struct wlan_dfs *dfs = NULL;
72 int i;
73 int nchans = 0;
74
75 c = &lc;
76
77 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
78 dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
79
80 now = oldest = qdf_system_ticks();
81 for (i = 0; i < nchans; i++) {
82 dfs_mlme_get_dfs_channels_for_freq
83 (dfs->dfs_pdev_obj,
84 &c->dfs_ch_freq,
85 &c->dfs_ch_flags,
86 &c->dfs_ch_flagext,
87 &c->dfs_ch_ieee,
88 &c->dfs_ch_vhtop_ch_freq_seg1,
89 &c->dfs_ch_vhtop_ch_freq_seg2,
90 &c->dfs_ch_mhz_freq_seg1,
91 &c->dfs_ch_mhz_freq_seg2,
92 i);
93 if (WLAN_IS_CHAN_RADAR(c)) {
94 if (qdf_system_time_after_eq(now,
95 dfs->dfs_nol_event[i] +
96 dfs_get_nol_timeout(dfs))) {
97 c->dfs_ch_flagext &= ~WLAN_CHAN_DFS_RADAR_FOUND;
98 if (c->dfs_ch_flags & WLAN_CHAN_DFS_RADAR) {
99 /*
100 * NB: do this here so we get only one
101 * msg instead of one for every channel
102 * table entry.
103 */
104 dfs_debug(dfs, WLAN_DEBUG_DFS,
105 "radar on channel %u (%u MHz) cleared after timeout",
106 c->dfs_ch_ieee,
107 c->dfs_ch_freq);
108 }
109 } else if (dfs->dfs_nol_event[i] < oldest) {
110 oldest = dfs->dfs_nol_event[i];
111 }
112 }
113 }
114 if (oldest != now) {
115 /* Arrange to process next channel up for a status change. */
116 qdf_timer_mod(&dfs->dfs_nol_timer,
117 dfs_get_nol_timeout(dfs) -
118 qdf_system_ticks_to_msecs(qdf_system_ticks()));
119 }
120}
121#else
122#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530123static os_timer_func(dfs_nol_timeout)
124{
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530125 struct dfs_channel *c = NULL, lc;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530126 unsigned long oldest, now;
127 struct wlan_dfs *dfs = NULL;
128 int i;
129 int nchans = 0;
130
131 c = &lc;
132
133 OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
134 dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
135
136 now = oldest = qdf_system_ticks();
137 for (i = 0; i < nchans; i++) {
138 dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
139 &(c->dfs_ch_freq),
140 &(c->dfs_ch_flags),
141 &(c->dfs_ch_flagext),
142 &(c->dfs_ch_ieee),
143 &(c->dfs_ch_vhtop_ch_freq_seg1),
144 &(c->dfs_ch_vhtop_ch_freq_seg2),
145 i);
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530146 if (WLAN_IS_CHAN_RADAR(c)) {
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530147 if (qdf_system_time_after_eq(now,
148 dfs->dfs_nol_event[i] +
149 dfs_get_nol_timeout(dfs))) {
150 c->dfs_ch_flagext &=
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530151 ~WLAN_CHAN_DFS_RADAR_FOUND;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530152 if (c->dfs_ch_flags &
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530153 WLAN_CHAN_DFS_RADAR) {
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530154 /*
155 * NB: do this here so we get only one
156 * msg instead of one for every channel
157 * table entry.
158 */
Abhijit Pradhan77561582017-10-05 17:47:57 +0530159 dfs_debug(dfs, WLAN_DEBUG_DFS,
160 "radar on channel %u (%u MHz) cleared after timeout",
161
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530162 c->dfs_ch_ieee,
163 c->dfs_ch_freq);
164 }
165 } else if (dfs->dfs_nol_event[i] < oldest)
166 oldest = dfs->dfs_nol_event[i];
167 }
168 }
169 if (oldest != now) {
170 /* Arrange to process next channel up for a status change. */
171 qdf_timer_mod(&dfs->dfs_nol_timer,
172 dfs_get_nol_timeout(dfs) -
173 qdf_system_ticks_to_msecs(qdf_system_ticks()));
174 }
175}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530176#endif
177#endif
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530178
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530179/**
180 * dfs_nol_elem_free_work_cb - Free NOL element
181 *
182 * Free the NOL element memory
183 */
184static void dfs_nol_elem_free_work_cb(void *context)
185{
186 struct wlan_dfs *dfs = (struct wlan_dfs *)context;
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530187 struct dfs_nolelem *nol_head;
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530188
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530189 while (true) {
190 WLAN_DFSNOL_LOCK(dfs);
191
192 nol_head = TAILQ_FIRST(&dfs->dfs_nol_free_list);
193 if (nol_head) {
194 TAILQ_REMOVE(&dfs->dfs_nol_free_list, nol_head,
195 nolelem_list);
Priyadarshnee S79a84bd2018-09-05 16:21:52 +0530196 WLAN_DFSNOL_UNLOCK(dfs);
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530197
198 qdf_timer_free(&nol_head->nol_timer);
199 qdf_mem_free(nol_head);
200 } else {
201 WLAN_DFSNOL_UNLOCK(dfs);
202 break;
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530203 }
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530204 }
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530205}
206
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530207void dfs_nol_timer_init(struct wlan_dfs *dfs)
208{
209 qdf_timer_init(NULL,
210 &(dfs->dfs_nol_timer),
211 dfs_nol_timeout,
212 (void *)(dfs),
213 QDF_TIMER_TYPE_WAKE_APPS);
214}
215
216void dfs_nol_attach(struct wlan_dfs *dfs)
217{
Arif Hussain877f3232017-08-09 16:05:03 -0700218 dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530219 dfs_nol_timer_init(dfs);
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530220 qdf_create_work(NULL, &dfs->dfs_nol_elem_free_work,
221 dfs_nol_elem_free_work_cb, dfs);
222 TAILQ_INIT(&dfs->dfs_nol_free_list);
Shaakir Mohamed6f35bb02017-09-15 15:52:21 -0700223 dfs->dfs_use_nol = 1;
Abhijit Pradhan67441612018-01-02 21:46:25 +0530224 WLAN_DFSNOL_LOCK_CREATE(dfs);
225}
226
227void dfs_nol_detach(struct wlan_dfs *dfs)
228{
bingsaa1810a2018-01-18 14:14:41 +0800229 dfs_nol_timer_cleanup(dfs);
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530230 qdf_flush_work(&dfs->dfs_nol_elem_free_work);
231 qdf_destroy_work(NULL, &dfs->dfs_nol_elem_free_work);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530232 WLAN_DFSNOL_LOCK_DESTROY(dfs);
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530233}
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530234
Shashikala Prabhu294c9b62018-08-14 12:28:27 +0530235void dfs_nol_timer_detach(struct wlan_dfs *dfs)
Abhijit Pradhan01abdac2018-07-24 18:03:50 +0530236{
237 qdf_timer_free(&dfs->dfs_nol_timer);
238}
239
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530240/**
241 * dfs_nol_delete() - Delete the given frequency/chwidth from the NOL.
242 * @dfs: Pointer to wlan_dfs structure.
243 * @delfreq: Freq to delete.
244 * @delchwidth: Channel width to delete.
245 */
246static void dfs_nol_delete(struct wlan_dfs *dfs,
247 uint16_t delfreq,
248 uint16_t delchwidth)
249{
250 struct dfs_nolelem *nol, **prev_next;
251
Abhijit Pradhan77561582017-10-05 17:47:57 +0530252 if (!dfs) {
253 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530254 return;
255 }
256
Abhijit Pradhan77561582017-10-05 17:47:57 +0530257 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
258 "remove channel=%d/%d MHz from NOL",
259 delfreq, delchwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530260 prev_next = &(dfs->dfs_nol);
261 nol = dfs->dfs_nol;
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700262 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530263 if (nol->nol_freq == delfreq &&
264 nol->nol_chwidth == delchwidth) {
265 *prev_next = nol->nol_next;
Abhijit Pradhan77561582017-10-05 17:47:57 +0530266 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
267 "removing channel %d/%dMHz from NOL tstamp=%d",
268 nol->nol_freq,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530269 nol->nol_chwidth,
270 (qdf_system_ticks_to_msecs
271 (qdf_system_ticks()) / 1000));
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530272 TAILQ_INSERT_TAIL(&dfs->dfs_nol_free_list,
273 nol, nolelem_list);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530274 nol = *prev_next;
275
276 /* Update the NOL counter. */
277 dfs->dfs_nol_count--;
278
279 /* Be paranoid! */
280 if (dfs->dfs_nol_count < 0) {
Abhijit Pradhan77561582017-10-05 17:47:57 +0530281 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0; eek!");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530282 dfs->dfs_nol_count = 0;
283 }
284
285 } else {
286 prev_next = &(nol->nol_next);
287 nol = nol->nol_next;
288 }
289 }
290}
291
292/**
293 * dfs_remove_from_nol() - Remove the freq from NOL list.
294 *
295 * When NOL times out, this function removes the channel from NOL list.
296 */
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530297#ifdef CONFIG_CHAN_FREQ_API
298static os_timer_func(dfs_remove_from_nol)
299{
300 struct dfs_nolelem *nol_arg;
301 struct wlan_dfs *dfs;
302 uint16_t delfreq;
303 uint16_t delchwidth;
304 uint8_t chan;
305
306 OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
307
308 dfs = nol_arg->nol_dfs;
309 delfreq = nol_arg->nol_freq;
310 delchwidth = nol_arg->nol_chwidth;
311
312 /* Delete the given NOL entry. */
313 DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
314
315 /* Update the wireless stack with the new NOL. */
316 dfs_nol_update(dfs);
317
318 dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
319 chan = utils_dfs_freq_to_chan(delfreq);
320 utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
321 WLAN_EV_NOL_FINISHED);
322 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
323 "remove channel %d from nol", chan);
324 utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
325 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
326 &delfreq, 1, DFS_NOL_RESET);
327 utils_dfs_save_nol(dfs->dfs_pdev_obj);
328}
329#else
330#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530331static os_timer_func(dfs_remove_from_nol)
332{
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530333 struct dfs_nolelem *nol_arg;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530334 struct wlan_dfs *dfs;
335 uint16_t delfreq;
336 uint16_t delchwidth;
Arif Hussaina23b0142017-04-25 23:27:54 -0700337 uint8_t chan;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530338
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530339 OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530340
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530341 dfs = nol_arg->nol_dfs;
342 delfreq = nol_arg->nol_freq;
343 delchwidth = nol_arg->nol_chwidth;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530344
345 /* Delete the given NOL entry. */
Abhijit Pradhan67441612018-01-02 21:46:25 +0530346 DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530347
348 /* Update the wireless stack with the new NOL. */
349 dfs_nol_update(dfs);
350
351 dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
Arif Hussaina23b0142017-04-25 23:27:54 -0700352 chan = utils_dfs_freq_to_chan(delfreq);
phadimanb68fa392018-11-22 16:35:55 +0530353 utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
354 WLAN_EV_NOL_FINISHED);
Abhijit Pradhan77561582017-10-05 17:47:57 +0530355 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
356 "remove channel %d from nol", chan);
Vignesh Mohan242d8de2019-05-21 15:01:07 +0530357 utils_dfs_unmark_precac_nol(dfs->dfs_pdev_obj, chan);
Arif Hussain8d88af52017-02-26 21:25:42 -0800358 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
bings276c0f12018-01-19 14:35:34 +0800359 &chan, 1, DFS_NOL_RESET);
Arif Hussain6dfa7ee2017-10-10 17:03:26 -0700360 utils_dfs_save_nol(dfs->dfs_pdev_obj);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530361}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530362#endif
363#endif
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530364
365void dfs_print_nol(struct wlan_dfs *dfs)
366{
367 struct dfs_nolelem *nol;
368 int i = 0;
369 uint32_t diff_ms, remaining_sec;
370
Abhijit Pradhan77561582017-10-05 17:47:57 +0530371 if (!dfs) {
372 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530373 return;
374 }
375
376 nol = dfs->dfs_nol;
Abhijit Pradhan77561582017-10-05 17:47:57 +0530377 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700378 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530379 diff_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() -
380 nol->nol_start_ticks);
381 diff_ms = (nol->nol_timeout_ms - diff_ms);
382 remaining_sec = diff_ms / 1000; /* Convert to seconds */
Abhijit Pradhan77561582017-10-05 17:47:57 +0530383 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
384 "nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol starttick=%llu",
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530385 i++, nol->nol_freq,
386 nol->nol_chwidth,
387 remaining_sec,
388 (uint64_t)nol->nol_start_ticks);
389 nol = nol->nol_next;
390 }
391}
392
393void dfs_print_nolhistory(struct wlan_dfs *dfs)
394{
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530395 struct dfs_channel *chan_list;
396 int i, j;
397 int nchans;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530398
Abhijit Pradhan77561582017-10-05 17:47:57 +0530399 if (!dfs) {
400 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530401 return;
402 }
403
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530404 nchans = dfs_get_num_chans();
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530405
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530406 chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
407 if (!chan_list)
408 return;
409
410 utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
411 (void *)chan_list, &nchans);
412 if (!nchans) {
413 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
414 qdf_mem_free(chan_list);
415 return;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530416 }
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530417
418 for (i = 0, j = 0; i < nchans; i++, j++)
419 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
420 "nolhistory = %d channel = %d MHz",
421 j, chan_list[i].dfs_ch_freq);
422
423 qdf_mem_free(chan_list);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530424}
425
426void dfs_get_nol(struct wlan_dfs *dfs,
427 struct dfsreq_nolelem *dfs_nol,
428 int *nchan)
429{
430 struct dfs_nolelem *nol;
431
432 *nchan = 0;
433
Abhijit Pradhan77561582017-10-05 17:47:57 +0530434 if (!dfs) {
435 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530436 return;
437 }
438
439 nol = dfs->dfs_nol;
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700440 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530441 dfs_nol[*nchan].nol_freq = nol->nol_freq;
442 dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
443 dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks;
444 dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
445 ++(*nchan);
446 nol = nol->nol_next;
447 }
448}
449
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530450#ifdef CONFIG_CHAN_FREQ_API
451void dfs_set_nol(struct wlan_dfs *dfs,
452 struct dfsreq_nolelem *dfs_nol,
453 int nchan)
454{
455#define TIME_IN_MS 1000
456 uint32_t nol_time_lft_ms;
457 struct dfs_channel chan;
458 int i;
459
460 if (!dfs) {
461 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
462 return;
463 }
464
465 for (i = 0; i < nchan; i++) {
466 nol_time_lft_ms =
467 qdf_system_ticks_to_msecs(qdf_system_ticks() -
468 dfs_nol[i].nol_start_ticks);
469
470 if (nol_time_lft_ms < dfs_nol[i].nol_timeout_ms) {
471 chan.dfs_ch_freq = dfs_nol[i].nol_freq;
472 chan.dfs_ch_flags = 0;
473 chan.dfs_ch_flagext = 0;
474 nol_time_lft_ms =
475 (dfs_nol[i].nol_timeout_ms - nol_time_lft_ms);
476
477 DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
478 (nol_time_lft_ms / TIME_IN_MS));
479 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
480 &chan.dfs_ch_freq,
481 1, DFS_NOL_SET);
482 }
483 }
484#undef TIME_IN_MS
485 dfs_nol_update(dfs);
486}
487#else
488#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530489void dfs_set_nol(struct wlan_dfs *dfs,
490 struct dfsreq_nolelem *dfs_nol,
491 int nchan)
492{
493#define TIME_IN_MS 1000
494 uint32_t nol_time_left_ms;
Shashikala Prabhua072dc52017-11-29 12:03:20 +0530495 struct dfs_channel chan;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530496 int i;
bings276c0f12018-01-19 14:35:34 +0800497 uint8_t chan_num;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530498
Abhijit Pradhan77561582017-10-05 17:47:57 +0530499 if (!dfs) {
500 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530501 return;
502 }
503
504 for (i = 0; i < nchan; i++) {
505 nol_time_left_ms =
506 qdf_system_ticks_to_msecs(qdf_system_ticks() -
507 dfs_nol[i].nol_start_ticks);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530508
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530509 if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
Abhijit Pradhan7dc39002017-05-29 20:43:03 +0530510 chan.dfs_ch_freq = dfs_nol[i].nol_freq;
511 chan.dfs_ch_flags = 0;
512 chan.dfs_ch_flagext = 0;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530513 nol_time_left_ms =
514 (dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530515
516 DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530517 (nol_time_left_ms / TIME_IN_MS));
bings276c0f12018-01-19 14:35:34 +0800518 chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
519 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
520 &chan_num, 1, DFS_NOL_SET);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530521 }
522 }
523#undef TIME_IN_MS
524 dfs_nol_update(dfs);
525}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530526#endif
527#endif
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530528
529void dfs_nol_addchan(struct wlan_dfs *dfs,
530 uint16_t freq,
531 uint32_t dfs_nol_timeout)
532{
533#define TIME_IN_MS 1000
534#define TIME_IN_US (TIME_IN_MS * 1000)
535 struct dfs_nolelem *nol, *elem, *prev;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530536 /* For now, assume all events are 20MHz wide. */
537 int ch_width = 20;
538
Abhijit Pradhan77561582017-10-05 17:47:57 +0530539 if (!dfs) {
540 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530541 return;
542 }
543 nol = dfs->dfs_nol;
544 prev = dfs->dfs_nol;
545 elem = NULL;
Jeff Johnsoncba07b42019-03-20 12:14:17 -0700546 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530547 if ((nol->nol_freq == freq) &&
548 (nol->nol_chwidth == ch_width)) {
549 nol->nol_start_ticks = qdf_system_ticks();
550 nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
551
Abhijit Pradhan77561582017-10-05 17:47:57 +0530552 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
553 "Update OS Ticks for NOL %d MHz / %d MHz",
554 nol->nol_freq, nol->nol_chwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530555
556 qdf_timer_stop(&nol->nol_timer);
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530557 qdf_timer_mod(&nol->nol_timer,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530558 dfs_nol_timeout * TIME_IN_MS);
559 return;
560 }
561 prev = nol;
562 nol = nol->nol_next;
563 }
564
565 /* Add a new element to the NOL. */
566 elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
Abhijit Pradhan77561582017-10-05 17:47:57 +0530567 if (!elem)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530568 goto bad;
569
Abhijit Pradhan93caac72018-03-09 11:42:06 +0530570 qdf_mem_zero(elem, sizeof(*elem));
Abhijit Pradhan0c80b532017-04-29 19:01:25 +0530571 elem->nol_dfs = dfs;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530572 elem->nol_freq = freq;
573 elem->nol_chwidth = ch_width;
574 elem->nol_start_ticks = qdf_system_ticks();
575 elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
576 elem->nol_next = NULL;
577 if (prev) {
578 prev->nol_next = elem;
579 } else {
580 /* This is the first element in the NOL. */
581 dfs->dfs_nol = elem;
582 }
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530583
584 qdf_timer_init(NULL,
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530585 &elem->nol_timer, dfs_remove_from_nol,
586 elem, QDF_TIMER_TYPE_WAKE_APPS);
587
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530588 qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530589
590 /* Update the NOL counter. */
591 dfs->dfs_nol_count++;
592
Abhijit Pradhan77561582017-10-05 17:47:57 +0530593 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
594 "new NOL channel %d MHz / %d MHz",
595 elem->nol_freq, elem->nol_chwidth);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530596 return;
597
598bad:
Abhijit Pradhan77561582017-10-05 17:47:57 +0530599 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
600 "failed to allocate memory for nol entry");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530601
602#undef TIME_IN_MS
603#undef TIME_IN_US
604}
605
Abhijit Pradhan67441612018-01-02 21:46:25 +0530606void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530607 uint32_t *nol_chfreq,
608 uint32_t *nol_chwidth,
609 int index)
610{
Abhijit Pradhan67441612018-01-02 21:46:25 +0530611 if (!dfs_nol)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530612 return;
613
Abhijit Pradhan67441612018-01-02 21:46:25 +0530614 *nol_chfreq = dfs_nol[index].nol_freq;
615 *nol_chwidth = dfs_nol[index].nol_chwidth;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530616}
617
618void dfs_nol_update(struct wlan_dfs *dfs)
619{
Abhijit Pradhan67441612018-01-02 21:46:25 +0530620 struct dfsreq_nolelem *dfs_nol;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530621 int nlen;
622
Shashikala Prabhucf7d57c2018-09-17 14:27:47 +0530623 if (!dfs->dfs_nol_count) {
624 dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
Priyadarshnee Sb3860802018-10-17 13:18:18 +0530625 dfs_mlme_clist_update(dfs->dfs_pdev_obj, NULL, 0);
Shashikala Prabhucf7d57c2018-09-17 14:27:47 +0530626 return;
627 }
628
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530629 /*
630 * Allocate enough entries to store the NOL. At least on Linux
631 * (don't ask why), if you allocate a 0 entry array, the
632 * returned pointer is 0x10. Make sure you're aware of this
633 * when you start debugging.
634 */
Abhijit Pradhan67441612018-01-02 21:46:25 +0530635 dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
636 sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530637
Madhvapathi Sriramb73fc282019-01-07 09:12:25 +0530638 /*
639 * XXX TODO: if this fails, just schedule a task to retry
640 * updating the NOL at a later stage. That way the NOL
641 * update _DOES_ happen - hopefully the failure was just
642 * temporary.
643 */
644 if (!dfs_nol)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530645 return;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530646
Abhijit Pradhan67441612018-01-02 21:46:25 +0530647 DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530648
649 /* Be suitably paranoid for now. */
650 if (nlen != dfs->dfs_nol_count)
Abhijit Pradhan77561582017-10-05 17:47:57 +0530651 dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
652 nlen, dfs->dfs_nol_count);
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530653
654 /*
655 * Call the driver layer to have it recalculate the NOL flags
656 * for each driver/umac channel. If the list is empty, pass
657 * NULL instead of dfs_nol. The operating system may have some
658 * special representation for "malloc a 0 byte memory region"
659 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
660 * than a valid allocation (and is likely not NULL so the
661 * pointer doesn't match NULL checks in any later code.
662 */
663 dfs_mlme_clist_update(dfs->dfs_pdev_obj,
664 (nlen > 0) ? dfs_nol : NULL,
665 nlen);
666
667 qdf_mem_free(dfs_nol);
668}
669
Abhijit Pradhan67441612018-01-02 21:46:25 +0530670void dfs_nol_free_list(struct wlan_dfs *dfs)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530671{
672 struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
673
674 while (nol) {
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530675 prev = nol;
676 nol = nol->nol_next;
677 qdf_mem_free(prev);
678 /* Update the NOL counter. */
679 dfs->dfs_nol_count--;
680
681 if (dfs->dfs_nol_count < 0) {
Abhijit Pradhan77561582017-10-05 17:47:57 +0530682 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0");
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530683 ASSERT(0);
684 }
685 }
Abhijit Pradhan67441612018-01-02 21:46:25 +0530686
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530687 dfs->dfs_nol = NULL;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530688}
689
Vignesh Mohan22200482019-10-14 10:58:17 +0530690#ifdef CONFIG_CHAN_FREQ_API
Abhijit Pradhan67441612018-01-02 21:46:25 +0530691void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
692{
693 struct dfs_nolelem *nol;
Vignesh Mohan22200482019-10-14 10:58:17 +0530694 uint16_t nol_freq;
Abhijit Pradhan67441612018-01-02 21:46:25 +0530695
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530696 while (true) {
Abhijit Pradhan01abdac2018-07-24 18:03:50 +0530697 WLAN_DFSNOL_LOCK(dfs);
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530698
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530699 nol = dfs->dfs_nol;
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530700 if (nol) {
701 dfs->dfs_nol = nol->nol_next;
702 dfs->dfs_nol_count--;
Vignesh Mohan22200482019-10-14 10:58:17 +0530703 nol_freq = nol->nol_freq;
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530704 WLAN_DFSNOL_UNLOCK(dfs);
Vignesh Mohan22200482019-10-14 10:58:17 +0530705 utils_dfs_reg_update_nol_chan_for_freq(
706 dfs->dfs_pdev_obj,
707 &nol_freq,
708 1,
709 DFS_NOL_RESET);
Shashikala Prabhue3807d42018-09-26 12:23:25 +0530710
711 qdf_timer_free(&nol->nol_timer);
712 qdf_mem_free(nol);
713 } else {
714 WLAN_DFSNOL_UNLOCK(dfs);
715 break;
716 }
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530717 }
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530718}
Vignesh Mohan22200482019-10-14 10:58:17 +0530719#else
720#ifdef CONFIG_CHAN_NUM_API
721void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
722{
723 struct dfs_nolelem *nol;
724 uint8_t nol_chan;
725
726 while (true) {
727 WLAN_DFSNOL_LOCK(dfs);
728
729 nol = dfs->dfs_nol;
730 if (nol) {
731 dfs->dfs_nol = nol->nol_next;
732 dfs->dfs_nol_count--;
733 nol_chan = utils_dfs_freq_to_chan(nol->nol_freq);
734 WLAN_DFSNOL_UNLOCK(dfs);
735 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
736 &nol_chan,
737 1,
738 DFS_NOL_RESET);
739
740 qdf_timer_free(&nol->nol_timer);
741 qdf_mem_free(nol);
742 } else {
743 WLAN_DFSNOL_UNLOCK(dfs);
744 break;
745 }
746 }
747}
748#endif
749#endif
Abhijit Pradhan67441612018-01-02 21:46:25 +0530750
Abhijit Pradhanf8e62c02018-01-23 09:47:20 +0530751void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
752{
753 qdf_flush_work(&dfs->dfs_nol_elem_free_work);
Abhijit Pradhan67441612018-01-02 21:46:25 +0530754}
755
Shaakir Mohamed6f35bb02017-09-15 15:52:21 -0700756int dfs_get_use_nol(struct wlan_dfs *dfs)
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530757{
Shaakir Mohamed6f35bb02017-09-15 15:52:21 -0700758 return dfs->dfs_use_nol;
Abhijit Pradhan49f69432017-03-08 17:27:17 +0530759}
760
761int dfs_get_nol_timeout(struct wlan_dfs *dfs)
762{
763 return dfs->wlan_dfs_nol_timeout;
764}
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530765
766void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
767{
768 struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
769
Abhijit Pradhan67441612018-01-02 21:46:25 +0530770 DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530771}
772
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530773#ifdef CONFIG_CHAN_FREQ_API
774void dfs_clear_nolhistory(struct wlan_dfs *dfs)
775{
776 struct dfs_channel *chan_list;
777 int nchans = 0;
778 bool sta_opmode;
779
780 if (!dfs->dfs_is_stadfs_enabled)
781 return;
782
783 sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
784 if (!sta_opmode)
785 return;
786
787 nchans = dfs_get_num_chans();
788
789 chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
790 if (!chan_list)
791 return;
792
793 utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
794 (void *)chan_list, &nchans);
795 if (!nchans) {
796 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
797 qdf_mem_free(chan_list);
798 return;
799 }
800
801 utils_dfs_reg_update_nol_history_chan_for_freq(dfs->dfs_pdev_obj,
802 (void *)chan_list, nchans,
803 DFS_NOL_HISTORY_RESET);
804
805 qdf_mem_free(chan_list);
806}
807#else
808#ifdef CONFIG_CHAN_NUM_API
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530809void dfs_clear_nolhistory(struct wlan_dfs *dfs)
810{
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530811 struct dfs_channel *chan_list;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530812 int nchans = 0;
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530813 bool sta_opmode;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530814
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530815 if (!dfs->dfs_is_stadfs_enabled)
816 return;
817
818 sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
819 if (!sta_opmode)
820 return;
821
822 nchans = dfs_get_num_chans();
823
824 chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
825 if (!chan_list)
826 return;
827
828 utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
829 (void *)chan_list, &nchans);
830 if (!nchans) {
831 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
832 qdf_mem_free(chan_list);
833 return;
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530834 }
Shashikala Prabhu62ce2262018-10-24 08:45:34 +0530835
836 utils_dfs_reg_update_nol_history_ch(dfs->dfs_pdev_obj,
837 (void *)chan_list, nchans,
838 DFS_NOL_HISTORY_RESET);
839
840 qdf_mem_free(chan_list);
Abhijit Pradhanc5152c72017-06-29 13:27:45 +0530841}
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530842#endif
843#endif
Vignesh U8785b9d2018-04-20 22:01:25 +0530844
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530845#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
846 defined(CONFIG_CHAN_FREQ_API)
847void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
848{
849 struct dfs_nolelem *nol;
850 uint16_t freq_list[NUM_CHANNELS_160MHZ];
851 int i, nchans = 0;
852
853 nchans = dfs_get_bonding_channels_for_freq(dfs,
854 &dfs->dfs_radar_found_chan,
855 SEG_ID_PRIMARY,
856 DETECTOR_ID_0,
857 freq_list);
858
859 WLAN_DFSNOL_LOCK(dfs);
860 for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
861 nol = dfs->dfs_nol;
862 while (nol) {
863 if (nol->nol_freq == freq_list[i]) {
864 OS_SET_TIMER(&nol->nol_timer, 0);
865 break;
866 }
867 nol = nol->nol_next;
868 }
869 }
870 WLAN_DFSNOL_UNLOCK(dfs);
871
872 utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
873 freq_list, nchans, DFS_NOL_RESET);
874}
875#else
876#if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
877 defined(CONFIG_CHAN_NUM_API)
Vignesh U8785b9d2018-04-20 22:01:25 +0530878void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
879{
880 struct dfs_nolelem *nol;
881 uint8_t channels[NUM_CHANNELS_160MHZ];
882 int i, nchans = 0;
883
Vignesh Mohan56a6f312019-06-18 14:23:12 +0530884 nchans = dfs_get_bonding_channels(dfs,
885 &dfs->dfs_radar_found_chan,
886 SEG_ID_PRIMARY,
887 DETECTOR_ID_0,
Vignesh U8785b9d2018-04-20 22:01:25 +0530888 channels);
889
890 WLAN_DFSNOL_LOCK(dfs);
891 for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
892 nol = dfs->dfs_nol;
893 while (nol) {
894 if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
895 channels[i])) {
896 OS_SET_TIMER(&nol->nol_timer, 0);
897 break;
898 }
899 nol = nol->nol_next;
900 }
901 }
902 WLAN_DFSNOL_UNLOCK(dfs);
Abhijit Pradhan45098b92018-06-07 16:24:28 +0530903
904 utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
905 channels, nchans, DFS_NOL_RESET);
Vignesh U8785b9d2018-04-20 22:01:25 +0530906}
907#endif
Priyadarshnee S38da66f2019-10-09 14:33:18 +0530908#endif
Vignesh Mohan86eba592019-10-23 17:34:14 +0530909
910void dfs_init_tmp_psoc_nol(struct wlan_dfs *dfs, uint8_t num_radios)
911{
912 struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
913
914 if (WLAN_UMAC_MAX_PDEVS < num_radios) {
915 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
916 "num_radios (%u) exceeds limit", num_radios);
917 return;
918 }
919
920 /* Allocate the temporary psoc NOL copy structure for the number
921 * of radios provided.
922 */
923 dfs_soc_obj->dfs_psoc_nolinfo =
924 qdf_mem_malloc(sizeof(struct dfsreq_nolinfo) * num_radios);
925}
926
927void dfs_deinit_tmp_psoc_nol(struct wlan_dfs *dfs)
928{
929 struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
930
931 if (!dfs_soc_obj->dfs_psoc_nolinfo)
932 return;
933
934 qdf_mem_free(dfs_soc_obj->dfs_psoc_nolinfo);
935 dfs_soc_obj->dfs_psoc_nolinfo = NULL;
936}
937
938void dfs_save_dfs_nol_in_psoc(struct wlan_dfs *dfs,
939 uint8_t pdev_id,
940 uint16_t low_5ghz_freq,
941 uint16_t high_5ghz_freq)
942{
943 struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
944 struct dfsreq_nolinfo tmp_nolinfo, *nolinfo;
945 uint32_t i, num_chans = 0;
946 uint16_t tmp_freq;
947
948 if (!dfs->dfs_nol_count)
949 return;
950
951 if (!dfs_soc_obj->dfs_psoc_nolinfo)
952 return;
953
954 nolinfo = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
955 /* Fetch the NOL entries for the DFS object. */
956 dfs_getnol(dfs, &tmp_nolinfo);
957
958 /* nolinfo might already have some data. Do not overwrite it */
959 num_chans = nolinfo->dfs_ch_nchans;
960 for (i = 0; i < tmp_nolinfo.dfs_ch_nchans; i++) {
961 tmp_freq = tmp_nolinfo.dfs_nol[i].nol_freq;
962
963 /* Add to nolinfo only if within the pdev's frequency range. */
964 if ((low_5ghz_freq < tmp_freq) && (high_5ghz_freq > tmp_freq)) {
965 /* Figure out the completed duration of each NOL. */
966 uint32_t nol_completed_ms =
967 qdf_system_ticks_to_msecs(qdf_system_ticks() -
968 tmp_nolinfo.dfs_nol[i].nol_start_ticks);
969
970 nolinfo->dfs_nol[num_chans] = tmp_nolinfo.dfs_nol[i];
971 /* Remember the remaining NOL time in the timeout
972 * variable.
973 */
974 nolinfo->dfs_nol[num_chans++].nol_timeout_ms -=
975 nol_completed_ms;
976 }
977 }
978
979 nolinfo->dfs_ch_nchans = num_chans;
980}
981
982void dfs_reinit_nol_from_psoc_copy(struct wlan_dfs *dfs, uint8_t pdev_id)
983{
984 struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
985 struct dfsreq_nolinfo *nol;
986 uint8_t i;
987
988 if (!dfs_soc_obj->dfs_psoc_nolinfo)
989 return;
990
991 if (!dfs_soc_obj->dfs_psoc_nolinfo[pdev_id].dfs_ch_nchans)
992 return;
993
994 nol = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
995
996 /* The NOL timeout value in each entry points to the remaining time
997 * of the NOL. This is to indicate that the NOL entries are paused
998 * and are not left to continue.
999 * While adding these NOL, update the start ticks to current time
1000 * to avoid losing entries which might have timed out during
1001 * the pause and resume mechanism.
1002 */
1003 for (i = 0; i < nol->dfs_ch_nchans; i++)
1004 nol->dfs_nol[i].nol_start_ticks = qdf_system_ticks();
1005 dfs_set_nol(dfs, nol->dfs_nol, nol->dfs_ch_nchans);
1006}