xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_cac.c (revision fa47688f04ef001a6dcafaebdcc3c031f15ee75e)
1 /*
2  * Copyright (c) 2016-2019 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 "../dfs_etsi_precac.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 
40 #define IS_CHANNEL_WEATHER_RADAR(freq) ((freq >= 5600) && (freq <= 5650))
41 #define ADJACENT_WEATHER_RADAR_CHANNEL   5580
42 #define CH100_START_FREQ                 5490
43 #define CH100                            100
44 
45 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout)
46 {
47 	if (!dfs)
48 		return -EIO;
49 
50 	dfs->dfs_cac_timeout_override = cac_timeout;
51 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d",
52 		(cac_timeout == -1) ? "default" : "overridden",
53 		cac_timeout);
54 
55 	return 0;
56 }
57 
58 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout)
59 {
60 	if (!dfs)
61 		return -EIO;
62 
63 	(*cac_timeout) = dfs->dfs_cac_timeout_override;
64 
65 	return 0;
66 }
67 
68 void dfs_cac_valid_reset(struct wlan_dfs *dfs,
69 		uint8_t prevchan_ieee,
70 		uint32_t prevchan_flags)
71 {
72 	if (dfs->dfs_cac_valid_time) {
73 		if ((prevchan_ieee != dfs->dfs_curchan->dfs_ch_ieee) ||
74 			(prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) {
75 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
76 					"Cancelling timer & clearing cac_valid"
77 					);
78 			qdf_timer_stop(&dfs->dfs_cac_valid_timer);
79 			dfs->dfs_cac_valid = 0;
80 		}
81 	}
82 }
83 
84 /**
85  * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer
86  *                           cac_valid bit will be reset in this function.
87  */
88 static os_timer_func(dfs_cac_valid_timeout)
89 {
90 	struct wlan_dfs *dfs = NULL;
91 
92 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
93 	dfs->dfs_cac_valid = 0;
94 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!");
95 }
96 
97 /**
98  * dfs_cac_timeout() - DFS cactimeout function.
99  *
100  * Sets dfs_cac_timer_running to 0  and dfs_cac_valid_timer.
101  */
102 static os_timer_func(dfs_cac_timeout)
103 {
104 	struct wlan_dfs *dfs = NULL;
105 
106 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
107 	dfs->dfs_cac_timer_running = 0;
108 
109 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d",
110 		dfs->dfs_curchan->dfs_ch_freq,
111 		(qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
112 
113 	/* Once CAC is done, add channel to ETSI precacdone list*/
114 	if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN)
115 		dfs_add_to_etsi_precac_done_list(dfs);
116 
117 	/*
118 	 * When radar is detected during a CAC we are woken up prematurely to
119 	 * switch to a new channel. Check the channel to decide how to act.
120 	 */
121 	if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) {
122 		dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
123 				dfs->dfs_curchan->dfs_ch_ieee,
124 				dfs->dfs_curchan->dfs_ch_freq,
125 				dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
126 				dfs->dfs_curchan->dfs_ch_flags);
127 		dfs_debug(dfs, WLAN_DEBUG_DFS,
128 			"CAC timer on channel %u (%u MHz) stopped due to radar",
129 			dfs->dfs_curchan->dfs_ch_ieee,
130 			dfs->dfs_curchan->dfs_ch_freq);
131 	} else {
132 		dfs_debug(dfs, WLAN_DEBUG_DFS,
133 			"CAC timer on channel %u (%u MHz) expired; no radar detected",
134 			dfs->dfs_curchan->dfs_ch_ieee,
135 			dfs->dfs_curchan->dfs_ch_freq);
136 
137 		/* On CAC completion, set the bit 'cac_valid'.
138 		 * CAC will not be re-done if this bit is reset.
139 		 * The flag will be reset when dfs_cac_valid_timer
140 		 * timesout.
141 		 */
142 		if (dfs->dfs_cac_valid_time) {
143 			dfs->dfs_cac_valid = 1;
144 			qdf_timer_mod(&dfs->dfs_cac_valid_timer,
145 					dfs->dfs_cac_valid_time * 1000);
146 		}
147 	}
148 
149 	/* Iterate over the nodes, processing the CAC completion event. */
150 	dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0);
151 
152 	/* Send a CAC timeout, VAP up event to user space */
153 	dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj);
154 
155 	if (dfs->dfs_defer_precac_channel_change == 1) {
156 		dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj);
157 		dfs->dfs_defer_precac_channel_change = 0;
158 	}
159 }
160 
161 void dfs_cac_timer_init(struct wlan_dfs *dfs)
162 {
163 	qdf_timer_init(NULL,
164 			&(dfs->dfs_cac_timer),
165 			dfs_cac_timeout,
166 			(void *)(dfs),
167 			QDF_TIMER_TYPE_WAKE_APPS);
168 
169 	qdf_timer_init(NULL,
170 			&(dfs->dfs_cac_valid_timer),
171 			dfs_cac_valid_timeout,
172 			(void *)(dfs),
173 			QDF_TIMER_TYPE_WAKE_APPS);
174 }
175 
176 void dfs_cac_attach(struct wlan_dfs *dfs)
177 {
178 	dfs->dfs_cac_timeout_override = -1;
179 	dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS;
180 	dfs_cac_timer_init(dfs);
181 }
182 
183 void dfs_cac_timer_reset(struct wlan_dfs *dfs)
184 {
185 	qdf_timer_stop(&dfs->dfs_cac_timer);
186 	dfs_get_override_cac_timeout(dfs,
187 			&(dfs->dfs_cac_timeout_override));
188 	qdf_mem_zero(&dfs->dfs_cac_started_chan,
189 		     sizeof(dfs->dfs_cac_started_chan));
190 
191 }
192 
193 void dfs_cac_timer_detach(struct wlan_dfs *dfs)
194 {
195 	qdf_timer_free(&dfs->dfs_cac_timer);
196 
197 	qdf_timer_free(&dfs->dfs_cac_valid_timer);
198 	dfs->dfs_cac_valid = 0;
199 }
200 
201 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs)
202 {
203 	return dfs->dfs_cac_timer_running;
204 }
205 
206 void dfs_start_cac_timer(struct wlan_dfs *dfs)
207 {
208 	int cac_timeout = 0;
209 	struct dfs_channel *chan = dfs->dfs_curchan;
210 
211 	cac_timeout = dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj,
212 					       chan->dfs_ch_freq,
213 					       chan->dfs_ch_vhtop_ch_freq_seg2,
214 					       chan->dfs_ch_flags);
215 
216 	dfs->dfs_cac_started_chan = *chan;
217 
218 	dfs_debug(dfs, WLAN_DEBUG_DFS,
219 		  "chan = %d cfreq2 = %d timeout = %d sec, curr_time = %d sec",
220 		  chan->dfs_ch_ieee, chan->dfs_ch_vhtop_ch_freq_seg2,
221 		  cac_timeout,
222 		  qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
223 
224 	qdf_timer_mod(&dfs->dfs_cac_timer, cac_timeout * 1000);
225 	dfs->dfs_cac_aborted = 0;
226 }
227 
228 void dfs_cancel_cac_timer(struct wlan_dfs *dfs)
229 {
230 	qdf_timer_stop(&dfs->dfs_cac_timer);
231 }
232 
233 void dfs_cac_stop(struct wlan_dfs *dfs)
234 {
235 	uint32_t phyerr;
236 
237 	dfs_get_debug_info(dfs, (void *)&phyerr);
238 	dfs_debug(dfs, WLAN_DEBUG_DFS,
239 		"Stopping CAC Timer %d procphyerr 0x%08x",
240 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
241 	qdf_timer_stop(&dfs->dfs_cac_timer);
242 	if (dfs->dfs_cac_timer_running)
243 		dfs->dfs_cac_aborted = 1;
244 	dfs->dfs_cac_timer_running = 0;
245 }
246 
247 void dfs_stacac_stop(struct wlan_dfs *dfs)
248 {
249 	uint32_t phyerr;
250 
251 	dfs_get_debug_info(dfs, (void *)&phyerr);
252 	dfs_debug(dfs, WLAN_DEBUG_DFS,
253 		"Stopping STA CAC Timer %d procphyerr 0x%08x",
254 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
255 }
256 
257 bool dfs_is_subset_channel(struct wlan_dfs *dfs,
258 			   struct dfs_channel *old_chan,
259 			   struct dfs_channel *new_chan)
260 {
261 	uint8_t old_subchans[NUM_CHANNELS_160MHZ];
262 	uint8_t new_subchans[NUM_CHANNELS_160MHZ];
263 	uint8_t old_n_chans;
264 	uint8_t new_n_chans;
265 	int i = 0, j = 0;
266 	bool is_found = false;
267 
268 	if (WLAN_IS_CHAN_11AC_VHT160(old_chan) ||
269 	    WLAN_IS_CHAN_11AC_VHT80_80(old_chan)) {
270 		/* If primary segment is NON-DFS */
271 		if (!WLAN_IS_CHAN_DFS(old_chan))
272 			old_n_chans = dfs_get_bonding_channels(dfs,
273 							       old_chan,
274 							       SEG_ID_SECONDARY,
275 							       old_subchans);
276 		else
277 			old_n_chans = dfs_get_bonding_channels_without_seg_info(
278 					old_chan, old_subchans);
279 	} else {
280 		old_n_chans = dfs_get_bonding_channels_without_seg_info(
281 				old_chan, old_subchans);
282 	}
283 
284 	if (WLAN_IS_CHAN_11AC_VHT160(new_chan) ||
285 	    WLAN_IS_CHAN_11AC_VHT80_80(new_chan)) {
286 		/* If primary segment is NON-DFS */
287 		if (WLAN_IS_CHAN_DFS(new_chan))
288 			new_n_chans = dfs_get_bonding_channels(
289 					dfs, new_chan, SEG_ID_SECONDARY,
290 					new_subchans);
291 		else
292 			new_n_chans = dfs_get_bonding_channels_without_seg_info(
293 					new_chan, new_subchans);
294 	} else {
295 		new_n_chans = dfs_get_bonding_channels_without_seg_info(
296 				new_chan, new_subchans);
297 	}
298 
299 	if (new_n_chans > old_n_chans)
300 		return false;
301 
302 	for (i = 0; i < new_n_chans; i++) {
303 		is_found = false;
304 		for (j = 0; j < old_n_chans; j++) {
305 			if (new_subchans[i] == old_subchans[j]) {
306 				is_found = true;
307 				break;
308 			}
309 		}
310 
311 		/* If new_subchans[i] is not found in old_subchans, then,
312 		 * new_chan is not subset of old_chan.
313 		 */
314 		if (!is_found)
315 			break;
316 	}
317 
318 	return is_found;
319 }
320 
321 bool dfs_is_curchan_subset_of_cac_started_chan(struct wlan_dfs *dfs)
322 {
323 	return dfs_is_subset_channel(dfs, &dfs->dfs_cac_started_chan,
324 				     dfs->dfs_curchan);
325 }
326 
327 void dfs_clear_cac_started_chan(struct wlan_dfs *dfs)
328 {
329 	qdf_mem_zero(&dfs->dfs_cac_started_chan,
330 		     sizeof(dfs->dfs_cac_started_chan));
331 }
332 
333 bool dfs_check_for_cac_start(struct wlan_dfs *dfs,
334 			     bool *continue_current_cac)
335 {
336 	if (dfs->dfs_ignore_dfs || dfs->dfs_cac_valid || dfs->dfs_ignore_cac) {
337 		dfs_debug(dfs, WLAN_DEBUG_DFS,
338 			  "Skip CAC, ignore_dfs = %d cac_valid = %d ignore_cac = %d",
339 			  dfs->dfs_ignore_dfs, dfs->dfs_cac_valid,
340 			  dfs->dfs_ignore_cac);
341 		return false;
342 	}
343 
344 	if (dfs_is_etsi_precac_done(dfs)) {
345 		dfs_debug(dfs, WLAN_DEBUG_DFS,
346 			  "ETSI PRE-CAC alreay done on this channel %d",
347 			  dfs->dfs_curchan->dfs_ch_ieee);
348 		return false;
349 	}
350 
351 	/* If the channel has completed PRE-CAC then CAC can be skipped here. */
352 	if (dfs_is_precac_done(dfs, dfs->dfs_curchan)) {
353 		dfs_debug(dfs, WLAN_DEBUG_DFS,
354 			  "PRE-CAC alreay done on this channel %d",
355 			  dfs->dfs_curchan->dfs_ch_ieee);
356 		return false;
357 	}
358 
359 	if (dfs_is_ap_cac_timer_running(dfs)) {
360 		/* Check if we should continue the existing CAC or
361 		 * cancel the existing CAC.
362 		 * For example: - if an existing VAP(0) is already in
363 		 * DFS wait state (which means the radio(wifi) is
364 		 * running the CAC) and it is in channel A and another
365 		 * VAP(1) comes up in the same channel then instead of
366 		 * cancelling the CAC we can let the CAC continue.
367 		 */
368 		if (dfs_is_curchan_subset_of_cac_started_chan(dfs)) {
369 			*continue_current_cac = true;
370 		} else {
371 			/* New CAC is needed, cancel the running CAC
372 			 * timer.
373 			 * 1) When AP is in DFS_WAIT state and it is in
374 			 *    channel A and user restarts the AP vap in
375 			 *    channel B, then cancel the running CAC in
376 			 *    channel A and start new CAC in channel B.
377 			 *
378 			 * 2) When AP detects the RADAR during CAC in
379 			 *    channel A, it cancels the running CAC and
380 			 *    tries to find channel B with the reduced
381 			 *    bandwidth with of channel A.
382 			 *    In this case, since the CAC is aborted by
383 			 *    the RADAR, AP should start the CAC again.
384 			 */
385 			dfs_cancel_cac_timer(dfs);
386 		}
387 	} else { /* CAC timer is not running. */
388 		if (dfs_is_curchan_subset_of_cac_started_chan(dfs)) {
389 			/* AP bandwidth reduce case:
390 			 * When AP detects the RADAR in in-service monitoring
391 			 * mode in channel A, it cancels the running CAC and
392 			 * tries to find the channel B with the reduced
393 			 * bandwidth of channel A.
394 			 * If the new channel B is subset of the channel A
395 			 * then AP skips the CAC.
396 			 */
397 			if (!dfs->dfs_cac_aborted) {
398 				dfs_debug(dfs, WLAN_DEBUG_DFS, "Skip CAC");
399 				return false;
400 			}
401 		}
402 	}
403 
404 	return true;
405 }
406