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