xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_nol.c (revision 6d768494e5ce14eb1603a695c86739d12ecc6ec2)
1 /*
2  * Copyright (c) 2016-2020 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 #include <qdf_types.h>
43 
44 void dfs_set_update_nol_flag(struct wlan_dfs *dfs, bool val)
45 {
46 	dfs->update_nol = val;
47 }
48 
49 bool dfs_get_update_nol_flag(struct wlan_dfs *dfs)
50 {
51 	return dfs->update_nol;
52 }
53 
54 /**
55  * dfs_nol_timeout() - NOL timeout function.
56  *
57  * Clears the WLAN_CHAN_DFS_RADAR_FOUND flag for the NOL timeout channel.
58  */
59 /* Unused function */
60 #ifdef CONFIG_CHAN_FREQ_API
61 static os_timer_func(dfs_nol_timeout)
62 {
63 	struct dfs_channel *c = NULL, lc;
64 	unsigned long oldest, now;
65 	struct wlan_dfs *dfs = NULL;
66 	int i;
67 	int nchans = 0;
68 
69 	c = &lc;
70 
71 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
72 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
73 
74 	now = oldest = qdf_system_ticks();
75 	for (i = 0; i < nchans; i++) {
76 		dfs_mlme_get_dfs_channels_for_freq
77 			(dfs->dfs_pdev_obj,
78 			 &c->dfs_ch_freq,
79 			 &c->dfs_ch_flags,
80 			 &c->dfs_ch_flagext,
81 			 &c->dfs_ch_ieee,
82 			 &c->dfs_ch_vhtop_ch_freq_seg1,
83 			 &c->dfs_ch_vhtop_ch_freq_seg2,
84 			 &c->dfs_ch_mhz_freq_seg1,
85 			 &c->dfs_ch_mhz_freq_seg2,
86 			 i);
87 		if (WLAN_IS_CHAN_RADAR(c)) {
88 			if (qdf_system_time_after_eq(now,
89 						     dfs->dfs_nol_event[i] +
90 						     dfs_get_nol_timeout(dfs))) {
91 				c->dfs_ch_flagext &= ~WLAN_CHAN_DFS_RADAR_FOUND;
92 				if (c->dfs_ch_flags & WLAN_CHAN_DFS_RADAR) {
93 					/*
94 					 * NB: do this here so we get only one
95 					 * msg instead of one for every channel
96 					 * table entry.
97 					 */
98 					dfs_debug(dfs, WLAN_DEBUG_DFS,
99 						  "radar on channel %u (%u MHz) cleared after timeout",
100 						  c->dfs_ch_ieee,
101 						  c->dfs_ch_freq);
102 				}
103 			} else if (dfs->dfs_nol_event[i] < oldest) {
104 				oldest = dfs->dfs_nol_event[i];
105 			}
106 		}
107 	}
108 	if (oldest != now) {
109 		/* Arrange to process next channel up for a status change. */
110 		qdf_timer_mod(&dfs->dfs_nol_timer,
111 			      dfs_get_nol_timeout(dfs) -
112 			      qdf_system_ticks_to_msecs(qdf_system_ticks()));
113 	}
114 }
115 #else
116 #ifdef CONFIG_CHAN_NUM_API
117 static os_timer_func(dfs_nol_timeout)
118 {
119 	struct dfs_channel *c = NULL, lc;
120 	unsigned long oldest, now;
121 	struct wlan_dfs *dfs = NULL;
122 	int i;
123 	int nchans = 0;
124 
125 	c = &lc;
126 
127 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
128 	dfs_mlme_get_dfs_ch_nchans(dfs->dfs_pdev_obj, &nchans);
129 
130 	now = oldest = qdf_system_ticks();
131 	for (i = 0; i < nchans; i++) {
132 		dfs_mlme_get_dfs_ch_channels(dfs->dfs_pdev_obj,
133 				&(c->dfs_ch_freq),
134 				&(c->dfs_ch_flags),
135 				&(c->dfs_ch_flagext),
136 				&(c->dfs_ch_ieee),
137 				&(c->dfs_ch_vhtop_ch_freq_seg1),
138 				&(c->dfs_ch_vhtop_ch_freq_seg2),
139 				i);
140 		if (WLAN_IS_CHAN_RADAR(c)) {
141 			if (qdf_system_time_after_eq(now,
142 						dfs->dfs_nol_event[i] +
143 						dfs_get_nol_timeout(dfs))) {
144 				c->dfs_ch_flagext &=
145 					~WLAN_CHAN_DFS_RADAR_FOUND;
146 				if (c->dfs_ch_flags &
147 						WLAN_CHAN_DFS_RADAR) {
148 					/*
149 					 * NB: do this here so we get only one
150 					 * msg instead of one for every channel
151 					 * table entry.
152 					 */
153 					dfs_debug(dfs, WLAN_DEBUG_DFS,
154 						"radar on channel %u (%u MHz) cleared after timeout",
155 
156 						c->dfs_ch_ieee,
157 						c->dfs_ch_freq);
158 				}
159 			} else if (dfs->dfs_nol_event[i] < oldest)
160 				oldest = dfs->dfs_nol_event[i];
161 		}
162 	}
163 	if (oldest != now) {
164 		/* Arrange to process next channel up for a status change. */
165 		qdf_timer_mod(&dfs->dfs_nol_timer,
166 				dfs_get_nol_timeout(dfs) -
167 				qdf_system_ticks_to_msecs(qdf_system_ticks()));
168 	}
169 }
170 #endif
171 #endif
172 
173 /**
174  * dfs_nol_elem_free_work_cb -  Free NOL element
175  *
176  * Free the NOL element memory
177  */
178 static void dfs_nol_elem_free_work_cb(void *context)
179 {
180 	struct wlan_dfs *dfs = (struct wlan_dfs *)context;
181 	struct dfs_nolelem *nol_head;
182 
183 	while (true) {
184 		WLAN_DFSNOL_LOCK(dfs);
185 
186 		nol_head = TAILQ_FIRST(&dfs->dfs_nol_free_list);
187 		if (nol_head) {
188 			TAILQ_REMOVE(&dfs->dfs_nol_free_list, nol_head,
189 				     nolelem_list);
190 			WLAN_DFSNOL_UNLOCK(dfs);
191 
192 			qdf_timer_free(&nol_head->nol_timer);
193 			qdf_mem_free(nol_head);
194 		} else {
195 			WLAN_DFSNOL_UNLOCK(dfs);
196 			break;
197 		}
198 	}
199 }
200 
201 void dfs_nol_timer_init(struct wlan_dfs *dfs)
202 {
203 	qdf_timer_init(NULL,
204 			&(dfs->dfs_nol_timer),
205 			dfs_nol_timeout,
206 			(void *)(dfs),
207 			QDF_TIMER_TYPE_WAKE_APPS);
208 }
209 
210 void dfs_nol_attach(struct wlan_dfs *dfs)
211 {
212 	dfs->wlan_dfs_nol_timeout = DFS_NOL_TIMEOUT_S;
213 	dfs_nol_timer_init(dfs);
214 	qdf_create_work(NULL, &dfs->dfs_nol_elem_free_work,
215 			dfs_nol_elem_free_work_cb, dfs);
216 	TAILQ_INIT(&dfs->dfs_nol_free_list);
217 	dfs->dfs_use_nol = 1;
218 	WLAN_DFSNOL_LOCK_CREATE(dfs);
219 }
220 
221 void dfs_nol_detach(struct wlan_dfs *dfs)
222 {
223 	dfs_nol_timer_cleanup(dfs);
224 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
225 	qdf_destroy_work(NULL, &dfs->dfs_nol_elem_free_work);
226 	WLAN_DFSNOL_LOCK_DESTROY(dfs);
227 }
228 
229 void dfs_nol_timer_detach(struct wlan_dfs *dfs)
230 {
231 	qdf_timer_free(&dfs->dfs_nol_timer);
232 }
233 
234 /**
235  * dfs_nol_delete() - Delete the given frequency/chwidth from the NOL.
236  * @dfs: Pointer to wlan_dfs structure.
237  * @delfreq: Freq to delete.
238  * @delchwidth: Channel width to delete.
239  */
240 static void dfs_nol_delete(struct wlan_dfs *dfs,
241 		uint16_t delfreq,
242 		uint16_t delchwidth)
243 {
244 	struct dfs_nolelem *nol, **prev_next;
245 
246 	if (!dfs) {
247 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
248 		return;
249 	}
250 
251 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
252 		"remove channel=%d/%d MHz from NOL",
253 		 delfreq, delchwidth);
254 	prev_next = &(dfs->dfs_nol);
255 	nol = dfs->dfs_nol;
256 	while (nol) {
257 		if (nol->nol_freq == delfreq &&
258 			nol->nol_chwidth == delchwidth) {
259 			*prev_next = nol->nol_next;
260 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
261 				"removing channel %d/%dMHz from NOL tstamp=%d",
262 				 nol->nol_freq,
263 				nol->nol_chwidth,
264 				(qdf_system_ticks_to_msecs
265 				 (qdf_system_ticks()) / 1000));
266 			TAILQ_INSERT_TAIL(&dfs->dfs_nol_free_list,
267 						nol, nolelem_list);
268 			nol = *prev_next;
269 
270 			/* Update the NOL counter. */
271 			dfs->dfs_nol_count--;
272 
273 			/* Be paranoid! */
274 			if (dfs->dfs_nol_count < 0) {
275 				dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "dfs_nol_count < 0; eek!");
276 				dfs->dfs_nol_count = 0;
277 			}
278 
279 		} else {
280 			prev_next = &(nol->nol_next);
281 			nol = nol->nol_next;
282 		}
283 	}
284 }
285 
286 /**
287  * dfs_remove_from_nol() - Remove the freq from NOL list.
288  *
289  * When NOL times out, this function removes the channel from NOL list.
290  */
291 #ifdef CONFIG_CHAN_FREQ_API
292 static os_timer_func(dfs_remove_from_nol)
293 {
294 	struct dfs_nolelem *nol_arg;
295 	struct wlan_dfs *dfs;
296 	uint16_t delfreq;
297 	uint16_t delchwidth;
298 	uint8_t chan;
299 
300 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
301 
302 	dfs = nol_arg->nol_dfs;
303 	delfreq = nol_arg->nol_freq;
304 	delchwidth = nol_arg->nol_chwidth;
305 
306 	/* Delete the given NOL entry. */
307 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
308 
309 	/* Update the wireless stack with the new NOL. */
310 	dfs_nol_update(dfs);
311 
312 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
313 	chan = utils_dfs_freq_to_chan(delfreq);
314 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
315 				WLAN_EV_NOL_FINISHED);
316 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
317 		  "remove channel %d from nol", chan);
318 	utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
319 	utils_dfs_rcac_sm_deliver_evt(dfs->dfs_pdev_obj,
320 				      DFS_RCAC_SM_EV_RCAC_START);
321 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
322 					     &delfreq, 1, DFS_NOL_RESET);
323 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
324 }
325 #else
326 #ifdef CONFIG_CHAN_NUM_API
327 static os_timer_func(dfs_remove_from_nol)
328 {
329 	struct dfs_nolelem *nol_arg;
330 	struct wlan_dfs *dfs;
331 	uint16_t delfreq;
332 	uint16_t delchwidth;
333 	uint8_t chan;
334 
335 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
336 
337 	dfs = nol_arg->nol_dfs;
338 	delfreq = nol_arg->nol_freq;
339 	delchwidth = nol_arg->nol_chwidth;
340 
341 	/* Delete the given NOL entry. */
342 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
343 
344 	/* Update the wireless stack with the new NOL. */
345 	dfs_nol_update(dfs);
346 
347 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
348 	chan = utils_dfs_freq_to_chan(delfreq);
349 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
350 				WLAN_EV_NOL_FINISHED);
351 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
352 		    "remove channel %d from nol", chan);
353 	utils_dfs_unmark_precac_nol(dfs->dfs_pdev_obj, chan);
354 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
355 				    &chan, 1, DFS_NOL_RESET);
356 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
357 }
358 #endif
359 #endif
360 
361 void dfs_print_nol(struct wlan_dfs *dfs)
362 {
363 	struct dfs_nolelem *nol;
364 	int i = 0;
365 	uint32_t diff_ms, remaining_sec;
366 
367 	if (!dfs) {
368 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
369 		return;
370 	}
371 
372 	nol = dfs->dfs_nol;
373 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
374 	while (nol) {
375 		diff_ms = qdf_do_div(qdf_get_monotonic_boottime() -
376 				     nol->nol_start_us, 1000);
377 		diff_ms = (nol->nol_timeout_ms - diff_ms);
378 		remaining_sec = diff_ms / 1000; /* Convert to seconds */
379 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
380 			"nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol start_us=%llu",
381 			i++, nol->nol_freq,
382 			nol->nol_chwidth,
383 			remaining_sec,
384 			nol->nol_start_us);
385 		nol = nol->nol_next;
386 	}
387 }
388 
389 void dfs_print_nolhistory(struct wlan_dfs *dfs)
390 {
391 	struct dfs_channel *chan_list;
392 	int i, j;
393 	int nchans;
394 
395 	if (!dfs) {
396 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
397 		return;
398 	}
399 
400 	nchans = dfs_get_num_chans();
401 
402 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
403 	if (!chan_list)
404 		return;
405 
406 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
407 					    (void *)chan_list, &nchans);
408 	if (!nchans) {
409 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
410 		qdf_mem_free(chan_list);
411 		return;
412 	}
413 
414 	for (i = 0, j = 0; i < nchans; i++, j++)
415 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
416 			 "nolhistory = %d channel = %d MHz",
417 			 j, chan_list[i].dfs_ch_freq);
418 
419 	qdf_mem_free(chan_list);
420 }
421 
422 void dfs_get_nol(struct wlan_dfs *dfs,
423 		struct dfsreq_nolelem *dfs_nol,
424 		int *nchan)
425 {
426 	struct dfs_nolelem *nol;
427 
428 	*nchan = 0;
429 
430 	if (!dfs) {
431 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
432 		return;
433 	}
434 
435 	nol = dfs->dfs_nol;
436 	while (nol) {
437 		dfs_nol[*nchan].nol_freq = nol->nol_freq;
438 		dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
439 		dfs_nol[*nchan].nol_start_us = nol->nol_start_us;
440 		dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
441 		++(*nchan);
442 		nol = nol->nol_next;
443 	}
444 }
445 
446 #ifdef CONFIG_CHAN_FREQ_API
447 void dfs_set_nol(struct wlan_dfs *dfs,
448 		 struct dfsreq_nolelem *dfs_nol,
449 		 int nchan)
450 {
451 #define TIME_IN_MS 1000
452 	uint32_t nol_time_lft_ms;
453 	struct dfs_channel chan;
454 	int i;
455 
456 	if (!dfs) {
457 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
458 		return;
459 	}
460 
461 	for (i = 0; i < nchan; i++) {
462 		nol_time_lft_ms = qdf_do_div(qdf_get_monotonic_boottime() -
463 					     dfs_nol[i].nol_start_us, 1000);
464 
465 		if (nol_time_lft_ms < dfs_nol[i].nol_timeout_ms) {
466 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
467 			chan.dfs_ch_flags = 0;
468 			chan.dfs_ch_flagext = 0;
469 			nol_time_lft_ms =
470 				(dfs_nol[i].nol_timeout_ms - nol_time_lft_ms);
471 
472 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
473 						(nol_time_lft_ms / TIME_IN_MS));
474 			utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
475 							     &chan.dfs_ch_freq,
476 							     1, DFS_NOL_SET);
477 		}
478 	}
479 #undef TIME_IN_MS
480 	dfs_nol_update(dfs);
481 }
482 #else
483 #ifdef CONFIG_CHAN_NUM_API
484 void dfs_set_nol(struct wlan_dfs *dfs,
485 		struct dfsreq_nolelem *dfs_nol,
486 		int nchan)
487 {
488 #define TIME_IN_MS 1000
489 	uint32_t nol_time_left_ms;
490 	struct dfs_channel chan;
491 	int i;
492 	uint8_t chan_num;
493 
494 	if (!dfs) {
495 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
496 		return;
497 	}
498 
499 	for (i = 0; i < nchan; i++) {
500 		nol_time_left_ms = qdf_do_div(qdf_get_monotonic_boottime() -
501 					      dfs_nol[i].nol_start_us, 1000);
502 
503 		if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
504 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
505 			chan.dfs_ch_flags = 0;
506 			chan.dfs_ch_flagext = 0;
507 			nol_time_left_ms =
508 				(dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
509 
510 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
511 					(nol_time_left_ms / TIME_IN_MS));
512 			chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
513 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
514 						&chan_num, 1, DFS_NOL_SET);
515 		}
516 	}
517 #undef TIME_IN_MS
518 	dfs_nol_update(dfs);
519 }
520 #endif
521 #endif
522 
523 void dfs_nol_addchan(struct wlan_dfs *dfs,
524 		uint16_t freq,
525 		uint32_t dfs_nol_timeout)
526 {
527 #define TIME_IN_MS 1000
528 #define TIME_IN_US (TIME_IN_MS * 1000)
529 	struct dfs_nolelem *nol, *elem, *prev;
530 	/* For now, assume all events are 20MHz wide. */
531 	int ch_width = 20;
532 
533 	if (!dfs) {
534 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
535 		return;
536 	}
537 	nol = dfs->dfs_nol;
538 	prev = dfs->dfs_nol;
539 	elem = NULL;
540 	while (nol) {
541 		if ((nol->nol_freq == freq) &&
542 				(nol->nol_chwidth == ch_width)) {
543 			nol->nol_start_us = qdf_get_monotonic_boottime();
544 			nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
545 
546 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
547 				"Update OS Ticks for NOL %d MHz / %d MHz",
548 				 nol->nol_freq, nol->nol_chwidth);
549 
550 			qdf_timer_stop(&nol->nol_timer);
551 			qdf_timer_mod(&nol->nol_timer,
552 					dfs_nol_timeout * TIME_IN_MS);
553 			return;
554 		}
555 		prev = nol;
556 		nol = nol->nol_next;
557 	}
558 
559 	/* Add a new element to the NOL. */
560 	elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
561 	if (!elem)
562 		goto bad;
563 
564 	qdf_mem_zero(elem, sizeof(*elem));
565 	elem->nol_dfs = dfs;
566 	elem->nol_freq = freq;
567 	elem->nol_chwidth = ch_width;
568 	elem->nol_start_us = qdf_get_monotonic_boottime();
569 	elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
570 	elem->nol_next = NULL;
571 	if (prev) {
572 		prev->nol_next = elem;
573 	} else {
574 		/* This is the first element in the NOL. */
575 		dfs->dfs_nol = elem;
576 	}
577 
578 	qdf_timer_init(NULL,
579 		       &elem->nol_timer, dfs_remove_from_nol,
580 		       elem, QDF_TIMER_TYPE_WAKE_APPS);
581 
582 	qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
583 
584 	/* Update the NOL counter. */
585 	dfs->dfs_nol_count++;
586 
587 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
588 		"new NOL channel %d MHz / %d MHz",
589 		 elem->nol_freq, elem->nol_chwidth);
590 	return;
591 
592 bad:
593 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
594 		"failed to allocate memory for nol entry");
595 
596 #undef TIME_IN_MS
597 #undef TIME_IN_US
598 }
599 
600 void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
601 		uint32_t *nol_chfreq,
602 		uint32_t *nol_chwidth,
603 		int index)
604 {
605 	if (!dfs_nol)
606 		return;
607 
608 	*nol_chfreq = dfs_nol[index].nol_freq;
609 	*nol_chwidth = dfs_nol[index].nol_chwidth;
610 }
611 
612 void dfs_nol_update(struct wlan_dfs *dfs)
613 {
614 	struct dfsreq_nolelem *dfs_nol;
615 	int nlen;
616 
617 	if (!dfs->dfs_nol_count) {
618 		dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
619 		dfs_mlme_clist_update(dfs->dfs_pdev_obj, NULL, 0);
620 		return;
621 	}
622 
623 	/*
624 	 * Allocate enough entries to store the NOL. At least on Linux
625 	 * (don't ask why), if you allocate a 0 entry array, the
626 	 * returned pointer is 0x10.  Make sure you're aware of this
627 	 * when you start debugging.
628 	 */
629 	dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
630 		sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
631 
632 	/*
633 	 * XXX TODO: if this fails, just schedule a task to retry
634 	 * updating the NOL at a later stage.  That way the NOL
635 	 * update _DOES_ happen - hopefully the failure was just
636 	 * temporary.
637 	 */
638 	if (!dfs_nol)
639 		return;
640 
641 	DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
642 
643 	/* Be suitably paranoid for now. */
644 	if (nlen != dfs->dfs_nol_count)
645 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
646 			 nlen, dfs->dfs_nol_count);
647 
648 	/*
649 	 * Call the driver layer to have it recalculate the NOL flags
650 	 * for each driver/umac channel. If the list is empty, pass
651 	 * NULL instead of dfs_nol. The operating system may have some
652 	 * special representation for "malloc a 0 byte memory region"
653 	 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
654 	 * than a valid allocation (and is likely not NULL so the
655 	 * pointer doesn't match NULL checks in any later code.
656 	 */
657 	dfs_mlme_clist_update(dfs->dfs_pdev_obj,
658 			(nlen > 0) ? dfs_nol : NULL,
659 			nlen);
660 
661 	qdf_mem_free(dfs_nol);
662 }
663 
664 void dfs_nol_free_list(struct wlan_dfs *dfs)
665 {
666 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
667 
668 	while (nol) {
669 		prev = nol;
670 		nol = nol->nol_next;
671 		qdf_mem_free(prev);
672 		/* Update the NOL counter. */
673 		dfs->dfs_nol_count--;
674 
675 		if (dfs->dfs_nol_count < 0) {
676 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_nol_count < 0");
677 			ASSERT(0);
678 		}
679 	}
680 
681 	dfs->dfs_nol = NULL;
682 }
683 
684 #ifdef CONFIG_CHAN_FREQ_API
685 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
686 {
687 	struct dfs_nolelem *nol;
688 	uint16_t nol_freq;
689 
690 	while (true) {
691 		WLAN_DFSNOL_LOCK(dfs);
692 
693 		nol = dfs->dfs_nol;
694 		if (nol) {
695 			dfs->dfs_nol = nol->nol_next;
696 			dfs->dfs_nol_count--;
697 			nol_freq = nol->nol_freq;
698 			WLAN_DFSNOL_UNLOCK(dfs);
699 			utils_dfs_reg_update_nol_chan_for_freq(
700 					dfs->dfs_pdev_obj,
701 					&nol_freq,
702 					1,
703 					DFS_NOL_RESET);
704 
705 			qdf_timer_free(&nol->nol_timer);
706 			qdf_mem_free(nol);
707 		} else {
708 			WLAN_DFSNOL_UNLOCK(dfs);
709 			break;
710 		}
711 	}
712 }
713 #else
714 #ifdef CONFIG_CHAN_NUM_API
715 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
716 {
717 	struct dfs_nolelem *nol;
718 	uint8_t nol_chan;
719 
720 	while (true) {
721 		WLAN_DFSNOL_LOCK(dfs);
722 
723 		nol = dfs->dfs_nol;
724 		if (nol) {
725 			dfs->dfs_nol = nol->nol_next;
726 			dfs->dfs_nol_count--;
727 			nol_chan = utils_dfs_freq_to_chan(nol->nol_freq);
728 			WLAN_DFSNOL_UNLOCK(dfs);
729 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
730 						    &nol_chan,
731 						    1,
732 						    DFS_NOL_RESET);
733 
734 			qdf_timer_free(&nol->nol_timer);
735 			qdf_mem_free(nol);
736 		} else {
737 			WLAN_DFSNOL_UNLOCK(dfs);
738 			break;
739 		}
740 	}
741 }
742 #endif
743 #endif
744 
745 void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
746 {
747 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
748 }
749 
750 int dfs_get_use_nol(struct wlan_dfs *dfs)
751 {
752 	return dfs->dfs_use_nol;
753 }
754 
755 int dfs_get_nol_timeout(struct wlan_dfs *dfs)
756 {
757 	return dfs->wlan_dfs_nol_timeout;
758 }
759 
760 void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
761 {
762 	struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
763 
764 	DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
765 }
766 
767 #if !defined(QCA_MCL_DFS_SUPPORT)
768 #ifdef CONFIG_CHAN_FREQ_API
769 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
770 {
771 	struct dfs_channel *chan_list;
772 	int nchans;
773 	bool sta_opmode;
774 	int i;
775 	qdf_freq_t *nol_freq_list = NULL;
776 	int num_nol_history_chans;
777 
778 	if (!dfs->dfs_is_stadfs_enabled)
779 		return;
780 
781 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
782 	if (!sta_opmode)
783 		return;
784 
785 	nchans = dfs_get_num_chans();
786 
787 	if (!nchans) {
788 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
789 		return;
790 	}
791 
792 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
793 	if (!chan_list)
794 		return;
795 
796 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
797 					    (void *)chan_list,
798 					    &num_nol_history_chans);
799 
800 	if (!num_nol_history_chans) {
801 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
802 		qdf_mem_free(chan_list);
803 		return;
804 	}
805 
806 	if (num_nol_history_chans > nchans)
807 		num_nol_history_chans = nchans;
808 
809 	nol_freq_list =
810 		qdf_mem_malloc(num_nol_history_chans * sizeof(qdf_freq_t));
811 
812 	if (!nol_freq_list) {
813 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unable to alloc memory for freq list");
814 		qdf_mem_free(chan_list);
815 		return;
816 	}
817 
818 	for (i = 0; i < num_nol_history_chans; i++)
819 		nol_freq_list[i] = chan_list[i].dfs_ch_freq;
820 
821 	utils_dfs_reg_update_nol_history_chan_for_freq(dfs->dfs_pdev_obj,
822 						       nol_freq_list,
823 						       num_nol_history_chans,
824 						       DFS_NOL_HISTORY_RESET);
825 	qdf_mem_free(chan_list);
826 	qdf_mem_free(nol_freq_list);
827 }
828 #else
829 #ifdef CONFIG_CHAN_NUM_API
830 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
831 {
832 	struct dfs_channel *chan_list;
833 	int nchans;
834 	bool sta_opmode;
835 	int i;
836 	uint8_t *nol_chan_ieee_list = NULL;
837 	int num_nol_history_chans;
838 
839 	if (!dfs->dfs_is_stadfs_enabled)
840 		return;
841 
842 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
843 	if (!sta_opmode)
844 		return;
845 
846 	nchans = dfs_get_num_chans();
847 
848 	if (!nchans) {
849 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
850 		return;
851 	}
852 
853 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
854 	if (!chan_list)
855 		return;
856 
857 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
858 					    (void *)chan_list,
859 					    &num_nol_history_chans);
860 
861 	if (!num_nol_history_chans) {
862 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
863 		qdf_mem_free(chan_list);
864 		return;
865 	}
866 
867 	if (num_nol_history_chans > nchans)
868 		num_nol_history_chans = nchans;
869 
870 	nol_chan_ieee_list =
871 		qdf_mem_malloc(num_nol_history_chans * sizeof(uint8_t));
872 
873 	if (!nol_chan_ieee_list) {
874 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unable to alloc memory for ieee list");
875 		qdf_mem_free(chan_list);
876 		return;
877 	}
878 
879 	for (i = 0; i < num_nol_history_chans; i++)
880 		nol_chan_ieee_list[i] = chan_list[i].dfs_ch_ieee;
881 
882 	utils_dfs_reg_update_nol_history_ch(dfs->dfs_pdev_obj,
883 					    nol_chan_ieee_list,
884 					    num_nol_history_chans,
885 					    DFS_NOL_HISTORY_RESET);
886 
887 	qdf_mem_free(chan_list);
888 	qdf_mem_free(nol_chan_ieee_list);
889 }
890 #endif
891 #endif
892 #endif
893 
894 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
895 	defined(CONFIG_CHAN_FREQ_API)
896 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
897 {
898 	struct dfs_nolelem *nol;
899 	uint16_t freq_list[NUM_CHANNELS_160MHZ];
900 	int i, nchans = 0;
901 
902 	nchans = dfs_get_bonding_channels_for_freq(dfs,
903 						   &dfs->dfs_radar_found_chan,
904 						   SEG_ID_PRIMARY,
905 						   DETECTOR_ID_0,
906 						   freq_list);
907 
908 	WLAN_DFSNOL_LOCK(dfs);
909 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
910 		nol = dfs->dfs_nol;
911 		while (nol) {
912 			if (nol->nol_freq == freq_list[i]) {
913 				OS_SET_TIMER(&nol->nol_timer, 0);
914 				break;
915 			}
916 			nol = nol->nol_next;
917 		}
918 	}
919 	WLAN_DFSNOL_UNLOCK(dfs);
920 
921 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
922 					     freq_list, nchans, DFS_NOL_RESET);
923 }
924 #else
925 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
926 	defined(CONFIG_CHAN_NUM_API)
927 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
928 {
929 	struct dfs_nolelem *nol;
930 	uint8_t channels[NUM_CHANNELS_160MHZ];
931 	int i, nchans = 0;
932 
933 	nchans = dfs_get_bonding_channels(dfs,
934 					  &dfs->dfs_radar_found_chan,
935 					  SEG_ID_PRIMARY,
936 					  DETECTOR_ID_0,
937 					  channels);
938 
939 	WLAN_DFSNOL_LOCK(dfs);
940 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
941 		nol = dfs->dfs_nol;
942 		while (nol) {
943 			if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
944 				    channels[i])) {
945 				OS_SET_TIMER(&nol->nol_timer, 0);
946 				break;
947 			}
948 			nol = nol->nol_next;
949 		}
950 	}
951 	WLAN_DFSNOL_UNLOCK(dfs);
952 
953 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
954 				    channels, nchans, DFS_NOL_RESET);
955 }
956 #endif
957 #endif
958 
959 void dfs_init_tmp_psoc_nol(struct wlan_dfs *dfs, uint8_t num_radios)
960 {
961 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
962 
963 	if (WLAN_UMAC_MAX_PDEVS < num_radios) {
964 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
965 			"num_radios (%u) exceeds limit", num_radios);
966 		return;
967 	}
968 
969 	/* Allocate the temporary psoc NOL copy structure for the number
970 	 * of radios provided.
971 	 */
972 	dfs_soc_obj->dfs_psoc_nolinfo =
973 		qdf_mem_malloc(sizeof(struct dfsreq_nolinfo) * num_radios);
974 }
975 
976 void dfs_deinit_tmp_psoc_nol(struct wlan_dfs *dfs)
977 {
978 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
979 
980 	if (!dfs_soc_obj->dfs_psoc_nolinfo)
981 		return;
982 
983 	qdf_mem_free(dfs_soc_obj->dfs_psoc_nolinfo);
984 	dfs_soc_obj->dfs_psoc_nolinfo = NULL;
985 }
986 
987 void dfs_save_dfs_nol_in_psoc(struct wlan_dfs *dfs,
988 			      uint8_t pdev_id)
989 {
990 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
991 	struct dfsreq_nolinfo tmp_nolinfo, *nolinfo;
992 	uint32_t i, num_chans = 0;
993 
994 	if (!dfs->dfs_nol_count)
995 		return;
996 
997 	if (!dfs_soc_obj->dfs_psoc_nolinfo)
998 		return;
999 
1000 	nolinfo = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
1001 	/* Fetch the NOL entries for the DFS object. */
1002 	dfs_getnol(dfs, &tmp_nolinfo);
1003 
1004 	/* nolinfo might already have some data. Do not overwrite it */
1005 	num_chans = nolinfo->dfs_ch_nchans;
1006 	for (i = 0; i < tmp_nolinfo.dfs_ch_nchans; i++) {
1007 		/* Figure out the completed duration of each NOL. */
1008 		uint32_t nol_completed_ms = qdf_do_div(
1009 			qdf_get_monotonic_boottime() -
1010 			tmp_nolinfo.dfs_nol[i].nol_start_us, 1000);
1011 
1012 		nolinfo->dfs_nol[num_chans] = tmp_nolinfo.dfs_nol[i];
1013 		/* Remember the remaining NOL time in the timeout
1014 		 * variable.
1015 		 */
1016 		nolinfo->dfs_nol[num_chans++].nol_timeout_ms -=
1017 			nol_completed_ms;
1018 	}
1019 
1020 	nolinfo->dfs_ch_nchans = num_chans;
1021 }
1022 
1023 void dfs_reinit_nol_from_psoc_copy(struct wlan_dfs *dfs,
1024 				   uint8_t pdev_id,
1025 				   uint16_t low_5ghz_freq,
1026 				   uint16_t high_5ghz_freq)
1027 {
1028 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
1029 	struct dfsreq_nolinfo *nol, req_nol;
1030 	uint8_t i, j = 0;
1031 
1032 	if (!dfs_soc_obj->dfs_psoc_nolinfo)
1033 		return;
1034 
1035 	if (!dfs_soc_obj->dfs_psoc_nolinfo[pdev_id].dfs_ch_nchans)
1036 		return;
1037 
1038 	nol = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
1039 
1040 	for (i = 0; i < nol->dfs_ch_nchans; i++) {
1041 		uint16_t tmp_freq = nol->dfs_nol[i].nol_freq;
1042 
1043 		/* Add to nol only if within the tgt pdev's frequency range. */
1044 		if ((low_5ghz_freq < tmp_freq) && (high_5ghz_freq > tmp_freq)) {
1045 			/* The NOL timeout value in each entry points to the
1046 			 * remaining time of the NOL. This is to indicate that
1047 			 * the NOL entries are paused and are not left to
1048 			 * continue.
1049 			 * While adding these NOL, update the start ticks to
1050 			 * current time to avoid losing entries which might
1051 			 * have timed out during the pause and resume mechanism.
1052 			 */
1053 			nol->dfs_nol[i].nol_start_us =
1054 				qdf_get_monotonic_boottime();
1055 			req_nol.dfs_nol[j++] = nol->dfs_nol[i];
1056 		}
1057 	}
1058 	dfs_set_nol(dfs, req_nol.dfs_nol, j);
1059 }
1060