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