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