xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_cac.c (revision 8b7e2ee3720101d16dde046b0345f866abb7a5d8)
1 /*
2  * Copyright (c) 2016-2018 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_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 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout)
45 {
46 	if (!dfs)
47 		return -EIO;
48 
49 	dfs->dfs_cac_timeout_override = cac_timeout;
50 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d",
51 		(cac_timeout == -1) ? "default" : "overridden",
52 		cac_timeout);
53 
54 	return 0;
55 }
56 
57 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout)
58 {
59 	if (!dfs)
60 		return -EIO;
61 
62 	(*cac_timeout) = dfs->dfs_cac_timeout_override;
63 
64 	return 0;
65 }
66 
67 void dfs_cac_valid_reset(struct wlan_dfs *dfs,
68 		uint8_t prevchan_ieee,
69 		uint32_t prevchan_flags)
70 {
71 	if (dfs->dfs_cac_valid_time) {
72 		if ((prevchan_ieee != dfs->dfs_curchan->dfs_ch_ieee) ||
73 			(prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) {
74 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
75 					"Cancelling timer & clearing cac_valid"
76 					);
77 			qdf_timer_stop(&dfs->dfs_cac_valid_timer);
78 			dfs->dfs_cac_valid = 0;
79 		}
80 	}
81 }
82 
83 /**
84  * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer
85  *                           cac_valid bit will be reset in this function.
86  */
87 static os_timer_func(dfs_cac_valid_timeout)
88 {
89 	struct wlan_dfs *dfs = NULL;
90 
91 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
92 	dfs->dfs_cac_valid = 0;
93 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!");
94 }
95 
96 /**
97  * dfs_cac_timeout() - DFS cactimeout function.
98  *
99  * Sets dfs_cac_timer_running to 0  and dfs_cac_valid_timer.
100  */
101 static os_timer_func(dfs_cac_timeout)
102 {
103 	struct wlan_dfs *dfs = NULL;
104 
105 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
106 	dfs->dfs_cac_timer_running = 0;
107 
108 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d",
109 		dfs->dfs_curchan->dfs_ch_freq,
110 		(qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
111 
112 	/* Once CAC is done, add channel to ETSI precacdone list*/
113 	if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN)
114 		dfs_add_to_etsi_precac_done_list(dfs);
115 
116 	/*
117 	 * When radar is detected during a CAC we are woken up prematurely to
118 	 * switch to a new channel. Check the channel to decide how to act.
119 	 */
120 	if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) {
121 		dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
122 				dfs->dfs_curchan->dfs_ch_ieee,
123 				dfs->dfs_curchan->dfs_ch_freq,
124 				dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
125 				dfs->dfs_curchan->dfs_ch_flags);
126 		dfs_debug(dfs, WLAN_DEBUG_DFS,
127 			"CAC timer on channel %u (%u MHz) stopped due to radar",
128 			dfs->dfs_curchan->dfs_ch_ieee,
129 			dfs->dfs_curchan->dfs_ch_freq);
130 	} else {
131 		dfs_debug(dfs, WLAN_DEBUG_DFS,
132 			"CAC timer on channel %u (%u MHz) expired; no radar detected",
133 			dfs->dfs_curchan->dfs_ch_ieee,
134 			dfs->dfs_curchan->dfs_ch_freq);
135 
136 		/* On CAC completion, set the bit 'cac_valid'.
137 		 * CAC will not be re-done if this bit is reset.
138 		 * The flag will be reset when dfs_cac_valid_timer
139 		 * timesout.
140 		 */
141 		if (dfs->dfs_cac_valid_time) {
142 			dfs->dfs_cac_valid = 1;
143 			qdf_timer_mod(&dfs->dfs_cac_valid_timer,
144 					dfs->dfs_cac_valid_time * 1000);
145 		}
146 	}
147 
148 	/* Iterate over the nodes, processing the CAC completion event. */
149 	dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0);
150 
151 	/* Send a CAC timeout, VAP up event to user space */
152 	dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj);
153 
154 	if (dfs->dfs_defer_precac_channel_change == 1) {
155 		dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj);
156 		dfs->dfs_defer_precac_channel_change = 0;
157 	}
158 }
159 
160 void dfs_cac_timer_init(struct wlan_dfs *dfs)
161 {
162 	qdf_timer_init(NULL,
163 			&(dfs->dfs_cac_timer),
164 			dfs_cac_timeout,
165 			(void *)(dfs),
166 			QDF_TIMER_TYPE_WAKE_APPS);
167 
168 	qdf_timer_init(NULL,
169 			&(dfs->dfs_cac_valid_timer),
170 			dfs_cac_valid_timeout,
171 			(void *)(dfs),
172 			QDF_TIMER_TYPE_WAKE_APPS);
173 }
174 
175 void dfs_cac_attach(struct wlan_dfs *dfs)
176 {
177 	dfs->dfs_cac_timeout_override = -1;
178 	dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS;
179 	dfs_cac_timer_init(dfs);
180 }
181 
182 void dfs_cac_timer_reset(struct wlan_dfs *dfs)
183 {
184 	qdf_timer_stop(&dfs->dfs_cac_timer);
185 	dfs_get_override_cac_timeout(dfs,
186 			&(dfs->dfs_cac_timeout_override));
187 	qdf_mem_zero(&dfs->dfs_cac_started_chan,
188 		     sizeof(dfs->dfs_cac_started_chan));
189 
190 }
191 
192 void dfs_cac_timer_detach(struct wlan_dfs *dfs)
193 {
194 	qdf_timer_free(&dfs->dfs_cac_timer);
195 
196 	qdf_timer_free(&dfs->dfs_cac_valid_timer);
197 	dfs->dfs_cac_valid = 0;
198 }
199 
200 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs)
201 {
202 	return dfs->dfs_cac_timer_running;
203 }
204 
205 void dfs_start_cac_timer(struct wlan_dfs *dfs)
206 {
207 	int cac_timeout = 0;
208 	struct dfs_channel *chan = dfs->dfs_curchan;
209 
210 	cac_timeout = dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj,
211 					       chan->dfs_ch_freq,
212 					       chan->dfs_ch_vhtop_ch_freq_seg2,
213 					       chan->dfs_ch_flags);
214 
215 	dfs->dfs_cac_started_chan = *chan;
216 
217 	dfs_debug(dfs, WLAN_DEBUG_DFS,
218 		  "chan = %d cfreq2 = %d timeout = %d sec, curr_time = %d sec",
219 		  chan->dfs_ch_ieee, chan->dfs_ch_vhtop_ch_freq_seg2,
220 		  cac_timeout,
221 		  qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000);
222 
223 	qdf_timer_mod(&dfs->dfs_cac_timer, cac_timeout * 1000);
224 	dfs->dfs_cac_aborted = 0;
225 }
226 
227 void dfs_cancel_cac_timer(struct wlan_dfs *dfs)
228 {
229 	qdf_timer_stop(&dfs->dfs_cac_timer);
230 }
231 
232 void dfs_cac_stop(struct wlan_dfs *dfs)
233 {
234 	uint32_t phyerr;
235 
236 	dfs_get_debug_info(dfs, (void *)&phyerr);
237 	dfs_debug(dfs, WLAN_DEBUG_DFS,
238 		"Stopping CAC Timer %d procphyerr 0x%08x",
239 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
240 	qdf_timer_stop(&dfs->dfs_cac_timer);
241 	if (dfs->dfs_cac_timer_running)
242 		dfs->dfs_cac_aborted = 1;
243 	dfs->dfs_cac_timer_running = 0;
244 }
245 
246 void dfs_stacac_stop(struct wlan_dfs *dfs)
247 {
248 	uint32_t phyerr;
249 
250 	dfs_get_debug_info(dfs, (void *)&phyerr);
251 	dfs_debug(dfs, WLAN_DEBUG_DFS,
252 		"Stopping STA CAC Timer %d procphyerr 0x%08x",
253 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
254 }
255 
256 bool dfs_is_subset_channel(struct dfs_channel *old_chan,
257 			   struct dfs_channel *new_chan)
258 {
259 	uint8_t old_subchans[NUM_CHANNELS_160MHZ];
260 	uint8_t new_subchans[NUM_CHANNELS_160MHZ];
261 	uint8_t old_n_chans;
262 	uint8_t new_n_chans;
263 	int i = 0, j = 0;
264 	bool is_found = false;
265 
266 	if (WLAN_IS_CHAN_11AC_VHT160(old_chan) ||
267 	    WLAN_IS_CHAN_11AC_VHT80_80(old_chan)) {
268 		/* If primary segment is NON-DFS */
269 		if (!WLAN_IS_CHAN_DFS(old_chan))
270 			old_n_chans = dfs_get_bonding_channels(old_chan,
271 							       SEG_ID_SECONDARY,
272 							       old_subchans);
273 		else
274 			old_n_chans = dfs_get_bonding_channels_without_seg_info(
275 					old_chan, old_subchans);
276 	} else {
277 		old_n_chans = dfs_get_bonding_channels_without_seg_info(
278 				old_chan, old_subchans);
279 	}
280 
281 	if (WLAN_IS_CHAN_11AC_VHT160(new_chan) ||
282 	    WLAN_IS_CHAN_11AC_VHT80_80(new_chan)) {
283 		/* If primary segment is NON-DFS */
284 		if (WLAN_IS_CHAN_DFS(new_chan))
285 			new_n_chans = dfs_get_bonding_channels(
286 					new_chan, SEG_ID_SECONDARY,
287 					new_subchans);
288 		else
289 			new_n_chans = dfs_get_bonding_channels_without_seg_info(
290 					new_chan, new_subchans);
291 	} else {
292 		new_n_chans = dfs_get_bonding_channels_without_seg_info(
293 				new_chan, new_subchans);
294 	}
295 
296 	if (new_n_chans > old_n_chans)
297 		return false;
298 
299 	for (i = 0; i < new_n_chans; i++) {
300 		is_found = false;
301 		for (j = 0; j < old_n_chans; j++) {
302 			if (new_subchans[i] == old_subchans[j]) {
303 				is_found = true;
304 				break;
305 			}
306 		}
307 
308 		/* If new_subchans[i] is not found in old_subchans, then,
309 		 * new_chan is not subset of old_chan.
310 		 */
311 		if (!is_found)
312 			break;
313 	}
314 
315 	return is_found;
316 }
317 
318 bool dfs_is_curchan_subset_of_cac_started_chan(struct wlan_dfs *dfs)
319 {
320 	return dfs_is_subset_channel(&dfs->dfs_cac_started_chan,
321 				     dfs->dfs_curchan);
322 }
323 
324 void dfs_clear_cac_started_chan(struct wlan_dfs *dfs)
325 {
326 	qdf_mem_zero(&dfs->dfs_cac_started_chan,
327 		     sizeof(dfs->dfs_cac_started_chan));
328 }
329