xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_nol.c (revision 27d564647e9b50e713c60b0d7e5ea2a9b0a3ae74)
1 /*
2  * Copyright (c) 2016-2018 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_dfs_utils_api.h>
36 #include <wlan_reg_services_api.h>
37 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
38 #include "../dfs_process_radar_found_ind.h"
39 #include "../dfs_partial_offload_radar.h"
40 #endif
41 
42 void dfs_set_update_nol_flag(struct wlan_dfs *dfs, bool val)
43 {
44 	dfs->update_nol = val;
45 }
46 
47 bool dfs_get_update_nol_flag(struct wlan_dfs *dfs)
48 {
49 	return dfs->update_nol;
50 }
51 
52 /**
53  * dfs_nol_timeout() - NOL timeout function.
54  *
55  * Clears the WLAN_CHAN_DFS_RADAR_FOUND flag for the NOL timeout channel.
56  */
57 static os_timer_func(dfs_nol_timeout)
58 {
59 	struct dfs_channel *c = NULL, lc;
60 	unsigned long oldest, now;
61 	struct wlan_dfs *dfs = NULL;
62 	int i;
63 	int nchans = 0;
64 
65 	c = &lc;
66 
67 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
68 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
69 
70 	now = oldest = qdf_system_ticks();
71 	for (i = 0; i < nchans; i++) {
72 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
73 				&(c->dfs_ch_freq),
74 				&(c->dfs_ch_flags),
75 				&(c->dfs_ch_flagext),
76 				&(c->dfs_ch_ieee),
77 				&(c->dfs_ch_vhtop_ch_freq_seg1),
78 				&(c->dfs_ch_vhtop_ch_freq_seg2),
79 				i);
80 		if (WLAN_IS_CHAN_RADAR(c)) {
81 			if (qdf_system_time_after_eq(now,
82 						dfs->dfs_nol_event[i] +
83 						dfs_get_nol_timeout(dfs))) {
84 				c->dfs_ch_flagext &=
85 					~WLAN_CHAN_DFS_RADAR_FOUND;
86 				if (c->dfs_ch_flags &
87 						WLAN_CHAN_DFS_RADAR) {
88 					/*
89 					 * NB: do this here so we get only one
90 					 * msg instead of one for every channel
91 					 * table entry.
92 					 */
93 					dfs_debug(dfs, WLAN_DEBUG_DFS,
94 						"radar on channel %u (%u MHz) cleared after timeout",
95 
96 						c->dfs_ch_ieee,
97 						c->dfs_ch_freq);
98 				}
99 			} else if (dfs->dfs_nol_event[i] < oldest)
100 				oldest = dfs->dfs_nol_event[i];
101 		}
102 	}
103 	if (oldest != now) {
104 		/* Arrange to process next channel up for a status change. */
105 		qdf_timer_mod(&dfs->dfs_nol_timer,
106 				dfs_get_nol_timeout(dfs) -
107 				qdf_system_ticks_to_msecs(qdf_system_ticks()));
108 	}
109 }
110 
111 /**
112  * dfs_nol_elem_free_work_cb -  Free NOL element
113  *
114  * Free the NOL element memory
115  */
116 static void dfs_nol_elem_free_work_cb(void *context)
117 {
118 	struct wlan_dfs *dfs = (struct wlan_dfs *)context;
119 	struct dfs_nolelem *nol_head;
120 
121 	while (true) {
122 		WLAN_DFSNOL_LOCK(dfs);
123 
124 		nol_head = TAILQ_FIRST(&dfs->dfs_nol_free_list);
125 		if (nol_head) {
126 			TAILQ_REMOVE(&dfs->dfs_nol_free_list, nol_head,
127 				     nolelem_list);
128 			WLAN_DFSNOL_UNLOCK(dfs);
129 
130 			qdf_timer_free(&nol_head->nol_timer);
131 			qdf_mem_free(nol_head);
132 		} else {
133 			WLAN_DFSNOL_UNLOCK(dfs);
134 			break;
135 		}
136 	}
137 }
138 
139 void dfs_nol_timer_init(struct wlan_dfs *dfs)
140 {
141 	qdf_timer_init(NULL,
142 			&(dfs->dfs_nol_timer),
143 			dfs_nol_timeout,
144 			(void *)(dfs),
145 			QDF_TIMER_TYPE_WAKE_APPS);
146 }
147 
148 void dfs_nol_attach(struct wlan_dfs *dfs)
149 {
150 	dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
151 	dfs_nol_timer_init(dfs);
152 	qdf_create_work(NULL, &dfs->dfs_nol_elem_free_work,
153 			dfs_nol_elem_free_work_cb, dfs);
154 	TAILQ_INIT(&dfs->dfs_nol_free_list);
155 	dfs->dfs_use_nol = 1;
156 	WLAN_DFSNOL_LOCK_CREATE(dfs);
157 }
158 
159 void dfs_nol_detach(struct wlan_dfs *dfs)
160 {
161 	dfs_nol_timer_cleanup(dfs);
162 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
163 	qdf_destroy_work(NULL, &dfs->dfs_nol_elem_free_work);
164 	WLAN_DFSNOL_LOCK_DESTROY(dfs);
165 }
166 
167 void dfs_nol_timer_detach(struct wlan_dfs *dfs)
168 {
169 	qdf_timer_free(&dfs->dfs_nol_timer);
170 }
171 
172 /**
173  * dfs_nol_delete() - Delete the given frequency/chwidth from the NOL.
174  * @dfs: Pointer to wlan_dfs structure.
175  * @delfreq: Freq to delete.
176  * @delchwidth: Channel width to delete.
177  */
178 static void dfs_nol_delete(struct wlan_dfs *dfs,
179 		uint16_t delfreq,
180 		uint16_t delchwidth)
181 {
182 	struct dfs_nolelem *nol, **prev_next;
183 
184 	if (!dfs) {
185 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
186 		return;
187 	}
188 
189 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
190 		"remove channel=%d/%d MHz from NOL",
191 		 delfreq, delchwidth);
192 	prev_next = &(dfs->dfs_nol);
193 	nol = dfs->dfs_nol;
194 	while (nol != NULL) {
195 		if (nol->nol_freq == delfreq &&
196 			nol->nol_chwidth == delchwidth) {
197 			*prev_next = nol->nol_next;
198 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
199 				"removing channel %d/%dMHz from NOL tstamp=%d",
200 				 nol->nol_freq,
201 				nol->nol_chwidth,
202 				(qdf_system_ticks_to_msecs
203 				 (qdf_system_ticks()) / 1000));
204 			TAILQ_INSERT_TAIL(&dfs->dfs_nol_free_list,
205 						nol, nolelem_list);
206 			nol = *prev_next;
207 
208 			/* Update the NOL counter. */
209 			dfs->dfs_nol_count--;
210 
211 			/* Be paranoid! */
212 			if (dfs->dfs_nol_count < 0) {
213 				dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0; eek!");
214 				dfs->dfs_nol_count = 0;
215 			}
216 
217 		} else {
218 			prev_next = &(nol->nol_next);
219 			nol = nol->nol_next;
220 		}
221 	}
222 }
223 
224 /**
225  * dfs_remove_from_nol() - Remove the freq from NOL list.
226  *
227  * When NOL times out, this function removes the channel from NOL list.
228  */
229 static os_timer_func(dfs_remove_from_nol)
230 {
231 	struct dfs_nolelem *nol_arg;
232 	struct wlan_dfs *dfs;
233 	uint16_t delfreq;
234 	uint16_t delchwidth;
235 	uint8_t chan;
236 
237 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
238 
239 	dfs = nol_arg->nol_dfs;
240 	delfreq = nol_arg->nol_freq;
241 	delchwidth = nol_arg->nol_chwidth;
242 
243 	/* Delete the given NOL entry. */
244 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
245 
246 	/* Update the wireless stack with the new NOL. */
247 	dfs_nol_update(dfs);
248 
249 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
250 	chan = utils_dfs_freq_to_chan(delfreq);
251 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
252 		    "remove channel %d from nol", chan);
253 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
254 				    &chan, 1, DFS_NOL_RESET);
255 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
256 
257 	/*
258 	 * Free the NOL element in a thread. This is to avoid freeing the
259 	 * timer object from within timer callback function . The nol element
260 	 * contains the timer Object.
261 	 */
262 	qdf_sched_work(NULL, &dfs->dfs_nol_elem_free_work);
263 }
264 
265 void dfs_print_nol(struct wlan_dfs *dfs)
266 {
267 	struct dfs_nolelem *nol;
268 	int i = 0;
269 	uint32_t diff_ms, remaining_sec;
270 
271 	if (!dfs) {
272 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
273 		return;
274 	}
275 
276 	nol = dfs->dfs_nol;
277 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
278 	while (nol != NULL) {
279 		diff_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() -
280 				nol->nol_start_ticks);
281 		diff_ms = (nol->nol_timeout_ms - diff_ms);
282 		remaining_sec = diff_ms / 1000; /* Convert to seconds */
283 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
284 			"nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol starttick=%llu",
285 			i++, nol->nol_freq,
286 			nol->nol_chwidth,
287 			remaining_sec,
288 			(uint64_t)nol->nol_start_ticks);
289 		nol = nol->nol_next;
290 	}
291 }
292 
293 void dfs_print_nolhistory(struct wlan_dfs *dfs)
294 {
295 	struct dfs_channel *c, lc;
296 	int i, j = 0;
297 	int nchans = 0;
298 
299 	if (!dfs) {
300 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
301 		return;
302 	}
303 
304 	c = &lc;
305 
306 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
307 	for (i = 0; i < nchans; i++) {
308 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
309 				&(c->dfs_ch_freq),
310 				&(c->dfs_ch_flags),
311 				&(c->dfs_ch_flagext),
312 				&(c->dfs_ch_ieee),
313 				&(c->dfs_ch_vhtop_ch_freq_seg1),
314 				&(c->dfs_ch_vhtop_ch_freq_seg2),
315 				i);
316 		if (WLAN_IS_CHAN_HISTORY_RADAR(c)) {
317 			dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
318 				"nolhistory:%d channel=%d MHz Flags=%llx",
319 				j, c->dfs_ch_freq, c->dfs_ch_flags);
320 			j++;
321 		}
322 	}
323 }
324 
325 void dfs_get_nol(struct wlan_dfs *dfs,
326 		struct dfsreq_nolelem *dfs_nol,
327 		int *nchan)
328 {
329 	struct dfs_nolelem *nol;
330 
331 	*nchan = 0;
332 
333 	if (!dfs) {
334 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
335 		return;
336 	}
337 
338 	nol = dfs->dfs_nol;
339 	while (nol != NULL) {
340 		dfs_nol[*nchan].nol_freq = nol->nol_freq;
341 		dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
342 		dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks;
343 		dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
344 		++(*nchan);
345 		nol = nol->nol_next;
346 	}
347 }
348 
349 void dfs_set_nol(struct wlan_dfs *dfs,
350 		struct dfsreq_nolelem *dfs_nol,
351 		int nchan)
352 {
353 #define TIME_IN_MS 1000
354 	uint32_t nol_time_left_ms;
355 	struct dfs_channel chan;
356 	int i;
357 	uint8_t chan_num;
358 
359 	if (!dfs) {
360 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
361 		return;
362 	}
363 
364 	for (i = 0; i < nchan; i++) {
365 		nol_time_left_ms =
366 			qdf_system_ticks_to_msecs(qdf_system_ticks() -
367 				dfs_nol[i].nol_start_ticks);
368 
369 		if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
370 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
371 			chan.dfs_ch_flags = 0;
372 			chan.dfs_ch_flagext = 0;
373 			nol_time_left_ms =
374 				(dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
375 
376 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
377 					(nol_time_left_ms / TIME_IN_MS));
378 			chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
379 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
380 						&chan_num, 1, DFS_NOL_SET);
381 		}
382 	}
383 #undef TIME_IN_MS
384 	dfs_nol_update(dfs);
385 }
386 
387 void dfs_nol_addchan(struct wlan_dfs *dfs,
388 		uint16_t freq,
389 		uint32_t dfs_nol_timeout)
390 {
391 #define TIME_IN_MS 1000
392 #define TIME_IN_US (TIME_IN_MS * 1000)
393 	struct dfs_nolelem *nol, *elem, *prev;
394 	/* For now, assume all events are 20MHz wide. */
395 	int ch_width = 20;
396 
397 	if (!dfs) {
398 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
399 		return;
400 	}
401 	nol = dfs->dfs_nol;
402 	prev = dfs->dfs_nol;
403 	elem = NULL;
404 	while (nol != NULL) {
405 		if ((nol->nol_freq == freq) &&
406 				(nol->nol_chwidth == ch_width)) {
407 			nol->nol_start_ticks = qdf_system_ticks();
408 			nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
409 
410 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
411 				"Update OS Ticks for NOL %d MHz / %d MHz",
412 				 nol->nol_freq, nol->nol_chwidth);
413 
414 			qdf_timer_stop(&nol->nol_timer);
415 			qdf_timer_mod(&nol->nol_timer,
416 					dfs_nol_timeout * TIME_IN_MS);
417 			return;
418 		}
419 		prev = nol;
420 		nol = nol->nol_next;
421 	}
422 
423 	/* Add a new element to the NOL. */
424 	elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
425 	if (!elem)
426 		goto bad;
427 
428 	qdf_mem_zero(elem, sizeof(*elem));
429 	elem->nol_dfs = dfs;
430 	elem->nol_freq = freq;
431 	elem->nol_chwidth = ch_width;
432 	elem->nol_start_ticks = qdf_system_ticks();
433 	elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
434 	elem->nol_next = NULL;
435 	if (prev) {
436 		prev->nol_next = elem;
437 	} else {
438 		/* This is the first element in the NOL. */
439 		dfs->dfs_nol = elem;
440 	}
441 
442 	qdf_timer_init(NULL,
443 			&elem->nol_timer, dfs_remove_from_nol,
444 			elem, QDF_TIMER_TYPE_WAKE_APPS);
445 	qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
446 
447 	/* Update the NOL counter. */
448 	dfs->dfs_nol_count++;
449 
450 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
451 		"new NOL channel %d MHz / %d MHz",
452 		 elem->nol_freq, elem->nol_chwidth);
453 	return;
454 
455 bad:
456 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
457 		"failed to allocate memory for nol entry");
458 
459 #undef TIME_IN_MS
460 #undef TIME_IN_US
461 }
462 
463 void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
464 		uint32_t *nol_chfreq,
465 		uint32_t *nol_chwidth,
466 		int index)
467 {
468 	if (!dfs_nol)
469 		return;
470 
471 	*nol_chfreq = dfs_nol[index].nol_freq;
472 	*nol_chwidth = dfs_nol[index].nol_chwidth;
473 }
474 
475 void dfs_nol_update(struct wlan_dfs *dfs)
476 {
477 	struct dfsreq_nolelem *dfs_nol;
478 	int nlen;
479 
480 	if (!dfs->dfs_nol_count) {
481 		dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
482 		return;
483 	}
484 
485 	/*
486 	 * Allocate enough entries to store the NOL. At least on Linux
487 	 * (don't ask why), if you allocate a 0 entry array, the
488 	 * returned pointer is 0x10.  Make sure you're aware of this
489 	 * when you start debugging.
490 	 */
491 	dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
492 		sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
493 
494 	if (!dfs_nol) {
495 		/*
496 		 * XXX TODO: if this fails, just schedule a task to retry
497 		 * updating the NOL at a later stage.  That way the NOL
498 		 * update _DOES_ happen - hopefully the failure was just
499 		 * temporary.
500 		 */
501 		dfs_alert(dfs, WLAN_DEBUG_DFS_ALWAYS, "failed to allocate NOL update memory!");
502 		return;
503 	}
504 
505 	DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
506 
507 	/* Be suitably paranoid for now. */
508 	if (nlen != dfs->dfs_nol_count)
509 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
510 			 nlen, dfs->dfs_nol_count);
511 
512 	/*
513 	 * Call the driver layer to have it recalculate the NOL flags
514 	 * for each driver/umac channel. If the list is empty, pass
515 	 * NULL instead of dfs_nol. The operating system may have some
516 	 * special representation for "malloc a 0 byte memory region"
517 	 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
518 	 * than a valid allocation (and is likely not NULL so the
519 	 * pointer doesn't match NULL checks in any later code.
520 	 */
521 	dfs_mlme_clist_update(dfs->dfs_pdev_obj,
522 			(nlen > 0) ? dfs_nol : NULL,
523 			nlen);
524 
525 	qdf_mem_free(dfs_nol);
526 }
527 
528 void dfs_nol_free_list(struct wlan_dfs *dfs)
529 {
530 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
531 
532 	while (nol) {
533 		prev = nol;
534 		nol = nol->nol_next;
535 		qdf_mem_free(prev);
536 		/* Update the NOL counter. */
537 		dfs->dfs_nol_count--;
538 
539 		if (dfs->dfs_nol_count < 0) {
540 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_nol_count < 0");
541 			ASSERT(0);
542 		}
543 	}
544 
545 	dfs->dfs_nol = NULL;
546 }
547 
548 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
549 {
550 	struct dfs_nolelem *nol;
551 
552 	while (true) {
553 		WLAN_DFSNOL_LOCK(dfs);
554 
555 		nol = dfs->dfs_nol;
556 		if (nol) {
557 			dfs->dfs_nol = nol->nol_next;
558 			dfs->dfs_nol_count--;
559 			WLAN_DFSNOL_UNLOCK(dfs);
560 
561 			qdf_timer_free(&nol->nol_timer);
562 			qdf_mem_free(nol);
563 		} else {
564 			WLAN_DFSNOL_UNLOCK(dfs);
565 			break;
566 		}
567 	}
568 }
569 
570 void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
571 {
572 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
573 }
574 
575 int dfs_get_use_nol(struct wlan_dfs *dfs)
576 {
577 	return dfs->dfs_use_nol;
578 }
579 
580 int dfs_get_nol_timeout(struct wlan_dfs *dfs)
581 {
582 	return dfs->wlan_dfs_nol_timeout;
583 }
584 
585 void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
586 {
587 	struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
588 
589 	DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
590 }
591 
592 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
593 {
594 	/* We should have a dfs_clear_nolhistory API from Regdomain. */
595 	struct dfs_channel *c, lc;
596 	int i;
597 	int nchans = 0;
598 
599 	c = &lc;
600 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
601 	for (i = 0; i < nchans; i++) {
602 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
603 				&(c->dfs_ch_freq),
604 				&(c->dfs_ch_flags),
605 				&(c->dfs_ch_flagext),
606 				&(c->dfs_ch_ieee),
607 				&(c->dfs_ch_vhtop_ch_freq_seg1),
608 				&(c->dfs_ch_vhtop_ch_freq_seg2),
609 				i);
610 		WLAN_CHAN_CLR_HISTORY_RADAR(c);
611 	}
612 }
613 
614 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
615 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
616 {
617 	struct dfs_nolelem *nol;
618 	uint8_t channels[NUM_CHANNELS_160MHZ];
619 	int i, nchans = 0;
620 
621 	nchans = dfs_get_bonding_channels(dfs, &dfs->dfs_radar_found_chan, 0,
622 					  channels);
623 
624 	WLAN_DFSNOL_LOCK(dfs);
625 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
626 		nol = dfs->dfs_nol;
627 		while (nol) {
628 			if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
629 				    channels[i])) {
630 				OS_SET_TIMER(&nol->nol_timer, 0);
631 				break;
632 			}
633 			nol = nol->nol_next;
634 		}
635 	}
636 	WLAN_DFSNOL_UNLOCK(dfs);
637 
638 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
639 				    channels, nchans, DFS_NOL_RESET);
640 }
641 #endif
642