xref: /wlan-dirver/qca-wifi-host-cmn/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c (revision fa47688f04ef001a6dcafaebdcc3c031f15ee75e)
1 /*
2  * Copyright (c) 2017-2019 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_zero_cac.h"
26 #include "../dfs_etsi_precac.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 /**
154  * dfs_radar_add_channel_list_to_nol()- Add given channels to nol
155  * @dfs: Pointer to wlan_dfs structure.
156  * @channels: Pointer to the channel list.
157  * @num_channels: Number of channels in the list.
158  *
159  * Add list of channels to nol, only if the channel is dfs.
160  *
161  * Return: QDF_STATUS
162  */
163 static QDF_STATUS dfs_radar_add_channel_list_to_nol(struct wlan_dfs *dfs,
164 						    uint8_t *channels,
165 						    uint8_t num_channels)
166 {
167 	int i;
168 	uint8_t last_chan = 0;
169 	uint8_t nollist[NUM_CHANNELS_160MHZ];
170 	uint8_t num_ch = 0;
171 
172 	if (num_channels > NUM_CHANNELS_160MHZ) {
173 		dfs_err(dfs, WLAN_DEBUG_DFS,
174 			"Invalid num channels: %d", num_channels);
175 		return QDF_STATUS_E_FAILURE;
176 	}
177 
178 	for (i = 0; i < num_channels; i++) {
179 		if (channels[i] == 0 ||
180 		    channels[i] == last_chan)
181 			continue;
182 		if (!utils_is_dfs_ch(dfs->dfs_pdev_obj, channels[i])) {
183 			dfs_info(dfs, WLAN_DEBUG_DFS, "ch=%d is not dfs, skip",
184 				 channels[i]);
185 			continue;
186 		}
187 		last_chan = channels[i];
188 		DFS_NOL_ADD_CHAN_LOCKED(dfs,
189 				(uint16_t)utils_dfs_chan_to_freq(channels[i]),
190 				dfs->wlan_dfs_nol_timeout);
191 		nollist[num_ch++] = last_chan;
192 		dfs_info(dfs, WLAN_DEBUG_DFS_NOL, "ch=%d Added to NOL",
193 			 last_chan);
194 	}
195 
196 	if (!num_ch) {
197 		dfs_err(dfs, WLAN_DEBUG_DFS,
198 			"dfs channels not found in channel list");
199 		return QDF_STATUS_E_FAILURE;
200 	}
201 
202 	utils_dfs_reg_update_nol_ch(dfs->dfs_pdev_obj,
203 				    nollist, num_ch, 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_ch(
208 					dfs->dfs_pdev_obj, nollist, num_ch,
209 					DFS_NOL_HISTORY_SET);
210 
211 	dfs_nol_update(dfs);
212 	utils_dfs_save_nol(dfs->dfs_pdev_obj);
213 
214 	return QDF_STATUS_SUCCESS;
215 }
216 
217 /**
218  * dfs_radar_chan_for_80()- Find frequency offsets for 80MHz
219  * @freq_offset: freq offset
220  * @center_freq: center frequency
221  *
222  * Find frequency offsets for 80MHz
223  *
224  * Return: None
225  */
226 static void dfs_radar_chan_for_80(struct freqs_offsets *freq_offset,
227 				  uint32_t center_freq)
228 {
229 	int i;
230 
231 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
232 		if (freq_offset->offset[i] < DFS_OFFSET_SECOND_LOWER)
233 			freq_offset->freq[i] =
234 				DFS_THIRD_LOWER_CHANNEL(center_freq);
235 		else if ((freq_offset->offset[i] > DFS_OFFSET_SECOND_LOWER) &&
236 			 (freq_offset->offset[i] < DFS_OFFSET_FIRST_LOWER))
237 			freq_offset->freq[i] =
238 				DFS_SECOND_LOWER_CHANNEL(center_freq);
239 		else if ((freq_offset->offset[i] > DFS_OFFSET_FIRST_LOWER) &&
240 			 (freq_offset->offset[i] < 0))
241 			freq_offset->freq[i] =
242 				DFS_FIRST_LOWER_CHANNEL(center_freq);
243 		else if ((freq_offset->offset[i] > 0) &&
244 			  (freq_offset->offset[i] < DFS_OFFSET_FIRST_UPPER))
245 			freq_offset->freq[i] =
246 				DFS_FIRST_UPPER_CHANNEL(center_freq);
247 		else if ((freq_offset->offset[i] > DFS_OFFSET_FIRST_UPPER) &&
248 			 (freq_offset->offset[i] < DFS_OFFSET_SECOND_UPPER))
249 			freq_offset->freq[i] =
250 				DFS_SECOND_UPPER_CHANNEL(center_freq);
251 		else if (freq_offset->offset[i] > DFS_OFFSET_SECOND_UPPER)
252 			freq_offset->freq[i] =
253 				DFS_THIRD_UPPER_CHANNEL(center_freq);
254 	}
255 }
256 
257 /**
258  * dfs_radar_chan_for_40()- Find frequency offsets for 40MHz
259  * @freq_offset: freq offset
260  * @center_freq: center frequency
261  *
262  * Find frequency offsets for 40MHz
263  *
264  * Return: None
265  */
266 static void dfs_radar_chan_for_40(struct freqs_offsets *freq_offset,
267 				  uint32_t center_freq)
268 {
269 	int i;
270 
271 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
272 		if (freq_offset->offset[i] < DFS_OFFSET_FIRST_LOWER)
273 			freq_offset->freq[i] =
274 				DFS_SECOND_LOWER_CHANNEL(center_freq);
275 		else if ((freq_offset->offset[i] > DFS_OFFSET_FIRST_LOWER) &&
276 			 (freq_offset->offset[i] < 0))
277 			freq_offset->freq[i] =
278 				DFS_FIRST_LOWER_CHANNEL(center_freq);
279 		else if ((freq_offset->offset[i] > 0) &&
280 			 (freq_offset->offset[i] < DFS_OFFSET_FIRST_UPPER))
281 			freq_offset->freq[i] =
282 				DFS_FIRST_UPPER_CHANNEL(center_freq);
283 		else if (freq_offset->offset[i] > DFS_OFFSET_FIRST_UPPER)
284 			freq_offset->freq[i] =
285 				DFS_SECOND_UPPER_CHANNEL(center_freq);
286 	}
287 }
288 
289 /**
290  * dfs_radar_chan_for_20()- Find frequency offsets for 20MHz
291  * @freq_offset: freq offset
292  * @center_freq: center frequency
293  *
294  * Find frequency offsets for 20MHz
295  *
296  * Return: None
297  */
298 static void dfs_radar_chan_for_20(struct freqs_offsets *freq_offset,
299 				  uint32_t center_freq)
300 {
301 	int i;
302 
303 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
304 		if (freq_offset->offset[i] <= DFS_20MZ_OFFSET_LOWER)
305 			freq_offset->freq[i] =
306 				DFS_20MHZ_LOWER_CHANNEL(center_freq);
307 		else if ((freq_offset->offset[i] > DFS_20MZ_OFFSET_LOWER) &&
308 			  (freq_offset->offset[i] < DFS_20MZ_OFFSET_UPPER))
309 			freq_offset->freq[i] = center_freq;
310 		else if (freq_offset->offset[i] >= DFS_20MZ_OFFSET_UPPER)
311 			freq_offset->freq[i] =
312 				DFS_20MHZ_UPPER_CHANNEL(center_freq);
313 	}
314 }
315 
316 /* dfs_compute_radar_found_cfreq(): Computes the centre frequency of the
317  * radar hit channel.
318  * @dfs: Pointer to wlan_dfs structure.
319  * @radar_found: Pointer to radar_found_info.
320  * @freq_center: Pointer to retrieve the value of radar found cfreq.
321  */
322 static void
323 dfs_compute_radar_found_cfreq(struct wlan_dfs *dfs,
324 			      struct radar_found_info
325 			      *radar_found,
326 			      uint32_t *freq_center)
327 {
328 	struct dfs_channel *curchan = dfs->dfs_curchan;
329 	uint64_t flag;
330 
331 	flag = curchan->dfs_ch_flags;
332 	if (!radar_found->segment_id) {
333 		*freq_center = utils_dfs_chan_to_freq(
334 				curchan->dfs_ch_vhtop_ch_freq_seg1);
335 	} else {
336 		if (dfs_is_precac_timer_running(dfs)) {
337 			*freq_center = utils_dfs_chan_to_freq(
338 					dfs->dfs_precac_secondary_freq);
339 		} else {
340 			*freq_center = utils_dfs_chan_to_freq(
341 					curchan->dfs_ch_vhtop_ch_freq_seg2);
342 			if ((flag & WLAN_CHAN_VHT160) ||
343 			    (flag & WLAN_CHAN_HE160))
344 				*freq_center += DFS_160MHZ_SECOND_SEG_OFFSET;
345 		}
346 	}
347 }
348 
349 /**
350  * dfs_find_radar_affected_subchans() - Finds radar affected sub channels.
351  * @dfs: Pointer to wlan_dfs structure.
352  * @radar_found: Pointer to radar_found structure.
353  * @channels: Pointer to save radar affected channels.
354  * @freq_center: Freq_center of the radar affected chan.
355  *
356  * Return: Number of channels.
357  */
358 static uint8_t dfs_find_radar_affected_subchans(struct wlan_dfs *dfs,
359 						struct radar_found_info
360 						*radar_found,
361 						uint8_t *channels,
362 						uint32_t freq_center)
363 {
364 	int i, j;
365 	uint8_t num_radar_subchans;
366 	uint32_t flag;
367 	int32_t sidx;
368 	uint8_t candidate_subchan;
369 	uint8_t cur_subchans[NUM_CHANNELS_160MHZ];
370 	uint8_t n_cur_subchans;
371 	struct dfs_channel *curchan = dfs->dfs_curchan;
372 	struct freqs_offsets freq_offset;
373 
374 	qdf_mem_set(&freq_offset, sizeof(freq_offset), 0);
375 	flag = curchan->dfs_ch_flags;
376 
377 	for (i = 0; i < DFS_NUM_FREQ_OFFSET; i++)
378 		freq_offset.offset[i] = radar_found->freq_offset;
379 
380 	sidx = DFS_FREQ_OFFSET_TO_SIDX(radar_found->freq_offset);
381 
382 	dfs_info(dfs, WLAN_DEBUG_DFS,
383 		 "seg=%d, sidx=%d, offset=%d, chirp=%d, flag=%d, f=%d",
384 		 radar_found->segment_id, sidx,
385 		 radar_found->freq_offset, radar_found->is_chirp,
386 		 flag, freq_center);
387 
388 	if ((WLAN_IS_CHAN_A(curchan)) ||
389 	    WLAN_IS_CHAN_MODE_20(curchan)) {
390 		if (radar_found->is_chirp ||
391 		    (sidx && !(abs(sidx) % DFS_BOUNDARY_SIDX))) {
392 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
393 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
394 		}
395 		dfs_radar_chan_for_20(&freq_offset, freq_center);
396 	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
397 		if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
398 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
399 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
400 		}
401 		dfs_radar_chan_for_40(&freq_offset, freq_center);
402 	} else if (WLAN_IS_CHAN_MODE_80(curchan) ||
403 			WLAN_IS_CHAN_MODE_160(curchan) ||
404 			WLAN_IS_CHAN_MODE_80_80(curchan)) {
405 		if (radar_found->is_chirp || !(abs(sidx) % DFS_BOUNDARY_SIDX)) {
406 			freq_offset.offset[LEFT_CH] -= DFS_CHIRP_OFFSET;
407 			freq_offset.offset[RIGHT_CH] += DFS_CHIRP_OFFSET;
408 		}
409 		dfs_radar_chan_for_80(&freq_offset, freq_center);
410 	} else {
411 		dfs_err(dfs, WLAN_DEBUG_DFS,
412 			"channel flag=%d is invalid", flag);
413 		return 0;
414 	}
415 
416 	n_cur_subchans = dfs_get_bonding_channels(dfs, curchan,
417 						  radar_found->segment_id,
418 						  cur_subchans);
419 
420 	for (i = 0, num_radar_subchans = 0; i < DFS_NUM_FREQ_OFFSET; i++) {
421 		candidate_subchan = utils_dfs_freq_to_chan(freq_offset.freq[i]);
422 		for (j = 0; j < n_cur_subchans; j++) {
423 			if (cur_subchans[j] == candidate_subchan) {
424 				channels[num_radar_subchans++] =
425 						candidate_subchan;
426 				dfs_info(dfs, WLAN_DEBUG_DFS,
427 					 "offset=%d, channel=%d",
428 					 num_radar_subchans,
429 					 channels[num_radar_subchans - 1]);
430 				break;
431 			}
432 		}
433 	}
434 	return num_radar_subchans;
435 }
436 
437 uint8_t dfs_get_bonding_channels_without_seg_info(struct dfs_channel *chan,
438 						  uint8_t *channels)
439 {
440 	uint8_t center_chan;
441 	uint8_t nchannels = 0;
442 
443 	center_chan = chan->dfs_ch_vhtop_ch_freq_seg1;
444 
445 	if (WLAN_IS_CHAN_MODE_20(chan)) {
446 		nchannels = 1;
447 		channels[0] = center_chan;
448 	} else if (WLAN_IS_CHAN_MODE_40(chan)) {
449 		nchannels = 2;
450 		channels[0] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
451 		channels[1] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
452 	} else if (WLAN_IS_CHAN_MODE_80(chan)) {
453 		nchannels = 4;
454 		channels[0] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
455 		channels[1] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
456 		channels[2] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
457 		channels[3] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
458 	} else if (WLAN_IS_CHAN_MODE_80_80(chan)) {
459 		nchannels = 8;
460 		channels[0] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
461 		channels[1] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
462 		channels[2] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
463 		channels[3] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
464 		center_chan = chan->dfs_ch_vhtop_ch_freq_seg2;
465 		channels[4] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
466 		channels[5] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
467 		channels[6] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
468 		channels[7] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
469 	} else if (WLAN_IS_CHAN_MODE_160(chan)) {
470 		nchannels = 8;
471 		center_chan = chan->dfs_ch_vhtop_ch_freq_seg2;
472 		channels[0] = center_chan - DFS_5GHZ_4TH_CHAN_OFFSET;
473 		channels[1] = center_chan - DFS_5GHZ_3RD_CHAN_OFFSET;
474 		channels[2] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
475 		channels[3] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
476 		channels[4] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
477 		channels[5] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
478 		channels[6] = center_chan + DFS_5GHZ_3RD_CHAN_OFFSET;
479 		channels[7] = center_chan + DFS_5GHZ_4TH_CHAN_OFFSET;
480 	}
481 
482 	return nchannels;
483 }
484 
485 uint8_t dfs_get_bonding_channels(struct wlan_dfs *dfs,
486 				 struct dfs_channel *curchan,
487 				 uint32_t segment_id,
488 				 uint8_t *channels)
489 {
490 	uint8_t center_chan;
491 	uint8_t nchannels = 0;
492 
493 	if (!segment_id)
494 		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg1;
495 	else {
496 		/* When precac is running "dfs_ch_vhtop_ch_freq_seg2" is
497 		 * zero and "dfs_precac_secondary_freq" holds the secondary
498 		 * frequency.
499 		 */
500 		if (dfs_is_precac_timer_running(dfs))
501 			center_chan = dfs->dfs_precac_secondary_freq;
502 		else
503 			center_chan = curchan->dfs_ch_vhtop_ch_freq_seg2;
504 	}
505 
506 	if (WLAN_IS_CHAN_MODE_20(curchan)) {
507 		nchannels = 1;
508 		channels[0] = center_chan;
509 	} else if (WLAN_IS_CHAN_MODE_40(curchan)) {
510 		nchannels = 2;
511 		channels[0] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
512 		channels[1] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
513 	} else if (WLAN_IS_CHAN_MODE_80(curchan) ||
514 		   WLAN_IS_CHAN_MODE_80_80(curchan)) {
515 		nchannels = 4;
516 		channels[0] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
517 		channels[1] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
518 		channels[2] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
519 		channels[3] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
520 	} else if (WLAN_IS_CHAN_MODE_160(curchan)) {
521 		nchannels = 8;
522 		center_chan = curchan->dfs_ch_vhtop_ch_freq_seg2;
523 		channels[0] = center_chan - DFS_5GHZ_4TH_CHAN_OFFSET;
524 		channels[1] = center_chan - DFS_5GHZ_3RD_CHAN_OFFSET;
525 		channels[2] = center_chan - DFS_5GHZ_2ND_CHAN_OFFSET;
526 		channels[3] = center_chan - DFS_5GHZ_NEXT_CHAN_OFFSET;
527 		channels[4] = center_chan + DFS_5GHZ_NEXT_CHAN_OFFSET;
528 		channels[5] = center_chan + DFS_5GHZ_2ND_CHAN_OFFSET;
529 		channels[6] = center_chan + DFS_5GHZ_3RD_CHAN_OFFSET;
530 		channels[7] = center_chan + DFS_5GHZ_4TH_CHAN_OFFSET;
531 	}
532 
533 	return nchannels;
534 }
535 
536 static inline void dfs_reset_bangradar(struct wlan_dfs *dfs)
537 {
538 	dfs->dfs_bangradar_type = DFS_NO_BANGRADAR;
539 }
540 
541 int dfs_radarevent_basic_sanity(struct wlan_dfs *dfs,
542 		struct dfs_channel *chan)
543 {
544 	if (!(dfs->dfs_seg_id == SEG_ID_SECONDARY &&
545 	      dfs_is_precac_timer_running(dfs)))
546 		if (!(WLAN_IS_PRIMARY_OR_SECONDARY_CHAN_DFS(chan))) {
547 			dfs_debug(dfs, WLAN_DEBUG_DFS2,
548 					"radar event on non-DFS chan");
549 			if (!(dfs->dfs_is_offload_enabled)) {
550 				dfs_reset_radarq(dfs);
551 				dfs_reset_alldelaylines(dfs);
552 				dfs_reset_bangradar(dfs);
553 			}
554 			return 0;
555 		}
556 
557 	return 1;
558 }
559 
560 /**
561  * dfs_send_csa_to_current_chan() - Send CSA to current channel
562  * @dfs: Pointer to wlan_dfs structure.
563  *
564  * For the test mode(usenol = 0), don't do a CSA; but setup the test timer so
565  * we get a CSA _back_ to the current operating channel.
566  */
567 static inline void dfs_send_csa_to_current_chan(struct wlan_dfs *dfs)
568 {
569 	qdf_timer_stop(&dfs->wlan_dfstesttimer);
570 	dfs->wlan_dfstest = 1;
571 	dfs->wlan_dfstest_ieeechan = dfs->dfs_curchan->dfs_ch_ieee;
572 	dfs->wlan_dfstesttime = 1;   /* 1ms */
573 	qdf_timer_mod(&dfs->wlan_dfstesttimer, dfs->wlan_dfstesttime);
574 }
575 
576 int dfs_second_segment_radar_disable(struct wlan_dfs *dfs)
577 {
578 	dfs->dfs_proc_phyerr &= ~DFS_SECOND_SEGMENT_RADAR_EN;
579 
580 	return 0;
581 }
582 
583 /* dfs_prepare_nol_ie_bitmap: Create a Bitmap from the radar found subchannels
584  * to be sent along with RCSA.
585  *
586  * Get the subchannels affected by radar and all the channels in current
587  * channel.
588  * start from the first bit pointing to first subchannel in the current
589  * channel, set as 1 if radar affected, 0 if unaffected.
590  * If the number of subchannels increases (future cases), the bitmap should
591  * be an array of required size.
592  *
593  * Please change macro "MIN_DFS_SUBCHAN_BW" when NOL logic changes.
594  */
595 static void dfs_prepare_nol_ie_bitmap(struct wlan_dfs *dfs,
596 				      struct radar_found_info *radar_found,
597 				      uint8_t *in_sub_channels,
598 				      uint8_t n_in_sub_channels)
599 {
600 	uint8_t cur_subchans[NUM_CHANNELS_160MHZ];
601 	uint8_t n_cur_subchans;
602 	uint8_t i;
603 	uint8_t j;
604 	uint8_t bits = 0x01;
605 
606 	n_cur_subchans = dfs_get_bonding_channels(dfs, dfs->dfs_curchan,
607 						  radar_found->segment_id,
608 						  cur_subchans);
609 	dfs->dfs_nol_ie_bandwidth = MIN_DFS_SUBCHAN_BW;
610 	dfs->dfs_nol_ie_startfreq =
611 		(uint16_t)utils_dfs_chan_to_freq(cur_subchans[0]);
612 
613 	/* Search through the array list of radar affected subchannels
614 	 * to find if the subchannel in our current channel has radar hit.
615 	 * Break if found to reduce loop count.
616 	 */
617 	for (i = 0; i < n_cur_subchans; i++) {
618 		for (j = 0; j < n_in_sub_channels; j++) {
619 			if (cur_subchans[i] == in_sub_channels[j]) {
620 				dfs->dfs_nol_ie_bitmap |= bits;
621 				break;
622 			}
623 		}
624 		bits <<= 1;
625 	}
626 }
627 
628 void dfs_fetch_nol_ie_info(struct wlan_dfs *dfs,
629 			   uint8_t *nol_ie_bandwidth,
630 			   uint16_t *nol_ie_startfreq,
631 			   uint8_t *nol_ie_bitmap)
632 {
633 	if (nol_ie_bandwidth)
634 		*nol_ie_bandwidth = dfs->dfs_nol_ie_bandwidth;
635 	if (nol_ie_startfreq)
636 		*nol_ie_startfreq = dfs->dfs_nol_ie_startfreq;
637 	if (nol_ie_bitmap)
638 		*nol_ie_bitmap = dfs->dfs_nol_ie_bitmap;
639 }
640 
641 void dfs_get_rcsa_flags(struct wlan_dfs *dfs, bool *is_rcsa_ie_sent,
642 			bool *is_nol_ie_sent)
643 {
644 	if (is_rcsa_ie_sent)
645 		*is_rcsa_ie_sent = dfs->dfs_is_rcsa_ie_sent;
646 	if (is_nol_ie_sent)
647 		*is_nol_ie_sent = dfs->dfs_is_nol_ie_sent;
648 }
649 
650 void dfs_set_rcsa_flags(struct wlan_dfs *dfs, bool is_rcsa_ie_sent,
651 			bool is_nol_ie_sent)
652 {
653 	dfs->dfs_is_rcsa_ie_sent = is_rcsa_ie_sent;
654 	dfs->dfs_is_nol_ie_sent = is_nol_ie_sent;
655 }
656 
657 bool dfs_process_nol_ie_bitmap(struct wlan_dfs *dfs, uint8_t nol_ie_bandwidth,
658 			       uint16_t nol_ie_startfreq, uint8_t nol_ie_bitmap)
659 {
660 	uint8_t num_subchans;
661 	uint8_t bits = 0x01;
662 	uint8_t radar_subchans[NUM_CHANNELS_160MHZ];
663 	bool should_nol_ie_be_sent = true;
664 
665 	qdf_mem_zero(radar_subchans, sizeof(radar_subchans));
666 	if (!dfs->dfs_use_nol_subchannel_marking) {
667 		/* Since subchannel marking is disabled, disregard
668 		 * NOL IE and set NOL IE flag as false, so it
669 		 * can't be sent to uplink.
670 		 */
671 		num_subchans =
672 			dfs_get_bonding_channels(dfs,
673 						 dfs->dfs_curchan,
674 						 dfs->dfs_curchan->dfs_ch_freq,
675 						 radar_subchans);
676 		should_nol_ie_be_sent = false;
677 	} else {
678 		/* Add the NOL IE information in DFS structure so that RCSA
679 		 * and NOL IE can be sent to uplink if uplink exists.
680 		 */
681 		uint32_t frequency = (uint32_t)nol_ie_startfreq;
682 
683 		dfs->dfs_nol_ie_bandwidth = nol_ie_bandwidth;
684 		dfs->dfs_nol_ie_startfreq = nol_ie_startfreq;
685 		dfs->dfs_nol_ie_bitmap = nol_ie_bitmap;
686 		for (num_subchans = 0; num_subchans < NUM_CHANNELS_160MHZ;
687 			num_subchans++) {
688 			if (nol_ie_bitmap & bits) {
689 				radar_subchans[num_subchans] =
690 					utils_dfs_freq_to_chan(frequency);
691 			}
692 			bits <<= 1;
693 			frequency += nol_ie_bandwidth;
694 		}
695 	}
696 
697 	dfs_radar_add_channel_list_to_nol(dfs, radar_subchans, num_subchans);
698 	return should_nol_ie_be_sent;
699 }
700 
701 QDF_STATUS dfs_process_radar_ind(struct wlan_dfs *dfs,
702 				 struct radar_found_info *radar_found)
703 {
704 	bool wait_for_csa = false;
705 	uint8_t channels[NUM_CHANNELS_160MHZ];
706 	uint8_t num_channels;
707 	QDF_STATUS status;
708 	uint32_t freq_center;
709 	uint32_t radarfound_freq;
710 
711 	if (!dfs->dfs_curchan) {
712 		dfs_err(dfs, WLAN_DEBUG_DFS_ALWAYS, "dfs->dfs_curchan is NULL");
713 		return QDF_STATUS_E_FAILURE;
714 	}
715 
716 	/* Check if the current channel is a non DFS channel */
717 	if (!dfs_radarevent_basic_sanity(dfs, dfs->dfs_curchan)) {
718 		dfs_err(dfs, WLAN_DEBUG_DFS,
719 			"radar event on a non-DFS channel");
720 		return QDF_STATUS_E_FAILURE;
721 	}
722 
723 	/* For Full Offload, FW sends segment id,freq_offset and chirp
724 	 * information and gets assigned when there is radar detect. In
725 	 * case of radartool bangradar enhanced command and real radar
726 	 * for DA and PO, we assign these information here.
727 	 */
728 	if (!(dfs->dfs_is_offload_enabled && dfs->dfs_radar_found_for_fo)) {
729 		radar_found->segment_id = dfs->dfs_seg_id;
730 		radar_found->freq_offset = dfs->dfs_freq_offset;
731 		radar_found->is_chirp = dfs->dfs_is_chirp;
732 	}
733 
734 	dfs_compute_radar_found_cfreq(dfs, radar_found, &freq_center);
735 	radarfound_freq = freq_center + dfs->dfs_freq_offset;
736 
737 	if (radar_found->segment_id == SEG_ID_SECONDARY)
738 		dfs_info(dfs, WLAN_DEBUG_DFS_ALWAYS,
739 			 "Radar found on second segment.Radarfound Freq=%d MHz.Secondary Chan cfreq=%d MHz.",
740 			 radarfound_freq, freq_center);
741 	else
742 		dfs_info(NULL, WLAN_DEBUG_DFS_ALWAYS,
743 			 "Radar found on channel=%d, freq=%d MHz. Primary beaconning chan:%d, freq=%d MHz.",
744 			 utils_dfs_freq_to_chan(radarfound_freq),
745 			 radarfound_freq, dfs->dfs_curchan->dfs_ch_ieee,
746 			 dfs->dfs_curchan->dfs_ch_freq);
747 
748 	if (!dfs->dfs_use_nol) {
749 		dfs_reset_bangradar(dfs);
750 		dfs_send_csa_to_current_chan(dfs);
751 		return QDF_STATUS_SUCCESS;
752 	}
753 
754 	if (dfs->dfs_bangradar_type == DFS_BANGRADAR_FOR_ALL_SUBCHANS)
755 		num_channels = dfs_get_bonding_channels_without_seg_info(
756 				 dfs->dfs_curchan, channels);
757 	/* BW reduction is dependent on subchannel marking */
758 	else if ((dfs->dfs_use_nol_subchannel_marking) &&
759 		 (!(dfs->dfs_bangradar_type) ||
760 		 (dfs->dfs_bangradar_type ==
761 		 DFS_BANGRADAR_FOR_SPECIFIC_SUBCHANS)))
762 		num_channels = dfs_find_radar_affected_subchans(dfs,
763 								radar_found,
764 								channels,
765 								freq_center);
766 	else
767 		num_channels = dfs_get_bonding_channels(dfs,
768 							dfs->dfs_curchan,
769 							radar_found->segment_id,
770 							channels);
771 
772 	dfs_reset_bangradar(dfs);
773 	status = dfs_radar_add_channel_list_to_nol(dfs, channels, num_channels);
774 	if (QDF_IS_STATUS_ERROR(status)) {
775 		dfs_err(dfs, WLAN_DEBUG_DFS,
776 			"radar event received on invalid channel");
777 		return status;
778 	}
779 	dfs->dfs_is_nol_ie_sent = false;
780 	(dfs->is_radar_during_precac) ?
781 		(dfs->dfs_is_rcsa_ie_sent = false) :
782 		(dfs->dfs_is_rcsa_ie_sent = true);
783 	if (dfs->dfs_use_nol_subchannel_marking) {
784 		dfs_prepare_nol_ie_bitmap(dfs, radar_found, channels,
785 					  num_channels);
786 		dfs->dfs_is_nol_ie_sent = true;
787 	}
788 
789 	/*
790 	 * If precac is running and the radar found in secondary
791 	 * VHT80 mark the channel as radar and add to NOL list.
792 	 * Otherwise random channel selection can choose this
793 	 * channel.
794 	 */
795 	dfs_debug(dfs, WLAN_DEBUG_DFS,
796 		  "found_on_second=%d is_pre=%d",
797 		  dfs->is_radar_found_on_secondary_seg,
798 		  dfs_is_precac_timer_running(dfs));
799 	/*
800 	 * Even if radar found on primary, we need to move the channel
801 	 * from precac-required-list and precac-done-list to
802 	 * precac-nol-list.
803 	 */
804 
805 	if (dfs->dfs_precac_enable)
806 		dfs_mark_precac_dfs(dfs, dfs->is_radar_found_on_secondary_seg);
807 
808 	if (utils_get_dfsdomain(dfs->dfs_pdev_obj) == DFS_ETSI_DOMAIN) {
809 		/* Remove chan from ETSI Pre-CAC Cleared List*/
810 		dfs_info(dfs, WLAN_DEBUG_DFS_NOL,
811 			 "%s : %d remove channel from ETSI PreCAC List\n",
812 			 __func__, __LINE__);
813 		dfs_mark_etsi_precac_dfs(dfs, channels, num_channels);
814 	}
815 	/*
816 	 * This calls into the umac DFS code, which sets the umac
817 	 * related radar flags and begins the channel change
818 	 * machinery.
819 
820 	 * Even during precac, this API is called, but with a flag
821 	 * saying not to send RCSA, but only the radar affected subchannel
822 	 * information.
823 	 */
824 
825 	dfs_mlme_start_rcsa(dfs->dfs_pdev_obj, &wait_for_csa);
826 
827 	if (!dfs->dfs_is_offload_enabled &&
828 	    dfs->is_radar_found_on_secondary_seg) {
829 		dfs_second_segment_radar_disable(dfs);
830 		dfs->is_radar_found_on_secondary_seg = 0;
831 
832 		if (dfs->is_radar_during_precac) {
833 			dfs->is_radar_during_precac = 0;
834 			return QDF_STATUS_SUCCESS;
835 		}
836 	}
837 
838 	/*
839 	 * XXX TODO: the umac NOL code isn't used, but
840 	 * WLAN_CHAN_DFS_RADAR still gets set. Since the umac
841 	 * NOL code isn't used, that flag is never cleared. This
842 	 * needs to be fixed. See EV 105776.
843 	 */
844 	if (wait_for_csa)
845 		return QDF_STATUS_SUCCESS;
846 
847 	/*
848 	 * EV 129487 : We have detected radar in the channel,
849 	 * stop processing PHY error data as this can cause
850 	 * false detect in the new channel while channel
851 	 * change is in progress.
852 	 */
853 
854 	if (!dfs->dfs_is_offload_enabled) {
855 		dfs_radar_disable(dfs);
856 		dfs_second_segment_radar_disable(dfs);
857 	}
858 
859 	dfs_mlme_mark_dfs(dfs->dfs_pdev_obj,
860 			dfs->dfs_curchan->dfs_ch_ieee,
861 			dfs->dfs_curchan->dfs_ch_freq,
862 			dfs->dfs_curchan->dfs_ch_vhtop_ch_freq_seg2,
863 			dfs->dfs_curchan->dfs_ch_flags);
864 
865 	return QDF_STATUS_SUCCESS;
866 }
867