xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_nol.c (revision 878d42c770e8f4f39f616b20412de44faeced7b9)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * 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"
31 #include "../dfs_ioctl_private.h"
32 #include "../dfs_internal.h"
33 #include <qdf_time.h>
34 #include <wlan_dfs_mlme_api.h>
35 #include <wlan_objmgr_vdev_obj.h>
36 #include <wlan_dfs_utils_api.h>
37 #include <wlan_reg_services_api.h>
38 #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
42 #include <qdf_types.h>
43 
44 void dfs_set_update_nol_flag(struct wlan_dfs *dfs, bool val)
45 {
46 	dfs->update_nol = val;
47 }
48 
49 bool dfs_get_update_nol_flag(struct wlan_dfs *dfs)
50 {
51 	return dfs->update_nol;
52 }
53 
54 /**
55  * dfs_nol_timeout() - NOL timeout function.
56  *
57  * Clears the WLAN_CHAN_DFS_RADAR_FOUND flag for the NOL timeout channel.
58  */
59 /* Unused function */
60 #ifdef CONFIG_CHAN_FREQ_API
61 static os_timer_func(dfs_nol_timeout)
62 {
63 	struct dfs_channel *c = NULL, lc;
64 	unsigned long oldest, now;
65 	struct wlan_dfs *dfs = NULL;
66 	int i;
67 	int nchans = 0;
68 
69 	c = &lc;
70 
71 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
72 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
73 
74 	now = oldest = qdf_system_ticks();
75 	for (i = 0; i < nchans; i++) {
76 		dfs_mlme_get_dfs_channels_for_freq
77 			(dfs->dfs_pdev_obj,
78 			 &c->dfs_ch_freq,
79 			 &c->dfs_ch_flags,
80 			 &c->dfs_ch_flagext,
81 			 &c->dfs_ch_ieee,
82 			 &c->dfs_ch_vhtop_ch_freq_seg1,
83 			 &c->dfs_ch_vhtop_ch_freq_seg2,
84 			 &c->dfs_ch_mhz_freq_seg1,
85 			 &c->dfs_ch_mhz_freq_seg2,
86 			 i);
87 		if (WLAN_IS_CHAN_RADAR(dfs, c)) {
88 			if (qdf_system_time_after_eq(now,
89 						     dfs->dfs_nol_event[i] +
90 						     dfs_get_nol_timeout(dfs))) {
91 				c->dfs_ch_flagext &= ~WLAN_CHAN_DFS_RADAR_FOUND;
92 				if (c->dfs_ch_flags & WLAN_CHAN_DFS_RADAR) {
93 					/*
94 					 * NB: do this here so we get only one
95 					 * msg instead of one for every channel
96 					 * table entry.
97 					 */
98 					dfs_debug(dfs, WLAN_DEBUG_DFS,
99 						  "radar on channel %u (%u MHz) cleared after timeout",
100 						  c->dfs_ch_ieee,
101 						  c->dfs_ch_freq);
102 				}
103 			} else if (dfs->dfs_nol_event[i] < oldest) {
104 				oldest = dfs->dfs_nol_event[i];
105 			}
106 		}
107 	}
108 	if (oldest != now) {
109 		/* Arrange to process next channel up for a status change. */
110 		qdf_timer_mod(&dfs->dfs_nol_timer,
111 			      dfs_get_nol_timeout(dfs) -
112 			      qdf_system_ticks_to_msecs(qdf_system_ticks()));
113 	}
114 }
115 #else
116 #ifdef CONFIG_CHAN_NUM_API
117 static os_timer_func(dfs_nol_timeout)
118 {
119 	struct dfs_channel *c = NULL, lc;
120 	unsigned long oldest, now;
121 	struct wlan_dfs *dfs = NULL;
122 	int i;
123 	int nchans = 0;
124 
125 	c = &lc;
126 
127 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
128 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
129 
130 	now = oldest = qdf_system_ticks();
131 	for (i = 0; i < nchans; i++) {
132 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
133 				&(c->dfs_ch_freq),
134 				&(c->dfs_ch_flags),
135 				&(c->dfs_ch_flagext),
136 				&(c->dfs_ch_ieee),
137 				&(c->dfs_ch_vhtop_ch_freq_seg1),
138 				&(c->dfs_ch_vhtop_ch_freq_seg2),
139 				i);
140 		if (WLAN_IS_CHAN_RADAR(dfs, c)) {
141 			if (qdf_system_time_after_eq(now,
142 						dfs->dfs_nol_event[i] +
143 						dfs_get_nol_timeout(dfs))) {
144 				c->dfs_ch_flagext &=
145 					~WLAN_CHAN_DFS_RADAR_FOUND;
146 				if (c->dfs_ch_flags &
147 						WLAN_CHAN_DFS_RADAR) {
148 					/*
149 					 * NB: do this here so we get only one
150 					 * msg instead of one for every channel
151 					 * table entry.
152 					 */
153 					dfs_debug(dfs, WLAN_DEBUG_DFS,
154 						"radar on channel %u (%u MHz) cleared after timeout",
155 
156 						c->dfs_ch_ieee,
157 						c->dfs_ch_freq);
158 				}
159 			} else if (dfs->dfs_nol_event[i] < oldest)
160 				oldest = dfs->dfs_nol_event[i];
161 		}
162 	}
163 	if (oldest != now) {
164 		/* Arrange to process next channel up for a status change. */
165 		qdf_timer_mod(&dfs->dfs_nol_timer,
166 				dfs_get_nol_timeout(dfs) -
167 				qdf_system_ticks_to_msecs(qdf_system_ticks()));
168 	}
169 }
170 #endif
171 #endif
172 
173 /**
174  * dfs_nol_elem_free_work_cb -  Free NOL element
175  *
176  * Free the NOL element memory
177  */
178 static void dfs_nol_elem_free_work_cb(void *context)
179 {
180 	struct wlan_dfs *dfs = (struct wlan_dfs *)context;
181 	struct dfs_nolelem *nol_head;
182 
183 	while (true) {
184 		WLAN_DFSNOL_LOCK(dfs);
185 
186 		nol_head = TAILQ_FIRST(&dfs->dfs_nol_free_list);
187 		if (nol_head) {
188 			TAILQ_REMOVE(&dfs->dfs_nol_free_list, nol_head,
189 				     nolelem_list);
190 			WLAN_DFSNOL_UNLOCK(dfs);
191 
192 			qdf_timer_free(&nol_head->nol_timer);
193 			qdf_mem_free(nol_head);
194 		} else {
195 			WLAN_DFSNOL_UNLOCK(dfs);
196 			break;
197 		}
198 	}
199 }
200 
201 void dfs_nol_timer_init(struct wlan_dfs *dfs)
202 {
203 	qdf_timer_init(NULL,
204 			&(dfs->dfs_nol_timer),
205 			dfs_nol_timeout,
206 			(void *)(dfs),
207 			QDF_TIMER_TYPE_WAKE_APPS);
208 }
209 
210 void dfs_nol_attach(struct wlan_dfs *dfs)
211 {
212 	dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
213 	dfs_nol_timer_init(dfs);
214 	qdf_create_work(NULL, &dfs->dfs_nol_elem_free_work,
215 			dfs_nol_elem_free_work_cb, dfs);
216 	TAILQ_INIT(&dfs->dfs_nol_free_list);
217 	dfs->dfs_use_nol = 1;
218 	WLAN_DFSNOL_LOCK_CREATE(dfs);
219 }
220 
221 void dfs_nol_detach(struct wlan_dfs *dfs)
222 {
223 	dfs_nol_timer_cleanup(dfs);
224 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
225 	qdf_destroy_work(NULL, &dfs->dfs_nol_elem_free_work);
226 	WLAN_DFSNOL_LOCK_DESTROY(dfs);
227 }
228 
229 void dfs_nol_timer_detach(struct wlan_dfs *dfs)
230 {
231 	qdf_timer_free(&dfs->dfs_nol_timer);
232 }
233 
234 /**
235  * dfs_nol_delete() - Delete the given frequency/chwidth from the NOL.
236  * @dfs: Pointer to wlan_dfs structure.
237  * @delfreq: Freq to delete.
238  * @delchwidth: Channel width to delete.
239  */
240 static void dfs_nol_delete(struct wlan_dfs *dfs,
241 		uint16_t delfreq,
242 		uint16_t delchwidth)
243 {
244 	struct dfs_nolelem *nol, **prev_next;
245 
246 	if (!dfs) {
247 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
248 		return;
249 	}
250 
251 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
252 		"remove channel=%d/%d MHz from NOL",
253 		 delfreq, delchwidth);
254 	prev_next = &(dfs->dfs_nol);
255 	nol = dfs->dfs_nol;
256 	while (nol) {
257 		if (nol->nol_freq == delfreq &&
258 			nol->nol_chwidth == delchwidth) {
259 			*prev_next = nol->nol_next;
260 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
261 				"removing channel %d/%dMHz from NOL tstamp=%d",
262 				 nol->nol_freq,
263 				nol->nol_chwidth,
264 				(qdf_system_ticks_to_msecs
265 				 (qdf_system_ticks()) / 1000));
266 			TAILQ_INSERT_TAIL(&dfs->dfs_nol_free_list,
267 						nol, nolelem_list);
268 			nol = *prev_next;
269 
270 			/* Update the NOL counter. */
271 			dfs->dfs_nol_count--;
272 
273 			/* Be paranoid! */
274 			if (dfs->dfs_nol_count < 0) {
275 				dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0; eek!");
276 				dfs->dfs_nol_count = 0;
277 			}
278 
279 		} else {
280 			prev_next = &(nol->nol_next);
281 			nol = nol->nol_next;
282 		}
283 	}
284 }
285 
286 /**
287  * dfs_remove_from_nol() - Remove the freq from NOL list.
288  *
289  * When NOL times out, this function removes the channel from NOL list.
290  */
291 #ifdef CONFIG_CHAN_FREQ_API
292 static os_timer_func(dfs_remove_from_nol)
293 {
294 	struct dfs_nolelem *nol_arg;
295 	struct wlan_dfs *dfs;
296 	uint16_t delfreq;
297 	uint16_t delchwidth;
298 	uint8_t chan;
299 
300 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
301 
302 	dfs = nol_arg->nol_dfs;
303 	delfreq = nol_arg->nol_freq;
304 	delchwidth = nol_arg->nol_chwidth;
305 
306 	/* Delete the given NOL entry. */
307 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
308 
309 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
310 					       &delfreq, 1, DFS_NOL_RESET);
311 	/* Update the wireless stack with the new NOL. */
312 	dfs_nol_update(dfs);
313 
314 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
315 	chan = utils_dfs_freq_to_chan(delfreq);
316 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
317 				WLAN_EV_NOL_FINISHED);
318 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
319 		  "remove channel %d from nol", chan);
320 	utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
321 
322 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
323 
324 	/*
325 	 * Check if a channel is configured by the user to which we have to
326 	 * switch after it's NOL expiry. If that is the case, change
327 	 * channel immediately.
328 	 *
329 	 * If a channel switch is required (indicated by the return value of
330 	 * dfs_switch_to_postnol_chan_if_nol_expired), return from this function
331 	 * without posting Start event to Agile SM. That will be taken care
332 	 * of, after VAP start.
333 	 */
334 	if (dfs_switch_to_postnol_chan_if_nol_expired(dfs))
335 		return;
336 
337 	/* In case of interCAC feature, check if the user configured
338 	 * desired channel is RCAC done or not.
339 	 * (AP operating on an intermediate channel as desired channel
340 	 * is still not CAC done). If the RCAC of the desired channel
341 	 * was interrupted by radar, initiate RCAC on NOL expiry
342 	 * of the channel.
343 	 *
344 	 * If rcac is not started by dfs_restart_rcac_on_nol_expiry() API,
345 	 * initiate rcac start here.
346 	 */
347 	if (!dfs_restart_rcac_on_nol_expiry(dfs))
348 		utils_dfs_agile_sm_deliver_evt(dfs->dfs_pdev_obj,
349 					       DFS_AGILE_SM_EV_AGILE_START);
350 }
351 #else
352 #ifdef CONFIG_CHAN_NUM_API
353 static os_timer_func(dfs_remove_from_nol)
354 {
355 	struct dfs_nolelem *nol_arg;
356 	struct wlan_dfs *dfs;
357 	uint16_t delfreq;
358 	uint16_t delchwidth;
359 	uint8_t chan;
360 
361 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
362 
363 	dfs = nol_arg->nol_dfs;
364 	delfreq = nol_arg->nol_freq;
365 	delchwidth = nol_arg->nol_chwidth;
366 
367 	/* Delete the given NOL entry. */
368 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
369 
370 	/* Update the wireless stack with the new NOL. */
371 	dfs_nol_update(dfs);
372 
373 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
374 	chan = utils_dfs_freq_to_chan(delfreq);
375 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
376 				WLAN_EV_NOL_FINISHED);
377 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
378 		    "remove channel %d from nol", chan);
379 	utils_dfs_unmark_precac_nol(dfs->dfs_pdev_obj, chan);
380 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
381 				    &chan, 1, DFS_NOL_RESET);
382 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
383 }
384 #endif
385 #endif
386 
387 void dfs_print_nol(struct wlan_dfs *dfs)
388 {
389 	struct dfs_nolelem *nol;
390 	int i = 0;
391 	uint32_t diff_ms, remaining_sec;
392 
393 	if (!dfs) {
394 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
395 		return;
396 	}
397 
398 	nol = dfs->dfs_nol;
399 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
400 	while (nol) {
401 		diff_ms = qdf_do_div(qdf_get_monotonic_boottime() -
402 				     nol->nol_start_us, 1000);
403 		diff_ms = (nol->nol_timeout_ms - diff_ms);
404 		remaining_sec = diff_ms / 1000; /* Convert to seconds */
405 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
406 			"nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol start_us=%llu",
407 			i++, nol->nol_freq,
408 			nol->nol_chwidth,
409 			remaining_sec,
410 			nol->nol_start_us);
411 		nol = nol->nol_next;
412 	}
413 }
414 
415 void dfs_print_nolhistory(struct wlan_dfs *dfs)
416 {
417 	struct dfs_channel *chan_list;
418 	int i, j;
419 	int nchans;
420 
421 	if (!dfs) {
422 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
423 		return;
424 	}
425 
426 	nchans = dfs_get_num_chans();
427 
428 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
429 	if (!chan_list)
430 		return;
431 
432 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
433 					    (void *)chan_list, &nchans);
434 	if (!nchans) {
435 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
436 		qdf_mem_free(chan_list);
437 		return;
438 	}
439 
440 	for (i = 0, j = 0; i < nchans; i++, j++)
441 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
442 			 "nolhistory = %d channel = %d MHz",
443 			 j, chan_list[i].dfs_ch_freq);
444 
445 	qdf_mem_free(chan_list);
446 }
447 
448 void dfs_get_nol(struct wlan_dfs *dfs,
449 		struct dfsreq_nolelem *dfs_nol,
450 		int *nchan)
451 {
452 	struct dfs_nolelem *nol;
453 
454 	*nchan = 0;
455 
456 	if (!dfs) {
457 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
458 		return;
459 	}
460 
461 	nol = dfs->dfs_nol;
462 	while (nol) {
463 		dfs_nol[*nchan].nol_freq = nol->nol_freq;
464 		dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
465 		dfs_nol[*nchan].nol_start_us = nol->nol_start_us;
466 		dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
467 		++(*nchan);
468 		nol = nol->nol_next;
469 	}
470 }
471 
472 #ifdef CONFIG_CHAN_FREQ_API
473 void dfs_set_nol(struct wlan_dfs *dfs,
474 		 struct dfsreq_nolelem *dfs_nol,
475 		 int nchan)
476 {
477 #define TIME_IN_MS 1000
478 	uint32_t nol_time_lft_ms;
479 	struct dfs_channel chan;
480 	int i;
481 
482 	if (!dfs) {
483 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
484 		return;
485 	}
486 
487 	for (i = 0; i < nchan; i++) {
488 		nol_time_lft_ms = qdf_do_div(qdf_get_monotonic_boottime() -
489 					     dfs_nol[i].nol_start_us, 1000);
490 
491 		if (nol_time_lft_ms < dfs_nol[i].nol_timeout_ms) {
492 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
493 			chan.dfs_ch_flags = 0;
494 			chan.dfs_ch_flagext = 0;
495 			nol_time_lft_ms =
496 				(dfs_nol[i].nol_timeout_ms - nol_time_lft_ms);
497 
498 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
499 						(nol_time_lft_ms / TIME_IN_MS));
500 			utils_dfs_reg_update_nol_chan_for_freq(
501 						dfs->dfs_pdev_obj,
502 						&chan.dfs_ch_freq,
503 						1, DFS_NOL_SET);
504 		}
505 	}
506 #undef TIME_IN_MS
507 	dfs_nol_update(dfs);
508 }
509 #else
510 #ifdef CONFIG_CHAN_NUM_API
511 void dfs_set_nol(struct wlan_dfs *dfs,
512 		 struct dfsreq_nolelem *dfs_nol,
513 		 int nchan)
514 {
515 #define TIME_IN_MS 1000
516 	uint32_t nol_time_lft_ms;
517 	struct dfs_channel chan;
518 	int i;
519 	uint8_t chan_num;
520 
521 	if (!dfs) {
522 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
523 		return;
524 	}
525 
526 	for (i = 0; i < nchan; i++) {
527 		nol_time_lft_ms = qdf_do_div(qdf_get_monotonic_boottime() -
528 					      dfs_nol[i].nol_start_us, 1000);
529 
530 		if (nol_time_lft_ms < dfs_nol[i].nol_timeout_ms) {
531 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
532 			chan.dfs_ch_flags = 0;
533 			chan.dfs_ch_flagext = 0;
534 			nol_time_lft_ms =
535 				(dfs_nol[i].nol_timeout_ms - nol_time_lft_ms);
536 
537 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
538 						(nol_time_lft_ms / TIME_IN_MS));
539 			chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
540 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
541 						    &chan_num, 1, DFS_NOL_SET);
542 		}
543 	}
544 #undef TIME_IN_MS
545 	dfs_nol_update(dfs);
546 }
547 #endif
548 #endif
549 
550 void dfs_nol_addchan(struct wlan_dfs *dfs,
551 		uint16_t freq,
552 		uint32_t dfs_nol_timeout)
553 {
554 #define TIME_IN_MS 1000
555 #define TIME_IN_US (TIME_IN_MS * 1000)
556 	struct dfs_nolelem *nol, *elem, *prev;
557 	/* For now, assume all events are 20MHz wide. */
558 	int ch_width = 20;
559 
560 	if (!dfs) {
561 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
562 		return;
563 	}
564 	nol = dfs->dfs_nol;
565 	prev = dfs->dfs_nol;
566 	elem = NULL;
567 	while (nol) {
568 		if ((nol->nol_freq == freq) &&
569 				(nol->nol_chwidth == ch_width)) {
570 			nol->nol_start_us = qdf_get_monotonic_boottime();
571 			nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
572 
573 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
574 				"Update OS Ticks for NOL %d MHz / %d MHz",
575 				 nol->nol_freq, nol->nol_chwidth);
576 
577 			qdf_timer_stop(&nol->nol_timer);
578 			qdf_timer_mod(&nol->nol_timer,
579 					dfs_nol_timeout * TIME_IN_MS);
580 			return;
581 		}
582 		prev = nol;
583 		nol = nol->nol_next;
584 	}
585 
586 	/* Add a new element to the NOL. */
587 	elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
588 	if (!elem)
589 		goto bad;
590 
591 	qdf_mem_zero(elem, sizeof(*elem));
592 	elem->nol_dfs = dfs;
593 	elem->nol_freq = freq;
594 	elem->nol_chwidth = ch_width;
595 	elem->nol_start_us = qdf_get_monotonic_boottime();
596 	elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
597 	elem->nol_next = NULL;
598 	if (prev) {
599 		prev->nol_next = elem;
600 	} else {
601 		/* This is the first element in the NOL. */
602 		dfs->dfs_nol = elem;
603 	}
604 
605 	qdf_timer_init(NULL,
606 		       &elem->nol_timer, dfs_remove_from_nol,
607 		       elem, QDF_TIMER_TYPE_WAKE_APPS);
608 
609 	qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
610 
611 	/* Update the NOL counter. */
612 	dfs->dfs_nol_count++;
613 
614 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
615 		"new NOL channel %d MHz / %d MHz",
616 		 elem->nol_freq, elem->nol_chwidth);
617 	return;
618 
619 bad:
620 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
621 		"failed to allocate memory for nol entry");
622 
623 #undef TIME_IN_MS
624 #undef TIME_IN_US
625 }
626 
627 void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
628 		uint32_t *nol_chfreq,
629 		uint32_t *nol_chwidth,
630 		int index)
631 {
632 	if (!dfs_nol)
633 		return;
634 
635 	*nol_chfreq = dfs_nol[index].nol_freq;
636 	*nol_chwidth = dfs_nol[index].nol_chwidth;
637 }
638 
639 void dfs_nol_update(struct wlan_dfs *dfs)
640 {
641 	struct dfsreq_nolelem *dfs_nol;
642 	int nlen;
643 
644 	if (!dfs->dfs_nol_count) {
645 		dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
646 		dfs_mlme_clist_update(dfs->dfs_pdev_obj, NULL, 0);
647 		return;
648 	}
649 
650 	/*
651 	 * Allocate enough entries to store the NOL. At least on Linux
652 	 * (don't ask why), if you allocate a 0 entry array, the
653 	 * returned pointer is 0x10.  Make sure you're aware of this
654 	 * when you start debugging.
655 	 */
656 	dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
657 		sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
658 
659 	/*
660 	 * XXX TODO: if this fails, just schedule a task to retry
661 	 * updating the NOL at a later stage.  That way the NOL
662 	 * update _DOES_ happen - hopefully the failure was just
663 	 * temporary.
664 	 */
665 	if (!dfs_nol)
666 		return;
667 
668 	DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
669 
670 	/* Be suitably paranoid for now. */
671 	if (nlen != dfs->dfs_nol_count)
672 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
673 			 nlen, dfs->dfs_nol_count);
674 
675 	/*
676 	 * Call the driver layer to have it recalculate the NOL flags
677 	 * for each driver/umac channel. If the list is empty, pass
678 	 * NULL instead of dfs_nol. The operating system may have some
679 	 * special representation for "malloc a 0 byte memory region"
680 	 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
681 	 * than a valid allocation (and is likely not NULL so the
682 	 * pointer doesn't match NULL checks in any later code.
683 	 */
684 	dfs_mlme_clist_update(dfs->dfs_pdev_obj,
685 			(nlen > 0) ? dfs_nol : NULL,
686 			nlen);
687 
688 	qdf_mem_free(dfs_nol);
689 }
690 
691 void dfs_nol_free_list(struct wlan_dfs *dfs)
692 {
693 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
694 
695 	while (nol) {
696 		prev = nol;
697 		nol = nol->nol_next;
698 		qdf_mem_free(prev);
699 		/* Update the NOL counter. */
700 		dfs->dfs_nol_count--;
701 
702 		if (dfs->dfs_nol_count < 0) {
703 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_nol_count < 0");
704 			ASSERT(0);
705 		}
706 	}
707 
708 	dfs->dfs_nol = NULL;
709 }
710 
711 #ifdef CONFIG_CHAN_FREQ_API
712 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
713 {
714 	struct dfs_nolelem *nol;
715 	uint16_t nol_freq;
716 
717 	while (true) {
718 		WLAN_DFSNOL_LOCK(dfs);
719 
720 		nol = dfs->dfs_nol;
721 		if (nol) {
722 			dfs->dfs_nol = nol->nol_next;
723 			dfs->dfs_nol_count--;
724 			nol_freq = nol->nol_freq;
725 			WLAN_DFSNOL_UNLOCK(dfs);
726 			utils_dfs_reg_update_nol_chan_for_freq(
727 					dfs->dfs_pdev_obj,
728 					&nol_freq,
729 					1,
730 					DFS_NOL_RESET);
731 
732 			qdf_timer_free(&nol->nol_timer);
733 			qdf_mem_free(nol);
734 		} else {
735 			WLAN_DFSNOL_UNLOCK(dfs);
736 			break;
737 		}
738 	}
739 }
740 #else
741 #ifdef CONFIG_CHAN_NUM_API
742 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
743 {
744 	struct dfs_nolelem *nol;
745 	uint8_t nol_chan;
746 
747 	while (true) {
748 		WLAN_DFSNOL_LOCK(dfs);
749 
750 		nol = dfs->dfs_nol;
751 		if (nol) {
752 			dfs->dfs_nol = nol->nol_next;
753 			dfs->dfs_nol_count--;
754 			nol_chan = utils_dfs_freq_to_chan(nol->nol_freq);
755 			WLAN_DFSNOL_UNLOCK(dfs);
756 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
757 						    &nol_chan,
758 						    1,
759 						    DFS_NOL_RESET);
760 
761 			qdf_timer_free(&nol->nol_timer);
762 			qdf_mem_free(nol);
763 		} else {
764 			WLAN_DFSNOL_UNLOCK(dfs);
765 			break;
766 		}
767 	}
768 }
769 #endif
770 #endif
771 
772 void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
773 {
774 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
775 }
776 
777 int dfs_get_use_nol(struct wlan_dfs *dfs)
778 {
779 	return dfs->dfs_use_nol;
780 }
781 
782 int dfs_get_nol_timeout(struct wlan_dfs *dfs)
783 {
784 	return dfs->wlan_dfs_nol_timeout;
785 }
786 
787 void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
788 {
789 	struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
790 
791 	DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
792 }
793 
794 #if !defined(QCA_MCL_DFS_SUPPORT)
795 #ifdef CONFIG_CHAN_FREQ_API
796 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
797 {
798 	struct dfs_channel *chan_list;
799 	int nchans;
800 	bool sta_opmode;
801 	int i;
802 	qdf_freq_t *nol_freq_list = NULL;
803 	int num_nol_history_chans;
804 
805 	if (!dfs->dfs_is_stadfs_enabled)
806 		return;
807 
808 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
809 	if (!sta_opmode)
810 		return;
811 
812 	nchans = dfs_get_num_chans();
813 
814 	if (!nchans) {
815 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
816 		return;
817 	}
818 
819 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
820 	if (!chan_list)
821 		return;
822 
823 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
824 					    (void *)chan_list,
825 					    &num_nol_history_chans);
826 
827 	if (!num_nol_history_chans) {
828 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
829 		qdf_mem_free(chan_list);
830 		return;
831 	}
832 
833 	if (num_nol_history_chans > nchans)
834 		num_nol_history_chans = nchans;
835 
836 	nol_freq_list =
837 		qdf_mem_malloc(num_nol_history_chans * sizeof(qdf_freq_t));
838 
839 	if (!nol_freq_list) {
840 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unable to alloc memory for freq list");
841 		qdf_mem_free(chan_list);
842 		return;
843 	}
844 
845 	for (i = 0; i < num_nol_history_chans; i++)
846 		nol_freq_list[i] = chan_list[i].dfs_ch_freq;
847 
848 	utils_dfs_reg_update_nol_history_chan_for_freq(dfs->dfs_pdev_obj,
849 						       nol_freq_list,
850 						       num_nol_history_chans,
851 						       DFS_NOL_HISTORY_RESET);
852 	qdf_mem_free(chan_list);
853 	qdf_mem_free(nol_freq_list);
854 }
855 #else
856 #ifdef CONFIG_CHAN_NUM_API
857 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
858 {
859 	struct dfs_channel *chan_list;
860 	int nchans;
861 	bool sta_opmode;
862 	int i;
863 	uint8_t *nol_chan_ieee_list = NULL;
864 	int num_nol_history_chans;
865 
866 	if (!dfs->dfs_is_stadfs_enabled)
867 		return;
868 
869 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
870 	if (!sta_opmode)
871 		return;
872 
873 	nchans = dfs_get_num_chans();
874 
875 	if (!nchans) {
876 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
877 		return;
878 	}
879 
880 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
881 	if (!chan_list)
882 		return;
883 
884 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
885 					    (void *)chan_list,
886 					    &num_nol_history_chans);
887 
888 	if (!num_nol_history_chans) {
889 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
890 		qdf_mem_free(chan_list);
891 		return;
892 	}
893 
894 	if (num_nol_history_chans > nchans)
895 		num_nol_history_chans = nchans;
896 
897 	nol_chan_ieee_list =
898 		qdf_mem_malloc(num_nol_history_chans * sizeof(uint8_t));
899 
900 	if (!nol_chan_ieee_list) {
901 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unable to alloc memory for ieee list");
902 		qdf_mem_free(chan_list);
903 		return;
904 	}
905 
906 	for (i = 0; i < num_nol_history_chans; i++)
907 		nol_chan_ieee_list[i] = chan_list[i].dfs_ch_ieee;
908 
909 	utils_dfs_reg_update_nol_history_ch(dfs->dfs_pdev_obj,
910 					    nol_chan_ieee_list,
911 					    num_nol_history_chans,
912 					    DFS_NOL_HISTORY_RESET);
913 
914 	qdf_mem_free(chan_list);
915 	qdf_mem_free(nol_chan_ieee_list);
916 }
917 #endif
918 #endif
919 #endif
920 
921 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
922 	defined(CONFIG_CHAN_FREQ_API)
923 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
924 {
925 	struct dfs_nolelem *nol;
926 	uint16_t freq_list[NUM_CHANNELS_160MHZ];
927 	int i, nchans = 0;
928 
929 	nchans = dfs_get_bonding_channels_for_freq(dfs,
930 						   &dfs->dfs_radar_found_chan,
931 						   SEG_ID_PRIMARY,
932 						   DETECTOR_ID_0,
933 						   freq_list);
934 
935 	WLAN_DFSNOL_LOCK(dfs);
936 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
937 		nol = dfs->dfs_nol;
938 		while (nol) {
939 			if (nol->nol_freq == freq_list[i]) {
940 				OS_SET_TIMER(&nol->nol_timer, 0);
941 				break;
942 			}
943 			nol = nol->nol_next;
944 		}
945 	}
946 	WLAN_DFSNOL_UNLOCK(dfs);
947 
948 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
949 					     freq_list, nchans, DFS_NOL_RESET);
950 }
951 #else
952 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
953 	defined(CONFIG_CHAN_NUM_API)
954 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
955 {
956 	struct dfs_nolelem *nol;
957 	uint8_t channels[NUM_CHANNELS_160MHZ];
958 	int i, nchans = 0;
959 
960 	nchans = dfs_get_bonding_channels(dfs,
961 					  &dfs->dfs_radar_found_chan,
962 					  SEG_ID_PRIMARY,
963 					  DETECTOR_ID_0,
964 					  channels);
965 
966 	WLAN_DFSNOL_LOCK(dfs);
967 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
968 		nol = dfs->dfs_nol;
969 		while (nol) {
970 			if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
971 				    channels[i])) {
972 				OS_SET_TIMER(&nol->nol_timer, 0);
973 				break;
974 			}
975 			nol = nol->nol_next;
976 		}
977 	}
978 	WLAN_DFSNOL_UNLOCK(dfs);
979 
980 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
981 				    channels, nchans, DFS_NOL_RESET);
982 }
983 #endif
984 #endif
985