xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_nol.c (revision 97f44cd39e4ff816eaa1710279d28cf6b9e65ad9)
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 #ifdef QCA_SUPPORT_DFS_CHAN_POSTNOL
287 /**
288  * dfs_switch_to_postnol_chan_if_nol_expired() - Find if NOL is expired
289  * in the postNOL channel configured. If true, trigger channel change.
290  * @dfs: Pointer to DFS of wlan_dfs structure.
291  *
292  * Return: True, if channel change is triggered, else false.
293  */
294 static bool
295 dfs_switch_to_postnol_chan_if_nol_expired(struct wlan_dfs *dfs)
296 {
297 	struct dfs_channel chan;
298 	struct dfs_channel *curchan = dfs->dfs_curchan;
299 	bool is_curchan_11ac = false, is_curchan_11axa = false;
300 	enum wlan_phymode postnol_phymode;
301 
302 	if (!dfs->dfs_chan_postnol_freq)
303 		return false;
304 
305 	if (WLAN_IS_CHAN_11AC_VHT20(curchan) ||
306 	    WLAN_IS_CHAN_11AC_VHT40(curchan) ||
307 	    WLAN_IS_CHAN_11AC_VHT80(curchan) ||
308 	    WLAN_IS_CHAN_11AC_VHT160(curchan) ||
309 	    WLAN_IS_CHAN_11AC_VHT80_80(curchan))
310 		is_curchan_11ac = true;
311 	else if (WLAN_IS_CHAN_11AXA_HE20(curchan) ||
312 		 WLAN_IS_CHAN_11AXA_HE40PLUS(curchan) ||
313 		 WLAN_IS_CHAN_11AXA_HE40MINUS(curchan) ||
314 		 WLAN_IS_CHAN_11AXA_HE80(curchan) ||
315 		 WLAN_IS_CHAN_11AXA_HE160(curchan) ||
316 		 WLAN_IS_CHAN_11AXA_HE80_80(curchan))
317 		is_curchan_11axa = true;
318 
319 	switch (dfs->dfs_chan_postnol_mode) {
320 	case CH_WIDTH_20MHZ:
321 		if (is_curchan_11ac)
322 			postnol_phymode = WLAN_PHYMODE_11AC_VHT20;
323 		else if (is_curchan_11axa)
324 			postnol_phymode = WLAN_PHYMODE_11AXA_HE20;
325 		else
326 			return false;
327 		break;
328 	case CH_WIDTH_40MHZ:
329 		if (is_curchan_11ac)
330 			postnol_phymode = WLAN_PHYMODE_11AC_VHT40;
331 		else if (is_curchan_11axa)
332 			postnol_phymode = WLAN_PHYMODE_11AXA_HE40;
333 		else
334 			return false;
335 		break;
336 	case CH_WIDTH_80MHZ:
337 		if (is_curchan_11ac)
338 			postnol_phymode = WLAN_PHYMODE_11AC_VHT80;
339 		else if (is_curchan_11axa)
340 			postnol_phymode = WLAN_PHYMODE_11AXA_HE80;
341 		else
342 			return false;
343 		break;
344 	case CH_WIDTH_160MHZ:
345 		if (is_curchan_11ac)
346 			postnol_phymode = WLAN_PHYMODE_11AC_VHT160;
347 		else if (is_curchan_11axa)
348 			postnol_phymode = WLAN_PHYMODE_11AXA_HE160;
349 		else
350 			return false;
351 		break;
352 	case CH_WIDTH_80P80MHZ:
353 		if (is_curchan_11ac)
354 			postnol_phymode = WLAN_PHYMODE_11AC_VHT80_80;
355 		else if (is_curchan_11axa)
356 			postnol_phymode = WLAN_PHYMODE_11AXA_HE80_80;
357 		else
358 			return false;
359 		break;
360 	default:
361 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
362 			"Invalid postNOL mode set. Cannot switch to the chan");
363 		return false;
364 	}
365 
366 	qdf_mem_zero(&chan, sizeof(struct dfs_channel));
367 	if (QDF_STATUS_SUCCESS !=
368 		dfs_mlme_find_dot11_chan_for_freq(
369 			dfs->dfs_pdev_obj,
370 			dfs->dfs_chan_postnol_freq,
371 			dfs->dfs_chan_postnol_cfreq2,
372 			postnol_phymode,
373 			&chan.dfs_ch_freq,
374 			&chan.dfs_ch_flags,
375 			&chan.dfs_ch_flagext,
376 			&chan.dfs_ch_ieee,
377 			&chan.dfs_ch_vhtop_ch_freq_seg1,
378 			&chan.dfs_ch_vhtop_ch_freq_seg2,
379 			&chan.dfs_ch_mhz_freq_seg1,
380 			&chan.dfs_ch_mhz_freq_seg2)) {
381 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
382 			"Channel %d not found for mode %d and cfreq2 %d",
383 			dfs->dfs_chan_postnol_freq,
384 			postnol_phymode,
385 			dfs->dfs_chan_postnol_cfreq2);
386 		return false;
387 	}
388 	if (WLAN_IS_CHAN_RADAR(&chan))
389 		return false;
390 
391 	if (global_dfs_to_mlme.mlme_postnol_chan_switch)
392 		global_dfs_to_mlme.mlme_postnol_chan_switch(
393 				dfs->dfs_pdev_obj,
394 				dfs->dfs_chan_postnol_freq,
395 				dfs->dfs_chan_postnol_cfreq2,
396 				postnol_phymode);
397 	return true;
398 }
399 #else
400 static inline bool
401 dfs_switch_to_postnol_chan_if_nol_expired(struct wlan_dfs *dfs)
402 {
403 	return false;
404 }
405 #endif
406 
407 /**
408  * dfs_remove_from_nol() - Remove the freq from NOL list.
409  *
410  * When NOL times out, this function removes the channel from NOL list.
411  */
412 #ifdef CONFIG_CHAN_FREQ_API
413 static os_timer_func(dfs_remove_from_nol)
414 {
415 	struct dfs_nolelem *nol_arg;
416 	struct wlan_dfs *dfs;
417 	uint16_t delfreq;
418 	uint16_t delchwidth;
419 	uint8_t chan;
420 
421 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
422 
423 	dfs = nol_arg->nol_dfs;
424 	delfreq = nol_arg->nol_freq;
425 	delchwidth = nol_arg->nol_chwidth;
426 
427 	/* Delete the given NOL entry. */
428 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
429 
430 	/* Update the wireless stack with the new NOL. */
431 	dfs_nol_update(dfs);
432 
433 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
434 	chan = utils_dfs_freq_to_chan(delfreq);
435 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
436 				WLAN_EV_NOL_FINISHED);
437 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
438 		  "remove channel %d from nol", chan);
439 	utils_dfs_unmark_precac_nol_for_freq(dfs->dfs_pdev_obj, delfreq);
440 
441 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
442 					     &delfreq, 1, DFS_NOL_RESET);
443 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
444 
445 	/*
446 	 * Check if a channel is configured by the user to which we have to
447 	 * switch after it's NOL expiry. If that is the case, change
448 	 * channel immediately.
449 	 *
450 	 * If a channel switch is required (indicated by the return value of
451 	 * dfs_switch_to_postnol_chan_if_nol_expired), return from this function
452 	 * without posting Start event to Agile SM. That will be taken care
453 	 * of, after VAP start.
454 	 */
455 	if (dfs_switch_to_postnol_chan_if_nol_expired(dfs))
456 		return;
457 
458 	utils_dfs_agile_sm_deliver_evt(dfs->dfs_pdev_obj,
459 				       DFS_AGILE_SM_EV_AGILE_START);
460 }
461 #else
462 #ifdef CONFIG_CHAN_NUM_API
463 static os_timer_func(dfs_remove_from_nol)
464 {
465 	struct dfs_nolelem *nol_arg;
466 	struct wlan_dfs *dfs;
467 	uint16_t delfreq;
468 	uint16_t delchwidth;
469 	uint8_t chan;
470 
471 	OS_GET_TIMER_ARG(nol_arg, struct dfs_nolelem *);
472 
473 	dfs = nol_arg->nol_dfs;
474 	delfreq = nol_arg->nol_freq;
475 	delchwidth = nol_arg->nol_chwidth;
476 
477 	/* Delete the given NOL entry. */
478 	DFS_NOL_DELETE_CHAN_LOCKED(dfs, delfreq, delchwidth);
479 
480 	/* Update the wireless stack with the new NOL. */
481 	dfs_nol_update(dfs);
482 
483 	dfs_mlme_nol_timeout_notification(dfs->dfs_pdev_obj);
484 	chan = utils_dfs_freq_to_chan(delfreq);
485 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, delfreq,
486 				WLAN_EV_NOL_FINISHED);
487 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
488 		    "remove channel %d from nol", chan);
489 	utils_dfs_unmark_precac_nol(dfs->dfs_pdev_obj, chan);
490 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
491 				    &chan, 1, DFS_NOL_RESET);
492 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
493 }
494 #endif
495 #endif
496 
497 void dfs_print_nol(struct wlan_dfs *dfs)
498 {
499 	struct dfs_nolelem *nol;
500 	int i = 0;
501 	uint32_t diff_ms, remaining_sec;
502 
503 	if (!dfs) {
504 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
505 		return;
506 	}
507 
508 	nol = dfs->dfs_nol;
509 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "NOL");
510 	while (nol) {
511 		diff_ms = qdf_do_div(qdf_get_monotonic_boottime() -
512 				     nol->nol_start_us, 1000);
513 		diff_ms = (nol->nol_timeout_ms - diff_ms);
514 		remaining_sec = diff_ms / 1000; /* Convert to seconds */
515 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
516 			"nol:%d channel=%d MHz width=%d MHz time left=%u seconds nol start_us=%llu",
517 			i++, nol->nol_freq,
518 			nol->nol_chwidth,
519 			remaining_sec,
520 			nol->nol_start_us);
521 		nol = nol->nol_next;
522 	}
523 }
524 
525 void dfs_print_nolhistory(struct wlan_dfs *dfs)
526 {
527 	struct dfs_channel *chan_list;
528 	int i, j;
529 	int nchans;
530 
531 	if (!dfs) {
532 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
533 		return;
534 	}
535 
536 	nchans = dfs_get_num_chans();
537 
538 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
539 	if (!chan_list)
540 		return;
541 
542 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
543 					    (void *)chan_list, &nchans);
544 	if (!nchans) {
545 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
546 		qdf_mem_free(chan_list);
547 		return;
548 	}
549 
550 	for (i = 0, j = 0; i < nchans; i++, j++)
551 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
552 			 "nolhistory = %d channel = %d MHz",
553 			 j, chan_list[i].dfs_ch_freq);
554 
555 	qdf_mem_free(chan_list);
556 }
557 
558 void dfs_get_nol(struct wlan_dfs *dfs,
559 		struct dfsreq_nolelem *dfs_nol,
560 		int *nchan)
561 {
562 	struct dfs_nolelem *nol;
563 
564 	*nchan = 0;
565 
566 	if (!dfs) {
567 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
568 		return;
569 	}
570 
571 	nol = dfs->dfs_nol;
572 	while (nol) {
573 		dfs_nol[*nchan].nol_freq = nol->nol_freq;
574 		dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth;
575 		dfs_nol[*nchan].nol_start_us = nol->nol_start_us;
576 		dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms;
577 		++(*nchan);
578 		nol = nol->nol_next;
579 	}
580 }
581 
582 #ifdef CONFIG_CHAN_FREQ_API
583 void dfs_set_nol(struct wlan_dfs *dfs,
584 		 struct dfsreq_nolelem *dfs_nol,
585 		 int nchan)
586 {
587 #define TIME_IN_MS 1000
588 	uint32_t nol_time_lft_ms;
589 	struct dfs_channel chan;
590 	int i;
591 
592 	if (!dfs) {
593 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
594 		return;
595 	}
596 
597 	for (i = 0; i < nchan; i++) {
598 		nol_time_lft_ms = qdf_do_div(qdf_get_monotonic_boottime() -
599 					     dfs_nol[i].nol_start_us, 1000);
600 
601 		if (nol_time_lft_ms < dfs_nol[i].nol_timeout_ms) {
602 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
603 			chan.dfs_ch_flags = 0;
604 			chan.dfs_ch_flagext = 0;
605 			nol_time_lft_ms =
606 				(dfs_nol[i].nol_timeout_ms - nol_time_lft_ms);
607 
608 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
609 						(nol_time_lft_ms / TIME_IN_MS));
610 			utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
611 							     &chan.dfs_ch_freq,
612 							     1, DFS_NOL_SET);
613 		}
614 	}
615 #undef TIME_IN_MS
616 	dfs_nol_update(dfs);
617 }
618 #else
619 #ifdef CONFIG_CHAN_NUM_API
620 void dfs_set_nol(struct wlan_dfs *dfs,
621 		struct dfsreq_nolelem *dfs_nol,
622 		int nchan)
623 {
624 #define TIME_IN_MS 1000
625 	uint32_t nol_time_left_ms;
626 	struct dfs_channel chan;
627 	int i;
628 	uint8_t chan_num;
629 
630 	if (!dfs) {
631 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
632 		return;
633 	}
634 
635 	for (i = 0; i < nchan; i++) {
636 		nol_time_left_ms = qdf_do_div(qdf_get_monotonic_boottime() -
637 					      dfs_nol[i].nol_start_us, 1000);
638 
639 		if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) {
640 			chan.dfs_ch_freq = dfs_nol[i].nol_freq;
641 			chan.dfs_ch_flags = 0;
642 			chan.dfs_ch_flagext = 0;
643 			nol_time_left_ms =
644 				(dfs_nol[i].nol_timeout_ms - nol_time_left_ms);
645 
646 			DFS_NOL_ADD_CHAN_LOCKED(dfs, chan.dfs_ch_freq,
647 					(nol_time_left_ms / TIME_IN_MS));
648 			chan_num = utils_dfs_freq_to_chan(chan.dfs_ch_freq);
649 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
650 						&chan_num, 1, DFS_NOL_SET);
651 		}
652 	}
653 #undef TIME_IN_MS
654 	dfs_nol_update(dfs);
655 }
656 #endif
657 #endif
658 
659 void dfs_nol_addchan(struct wlan_dfs *dfs,
660 		uint16_t freq,
661 		uint32_t dfs_nol_timeout)
662 {
663 #define TIME_IN_MS 1000
664 #define TIME_IN_US (TIME_IN_MS * 1000)
665 	struct dfs_nolelem *nol, *elem, *prev;
666 	/* For now, assume all events are 20MHz wide. */
667 	int ch_width = 20;
668 
669 	if (!dfs) {
670 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs is NULL");
671 		return;
672 	}
673 	nol = dfs->dfs_nol;
674 	prev = dfs->dfs_nol;
675 	elem = NULL;
676 	while (nol) {
677 		if ((nol->nol_freq == freq) &&
678 				(nol->nol_chwidth == ch_width)) {
679 			nol->nol_start_us = qdf_get_monotonic_boottime();
680 			nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS;
681 
682 			dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
683 				"Update OS Ticks for NOL %d MHz / %d MHz",
684 				 nol->nol_freq, nol->nol_chwidth);
685 
686 			qdf_timer_stop(&nol->nol_timer);
687 			qdf_timer_mod(&nol->nol_timer,
688 					dfs_nol_timeout * TIME_IN_MS);
689 			return;
690 		}
691 		prev = nol;
692 		nol = nol->nol_next;
693 	}
694 
695 	/* Add a new element to the NOL. */
696 	elem = (struct dfs_nolelem *)qdf_mem_malloc(sizeof(struct dfs_nolelem));
697 	if (!elem)
698 		goto bad;
699 
700 	qdf_mem_zero(elem, sizeof(*elem));
701 	elem->nol_dfs = dfs;
702 	elem->nol_freq = freq;
703 	elem->nol_chwidth = ch_width;
704 	elem->nol_start_us = qdf_get_monotonic_boottime();
705 	elem->nol_timeout_ms = dfs_nol_timeout*TIME_IN_MS;
706 	elem->nol_next = NULL;
707 	if (prev) {
708 		prev->nol_next = elem;
709 	} else {
710 		/* This is the first element in the NOL. */
711 		dfs->dfs_nol = elem;
712 	}
713 
714 	qdf_timer_init(NULL,
715 		       &elem->nol_timer, dfs_remove_from_nol,
716 		       elem, QDF_TIMER_TYPE_WAKE_APPS);
717 
718 	qdf_timer_mod(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS);
719 
720 	/* Update the NOL counter. */
721 	dfs->dfs_nol_count++;
722 
723 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL,
724 		"new NOL channel %d MHz / %d MHz",
725 		 elem->nol_freq, elem->nol_chwidth);
726 	return;
727 
728 bad:
729 	dfs_debug(dfs, WLAN_DEBUG_DFS_NOL | WLAN_DEBUG_DFS,
730 		"failed to allocate memory for nol entry");
731 
732 #undef TIME_IN_MS
733 #undef TIME_IN_US
734 }
735 
736 void dfs_get_nol_chfreq_and_chwidth(struct dfsreq_nolelem *dfs_nol,
737 		uint32_t *nol_chfreq,
738 		uint32_t *nol_chwidth,
739 		int index)
740 {
741 	if (!dfs_nol)
742 		return;
743 
744 	*nol_chfreq = dfs_nol[index].nol_freq;
745 	*nol_chwidth = dfs_nol[index].nol_chwidth;
746 }
747 
748 void dfs_nol_update(struct wlan_dfs *dfs)
749 {
750 	struct dfsreq_nolelem *dfs_nol;
751 	int nlen;
752 
753 	if (!dfs->dfs_nol_count) {
754 		dfs_debug(dfs, WLAN_DEBUG_DFS_NOL, "dfs_nol_count is zero");
755 		dfs_mlme_clist_update(dfs->dfs_pdev_obj, NULL, 0);
756 		return;
757 	}
758 
759 	/*
760 	 * Allocate enough entries to store the NOL. At least on Linux
761 	 * (don't ask why), if you allocate a 0 entry array, the
762 	 * returned pointer is 0x10.  Make sure you're aware of this
763 	 * when you start debugging.
764 	 */
765 	dfs_nol = (struct dfsreq_nolelem *)qdf_mem_malloc(
766 		sizeof(struct dfsreq_nolelem) * dfs->dfs_nol_count);
767 
768 	/*
769 	 * XXX TODO: if this fails, just schedule a task to retry
770 	 * updating the NOL at a later stage.  That way the NOL
771 	 * update _DOES_ happen - hopefully the failure was just
772 	 * temporary.
773 	 */
774 	if (!dfs_nol)
775 		return;
776 
777 	DFS_GET_NOL_LOCKED(dfs, dfs_nol, &nlen);
778 
779 	/* Be suitably paranoid for now. */
780 	if (nlen != dfs->dfs_nol_count)
781 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS, "nlen (%d) != dfs->dfs_nol_count (%d)!",
782 			 nlen, dfs->dfs_nol_count);
783 
784 	/*
785 	 * Call the driver layer to have it recalculate the NOL flags
786 	 * for each driver/umac channel. If the list is empty, pass
787 	 * NULL instead of dfs_nol. The operating system may have some
788 	 * special representation for "malloc a 0 byte memory region"
789 	 * - for example, Linux 2.6.38-13 (ubuntu) returns 0x10 rather
790 	 * than a valid allocation (and is likely not NULL so the
791 	 * pointer doesn't match NULL checks in any later code.
792 	 */
793 	dfs_mlme_clist_update(dfs->dfs_pdev_obj,
794 			(nlen > 0) ? dfs_nol : NULL,
795 			nlen);
796 
797 	qdf_mem_free(dfs_nol);
798 }
799 
800 void dfs_nol_free_list(struct wlan_dfs *dfs)
801 {
802 	struct dfs_nolelem *nol = dfs->dfs_nol, *prev;
803 
804 	while (nol) {
805 		prev = nol;
806 		nol = nol->nol_next;
807 		qdf_mem_free(prev);
808 		/* Update the NOL counter. */
809 		dfs->dfs_nol_count--;
810 
811 		if (dfs->dfs_nol_count < 0) {
812 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,  "dfs_nol_count < 0");
813 			ASSERT(0);
814 		}
815 	}
816 
817 	dfs->dfs_nol = NULL;
818 }
819 
820 #ifdef CONFIG_CHAN_FREQ_API
821 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
822 {
823 	struct dfs_nolelem *nol;
824 	uint16_t nol_freq;
825 
826 	while (true) {
827 		WLAN_DFSNOL_LOCK(dfs);
828 
829 		nol = dfs->dfs_nol;
830 		if (nol) {
831 			dfs->dfs_nol = nol->nol_next;
832 			dfs->dfs_nol_count--;
833 			nol_freq = nol->nol_freq;
834 			WLAN_DFSNOL_UNLOCK(dfs);
835 			utils_dfs_reg_update_nol_chan_for_freq(
836 					dfs->dfs_pdev_obj,
837 					&nol_freq,
838 					1,
839 					DFS_NOL_RESET);
840 
841 			qdf_timer_free(&nol->nol_timer);
842 			qdf_mem_free(nol);
843 		} else {
844 			WLAN_DFSNOL_UNLOCK(dfs);
845 			break;
846 		}
847 	}
848 }
849 #else
850 #ifdef CONFIG_CHAN_NUM_API
851 void dfs_nol_timer_cleanup(struct wlan_dfs *dfs)
852 {
853 	struct dfs_nolelem *nol;
854 	uint8_t nol_chan;
855 
856 	while (true) {
857 		WLAN_DFSNOL_LOCK(dfs);
858 
859 		nol = dfs->dfs_nol;
860 		if (nol) {
861 			dfs->dfs_nol = nol->nol_next;
862 			dfs->dfs_nol_count--;
863 			nol_chan = utils_dfs_freq_to_chan(nol->nol_freq);
864 			WLAN_DFSNOL_UNLOCK(dfs);
865 			utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
866 						    &nol_chan,
867 						    1,
868 						    DFS_NOL_RESET);
869 
870 			qdf_timer_free(&nol->nol_timer);
871 			qdf_mem_free(nol);
872 		} else {
873 			WLAN_DFSNOL_UNLOCK(dfs);
874 			break;
875 		}
876 	}
877 }
878 #endif
879 #endif
880 
881 void dfs_nol_workqueue_cleanup(struct wlan_dfs *dfs)
882 {
883 	qdf_flush_work(&dfs->dfs_nol_elem_free_work);
884 }
885 
886 int dfs_get_use_nol(struct wlan_dfs *dfs)
887 {
888 	return dfs->dfs_use_nol;
889 }
890 
891 int dfs_get_nol_timeout(struct wlan_dfs *dfs)
892 {
893 	return dfs->wlan_dfs_nol_timeout;
894 }
895 
896 void dfs_getnol(struct wlan_dfs *dfs, void *dfs_nolinfo)
897 {
898 	struct dfsreq_nolinfo *nolinfo = (struct dfsreq_nolinfo *)dfs_nolinfo;
899 
900 	DFS_GET_NOL_LOCKED(dfs, nolinfo->dfs_nol, &(nolinfo->dfs_ch_nchans));
901 }
902 
903 #if !defined(QCA_MCL_DFS_SUPPORT)
904 #ifdef CONFIG_CHAN_FREQ_API
905 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
906 {
907 	struct dfs_channel *chan_list;
908 	int nchans;
909 	bool sta_opmode;
910 	int i;
911 	qdf_freq_t *nol_freq_list = NULL;
912 	int num_nol_history_chans;
913 
914 	if (!dfs->dfs_is_stadfs_enabled)
915 		return;
916 
917 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
918 	if (!sta_opmode)
919 		return;
920 
921 	nchans = dfs_get_num_chans();
922 
923 	if (!nchans) {
924 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
925 		return;
926 	}
927 
928 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
929 	if (!chan_list)
930 		return;
931 
932 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
933 					    (void *)chan_list,
934 					    &num_nol_history_chans);
935 
936 	if (!num_nol_history_chans) {
937 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
938 		qdf_mem_free(chan_list);
939 		return;
940 	}
941 
942 	if (num_nol_history_chans > nchans)
943 		num_nol_history_chans = nchans;
944 
945 	nol_freq_list =
946 		qdf_mem_malloc(num_nol_history_chans * sizeof(qdf_freq_t));
947 
948 	if (!nol_freq_list) {
949 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unable to alloc memory for freq list");
950 		qdf_mem_free(chan_list);
951 		return;
952 	}
953 
954 	for (i = 0; i < num_nol_history_chans; i++)
955 		nol_freq_list[i] = chan_list[i].dfs_ch_freq;
956 
957 	utils_dfs_reg_update_nol_history_chan_for_freq(dfs->dfs_pdev_obj,
958 						       nol_freq_list,
959 						       num_nol_history_chans,
960 						       DFS_NOL_HISTORY_RESET);
961 	qdf_mem_free(chan_list);
962 	qdf_mem_free(nol_freq_list);
963 }
964 #else
965 #ifdef CONFIG_CHAN_NUM_API
966 void dfs_clear_nolhistory(struct wlan_dfs *dfs)
967 {
968 	struct dfs_channel *chan_list;
969 	int nchans;
970 	bool sta_opmode;
971 	int i;
972 	uint8_t *nol_chan_ieee_list = NULL;
973 	int num_nol_history_chans;
974 
975 	if (!dfs->dfs_is_stadfs_enabled)
976 		return;
977 
978 	sta_opmode = dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj);
979 	if (!sta_opmode)
980 		return;
981 
982 	nchans = dfs_get_num_chans();
983 
984 	if (!nchans) {
985 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
986 		return;
987 	}
988 
989 	chan_list = qdf_mem_malloc(nchans * sizeof(*chan_list));
990 	if (!chan_list)
991 		return;
992 
993 	utils_dfs_get_nol_history_chan_list(dfs->dfs_pdev_obj,
994 					    (void *)chan_list,
995 					    &num_nol_history_chans);
996 
997 	if (!num_nol_history_chans) {
998 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "zero chans");
999 		qdf_mem_free(chan_list);
1000 		return;
1001 	}
1002 
1003 	if (num_nol_history_chans > nchans)
1004 		num_nol_history_chans = nchans;
1005 
1006 	nol_chan_ieee_list =
1007 		qdf_mem_malloc(num_nol_history_chans * sizeof(uint8_t));
1008 
1009 	if (!nol_chan_ieee_list) {
1010 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "Unable to alloc memory for ieee list");
1011 		qdf_mem_free(chan_list);
1012 		return;
1013 	}
1014 
1015 	for (i = 0; i < num_nol_history_chans; i++)
1016 		nol_chan_ieee_list[i] = chan_list[i].dfs_ch_ieee;
1017 
1018 	utils_dfs_reg_update_nol_history_ch(dfs->dfs_pdev_obj,
1019 					    nol_chan_ieee_list,
1020 					    num_nol_history_chans,
1021 					    DFS_NOL_HISTORY_RESET);
1022 
1023 	qdf_mem_free(chan_list);
1024 	qdf_mem_free(nol_chan_ieee_list);
1025 }
1026 #endif
1027 #endif
1028 #endif
1029 
1030 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
1031 	defined(CONFIG_CHAN_FREQ_API)
1032 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
1033 {
1034 	struct dfs_nolelem *nol;
1035 	uint16_t freq_list[NUM_CHANNELS_160MHZ];
1036 	int i, nchans = 0;
1037 
1038 	nchans = dfs_get_bonding_channels_for_freq(dfs,
1039 						   &dfs->dfs_radar_found_chan,
1040 						   SEG_ID_PRIMARY,
1041 						   DETECTOR_ID_0,
1042 						   freq_list);
1043 
1044 	WLAN_DFSNOL_LOCK(dfs);
1045 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
1046 		nol = dfs->dfs_nol;
1047 		while (nol) {
1048 			if (nol->nol_freq == freq_list[i]) {
1049 				OS_SET_TIMER(&nol->nol_timer, 0);
1050 				break;
1051 			}
1052 			nol = nol->nol_next;
1053 		}
1054 	}
1055 	WLAN_DFSNOL_UNLOCK(dfs);
1056 
1057 	utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
1058 					     freq_list, nchans, DFS_NOL_RESET);
1059 }
1060 #else
1061 #if defined(WLAN_DFS_PARTIAL_OFFLOAD) && defined(HOST_DFS_SPOOF_TEST) && \
1062 	defined(CONFIG_CHAN_NUM_API)
1063 void dfs_remove_spoof_channel_from_nol(struct wlan_dfs *dfs)
1064 {
1065 	struct dfs_nolelem *nol;
1066 	uint8_t channels[NUM_CHANNELS_160MHZ];
1067 	int i, nchans = 0;
1068 
1069 	nchans = dfs_get_bonding_channels(dfs,
1070 					  &dfs->dfs_radar_found_chan,
1071 					  SEG_ID_PRIMARY,
1072 					  DETECTOR_ID_0,
1073 					  channels);
1074 
1075 	WLAN_DFSNOL_LOCK(dfs);
1076 	for (i = 0; i < nchans && i < NUM_CHANNELS_160MHZ; i++) {
1077 		nol = dfs->dfs_nol;
1078 		while (nol) {
1079 			if (nol->nol_freq == (uint16_t)utils_dfs_chan_to_freq(
1080 				    channels[i])) {
1081 				OS_SET_TIMER(&nol->nol_timer, 0);
1082 				break;
1083 			}
1084 			nol = nol->nol_next;
1085 		}
1086 	}
1087 	WLAN_DFSNOL_UNLOCK(dfs);
1088 
1089 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
1090 				    channels, nchans, DFS_NOL_RESET);
1091 }
1092 #endif
1093 #endif
1094 
1095 void dfs_init_tmp_psoc_nol(struct wlan_dfs *dfs, uint8_t num_radios)
1096 {
1097 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
1098 
1099 	if (WLAN_UMAC_MAX_PDEVS < num_radios) {
1100 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
1101 			"num_radios (%u) exceeds limit", num_radios);
1102 		return;
1103 	}
1104 
1105 	/* Allocate the temporary psoc NOL copy structure for the number
1106 	 * of radios provided.
1107 	 */
1108 	dfs_soc_obj->dfs_psoc_nolinfo =
1109 		qdf_mem_malloc(sizeof(struct dfsreq_nolinfo) * num_radios);
1110 }
1111 
1112 void dfs_deinit_tmp_psoc_nol(struct wlan_dfs *dfs)
1113 {
1114 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
1115 
1116 	if (!dfs_soc_obj->dfs_psoc_nolinfo)
1117 		return;
1118 
1119 	qdf_mem_free(dfs_soc_obj->dfs_psoc_nolinfo);
1120 	dfs_soc_obj->dfs_psoc_nolinfo = NULL;
1121 }
1122 
1123 void dfs_save_dfs_nol_in_psoc(struct wlan_dfs *dfs,
1124 			      uint8_t pdev_id)
1125 {
1126 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
1127 	struct dfsreq_nolinfo tmp_nolinfo, *nolinfo;
1128 	uint32_t i, num_chans = 0;
1129 
1130 	if (!dfs->dfs_nol_count)
1131 		return;
1132 
1133 	if (!dfs_soc_obj->dfs_psoc_nolinfo)
1134 		return;
1135 
1136 	nolinfo = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
1137 	/* Fetch the NOL entries for the DFS object. */
1138 	dfs_getnol(dfs, &tmp_nolinfo);
1139 
1140 	/* nolinfo might already have some data. Do not overwrite it */
1141 	num_chans = nolinfo->dfs_ch_nchans;
1142 	for (i = 0; i < tmp_nolinfo.dfs_ch_nchans; i++) {
1143 		/* Figure out the completed duration of each NOL. */
1144 		uint32_t nol_completed_ms = qdf_do_div(
1145 			qdf_get_monotonic_boottime() -
1146 			tmp_nolinfo.dfs_nol[i].nol_start_us, 1000);
1147 
1148 		nolinfo->dfs_nol[num_chans] = tmp_nolinfo.dfs_nol[i];
1149 		/* Remember the remaining NOL time in the timeout
1150 		 * variable.
1151 		 */
1152 		nolinfo->dfs_nol[num_chans++].nol_timeout_ms -=
1153 			nol_completed_ms;
1154 	}
1155 
1156 	nolinfo->dfs_ch_nchans = num_chans;
1157 }
1158 
1159 void dfs_reinit_nol_from_psoc_copy(struct wlan_dfs *dfs,
1160 				   uint8_t pdev_id,
1161 				   uint16_t low_5ghz_freq,
1162 				   uint16_t high_5ghz_freq)
1163 {
1164 	struct dfs_soc_priv_obj *dfs_soc_obj = dfs->dfs_soc_obj;
1165 	struct dfsreq_nolinfo *nol, req_nol;
1166 	uint8_t i, j = 0;
1167 
1168 	if (!dfs_soc_obj->dfs_psoc_nolinfo)
1169 		return;
1170 
1171 	if (!dfs_soc_obj->dfs_psoc_nolinfo[pdev_id].dfs_ch_nchans)
1172 		return;
1173 
1174 	nol = &dfs_soc_obj->dfs_psoc_nolinfo[pdev_id];
1175 
1176 	for (i = 0; i < nol->dfs_ch_nchans; i++) {
1177 		uint16_t tmp_freq = nol->dfs_nol[i].nol_freq;
1178 
1179 		/* Add to nol only if within the tgt pdev's frequency range. */
1180 		if ((low_5ghz_freq < tmp_freq) && (high_5ghz_freq > tmp_freq)) {
1181 			/* The NOL timeout value in each entry points to the
1182 			 * remaining time of the NOL. This is to indicate that
1183 			 * the NOL entries are paused and are not left to
1184 			 * continue.
1185 			 * While adding these NOL, update the start ticks to
1186 			 * current time to avoid losing entries which might
1187 			 * have timed out during the pause and resume mechanism.
1188 			 */
1189 			nol->dfs_nol[i].nol_start_us =
1190 				qdf_get_monotonic_boottime();
1191 			req_nol.dfs_nol[j++] = nol->dfs_nol[i];
1192 		}
1193 	}
1194 	dfs_set_nol(dfs, req_nol.dfs_nol, j);
1195 }
1196