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