xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c (revision d0c05845839e5f2ba5a8dcebe0cd3e4cd4e8dfcf)
1 /*
2  * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: API for processing radar found indication.
22  *
23  */
24 
25 #include "../dfs.h"
26 #include "../dfs_zero_cac.h"
27 #include "../dfs_process_radar_found_ind.h"
28 #include <wlan_reg_services_api.h>
29 #include <wlan_objmgr_vdev_obj.h>
30 #include <wlan_dfs_utils_api.h>
31 #include <wlan_dfs_tgt_api.h>
32 #include "wlan_dfs_mlme_api.h"
33 #include "../dfs_internal.h"
34 /**
35  * TODO: The code is not according to the following description needs
36  * modification and correction. Code always adds left and right channels to
37  * NOL even if it is not a chirp radar.
38  *
39  * A) If chirp radar starts at boundary and ends at boundary then three channels
40  *    will be affected.
41  *    freq_offset.freq[0] = fn   (Center frequency)
42  *    freq_offset.freq[1] = fn-1 (Left of center)
43  *    freq_offset.freq[2] = fn+1 (Right of center)
44  *
45  *    Three channels, ch(n-1), ch(n)and ch(n+1) will be added to NOL.
46  *
47  *                     Chirp start freq         Chirp end freq
48  *                             |                       |
49  *                             |                       |
50  *                             V                       V
51  *      _______________________________________________________________________
52  *     |       center freq     |       center freq     |       center freq     |
53  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
54  *     |           |           |           |           |           |           |
55  *     |           |           |           |           |           |           |
56  *     |           |           |           |           |           |           |
57  *                fn-1                    fn         boundary     fn+1
58  *     <-------- 20 Mhz ------>
59  *
60  * B) If chirp radar starts at one channel and continues up to another channel
61  *    then two channels will be affected.
62  *    freq_offset.freq[0] = fn
63  *    freq_offset.freq[1] = 0
64  *    freq_offset.freq[2] = fn+1
65  *
66  *    Three channels, ch(n-1), ch(n)and ch(n+1) will be added to NOL.
67  *
68  *                                   Chirp start freq         Chirp end freq
69  *                                           |                       |
70  *                                           |                       |
71  *                                           V                       V
72  *      _______________________________________________________________________
73  *     |       center freq     |       center freq     |       center freq     |
74  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
75  *     |           |           |           |           |           |           |
76  *     |           |           |           |           |           |           |
77  *     |           |           |           |           |           |           |
78  *                fn-1                    fn         boundary     fn+1
79  *     <-------- 20 Mhz ------>
80  *
81  * C) Radar found at boundary, two channels will be affected.
82  *    freq_offset.freq[0] = fn
83  *    freq_offset.freq[1] = 0
84  *    freq_offset.freq[2] = fn+1
85  *
86  *    Two channels, ch(n) and ch(n+1) will be added to NOL.
87  *
88  *                                            dfs_freq_offset (radar found freq)
89  *                                                     |
90  *                                                     |
91  *                                                     V
92  *      _______________________________________________________________________
93  *     |       center freq     |       center freq     |       center freq     |
94  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
95  *     |           |           |           |           |           |           |
96  *     |           |           |           |           |           |           |
97  *     |           |           |           |           |           |           |
98  *                fn-1                    fn         boundary     fn+1
99  *     <-------- 20 Mhz ------>
100  *
101  *
102  * D) Else only one channel will be affected.
103  *    freq_offset.freq[0] = fn
104  *    freq_offset.freq[1] = 0
105  *    freq_offset.freq[2] = 0
106  *
107  *   One channel ch(n) will be added to NOL.
108  *
109  *
110  *                                            dfs_freq_offset (radar found freq)
111  *                                                |
112  *                                                |
113  *                                                V
114  *      _______________________________________________________________________
115  *     |       center freq     |       center freq     |       center freq     |
116  *     |          ch(n-1)      |          ch(n)        |          ch(n+1)      |
117  *     |           |           |           |           |           |           |
118  *     |           |           |           |           |           |           |
119  *     |           |           |           |           |           |           |
120  *                fn-1                    fn         boundary     fn+1
121  *     <-------- 20 Mhz ------>
122  */
123 
124 int dfs_set_nol_subchannel_marking(struct wlan_dfs *dfs,
125 				   bool nol_subchannel_marking)
126 {
127 	QDF_STATUS status = QDF_STATUS_SUCCESS;
128 
129 	if (!dfs)
130 		return -EIO;
131 
132 	dfs->dfs_use_nol_subchannel_marking = nol_subchannel_marking;
133 	dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS, "NOL subchannel marking is %s ",
134 		 (nol_subchannel_marking) ? "set" : "disabled");
135 	if (dfs->dfs_is_offload_enabled)
136 		status = tgt_dfs_send_subchan_marking(dfs->dfs_pdev_obj,
137 						      nol_subchannel_marking);
138 
139 	return qdf_status_to_os_return(status);
140 }
141 
142 int dfs_get_nol_subchannel_marking(struct wlan_dfs *dfs,
143 				   bool *nol_subchannel_marking)
144 {
145 	if (!dfs)
146 		return -EIO;
147 
148 	(*nol_subchannel_marking) = dfs->dfs_use_nol_subchannel_marking;
149 
150 	return 0;
151 }
152 
153 #ifdef CONFIG_CHAN_FREQ_API
154 QDF_STATUS
155 dfs_radar_add_channel_list_to_nol_for_freq(struct wlan_dfs *dfs,
156 					   uint16_t *freq_list,
157 					   uint16_t *nol_freq_list,
158 					   uint8_t *num_channels)
159 {
160 	int i;
161 	uint16_t last_chan_freq = 0;
162 	uint8_t num_ch = 0;
163 
164 	if (*num_channels > MAX_20MHZ_SUBCHANS) {
165 		dfs_err(dfs, WLAN_DEBUG_DFS,
166 			"Invalid num channels: %d", *num_channels);
167 		return QDF_STATUS_E_FAILURE;
168 	}
169 
170 	for (i = 0; i < *num_channels; i++) {
171 		if (freq_list[i] == 0 ||
172 		    freq_list[i] == last_chan_freq)
173 			continue;
174 		if (!utils_is_dfs_chan_for_freq(dfs->dfs_pdev_obj,
175 						freq_list[i])) {
176 			dfs_info(dfs, WLAN_DEBUG_DFS, "ch=%d is not dfs, skip",
177 				 freq_list[i]);
178 			continue;
179 		}
180 
181 		last_chan_freq = freq_list[i];
182 		DFS_NOL_ADD_CHAN_LOCKED(dfs,
183 					freq_list[i],
184 					dfs->wlan_dfs_nol_timeout);
185 		nol_freq_list[num_ch++] = last_chan_freq;
186 		utils_dfs_deliver_event(dfs->dfs_pdev_obj,
187 					freq_list[i],
188 					WLAN_EV_NOL_STARTED);
189 		dfs_info(dfs, WLAN_DEBUG_DFS_NOL, "ch=%d Added to NOL",
190 			 last_chan_freq);
191 	}
192 
193 	if (!num_ch) {
194 		dfs_err(dfs, WLAN_DEBUG_DFS,
195 			"dfs channels not found in channel list");
196 		return QDF_STATUS_E_FAILURE;
197 	}
198 	*num_channels = num_ch;
199 
200 	if (!dfs_get_disable_radar_marking(dfs)) {
201 		utils_dfs_reg_update_nol_chan_for_freq(dfs->dfs_pdev_obj,
202 						       nol_freq_list, num_ch,
203 						       DFS_NOL_SET);
204 
205 		if (dfs->dfs_is_stadfs_enabled)
206 			if (dfs_mlme_is_opmode_sta(dfs->dfs_pdev_obj))
207 				utils_dfs_reg_update_nol_history_chan_for_freq(
208 					dfs->dfs_pdev_obj, nol_freq_list,
209 					num_ch, DFS_NOL_HISTORY_SET);
210 	}
211 
212 	dfs_nol_update(dfs);
213 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
214 
215 	return QDF_STATUS_SUCCESS;
216 }
217 #endif
218 
219 /**
220  * dfs_find_20mhz_subchans_from_offsets()- Find frequency offsets
221  * that aligns with 20MHz sub-channel centers.
222  *
223  * @freq_offset: freq offset
224  * @center_freq: center frequency
225  * @ch_width: Channel Width value: 20/40/80/160/320MHz.
226  * Find frequency offsets for 80MHz
227  *
228  * Return: None
229  */
230 static void
231 dfs_find_20mhz_subchans_from_offsets(struct freqs_offsets *freq_offset,
232 				     uint32_t center_freq,
233 				     uint16_t ch_width)
234 {
235 	uint16_t first_chan20_cen = center_freq - (ch_width / 2) + BW_10;
236 	uint16_t i, j;
237 	uint8_t num_20mhz_subchans = ch_width / BW_20;
238 
239 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
240 		uint16_t radar_found_freq =
241 					center_freq + freq_offset->offset[i];
242 		uint16_t chan20_cen = first_chan20_cen;
243 
244 		for (j = 0; j < num_20mhz_subchans; j++) {
245 			if ((radar_found_freq > chan20_cen - BW_10) &&
246 			    (radar_found_freq < chan20_cen + BW_10)) {
247 				freq_offset->freq[i] = chan20_cen;
248 				break;
249 			}
250 			chan20_cen += BW_20;
251 		}
252 	}
253 }
254 
255 #ifdef CONFIG_CHAN_FREQ_API
256 void
257 dfs_compute_radar_found_cfreq(struct wlan_dfs *dfs,
258 			      struct radar_found_info *radar_found,
259 			      uint32_t *freq_center)
260 {
261 	struct dfs_channel *curchan = dfs->dfs_curchan;
262 
263 	/* In case of 11BE Chipsets, radar found center frequency is
264 	 * directly obtained from WMI.
265 	 */
266 	if (dfs->dfs_is_radar_found_chan_freq_eq_center_freq) {
267 		*freq_center = radar_found->chan_freq;
268 		return;
269 	}
270 
271 	/* Radar found on agile detector ID.
272 	 * Applicable to chips that have a separate agile radar detector
273 	 * engine.
274 	 */
275 	if (radar_found->detector_id == dfs_get_agile_detector_id(dfs)) {
276 		*freq_center = dfs->dfs_agile_precac_freq_mhz;
277 		if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) {
278 			if (radar_found->segment_id == PRIMARY_SEG)
279 				*freq_center -= DFS_160MHZ_SECOND_SEG_OFFSET;
280 			else
281 				*freq_center += DFS_160MHZ_SECOND_SEG_OFFSET;
282 		} else if (dfs->dfs_precac_chwidth == CH_WIDTH_80P80MHZ &&
283 			   dfs->dfs_agile_precac_freq_mhz ==
284 				RESTRICTED_80P80_CHAN_CENTER_FREQ) {
285 			/*
286 			 * The reason why left and right offsets
287 			 * are different.
288 			 * Center of 165 is 5730MHz.
289 			 * Center of left 80 is 5690MHz.
290 			 * Center of right 80 is 5775MHz.
291 			 */
292 			if (radar_found->segment_id == PRIMARY_SEG)
293 				*freq_center -=
294 				    DFS_165MHZ_SECOND_SEG_OFFSET_LEFT;
295 			else
296 				*freq_center +=
297 				    DFS_165MHZ_SECOND_SEG_OFFSET_RIGHT;
298 		}
299 	} else if (!radar_found->segment_id) {
300 		*freq_center = curchan->dfs_ch_mhz_freq_seg1;
301 	} else {
302 		/* Radar found on secondary segment by the HW, when preCAC
303 		 * was not running in legacy chips or preCAC was running
304 		 * in Lithium chips.
305 		 */
306 		*freq_center = curchan->dfs_ch_mhz_freq_seg2;
307 		if (WLAN_IS_CHAN_MODE_160(curchan)) {
308 			/* If center frequency of entire 160 band
309 			 * is less than center frequency of primary
310 			 * segment, then the center frequency of
311 			 * secondary segment is -40 of center
312 			 * frequency of entire 160 segment.
313 			 */
314 			if (curchan->dfs_ch_mhz_freq_seg2 <
315 			    curchan->dfs_ch_mhz_freq_seg1)
316 				*freq_center -=
317 					DFS_160MHZ_SECOND_SEG_OFFSET;
318 			else
319 				*freq_center +=
320 					DFS_160MHZ_SECOND_SEG_OFFSET;
321 		}
322 	}
323 }
324 #endif
325 
326 /**
327  * dfs_find_radar_affected_subchans_for_freq() - Find radar affected sub chans.
328  * @dfs: Pointer to wlan_dfs structure.
329  * @radar_found: Pointer to radar_found structure.
330  * @freq_list: Pointer to save radar affected channels.
331  * @freq_center: Freq_center of the radar affected chan.
332  *
333  * Return: Number of channels.
334  */
335 #ifdef CONFIG_CHAN_FREQ_API
336 static uint8_t
337 dfs_find_radar_affected_subchans_for_freq(struct wlan_dfs *dfs,
338 					  struct radar_found_info *radar_found,
339 					  uint16_t *freq_list,
340 					  uint32_t freq_center)
341 {
342 	int i, j;
343 	uint8_t num_radar_subchans;
344 	uint32_t flag;
345 	int32_t sidx;
346 	uint16_t candidate_subchan_freq;
347 	uint16_t cur_subchans[MAX_20MHZ_SUBCHANS];
348 	uint8_t n_cur_subchans;
349 	struct dfs_channel *curchan = dfs->dfs_curchan;
350 	struct freqs_offsets freq_offset;
351 	uint16_t ch_width;
352 
353 	qdf_mem_zero(&freq_offset, sizeof(freq_offset));
354 	flag = curchan->dfs_ch_flags;
355 
356 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++)
357 		freq_offset.offset[i] = radar_found->freq_offset;
358 
359 	sidx = DFS_FREQ_OFFSET_TO_SIDX(radar_found->freq_offset);
360 
361 	dfs_info(dfs, WLAN_DEBUG_DFS,
362 		 "seg=%d, det=%d, sidx=%d, offset=%d, chirp=%d, flag=%d, f=%d",
363 		 radar_found->segment_id, radar_found->detector_id, sidx,
364 		 radar_found->freq_offset, radar_found->is_chirp,
365 		 flag, freq_center);
366 
367 	ch_width = dfs_chan_to_ch_width(curchan);
368 	if (ch_width == BW_INVALID) {
369 		dfs_err(dfs, WLAN_DEBUG_DFS,
370 			"channel flag=%d is invalid", flag);
371 		return 0;
372 	}
373 
374 	if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
375 		freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
376 		freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
377 	}
378 
379 	dfs_find_20mhz_subchans_from_offsets(&freq_offset, freq_center,
380 					     ch_width);
381 
382 	n_cur_subchans =
383 	    dfs_get_bonding_channels_for_freq(dfs, curchan,
384 					      radar_found->segment_id,
385 					      radar_found->detector_id,
386 					      cur_subchans);
387 
388 	for (i = 0, num_radar_subchans = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
389 		candidate_subchan_freq = freq_offset.freq[i];
390 		for (j = 0; j < n_cur_subchans; j++) {
391 			if (cur_subchans[j] == candidate_subchan_freq) {
392 				freq_list[num_radar_subchans++] =
393 						candidate_subchan_freq;
394 				dfs_info(dfs, WLAN_DEBUG_DFS,
395 					 "offset=%d, channel=%d",
396 					 num_radar_subchans,
397 					 freq_list[num_radar_subchans - 1]);
398 				break;
399 			}
400 		}
401 	}
402 	return num_radar_subchans;
403 }
404 #endif
405 
406 /**
407  * dfs_calc_bonding_freqs: Calculate bonding channel frequencies from the
408  * channel width's center frequency and channel width.
409  * It is assumed that the caller has allocated sufficient memory for 'freq_list'
410  * so that it can hold all the output subchannels.
411  *
412  * center_freq: Center frequency of the channel width.
413  * ch_width: Channel width.
414  * freq_list: output array of sub-channel frequencies.
415  *
416  * Return: void
417  */
418 static void
419 dfs_calc_bonding_freqs(qdf_freq_t center_freq,
420 		       uint16_t ch_width,
421 		       uint16_t *freq_list)
422 {
423 #define CHAN_SPACING_MHZ_5G 20
424 #define SUB20CHAN_BW_MHZ_5G 20
425 	uint8_t nchans = ch_width / CHAN_SPACING_MHZ_5G;
426 	qdf_freq_t first_subchan_cfreq = center_freq - (ch_width / 2) +
427 					 (SUB20CHAN_BW_MHZ_5G / 2);
428 	uint8_t i;
429 
430 	for (i = 0; i < nchans; ++i)
431 		freq_list[i] = first_subchan_cfreq + (i * CHAN_SPACING_MHZ_5G);
432 }
433 
434 /**
435  * dfs_get_20mhz_bonding_channels() - Get bonding frequency list of 20MHz
436  * channel.
437  * @center_freq: Center frequency of the 20MHz channel.
438  * @freq_list: Pointer to frequency list.
439  *
440  * Return: void
441  */
442 static
443 void dfs_get_20mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list)
444 {
445 	uint16_t chwidth = BW_20;
446 
447 	dfs_calc_bonding_freqs(center_freq, chwidth, freq_list);
448 }
449 
450 /**
451  * dfs_get_40mhz_bonding_channels() - Get bonding frequency list of 40MHz
452  * channel.
453  * @center_freq: Center frequency of the 40MHz channel.
454  * @freq_list: Pointer to frequency list.
455  *
456  * Return: void
457  */
458 static
459 void dfs_get_40mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list)
460 {
461 	uint16_t chwidth = BW_40;
462 
463 	dfs_calc_bonding_freqs(center_freq, chwidth, freq_list);
464 }
465 
466 /**
467  * dfs_get_80mhz_bonding_channels() - Get bonding frequency list of 80MHz
468  * channel.
469  * @center_freq: Center frequency of the 80MHz channel.
470  * @freq_list: Pointer to frequency list.
471  *
472  * Return: void
473  */
474 static
475 void dfs_get_80mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list)
476 {
477 	uint16_t chwidth = BW_80;
478 
479 	dfs_calc_bonding_freqs(center_freq, chwidth, freq_list);
480 }
481 
482 /**
483  * dfs_get_160mhz_bonding_channels() - Get bonding frequency list of 160MHz
484  * channel.
485  * @center_freq: Center frequency of the 160MHz channel.
486  * @freq_list: Pointer to frequency list.
487  *
488  * Return: void
489  */
490 static
491 void dfs_get_160mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list)
492 {
493 	uint16_t chwidth = BW_160;
494 
495 	dfs_calc_bonding_freqs(center_freq, chwidth, freq_list);
496 }
497 
498 /**
499  * dfs_get_320mhz_bonding_channels() - Get bonding frequency list of 320MHz
500  * channel.
501  * @center_freq: Center frequency of the 320MHz channel.
502  * @freq_list: Pointer to frequency list.
503  *
504  * Return: void
505  */
506 #ifdef WLAN_FEATURE_11BE
507 static
508 void dfs_get_320mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list,
509 				     uint8_t *nchannels)
510 {
511 	uint16_t chwidth = 320;
512 
513 	/*
514 	 * In 5Ghz band, the 320Mhz channel is always 80Mhz punctured
515 	 * to the right. Therefore, it is actually a 240Mhz channel and
516 	 * has twelve 20Mhz subchannels.
517 	 */
518 	*nchannels = NUM_CHANNELS_240MHZ;
519 	dfs_calc_bonding_freqs(center_freq, chwidth, freq_list);
520 }
521 #else
522 static
523 void dfs_get_320mhz_bonding_channels(uint16_t center_freq, uint16_t *freq_list,
524 				     uint8_t *nchannels)
525 {
526 	*nchannels = 0;
527 	dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS,
528 		  "320MHz chan width for non 11be");
529 }
530 #endif
531 
532 /*
533  * dfs_get_bonding_channel_without_seg_info_for_freq() - Get bonding frequency
534  * list.
535  * @chan: Pointer to dfs_channel.
536  * @freq_list: Pointer to frequency list.
537  */
538 #ifdef CONFIG_CHAN_FREQ_API
539 uint8_t
540 dfs_get_bonding_channel_without_seg_info_for_freq(struct dfs_channel *chan,
541 						  uint16_t *freq_list)
542 {
543 	uint16_t center_freq;
544 	uint8_t nchannels = 0;
545 
546 	center_freq = chan->dfs_ch_mhz_freq_seg1;
547 
548 	if (WLAN_IS_CHAN_MODE_20(chan)) {
549 		nchannels = 1;
550 		dfs_get_20mhz_bonding_channels(center_freq,
551 					       freq_list);
552 	} else if (WLAN_IS_CHAN_MODE_40(chan)) {
553 		nchannels = 2;
554 		dfs_get_40mhz_bonding_channels(center_freq,
555 					       freq_list);
556 	} else if (WLAN_IS_CHAN_MODE_80(chan)) {
557 		nchannels = 4;
558 		dfs_get_80mhz_bonding_channels(center_freq,
559 					       freq_list);
560 	} else if (WLAN_IS_CHAN_MODE_80_80(chan)) {
561 		nchannels = 8;
562 		dfs_get_80mhz_bonding_channels(center_freq,
563 					       freq_list);
564 		center_freq = chan->dfs_ch_mhz_freq_seg2;
565 		dfs_get_80mhz_bonding_channels(center_freq,
566 					       freq_list + 4);
567 	} else if (WLAN_IS_CHAN_MODE_160(chan)) {
568 		nchannels = 8;
569 		center_freq = chan->dfs_ch_mhz_freq_seg2;
570 		dfs_get_160mhz_bonding_channels(center_freq, freq_list);
571 	} else if (WLAN_IS_CHAN_MODE_320(chan)) {
572 		center_freq = chan->dfs_ch_mhz_freq_seg2;
573 		dfs_get_320mhz_bonding_channels(center_freq, freq_list,
574 						&nchannels);
575 	}
576 
577 	return nchannels;
578 }
579 #endif
580 
581 #ifdef CONFIG_CHAN_FREQ_API
582 /*
583  * dfs_get_agile_subchans_for_curchan_160() - Get bonding frequency list of
584  * agile channels when current operating channel is 160MHz.
585  *
586  * @dfs: Pointer to DFS structure.
587  * @center_freq: Center frequency of the channel.
588  * @segment_id: Segment ID of interest. 0 for primary segment and 1 for
589  * secondary segment.
590  * @freq_list: Pointer to frequency list.
591  * @nchannels: Number of subchannel.
592  */
593 static void
594 dfs_get_agile_subchans_for_curchan_160(struct wlan_dfs *dfs,
595 				       uint16_t center_freq,
596 				       uint32_t segment_id,
597 				       uint16_t *freq_list,
598 				       uint8_t *nchannels)
599 {
600 	if (dfs->dfs_precac_chwidth == CH_WIDTH_80MHZ) {
601 		/*
602 		 * The current operating channel is 160MHz and
603 		 * the agile channel is 80MHz. This can happen
604 		 * in HK only.
605 		 */
606 		*nchannels = 4;
607 		dfs_get_80mhz_bonding_channels(center_freq,
608 					       freq_list);
609 	} else if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ)
610 		/*
611 		 * The current operating channel is 160MHz and
612 		 * the agile channel is 160MHz.
613 		 * Pine ADFS specific.
614 		 */
615 		dfs_get_160mhz_bonding_channels(center_freq,
616 						freq_list);
617 	else if (dfs->dfs_precac_chwidth == CH_WIDTH_80P80MHZ) {
618 		/*
619 		 * The current operating channel is 160MHz and the agile channel
620 		 * is 165MHz(restricted 80P80MHZ). Pine ADFS specific.
621 		 * If the segment id is primary segment 0, shift the center
622 		 * frequency 5730MHz to the center of left 80MHz segment 5690MHz
623 		 * and add the subchannels of the left 80MHz segment.
624 		 * If the segment id is secondary segment 1, shift the center
625 		 * frequency 5730MHz to the center of right 80MHz segment
626 		 * 5775MHz and add the subchannels of the right 80MHz segment.
627 		 */
628 		*nchannels = 4;
629 		center_freq = (segment_id) ?
630 			(center_freq + DFS_165MHZ_SECOND_SEG_OFFSET_RIGHT) :
631 			(center_freq - DFS_165MHZ_SECOND_SEG_OFFSET_LEFT);
632 		dfs_get_80mhz_bonding_channels(center_freq,
633 					       freq_list);
634 	}
635 }
636 
637 /*
638  * dfs_get_bonding_channels_for_freq() - Get bonding channel frequency.
639  * @dfs: Pointer to wlan_dfs.
640  * @curchan: Pointer to dfs_channel.
641  * @segment_id: Segment ID.
642  * @detector_id: Detector ID.
643  * @freq_list: Pointer to frequency list.
644  */
645 uint8_t dfs_get_bonding_channels_for_freq(struct wlan_dfs *dfs,
646 					  struct dfs_channel *curchan,
647 					  uint32_t segment_id,
648 					  uint8_t detector_id,
649 					  uint16_t *freq_list)
650 {
651 	uint16_t center_freq;
652 	uint8_t nchannels = 0;
653 
654 	/*
655 	 * For radar in agile detector, use the center of the channel
656 	 * configured to the agile detector.
657 	 * For radar on a 160MHz home channel, use the center of 160MHz.
658 	 * For radar on all other bandwidths, use the center of the segment
659 	 * affected.
660 	 */
661 	if (detector_id == dfs_get_agile_detector_id(dfs))
662 		center_freq = dfs->dfs_agile_precac_freq_mhz;
663 	else if (WLAN_IS_CHAN_MODE_160(curchan) ||
664 		 WLAN_IS_CHAN_MODE_320(curchan))
665 		center_freq = curchan->dfs_ch_mhz_freq_seg2;
666 	else if (!segment_id)
667 		center_freq = curchan->dfs_ch_mhz_freq_seg1;
668 	else
669 		center_freq = curchan->dfs_ch_mhz_freq_seg2;
670 
671 	if (WLAN_IS_CHAN_MODE_20(curchan)) {
672 		nchannels = 1;
673 		dfs_get_20mhz_bonding_channels(center_freq, freq_list);
674 	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
675 		nchannels = 2;
676 		dfs_get_40mhz_bonding_channels(center_freq, freq_list);
677 	} else if (WLAN_IS_CHAN_MODE_80(curchan)) {
678 		nchannels = 4;
679 		dfs_get_80mhz_bonding_channels(center_freq, freq_list);
680 	} else if (WLAN_IS_CHAN_MODE_160(curchan)) {
681 		nchannels = 8;
682 		if (detector_id == dfs_get_agile_detector_id(dfs))
683 			dfs_get_agile_subchans_for_curchan_160(dfs,
684 							       center_freq,
685 							       segment_id,
686 							       freq_list,
687 							       &nchannels);
688 		else
689 			dfs_get_160mhz_bonding_channels(center_freq, freq_list);
690 	} else if (WLAN_IS_CHAN_MODE_320(curchan)) {
691 		dfs_get_320mhz_bonding_channels(center_freq, freq_list,
692 						&nchannels);
693 	}  else if (WLAN_IS_CHAN_MODE_80_80(curchan)) {
694 		/*
695 		 * If the current channel's bandwidth is 80P80MHz,
696 		 * the corresponding agile Detector's bandwidth will be 160MHz
697 		 * in case of Pine ADFS.
698 		 */
699 		if (detector_id == dfs_get_agile_detector_id(dfs)) {
700 			if (dfs->dfs_precac_chwidth == CH_WIDTH_160MHZ) {
701 				nchannels = 8;
702 				dfs_get_160mhz_bonding_channels(center_freq,
703 								freq_list);
704 			} else if (dfs->dfs_precac_chwidth == CH_WIDTH_80MHZ) {
705 				nchannels = 4;
706 				dfs_get_80mhz_bonding_channels(center_freq,
707 							       freq_list);
708 			} else {
709 				dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
710 					"Incorrect precac width %u",
711 					dfs->dfs_precac_chwidth);
712 			}
713 		} else {
714 			/*
715 			 * If the radar is getting detected in 80P80MHz home
716 			 * channel, only the 80MHz segment that is infected with
717 			 * radar is of interest. The other 80MHz segment is
718 			 * ignored. The center frequency of the radar infected
719 			 * segment is dfs_ch_mhz_freq_seg1 if primary and
720 			 * dfs_ch_mhz_freq_seg2 in case of secondary.
721 			 */
722 			nchannels = 4;
723 			dfs_get_80mhz_bonding_channels(center_freq, freq_list);
724 		}
725 	}
726 
727 	return nchannels;
728 }
729 #endif
730 
731 void dfs_reset_bangradar(struct wlan_dfs *dfs)
732 {
733 	dfs->dfs_bangradar_type = DFS_NO_BANGRADAR;
734 }
735 
736 /**
737  * dfs_radar_found_event_basic_sanity() - Check if radar event is received on a
738  * DFS channel.
739  * @dfs: Pointer to wlan_dfs structure.
740  * @chan: Current channel.
741  *
742  * Return: If a radar event found on NON-DFS channel return false. Otherwise,
743  * return true.
744  */
745 static
746 bool dfs_radar_found_event_basic_sanity(struct wlan_dfs *dfs,
747 					struct dfs_channel *chan)
748 {
749 	if (!chan) {
750 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS,
751 			"dfs->dfs_curchan is NULL");
752 		return false;
753 	}
754 
755 	if (!(WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(chan))) {
756 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
757 			  "radar event on non-DFS chan");
758 		return false;
759 	}
760 
761 	return true;
762 }
763 
764 void dfs_send_csa_to_current_chan(struct wlan_dfs *dfs)
765 {
766 	dfs->wlan_dfstest = 1;
767 	dfs->wlan_dfstest_ieeechan = dfs->dfs_curchan->dfs_ch_ieee;
768 	dfs->wlan_dfstesttime = 1;   /* 1ms */
769 	qdf_timer_sync_cancel(&dfs->wlan_dfstesttimer);
770 	qdf_timer_start(&dfs->wlan_dfstesttimer, dfs->wlan_dfstesttime);
771 }
772 
773 int dfs_second_segment_radar_disable(struct wlan_dfs *dfs)
774 {
775 	dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN;
776 
777 	return 0;
778 }
779 
780 #ifdef WLAN_DFS_FULL_OFFLOAD
781 void dfs_inc_num_radar(struct wlan_dfs *dfs)
782 {
783 	dfs->wlan_dfs_stats.num_radar_detects++;
784 }
785 #endif /* WLAN_DFS_FULL_OFFLOAD */
786 
787 #if defined(WLAN_DFS_TRUE_160MHZ_SUPPORT) && defined(WLAN_DFS_FULL_OFFLOAD)
788 void dfs_translate_radar_params(struct wlan_dfs *dfs,
789 				struct radar_found_info *radar_found)
790 {
791 	struct dfs_channel *curchan = dfs->dfs_curchan;
792 	bool is_primary_ch_right_of_center = false;
793 
794 	if (!dfs_is_true_160mhz_supported(dfs))
795 		return;
796 
797 	if (radar_found->detector_id == dfs_get_agile_detector_id(dfs)) {
798 		dfs_translate_radar_params_for_agile_chan(dfs, radar_found);
799 		return;
800 	}
801 
802 	/* Is the primary channel ( or primary 80 segment) to the right
803 	 * of the center of 160/165Mhz channel.
804 	 */
805 	if (curchan->dfs_ch_freq > curchan->dfs_ch_mhz_freq_seg2)
806 		is_primary_ch_right_of_center = true;
807 
808 	if (WLAN_IS_CHAN_MODE_160(curchan)) {
809 		if (radar_found->freq_offset > 0) {
810 			/* Offset positive: Equivalent to Upper IEEE
811 			 * 80Mhz chans Synthesizer.
812 			 */
813 			if (!is_primary_ch_right_of_center)
814 				radar_found->segment_id = SEG_ID_SECONDARY;
815 			radar_found->freq_offset -=
816 				DFS_160MHZ_SECOND_SEG_OFFSET;
817 		} else {
818 			/* Offset negative: Equivalent to Lower IEEE
819 			 * 80Mhz chans Synthesizer.
820 			 */
821 			if (is_primary_ch_right_of_center)
822 				radar_found->segment_id = SEG_ID_SECONDARY;
823 			radar_found->freq_offset +=
824 				DFS_160MHZ_SECOND_SEG_OFFSET;
825 		}
826 	} else if (WLAN_IS_CHAN_MODE_165(dfs, curchan)) {
827 		/* If offset is greater than 40MHz, radar is found on the
828 		 * secondary segment.
829 		 */
830 		if (abs(radar_found->freq_offset) > 40) {
831 			radar_found->segment_id = SEG_ID_SECONDARY;
832 			/* Update the freq. offset with respect to the
833 			 * secondary segment center freq.
834 			 */
835 			if (is_primary_ch_right_of_center)
836 				radar_found->freq_offset +=
837 					DFS_80P80MHZ_SECOND_SEG_OFFSET;
838 			else
839 				radar_found->freq_offset -=
840 					DFS_80P80MHZ_SECOND_SEG_OFFSET;
841 		}
842 	}
843 }
844 #endif /* WLAN_DFS_TRUE_160MHZ_SUPPORT */
845 
846 /**
847  * dfs_radar_action_for_hw_mode_switch()- Radar cannot be processed when HW
848  * switch is in progress. So save the radar found parameters for
849  * future processing.
850  * @dfs: Pointer to wlan_dfs structure.
851  * @radar_found: Pointer to radar found structure.
852  *
853  * Return: QDF_STATUS
854  */
855 static QDF_STATUS
856 dfs_radar_action_for_hw_mode_switch(struct wlan_dfs *dfs,
857 				    struct radar_found_info *radar_found)
858 {
859 	struct radar_found_info *radar_params = NULL;
860 
861 	radar_params = qdf_mem_malloc(sizeof(*radar_params));
862 	if (!radar_params)
863 		return QDF_STATUS_E_NOMEM;
864 
865 	/* If CAC timer is running, cancel it here rather than
866 	 * after processing to avoid handling unnecessary CAC timeouts.
867 	 */
868 	if (dfs->dfs_cac_timer_running)
869 		dfs_cac_stop(dfs);
870 
871 	/* If CAC timer is to be handled after mode switch and then
872 	 * we receive radar, no point in handling CAC completion.
873 	 */
874 	if (dfs->dfs_defer_params.is_cac_completed)
875 		dfs->dfs_defer_params.is_cac_completed = false;
876 	qdf_mem_copy(radar_params, radar_found, sizeof(*radar_params));
877 	dfs->dfs_defer_params.radar_params = radar_params;
878 	dfs->dfs_defer_params.is_radar_detected = true;
879 
880 	return QDF_STATUS_SUCCESS;
881 }
882 
883 #ifdef CONFIG_CHAN_FREQ_API
884 uint8_t
885 dfs_find_radar_affected_channels(struct wlan_dfs *dfs,
886 				 struct radar_found_info *radar_found,
887 				 uint16_t *freq_list,
888 				 uint32_t freq_center)
889 {
890 	uint8_t num_channels;
891 
892 	if (dfs->dfs_bangradar_type == DFS_BANGRADAR_FOR_ALL_SUBCHANS)
893 		num_channels =
894 			dfs_get_bonding_channel_without_seg_info_for_freq
895 			(dfs->dfs_curchan, freq_list);
896 	/* BW reduction is dependent on subchannel marking */
897 	else if ((dfs->dfs_use_nol_subchannel_marking) &&
898 		 (!(dfs->dfs_bangradar_type) ||
899 		 (dfs->dfs_bangradar_type ==
900 		  DFS_BANGRADAR_FOR_SPECIFIC_SUBCHANS)))
901 		num_channels =
902 		dfs_find_radar_affected_subchans_for_freq(dfs,
903 							  radar_found,
904 							  freq_list,
905 							  freq_center);
906 	else
907 		num_channels = dfs_get_bonding_channels_for_freq
908 			(dfs,
909 			 dfs->dfs_curchan,
910 			 radar_found->segment_id,
911 			 radar_found->detector_id,
912 			 freq_list);
913 
914 	return num_channels;
915 }
916 
917 #if defined(QCA_SUPPORT_AGILE_DFS) || defined(ATH_SUPPORT_ZERO_CAC_DFS) || \
918 	defined(QCA_SUPPORT_ADFS_RCAC)
919 /**
920  * dfs_is_radarsource_agile() - Indicates whether the radar event is received
921  * on the agile channel.
922  * @dfs: Pointer to wlan_dfs structure.
923  * @radar_found: Pointer to radar_found_info structure.
924  *
925  * Return: QDF_STATUS
926  */
927 static
928 bool dfs_is_radarsource_agile(struct wlan_dfs *dfs,
929 			      struct radar_found_info *radar_found)
930 {
931 	bool is_radar_from_agile_dfs =
932 	    ((dfs_is_agile_precac_enabled(dfs) &&
933 	      dfs_is_precac_timer_running(dfs)) ||
934 	     dfs_is_agile_rcac_enabled(dfs)) &&
935 	    (radar_found->detector_id == dfs_get_agile_detector_id(dfs));
936 
937 	dfs_debug(dfs, WLAN_DEBUG_DFS_AGILE,
938 		  "radar on PreCAC segment: ADFS:%d",
939 		  is_radar_from_agile_dfs);
940 
941 	return is_radar_from_agile_dfs;
942 }
943 #else
944 static
945 bool dfs_is_radarsource_agile(struct wlan_dfs *dfs,
946 			      struct radar_found_info *radar_found)
947 {
948 	return false;
949 }
950 #endif
951 
952 QDF_STATUS
953 dfs_process_radar_ind(struct wlan_dfs *dfs,
954 		      struct radar_found_info *radar_found)
955 {
956 	QDF_STATUS status;
957 
958 	/* Acquire a lock to avoid initiating mode switch till radar
959 	 * processing is completed.
960 	 */
961 	DFS_RADAR_MODE_SWITCH_LOCK(dfs);
962 
963 	if (utils_dfs_can_ignore_radar_event(dfs->dfs_pdev_obj)) {
964 		DFS_RADAR_MODE_SWITCH_UNLOCK(dfs);
965 		return QDF_STATUS_SUCCESS;
966 	}
967 
968 	/* Before processing radar, check if HW mode switch is in progress.
969 	 * If in progress, defer the processing of radar event received till
970 	 * the mode switch is completed.
971 	 */
972 	if (dfs_is_hw_mode_switch_in_progress(dfs))
973 		status = dfs_radar_action_for_hw_mode_switch(dfs, radar_found);
974 	else if (dfs_is_radarsource_agile(dfs, radar_found))
975 		status = dfs_process_radar_ind_on_agile_chan(dfs, radar_found);
976 	else
977 		status = dfs_process_radar_ind_on_home_chan(dfs, radar_found);
978 
979 	DFS_RADAR_MODE_SWITCH_UNLOCK(dfs);
980 
981 	return status;
982 }
983 
984 QDF_STATUS
985 dfs_process_radar_ind_on_home_chan(struct wlan_dfs *dfs,
986 				   struct radar_found_info *radar_found)
987 {
988 	bool wait_for_csa = false;
989 	uint16_t freq_list[MAX_20MHZ_SUBCHANS];
990 	uint16_t nol_freq_list[MAX_20MHZ_SUBCHANS];
991 	uint8_t num_channels;
992 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
993 	uint32_t freq_center;
994 	uint32_t radarfound_freq;
995 	struct dfs_channel *dfs_curchan;
996 
997 	dfs_curchan = dfs->dfs_curchan;
998 
999 	/* Check if the current channel is a non DFS channel
1000 	 * If the current channel is non-DFS and the radar is from Agile
1001 	 * Detector we need to process it since Agile Detector has a
1002 	 * different channel.
1003 	 */
1004 	if (!dfs_radar_found_event_basic_sanity(dfs, dfs_curchan))
1005 		goto exit;
1006 
1007 	dfs_compute_radar_found_cfreq(dfs, radar_found, &freq_center);
1008 	radarfound_freq = freq_center + radar_found->freq_offset;
1009 
1010 	if (radar_found->segment_id == SEG_ID_SECONDARY)
1011 		dfs_debug(dfs, WLAN_DEBUG_DFS_ALWAYS,
1012 			  "Radar found on second segment.Radarfound Freq=%d MHz.Secondary Chan cfreq=%d MHz.",
1013 			  radarfound_freq, freq_center);
1014 	else
1015 		dfs_debug(NULL, WLAN_DEBUG_DFS_ALWAYS,
1016 			  "Radar found on channel=%d, freq=%d MHz. Primary beaconning chan:%d, freq=%d MHz.",
1017 			  utils_dfs_freq_to_chan(radarfound_freq),
1018 			  radarfound_freq, dfs_curchan->dfs_ch_ieee,
1019 			  dfs_curchan->dfs_ch_freq);
1020 
1021 	utils_dfs_deliver_event(dfs->dfs_pdev_obj, radarfound_freq,
1022 				WLAN_EV_RADAR_DETECTED);
1023 
1024 	if (!dfs->dfs_use_nol) {
1025 		if (!dfs->dfs_is_offload_enabled) {
1026 			dfs_radar_disable(dfs);
1027 			dfs_second_segment_radar_disable(dfs);
1028 			dfs_flush_additional_pulses(dfs);
1029 		}
1030 		dfs_reset_bangradar(dfs);
1031 		dfs_send_csa_to_current_chan(dfs);
1032 		status = QDF_STATUS_SUCCESS;
1033 		goto exit;
1034 	}
1035 	num_channels = dfs_find_radar_affected_channels(dfs,
1036 							radar_found,
1037 							freq_list,
1038 							freq_center);
1039 
1040 	dfs_reset_bangradar(dfs);
1041 
1042 	status = dfs_radar_add_channel_list_to_nol_for_freq(dfs,
1043 							    freq_list,
1044 							    nol_freq_list,
1045 							    &num_channels);
1046 	if (QDF_IS_STATUS_ERROR(status)) {
1047 		dfs_err(dfs, WLAN_DEBUG_DFS,
1048 			"radar event received on invalid channel");
1049 		goto exit;
1050 	}
1051 
1052 	/*
1053 	 * If precac is running and the radar found in secondary
1054 	 * VHT80 mark the channel as radar and add to NOL list.
1055 	 * Otherwise random channel selection can choose this
1056 	 * channel.
1057 	 */
1058 	dfs_debug(dfs, WLAN_DEBUG_DFS,
1059 		  "found_on_second=%d is_pre=%d",
1060 		  dfs->is_radar_found_on_secondary_seg,
1061 		  dfs_is_precac_timer_running(dfs));
1062 	/*
1063 	 * Even if radar found on primary, we need to mark the channel as NOL
1064 	 * in preCAC list. The preCAC list also maintains the current CAC
1065 	 * channels as part of pre-cleared DFS. Hence call the API
1066 	 * to mark channels as NOL irrespective of preCAC being enabled or not.
1067 	 */
1068 
1069 	dfs_debug(dfs, WLAN_DEBUG_DFS,
1070 		  "Radar found on dfs detector: %d", radar_found->detector_id);
1071 	dfs_mark_precac_nol_for_freq(dfs,
1072 				     dfs->is_radar_found_on_secondary_seg,
1073 				     radar_found->detector_id,
1074 				     nol_freq_list,
1075 				     num_channels);
1076 
1077 	dfs_send_nol_ie_and_rcsa(dfs,
1078 				 radar_found,
1079 				 nol_freq_list,
1080 				 num_channels,
1081 				 &wait_for_csa);
1082 
1083 	if (!dfs->dfs_is_offload_enabled &&
1084 	    dfs->is_radar_found_on_secondary_seg) {
1085 		dfs_second_segment_radar_disable(dfs);
1086 		dfs->is_radar_found_on_secondary_seg = 0;
1087 
1088 		if (dfs->is_radar_during_precac) {
1089 			dfs->is_radar_during_precac = 0;
1090 			goto exit;
1091 		}
1092 	}
1093 
1094 	/*
1095 	 * XXX TODO: the umac NOL code isn't used, but
1096 	 * WLAN_CHAN_DFS_RADAR still gets set. Since the umac
1097 	 * NOL code isn't used, that flag is never cleared. This
1098 	 * needs to be fixed. See EV 105776.
1099 	 */
1100 	if (wait_for_csa)
1101 		goto exit;
1102 
1103 	/*
1104 	 * EV 129487 : We have detected radar in the channel,
1105 	 * stop processing PHY error data as this can cause
1106 	 * false detect in the new channel while channel
1107 	 * change is in progress.
1108 	 */
1109 
1110 	if (!dfs->dfs_is_offload_enabled) {
1111 		dfs_radar_disable(dfs);
1112 		dfs_second_segment_radar_disable(dfs);
1113 		/*
1114 		 * The radar queues were reset just after the filter match, but
1115 		 * the phyerror reception was not disabled. This might
1116 		 * cause the unwanted additional/accumulated pulses to be
1117 		 * detected as radar in the new channel. So, clear the radar
1118 		 * queues and the associated variables.
1119 		 */
1120 		dfs_flush_additional_pulses(dfs);
1121 	}
1122 
1123 	dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
1124 			  dfs->dfs_curchan->dfs_ch_ieee,
1125 			  dfs->dfs_curchan->dfs_ch_freq,
1126 			  dfs->dfs_curchan->dfs_ch_mhz_freq_seg2,
1127 			  dfs->dfs_curchan->dfs_ch_flags);
1128 
1129 exit:
1130 	return status;
1131 }
1132 #endif
1133