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