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