xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_cac.c (revision 87a8e4458319c60b618522e263ed900e36aab528)
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 
38 #define IS_CHANNEL_WEATHER_RADAR(freq) ((freq >= 5600) && (freq <= 5650))
39 #define ADJACENT_WEATHER_RADAR_CHANNEL   5580
40 #define CH100_START_FREQ                 5490
41 #define CH100                            100
42 
43 int dfs_override_cac_timeout(struct wlan_dfs *dfs, int cac_timeout)
44 {
45 	if (!dfs)
46 		return -EIO;
47 
48 	dfs->dfs_cac_timeout_override = cac_timeout;
49 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "CAC timeout is now %s %d",
50 		(cac_timeout == -1) ? "default" : "overridden",
51 		cac_timeout);
52 
53 	return 0;
54 }
55 
56 int dfs_get_override_cac_timeout(struct wlan_dfs *dfs, int *cac_timeout)
57 {
58 	if (!dfs)
59 		return -EIO;
60 
61 	(*cac_timeout) = dfs->dfs_cac_timeout_override;
62 
63 	return 0;
64 }
65 
66 void dfs_cac_valid_reset(struct wlan_dfs *dfs,
67 		uint8_t prevchan_ieee,
68 		uint32_t prevchan_flags)
69 {
70 	if (dfs->dfs_cac_valid_time) {
71 		if ((prevchan_ieee != dfs->dfs_curchan->dfs_ch_ieee) ||
72 			(prevchan_flags != dfs->dfs_curchan->dfs_ch_flags)) {
73 			dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
74 					"Cancelling timer & clearing cac_valid"
75 					);
76 			qdf_timer_stop(&dfs->dfs_cac_valid_timer);
77 			dfs->dfs_cac_valid = 0;
78 		}
79 	}
80 }
81 
82 /**
83  * dfs_cac_valid_timeout() - Timeout function for dfs_cac_valid_timer
84  *                           cac_valid bit will be reset in this function.
85  */
86 static os_timer_func(dfs_cac_valid_timeout)
87 {
88 	struct wlan_dfs *dfs = NULL;
89 
90 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
91 	dfs->dfs_cac_valid = 0;
92 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, ": Timed out!!");
93 }
94 
95 /**
96  * dfs_cac_timeout() - DFS cactimeout function.
97  *
98  * Sets dfs_cac_timer_running to 0  and dfs_cac_valid_timer.
99  */
100 static os_timer_func(dfs_cac_timeout)
101 {
102 	struct wlan_dfs *dfs = NULL;
103 
104 	OS_GET_TIMER_ARG(dfs, struct wlan_dfs *);
105 	dfs->dfs_cac_timer_running = 0;
106 
107 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "cac expired, chan %d curr time %d",
108 		dfs->dfs_curchan->dfs_ch_freq,
109 		(qdf_system_ticks_to_msecs(qdf_system_ticks()) / 1000));
110 
111 	/* Once CAC is done, add channel to ETSI precacdone list*/
112 	if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN)
113 		dfs_add_to_etsi_precac_done_list(dfs);
114 
115 	/*
116 	 * When radar is detected during a CAC we are woken up prematurely to
117 	 * switch to a new channel. Check the channel to decide how to act.
118 	 */
119 	if (WLAN_IS_CHAN_RADAR(dfs->dfs_curchan)) {
120 		dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
121 				dfs->dfs_curchan->dfs_ch_ieee,
122 				dfs->dfs_curchan->dfs_ch_freq,
123 				dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
124 				dfs->dfs_curchan->dfs_ch_flags);
125 		dfs_debug(dfs, WLAN_DEBUG_DFS,
126 			"CAC timer on channel %u (%u MHz) stopped due to radar",
127 			dfs->dfs_curchan->dfs_ch_ieee,
128 			dfs->dfs_curchan->dfs_ch_freq);
129 	} else {
130 		dfs_debug(dfs, WLAN_DEBUG_DFS,
131 			"CAC timer on channel %u (%u MHz) expired; no radar detected",
132 			dfs->dfs_curchan->dfs_ch_ieee,
133 			dfs->dfs_curchan->dfs_ch_freq);
134 
135 		/* On CAC completion, set the bit 'cac_valid'.
136 		 * CAC will not be re-done if this bit is reset.
137 		 * The flag will be reset when dfs_cac_valid_timer
138 		 * timesout.
139 		 */
140 		if (dfs->dfs_cac_valid_time) {
141 			dfs->dfs_cac_valid = 1;
142 			qdf_timer_mod(&dfs->dfs_cac_valid_timer,
143 					dfs->dfs_cac_valid_time * 1000);
144 		}
145 	}
146 
147 	/* Iterate over the nodes, processing the CAC completion event. */
148 	dfs_mlme_proc_cac(dfs->dfs_pdev_obj, 0);
149 
150 	/* Send a CAC timeout, VAP up event to user space */
151 	dfs_mlme_deliver_event_up_after_cac(dfs->dfs_pdev_obj);
152 
153 	if (dfs->dfs_defer_precac_channel_change == 1) {
154 		dfs_mlme_channel_change_by_precac(dfs->dfs_pdev_obj);
155 		dfs->dfs_defer_precac_channel_change = 0;
156 	}
157 }
158 
159 void dfs_cac_timer_init(struct wlan_dfs *dfs)
160 {
161 	qdf_timer_init(NULL,
162 			&(dfs->dfs_cac_timer),
163 			dfs_cac_timeout,
164 			(void *)(dfs),
165 			QDF_TIMER_TYPE_WAKE_APPS);
166 
167 	qdf_timer_init(NULL,
168 			&(dfs->dfs_cac_valid_timer),
169 			dfs_cac_valid_timeout,
170 			(void *)(dfs),
171 			QDF_TIMER_TYPE_WAKE_APPS);
172 }
173 
174 void dfs_cac_attach(struct wlan_dfs *dfs)
175 {
176 	dfs->dfs_cac_timeout_override = -1;
177 	dfs->wlan_dfs_cac_time = WLAN_DFS_WAIT_MS;
178 	dfs_cac_timer_init(dfs);
179 }
180 
181 void dfs_cac_timer_reset(struct wlan_dfs *dfs)
182 {
183 	qdf_timer_stop(&dfs->dfs_cac_timer);
184 	dfs_get_override_cac_timeout(dfs,
185 			&(dfs->dfs_cac_timeout_override));
186 
187 }
188 
189 void dfs_cac_timer_detach(struct wlan_dfs *dfs)
190 {
191 	qdf_timer_free(&dfs->dfs_cac_timer);
192 
193 	qdf_timer_free(&dfs->dfs_cac_valid_timer);
194 	dfs->dfs_cac_valid = 0;
195 }
196 
197 int dfs_is_ap_cac_timer_running(struct wlan_dfs *dfs)
198 {
199 	return dfs->dfs_cac_timer_running;
200 }
201 
202 void dfs_start_cac_timer(struct wlan_dfs *dfs)
203 {
204 	qdf_timer_mod(&dfs->dfs_cac_timer,
205 			dfs_mlme_get_cac_timeout(dfs->dfs_pdev_obj,
206 				dfs->dfs_curchan->dfs_ch_freq,
207 				dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
208 				dfs->dfs_curchan->dfs_ch_flags) * 1000);
209 }
210 
211 void dfs_cancel_cac_timer(struct wlan_dfs *dfs)
212 {
213 	qdf_timer_stop(&dfs->dfs_cac_timer);
214 }
215 
216 void dfs_cac_stop(struct wlan_dfs *dfs)
217 {
218 	uint32_t phyerr;
219 
220 	dfs_get_debug_info(dfs, (void *)&phyerr);
221 	dfs_debug(dfs, WLAN_DEBUG_DFS,
222 		"Stopping CAC Timer %d procphyerr 0x%08x",
223 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
224 	qdf_timer_stop(&dfs->dfs_cac_timer);
225 	dfs->dfs_cac_timer_running = 0;
226 }
227 
228 void dfs_stacac_stop(struct wlan_dfs *dfs)
229 {
230 	uint32_t phyerr;
231 
232 	dfs_get_debug_info(dfs, (void *)&phyerr);
233 	dfs_debug(dfs, WLAN_DEBUG_DFS,
234 		"Stopping STA CAC Timer %d procphyerr 0x%08x",
235 		 dfs->dfs_curchan->dfs_ch_freq, phyerr);
236 }
237