xref: /wlan-driver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_cac.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
4  * All rights reserved.
5  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /**
29  * DOC: This file has the functions related to DFS CAC.
30  */
31 
32 #include "../dfs_channel.h"
33 #include "../dfs_zero_cac.h"
34 #include <wlan_objmgr_vdev_obj.h>
35 #include "wlan_dfs_utils_api.h"
36 #include "wlan_dfs_mlme_api.h"
37 #include "../dfs_internal.h"
38 #include "../dfs_process_radar_found_ind.h"
39 #ifdef CONFIG_HOST_FIND_CHAN
40 #include <wlan_reg_channel_api.h>
41 #endif
42 
43 #define IS_CHANNEL_WEATHER_RADAR(freq) ((freq >= 5600) && (freq <= 5650))
44 #define ADJACENT_WEATHER_RADAR_CHANNEL   5580
45 #define CH100_START_FREQ                 5490
46 #define CH100                            100
47 
48 /*
49  * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer
50  *                           cac_valid bit will be reset in this function.
51  *
52  * NB: not using kernel-doc format since the kernel-doc script doesn't
53  *     handle the os_timer_func() macro
54  */
os_timer_func(dfs_cac_valid_timeout)55 static os_timer_func(dfs_cac_valid_timeout)
56 {
57 	struct wlan_dfs *dfs = NULL;
58 
59 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
60 	dfs->dfs_cac_valid = 0;
61 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!");
62 }
63 
64 /**
65  * dfs_clear_cac_started_chan() - Clear dfs cac started channel.
66  * @dfs: Pointer to wlan_dfs structure.
67  */
dfs_clear_cac_started_chan(struct wlan_dfs * dfs)68 void dfs_clear_cac_started_chan(struct wlan_dfs *dfs)
69 {
70 	qdf_mem_zero(&dfs->dfs_cac_started_chan,
71 		     sizeof(dfs->dfs_cac_started_chan));
72 }
73 
dfs_clear_nol_history_for_curchan(struct wlan_dfs * dfs)74 static void dfs_clear_nol_history_for_curchan(struct wlan_dfs *dfs)
75 {
76 	struct dfs_channel *chan = dfs->dfs_curchan;
77 	uint16_t sub_channels[MAX_20MHZ_SUBCHANS];
78 	uint8_t num_subchs;
79 
80 	num_subchs = dfs_get_bonding_channel_without_seg_info_for_freq(
81 				chan, sub_channels);
82 
83 	if (dfs->dfs_is_stadfs_enabled)
84 		if (dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj))
85 			utils_dfs_reg_update_nol_history_chan_for_freq(
86 				dfs->dfs_pdev_obj, sub_channels,
87 				num_subchs, DFS_NOL_HISTORY_RESET);
88 }
89 
90 #if defined(QCA_SUPPORT_DFS_CAC) && defined(WLAN_FEATURE_11BE)
dfs_is_radar_on_punc_chan(struct wlan_dfs * dfs,struct dfs_channel * chan)91 bool dfs_is_radar_on_punc_chan(struct wlan_dfs *dfs, struct dfs_channel *chan)
92 {
93 	qdf_freq_t sub_freq_list[MAX_20MHZ_SUBCHANS];
94 	uint8_t n_subchans, i;
95 	uint16_t radar_punc_bitmap = NO_SCHANS_PUNC;
96 
97 	if (!chan || !WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(chan))
98 		return false;
99 
100 	n_subchans = dfs_get_bonding_channel_without_seg_info_for_freq(
101 				chan,
102 				sub_freq_list);
103 
104 	for (i = 0; i < n_subchans; i++) {
105 		if (wlan_reg_is_nol_for_freq(dfs->dfs_pdev_obj,
106 					     sub_freq_list[i]))
107 			radar_punc_bitmap |=  1 << i;
108 	}
109 	return ((radar_punc_bitmap & chan->dfs_ch_punc_pattern) ==
110 		 radar_punc_bitmap);
111 }
112 #else
113 static inline bool
dfs_is_radar_on_punc_chan(struct wlan_dfs * dfs,struct dfs_channel * chan)114 dfs_is_radar_on_punc_chan(struct wlan_dfs *dfs, struct dfs_channel *chan)
115 {
116 	return false;
117 }
118 #endif
119 
dfs_process_cac_completion(struct wlan_dfs * dfs)120 void dfs_process_cac_completion(struct wlan_dfs *dfs)
121 {
122 	enum phy_ch_width ch_width = CH_WIDTH_INVALID;
123 	uint16_t primary_chan_freq = 0, sec_chan_freq = 0;
124 	struct dfs_channel *dfs_curchan;
125 
126 	dfs->dfs_cac_timer_running = 0;
127 	dfs_curchan = dfs->dfs_curchan;
128 
129 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d cur time %d",
130 		 dfs->dfs_curchan->dfs_ch_freq,
131 		 (qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
132 
133 	/*
134 	 * When radar is detected during a CAC we are woken up prematurely to
135 	 * switch to a new channel. Check the channel to decide how to act.
136 	 */
137 	if (WLAN_IS_CHAN_RADAR(dfs, dfs->dfs_curchan) &&
138 	    !dfs_is_radar_on_punc_chan(dfs, dfs->dfs_curchan)) {
139 		dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
140 				  dfs_curchan->dfs_ch_ieee,
141 				  dfs_curchan->dfs_ch_freq,
142 				  dfs_curchan->dfs_ch_mhz_freq_seg2,
143 				  dfs_curchan->dfs_ch_flags,
144 				  0);
145 		dfs_debug(dfs, WLAN_DEBUG_DFS,
146 			  "CAC timer on chan %u (%u MHz) stopped due to radar",
147 			  dfs_curchan->dfs_ch_ieee,
148 			  dfs_curchan->dfs_ch_freq);
149 	} else {
150 		dfs_debug(dfs, WLAN_DEBUG_DFS,
151 			  "CAC timer on channel %u (%u MHz) expired;"
152 			  "no radar detected",
153 			  dfs_curchan->dfs_ch_ieee,
154 			  dfs_curchan->dfs_ch_freq);
155 
156 		/* On CAC completion, set the bit 'cac_valid'.
157 		 * CAC will not be re-done if this bit is reset.
158 		 * The flag will be reset when dfs_cac_valid_timer
159 		 * timesout.
160 		 */
161 		if (dfs->dfs_cac_valid_time) {
162 			dfs->dfs_cac_valid = 1;
163 			qdf_timer_mod(&dfs->dfs_cac_valid_timer,
164 				      dfs->dfs_cac_valid_time * 1000);
165 		}
166 
167 		dfs_find_curchwidth_and_center_chan_for_freq(dfs,
168 							     &ch_width,
169 							     &primary_chan_freq,
170 							     &sec_chan_freq);
171 
172 		/* ETSI allows the driver to cache the CAC ( Once CAC done,
173 		 * it can be used in future).
174 		 * Therefore mark the current channel CAC done.
175 		 */
176 		if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN)
177 			dfs_mark_precac_done_for_freq(dfs,
178 						      primary_chan_freq,
179 						      sec_chan_freq,
180 						      ch_width);
181 	}
182 
183 	dfs_update_cac_elements(dfs, NULL, 0, dfs->dfs_curchan, WLAN_EV_CAC_COMPLETED);
184 
185 	dfs_clear_cac_started_chan(dfs);
186 
187 	/* Clear NOL history for current channel on successful CAC completion */
188 	dfs_clear_nol_history_for_curchan(dfs);
189 	/* Iterate over the nodes, processing the CAC completion event. */
190 	dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0);
191 
192 	/* Send a CAC timeout, VAP up event to user space */
193 	dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj);
194 
195 	if (dfs->dfs_defer_precac_channel_change == 1) {
196 		dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj);
197 		dfs->dfs_defer_precac_channel_change = 0;
198 	}
199 }
200 
201 /**
202  * dfs_cac_timeout() - DFS cactimeout function.
203  * @arg: Container of dfs object.
204  *
205  * Sets dfs_cac_timer_running to 0  and dfs_cac_valid_timer.
206  */
207 #ifdef CONFIG_CHAN_FREQ_API
208 static enum qdf_hrtimer_restart_status
dfs_cac_timeout(qdf_hrtimer_data_t * arg)209 dfs_cac_timeout(qdf_hrtimer_data_t *arg)
210 {
211 	struct wlan_dfs *dfs;
212 
213 	dfs = container_of(arg, struct wlan_dfs, dfs_cac_timer);
214 
215 	if (dfs_is_hw_mode_switch_in_progress(dfs))
216 		dfs->dfs_defer_params.is_cac_completed = true;
217 	else
218 		dfs_process_cac_completion(dfs);
219 
220 	return QDF_HRTIMER_NORESTART;
221 }
222 #endif
223 
224 #ifdef QCA_SUPPORT_DFS_CAC
dfs_cac_timer_attach(struct wlan_dfs * dfs)225 void dfs_cac_timer_attach(struct wlan_dfs *dfs)
226 {
227 	dfs->dfs_cac_timeout_override = -1;
228 	dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS;
229 	qdf_hrtimer_init(&dfs->dfs_cac_timer,
230 			 dfs_cac_timeout,
231 			 QDF_CLOCK_MONOTONIC,
232 			 QDF_HRTIMER_MODE_REL,
233 			 QDF_CONTEXT_TASKLET);
234 	qdf_timer_init(NULL,
235 			&(dfs->dfs_cac_valid_timer),
236 			dfs_cac_valid_timeout,
237 			(void *)(dfs),
238 			QDF_TIMER_TYPE_WAKE_APPS);
239 }
240 
dfs_cac_timer_reset(struct wlan_dfs * dfs)241 void dfs_cac_timer_reset(struct wlan_dfs *dfs)
242 {
243 	qdf_hrtimer_cancel(&dfs->dfs_cac_timer);
244 	dfs_get_override_cac_timeout(dfs,
245 			&(dfs->dfs_cac_timeout_override));
246 	dfs_update_cac_elements(dfs, NULL, 0, dfs->dfs_curchan, WLAN_EV_CAC_RESET);
247 	dfs_clear_cac_started_chan(dfs);
248 }
249 
dfs_cac_timer_detach(struct wlan_dfs * dfs)250 void dfs_cac_timer_detach(struct wlan_dfs *dfs)
251 {
252 	qdf_hrtimer_kill(&dfs->dfs_cac_timer);
253 	qdf_timer_free(&dfs->dfs_cac_valid_timer);
254 	dfs->dfs_cac_valid = 0;
255 }
256 
257 #if defined(QCA_DFS_BW_PUNCTURE) && !defined(CONFIG_REG_CLIENT)
dfs_puncture_cac_timer_detach(struct wlan_dfs * dfs)258 void dfs_puncture_cac_timer_detach(struct wlan_dfs *dfs)
259 {
260 	uint8_t i;
261 	struct dfs_punc_obj *dfs_punc_obj;
262 
263 	for (i = 0 ; i < N_MAX_PUNC_SM; i++) {
264 		dfs_punc_obj = &dfs->dfs_punc_lst.dfs_punc_arr[i];
265 		dfs_punc_cac_timer_detach(dfs_punc_obj);
266 	}
267 }
268 #endif
269 
dfs_is_ap_cac_timer_running(struct wlan_dfs * dfs)270 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs)
271 {
272 	return dfs->dfs_cac_timer_running;
273 }
274 
275 #ifdef CONFIG_CHAN_FREQ_API
dfs_start_cac_timer(struct wlan_dfs * dfs)276 void dfs_start_cac_timer(struct wlan_dfs *dfs)
277 {
278 	int cac_timeout = 0;
279 	struct dfs_channel *chan = dfs->dfs_curchan;
280 
281 	cac_timeout =
282 	    dfs_mlme_get_cac_timeout_for_freq(dfs->dfs_pdev_obj,
283 					      chan->dfs_ch_freq,
284 					      chan->dfs_ch_mhz_freq_seg2,
285 					      chan->dfs_ch_flags);
286 
287 	dfs->dfs_cac_started_chan = *chan;
288 
289 	dfs_deliver_cac_state_events(dfs);
290 	dfs_debug(dfs, WLAN_DEBUG_DFS,
291 		  "chan = %d cfreq2 = %d timeout = %d sec, curr_time = %d sec",
292 		  chan->dfs_ch_ieee, chan->dfs_ch_vhtop_ch_freq_seg2,
293 		  cac_timeout,
294 		  qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
295 
296 	qdf_hrtimer_start(&dfs->dfs_cac_timer,
297 			  qdf_time_ms_to_ktime(cac_timeout * 1000),
298 			  QDF_HRTIMER_MODE_REL);
299 	dfs->dfs_cac_aborted = 0;
300 }
301 #endif
302 
dfs_cancel_cac_timer(struct wlan_dfs * dfs)303 void dfs_cancel_cac_timer(struct wlan_dfs *dfs)
304 {
305 	qdf_hrtimer_cancel(&dfs->dfs_cac_timer);
306 	dfs_update_cac_elements(dfs, NULL, 0, dfs->dfs_curchan, WLAN_EV_CAC_RESET);
307 	dfs_clear_cac_started_chan(dfs);
308 }
309 
dfs_send_dfs_events_for_chan(struct wlan_dfs * dfs,struct dfs_channel * chan,enum WLAN_DFS_EVENTS event)310 void dfs_send_dfs_events_for_chan(struct wlan_dfs *dfs,
311 				  struct dfs_channel *chan,
312 				  enum WLAN_DFS_EVENTS event)
313 {
314 	uint8_t nchannels, i;
315 	qdf_freq_t freq_list[MAX_20MHZ_SUBCHANS];
316 
317 	nchannels =
318 		dfs_get_bonding_channel_without_seg_info_for_freq(chan,
319 								  freq_list);
320 
321 	/* If radar is found during CAC period, CAC cancel is invoked and hence
322 	 * dfs_cac_stop posts WLAN_EV_CAC_RESET. However, since the channel is
323 	 * radar infected and is added to the NOL, the most appropriate state of
324 	 * the channel should be WLAN_EV_NOL_STARTED.
325 	 * After NOL timeout, WLAN_EV_CAC_RESET should be posted.
326 	 */
327 	for (i = 0; i < nchannels; i++) {
328 		if (wlan_reg_is_nol_for_freq(dfs->dfs_pdev_obj, freq_list[i]))
329 			event = WLAN_EV_NOL_STARTED;
330 		utils_dfs_deliver_event(dfs->dfs_pdev_obj,
331 					freq_list[i],
332 					event);
333 	}
334 }
335 
dfs_cac_stop(struct wlan_dfs * dfs)336 void dfs_cac_stop(struct wlan_dfs *dfs)
337 {
338 	uint32_t phyerr;
339 	struct dfs_channel *chan;
340 
341 	chan = &dfs->dfs_cac_started_chan;
342 	dfs_get_debug_info(dfs, (void *)&phyerr);
343 	dfs_debug(dfs, WLAN_DEBUG_DFS,
344 		"Stopping CAC Timer %d procphyerr 0x%08x",
345 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
346 	qdf_hrtimer_cancel(&dfs->dfs_cac_timer);
347 
348 	dfs_send_dfs_events_for_chan(dfs, chan, WLAN_EV_CAC_RESET);
349 	dfs_update_cac_elements(dfs, NULL, 0, chan, WLAN_EV_CAC_RESET);
350 
351 	if (dfs->dfs_cac_timer_running)
352 		dfs->dfs_cac_aborted = 1;
353 	dfs_clear_cac_started_chan(dfs);
354 	dfs->dfs_cac_timer_running = 0;
355 }
356 
dfs_stacac_stop(struct wlan_dfs * dfs)357 void dfs_stacac_stop(struct wlan_dfs *dfs)
358 {
359 	uint32_t phyerr;
360 
361 	dfs_get_debug_info(dfs, (void *)&phyerr);
362 	dfs_debug(dfs, WLAN_DEBUG_DFS,
363 		"Stopping STA CAC Timer %d procphyerr 0x%08x",
364 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
365 	dfs_clear_cac_started_chan(dfs);
366 }
367 
dfs_override_cac_timeout(struct wlan_dfs * dfs,int cac_timeout)368 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout)
369 {
370 	if (!dfs)
371 		return -EIO;
372 
373 	dfs->dfs_cac_timeout_override = cac_timeout;
374 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d",
375 		 (cac_timeout == -1) ? "default" : "overridden",
376 		 cac_timeout);
377 
378 	return 0;
379 }
380 
dfs_get_override_cac_timeout(struct wlan_dfs * dfs,int * cac_timeout)381 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout)
382 {
383 	if (!dfs)
384 		return -EIO;
385 
386 	(*cac_timeout) = dfs->dfs_cac_timeout_override;
387 
388 	return 0;
389 }
390 
391 #ifdef CONFIG_CHAN_FREQ_API
dfs_cac_valid_reset_for_freq(struct wlan_dfs * dfs,uint16_t prevchan_freq,uint32_t prevchan_flags)392 void dfs_cac_valid_reset_for_freq(struct wlan_dfs *dfs,
393 				  uint16_t prevchan_freq,
394 				  uint32_t prevchan_flags)
395 {
396 	if (dfs->dfs_cac_valid_time) {
397 		if ((prevchan_freq != dfs->dfs_curchan->dfs_ch_freq) ||
398 		    (prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) {
399 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
400 				"Cancelling timer & clearing cac_valid");
401 			qdf_timer_stop(&dfs->dfs_cac_valid_timer);
402 			dfs->dfs_cac_valid = 0;
403 		}
404 	}
405 }
406 #endif
407 #endif
408 
409 #ifdef CONFIG_CHAN_FREQ_API
410 bool
dfs_is_subset_channel_for_freq(uint16_t * old_subchans_freq,uint8_t old_n_chans,uint16_t * new_subchans_freq,uint8_t new_n_chans)411 dfs_is_subset_channel_for_freq(uint16_t *old_subchans_freq,
412 			       uint8_t old_n_chans,
413 			       uint16_t *new_subchans_freq,
414 			       uint8_t new_n_chans)
415 {
416 	bool is_found;
417 	int i, j;
418 
419 	if (!new_n_chans)
420 		return true;
421 
422 	if (new_n_chans > old_n_chans)
423 		return false;
424 
425 	for (i = 0; i < new_n_chans; i++) {
426 		is_found = false;
427 		for (j = 0; j < old_n_chans; j++) {
428 			if (new_subchans_freq[i] == old_subchans_freq[j]) {
429 				is_found = true;
430 				break;
431 			}
432 		}
433 
434 		/* If new_subchans[i] is not found in old_subchans, then,
435 		 * new_chan is not subset of old_chan.
436 		 */
437 		if (!is_found)
438 			break;
439 	}
440 
441 	return is_found;
442 }
443 #endif
444 
445 #ifdef CONFIG_CHAN_FREQ_API
446 uint8_t
dfs_find_dfs_sub_channels_for_freq(struct wlan_dfs * dfs,struct dfs_channel * chan,uint16_t * subchan_arr)447 dfs_find_dfs_sub_channels_for_freq(struct wlan_dfs *dfs,
448 				   struct dfs_channel *chan,
449 				   uint16_t *subchan_arr)
450 {
451 	if (WLAN_IS_CHAN_MODE_160(chan) || WLAN_IS_CHAN_MODE_80_80(chan)) {
452 		if (WLAN_IS_CHAN_DFS(chan) && WLAN_IS_CHAN_DFS_CFREQ2(chan))
453 			return dfs_get_bonding_channel_without_seg_info_for_freq
454 				(chan, subchan_arr);
455 		if (WLAN_IS_CHAN_DFS(chan))
456 			return dfs_get_bonding_channels_for_freq(dfs,
457 								 chan,
458 								 SEG_ID_PRIMARY,
459 								 DETECTOR_ID_0,
460 								 subchan_arr);
461 		if (WLAN_IS_CHAN_DFS_CFREQ2(chan))
462 			return dfs_get_bonding_channels_for_freq
463 				(dfs, chan, SEG_ID_SECONDARY,
464 				 DETECTOR_ID_0, subchan_arr);
465 		/* All channels in 160/80_80 BW are non DFS, return 0
466 		 * as number of subchannels
467 		 */
468 		return 0;
469 	} else if (WLAN_IS_CHAN_DFS(chan)) {
470 		return dfs_get_bonding_channel_without_seg_info_for_freq
471 			(chan, subchan_arr);
472 	}
473 	/* All channels are non DFS, return 0 as number of subchannels*/
474 	return 0;
475 }
476 #endif
477 
478 #ifdef CONFIG_CHAN_FREQ_API
479 bool
dfs_is_new_chan_subset_of_old_chan(struct wlan_dfs * dfs,struct dfs_channel * new_chan,struct dfs_channel * old_chan)480 dfs_is_new_chan_subset_of_old_chan(struct wlan_dfs *dfs,
481 				   struct dfs_channel *new_chan,
482 				   struct dfs_channel *old_chan)
483 {
484 	uint16_t new_subchans[MAX_20MHZ_SUBCHANS];
485 	uint16_t old_subchans[MAX_20MHZ_SUBCHANS];
486 	uint8_t n_new_subchans = 0;
487 	uint8_t n_old_subchans = 0;
488 
489 	/* Given channel is the old channel. i.e. The channel which
490 	 * should have the new channel as subset.
491 	 */
492 	n_old_subchans = dfs_find_dfs_sub_channels_for_freq(dfs, old_chan,
493 							    old_subchans);
494 	/* cur_chan is the new channel to be check if subset of old channel */
495 	n_new_subchans = dfs_find_dfs_sub_channels_for_freq(dfs, new_chan,
496 							    new_subchans);
497 
498 	return dfs_is_subset_channel_for_freq(old_subchans,
499 					      n_old_subchans,
500 					      new_subchans,
501 					      n_new_subchans);
502 }
503 #endif
504 
505 #ifdef QCA_SUPPORT_DFS_CAC
dfs_is_cac_required(struct wlan_dfs * dfs,struct dfs_channel * cur_chan,struct dfs_channel * prev_chan,bool * continue_current_cac,bool is_vap_restart)506 bool dfs_is_cac_required(struct wlan_dfs *dfs,
507 			 struct dfs_channel *cur_chan,
508 			 struct dfs_channel *prev_chan,
509 			 bool *continue_current_cac,
510 			 bool is_vap_restart)
511 {
512 	struct dfs_channel *cac_started_chan = &dfs->dfs_cac_started_chan;
513 
514 	if (!WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(cur_chan)) {
515 		dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC on non-DFS channel");
516 		return false;
517 	}
518 
519 	if (dfs->dfs_ignore_dfs || dfs->dfs_cac_valid || dfs->dfs_ignore_cac) {
520 		dfs_debug(dfs, WLAN_DEBUG_DFS,
521 			  "Skip CAC, ignore_dfs = %d cac_valid = %d ignore_cac = %d",
522 			  dfs->dfs_ignore_dfs, dfs->dfs_cac_valid,
523 			  dfs->dfs_ignore_cac);
524 		return false;
525 	}
526 
527 	/* In case of RCAC, check if CAC is completed only on the RCAC channel
528 	 * and do not check the CAC info on current operating channel.
529 	 */
530 	if (dfs_is_agile_rcac_enabled(dfs) &&
531 	    dfs_is_rcac_cac_done(dfs, cur_chan, prev_chan))
532 		return false;
533 
534 	/* If the channel has completed PRE-CAC then CAC can be skipped here. */
535 	if (dfs_is_precac_done(dfs, cur_chan)) {
536 		dfs_debug(dfs, WLAN_DEBUG_DFS,
537 			  "PRE-CAC already done on this channel %d",
538 			  cur_chan->dfs_ch_ieee);
539 		return false;
540 	}
541 
542 	if (dfs_is_ap_cac_timer_running(dfs)) {
543 		/* Check if we should continue the existing CAC or
544 		 * cancel the existing CAC.
545 		 * For example: - if an existing VAP(0) is already in
546 		 * DFS wait state (which means the radio(wifi) is
547 		 * running the CAC) and it is in channel A and another
548 		 * VAP(1) comes up in the same channel then instead of
549 		 * cancelling the CAC we can let the CAC continue.
550 		 */
551 		if (dfs_is_new_chan_subset_of_old_chan(dfs,
552 						       cur_chan,
553 						       cac_started_chan)) {
554 			if (continue_current_cac)
555 				*continue_current_cac = true;
556 		} else {
557 			/* New CAC is needed, cancel the running CAC
558 			 * timer.
559 			 * 1) When AP is in DFS_WAIT state and it is in
560 			 *    channel A and user restarts the AP vap in
561 			 *    channel B, then cancel the running CAC in
562 			 *    channel A and start new CAC in channel B.
563 			 *
564 			 * 2) When AP detects the RADAR during CAC in
565 			 *    channel A, it cancels the running CAC and
566 			 *    tries to find channel B with the reduced
567 			 *    bandwidth with of channel A.
568 			 *    In this case, since the CAC is aborted by
569 			 *    the RADAR, AP should start the CAC again.
570 			 */
571 			dfs_cancel_cac_timer(dfs);
572 		}
573 	} else { /* CAC timer is not running. */
574 		/* If channel change happens via VAP DOWN/UP on subset channels,
575 		 * (eg: from 52 HT80 to 64 HT80) CAC done information
576 		 * (of 52 HT80) based on subset logic
577 		 * (as 52 and 64 HT80 are subsets of each other)
578 		 * is not expected to be preserved as VAP has come up
579 		 * from DOWN state. Hence do not skip CAC on 64 HT80.
580 		 * is_vap_restart flag is used as an identifier to indicate if
581 		 * vap has come up from a DOWN state or UP state (vap restart).
582 		 */
583 		if (!is_vap_restart) {
584 			dfs_debug(dfs, WLAN_DEBUG_DFS, "CAC is needed");
585 			return true;
586 		}
587 		if (dfs_is_new_chan_subset_of_old_chan(dfs,
588 						       cur_chan,
589 						       prev_chan)) {
590 			/* AP bandwidth reduce case:
591 			 * When AP detects the RADAR in in-service monitoring
592 			 * mode in channel A, it cancels the running CAC and
593 			 * tries to find the channel B with the reduced
594 			 * bandwidth of channel A.
595 			 * If the new channel B is subset of the channel A
596 			 * then AP skips the CAC.
597 			 */
598 			if (!dfs->dfs_cac_aborted) {
599 				dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC");
600 				return false;
601 			}
602 		}
603 	}
604 
605 	return true;
606 }
607 #endif
608