xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c (revision 3149adf58a329e17232a4c0e58d460d025edd55a)
1 /*
2  * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: API for processing radar found indication.
21  *
22  */
23 
24 #include "../dfs.h"
25 #include "../dfs_process_radar_found_ind.h"
26 #include <wlan_reg_services_api.h>
27 #include <wlan_dfs_utils_api.h>
28 #include "wlan_dfs_mlme_api.h"
29 
30 /**
31  * TODO: The code is not according to the following description needs
32  * modification and correction. Code always adds left and right channels to
33  * NOL even if it is not a chirp radar.
34  *
35  * A) If chirp radar starts at boundary and ends at boundary then three channels
36  *    will be affected.
37  *    freq_offset.freq[0] = fn   (Center frequency)
38  *    freq_offset.freq[1] = fn-1 (Left of center)
39  *    freq_offset.freq[2] = fn+1 (Right of center)
40  *
41  *    Three channels, ch(n-1), ch(n)and ch(n+1) will be added to NOL.
42  *
43  *                     Chirp start freq         Chirp end freq
44  *                             |                       |
45  *                             |                       |
46  *                             V                       V
47  *      _______________________________________________________________________
48  *     |       center freq     |       center freq     |       center freq     |
49  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
50  *     |           |           |           |           |           |           |
51  *     |           |           |           |           |           |           |
52  *     |           |           |           |           |           |           |
53  *                fn-1                    fn         boundary     fn+1
54  *     <-------- 20 Mhz ------>
55  *
56  * B) If chirp radar starts at one channel and continues up to another channel
57  *    then two channels will be affected.
58  *    freq_offset.freq[0] = fn
59  *    freq_offset.freq[1] = 0
60  *    freq_offset.freq[2] = fn+1
61  *
62  *    Three channels, ch(n-1), ch(n)and ch(n+1) will be added to NOL.
63  *
64  *                                   Chirp start freq         Chirp end freq
65  *                                           |                       |
66  *                                           |                       |
67  *                                           V                       V
68  *      _______________________________________________________________________
69  *     |       center freq     |       center freq     |       center freq     |
70  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
71  *     |           |           |           |           |           |           |
72  *     |           |           |           |           |           |           |
73  *     |           |           |           |           |           |           |
74  *                fn-1                    fn         boundary     fn+1
75  *     <-------- 20 Mhz ------>
76  *
77  * C) Radar found at boundary, two channels will be affected.
78  *    freq_offset.freq[0] = fn
79  *    freq_offset.freq[1] = 0
80  *    freq_offset.freq[2] = fn+1
81  *
82  *    Two channels, ch(n) and ch(n+1) will be added to NOL.
83  *
84  *                                            dfs_freq_offset (radar found freq)
85  *                                                     |
86  *                                                     |
87  *                                                     V
88  *      _______________________________________________________________________
89  *     |       center freq     |       center freq     |       center freq     |
90  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
91  *     |           |           |           |           |           |           |
92  *     |           |           |           |           |           |           |
93  *     |           |           |           |           |           |           |
94  *                fn-1                    fn         boundary     fn+1
95  *     <-------- 20 Mhz ------>
96  *
97  *
98  * D) Else only one channel will be affected.
99  *    freq_offset.freq[0] = fn
100  *    freq_offset.freq[1] = 0
101  *    freq_offset.freq[2] = 0
102  *
103  *   One channel ch(n) will be added to NOL.
104  *
105  *
106  *                                            dfs_freq_offset (radar found freq)
107  *                                                |
108  *                                                |
109  *                                                V
110  *      _______________________________________________________________________
111  *     |       center freq     |       center freq     |       center freq     |
112  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
113  *     |           |           |           |           |           |           |
114  *     |           |           |           |           |           |           |
115  *     |           |           |           |           |           |           |
116  *                fn-1                    fn         boundary     fn+1
117  *     <-------- 20 Mhz ------>
118  */
119 
120 /**
121  * dfs_radar_add_channel_list_to_nol()- Add given channels to nol
122  * @dfs: Pointer to wlan_dfs structure.
123  * @channels: Pointer to the channel list.
124  * @num_channels: Number of channels in the list.
125  *
126  * Add list of channels to nol, only if the channel is dfs.
127  *
128  * Return: QDF_STATUS
129  */
130 static QDF_STATUS dfs_radar_add_channel_list_to_nol(struct wlan_dfs *dfs,
131 						    uint8_t *channels,
132 						    uint8_t num_channels)
133 {
134 	int i;
135 	uint8_t last_chan = 0;
136 	uint8_t nollist[NUM_CHANNELS_160MHZ];
137 	uint8_t num_ch = 0;
138 
139 	if (num_channels > NUM_CHANNELS_160MHZ) {
140 		dfs_err(dfs, WLAN_DEBUG_DFS,
141 			"Invalid num channels: %d", num_channels);
142 		return QDF_STATUS_E_FAILURE;
143 	}
144 
145 	for (i = 0; i < num_channels; i++) {
146 		if (channels[i] == 0 ||
147 		    channels[i] == last_chan)
148 			continue;
149 		if (!utils_is_dfs_ch(dfs->dfs_pdev_obj, channels[i])) {
150 			dfs_info(dfs, WLAN_DEBUG_DFS, "ch=%d is not dfs, skip",
151 				 channels[i]);
152 			continue;
153 		}
154 		last_chan = channels[i];
155 		DFS_NOL_ADD_CHAN_LOCKED(dfs,
156 				(uint16_t)utils_dfs_chan_to_freq(channels[i]),
157 				dfs->wlan_dfs_nol_timeout);
158 		nollist[num_ch++] = last_chan;
159 		dfs_info(dfs, WLAN_DEBUG_DFS, "ch=%d Added to NOL", last_chan);
160 	}
161 
162 	if (!num_ch) {
163 		dfs_err(dfs, WLAN_DEBUG_DFS,
164 			"dfs channels not found in channel list");
165 		return QDF_STATUS_E_FAILURE;
166 	}
167 
168 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
169 				    nollist, num_ch, DFS_NOL_SET);
170 	dfs_nol_update(dfs);
171 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
172 
173 	return QDF_STATUS_SUCCESS;
174 }
175 
176 /**
177  * dfs_radar_chan_for_80()- Find frequency offsets for 80MHz
178  * @freq_offset: freq offset
179  * @center_freq: center frequency
180  *
181  * Find frequency offsets for 80MHz
182  *
183  * Return: None
184  */
185 static void dfs_radar_chan_for_80(struct freqs_offsets *freq_offset,
186 				  uint32_t center_freq)
187 {
188 	int i;
189 
190 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
191 		if (freq_offset->offset[i] < DFS_OFFET_SECOND_LOWER)
192 			freq_offset->freq[i] =
193 				DFS_THIRD_LOWER_CHANNEL(center_freq);
194 		else if ((freq_offset->offset[i] > DFS_OFFET_SECOND_LOWER) &&
195 			 (freq_offset->offset[i] < DFS_OFFET_FIRST_LOWER))
196 			freq_offset->freq[i] =
197 				DFS_SECOND_LOWER_CHANNEL(center_freq);
198 		else if ((freq_offset->offset[i] > DFS_OFFET_FIRST_LOWER) &&
199 			 (freq_offset->offset[i] < 0))
200 			freq_offset->freq[i] =
201 				DFS_FIRST_LOWER_CHANNEL(center_freq);
202 		else if ((freq_offset->offset[i] > 0) &&
203 			  (freq_offset->offset[i] < DFS_OFFET_FIRST_UPPER))
204 			freq_offset->freq[i] =
205 				DFS_FIRST_UPPER_CHANNEL(center_freq);
206 		else if ((freq_offset->offset[i] > DFS_OFFET_FIRST_UPPER) &&
207 			 (freq_offset->offset[i] < DFS_OFFET_SECOND_UPPER))
208 			freq_offset->freq[i] =
209 				DFS_SECOND_UPPER_CHANNEL(center_freq);
210 		else if (freq_offset->offset[i] > DFS_OFFET_SECOND_UPPER)
211 			freq_offset->freq[i] =
212 				DFS_THIRD_UPPER_CHANNEL(center_freq);
213 	}
214 }
215 
216 /**
217  * dfs_radar_chan_for_40()- Find frequency offsets for 40MHz
218  * @freq_offset: freq offset
219  * @center_freq: center frequency
220  *
221  * Find frequency offsets for 40MHz
222  *
223  * Return: None
224  */
225 static void dfs_radar_chan_for_40(struct freqs_offsets *freq_offset,
226 				  uint32_t center_freq)
227 {
228 	int i;
229 
230 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
231 		if (freq_offset->offset[i] < DFS_OFFET_FIRST_LOWER)
232 			freq_offset->freq[i] =
233 				DFS_SECOND_LOWER_CHANNEL(center_freq);
234 		else if ((freq_offset->offset[i] > DFS_OFFET_FIRST_LOWER) &&
235 			 (freq_offset->offset[i] < 0))
236 			freq_offset->freq[i] =
237 				DFS_FIRST_LOWER_CHANNEL(center_freq);
238 		else if ((freq_offset->offset[i] > 0) &&
239 			 (freq_offset->offset[i] < DFS_OFFET_FIRST_UPPER))
240 			freq_offset->freq[i] =
241 				DFS_FIRST_UPPER_CHANNEL(center_freq);
242 		else if (freq_offset->offset[i] > DFS_OFFET_FIRST_UPPER)
243 			freq_offset->freq[i] =
244 				DFS_SECOND_UPPER_CHANNEL(center_freq);
245 	}
246 }
247 
248 /**
249  * dfs_radar_chan_for_20()- Find frequency offsets for 20MHz
250  * @freq_offset: freq offset
251  * @center_freq: center frequency
252  *
253  * Find frequency offsets for 20MHz
254  *
255  * Return: None
256  */
257 static void dfs_radar_chan_for_20(struct freqs_offsets *freq_offset,
258 				  uint32_t center_freq)
259 {
260 	int i;
261 
262 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
263 		if (freq_offset->offset[i] <= DFS_20MZ_OFFSET_LOWER)
264 			freq_offset->freq[i] =
265 				DFS_20MHZ_LOWER_CHANNEL(center_freq);
266 		else if ((freq_offset->offset[i] > DFS_20MZ_OFFSET_LOWER) &&
267 			  (freq_offset->offset[i] < DFS_20MZ_OFFSET_UPPER))
268 			freq_offset->freq[i] = center_freq;
269 		else if (freq_offset->offset[i] >= DFS_20MZ_OFFSET_UPPER)
270 			freq_offset->freq[i] =
271 				DFS_20MHZ_UPPER_CHANNEL(center_freq);
272 	}
273 }
274 
275 /**
276  * dfs_find_radar_affected_subchans() - Finds radar affected sub channels.
277  * @dfs: Pointer to wlan_dfs structure.
278  * @radar_found: Pointer to radar_found structure.
279  * @channels: Pointer to save radar affected channels.
280  *
281  * Return: Number of channels.
282  */
283 static uint8_t dfs_find_radar_affected_subchans(struct wlan_dfs *dfs,
284 						struct radar_found_info
285 						*radar_found,
286 						uint8_t *channels)
287 {
288 	int i;
289 	uint32_t freq_center, flag;
290 	int32_t sidx;
291 	struct dfs_channel *curchan = dfs->dfs_curchan;
292 	struct freqs_offsets freq_offset;
293 
294 	qdf_mem_set(&freq_offset, sizeof(freq_offset), 0);
295 	flag = curchan->dfs_ch_flags;
296 
297 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++)
298 		freq_offset.offset[i] = radar_found->freq_offset;
299 
300 	sidx = DFS_FREQ_OFFSET_TO_SIDX(radar_found->freq_offset);
301 
302 	if (!radar_found->segment_id)
303 		freq_center = utils_dfs_chan_to_freq(
304 				curchan->dfs_ch_vhtop_ch_freq_seg1);
305 	else {
306 		if (dfs_is_precac_timer_running(dfs)) {
307 			freq_center = utils_dfs_chan_to_freq(
308 					dfs->dfs_precac_secondary_freq);
309 		} else {
310 			freq_center = utils_dfs_chan_to_freq(
311 					curchan->dfs_ch_vhtop_ch_freq_seg2);
312 			if (flag & WLAN_CHAN_VHT160)
313 				freq_center += DFS_160MHZ_SECOND_SEG_OFFSET;
314 		}
315 	}
316 
317 	dfs_info(dfs, WLAN_DEBUG_DFS,
318 		 "seg=%d, sidx=%d, offset=%d, chirp=%d, flag=%d, f=%d",
319 		 radar_found->segment_id, sidx,
320 		 radar_found->freq_offset, radar_found->is_chirp,
321 		 flag, freq_center);
322 
323 	if ((WLAN_IS_CHAN_A(curchan)) ||
324 	    WLAN_IS_CHAN_MODE_20(curchan)) {
325 		if (radar_found->is_chirp ||
326 		    (sidx && !(abs(sidx) % DFS_BOUNDARY_SIDX))) {
327 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
328 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
329 		}
330 		dfs_radar_chan_for_20(&freq_offset, freq_center);
331 	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
332 		if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
333 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
334 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
335 		}
336 		dfs_radar_chan_for_40(&freq_offset, freq_center);
337 	} else if (WLAN_IS_CHAN_MODE_80(curchan) ||
338 			WLAN_IS_CHAN_MODE_160(curchan) ||
339 			WLAN_IS_CHAN_MODE_80_80(curchan)) {
340 		if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
341 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
342 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
343 		}
344 		dfs_radar_chan_for_80(&freq_offset, freq_center);
345 	} else {
346 		dfs_err(dfs, WLAN_DEBUG_DFS,
347 			"channel flag=%d is invalid", flag);
348 		return 0;
349 	}
350 
351 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
352 		channels[i] = utils_dfs_freq_to_chan(freq_offset.freq[i]);
353 		dfs_info(dfs, WLAN_DEBUG_DFS, "offset=%d, channel=%d",
354 			 i, channels[i]);
355 	}
356 
357 	return i;
358 }
359 
360 /**
361  * dfs_get_bonding_channels() - Get bonding channels.
362  * @curchan: Pointer to dfs_channels to know width and primary channel.
363  * @segment_id: Segment id, useful for 80+80/160 MHz operating band.
364  * @channels: Pointer to save radar affected channels.
365  *
366  * Return: Number of channels.
367  */
368 static uint8_t dfs_get_bonding_channels(struct dfs_channel *curchan,
369 					uint32_t segment_id,
370 					uint8_t *channels)
371 {
372 	uint8_t center_chan;
373 	uint8_t nchannels = 0;
374 
375 	if (!segment_id)
376 		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg1;
377 	else
378 		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg2;
379 
380 	if (WLAN_IS_CHAN_MODE_20(curchan)) {
381 		nchannels = 1;
382 		channels[0] = center_chan;
383 	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
384 		nchannels = 2;
385 		channels[0] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
386 		channels[1] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
387 	} else if (WLAN_IS_CHAN_MODE_80(curchan) ||
388 		   WLAN_IS_CHAN_MODE_80_80(curchan)) {
389 		nchannels = 4;
390 		channels[0] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
391 		channels[1] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
392 		channels[2] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
393 		channels[3] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
394 	} else if (WLAN_IS_CHAN_MODE_160(curchan)) {
395 		nchannels = 8;
396 		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg2;
397 		channels[0] = center_chan - DFS_5GHZ_4TH_CHAN_OFFSET;
398 		channels[1] = center_chan - DFS_5GHZ_3RD_CHAN_OFFSET;
399 		channels[2] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
400 		channels[3] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
401 		channels[4] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
402 		channels[5] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
403 		channels[6] = center_chan + DFS_5GHZ_3RD_CHAN_OFFSET;
404 		channels[7] = center_chan + DFS_5GHZ_4TH_CHAN_OFFSET;
405 	}
406 
407 	return nchannels;
408 }
409 
410 QDF_STATUS dfs_process_radar_ind(struct wlan_dfs *dfs,
411 				 struct radar_found_info *radar_found)
412 {
413 	bool wait_for_csa = false;
414 	uint8_t channels[NUM_CHANNELS_160MHZ];
415 	uint8_t num_channels;
416 	QDF_STATUS status;
417 
418 	if (!dfs->dfs_curchan) {
419 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs->dfs_curchan is NULL");
420 		return QDF_STATUS_E_FAILURE;
421 	}
422 
423 	/* Check if the current channel is a non DFS channel */
424 	if (!dfs_radarevent_basic_sanity(dfs, dfs->dfs_curchan)) {
425 		dfs_err(dfs, WLAN_DEBUG_DFS,
426 			"radar event on a non-DFS channel");
427 		return QDF_STATUS_E_FAILURE;
428 	}
429 
430 	if (!dfs->dfs_use_nol) {
431 		dfs_send_csa_to_current_chan(dfs);
432 		return QDF_STATUS_SUCCESS;
433 	}
434 
435 	if (dfs->dfs_use_nol_subchannel_marking)
436 		num_channels = dfs_find_radar_affected_subchans(dfs,
437 								radar_found,
438 								channels);
439 	else
440 		num_channels = dfs_get_bonding_channels(dfs->dfs_curchan,
441 							radar_found->segment_id,
442 							channels);
443 
444 	status = dfs_radar_add_channel_list_to_nol(dfs, channels, num_channels);
445 	if (QDF_IS_STATUS_ERROR(status)) {
446 		dfs_err(dfs, WLAN_DEBUG_DFS,
447 			"radar event received on invalid channel");
448 		return status;
449 	}
450 
451 	if (radar_found->segment_id == SEG_ID_SECONDARY)
452 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
453 			 "Radar found on second segment VHT80 freq=%d MHz",
454 			 dfs->dfs_precac_secondary_freq);
455 	else
456 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
457 			 "Radar found on channel=%d, freq=%d MHz",
458 			 dfs->dfs_curchan->dfs_ch_ieee,
459 			 dfs->dfs_curchan->dfs_ch_freq);
460 
461 	/*
462 	 * If precac is running and the radar found in secondary
463 	 * VHT80 mark the channel as radar and add to NOL list.
464 	 * Otherwise random channel selection can choose this
465 	 * channel.
466 	 */
467 	dfs_debug(dfs, WLAN_DEBUG_DFS,
468 		  "found_on_second=%d is_pre=%d",
469 		  dfs->is_radar_found_on_secondary_seg,
470 		  dfs_is_precac_timer_running(dfs));
471 
472 	/*
473 	 * Even if radar found on primary, we need to move the channel
474 	 * from precac-required-list and precac-done-list to
475 	 * precac-nol-list.
476 	 */
477 	if (dfs->dfs_precac_enable)
478 		dfs_mark_precac_dfs(dfs, dfs->is_radar_found_on_secondary_seg);
479 
480 	if (!dfs->dfs_is_offload_enabled &&
481 	    dfs->is_radar_found_on_secondary_seg) {
482 		dfs_second_segment_radar_disable(dfs);
483 		dfs->is_radar_found_on_secondary_seg = 0;
484 
485 		if (dfs->is_radar_during_precac) {
486 			dfs->is_radar_during_precac = 0;
487 			return QDF_STATUS_SUCCESS;
488 		}
489 	}
490 
491 	/*
492 	 * This calls into the umac DFS code, which sets the umac
493 	 * related radar flags and begins the channel change
494 	 * machinery.
495 	 * XXX TODO: the umac NOL code isn't used, but
496 	 * WLAN_CHAN_DFS_RADAR still gets set. Since the umac
497 	 * NOL code isn't used, that flag is never cleared. This
498 	 * needs to be fixed. See EV 105776.
499 	 */
500 	dfs_mlme_start_rcsa(dfs->dfs_pdev_obj, &wait_for_csa);
501 	if (wait_for_csa)
502 		return QDF_STATUS_SUCCESS;
503 
504 	/*
505 	 * EV 129487 : We have detected radar in the channel,
506 	 * stop processing PHY error data as this can cause
507 	 * false detect in the new channel while channel
508 	 * change is in progress.
509 	 */
510 
511 	if (!dfs->dfs_is_offload_enabled) {
512 		dfs_radar_disable(dfs);
513 		dfs_second_segment_radar_disable(dfs);
514 	}
515 
516 	dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
517 			dfs->dfs_curchan->dfs_ch_ieee,
518 			dfs->dfs_curchan->dfs_ch_freq,
519 			dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
520 			dfs->dfs_curchan->dfs_ch_flags);
521 
522 	return QDF_STATUS_SUCCESS;
523 }
524