xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_nol.c (revision dd4dc88b837a295134aa9869114a2efee0f4894b)
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) {
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 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
253 				WLAN_EV_NOL_FINISHED);
254 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
255 		    "remove channel %d from nol", chan);
256 	utils_dfs_add_to_etsi_precac_required_list(dfs->dfs_pdev_obj,
257 						   &chan);
258 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
259 				    &chan, 1, DFS_NOL_RESET);
260 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
261 }
262 
263 void dfs_print_nol(struct wlan_dfs *dfs)
264 {
265 	struct dfs_nolelem *nol;
266 	int i = 0;
267 	uint32_t diff_ms, remaining_sec;
268 
269 	if (!dfs) {
270 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
271 		return;
272 	}
273 
274 	nol = dfs->dfs_nol;
275 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
276 	while (nol) {
277 		diff_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() -
278 				nol->nol_start_ticks);
279 		diff_ms = (nol->nol_timeout_ms - diff_ms);
280 		remaining_sec = diff_ms / 1000; /* Convert to seconds */
281 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
282 			"nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol starttick=%llu",
283 			i++, nol->nol_freq,
284 			nol->nol_chwidth,
285 			remaining_sec,
286 			(uint64_t)nol->nol_start_ticks);
287 		nol = nol->nol_next;
288 	}
289 }
290 
291 void dfs_print_nolhistory(struct wlan_dfs *dfs)
292 {
293 	struct dfs_channel *chan_list;
294 	int i, j;
295 	int nchans;
296 
297 	if (!dfs) {
298 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
299 		return;
300 	}
301 
302 	nchans = dfs_get_num_chans();
303 
304 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
305 	if (!chan_list)
306 		return;
307 
308 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
309 					    (void *)chan_list, &nchans);
310 	if (!nchans) {
311 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
312 		qdf_mem_free(chan_list);
313 		return;
314 	}
315 
316 	for (i = 0, j = 0; i < nchans; i++, j++)
317 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
318 			 "nolhistory = %d channel = %d MHz",
319 			 j, chan_list[i].dfs_ch_freq);
320 
321 	qdf_mem_free(chan_list);
322 }
323 
324 void dfs_get_nol(struct wlan_dfs *dfs,
325 		struct dfsreq_nolelem *dfs_nol,
326 		int *nchan)
327 {
328 	struct dfs_nolelem *nol;
329 
330 	*nchan = 0;
331 
332 	if (!dfs) {
333 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
334 		return;
335 	}
336 
337 	nol = dfs->dfs_nol;
338 	while (nol) {
339 		dfs_nol[*nchan].nol_freq = nol->nol_freq;
340 		dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
341 		dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks;
342 		dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
343 		++(*nchan);
344 		nol = nol->nol_next;
345 	}
346 }
347 
348 void dfs_set_nol(struct wlan_dfs *dfs,
349 		struct dfsreq_nolelem *dfs_nol,
350 		int nchan)
351 {
352 #define TIME_IN_MS 1000
353 	uint32_t nol_time_left_ms;
354 	struct dfs_channel chan;
355 	int i;
356 	uint8_t chan_num;
357 
358 	if (!dfs) {
359 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
360 		return;
361 	}
362 
363 	for (i = 0; i < nchan; i++) {
364 		nol_time_left_ms =
365 			qdf_system_ticks_to_msecs(qdf_system_ticks() -
366 				dfs_nol[i].nol_start_ticks);
367 
368 		if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
369 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
370 			chan.dfs_ch_flags = 0;
371 			chan.dfs_ch_flagext = 0;
372 			nol_time_left_ms =
373 				(dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
374 
375 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
376 					(nol_time_left_ms / TIME_IN_MS));
377 			chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
378 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
379 						&chan_num, 1, DFS_NOL_SET);
380 		}
381 	}
382 #undef TIME_IN_MS
383 	dfs_nol_update(dfs);
384 }
385 
386 void dfs_nol_addchan(struct wlan_dfs *dfs,
387 		uint16_t freq,
388 		uint32_t dfs_nol_timeout)
389 {
390 #define TIME_IN_MS 1000
391 #define TIME_IN_US (TIME_IN_MS * 1000)
392 	struct dfs_nolelem *nol, *elem, *prev;
393 	/* For now, assume all events are 20MHz wide. */
394 	int ch_width = 20;
395 
396 	if (!dfs) {
397 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
398 		return;
399 	}
400 	nol = dfs->dfs_nol;
401 	prev = dfs->dfs_nol;
402 	elem = NULL;
403 	while (nol) {
404 		if ((nol->nol_freq == freq) &&
405 				(nol->nol_chwidth == ch_width)) {
406 			nol->nol_start_ticks = qdf_system_ticks();
407 			nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
408 
409 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
410 				"Update OS Ticks for NOL %d MHz / %d MHz",
411 				 nol->nol_freq, nol->nol_chwidth);
412 
413 			qdf_timer_stop(&nol->nol_timer);
414 			qdf_timer_mod(&nol->nol_timer,
415 					dfs_nol_timeout * TIME_IN_MS);
416 			return;
417 		}
418 		prev = nol;
419 		nol = nol->nol_next;
420 	}
421 
422 	/* Add a new element to the NOL. */
423 	elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
424 	if (!elem)
425 		goto bad;
426 
427 	qdf_mem_zero(elem, sizeof(*elem));
428 	elem->nol_dfs = dfs;
429 	elem->nol_freq = freq;
430 	elem->nol_chwidth = ch_width;
431 	elem->nol_start_ticks = qdf_system_ticks();
432 	elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
433 	elem->nol_next = NULL;
434 	if (prev) {
435 		prev->nol_next = elem;
436 	} else {
437 		/* This is the first element in the NOL. */
438 		dfs->dfs_nol = elem;
439 	}
440 
441 	qdf_timer_init(NULL,
442 			&elem->nol_timer, dfs_remove_from_nol,
443 			elem, QDF_TIMER_TYPE_WAKE_APPS);
444 	qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
445 
446 	/* Update the NOL counter. */
447 	dfs->dfs_nol_count++;
448 
449 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
450 		"new NOL channel %d MHz / %d MHz",
451 		 elem->nol_freq, elem->nol_chwidth);
452 	return;
453 
454 bad:
455 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
456 		"failed to allocate memory for nol entry");
457 
458 #undef TIME_IN_MS
459 #undef TIME_IN_US
460 }
461 
462 void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
463 		uint32_t *nol_chfreq,
464 		uint32_t *nol_chwidth,
465 		int index)
466 {
467 	if (!dfs_nol)
468 		return;
469 
470 	*nol_chfreq = dfs_nol[index].nol_freq;
471 	*nol_chwidth = dfs_nol[index].nol_chwidth;
472 }
473 
474 void dfs_nol_update(struct wlan_dfs *dfs)
475 {
476 	struct dfsreq_nolelem *dfs_nol;
477 	int nlen;
478 
479 	if (!dfs->dfs_nol_count) {
480 		dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
481 		dfs_mlme_clist_update(dfs->dfs_pdev_obj, NULL, 0);
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 	/*
495 	 * XXX TODO: if this fails, just schedule a task to retry
496 	 * updating the NOL at a later stage.  That way the NOL
497 	 * update _DOES_ happen - hopefully the failure was just
498 	 * temporary.
499 	 */
500 	if (!dfs_nol)
501 		return;
502 
503 	DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
504 
505 	/* Be suitably paranoid for now. */
506 	if (nlen != dfs->dfs_nol_count)
507 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
508 			 nlen, dfs->dfs_nol_count);
509 
510 	/*
511 	 * Call the driver layer to have it recalculate the NOL flags
512 	 * for each driver/umac channel. If the list is empty, pass
513 	 * NULL instead of dfs_nol. The operating system may have some
514 	 * special representation for "malloc a 0 byte memory region"
515 	 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
516 	 * than a valid allocation (and is likely not NULL so the
517 	 * pointer doesn't match NULL checks in any later code.
518 	 */
519 	dfs_mlme_clist_update(dfs->dfs_pdev_obj,
520 			(nlen > 0) ? dfs_nol : NULL,
521 			nlen);
522 
523 	qdf_mem_free(dfs_nol);
524 }
525 
526 void dfs_nol_free_list(struct wlan_dfs *dfs)
527 {
528 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
529 
530 	while (nol) {
531 		prev = nol;
532 		nol = nol->nol_next;
533 		qdf_mem_free(prev);
534 		/* Update the NOL counter. */
535 		dfs->dfs_nol_count--;
536 
537 		if (dfs->dfs_nol_count < 0) {
538 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_nol_count < 0");
539 			ASSERT(0);
540 		}
541 	}
542 
543 	dfs->dfs_nol = NULL;
544 }
545 
546 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
547 {
548 	struct dfs_nolelem *nol;
549 
550 	while (true) {
551 		WLAN_DFSNOL_LOCK(dfs);
552 
553 		nol = dfs->dfs_nol;
554 		if (nol) {
555 			dfs->dfs_nol = nol->nol_next;
556 			dfs->dfs_nol_count--;
557 			WLAN_DFSNOL_UNLOCK(dfs);
558 
559 			qdf_timer_free(&nol->nol_timer);
560 			qdf_mem_free(nol);
561 		} else {
562 			WLAN_DFSNOL_UNLOCK(dfs);
563 			break;
564 		}
565 	}
566 }
567 
568 void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
569 {
570 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
571 }
572 
573 int dfs_get_use_nol(struct wlan_dfs *dfs)
574 {
575 	return dfs->dfs_use_nol;
576 }
577 
578 int dfs_get_nol_timeout(struct wlan_dfs *dfs)
579 {
580 	return dfs->wlan_dfs_nol_timeout;
581 }
582 
583 void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
584 {
585 	struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
586 
587 	DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
588 }
589 
590 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
591 {
592 	struct dfs_channel *chan_list;
593 	int nchans = 0;
594 	bool sta_opmode;
595 
596 	if (!dfs->dfs_is_stadfs_enabled)
597 		return;
598 
599 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
600 	if (!sta_opmode)
601 		return;
602 
603 	nchans = dfs_get_num_chans();
604 
605 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
606 	if (!chan_list)
607 		return;
608 
609 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
610 					    (void *)chan_list, &nchans);
611 	if (!nchans) {
612 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
613 		qdf_mem_free(chan_list);
614 		return;
615 	}
616 
617 	utils_dfs_reg_update_nol_history_ch(dfs->dfs_pdev_obj,
618 					    (void *)chan_list, nchans,
619 					    DFS_NOL_HISTORY_RESET);
620 
621 	qdf_mem_free(chan_list);
622 }
623 
624 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST)
625 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
626 {
627 	struct dfs_nolelem *nol;
628 	uint8_t channels[NUM_CHANNELS_160MHZ];
629 	int i, nchans = 0;
630 
631 	nchans = dfs_get_bonding_channels(dfs, &dfs->dfs_radar_found_chan, 0,
632 					  channels);
633 
634 	WLAN_DFSNOL_LOCK(dfs);
635 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
636 		nol = dfs->dfs_nol;
637 		while (nol) {
638 			if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
639 				    channels[i])) {
640 				OS_SET_TIMER(&nol->nol_timer, 0);
641 				break;
642 			}
643 			nol = nol->nol_next;
644 		}
645 	}
646 	WLAN_DFSNOL_UNLOCK(dfs);
647 
648 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
649 				    channels, nchans, DFS_NOL_RESET);
650 }
651 #endif
652