1 /*
2 * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2011, Atheros Communications Inc.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include "../dfs.h"
19 #include "../dfs_zero_cac.h"
20 #include "../dfs_filter_init.h"
21 #include "wlan_dfs_mlme_api.h"
22 #include "wlan_dfs_lmac_api.h"
23 #include "../dfs_partial_offload_radar.h"
24 #include "../dfs_internal.h"
25
dfs_get_radars(struct wlan_dfs * dfs)26 void dfs_get_radars(struct wlan_dfs *dfs)
27 {
28 struct wlan_objmgr_psoc *psoc;
29
30 if (!dfs) {
31 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
32 return;
33 }
34
35 psoc = wlan_pdev_get_psoc(dfs->dfs_pdev_obj);
36 if (!psoc) {
37 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "psoc is NULL");
38 return;
39 }
40
41 if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL) {
42 /* For Partial offload */
43 dfs_get_po_radars(dfs);
44 }
45 }
46
dfs_radar_disable(struct wlan_dfs * dfs)47 int dfs_radar_disable(struct wlan_dfs *dfs)
48 {
49 dfs->dfs_proc_phyerr &= ~DFS_AR_EN;
50 dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN;
51
52 return 0;
53 }
54
dfs_phyerr_param_copy(struct wlan_dfs_phyerr_param * dst,struct wlan_dfs_phyerr_param * src)55 void dfs_phyerr_param_copy(struct wlan_dfs_phyerr_param *dst,
56 struct wlan_dfs_phyerr_param *src)
57 {
58 qdf_mem_copy(dst, src, sizeof(*dst));
59 }
60
61 #ifdef CONFIG_CHAN_FREQ_API
dfs_getchanstate(struct wlan_dfs * dfs,uint8_t * index,int ext_chan_flag)62 struct dfs_state *dfs_getchanstate(struct wlan_dfs *dfs, uint8_t *index,
63 int ext_chan_flag)
64 {
65 struct dfs_state *rs = NULL;
66 struct dfs_channel *ch, cmp_ch1;
67 int i;
68 QDF_STATUS err;
69
70 if (!dfs) {
71 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
72 return NULL;
73 }
74 ch = &cmp_ch1;
75 if (ext_chan_flag) {
76 err = dfs_mlme_get_extchan_for_freq(
77 dfs->dfs_pdev_obj,
78 &ch->dfs_ch_freq,
79 &ch->dfs_ch_flags,
80 &ch->dfs_ch_flagext,
81 &ch->dfs_ch_ieee,
82 &ch->dfs_ch_vhtop_ch_freq_seg1,
83 &ch->dfs_ch_vhtop_ch_freq_seg2,
84 &ch->dfs_ch_mhz_freq_seg1,
85 &ch->dfs_ch_mhz_freq_seg2);
86
87 if (err == QDF_STATUS_SUCCESS) {
88 dfs_debug(dfs, WLAN_DEBUG_DFS2,
89 "Extension channel freq = %u flags=0x%x",
90 ch->dfs_ch_freq,
91 ch->dfs_ch_flagext);
92 } else {
93 return NULL;
94 }
95 } else {
96 ch = dfs->dfs_curchan;
97 dfs_debug(dfs, WLAN_DEBUG_DFS2,
98 "Primary channel freq = %u flags=0x%x",
99 ch->dfs_ch_freq, ch->dfs_ch_flagext);
100 }
101
102 for (i = 0; i < DFS_NUM_RADAR_STATES; i++) {
103 if ((dfs->dfs_radar[i].rs_chan.dfs_ch_freq ==
104 ch->dfs_ch_freq) &&
105 (dfs->dfs_radar[i].rs_chan.dfs_ch_flags ==
106 ch->dfs_ch_flags)) {
107 if (index)
108 *index = (uint8_t)i;
109 return &dfs->dfs_radar[i];
110 }
111 }
112 /* No existing channel found, look for first free channel state entry.*/
113 for (i = 0; i < DFS_NUM_RADAR_STATES; i++) {
114 if (dfs->dfs_radar[i].rs_chan.dfs_ch_freq == 0) {
115 rs = &dfs->dfs_radar[i];
116 /* Found one, set channel info and default thresholds.*/
117 rs->rs_chan = *ch;
118
119 /* Copy the parameters from the default set. */
120 dfs_phyerr_param_copy(&rs->rs_param,
121 &dfs->dfs_defaultparams);
122
123 if (index)
124 *index = (uint8_t)i;
125
126 return rs;
127 }
128 }
129 dfs_debug(dfs, WLAN_DEBUG_DFS2, "No more radar states left.");
130
131 return NULL;
132 }
133 #endif
134
135 #ifdef CONFIG_CHAN_FREQ_API
dfs_radar_enable(struct wlan_dfs * dfs,int no_cac,uint32_t opmode)136 void dfs_radar_enable(struct wlan_dfs *dfs, int no_cac, uint32_t opmode)
137 {
138 int is_ext_ch;
139 int is_fastclk = 0;
140 struct dfs_channel *exch, extchan;
141 QDF_STATUS err = QDF_STATUS_E_FAILURE;
142
143 if (!dfs) {
144 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
145 return;
146 }
147
148 is_ext_ch = WLAN_IS_CHAN_11N_HT40(dfs->dfs_curchan);
149 lmac_dfs_disable(dfs->dfs_pdev_obj, no_cac);
150 /*
151 * In all modes, if the primary is DFS then we have to
152 * enable radar detection. In HT80_80, we can have
153 * primary non-DFS 80MHz with extension 80MHz DFS.
154 */
155 if ((WLAN_IS_CHAN_DFS(dfs->dfs_curchan) ||
156 ((WLAN_IS_CHAN_11AC_VHT160(dfs->dfs_curchan) ||
157 WLAN_IS_CHAN_11AC_VHT80_80(dfs->dfs_curchan)) &&
158 WLAN_IS_CHAN_DFS_CFREQ2(dfs->dfs_curchan))) ||
159 (dfs_is_precac_timer_running(dfs))) {
160 struct dfs_state *rs_pri = NULL, *rs_ext = NULL;
161 uint8_t index_pri, index_ext;
162
163 dfs->dfs_proc_phyerr |= DFS_AR_EN;
164 dfs->dfs_proc_phyerr |= DFS_RADAR_EN;
165 dfs->dfs_proc_phyerr |= DFS_SECOND_SEGMENT_RADAR_EN;
166
167 exch = &extchan;
168 if (is_ext_ch) {
169 err = dfs_mlme_get_extchan_for_freq
170 (
171 dfs->dfs_pdev_obj,
172 &exch->dfs_ch_freq,
173 &exch->dfs_ch_flags,
174 &exch->dfs_ch_flagext,
175 &exch->dfs_ch_ieee,
176 &exch->dfs_ch_vhtop_ch_freq_seg1,
177 &exch->dfs_ch_vhtop_ch_freq_seg2,
178 &exch->dfs_ch_mhz_freq_seg1,
179 &exch->dfs_ch_mhz_freq_seg2);
180 }
181 dfs_reset_alldelaylines(dfs);
182
183 rs_pri = dfs_getchanstate(dfs, &index_pri, 0);
184 if (err == QDF_STATUS_SUCCESS)
185 rs_ext = dfs_getchanstate(dfs, &index_ext, 1);
186
187 if (rs_pri && ((err == QDF_STATUS_E_FAILURE) || (rs_ext))) {
188 struct wlan_dfs_phyerr_param pe;
189
190 qdf_mem_set(&pe, sizeof(pe), '\0');
191
192 if (index_pri != dfs->dfs_curchan_radindex)
193 dfs_reset_alldelaylines(dfs);
194
195 dfs->dfs_curchan_radindex = (int16_t)index_pri;
196
197 if (rs_ext)
198 dfs->dfs_extchan_radindex = (int16_t)index_ext;
199
200 dfs_phyerr_param_copy(&pe, &rs_pri->rs_param);
201 dfs_debug(dfs, WLAN_DEBUG_DFS3,
202 "firpwr=%d, rssi=%d, height=%d, prssi=%d, inband=%d, relpwr=%d, relstep=%d, maxlen=%d",
203 pe.pe_firpwr,
204 pe.pe_rrssi, pe.pe_height,
205 pe.pe_prssi, pe.pe_inband,
206 pe.pe_relpwr, pe.pe_relstep,
207 pe.pe_maxlen);
208
209 lmac_dfs_enable(dfs->dfs_pdev_obj, &is_fastclk,
210 &pe, dfs->dfsdomain);
211 dfs_debug(dfs, WLAN_DEBUG_DFS,
212 "Enabled radar detection on channel %d",
213 dfs->dfs_curchan->dfs_ch_freq);
214
215 dfs->dur_multiplier = is_fastclk ?
216 DFS_FAST_CLOCK_MULTIPLIER :
217 DFS_NO_FAST_CLOCK_MULTIPLIER;
218
219 dfs_debug(dfs, WLAN_DEBUG_DFS3,
220 "duration multiplier is %d",
221 dfs->dur_multiplier);
222 } else
223 dfs_debug(dfs, WLAN_DEBUG_DFS,
224 "No more radar states left");
225 }
226 }
227 #endif
228
dfs_set_thresholds(struct wlan_dfs * dfs,const uint32_t threshtype,const uint32_t value)229 int dfs_set_thresholds(struct wlan_dfs *dfs, const uint32_t threshtype,
230 const uint32_t value)
231 {
232 int16_t chanindex;
233 struct dfs_state *rs;
234 struct wlan_dfs_phyerr_param pe;
235 int is_fastclk = 0;
236
237 if (!dfs) {
238 dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs is NULL");
239 return 0;
240 }
241
242 chanindex = dfs->dfs_curchan_radindex;
243 if ((chanindex < 0) || (chanindex >= DFS_NUM_RADAR_STATES)) {
244 dfs_debug(dfs, WLAN_DEBUG_DFS1,
245 "chanindex = %d, DFS_NUM_RADAR_STATES=%d",
246 chanindex,
247 DFS_NUM_RADAR_STATES);
248 return 0;
249 }
250
251 dfs_debug(dfs, WLAN_DEBUG_DFS,
252 "threshtype=%d, value=%d", threshtype, value);
253
254 wlan_dfs_phyerr_init_noval(&pe);
255
256 rs = &(dfs->dfs_radar[chanindex]);
257 switch (threshtype) {
258 case DFS_PARAM_FIRPWR:
259 rs->rs_param.pe_firpwr = (int32_t) value;
260 pe.pe_firpwr = value;
261 break;
262 case DFS_PARAM_RRSSI:
263 rs->rs_param.pe_rrssi = value;
264 pe.pe_rrssi = value;
265 break;
266 case DFS_PARAM_HEIGHT:
267 rs->rs_param.pe_height = value;
268 pe.pe_height = value;
269 break;
270 case DFS_PARAM_PRSSI:
271 rs->rs_param.pe_prssi = value;
272 pe.pe_prssi = value;
273 break;
274 case DFS_PARAM_INBAND:
275 rs->rs_param.pe_inband = value;
276 pe.pe_inband = value;
277 break;
278 /* 5413 specific */
279 case DFS_PARAM_RELPWR:
280 rs->rs_param.pe_relpwr = value;
281 pe.pe_relpwr = value;
282 break;
283 case DFS_PARAM_RELSTEP:
284 rs->rs_param.pe_relstep = value;
285 pe.pe_relstep = value;
286 break;
287 case DFS_PARAM_MAXLEN:
288 rs->rs_param.pe_maxlen = value;
289 pe.pe_maxlen = value;
290 break;
291 default:
292 dfs_debug(dfs, WLAN_DEBUG_DFS1,
293 "unknown threshtype (%d)", threshtype);
294 break;
295 }
296
297
298 /*
299 * The driver layer dfs_enable routine is tasked with translating
300 * values from the global format to the per-device (HAL, offload)
301 * format.
302 */
303 lmac_dfs_enable(dfs->dfs_pdev_obj, &is_fastclk,
304 &pe, dfs->dfsdomain);
305
306 return 1;
307 }
308
dfs_get_thresholds(struct wlan_dfs * dfs,struct wlan_dfs_phyerr_param * param)309 int dfs_get_thresholds(struct wlan_dfs *dfs,
310 struct wlan_dfs_phyerr_param *param)
311 {
312 lmac_dfs_get_thresholds(dfs->dfs_pdev_obj, param);
313
314 return 1;
315 }
316
dfs_chan2freq(struct dfs_channel * chan)317 uint16_t dfs_chan2freq(struct dfs_channel *chan)
318 {
319 if (!chan)
320 return 0;
321
322 return chan == WLAN_CHAN_ANYC ? WLAN_CHAN_ANY : chan->dfs_ch_freq;
323 }
324