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