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