xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral_phyerr.c (revision f291b79d0d2c54b6611a13b8ca758b89bb82b934)
1 /*
2  * Copyright (c) 2011,2017-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <osdep.h>
21 #include <qdf_types.h>
22 #include <qdf_module.h>
23 #include <wlan_tgt_def_config.h>
24 #include <hif.h>
25 #include <hif_hw_version.h>
26 #include <wmi_unified_api.h>
27 #include <target_if_spectral.h>
28 #include <wlan_lmac_if_def.h>
29 #include <wlan_osif_priv.h>
30 #include <reg_services_public_struct.h>
31 #include <target_if.h>
32 #ifdef DIRECT_BUF_RX_ENABLE
33 #include <target_if_direct_buf_rx_api.h>
34 #endif
35 extern int spectral_debug_level;
36 
37 #ifdef WLAN_CONV_SPECTRAL_ENABLE
38 
39 #define SPECTRAL_HEXDUMP_OCTET_PRINT_SIZE           (3)
40 #define SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE        (16)
41 #define SPECTRAL_HEXDUMP_EXTRA_BUFFER_PER_LINE      (16)
42 
43 /*
44  * Provision for the expected hexdump line size as follows:
45  *
46  * Size per octet multiplied by number of octets per line
47  * +
48  * ASCII representation which is equivalent in print size to number of octets
49  * per line
50  * +
51  * Some extra buffer
52  */
53 #define SPECTRAL_HEXDUMP_LINESIZE                           \
54 		((SPECTRAL_HEXDUMP_OCTET_PRINT_SIZE *       \
55 		  SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) +   \
56 		 SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE +     \
57 		 SPECTRAL_HEXDUMP_EXTRA_BUFFER_PER_LINE)
58 
59 /**
60  * target_if_spectral_hexdump() - Print hexdump of the given buffer
61  * @_buf: Pointer to buffer
62  * @_len: Length of the buffer
63  *
64  * Print the hexdump of buffer upto given length. Print upto
65  * SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE per line, followed by the ASCII
66  * representation of these octets.
67  */
68 static inline void target_if_spectral_hexdump(unsigned char *_buf, int _len)
69 {
70 	int i, mod;
71 	unsigned char ascii[SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE + 1];
72 	unsigned char *pc = (_buf);
73 	char hexdump_line[SPECTRAL_HEXDUMP_LINESIZE + 1];
74 	int loc = 0;
75 
76 	qdf_mem_zero(hexdump_line, sizeof(hexdump_line));
77 
78 	if (_len <= 0) {
79 		spectral_err("buffer len is %d, too short", _len);
80 		return;
81 	}
82 
83 	for (i = 0; i < _len; i++) {
84 		mod = i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE;
85 
86 		if (!mod) {
87 			if (i) {
88 				if (loc >= sizeof(hexdump_line)) {
89 					spectral_err("loc index is %u, greater than hexdump_line array size",
90 						     loc);
91 					return;
92 				}
93 				loc += snprintf(&hexdump_line[loc],
94 						sizeof(hexdump_line) - loc,
95 						"  %s", ascii);
96 				spectral_debug("%s", hexdump_line);
97 				qdf_mem_zero(hexdump_line,
98 					     sizeof(hexdump_line));
99 				loc = 0;
100 			}
101 		}
102 
103 		if (loc >= sizeof(hexdump_line)) {
104 			spectral_err("loc index is %u, greater than hexdump_line array size",
105 				     loc);
106 			return;
107 		}
108 		loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
109 				" %02x", pc[i]);
110 
111 		if ((pc[i] < 0x20) || (pc[i] > 0x7e))
112 			ascii[mod] = '.';
113 		else
114 			ascii[mod] = pc[i];
115 		ascii[(mod) + 1] = '\0';
116 	}
117 
118 	while ((i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) != 0) {
119 		if (loc >= sizeof(hexdump_line)) {
120 			spectral_err("loc index is %u, greater than hexdump_line array size",
121 				     loc);
122 			return;
123 		}
124 		loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
125 				"   ");
126 		i++;
127 	}
128 
129 	if (loc >= sizeof(hexdump_line)) {
130 		spectral_err("loc index is %u, greater than hexdump_line array size",
131 			     loc);
132 		return;
133 	}
134 	snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, "  %s", ascii);
135 	spectral_debug("%s", hexdump_line);
136 }
137 
138 /**
139  * target_if_print_buf() - Prints given buffer for given length
140  * @pbuf: Pointer to buffer
141  * @len: length
142  *
143  * Prints given buffer for given length
144  *
145  * Return: void
146  */
147 static void
148 target_if_print_buf(uint8_t *pbuf, int len)
149 {
150 	int i = 0;
151 
152 	for (i = 0; i < len; i++) {
153 		spectral_debug("%02X ", pbuf[i]);
154 		if (i % 32 == 31)
155 			spectral_debug("\n");
156 	}
157 }
158 
159 int
160 target_if_spectral_dump_fft(uint8_t *pfft, int fftlen)
161 {
162 	int i = 0;
163 
164 	/*
165 	 * TODO : Do not delete the following print
166 	 *        The scripts used to validate Spectral depend on this Print
167 	 */
168 	spectral_debug("SPECTRAL : FFT Length is 0x%x (%d)", fftlen, fftlen);
169 
170 	spectral_debug("fft_data # ");
171 	for (i = 0; i < fftlen; i++)
172 		spectral_debug("%d ", pfft[i]);
173 	spectral_debug("\n");
174 	return 0;
175 }
176 
177 QDF_STATUS target_if_spectral_fw_hang(struct target_if_spectral *spectral)
178 {
179 	struct crash_inject param;
180 	struct wlan_objmgr_pdev *pdev;
181 	struct wlan_objmgr_psoc *psoc;
182 	struct target_if_psoc_spectral *psoc_spectral;
183 
184 	if (!spectral) {
185 		spectral_err("Spectral LMAC object is null");
186 		return QDF_STATUS_E_INVAL;
187 	}
188 
189 	pdev = spectral->pdev_obj;
190 	if (!pdev) {
191 		spectral_err("pdev is null");
192 		return QDF_STATUS_E_FAILURE;
193 	}
194 
195 	psoc = wlan_pdev_get_psoc(pdev);
196 	if (!psoc) {
197 		spectral_err("psoc is null");
198 		return QDF_STATUS_E_FAILURE;
199 	}
200 
201 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
202 	if (!psoc_spectral) {
203 		spectral_err("spectral psoc object is null");
204 		return QDF_STATUS_E_FAILURE;
205 	}
206 
207 	qdf_mem_set(&param, sizeof(param), 0);
208 	param.type = 1; //RECOVERY_SIM_ASSERT
209 
210 	return psoc_spectral->wmi_ops.wmi_spectral_crash_inject(
211 		GET_WMI_HDL_FROM_PDEV(spectral->pdev_obj), &param);
212 }
213 
214 #ifdef OPTIMIZED_SAMP_MESSAGE
215 void
216 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg)
217 {
218 	int span, det;
219 	struct samp_detector_info *det_info;
220 	struct samp_freq_span_info *span_info;
221 
222 	spectral_dbg_line();
223 	spectral_debug("Spectral Message");
224 	spectral_dbg_line();
225 	spectral_debug("Signature        :   0x%x", ss_msg->signature);
226 	spectral_debug("Freq             :   %u", ss_msg->pri20_freq);
227 	spectral_debug("sscan width      :   %d", ss_msg->sscan_bw);
228 	spectral_debug("sscan cfreq1     :   %u", ss_msg->sscan_cfreq1);
229 	spectral_debug("sscan cfreq2     :   %u", ss_msg->sscan_cfreq2);
230 	spectral_debug("bin power count  :   %d", ss_msg->bin_pwr_count);
231 	spectral_debug("Number of spans  :   %d", ss_msg->num_freq_spans);
232 	spectral_dbg_line();
233 	for (span = 0; span < ss_msg->num_freq_spans; span++) {
234 		span_info = &ss_msg->freq_span_info[span];
235 		spectral_debug("-------- Span ID : %d --------", span);
236 		spectral_debug("Number of detectors  :  %d",
237 			       span_info->num_detectors);
238 		spectral_dbg_line();
239 		for (det = 0; det < span_info->num_detectors; det++) {
240 			det_info = &span_info->detector_info[det];
241 			spectral_debug("------ Detector ID : %d ------", det);
242 			spectral_dbg_line();
243 			spectral_debug("RSSI            : %d", det_info->rssi);
244 			spectral_debug("Timestamp       : %u",
245 				       det_info->timestamp);
246 			spectral_debug("Start bin index : %d",
247 				       det_info->start_bin_idx);
248 			spectral_debug("End bin index   : %d",
249 				       det_info->end_bin_idx);
250 			spectral_debug("Start frequency : %d",
251 				       det_info->start_frequency);
252 			spectral_debug("End frequency   : %d",
253 				       det_info->end_frequency);
254 			spectral_dbg_line();
255 		}
256 	}
257 }
258 #else
259 void
260 target_if_dbg_print_samp_param(struct target_if_samp_msg_params *p)
261 {
262 	spectral_debug("\nSAMP Packet : -------------------- START --------------------");
263 	spectral_debug("Freq        = %d", p->freq);
264 	spectral_debug("RSSI        = %d", p->rssi);
265 	spectral_debug("Bin Count   = %d", p->pwr_count);
266 	spectral_debug("Timestamp   = %d", p->tstamp);
267 	spectral_debug("SAMP Packet : -------------------- END -----------------------");
268 }
269 
270 void
271 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg)
272 {
273 	int i = 0;
274 
275 	struct spectral_samp_data *p = &ss_msg->samp_data;
276 	struct spectral_classifier_params *pc = &p->classifier_params;
277 	struct interf_src_rsp *pi = &p->interf_list;
278 
279 	spectral_dbg_line();
280 	spectral_debug("Spectral Message");
281 	spectral_dbg_line();
282 	spectral_debug("Signature   :   0x%x", ss_msg->signature);
283 	spectral_debug("Freq        :   %d", ss_msg->freq);
284 	spectral_debug("Freq load   :   %d", ss_msg->freq_loading);
285 	spectral_debug("Intfnc type :   %d", ss_msg->int_type);
286 	spectral_dbg_line();
287 	spectral_debug("Spectral Data info");
288 	spectral_dbg_line();
289 	spectral_debug("data length     :   %d", p->spectral_data_len);
290 	spectral_debug("rssi            :   %d", p->spectral_rssi);
291 	spectral_debug("combined rssi   :   %d", p->spectral_combined_rssi);
292 	spectral_debug("upper rssi      :   %d", p->spectral_upper_rssi);
293 	spectral_debug("lower rssi      :   %d", p->spectral_lower_rssi);
294 	spectral_debug("bw info         :   %d", p->spectral_bwinfo);
295 	spectral_debug("timestamp       :   %d", p->spectral_tstamp);
296 	spectral_debug("max index       :   %d", p->spectral_max_index);
297 	spectral_debug("max exp         :   %d", p->spectral_max_exp);
298 	spectral_debug("max mag         :   %d", p->spectral_max_mag);
299 	spectral_debug("last timstamp   :   %d", p->spectral_last_tstamp);
300 	spectral_debug("upper max idx   :   %d", p->spectral_upper_max_index);
301 	spectral_debug("lower max idx   :   %d", p->spectral_lower_max_index);
302 	spectral_debug("bin power count :   %d", p->bin_pwr_count);
303 	spectral_dbg_line();
304 	spectral_debug("Classifier info");
305 	spectral_dbg_line();
306 	spectral_debug("20/40 Mode      :   %d", pc->spectral_20_40_mode);
307 	spectral_debug("dc index        :   %d", pc->spectral_dc_index);
308 	spectral_debug("dc in MHz       :   %d", pc->spectral_dc_in_mhz);
309 	spectral_debug("upper channel   :   %d", pc->upper_chan_in_mhz);
310 	spectral_debug("lower channel   :   %d", pc->lower_chan_in_mhz);
311 	spectral_dbg_line();
312 	spectral_debug("Interference info");
313 	spectral_dbg_line();
314 	spectral_debug("inter count     :   %d", pi->count);
315 
316 	for (i = 0; i < pi->count; i++) {
317 		spectral_debug("inter type  :   %d",
318 			       pi->interf[i].interf_type);
319 		spectral_debug("min freq    :   %d",
320 			       pi->interf[i].interf_min_freq);
321 		spectral_debug("max freq    :   %d",
322 			       pi->interf[i].interf_max_freq);
323 	}
324 }
325 #endif /* OPTIMIZED_SAMP_MESSAGE */
326 
327 uint32_t
328 target_if_get_offset_swar_sec80(uint32_t channel_width)
329 {
330 	uint32_t offset = 0;
331 
332 	switch (channel_width) {
333 	case CH_WIDTH_20MHZ:
334 		offset = OFFSET_CH_WIDTH_20;
335 		break;
336 	case CH_WIDTH_40MHZ:
337 		offset = OFFSET_CH_WIDTH_40;
338 		break;
339 	case CH_WIDTH_80MHZ:
340 		offset = OFFSET_CH_WIDTH_80;
341 		break;
342 	case CH_WIDTH_160MHZ:
343 	case CH_WIDTH_80P80MHZ:
344 		offset = OFFSET_CH_WIDTH_160;
345 		break;
346 	default:
347 		offset = OFFSET_CH_WIDTH_80;
348 		break;
349 	}
350 	return offset;
351 }
352 
353 /**
354  * target_if_dump_summary_report_gen2() - Dump Spectral Summary Report for gen2
355  * @ptlv: Pointer to Spectral Phyerr TLV
356  * @tlvlen: length
357  * @is_160_format: Indicates whether information provided by HW is in altered
358  *                 format for 802.11ac 160/80+80 MHz support (QCA9984 onwards)
359  *
360  * Dump Spectral Summary Report for gen2
361  *
362  * Return: Success/Failure
363  */
364 static int
365 target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
366 				   int tlvlen, bool is_160_format)
367 {
368 	/*
369 	 * For simplicity, everything is defined as uint32_t (except one).
370 	 * Proper code will later use the right sizes.
371 	 */
372 
373 	/*
374 	 * For easy comparison between MDK team and OS team, the MDK script
375 	 * variable names have been used
376 	 */
377 
378 	uint32_t agc_mb_gain;
379 	uint32_t sscan_gidx;
380 	uint32_t agc_total_gain;
381 	uint32_t recent_rfsat;
382 	uint32_t ob_flag;
383 	uint32_t nb_mask;
384 	uint32_t peak_mag;
385 	int16_t peak_inx;
386 
387 	uint32_t ss_summary_A = 0;
388 	uint32_t ss_summary_B = 0;
389 	uint32_t ss_summary_C = 0;
390 	uint32_t ss_summary_D = 0;
391 	uint32_t ss_summary_E = 0;
392 	struct spectral_phyerr_hdr_gen2 *phdr =
393 	    (struct spectral_phyerr_hdr_gen2 *)(
394 		(uint8_t *)ptlv +
395 		sizeof(struct spectral_phyerr_tlv_gen2));
396 
397 	spectral_debug("SPECTRAL : SPECTRAL SUMMARY REPORT");
398 
399 	if (is_160_format) {
400 		if (tlvlen != 20) {
401 			spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
402 				     tlvlen);
403 			target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
404 			return -EPERM;
405 		}
406 
407 		/* Doing copy as the contents may not be aligned */
408 		qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
409 		qdf_mem_copy(&ss_summary_B,
410 			     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
411 			     sizeof(int));
412 		qdf_mem_copy(&ss_summary_C,
413 			     (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
414 			     sizeof(int));
415 		qdf_mem_copy(&ss_summary_D,
416 			     (uint8_t *)((uint8_t *)phdr + 3 * sizeof(int)),
417 			     sizeof(int));
418 		qdf_mem_copy(&ss_summary_E,
419 			     (uint8_t *)((uint8_t *)phdr + 4 * sizeof(int)),
420 			     sizeof(int));
421 
422 		/*
423 		 * The following is adapted from MDK scripts for
424 		 * easier comparability
425 		 */
426 
427 		recent_rfsat = ((ss_summary_A >> 8) & 0x1);
428 		sscan_gidx = (ss_summary_A & 0xff);
429 		spectral_debug("sscan_gidx=%d, is_recent_rfsat=%d",
430 			       sscan_gidx, recent_rfsat);
431 
432 		/* First segment */
433 		agc_mb_gain = ((ss_summary_B >> 10) & 0x7f);
434 		agc_total_gain = (ss_summary_B & 0x3ff);
435 		nb_mask = ((ss_summary_C >> 22) & 0xff);
436 		ob_flag = ((ss_summary_B >> 17) & 0x1);
437 		peak_inx = (ss_summary_C & 0xfff);
438 		if (peak_inx > 2047)
439 			peak_inx = peak_inx - 4096;
440 		peak_mag = ((ss_summary_C >> 12) & 0x3ff);
441 
442 		spectral_debug("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d",
443 			       agc_total_gain, agc_mb_gain);
444 		spectral_debug("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, peak_index_segid0=%d, peak_mag_segid0=%d",
445 			       nb_mask, ob_flag, peak_inx, peak_mag);
446 
447 		/* Second segment */
448 		agc_mb_gain = ((ss_summary_D >> 10) & 0x7f);
449 		agc_total_gain = (ss_summary_D & 0x3ff);
450 		nb_mask = ((ss_summary_E >> 22) & 0xff);
451 		ob_flag = ((ss_summary_D >> 17) & 0x1);
452 		peak_inx = (ss_summary_E & 0xfff);
453 		if (peak_inx > 2047)
454 			peak_inx = peak_inx - 4096;
455 		peak_mag = ((ss_summary_E >> 12) & 0x3ff);
456 
457 		spectral_debug("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d",
458 			       agc_total_gain, agc_mb_gain);
459 		spectral_debug("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, peak_index_segid1=%d, peak_mag_segid1=%d",
460 			       nb_mask, ob_flag, peak_inx, peak_mag);
461 	} else {
462 		if (tlvlen != 8) {
463 			spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
464 				     tlvlen);
465 			target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
466 			return -EPERM;
467 		}
468 
469 		/* Doing copy as the contents may not be aligned */
470 		qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
471 		qdf_mem_copy(&ss_summary_B,
472 			     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
473 			     sizeof(int));
474 
475 		nb_mask = ((ss_summary_B >> 22) & 0xff);
476 		ob_flag = ((ss_summary_B >> 30) & 0x1);
477 		peak_inx = (ss_summary_B & 0xfff);
478 
479 		if (peak_inx > 2047)
480 			peak_inx = peak_inx - 4096;
481 
482 		peak_mag = ((ss_summary_B >> 12) & 0x3ff);
483 		agc_mb_gain = ((ss_summary_A >> 24) & 0x7f);
484 		agc_total_gain = (ss_summary_A & 0x3ff);
485 		sscan_gidx = ((ss_summary_A >> 16) & 0xff);
486 		recent_rfsat = ((ss_summary_B >> 31) & 0x1);
487 
488 		spectral_debug("nb_mask = 0x%.2x, ob_flag=%d, peak_index=%d, peak_mag=%d, agc_mb_gain=%d, agc_total_gain=%d, sscan_gidx=%d, recent_rfsat=%d",
489 			       nb_mask, ob_flag, peak_inx, peak_mag,
490 			       agc_mb_gain, agc_total_gain, sscan_gidx,
491 			       recent_rfsat);
492 	}
493 
494 	return 0;
495 }
496 
497 /**
498  * target_if_process_sfft_report_gen2() - Process Search FFT Report
499  * @ptlv: Pointer to Spectral Phyerr TLV
500  * @tlvlen: length
501  * @p_fft_info: Pointer to search fft info
502  *
503  * Dump Spectral Summary Report for gen2
504  *
505  * Return: Success/Failure
506  */
507 static int
508 target_if_process_sfft_report_gen2(
509 	struct spectral_phyerr_tlv_gen2 *ptlv,
510 	int tlvlen,
511 	struct spectral_search_fft_info_gen2 *p_fft_info)
512 {
513 	/*
514 	 * For simplicity, everything is defined as uint32_t (except one).
515 	 * Proper code will later use the right sizes.
516 	 */
517 	/*
518 	 * For easy comparison between MDK team and OS team, the MDK script
519 	 * variable names have been used
520 	 */
521 	uint32_t relpwr_db;
522 	uint32_t num_str_bins_ib;
523 	uint32_t base_pwr;
524 	uint32_t total_gain_info;
525 
526 	uint32_t fft_chn_idx;
527 	int16_t peak_inx;
528 	uint32_t avgpwr_db;
529 	uint32_t peak_mag;
530 
531 	uint32_t fft_summary_A = 0;
532 	uint32_t fft_summary_B = 0;
533 	uint8_t *tmp = (uint8_t *)ptlv;
534 	struct spectral_phyerr_hdr_gen2 *phdr =
535 	    (struct spectral_phyerr_hdr_gen2 *)(
536 		tmp +
537 		sizeof(struct spectral_phyerr_tlv_gen2));
538 
539 	/* Relook this */
540 	if (tlvlen < 8) {
541 		spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
542 			     tlvlen);
543 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
544 		return -EPERM;
545 	}
546 
547 	/* Doing copy as the contents may not be aligned */
548 	qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
549 	qdf_mem_copy(&fft_summary_B,
550 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
551 		     sizeof(int));
552 
553 	relpwr_db = ((fft_summary_B >> 26) & 0x3f);
554 	num_str_bins_ib = fft_summary_B & 0xff;
555 	base_pwr = ((fft_summary_A >> 14) & 0x1ff);
556 	total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
557 
558 	fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
559 	peak_inx = fft_summary_A & 0xfff;
560 
561 	if (peak_inx > 2047)
562 		peak_inx = peak_inx - 4096;
563 
564 	avgpwr_db = ((fft_summary_B >> 18) & 0xff);
565 	peak_mag = ((fft_summary_B >> 8) & 0x3ff);
566 
567 	/* Populate the Search FFT Info */
568 	if (p_fft_info) {
569 		p_fft_info->relpwr_db = relpwr_db;
570 		p_fft_info->num_str_bins_ib = num_str_bins_ib;
571 		p_fft_info->base_pwr = base_pwr;
572 		p_fft_info->total_gain_info = total_gain_info;
573 		p_fft_info->fft_chn_idx = fft_chn_idx;
574 		p_fft_info->peak_inx = peak_inx;
575 		p_fft_info->avgpwr_db = avgpwr_db;
576 		p_fft_info->peak_mag = peak_mag;
577 	}
578 
579 	return 0;
580 }
581 
582 /**
583  * target_if_dump_adc_report_gen2() - Dump ADC Reports for gen2
584  * @ptlv: Pointer to Spectral Phyerr TLV
585  * @tlvlen: length
586  *
587  * Dump ADC Reports for gen2
588  *
589  * Return: Success/Failure
590  */
591 static int
592 target_if_dump_adc_report_gen2(
593 	struct spectral_phyerr_tlv_gen2 *ptlv, int tlvlen)
594 {
595 	int i;
596 	uint32_t *pdata;
597 	uint32_t data;
598 
599 	/*
600 	 * For simplicity, everything is defined as uint32_t (except one).
601 	 * Proper code will later use the right sizes.
602 	 */
603 	uint32_t samp_fmt;
604 	uint32_t chn_idx;
605 	uint32_t recent_rfsat;
606 	uint32_t agc_mb_gain;
607 	uint32_t agc_total_gain;
608 
609 	uint32_t adc_summary = 0;
610 
611 	uint8_t *ptmp = (uint8_t *)ptlv;
612 
613 	spectral_debug("SPECTRAL : ADC REPORT");
614 
615 	/* Relook this */
616 	if (tlvlen < 4) {
617 		spectral_err("Unexpected TLV length %d for ADC Report! Hexdump follows",
618 			     tlvlen);
619 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
620 		return -EPERM;
621 	}
622 
623 	qdf_mem_copy(&adc_summary, (uint8_t *)(ptlv + 4), sizeof(int));
624 
625 	samp_fmt = ((adc_summary >> 28) & 0x1);
626 	chn_idx = ((adc_summary >> 24) & 0x3);
627 	recent_rfsat = ((adc_summary >> 23) & 0x1);
628 	agc_mb_gain = ((adc_summary >> 16) & 0x7f);
629 	agc_total_gain = adc_summary & 0x3ff;
630 
631 	spectral_debug("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u agc_total_gain=%u",
632 		       samp_fmt, chn_idx, recent_rfsat, agc_mb_gain,
633 		       agc_total_gain);
634 
635 	for (i = 0; i < (tlvlen / 4); i++) {
636 		pdata = (uint32_t *)(ptmp + 4 + i * 4);
637 		data = *pdata;
638 
639 		/* Interpreting capture format 1 */
640 		if (1) {
641 			uint8_t i1;
642 			uint8_t q1;
643 			uint8_t i2;
644 			uint8_t q2;
645 			int8_t si1;
646 			int8_t sq1;
647 			int8_t si2;
648 			int8_t sq2;
649 
650 			i1 = data & 0xff;
651 			q1 = (data >> 8) & 0xff;
652 			i2 = (data >> 16) & 0xff;
653 			q2 = (data >> 24) & 0xff;
654 
655 			if (i1 > 127)
656 				si1 = i1 - 256;
657 			else
658 				si1 = i1;
659 
660 			if (q1 > 127)
661 				sq1 = q1 - 256;
662 			else
663 				sq1 = q1;
664 
665 			if (i2 > 127)
666 				si2 = i2 - 256;
667 			else
668 				si2 = i2;
669 
670 			if (q2 > 127)
671 				sq2 = q2 - 256;
672 			else
673 				sq2 = q2;
674 
675 			spectral_debug("SPECTRAL ADC : Interpreting capture format 1");
676 			spectral_debug("adc_data_format_1 # %d %d %d",
677 				       2 * i, si1, sq1);
678 			spectral_debug("adc_data_format_1 # %d %d %d",
679 				       2 * i + 1, si2, sq2);
680 		}
681 
682 		/* Interpreting capture format 0 */
683 		if (1) {
684 			uint16_t i1;
685 			uint16_t q1;
686 			int16_t si1;
687 			int16_t sq1;
688 
689 			i1 = data & 0xffff;
690 			q1 = (data >> 16) & 0xffff;
691 			if (i1 > 32767)
692 				si1 = i1 - 65536;
693 			else
694 				si1 = i1;
695 
696 			if (q1 > 32767)
697 				sq1 = q1 - 65536;
698 			else
699 				sq1 = q1;
700 			spectral_debug("SPECTRAL ADC : Interpreting capture format 0");
701 			spectral_debug("adc_data_format_2 # %d %d %d",
702 				       i, si1, sq1);
703 		}
704 	}
705 
706 	spectral_debug("\n");
707 
708 	return 0;
709 }
710 
711 /**
712  * target_if_dump_sfft_report_gen2() - Process Search FFT Report for gen2
713  * @ptlv: Pointer to Spectral Phyerr TLV
714  * @tlvlen: length
715  * @is_160_format: Indicates 160 format
716  *
717  * Process Search FFT Report for gen2
718  *
719  * Return: Success/Failure
720  */
721 static int
722 target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
723 				int tlvlen, bool is_160_format)
724 {
725 	int i;
726 	uint32_t fft_mag;
727 
728 	/*
729 	 * For simplicity, everything is defined as uint32_t (except one).
730 	 * Proper code will later use the right sizes.
731 	 */
732 	/*
733 	 * For easy comparison between MDK team and OS team, the MDK script
734 	 * variable names have been used
735 	 */
736 	uint32_t relpwr_db;
737 	uint32_t num_str_bins_ib;
738 	uint32_t base_pwr;
739 	uint32_t total_gain_info;
740 
741 	uint32_t fft_chn_idx;
742 	int16_t peak_inx;
743 	uint32_t avgpwr_db;
744 	uint32_t peak_mag;
745 	uint8_t segid;
746 
747 	uint32_t fft_summary_A = 0;
748 	uint32_t fft_summary_B = 0;
749 	uint32_t fft_summary_C = 0;
750 	uint8_t *tmp = (uint8_t *)ptlv;
751 	struct spectral_phyerr_hdr_gen2 *phdr =
752 	    (struct spectral_phyerr_hdr_gen2 *)(
753 		tmp +
754 		sizeof(struct spectral_phyerr_tlv_gen2));
755 	uint32_t segid_skiplen = 0;
756 
757 	if (is_160_format)
758 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
759 
760 	spectral_debug("SPECTRAL : SEARCH FFT REPORT");
761 
762 	/* Relook this */
763 	if (tlvlen < (8 + segid_skiplen)) {
764 		spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
765 			     tlvlen);
766 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
767 		return -EPERM;
768 	}
769 
770 	/* Doing copy as the contents may not be aligned */
771 	qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
772 	qdf_mem_copy(&fft_summary_B,
773 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
774 		     sizeof(int));
775 	if (is_160_format)
776 		qdf_mem_copy(&fft_summary_C,
777 			     (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
778 			     sizeof(int));
779 
780 	relpwr_db = ((fft_summary_B >> 26) & 0x3f);
781 	num_str_bins_ib = fft_summary_B & 0xff;
782 	base_pwr = ((fft_summary_A >> 14) & 0x1ff);
783 	total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
784 
785 	fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
786 	peak_inx = fft_summary_A & 0xfff;
787 
788 	if (peak_inx > 2047)
789 		peak_inx = peak_inx - 4096;
790 
791 	avgpwr_db = ((fft_summary_B >> 18) & 0xff);
792 	peak_mag = ((fft_summary_B >> 8) & 0x3ff);
793 
794 	spectral_debug("Header A = 0x%x Header B = 0x%x",
795 		       phdr->hdr_a, phdr->hdr_b);
796 	spectral_debug("Base Power= 0x%x, Total Gain= %d, relpwr_db=%d, num_str_bins_ib=%d fft_chn_idx=%d peak_inx=%d avgpwr_db=%d peak_mag=%d",
797 		       base_pwr, total_gain_info, relpwr_db, num_str_bins_ib,
798 		       fft_chn_idx, peak_inx, avgpwr_db, peak_mag);
799 	if (is_160_format) {
800 		segid = fft_summary_C & 0x1;
801 		spectral_debug("Segment ID: %hhu", segid);
802 	}
803 
804 	spectral_debug("FFT bins:");
805 	for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) {
806 		fft_mag = ((uint8_t *)ptlv)[12 + segid_skiplen + i];
807 		spectral_debug("%d %d, ", i, fft_mag);
808 	}
809 
810 	spectral_debug("\n");
811 
812 	return 0;
813 }
814 
815 #ifndef OPTIMIZED_SAMP_MESSAGE
816 #ifdef SPECTRAL_DEBUG_SAMP_MSG
817 /**
818  * target_if_spectral_log_SAMP_param() - Log SAMP parameters
819  * @params: Reference to target_if_samp_msg_params
820  *
821  * API to log spectral SAMP message parameters
822  *
823  * Return: None
824  */
825 static void
826 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
827 {
828 	target_if_dbg_print_samp_param(params);
829 }
830 
831 #else
832 static void
833 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
834 {
835 }
836 #endif
837 #endif /* OPTIMIZED_SAMP_MESSAGE */
838 
839 #ifdef OPTIMIZED_SAMP_MESSAGE
840 /**
841  * target_if_spectral_unify_cfreq_format() - Unify the cfreq representations.
842  * @spectral: Pointer to target_if spectral internal structure
843  * @cfreq1: cfreq1 value received in the Spectral report
844  * @cfreq2: cfreq2 value received in the Spectral report
845  * @pri20_freq: Primary 20MHz frequency of operation
846  * @ch_width: channel width. If the center frequencies are of operating channel,
847  * pass the operating channel width, else pass the sscan channel width.
848  * @smode: Spectral scan mode
849  *
850  * This API converts the cfreq1 and cfreq2 representations as follows.
851  * For a contiguous channel, cfreq1 will represent the center of the entire
852  * span and cfreq2 will be 0. For a discontiguous channel like 80p80, cfreq1
853  * will represent the center of primary segment whereas cfreq2 will
854  * represent the center of secondary segment.
855  *
856  * Return: Success/Failure
857  */
858 static QDF_STATUS
859 target_if_spectral_unify_cfreq_format(struct target_if_spectral *spectral,
860 				      uint32_t *cfreq1, uint32_t *cfreq2,
861 				      uint32_t pri20_freq,
862 				      enum phy_ch_width ch_width,
863 				      enum spectral_scan_mode smode)
864 
865 {
866 	uint32_t reported_cfreq1, reported_cfreq2;
867 	struct wlan_objmgr_psoc *psoc;
868 
869 	if (!spectral) {
870 		spectral_err_rl("Spectral LMAC object is null");
871 		return QDF_STATUS_E_NULL_VALUE;
872 	}
873 	if (!spectral->pdev_obj) {
874 		spectral_err_rl("Spectral PDEV is null");
875 		return QDF_STATUS_E_NULL_VALUE;
876 	}
877 
878 	psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
879 	if (!psoc) {
880 		spectral_err_rl("psoc is null");
881 		return QDF_STATUS_E_NULL_VALUE;
882 	}
883 
884 	reported_cfreq1 = *cfreq1;
885 	reported_cfreq2 = *cfreq2;
886 
887 	if (ch_width == CH_WIDTH_160MHZ &&
888 	    spectral->rparams.fragmentation_160[smode]) {
889 		/* cfreq should be 0 for 160MHz as it is contiguous */
890 		*cfreq2 = 0;
891 
892 		/**
893 		 * For gen3 chipsets that use fragmentation, cfreq1 is center of
894 		 * pri80, and cfreq2 is center of sec80. Averaging them gives
895 		 * the center of the 160MHz span.
896 		 * Whereas gen2 chipsets report the center of the 160MHz span in
897 		 * cfreq2 itself.
898 		 */
899 		if (spectral->spectral_gen == SPECTRAL_GEN3)
900 			*cfreq1 = (reported_cfreq1 + reported_cfreq2) >> 1;
901 		else
902 			*cfreq1 = reported_cfreq2;
903 	} else if (ch_width == CH_WIDTH_80P80MHZ &&
904 		   wlan_psoc_nif_fw_ext_cap_get(
905 		   psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
906 			/* In restricted 80p80 case */
907 			const struct bonded_channel_freq
908 					*bonded_chan_ptr = NULL;
909 			enum channel_state state;
910 
911 			/* Get the 80MHz channel containing the pri20 freq */
912 			state =
913 			    wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
914 				(spectral->pdev_obj, pri20_freq, CH_WIDTH_80MHZ,
915 				 &bonded_chan_ptr, REG_CURRENT_PWR_MODE,
916 				 NO_SCHANS_PUNC);
917 
918 			if (state == CHANNEL_STATE_DISABLE ||
919 			    state == CHANNEL_STATE_INVALID) {
920 				spectral_err_rl("Channel state is disable or invalid");
921 				return QDF_STATUS_E_FAILURE;
922 			}
923 
924 			if (!bonded_chan_ptr) {
925 				spectral_err_rl("Bonded channel is not found");
926 				return QDF_STATUS_E_FAILURE;
927 			}
928 
929 			/* cfreq1 is the center of the pri80 segment */
930 			*cfreq1 = (bonded_chan_ptr->start_freq +
931 				   bonded_chan_ptr->end_freq) >> 1;
932 
933 			/**
934 			 * cfreq2 is 85MHz away from cfreq1. Whether it is
935 			 * higher or lower depends on pri20_freq's relationship
936 			 * with the reported center frequency.
937 			 */
938 			if (pri20_freq < reported_cfreq1)
939 				*cfreq2 = *cfreq1 + FREQ_OFFSET_85MHZ;
940 			else
941 				*cfreq2 = *cfreq1 - FREQ_OFFSET_85MHZ;
942 	} else {
943 		/* All other cases are reporting the cfreq properly */
944 		*cfreq1 = reported_cfreq1;
945 		*cfreq2 = reported_cfreq2;
946 	}
947 
948 	return QDF_STATUS_SUCCESS;
949 }
950 
951 /**
952  * target_if_populate_det_start_end_freqs() - Populate the start and end
953  * frequencies, on per-detector level.
954  * @spectral: Pointer to target_if spectral internal structure
955  * @smode: Spectral scan mode
956  *
957  * Populate the start and end frequencies, on per-detector level.
958  *
959  * Return: Success/Failure
960  */
961 static QDF_STATUS
962 target_if_populate_det_start_end_freqs(struct target_if_spectral *spectral,
963 				       enum spectral_scan_mode smode)
964 {
965 	struct per_session_report_info *rpt_info;
966 	struct per_session_det_map *det_map;
967 	struct per_session_dest_det_info *dest_det_info;
968 	enum phy_ch_width ch_width;
969 	struct sscan_detector_list *detector_list;
970 	bool is_fragmentation_160;
971 	uint8_t det;
972 	uint32_t cfreq;
973 	uint32_t start_end_freq_arr[2];
974 
975 	if (!spectral) {
976 		spectral_err_rl("Spectral LMAC object is null");
977 		return QDF_STATUS_E_NULL_VALUE;
978 	}
979 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
980 		spectral_err_rl("Invalid Spectral mode");
981 		return QDF_STATUS_E_FAILURE;
982 	}
983 
984 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
985 
986 	ch_width = spectral->report_info[smode].sscan_bw;
987 	is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
988 
989 	rpt_info = &spectral->report_info[smode];
990 
991 	qdf_spin_lock_bh(&spectral->detector_list_lock);
992 	detector_list = &spectral->detector_list[smode][ch_width];
993 
994 	for (det = 0; det < detector_list->num_detectors; det++) {
995 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
996 		det_map = &spectral->det_map
997 				[detector_list->detectors[det]];
998 		dest_det_info = &det_map->dest_det_info[0];
999 
1000 		switch (det) {
1001 		case 0:
1002 			if (ch_width == CH_WIDTH_160MHZ &&
1003 			    is_fragmentation_160) {
1004 				if (rpt_info->pri20_freq <
1005 				    rpt_info->sscan_cfreq1)
1006 					cfreq = rpt_info->sscan_cfreq1 -
1007 						FREQ_OFFSET_40MHZ;
1008 				else
1009 					cfreq = rpt_info->sscan_cfreq1 +
1010 						FREQ_OFFSET_40MHZ;
1011 			} else
1012 				cfreq = rpt_info->sscan_cfreq1;
1013 			break;
1014 
1015 		case 1:
1016 			if (ch_width == CH_WIDTH_160MHZ &&
1017 			    is_fragmentation_160) {
1018 				if (rpt_info->pri20_freq <
1019 				    rpt_info->sscan_cfreq1)
1020 					cfreq = rpt_info->sscan_cfreq1 +
1021 						FREQ_OFFSET_40MHZ;
1022 				else
1023 					cfreq = rpt_info->sscan_cfreq1 -
1024 						FREQ_OFFSET_40MHZ;
1025 			} else
1026 				cfreq = rpt_info->sscan_cfreq2;
1027 			break;
1028 
1029 		default:
1030 			qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1031 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
1032 			qdf_spin_unlock_bh(
1033 					&spectral->session_report_info_lock);
1034 
1035 			return QDF_STATUS_E_FAILURE;
1036 		}
1037 
1038 		/* Set start and end frequencies */
1039 		target_if_spectral_set_start_end_freq(cfreq,
1040 						      ch_width,
1041 						      is_fragmentation_160,
1042 						      start_end_freq_arr);
1043 		dest_det_info->start_freq = start_end_freq_arr[0];
1044 		dest_det_info->end_freq = start_end_freq_arr[1];
1045 
1046 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1047 	}
1048 
1049 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
1050 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1051 
1052 	return QDF_STATUS_SUCCESS;
1053 }
1054 
1055 QDF_STATUS
1056 target_if_populate_fft_bins_info(struct target_if_spectral *spectral,
1057 				 enum spectral_scan_mode smode)
1058 {
1059 	struct per_session_det_map *det_map;
1060 	struct per_session_dest_det_info *dest_det_info;
1061 	enum phy_ch_width ch_width;
1062 	struct sscan_detector_list *detector_list;
1063 	bool is_fragmentation_160;
1064 	uint8_t spectral_fft_size;
1065 	uint8_t rpt_mode;
1066 	uint32_t num_fft_bins;
1067 	uint16_t start_bin;
1068 	uint8_t det;
1069 
1070 	if (!spectral) {
1071 		spectral_err_rl("Spectral LMAC object is null");
1072 		return QDF_STATUS_E_NULL_VALUE;
1073 	}
1074 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1075 		spectral_err_rl("Invalid Spectral mode");
1076 		return QDF_STATUS_E_FAILURE;
1077 	}
1078 
1079 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1080 
1081 	ch_width = spectral->report_info[smode].sscan_bw;
1082 	is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
1083 	spectral_fft_size = spectral->params[smode].ss_fft_size;
1084 	rpt_mode = spectral->params[smode].ss_rpt_mode;
1085 	num_fft_bins =
1086 		target_if_spectral_get_num_fft_bins(spectral_fft_size,
1087 						    rpt_mode);
1088 	if (num_fft_bins < 0) {
1089 		qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1090 		spectral_err_rl("Invalid number of FFT bins %d",
1091 				num_fft_bins);
1092 		return QDF_STATUS_E_FAILURE;
1093 	}
1094 
1095 	qdf_spin_lock_bh(&spectral->detector_list_lock);
1096 	detector_list = &spectral->detector_list[smode][ch_width];
1097 
1098 	for (det = 0; det < detector_list->num_detectors; det++) {
1099 		uint16_t lb_extrabins_offset = 0;
1100 
1101 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
1102 		det_map = &spectral->det_map
1103 				[detector_list->detectors[det]];
1104 		dest_det_info = &det_map->dest_det_info[0];
1105 		dest_det_info->lb_extrabins_num = spectral->lb_edge_extrabins;
1106 		dest_det_info->rb_extrabins_num = spectral->rb_edge_extrabins;
1107 		switch (det) {
1108 		case 0:
1109 			if (ch_width == CH_WIDTH_160MHZ &&
1110 			    is_fragmentation_160 &&
1111 			    spectral->report_info[smode].pri20_freq >
1112 			    spectral->report_info[smode].sscan_cfreq1) {
1113 				start_bin = num_fft_bins;
1114 				lb_extrabins_offset =
1115 					dest_det_info->lb_extrabins_num +
1116 					dest_det_info->rb_extrabins_num;
1117 			} else {
1118 				start_bin = 0;
1119 			}
1120 			break;
1121 		case 1:
1122 			if (ch_width == CH_WIDTH_160MHZ &&
1123 			    is_fragmentation_160 &&
1124 			    spectral->report_info[smode].pri20_freq >
1125 			    spectral->report_info[smode].sscan_cfreq1)
1126 				start_bin = 0;
1127 			else {
1128 				start_bin = num_fft_bins;
1129 				lb_extrabins_offset =
1130 					dest_det_info->lb_extrabins_num +
1131 					dest_det_info->rb_extrabins_num;
1132 			}
1133 			break;
1134 		default:
1135 			qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1136 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
1137 			qdf_spin_unlock_bh(
1138 					&spectral->session_report_info_lock);
1139 
1140 			return QDF_STATUS_E_FAILURE;
1141 		}
1142 		dest_det_info->dest_start_bin_idx = start_bin;
1143 		dest_det_info->dest_end_bin_idx =
1144 					dest_det_info->dest_start_bin_idx;
1145 		if (num_fft_bins > 0)
1146 			dest_det_info->dest_end_bin_idx += (num_fft_bins - 1);
1147 
1148 		if (dest_det_info->lb_extrabins_num) {
1149 			if (is_ch_width_160_or_80p80(ch_width)) {
1150 				dest_det_info->lb_extrabins_start_idx =
1151 							2 * num_fft_bins +
1152 							lb_extrabins_offset;
1153 			} else {
1154 				dest_det_info->lb_extrabins_start_idx =
1155 								num_fft_bins;
1156 			}
1157 		}
1158 		if (dest_det_info->rb_extrabins_num)
1159 			dest_det_info->rb_extrabins_start_idx =
1160 					dest_det_info->lb_extrabins_start_idx +
1161 					dest_det_info->lb_extrabins_num;
1162 		dest_det_info->src_start_bin_idx = 0;
1163 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1164 	}
1165 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
1166 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1167 
1168 	return QDF_STATUS_SUCCESS;
1169 }
1170 
1171 /**
1172  * target_if_update_session_info_from_report_ctx() - Update per-session
1173  * information from the consume report context. This includes populating start
1174  * and end bin indices, and set the start and end frequency per-detector.
1175  * @spectral: Pointer to target_if spectral internal structure
1176  * @fft_bin_size: Size of 1 FFT bin (in bytes)
1177  * @cfreq1: Center frequency of Detector 1
1178  * @cfreq2: Center frequency of Detector 2
1179  * @smode: Spectral scan mode
1180  *
1181  * Update per-session information from the consume report context.
1182  *
1183  * Return: Success/Failure
1184  */
1185 static QDF_STATUS
1186 target_if_update_session_info_from_report_ctx(
1187 				struct target_if_spectral *spectral,
1188 				uint8_t fft_bin_size,
1189 				uint32_t cfreq1, uint32_t cfreq2,
1190 				enum spectral_scan_mode smode)
1191 {
1192 	struct target_if_spectral_ops *p_sops;
1193 	struct per_session_report_info *rpt_info;
1194 	struct per_session_det_map *det_map;
1195 	struct per_session_dest_det_info *dest_det_info;
1196 	enum phy_ch_width ch_width;
1197 	struct wlan_objmgr_psoc *psoc;
1198 	bool is_fragmentation_160;
1199 	uint32_t start_end_freq_arr[2];
1200 	QDF_STATUS ret;
1201 	bool is_session_info_expected;
1202 
1203 	if (!spectral) {
1204 		spectral_err_rl("Spectral LMAC object is null");
1205 		return QDF_STATUS_E_NULL_VALUE;
1206 	}
1207 
1208 	ret = spectral_is_session_info_expected_from_target(
1209 				spectral->pdev_obj,
1210 				&is_session_info_expected);
1211 	if (QDF_IS_STATUS_ERROR(ret)) {
1212 		spectral_err_rl("Failed to check if session info is expected");
1213 		return ret;
1214 	}
1215 
1216 	/* If FW sends this information, use it, no need to get it from here */
1217 	if (is_session_info_expected)
1218 		return QDF_STATUS_SUCCESS;
1219 
1220 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1221 		spectral_err_rl("Invalid Spectral mode");
1222 		return QDF_STATUS_E_FAILURE;
1223 	}
1224 	if (!spectral->pdev_obj) {
1225 		spectral_err_rl("Spectral PDEV is null");
1226 		return QDF_STATUS_E_NULL_VALUE;
1227 	}
1228 
1229 	psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
1230 	if (!psoc) {
1231 		spectral_err_rl("psoc is null");
1232 		return QDF_STATUS_E_NULL_VALUE;
1233 	}
1234 
1235 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1236 
1237 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1238 
1239 	rpt_info = &spectral->report_info[smode];
1240 	ch_width = rpt_info->sscan_bw;
1241 	is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
1242 
1243 	rpt_info->pri20_freq = p_sops->get_current_channel(spectral, smode);
1244 	rpt_info->cfreq1 = cfreq1;
1245 	rpt_info->cfreq2 = cfreq2;
1246 
1247 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1248 		spectral_debug("Before conversion: cfreq1: %u cfreq2: %u",
1249 			       rpt_info->cfreq1, rpt_info->cfreq2);
1250 
1251 	ret = target_if_spectral_unify_cfreq_format(
1252 		spectral, &rpt_info->cfreq1, &rpt_info->cfreq2,
1253 		rpt_info->pri20_freq, rpt_info->operating_bw, smode);
1254 
1255 	if (QDF_IS_STATUS_ERROR(ret)) {
1256 		qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1257 		spectral_err_rl("Unable to unify cfreq1/cfreq2");
1258 		return QDF_STATUS_E_FAILURE;
1259 	}
1260 
1261 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1262 		spectral_debug("After conversion: cfreq1: %d cfreq2: %d",
1263 			       rpt_info->cfreq1, rpt_info->cfreq2);
1264 
1265 	/* For Agile mode, sscan_cfreq1 and sscan_cfreq2 are populated
1266 	 * during Spectral start scan
1267 	 */
1268 	if (smode == SPECTRAL_SCAN_MODE_NORMAL) {
1269 		rpt_info->sscan_cfreq1 = rpt_info->cfreq1;
1270 		rpt_info->sscan_cfreq2 = rpt_info->cfreq2;
1271 	}
1272 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1273 
1274 	if (ch_width == CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
1275 	    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
1276 		/* Restricted 80p80 */
1277 		struct spectral_fft_bin_markers_160_165mhz *marker;
1278 		struct sscan_detector_list *detector_list;
1279 
1280 		marker = &spectral->rparams.marker[smode];
1281 		if (!marker->is_valid)
1282 			return QDF_STATUS_E_FAILURE;
1283 
1284 		/**
1285 		 * Restricted 80p80 on Pine has only 1 detector for
1286 		 * normal/agile spectral scan. So, detector_list will
1287 		 * have only one detector
1288 		 */
1289 		qdf_spin_lock_bh(&spectral->detector_list_lock);
1290 		detector_list = &spectral->detector_list[smode][ch_width];
1291 
1292 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
1293 		det_map = &spectral->det_map[detector_list->detectors[0]];
1294 
1295 		dest_det_info = &det_map->dest_det_info[0];
1296 		dest_det_info->dest_start_bin_idx = marker->start_pri80;
1297 		dest_det_info->dest_end_bin_idx =
1298 					dest_det_info->dest_start_bin_idx +
1299 					marker->num_pri80 - 1;
1300 		dest_det_info->src_start_bin_idx = marker->start_pri80 *
1301 						   fft_bin_size;
1302 		/* Set start and end frequencies */
1303 		qdf_spin_lock_bh(&spectral->session_report_info_lock);
1304 		target_if_spectral_set_start_end_freq(rpt_info->sscan_cfreq1,
1305 						      ch_width,
1306 						      is_fragmentation_160,
1307 						      start_end_freq_arr);
1308 		dest_det_info->start_freq = start_end_freq_arr[0];
1309 		dest_det_info->end_freq = start_end_freq_arr[1];
1310 
1311 
1312 		dest_det_info = &det_map->dest_det_info[1];
1313 		dest_det_info->dest_start_bin_idx = marker->start_sec80;
1314 		dest_det_info->dest_end_bin_idx =
1315 					dest_det_info->dest_start_bin_idx +
1316 					marker->num_sec80 - 1;
1317 		dest_det_info->src_start_bin_idx = marker->start_sec80 *
1318 						   fft_bin_size;
1319 		/* Set start and end frequencies */
1320 		target_if_spectral_set_start_end_freq(rpt_info->sscan_cfreq2,
1321 						      ch_width,
1322 						      is_fragmentation_160,
1323 						      start_end_freq_arr);
1324 		dest_det_info->start_freq = start_end_freq_arr[0];
1325 		dest_det_info->end_freq = start_end_freq_arr[1];
1326 
1327 		dest_det_info = &det_map->dest_det_info[2];
1328 		dest_det_info->dest_start_bin_idx = marker->start_5mhz;
1329 		dest_det_info->dest_end_bin_idx =
1330 					dest_det_info->dest_start_bin_idx +
1331 					marker->num_5mhz - 1;
1332 		dest_det_info->src_start_bin_idx = marker->start_5mhz *
1333 						   fft_bin_size;
1334 		/* Set start and end frequencies */
1335 		dest_det_info->start_freq =
1336 				min(det_map->dest_det_info[0].end_freq,
1337 				    det_map->dest_det_info[1].end_freq);
1338 		dest_det_info->end_freq =
1339 				max(det_map->dest_det_info[0].start_freq,
1340 				    det_map->dest_det_info[1].start_freq);
1341 
1342 		qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1343 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1344 		qdf_spin_unlock_bh(&spectral->detector_list_lock);
1345 	} else {
1346 		ret = target_if_populate_fft_bins_info(spectral, smode);
1347 		if (QDF_IS_STATUS_ERROR(ret)) {
1348 			spectral_err_rl("Error in populating fft bins info");
1349 			return QDF_STATUS_E_FAILURE;
1350 		}
1351 
1352 		ret = target_if_populate_det_start_end_freqs(spectral, smode);
1353 		if (QDF_IS_STATUS_ERROR(ret)) {
1354 			spectral_err_rl("Failed to populate start/end freqs");
1355 			return QDF_STATUS_E_FAILURE;
1356 		}
1357 	}
1358 
1359 	return QDF_STATUS_SUCCESS;
1360 }
1361 #endif /* OPTIMIZED_SAMP_MESSAGE */
1362 
1363 #ifdef OPTIMIZED_SAMP_MESSAGE
1364 /**
1365  * target_if_spectral_populate_samp_params_gen2() - Populate the SAMP params
1366  * for gen2. SAMP params are to be used for populating SAMP msg.
1367  * @spectral: Pointer to spectral object
1368  * @phyerr_info: Pointer to processed phyerr info
1369  * @params: Pointer to Spectral SAMP message fields to be populated
1370  *
1371  * Populate the SAMP params for gen2, which will be used to populate SAMP msg.
1372  *
1373  * Return: Success/Failure
1374  */
1375 static QDF_STATUS
1376 target_if_spectral_populate_samp_params_gen2(
1377 			struct target_if_spectral *spectral,
1378 			struct spectral_process_phyerr_info_gen2 *phyerr_info,
1379 			struct target_if_samp_msg_params *params)
1380 {
1381 	uint8_t chn_idx_highest_enabled;
1382 	uint8_t chn_idx_lowest_enabled;
1383 	int8_t control_rssi;
1384 	int8_t extension_rssi;
1385 	struct target_if_spectral_rfqual_info *p_rfqual;
1386 	struct spectral_search_fft_info_gen2 *p_sfft;
1387 	struct spectral_phyerr_fft_gen2 *pfft;
1388 	struct target_if_spectral_acs_stats *acs_stats;
1389 	enum phy_ch_width ch_width;
1390 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1391 
1392 	if (!spectral) {
1393 		spectral_err_rl("Spectral LMAC object is null");
1394 		return QDF_STATUS_E_NULL_VALUE;
1395 	}
1396 	if (!phyerr_info) {
1397 		spectral_err_rl("Pointer to phyerr info is null");
1398 		return QDF_STATUS_E_NULL_VALUE;
1399 	}
1400 	if (!params) {
1401 		spectral_err_rl("SAMP msg params structure is null");
1402 		return QDF_STATUS_E_NULL_VALUE;
1403 	}
1404 
1405 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1406 	ch_width = spectral->report_info[smode].sscan_bw;
1407 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1408 
1409 	acs_stats = phyerr_info->acs_stats;
1410 	pfft = phyerr_info->pfft;
1411 	p_sfft = phyerr_info->p_sfft;
1412 	p_rfqual = phyerr_info->p_rfqual;
1413 
1414 	params->hw_detector_id = phyerr_info->seg_id;
1415 	params->rssi = p_rfqual->rssi_comb;
1416 	if (spectral->is_sec80_rssi_war_required && phyerr_info->seg_id == 1)
1417 		params->rssi = target_if_get_combrssi_sec80_seg_gen2(spectral,
1418 								     p_sfft);
1419 
1420 	chn_idx_highest_enabled =
1421 		   ((spectral->params[smode].ss_chn_mask & 0x8) ? 3 :
1422 		    (spectral->params[smode].ss_chn_mask & 0x4) ? 2 :
1423 		    (spectral->params[smode].ss_chn_mask & 0x2) ? 1 : 0);
1424 	chn_idx_lowest_enabled =
1425 		   ((spectral->params[smode].ss_chn_mask & 0x1) ? 0 :
1426 		    (spectral->params[smode].ss_chn_mask & 0x2) ? 1 :
1427 		    (spectral->params[smode].ss_chn_mask & 0x4) ? 2 : 3);
1428 	control_rssi =
1429 		p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
1430 	extension_rssi =
1431 		p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
1432 
1433 	if (spectral->upper_is_control)
1434 		params->upper_rssi = control_rssi;
1435 	else
1436 		params->upper_rssi = extension_rssi;
1437 
1438 	if (spectral->lower_is_control)
1439 		params->lower_rssi = control_rssi;
1440 	else
1441 		params->lower_rssi = extension_rssi;
1442 
1443 	if (spectral->sc_spectral_noise_pwr_cal) {
1444 		int idx;
1445 
1446 		for (idx = 0; idx < HOST_MAX_ANTENNA; idx++) {
1447 			params->chain_ctl_rssi[idx] =
1448 				p_rfqual->pc_rssi_info[idx].rssi_pri20;
1449 			params->chain_ext_rssi[idx] =
1450 				p_rfqual->pc_rssi_info[idx].rssi_sec20;
1451 		}
1452 	}
1453 	params->timestamp = (phyerr_info->tsf64 & SPECTRAL_TSMASK);
1454 	params->max_mag = p_sfft->peak_mag;
1455 	params->max_index = p_sfft->peak_inx;
1456 
1457 	/*
1458 	 * For VHT80_80/VHT160, the noise floor for primary
1459 	 * 80MHz segment is populated with the lowest enabled
1460 	 * antenna chain and the noise floor for secondary 80MHz segment
1461 	 * is populated with the highest enabled antenna chain.
1462 	 * For modes upto VHT80, the noise floor is populated with the
1463 	 * one corresponding to the highest enabled antenna chain.
1464 	 */
1465 	if (is_ch_width_160_or_80p80(ch_width) && phyerr_info->seg_id == 0)
1466 		params->noise_floor =
1467 				p_rfqual->noise_floor[chn_idx_lowest_enabled];
1468 	else
1469 		params->noise_floor =
1470 				p_rfqual->noise_floor[chn_idx_highest_enabled];
1471 
1472 	acs_stats->ctrl_nf = params->noise_floor;
1473 	acs_stats->ext_nf = params->noise_floor;
1474 	acs_stats->nfc_ctl_rssi = control_rssi;
1475 	acs_stats->nfc_ext_rssi = extension_rssi;
1476 
1477 	params->bin_pwr_data = (uint8_t *)pfft;
1478 
1479 	return QDF_STATUS_SUCCESS;
1480 }
1481 
1482 int
1483 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
1484 			      uint8_t *data,
1485 			      uint32_t datalen,
1486 			      struct target_if_spectral_rfqual_info *p_rfqual,
1487 			      struct target_if_spectral_chan_info *p_chaninfo,
1488 			      uint64_t tsf64,
1489 			      struct target_if_spectral_acs_stats *acs_stats)
1490 {
1491 	/*
1492 	 * XXX : The classifier do not use all the members of the SAMP
1493 	 *       message data format.
1494 	 *       The classifier only depends upon the following parameters
1495 	 *
1496 	 *          1. Frequency
1497 	 *          2. Spectral RSSI
1498 	 *          3. Bin Power Count
1499 	 *          4. Bin Power values
1500 	 *          5. Spectral Timestamp
1501 	 *          6. MAC Address
1502 	 *
1503 	 *       This function prepares the params structure and populates it
1504 	 *       with relevant values, this is in turn passed to
1505 	 *       spectral_fill_samp_msg()
1506 	 *       to prepare fully formatted Spectral SAMP message
1507 	 *
1508 	 *       XXX : Need to verify
1509 	 *          1. Order of FFT bin values
1510 	 *
1511 	 */
1512 
1513 	struct target_if_samp_msg_params params;
1514 	struct spectral_search_fft_info_gen2 search_fft_info;
1515 	struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
1516 	struct spectral_search_fft_info_gen2 search_fft_info_sec80;
1517 	struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
1518 		&search_fft_info_sec80;
1519 	uint32_t segid_skiplen = 0;
1520 	struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
1521 	struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
1522 	struct spectral_phyerr_fft_gen2 *pfft = NULL;
1523 	struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
1524 	struct spectral_process_phyerr_info_gen2 process_phyerr_fields;
1525 	struct spectral_process_phyerr_info_gen2 *phyerr_info =
1526 						&process_phyerr_fields;
1527 	uint8_t segid = 0;
1528 	uint8_t segid_sec80;
1529 	enum phy_ch_width ch_width;
1530 	QDF_STATUS ret;
1531 	struct target_if_spectral_ops *p_sops;
1532 
1533 	if (!spectral) {
1534 		spectral_err_rl("Spectral LMAC object is null");
1535 		return -EPERM;
1536 	}
1537 
1538 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1539 	/* Drop the sample if Spectral is not active */
1540 	if (!p_sops->is_spectral_active(spectral,
1541 					SPECTRAL_SCAN_MODE_NORMAL)) {
1542 		spectral_info_rl("Spectral scan is not active");
1543 		goto fail_no_print;
1544 	}
1545 
1546 	if (!data) {
1547 		spectral_err_rl("Phyerror event buffer is null");
1548 		goto fail;
1549 	}
1550 	if (!p_rfqual) {
1551 		spectral_err_rl("RF quality information is null");
1552 		goto fail;
1553 	}
1554 	if (!p_chaninfo) {
1555 		spectral_err_rl("Channel information is null");
1556 		goto fail;
1557 	}
1558 	if (!acs_stats) {
1559 		spectral_err_rl("ACS stats pointer is null");
1560 		goto fail;
1561 	}
1562 
1563 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1564 	ch_width = spectral->report_info[SPECTRAL_SCAN_MODE_NORMAL].sscan_bw;
1565 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1566 
1567 	ptlv = (struct spectral_phyerr_tlv_gen2 *)data;
1568 
1569 	if (spectral->is_160_format)
1570 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
1571 
1572 	pfft = (struct spectral_phyerr_fft_gen2 *)(
1573 			data +
1574 			sizeof(struct spectral_phyerr_tlv_gen2) +
1575 			sizeof(struct spectral_phyerr_hdr_gen2) +
1576 			segid_skiplen);
1577 
1578 	/*
1579 	 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
1580 	 * and use this facility inside spectral_dump_phyerr_data()
1581 	 * and supporting functions.
1582 	 */
1583 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1584 		target_if_spectral_dump_phyerr_data_gen2(
1585 					data, datalen,
1586 					spectral->is_160_format);
1587 
1588 	if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1589 		/*
1590 		 * EV# 118023: We tentatively disable the below print
1591 		 * and provide stats instead.
1592 		 */
1593 		spectral->diag_stats.spectral_mismatch++;
1594 		goto fail;
1595 	}
1596 
1597 	qdf_mem_zero(&params, sizeof(params));
1598 
1599 	if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1600 		if (spectral->is_160_format) {
1601 			segid = *((SPECTRAL_SEGID_INFO *)(
1602 				  (uint8_t *)ptlv +
1603 				  sizeof(struct spectral_phyerr_tlv_gen2) +
1604 				  sizeof(struct spectral_phyerr_hdr_gen2)));
1605 
1606 			if (segid != 0) {
1607 				struct spectral_diag_stats *p_diag_stats =
1608 					&spectral->diag_stats;
1609 				p_diag_stats->spectral_vhtseg1id_mismatch++;
1610 				goto fail;
1611 			}
1612 		}
1613 
1614 		target_if_process_sfft_report_gen2(ptlv, ptlv->length,
1615 						   p_sfft);
1616 
1617 		ret = target_if_update_session_info_from_report_ctx(
1618 						spectral, FFT_BIN_SIZE_1BYTE,
1619 						p_chaninfo->center_freq1,
1620 						p_chaninfo->center_freq2,
1621 						SPECTRAL_SCAN_MODE_NORMAL);
1622 		if (QDF_IS_STATUS_ERROR(ret)) {
1623 			spectral_err_rl("Failed to update per-session info");
1624 			goto fail;
1625 		}
1626 
1627 		phyerr_info->p_rfqual = p_rfqual;
1628 		phyerr_info->p_sfft = p_sfft;
1629 		phyerr_info->pfft = pfft;
1630 		phyerr_info->acs_stats = acs_stats;
1631 		phyerr_info->tsf64 = tsf64;
1632 		phyerr_info->seg_id = segid;
1633 
1634 		ret = target_if_spectral_populate_samp_params_gen2(spectral,
1635 								   phyerr_info,
1636 								   &params);
1637 		if (QDF_IS_STATUS_ERROR(ret)) {
1638 			spectral_err_rl("Failed to populate SAMP params");
1639 			goto fail;
1640 		}
1641 
1642 		ret = target_if_spectral_fill_samp_msg(spectral, &params);
1643 		if (QDF_IS_STATUS_ERROR(ret)) {
1644 			spectral_err_rl("Failed to fill the SAMP msg");
1645 			goto fail;
1646 		}
1647 
1648 		if (spectral->is_160_format &&
1649 		    is_ch_width_160_or_80p80(ch_width)) {
1650 			/*
1651 			 * We expect to see one more Search FFT report, and it
1652 			 * should be equal in size to the current one.
1653 			 */
1654 			if (datalen < (
1655 				2 * (sizeof(struct spectral_phyerr_tlv_gen2) +
1656 				     ptlv->length))) {
1657 				struct spectral_diag_stats *p_diag_stats =
1658 					&spectral->diag_stats;
1659 				p_diag_stats->spectral_sec80_sfft_insufflen++;
1660 				goto fail;
1661 			}
1662 
1663 			ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1664 				      data +
1665 				      sizeof(struct spectral_phyerr_tlv_gen2) +
1666 				      ptlv->length);
1667 
1668 			if (ptlv_sec80->signature !=
1669 			    SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1670 				spectral->diag_stats.spectral_mismatch++;
1671 				goto fail;
1672 			}
1673 
1674 			if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1675 				spectral->diag_stats.spectral_no_sec80_sfft++;
1676 				goto fail;
1677 			}
1678 
1679 			segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
1680 				(uint8_t *)ptlv_sec80 +
1681 				sizeof(struct spectral_phyerr_tlv_gen2) +
1682 				sizeof(struct spectral_phyerr_hdr_gen2)));
1683 
1684 			if (segid_sec80 != 1) {
1685 				struct spectral_diag_stats *p_diag_stats =
1686 					&spectral->diag_stats;
1687 				p_diag_stats->spectral_vhtseg2id_mismatch++;
1688 				goto fail;
1689 			}
1690 
1691 			target_if_process_sfft_report_gen2(ptlv_sec80,
1692 							   ptlv_sec80->length,
1693 							   p_sfft_sec80);
1694 
1695 			pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
1696 				((uint8_t *)ptlv_sec80) +
1697 				sizeof(struct spectral_phyerr_tlv_gen2) +
1698 				sizeof(struct spectral_phyerr_hdr_gen2) +
1699 				segid_skiplen);
1700 
1701 			qdf_mem_zero(&params, sizeof(params));
1702 
1703 			phyerr_info->p_rfqual = p_rfqual;
1704 			phyerr_info->p_sfft = p_sfft_sec80;
1705 			phyerr_info->pfft = pfft_sec80;
1706 			phyerr_info->acs_stats = acs_stats;
1707 			phyerr_info->tsf64 = tsf64;
1708 			phyerr_info->seg_id = segid_sec80;
1709 
1710 			ret = target_if_spectral_populate_samp_params_gen2(
1711 							spectral, phyerr_info,
1712 							&params);
1713 			if (QDF_IS_STATUS_ERROR(ret)) {
1714 				spectral_err_rl("Failed to populate SAMP params");
1715 				goto fail;
1716 			}
1717 			ret = target_if_spectral_fill_samp_msg(spectral,
1718 							       &params);
1719 			if (QDF_IS_STATUS_ERROR(ret)) {
1720 				spectral_err_rl("Failed to fill the SAMP msg");
1721 				goto fail;
1722 			}
1723 		}
1724 	}
1725 
1726 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1727 		spectral_debug_level = DEBUG_SPECTRAL;
1728 
1729 	return 0;
1730 
1731 fail:
1732 	spectral_err_rl("Error while processing Spectral report");
1733 
1734 fail_no_print:
1735 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1736 		spectral_debug_level = DEBUG_SPECTRAL;
1737 
1738 	free_samp_msg_skb(spectral, SPECTRAL_SCAN_MODE_NORMAL);
1739 	return -EPERM;
1740 }
1741 
1742 #else
1743 int
1744 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
1745 			      uint8_t *data,
1746 			      uint32_t datalen,
1747 			      struct target_if_spectral_rfqual_info *p_rfqual,
1748 			      struct target_if_spectral_chan_info *p_chaninfo,
1749 			      uint64_t tsf64,
1750 			      struct target_if_spectral_acs_stats *acs_stats)
1751 {
1752 	/*
1753 	 * XXX : The classifier do not use all the members of the SAMP
1754 	 *       message data format.
1755 	 *       The classifier only depends upon the following parameters
1756 	 *
1757 	 *          1. Frequency (freq, msg->freq)
1758 	 *          2. Spectral RSSI (spectral_rssi,
1759 	 *          msg->samp_data.spectral_rssi)
1760 	 *          3. Bin Power Count (bin_pwr_count,
1761 	 *          msg->samp_data.bin_pwr_count)
1762 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
1763 	 *          5. Spectral Timestamp (spectral_tstamp,
1764 	 *          msg->samp_data.spectral_tstamp)
1765 	 *          6. MAC Address (macaddr, msg->macaddr)
1766 	 *
1767 	 *       This function prepares the params structure and populates it
1768 	 *       with
1769 	 *       relevant values, this is in turn passed to
1770 	 *       spectral_create_samp_msg()
1771 	 *       to prepare fully formatted Spectral SAMP message
1772 	 *
1773 	 *       XXX : Need to verify
1774 	 *          1. Order of FFT bin values
1775 	 *
1776 	 */
1777 
1778 	struct target_if_samp_msg_params params;
1779 	struct spectral_search_fft_info_gen2 search_fft_info;
1780 	struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
1781 	struct spectral_search_fft_info_gen2 search_fft_info_sec80;
1782 	struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
1783 		&search_fft_info_sec80;
1784 	uint32_t segid_skiplen = 0;
1785 
1786 	int8_t rssi_up = 0;
1787 	int8_t rssi_low = 0;
1788 
1789 	int8_t chn_idx_highest_enabled = 0;
1790 	int8_t chn_idx_lowest_enabled = 0;
1791 
1792 	uint8_t control_rssi = 0;
1793 	uint8_t extension_rssi = 0;
1794 	uint8_t combined_rssi = 0;
1795 
1796 	uint32_t tstamp = 0;
1797 
1798 	struct target_if_spectral_ops *p_sops =
1799 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1800 
1801 	struct spectral_phyerr_tlv_gen2 *ptlv =
1802 		(struct spectral_phyerr_tlv_gen2 *)data;
1803 	struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
1804 	struct spectral_phyerr_fft_gen2 *pfft = NULL;
1805 	struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
1806 
1807 	uint8_t segid = 0;
1808 	uint8_t segid_sec80 = 0;
1809 	enum phy_ch_width ch_width =
1810 				spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL];
1811 
1812 	if (spectral->is_160_format)
1813 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
1814 
1815 	pfft = (struct spectral_phyerr_fft_gen2 *)(
1816 			data +
1817 			sizeof(struct spectral_phyerr_tlv_gen2) +
1818 			sizeof(struct spectral_phyerr_hdr_gen2) +
1819 			segid_skiplen);
1820 
1821 	/*
1822 	 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
1823 	 * and use this facility inside spectral_dump_phyerr_data()
1824 	 * and supporting functions.
1825 	 */
1826 	if (spectral_debug_level & DEBUG_SPECTRAL2)
1827 		target_if_spectral_dump_phyerr_data_gen2(
1828 					data, datalen,
1829 					spectral->is_160_format);
1830 
1831 	if (spectral_debug_level & DEBUG_SPECTRAL4) {
1832 		target_if_spectral_dump_phyerr_data_gen2(
1833 					data, datalen,
1834 					spectral->is_160_format);
1835 		spectral_debug_level = DEBUG_SPECTRAL;
1836 	}
1837 
1838 	if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1839 		/*
1840 		 * EV# 118023: We tentatively disable the below print
1841 		 * and provide stats instead.
1842 		 */
1843 		spectral->diag_stats.spectral_mismatch++;
1844 		return -EPERM;
1845 	}
1846 
1847 	OS_MEMZERO(&params, sizeof(params));
1848 	/* Gen 2 only supports normal Spectral scan currently */
1849 	params.smode = SPECTRAL_SCAN_MODE_NORMAL;
1850 
1851 	if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1852 		if (spectral->is_160_format) {
1853 			segid = *((SPECTRAL_SEGID_INFO *)(
1854 				  (uint8_t *)ptlv +
1855 				  sizeof(struct spectral_phyerr_tlv_gen2) +
1856 				  sizeof(struct spectral_phyerr_hdr_gen2)));
1857 
1858 			if (segid != 0) {
1859 				struct spectral_diag_stats *p_diag_stats =
1860 					&spectral->diag_stats;
1861 				p_diag_stats->spectral_vhtseg1id_mismatch++;
1862 				return -EPERM;
1863 			}
1864 		}
1865 
1866 		target_if_process_sfft_report_gen2(ptlv, ptlv->length,
1867 						   &search_fft_info);
1868 
1869 		tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
1870 
1871 		combined_rssi = p_rfqual->rssi_comb;
1872 
1873 		if (spectral->upper_is_control)
1874 			rssi_up = control_rssi;
1875 		else
1876 			rssi_up = extension_rssi;
1877 
1878 		if (spectral->lower_is_control)
1879 			rssi_low = control_rssi;
1880 		else
1881 			rssi_low = extension_rssi;
1882 
1883 		params.rssi = p_rfqual->rssi_comb;
1884 		params.lower_rssi = rssi_low;
1885 		params.upper_rssi = rssi_up;
1886 
1887 		if (spectral->sc_spectral_noise_pwr_cal) {
1888 			params.chain_ctl_rssi[0] =
1889 			    p_rfqual->pc_rssi_info[0].rssi_pri20;
1890 			params.chain_ctl_rssi[1] =
1891 			    p_rfqual->pc_rssi_info[1].rssi_pri20;
1892 			params.chain_ctl_rssi[2] =
1893 			    p_rfqual->pc_rssi_info[2].rssi_pri20;
1894 			params.chain_ext_rssi[0] =
1895 			    p_rfqual->pc_rssi_info[0].rssi_sec20;
1896 			params.chain_ext_rssi[1] =
1897 			    p_rfqual->pc_rssi_info[1].rssi_sec20;
1898 			params.chain_ext_rssi[2] =
1899 			    p_rfqual->pc_rssi_info[2].rssi_sec20;
1900 		}
1901 
1902 		/*
1903 		 * XXX : This actually depends on the programmed chain mask
1904 		 *       This value decides the per-chain enable mask to select
1905 		 *       the input ADC for search FTT.
1906 		 *       For modes upto VHT80, if more than one chain is
1907 		 *       enabled, the max valid chain
1908 		 *       is used. LSB corresponds to chain zero.
1909 		 *       For VHT80_80 and VHT160, the lowest enabled chain is
1910 		 *       used for primary
1911 		 *       detection and highest enabled chain is used for
1912 		 *       secondary detection.
1913 		 *
1914 		 * XXX : The current algorithm do not use these control and
1915 		 *       extension channel
1916 		 *       Instead, it just relies on the combined RSSI values
1917 		 *       only.
1918 		 *       For fool-proof detection algorithm, we should take
1919 		 *       these RSSI values in to account.
1920 		 *       This is marked for future enhancements.
1921 		 */
1922 		chn_idx_highest_enabled =
1923 		   ((spectral->params[params.smode].ss_chn_mask & 0x8) ? 3 :
1924 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 :
1925 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 0);
1926 		chn_idx_lowest_enabled =
1927 		   ((spectral->params[params.smode].ss_chn_mask & 0x1) ? 0 :
1928 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 :
1929 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 3);
1930 		control_rssi = (uint8_t)
1931 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
1932 		extension_rssi = (uint8_t)
1933 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
1934 
1935 		params.bwinfo = 0;
1936 		params.tstamp = 0;
1937 		params.max_mag = p_sfft->peak_mag;
1938 
1939 		params.max_index = p_sfft->peak_inx;
1940 		params.max_exp = 0;
1941 		params.peak = 0;
1942 		params.bin_pwr_data = (uint8_t *)pfft;
1943 		params.freq = p_sops->get_current_channel(spectral,
1944 							  params.smode);
1945 		params.freq_loading = 0;
1946 
1947 		params.interf_list.count = 0;
1948 		params.max_lower_index = 0;
1949 		params.max_upper_index = 0;
1950 		params.nb_lower = 0;
1951 		params.nb_upper = 0;
1952 		/*
1953 		 * For modes upto VHT80, the noise floor is populated with the
1954 		 * one corresponding
1955 		 * to the highest enabled antenna chain
1956 		 */
1957 		params.noise_floor =
1958 		    p_rfqual->noise_floor[chn_idx_highest_enabled];
1959 		params.datalen = ptlv->length;
1960 		params.pwr_count = ptlv->length -
1961 		    sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen;
1962 		params.tstamp = (tsf64 & SPECTRAL_TSMASK);
1963 
1964 		acs_stats->ctrl_nf = params.noise_floor;
1965 		acs_stats->ext_nf = params.noise_floor;
1966 		acs_stats->nfc_ctl_rssi = control_rssi;
1967 		acs_stats->nfc_ext_rssi = extension_rssi;
1968 
1969 		if (spectral->is_160_format &&
1970 		    is_ch_width_160_or_80p80(ch_width)) {
1971 			/*
1972 			 * We expect to see one more Search FFT report, and it
1973 			 * should be equal in size to the current one.
1974 			 */
1975 			if (datalen < (
1976 				2 * (
1977 				sizeof(struct spectral_phyerr_tlv_gen2) +
1978 				ptlv->length))) {
1979 				struct spectral_diag_stats *p_diag_stats =
1980 					&spectral->diag_stats;
1981 				p_diag_stats->spectral_sec80_sfft_insufflen++;
1982 				return -EPERM;
1983 			}
1984 
1985 			ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1986 				      data +
1987 				      sizeof(struct spectral_phyerr_tlv_gen2) +
1988 				      ptlv->length);
1989 
1990 			if (ptlv_sec80->signature !=
1991 			    SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1992 				spectral->diag_stats.spectral_mismatch++;
1993 				return -EPERM;
1994 			}
1995 
1996 			if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1997 				spectral->diag_stats.spectral_no_sec80_sfft++;
1998 				return -EPERM;
1999 			}
2000 
2001 			segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
2002 				(uint8_t *)ptlv_sec80 +
2003 				sizeof(struct spectral_phyerr_tlv_gen2) +
2004 				sizeof(struct spectral_phyerr_hdr_gen2)));
2005 
2006 			if (segid_sec80 != 1) {
2007 				struct spectral_diag_stats *p_diag_stats =
2008 					&spectral->diag_stats;
2009 				p_diag_stats->spectral_vhtseg2id_mismatch++;
2010 				return -EPERM;
2011 			}
2012 
2013 			params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
2014 			params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
2015 
2016 			target_if_process_sfft_report_gen2(
2017 				ptlv_sec80,
2018 				ptlv_sec80->length,
2019 				&search_fft_info_sec80);
2020 
2021 			pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
2022 				((uint8_t *)ptlv_sec80) +
2023 				sizeof(struct spectral_phyerr_tlv_gen2) +
2024 				sizeof(struct spectral_phyerr_hdr_gen2) +
2025 				segid_skiplen);
2026 
2027 			/* XXX: Confirm. TBD at SoD. */
2028 			params.rssi_sec80 = p_rfqual->rssi_comb;
2029 			if (spectral->is_sec80_rssi_war_required)
2030 				params.rssi_sec80 =
2031 				    target_if_get_combrssi_sec80_seg_gen2
2032 				    (spectral, &search_fft_info_sec80);
2033 			/* XXX: Determine dynamically. TBD at SoD. */
2034 			/*
2035 			 * For VHT80_80/VHT160, the noise floor for primary
2036 			 * 80MHz segment is populated with the
2037 			 * lowest enabled antenna chain and the noise floor for
2038 			 * secondary 80MHz segment is populated
2039 			 * with the highest enabled antenna chain
2040 			 */
2041 			params.noise_floor_sec80 =
2042 			    p_rfqual->noise_floor[chn_idx_highest_enabled];
2043 			params.noise_floor =
2044 			    p_rfqual->noise_floor[chn_idx_lowest_enabled];
2045 
2046 			params.max_mag_sec80 = p_sfft_sec80->peak_mag;
2047 			params.max_index_sec80 = p_sfft_sec80->peak_inx;
2048 			/* XXX Does this definition of datalen *still hold? */
2049 			params.datalen_sec80 = ptlv_sec80->length;
2050 			params.pwr_count_sec80 =
2051 			    ptlv_sec80->length -
2052 			    sizeof(struct spectral_phyerr_hdr_gen2) -
2053 			    segid_skiplen;
2054 			params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80;
2055 		}
2056 		qdf_mem_copy(&params.classifier_params,
2057 			     &spectral->classifier_params,
2058 			     sizeof(struct spectral_classifier_params));
2059 
2060 		target_if_spectral_log_SAMP_param(&params);
2061 		target_if_spectral_create_samp_msg(spectral, &params);
2062 	}
2063 
2064 	return 0;
2065 }
2066 #endif /* OPTIMIZED_SAMP_MESSAGE */
2067 
2068 int
2069 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr)
2070 {
2071 	uint32_t a = 0;
2072 	uint32_t b = 0;
2073 
2074 	qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int));
2075 	qdf_mem_copy(&b,
2076 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
2077 		     sizeof(int));
2078 
2079 	spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a);
2080 	spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b);
2081 	return 0;
2082 }
2083 
2084 int8_t
2085 target_if_get_combrssi_sec80_seg_gen2(
2086 	struct target_if_spectral *spectral,
2087 	struct spectral_search_fft_info_gen2 *p_sfft_sec80)
2088 {
2089 	uint32_t avgpwr_db = 0;
2090 	uint32_t total_gain_db = 0;
2091 	uint32_t offset = 0;
2092 	int8_t comb_rssi = 0;
2093 
2094 	/* Obtain required parameters for algorithm from search FFT report */
2095 	avgpwr_db = p_sfft_sec80->avgpwr_db;
2096 	total_gain_db = p_sfft_sec80->total_gain_info;
2097 
2098 	/* Calculate offset */
2099 	offset = target_if_get_offset_swar_sec80(
2100 			spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL]);
2101 
2102 	/* Calculate RSSI */
2103 	comb_rssi = ((avgpwr_db - total_gain_db) + offset);
2104 
2105 	return comb_rssi;
2106 }
2107 
2108 int
2109 target_if_spectral_dump_tlv_gen2(
2110 	struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format)
2111 {
2112 	int ret = 0;
2113 
2114 	/*
2115 	 * TODO : Do not delete the following print
2116 	 *        The scripts used to validate Spectral depend on this Print
2117 	 */
2118 	spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)",
2119 		       ptlv->length, ptlv->length);
2120 
2121 	switch (ptlv->tag) {
2122 	case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
2123 		ret =
2124 		    target_if_dump_summary_report_gen2(
2125 			ptlv, ptlv->length, is_160_format);
2126 		break;
2127 
2128 	case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
2129 		ret =
2130 		    target_if_dump_sfft_report_gen2(ptlv, ptlv->length,
2131 						    is_160_format);
2132 		break;
2133 
2134 	case TLV_TAG_ADC_REPORT_GEN2:
2135 		ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length);
2136 		break;
2137 
2138 	default:
2139 		spectral_warn("INVALID TLV");
2140 		ret = -1;
2141 		break;
2142 	}
2143 
2144 	return ret;
2145 }
2146 
2147 int
2148 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen,
2149 					 bool is_160_format)
2150 {
2151 	struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
2152 	uint32_t bytes_processed = 0;
2153 	uint32_t bytes_remaining = datalen;
2154 	uint32_t curr_tlv_complete_size = 0;
2155 
2156 	if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) {
2157 		spectral_err("Total PHY error data length %u too short to contain any TLVs",
2158 			     datalen);
2159 		return -EPERM;
2160 	}
2161 
2162 	while (bytes_processed < datalen) {
2163 		if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) {
2164 			spectral_err("Remaining PHY error data length %u too short to contain a TLV",
2165 				     bytes_remaining);
2166 			return -EPERM;
2167 		}
2168 
2169 		ptlv = (struct spectral_phyerr_tlv_gen2 *)(data +
2170 							   bytes_processed);
2171 
2172 		if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
2173 			spectral_err("Invalid signature 0x%x!",
2174 				     ptlv->signature);
2175 			return -EPERM;
2176 		}
2177 
2178 		curr_tlv_complete_size =
2179 			sizeof(struct spectral_phyerr_tlv_gen2) +
2180 			ptlv->length;
2181 
2182 		if (curr_tlv_complete_size > bytes_remaining) {
2183 			spectral_err("TLV size %d greater than number of bytes remaining %d",
2184 				     curr_tlv_complete_size, bytes_remaining);
2185 			return -EPERM;
2186 		}
2187 
2188 		if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
2189 			return -EPERM;
2190 
2191 		bytes_processed += curr_tlv_complete_size;
2192 		bytes_remaining = datalen - bytes_processed;
2193 	}
2194 
2195 	return 0;
2196 }
2197 
2198 QDF_STATUS
2199 target_if_spectral_copy_fft_bins(struct target_if_spectral *spectral,
2200 				 const void *src_fft_buf,
2201 				 void *dest_fft_buf,
2202 				 uint32_t fft_bin_count,
2203 				 uint32_t *bytes_copied,
2204 				 uint16_t pwr_format)
2205 {
2206 	uint16_t idx, dword_idx, fft_bin_idx;
2207 	uint8_t num_bins_per_dword, hw_fft_bin_width_bits;
2208 	uint32_t num_dwords;
2209 	uint16_t fft_bin_val;
2210 	struct spectral_report_params *rparams;
2211 	const uint32_t *dword_ptr;
2212 	uint32_t dword;
2213 	uint8_t *fft_bin_buf;
2214 
2215 	*bytes_copied = 0;
2216 
2217 	if (!spectral) {
2218 		spectral_err("spectral lmac object is NULL");
2219 		return QDF_STATUS_E_NULL_VALUE;
2220 	}
2221 
2222 	if (!src_fft_buf) {
2223 		spectral_err("source fft bin buffer is NULL");
2224 		return QDF_STATUS_E_NULL_VALUE;
2225 	}
2226 
2227 	if (!dest_fft_buf) {
2228 		spectral_err("destination fft bin buffer is NULL");
2229 		return QDF_STATUS_E_NULL_VALUE;
2230 	}
2231 
2232 	rparams = &spectral->rparams;
2233 	num_bins_per_dword = SPECTRAL_DWORD_SIZE / rparams->hw_fft_bin_width;
2234 	num_dwords = fft_bin_count / num_bins_per_dword;
2235 	hw_fft_bin_width_bits = rparams->hw_fft_bin_width * QDF_CHAR_BIT;
2236 
2237 	fft_bin_idx = 0;
2238 	dword_ptr = src_fft_buf;
2239 	fft_bin_buf = dest_fft_buf;
2240 	for (dword_idx = 0; dword_idx < num_dwords; dword_idx++) {
2241 		dword = *dword_ptr++; /* Read a DWORD */
2242 		for (idx = 0; idx < num_bins_per_dword; idx++) {
2243 			/**
2244 			 * If we use QDF_GET_BITS, when hw_fft_bin_width_bits is
2245 			 * 32, on certain platforms, we could end up doing a
2246 			 * 32-bit left shift operation on 32-bit constant
2247 			 * integer '1'. As per C standard, result of shifting an
2248 			 * operand by a count greater than or equal to width
2249 			 * (in bits) of the operand is undefined.
2250 			 * If we use QDF_GET_BITS_64, we can avoid that.
2251 			 */
2252 			fft_bin_val = (uint16_t)QDF_GET_BITS64(
2253 					dword,
2254 					idx * hw_fft_bin_width_bits,
2255 					hw_fft_bin_width_bits);
2256 
2257 			fft_bin_buf[fft_bin_idx++] =
2258 				clamp_fft_bin_value(fft_bin_val, pwr_format);
2259 		}
2260 	}
2261 
2262 	*bytes_copied = num_dwords *  SPECTRAL_DWORD_SIZE;
2263 
2264 	return QDF_STATUS_SUCCESS;
2265 }
2266 
2267 #ifdef DIRECT_BUF_RX_ENABLE
2268 /**
2269  * target_if_get_spectral_mode() - Get Spectral scan mode corresponding to a
2270  * detector id
2271  * @detector_id: detector id in the Spectral report
2272  * @rparams: pointer to report params object
2273  *
2274  * Helper API to get Spectral scan mode from the detector ID. This mapping is
2275  * target specific.
2276  *
2277  * Return: Spectral scan mode
2278  */
2279 static enum spectral_scan_mode
2280 target_if_get_spectral_mode(enum spectral_detector_id detector_id,
2281 			    struct spectral_report_params *rparams)
2282 {
2283 	if (detector_id >= SPECTRAL_DETECTOR_ID_MAX) {
2284 		spectral_err_rl("Invalid detector id %d", detector_id);
2285 		return SPECTRAL_SCAN_MODE_INVALID;
2286 	}
2287 
2288 	return rparams->detid_mode_table[detector_id];
2289 }
2290 
2291 /**
2292  * target_if_spectral_get_bin_count_after_len_adj() - Get number of FFT bins in
2293  * Spectral FFT report
2294  * @fft_bin_len: FFT bin length reported by target
2295  * @rpt_mode: Spectral report mode
2296  * @swar: Spectral FFT bin length adjustments SWAR parameters
2297  * @fft_bin_size: Size of one FFT bin in bytes
2298  *
2299  * Get actual number of FFT bins in the FFT report after adjusting the length
2300  * by applying the SWARs for getting correct length.
2301  *
2302  * Return: FFT bin count
2303  */
2304 static size_t
2305 target_if_spectral_get_bin_count_after_len_adj(
2306 				size_t fft_bin_len, uint8_t rpt_mode,
2307 				struct spectral_fft_bin_len_adj_swar *swar,
2308 				size_t *fft_bin_size)
2309 {
2310 	size_t fft_bin_count = fft_bin_len;
2311 
2312 	if (rpt_mode == 1 && swar->null_fftbin_adj) {
2313 		/*
2314 		 * No FFT bins are expected. Explicitly set FFT bin
2315 		 * count to 0.
2316 		 */
2317 		fft_bin_count = 0;
2318 		*fft_bin_size = 0;
2319 	} else {
2320 		/*
2321 		 * Divide fft bin length by appropriate factor depending
2322 		 * on the value of fftbin_size_war.
2323 		 */
2324 		switch (swar->fftbin_size_war) {
2325 		case SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE:
2326 			fft_bin_count >>= 2;
2327 			*fft_bin_size = 4;
2328 			break;
2329 		case SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE:
2330 			fft_bin_count >>= 1;
2331 			*fft_bin_size = 2;
2332 			/* Ideally we should be dividing fft bin length
2333 			 * by 2. Due to a HW bug, actual length is two
2334 			 * times the expected length.
2335 			 */
2336 			if (swar->packmode_fftbin_size_adj)
2337 				fft_bin_count >>= 1;
2338 			break;
2339 		case SPECTRAL_FFTBIN_SIZE_NO_WAR:
2340 			fallthrough;
2341 		default:
2342 			*fft_bin_size = 1;
2343 			/* No length adjustment */
2344 		}
2345 
2346 		if (rpt_mode == 2 && swar->inband_fftbin_size_adj)
2347 			fft_bin_count >>= 1;
2348 	}
2349 
2350 	return fft_bin_count;
2351 }
2352 
2353 #ifndef OPTIMIZED_SAMP_MESSAGE
2354 /**
2355  * target_if_process_sfft_report_gen3() - Process Search FFT Report for gen3
2356  * @p_fft_report: Pointer to fft report
2357  * @p_sfft: Pointer to search fft report
2358  * @rparams: pointer to report params object
2359  *
2360  * Process Search FFT Report for gen3
2361  *
2362  * Return: Success/Failure
2363  */
2364 static int
2365 target_if_process_sfft_report_gen3(
2366 	struct spectral_phyerr_fft_report_gen3 *p_fft_report,
2367 	struct spectral_search_fft_info_gen3 *p_sfft,
2368 	struct spectral_report_params *rparams)
2369 {
2370 	int32_t peak_sidx = 0;
2371 	int32_t peak_mag;
2372 
2373 	if (!p_fft_report || !p_sfft || !rparams) {
2374 		spectral_err("null params: p_fft_report %pK p_sfft %pK rparams %pK",
2375 			     p_fft_report, p_sfft, rparams);
2376 		return -EINVAL;
2377 	}
2378 
2379 	/*
2380 	 * For simplicity, everything is defined as uint32_t (except one).
2381 	 * Proper code will later use the right sizes.
2382 	 */
2383 	/*
2384 	 * For easy comparison between MDK team and OS team, the MDK script
2385 	 * variable names have been used
2386 	 */
2387 
2388 	/* Populate the Search FFT Info */
2389 	p_sfft->timestamp = p_fft_report->fft_timestamp;
2390 
2391 	p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a,
2392 					       2, 0);
2393 	p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2);
2394 
2395 	switch (rparams->version) {
2396 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
2397 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
2398 						       12, 5);
2399 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17);
2400 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28);
2401 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
2402 						       9, 0);
2403 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
2404 							 8, 9);
2405 		break;
2406 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
2407 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
2408 						       14, 5);
2409 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 19);
2410 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_b, 3, 0);
2411 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
2412 						       9, 3);
2413 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
2414 							 8, 12);
2415 		break;
2416 	default:
2417 		spectral_err_rl("Invalid spectral report format: %d",
2418 				rparams->version);
2419 		return -EINVAL;
2420 	}
2421 
2422 	p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
2423 
2424 	p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
2425 						   8, 0);
2426 	peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8);
2427 	p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
2428 	p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
2429 					     7, 18);
2430 	p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
2431 					     7, 25);
2432 
2433 	return 0;
2434 }
2435 #endif
2436 
2437 /**
2438  * target_if_dump_fft_report_gen3() - Dump FFT Report for gen3
2439  * @spectral: Pointer to Spectral object
2440  * @smode: Spectral scan mode
2441  * @p_fft_report: Pointer to fft report
2442  * @p_sfft: Pointer to search fft report
2443  *
2444  * Dump FFT Report for gen3
2445  *
2446  * Return: void
2447  */
2448 static void
2449 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral,
2450 			enum spectral_scan_mode smode,
2451 			struct spectral_phyerr_fft_report_gen3 *p_fft_report,
2452 			struct spectral_search_fft_info_gen3 *p_sfft)
2453 {
2454 	size_t fft_hdr_length;
2455 	size_t report_len;
2456 	size_t fft_bin_len;
2457 	size_t fft_bin_count;
2458 	size_t fft_bin_size;
2459 	size_t fft_bin_len_inband_tfer = 0;
2460 	uint8_t tag, signature;
2461 
2462 	if (!spectral) {
2463 		spectral_err_rl("spectral pointer is null.");
2464 		return;
2465 	}
2466 
2467 	/* There won't be FFT report/bins in report mode 0, so return */
2468 	if (!spectral->params[smode].ss_rpt_mode)
2469 		return;
2470 
2471 	fft_hdr_length = get_bitfield(
2472 				p_fft_report->fft_hdr_lts,
2473 				SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
2474 				SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
2475 
2476 	tag = get_bitfield(p_fft_report->fft_hdr_lts,
2477 			   SPECTRAL_REPORT_LTS_TAG_SIZE_GEN3,
2478 			   SPECTRAL_REPORT_LTS_TAG_POS_GEN3);
2479 
2480 	signature = get_bitfield(p_fft_report->fft_hdr_lts,
2481 				 SPECTRAL_REPORT_LTS_SIGNATURE_SIZE_GEN3,
2482 				 SPECTRAL_REPORT_LTS_SIGNATURE_POS_GEN3);
2483 
2484 	report_len = (fft_hdr_length + 8);
2485 	fft_bin_len = fft_hdr_length - spectral->rparams.fft_report_hdr_len;
2486 	fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
2487 			fft_bin_len,
2488 			spectral->params[smode].ss_rpt_mode,
2489 			&spectral->len_adj_swar, &fft_bin_size);
2490 
2491 	if ((spectral->params[smode].ss_rpt_mode == 2) &&
2492 	    spectral->len_adj_swar.inband_fftbin_size_adj)
2493 		fft_bin_len_inband_tfer = fft_bin_len >> 1;
2494 
2495 	spectral_debug("Spectral FFT Report");
2496 	spectral_debug("fft_timestamp = 0x%x", p_fft_report->fft_timestamp);
2497 	spectral_debug("fft_hdr_length = %zu(32 bit words)",
2498 		       fft_hdr_length >> 2);
2499 	spectral_debug("fft_hdr_tag = 0x%x", tag);
2500 	spectral_debug("fft_hdr_sig = 0x%x", signature);
2501 
2502 	spectral_debug("Length field in search fft report is %zu(0x%zx) bytes",
2503 		       fft_hdr_length, fft_hdr_length);
2504 	spectral_debug("Total length of search fft report is %zu(0x%zx) bytes",
2505 		       report_len, report_len);
2506 	spectral_debug("Target reported fftbins in report is %zu(0x%zx)",
2507 		       fft_bin_len, fft_bin_len);
2508 
2509 	if ((spectral->params[smode].ss_rpt_mode == 1) &&
2510 	    spectral->len_adj_swar.null_fftbin_adj)
2511 		spectral_debug("WAR: Considering number of FFT bins as 0");
2512 	else if ((spectral->params[smode].ss_rpt_mode == 2) &&
2513 		 spectral->len_adj_swar.inband_fftbin_size_adj) {
2514 		spectral_debug("FW fftbins actually transferred (in-band report mode) %zu(0x%zx)",
2515 			       fft_bin_len_inband_tfer,
2516 			       fft_bin_len_inband_tfer);
2517 	}
2518 
2519 	spectral_debug("Actual number of fftbins in report is %zu(0x%zx)",
2520 		       fft_bin_count, fft_bin_count);
2521 
2522 	spectral_debug("fft_detector_id = %u", p_sfft->fft_detector_id);
2523 	spectral_debug("fft_num = %u", p_sfft->fft_num);
2524 	spectral_debug("fft_radar_check = %u", p_sfft->fft_radar_check);
2525 	spectral_debug("fft_peak_sidx = %d",  p_sfft->fft_peak_sidx);
2526 	spectral_debug("fft_chn_idx = %u", p_sfft->fft_chn_idx);
2527 	spectral_debug("fft_base_pwr_db = %u", p_sfft->fft_base_pwr_db);
2528 	spectral_debug("fft_total_gain_db = %u", p_sfft->fft_total_gain_db);
2529 	spectral_debug("fft_num_str_bins_ib = %u", p_sfft->fft_num_str_bins_ib);
2530 	spectral_debug("fft_peak_mag = %d", p_sfft->fft_peak_mag);
2531 	spectral_debug("fft_avgpwr_db = %u", p_sfft->fft_avgpwr_db);
2532 	spectral_debug("fft_relpwr_db = %u", p_sfft->fft_relpwr_db);
2533 
2534 	if (fft_bin_count > 0) {
2535 		uint8_t *fft_bin_buf;
2536 		uint32_t bytes_copied;
2537 		QDF_STATUS status;
2538 
2539 		fft_bin_buf = qdf_mem_malloc(fft_bin_count);
2540 		if (!fft_bin_buf) {
2541 			spectral_err_rl("memory allocation failed");
2542 			return;
2543 		}
2544 
2545 		status = target_if_spectral_copy_fft_bins(
2546 				spectral, &p_fft_report->buf,
2547 				fft_bin_buf, fft_bin_count, &bytes_copied,
2548 				spectral->params[smode].ss_pwr_format);
2549 		if (QDF_IS_STATUS_ERROR(status)) {
2550 			spectral_err_rl("Unable to populate FFT bins");
2551 			qdf_mem_free(fft_bin_buf);
2552 			return;
2553 		}
2554 
2555 		spectral_debug("FFT bin buffer size = %zu", fft_bin_count);
2556 		spectral_debug("FFT bins:");
2557 		target_if_spectral_hexdump(fft_bin_buf, fft_bin_count);
2558 		qdf_mem_free(fft_bin_buf);
2559 	}
2560 }
2561 #endif
2562 
2563 #ifdef OPTIMIZED_SAMP_MESSAGE
2564 QDF_STATUS
2565 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
2566 				       enum spectral_scan_mode smode,
2567 				       uint8_t detector_id) {
2568 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2569 
2570 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2571 		spectral_err_rl("Invalid Spectral mode %d", smode);
2572 		return QDF_STATUS_E_INVAL;
2573 	}
2574 
2575 	if (!is_ch_width_160_or_80p80(spectral->report_info[smode].sscan_bw)) {
2576 		spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
2577 				spectral->report_info[smode].sscan_bw, smode);
2578 		return QDF_STATUS_E_FAILURE;
2579 	}
2580 
2581 	switch (spectral->state_160mhz_delivery[smode]) {
2582 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
2583 		if (detector_id == SPECTRAL_DETECTOR_ID_0)
2584 			spectral->state_160mhz_delivery[smode] =
2585 				SPECTRAL_REPORT_WAIT_SECONDARY80;
2586 		else {
2587 			status = QDF_STATUS_E_FAILURE;
2588 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
2589 		}
2590 		break;
2591 
2592 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
2593 		if (detector_id == SPECTRAL_DETECTOR_ID_1)
2594 			spectral->state_160mhz_delivery[smode] =
2595 				SPECTRAL_REPORT_WAIT_PRIMARY80;
2596 		else {
2597 			spectral->state_160mhz_delivery[smode] =
2598 				SPECTRAL_REPORT_WAIT_PRIMARY80;
2599 			status = QDF_STATUS_E_FAILURE;
2600 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
2601 		}
2602 		break;
2603 
2604 	default:
2605 		break;
2606 	}
2607 
2608 	return status;
2609 }
2610 #else
2611 QDF_STATUS
2612 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
2613 				       enum spectral_scan_mode smode,
2614 				       uint8_t detector_id) {
2615 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2616 
2617 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2618 		spectral_err_rl("Invalid Spectral mode %d", smode);
2619 		return QDF_STATUS_E_INVAL;
2620 	}
2621 
2622 	if (!is_ch_width_160_or_80p80(spectral->ch_width[smode])) {
2623 		spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
2624 				spectral->ch_width[smode], smode);
2625 		return QDF_STATUS_E_FAILURE;
2626 	}
2627 
2628 	switch (spectral->state_160mhz_delivery[smode]) {
2629 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
2630 		if (detector_id == SPECTRAL_DETECTOR_ID_0)
2631 			spectral->state_160mhz_delivery[smode] =
2632 				SPECTRAL_REPORT_RX_PRIMARY80;
2633 		else {
2634 			status = QDF_STATUS_E_FAILURE;
2635 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
2636 		}
2637 		break;
2638 
2639 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
2640 		if (detector_id == SPECTRAL_DETECTOR_ID_1)
2641 			spectral->state_160mhz_delivery[smode] =
2642 				SPECTRAL_REPORT_RX_SECONDARY80;
2643 		else {
2644 			spectral->state_160mhz_delivery[smode] =
2645 				SPECTRAL_REPORT_WAIT_PRIMARY80;
2646 			status = QDF_STATUS_E_FAILURE;
2647 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
2648 		}
2649 		break;
2650 
2651 	case SPECTRAL_REPORT_RX_SECONDARY80:
2652 		/* We don't care about detector id in this state. */
2653 		reset_160mhz_delivery_state_machine(spectral, smode);
2654 		break;
2655 
2656 	case SPECTRAL_REPORT_RX_PRIMARY80:
2657 		/* We don't care about detector id in this state */
2658 		spectral->state_160mhz_delivery[smode] =
2659 				SPECTRAL_REPORT_WAIT_SECONDARY80;
2660 		break;
2661 
2662 	default:
2663 		break;
2664 	}
2665 
2666 	return status;
2667 }
2668 #endif /* OPTIMIZED_SAMP_MESSAGE */
2669 
2670 #ifdef DIRECT_BUF_RX_ENABLE
2671 /**
2672  * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector
2673  * ID from Spectral summary report
2674  * @data: Pointer to Spectral summary report
2675  * @detector_id: Pointer to detector id
2676  *
2677  * Return: QDF_STATUS
2678  */
2679 static QDF_STATUS
2680 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data,
2681 						    uint8_t *detector_id)
2682 {
2683 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
2684 
2685 	if (!data) {
2686 		spectral_err("Argument(data) is null.");
2687 		return QDF_STATUS_E_NULL_VALUE;
2688 	}
2689 
2690 	psscan_summary_report =
2691 		(struct spectral_sscan_summary_report_gen3 *)data;
2692 
2693 	*detector_id = get_bitfield(
2694 			psscan_summary_report->hdr_a,
2695 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
2696 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
2697 
2698 	return QDF_STATUS_SUCCESS;
2699 }
2700 
2701 #ifndef OPTIMIZED_SAMP_MESSAGE
2702 /**
2703  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
2704  * report
2705  * @data: Pointer to Spectral summary report
2706  * @fields: Pointer to structure to be populated with extracted fields
2707  * @rparams: Pointer to structure with Spectral report params
2708  *
2709  * Consume Spectral summary report for gen3
2710  *
2711  * Return: void
2712  */
2713 static void
2714 target_if_consume_sscan_summary_report_gen3(
2715 				uint8_t *data,
2716 				struct sscan_report_fields_gen3 *fields,
2717 				struct spectral_report_params *rparams) {
2718 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
2719 
2720 	if (!data || !fields || !rparams) {
2721 		spectral_err("null arguments: data %pK, fields %pK, rparams %pK.",
2722 			     data, fields, rparams);
2723 		return;
2724 	}
2725 
2726 	psscan_summary_report =
2727 		(struct spectral_sscan_summary_report_gen3 *)data;
2728 
2729 	fields->sscan_agc_total_gain = get_bitfield(
2730 			psscan_summary_report->hdr_a,
2731 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
2732 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
2733 	fields->inband_pwr_db = get_bitfield(
2734 			psscan_summary_report->hdr_a,
2735 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
2736 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
2737 	fields->sscan_pri80 = get_bitfield(
2738 			psscan_summary_report->hdr_a,
2739 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
2740 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
2741 
2742 	switch (rparams->version) {
2743 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
2744 		fields->sscan_gainchange = get_bitfield(
2745 			psscan_summary_report->hdr_b,
2746 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
2747 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
2748 		break;
2749 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
2750 		fields->sscan_gainchange = get_bitfield(
2751 			psscan_summary_report->hdr_c,
2752 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
2753 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
2754 		break;
2755 	default:
2756 		spectral_err("Invalid spectral report format version: %d.",
2757 			     rparams->version);
2758 		return;
2759 	}
2760 }
2761 #endif
2762 
2763 /**
2764  * target_if_verify_sig_and_tag_gen3() - Verify tag and signature
2765  *                                       of spectral report
2766  * @spectral: Pointer to spectral object
2767  * @data: Pointer to spectral summary report
2768  * @exp_tag: iexpected tag value
2769  *
2770  * Process fft report for gen3
2771  *
2772  * Return: SUCCESS/FAILURE
2773  */
2774 static int
2775 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral,
2776 				  uint8_t *data, uint8_t exp_tag)
2777 {
2778 	uint8_t tag = 0;
2779 	uint8_t signature = 0;
2780 	uint32_t lts;
2781 
2782 	lts = *((uint32_t *)(data + SPECTRAL_PHYERR_HDR_LTS_POS));
2783 	/* Peek into the data to figure out whether
2784 	 *      1) Signature matches the expected value
2785 	 *      2) What is inside the package (TAG ID is used for finding this)
2786 	 */
2787 	tag = get_bitfield(lts,
2788 			   SPECTRAL_REPORT_LTS_TAG_SIZE_GEN3,
2789 			   SPECTRAL_REPORT_LTS_TAG_POS_GEN3);
2790 
2791 	signature = get_bitfield(lts,
2792 				 SPECTRAL_REPORT_LTS_SIGNATURE_SIZE_GEN3,
2793 				 SPECTRAL_REPORT_LTS_SIGNATURE_POS_GEN3);
2794 
2795 
2796 	if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
2797 		spectral->diag_stats.spectral_mismatch++;
2798 		return -EINVAL;
2799 	}
2800 
2801 	if (tag != exp_tag) {
2802 		spectral->diag_stats.spectral_mismatch++;
2803 		return -EINVAL;
2804 	}
2805 
2806 	return 0;
2807 }
2808 
2809 static uint8_t
2810 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)
2811 {
2812 	uint8_t idx;
2813 
2814 	for (idx = 0; idx < DBR_MAX_CHAINS; idx++) {
2815 		if (chainmask & 0x1)
2816 			break;
2817 		chainmask >>= 1;
2818 	}
2819 	return idx;
2820 }
2821 
2822 #ifdef DIRECT_BUF_RX_DEBUG
2823 static void target_if_spectral_check_buffer_poisoning(
2824 	struct target_if_spectral *spectral,
2825 	struct spectral_report *report,
2826 	int num_fft_bins, enum spectral_scan_mode smode)
2827 {
2828 	uint32_t *data;
2829 	size_t len;
2830 	size_t words_to_check =
2831 		sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
2832 	bool poisoned_words_found = false;
2833 
2834 	if (!spectral) {
2835 		spectral_err_rl("Spectral LMAC object is null");
2836 		return;
2837 	}
2838 
2839 	if (!spectral->dbr_buff_debug)
2840 		return;
2841 
2842 	if (!report) {
2843 		spectral_err_rl("Spectral report is null");
2844 		return;
2845 	}
2846 
2847 	/* Add search FFT report */
2848 	if (spectral->params[smode].ss_rpt_mode > 0)
2849 		words_to_check +=
2850 			sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
2851 
2852 	/* Now add the number of FFT bins */
2853 	if (spectral->params[smode].ss_rpt_mode > 1) {
2854 		/* Caller should take care to pass correct number of FFT bins */
2855 		if (spectral->len_adj_swar.fftbin_size_war ==
2856 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
2857 			words_to_check += num_fft_bins;
2858 		else if (spectral->len_adj_swar.fftbin_size_war ==
2859 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE)
2860 			words_to_check += (num_fft_bins >> 1);
2861 	}
2862 
2863 	data = (uint32_t *)report->data;
2864 	for (len = 0; len < words_to_check; ++len) {
2865 		if (*data == MEM_POISON_SIGNATURE) {
2866 			spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK",
2867 				     MEM_POISON_SIGNATURE,
2868 				     (len << 2), report->data);
2869 			poisoned_words_found = true;
2870 			break;
2871 		}
2872 		++data;
2873 	}
2874 
2875 	/* Crash the FW even if one word is poisoned */
2876 	if (poisoned_words_found) {
2877 		spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows",
2878 			     MEM_POISON_SIGNATURE);
2879 		target_if_spectral_hexdump((unsigned char *)report->data,
2880 					   words_to_check << 2);
2881 		spectral_err("Asserting the FW");
2882 		target_if_spectral_fw_hang(spectral);
2883 	}
2884 }
2885 
2886 #ifdef OPTIMIZED_SAMP_MESSAGE
2887 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2888 					 uint8_t *buf, uint32_t current_ts,
2889 					 uint8_t detector_id)
2890 {
2891 	if (!spectral) {
2892 		spectral_err_rl("Spectral LMAC object is null");
2893 		return;
2894 	}
2895 	if (detector_id >= MAX_DETECTORS_PER_PDEV) {
2896 		spectral_err_rl("Spectral detector_id %d exceeds range",
2897 				detector_id);
2898 		return;
2899 	}
2900 
2901 	if (!spectral->dbr_buff_debug)
2902 		return;
2903 
2904 	if (spectral->prev_tstamp[detector_id]) {
2905 		if (current_ts == spectral->prev_tstamp[detector_id]) {
2906 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
2907 				     current_ts, buf);
2908 			target_if_spectral_fw_hang(spectral);
2909 		}
2910 	}
2911 	spectral->prev_tstamp[detector_id] = current_ts;
2912 }
2913 #else
2914 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2915 					 uint8_t *buf, uint32_t current_ts)
2916 {
2917 	if (!spectral) {
2918 		spectral_err_rl("Spectral LMAC object is null");
2919 		return;
2920 	}
2921 
2922 	if (!spectral->dbr_buff_debug)
2923 		return;
2924 
2925 	if (spectral->prev_tstamp) {
2926 		if (current_ts == spectral->prev_tstamp) {
2927 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
2928 				     current_ts, buf);
2929 			target_if_spectral_fw_hang(spectral);
2930 		}
2931 	}
2932 	spectral->prev_tstamp = current_ts;
2933 }
2934 #endif /* OPTIMIZED_SAMP_MESSAGE */
2935 #else
2936 static void target_if_spectral_check_buffer_poisoning(
2937 	struct target_if_spectral *spectral,
2938 	struct spectral_report *report,
2939 	int num_fft_bins, enum spectral_scan_mode smode)
2940 {
2941 }
2942 
2943 #ifdef OPTIMIZED_SAMP_MESSAGE
2944 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2945 					 uint8_t *buf, uint32_t current_ts,
2946 					 uint8_t detector_id)
2947 {
2948 }
2949 #else
2950 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2951 					 uint8_t *buf, uint32_t current_ts)
2952 {
2953 }
2954 #endif /* OPTIMIZED_SAMP_MESSAGE */
2955 #endif
2956 
2957 /**
2958  * target_if_spectral_get_adjusted_timestamp() - Adjust Spectral time
2959  * stamp to account for reset in time stamp due to target reset
2960  * @twar: Spectral time stamp WAR related information
2961  * @raw_timestamp: Spectral time stamp reported by target
2962  * @reset_delay: Reset delay at target
2963  * @smode: Spectral scan mode
2964  * @tstamp: Pointer to adjusted timestamp
2965  *
2966  * Correct time stamp to account for reset in time stamp due to target reset
2967  *
2968  * Return: QDF_STATUS
2969  */
2970 static QDF_STATUS
2971 target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war *twar,
2972 					  uint32_t raw_timestamp,
2973 					  uint32_t reset_delay,
2974 					  enum spectral_scan_mode smode,
2975 					  uint32_t *tstamp)
2976 {
2977 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2978 		spectral_err("Invalid spectral scan mode: %d", smode);
2979 		return QDF_STATUS_E_INVAL;
2980 	}
2981 
2982 	if (reset_delay) {
2983 		enum spectral_scan_mode m =
2984 					SPECTRAL_SCAN_MODE_NORMAL;
2985 
2986 		/* Adjust the offset for all the Spectral modes.
2987 		 * Target will be sending the non zero reset delay for
2988 		 * the first Spectral report after reset. This delay is
2989 		 * common for all the Spectral modes.
2990 		 */
2991 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
2992 			twar->timestamp_war_offset[m] += (reset_delay +
2993 					twar->last_fft_timestamp[m]);
2994 		twar->target_reset_count++;
2995 	}
2996 	twar->last_fft_timestamp[smode] = raw_timestamp;
2997 
2998 	*tstamp = raw_timestamp + twar->timestamp_war_offset[smode];
2999 
3000 	return QDF_STATUS_SUCCESS;
3001 }
3002 
3003 #ifdef BIG_ENDIAN_HOST
3004 QDF_STATUS target_if_byte_swap_spectral_headers_gen3(
3005 	 struct target_if_spectral *spectral,
3006 	 void *data)
3007 {
3008 	int i;
3009 	uint32_t *ptr32;
3010 	size_t words32;
3011 
3012 	if (!data || !spectral) {
3013 		spectral_err_rl("null params: data %pK, spectral %pK.",
3014 				data, spectral);
3015 		return QDF_STATUS_E_NULL_VALUE;
3016 	}
3017 
3018 	ptr32 = (uint32_t *)data;
3019 
3020 	/* Summary Report */
3021 	words32 = sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
3022 	for (i = 0; i < words32; ++i) {
3023 		*ptr32 = qdf_le32_to_cpu(*ptr32);
3024 		++ptr32;
3025 	}
3026 
3027 	/* No need to swap the padding bytes */
3028 	ptr32 += (spectral->rparams.ssummary_padding_bytes >> 2);
3029 
3030 	/* Search FFT Report */
3031 	words32 = sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
3032 	for (i = 0; i < words32; ++i) {
3033 		*ptr32 = qdf_le32_to_cpu(*ptr32);
3034 		++ptr32;
3035 	}
3036 
3037 	return QDF_STATUS_SUCCESS;
3038 }
3039 
3040 QDF_STATUS target_if_byte_swap_spectral_fft_bins_gen3(
3041 	const struct spectral_report_params *rparams,
3042 	void *bin_pwr_data, size_t num_fftbins)
3043 {
3044 	uint16_t dword_idx, num_dwords;
3045 	uint8_t num_bins_per_dword;
3046 	uint32_t *dword_ptr;
3047 
3048 	if (!bin_pwr_data || !rparams) {
3049 		spectral_err_rl("null params, bin_pwr_data %pK, rparams %pK.",
3050 				bin_pwr_data, rparams);
3051 		return QDF_STATUS_E_NULL_VALUE;
3052 	}
3053 
3054 	num_bins_per_dword = SPECTRAL_DWORD_SIZE / rparams->hw_fft_bin_width;
3055 	num_dwords = num_fftbins / num_bins_per_dword;
3056 	dword_ptr = (uint32_t *)bin_pwr_data;
3057 
3058 	for (dword_idx = 0; dword_idx < num_dwords; dword_idx++) {
3059 		/* Read a DWORD, byteswap it, and copy it back */
3060 		*dword_ptr = qdf_le32_to_cpu(*dword_ptr);
3061 		++dword_ptr;
3062 	}
3063 
3064 	return QDF_STATUS_SUCCESS;
3065 }
3066 #endif /* BIG_ENDIAN_HOST */
3067 
3068 #ifdef OPTIMIZED_SAMP_MESSAGE
3069 /**
3070  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
3071  * report
3072  * @data: Pointer to Spectral summary report
3073  * @fields: Pointer to structure to be populated with extracted fields
3074  * @spectral: Pointer to spectral object
3075  *
3076  * Consume Spectral summary report for gen3
3077  *
3078  * Return: QDF_STATUS
3079  */
3080 static QDF_STATUS
3081 target_if_consume_sscan_summary_report_gen3(
3082 				uint8_t **data,
3083 				struct sscan_report_fields_gen3 *fields,
3084 				struct target_if_spectral *spectral)
3085 {
3086 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
3087 	struct spectral_sscan_summary_report_padding_gen3_v2 *padding;
3088 	bool scan_radio_blanking;
3089 	QDF_STATUS ret;
3090 	uint8_t dtr_id;
3091 
3092 	if (!data) {
3093 		spectral_err_rl("Summary report buffer is null");
3094 		return QDF_STATUS_E_NULL_VALUE;
3095 	}
3096 
3097 	if (!fields) {
3098 		spectral_err_rl("Invalid pointer to Summary report fields");
3099 		return QDF_STATUS_E_NULL_VALUE;
3100 	}
3101 
3102 	if (!spectral) {
3103 		spectral_err_rl("Spectral LMAC object is null");
3104 		return QDF_STATUS_E_NULL_VALUE;
3105 	}
3106 
3107 	/* Validate Spectral scan summary report */
3108 	if (target_if_verify_sig_and_tag_gen3(
3109 			spectral, *data,
3110 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
3111 		spectral_err_rl("Wrong tag/sig in sscan summary");
3112 		return QDF_STATUS_E_FAILURE;
3113 	}
3114 
3115 	ret = target_if_get_detector_id_sscan_summary_report_gen3(*data,
3116 								  &dtr_id);
3117 	if (QDF_IS_STATUS_ERROR(ret))
3118 		return QDF_STATUS_E_FAILURE;
3119 
3120 	fields->sscan_detector_id = dtr_id;
3121 	if (fields->sscan_detector_id >=
3122 	    spectral->rparams.num_spectral_detectors) {
3123 		spectral->diag_stats.spectral_invalid_detector_id++;
3124 		spectral_err_rl("Invalid detector id %u, expected is 0 to %u",
3125 				fields->sscan_detector_id,
3126 				spectral->rparams.num_spectral_detectors);
3127 		return QDF_STATUS_E_FAILURE;
3128 	}
3129 
3130 	psscan_summary_report =
3131 		(struct spectral_sscan_summary_report_gen3 *)*data;
3132 
3133 	fields->sscan_agc_total_gain = get_bitfield(
3134 			psscan_summary_report->hdr_a,
3135 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
3136 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
3137 	fields->inband_pwr_db = get_bitfield(
3138 			psscan_summary_report->hdr_a,
3139 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
3140 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
3141 	fields->sscan_pri80 = get_bitfield(
3142 			psscan_summary_report->hdr_a,
3143 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
3144 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
3145 
3146 	switch (spectral->rparams.version) {
3147 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
3148 		fields->sscan_gainchange = get_bitfield(
3149 			psscan_summary_report->hdr_b,
3150 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
3151 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
3152 		break;
3153 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
3154 		fields->sscan_gainchange = get_bitfield(
3155 			psscan_summary_report->hdr_c,
3156 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
3157 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
3158 		break;
3159 	default:
3160 		spectral_err_rl("Invalid spectral version: %d.",
3161 				spectral->rparams.version);
3162 		return QDF_STATUS_E_INVAL;
3163 	}
3164 
3165 	/* Advance buf pointer to the search fft report */
3166 	*data += sizeof(struct spectral_sscan_summary_report_gen3);
3167 
3168 	if (!spectral->rparams.ssummary_padding_bytes)
3169 		return QDF_STATUS_SUCCESS;
3170 
3171 	scan_radio_blanking =
3172 		wlan_pdev_nif_feat_ext_cap_get(spectral->pdev_obj,
3173 					       WLAN_PDEV_FEXT_SCAN_BLANKING_EN);
3174 	padding = (struct spectral_sscan_summary_report_padding_gen3_v2 *)*data;
3175 
3176 	if (scan_radio_blanking) {
3177 		uint32_t blanking_tag;
3178 		uint8_t blanking_tag_size;
3179 		uint8_t blanking_tag_pos;
3180 
3181 		blanking_tag_size =
3182 			SSCAN_SUMMARY_REPORT_PAD_HDR_A_BLANKING_SIZE_GEN3_V2;
3183 		blanking_tag_pos =
3184 			SSCAN_SUMMARY_REPORT_PAD_HDR_A_BLANKING_POS_GEN3_V2;
3185 		blanking_tag = get_bitfield(padding->hdr_a, blanking_tag_size,
3186 					    blanking_tag_pos);
3187 
3188 		if (blanking_tag ==
3189 		    SSCAN_SUMMARY_REPORT_PAD_HDR_A_BLANKING_TAG_GEN3_V2)
3190 			fields->blanking_status = 1;
3191 		else
3192 			fields->blanking_status = 0;
3193 	}
3194 
3195 	*data += sizeof(struct spectral_sscan_summary_report_padding_gen3_v2);
3196 
3197 	return QDF_STATUS_SUCCESS;
3198 }
3199 
3200 /**
3201  * target_if_process_sfft_report_gen3() - Validate and Process Search
3202  * FFT Report for gen3
3203  * @data: Pointer to Spectral FFT report
3204  * @p_sfft: Pointer to search fft report
3205  * @spectral: Pointer to spectral object
3206  * @sscan_detector_id: Spectral detector id extracted from Summary report
3207  * @reset_delay: Time taken for warm reset in usec
3208  *
3209  * Validate and Process Search FFT Report for gen3
3210  *
3211  * Return: Success/Failure
3212  */
3213 static QDF_STATUS
3214 target_if_process_sfft_report_gen3(
3215 	uint8_t *data,
3216 	struct spectral_search_fft_info_gen3 *p_sfft,
3217 	struct target_if_spectral *spectral,
3218 	enum spectral_detector_id sscan_detector_id,
3219 	uint32_t reset_delay)
3220 {
3221 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3222 	int32_t peak_sidx = 0;
3223 	int32_t peak_mag;
3224 	int fft_hdr_length = 0;
3225 	uint32_t tstamp;
3226 	struct target_if_spectral_ops *p_sops;
3227 	enum spectral_scan_mode spectral_mode;
3228 	QDF_STATUS ret;
3229 
3230 	if (!data) {
3231 		spectral_err_rl("FFT report buffer is null");
3232 		return QDF_STATUS_E_NULL_VALUE;
3233 	}
3234 
3235 	if (!p_sfft) {
3236 		spectral_err_rl("Invalid pointer to Search FFT report info");
3237 		return QDF_STATUS_E_NULL_VALUE;
3238 	}
3239 
3240 	if (!spectral) {
3241 		spectral_err_rl("Spectral LMAC object is null");
3242 		return QDF_STATUS_E_NULL_VALUE;
3243 	}
3244 
3245 	/*
3246 	 * For easy comparison between MDK team and OS team, the MDK script
3247 	 * variable names have been used
3248 	 */
3249 
3250 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3251 
3252 	/* Validate Spectral search FFT report */
3253 	if (target_if_verify_sig_and_tag_gen3(
3254 			spectral, data, TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3255 		spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3256 				sscan_detector_id);
3257 		return QDF_STATUS_E_FAILURE;
3258 	}
3259 
3260 	p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3261 
3262 	fft_hdr_length = get_bitfield(
3263 			p_fft_report->fft_hdr_lts,
3264 			SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3265 			SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3266 	if (fft_hdr_length < 16) {
3267 		spectral_err("Wrong TLV length %u, detector id = %d",
3268 			     fft_hdr_length, sscan_detector_id);
3269 		return QDF_STATUS_E_FAILURE;
3270 	}
3271 
3272 	p_sfft->fft_detector_id = get_bitfield(
3273 					p_fft_report->hdr_a,
3274 					FFT_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
3275 					FFT_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
3276 
3277 	/* It is expected to have same detector id for
3278 	 * summary and fft report
3279 	 */
3280 	if (sscan_detector_id != p_sfft->fft_detector_id) {
3281 		spectral_err_rl("Different detid in ssummary(%u) and sfft(%u)",
3282 				sscan_detector_id, p_sfft->fft_detector_id);
3283 		return QDF_STATUS_E_FAILURE;
3284 	}
3285 
3286 	if (p_sfft->fft_detector_id >
3287 				spectral->rparams.num_spectral_detectors) {
3288 		spectral->diag_stats.spectral_invalid_detector_id++;
3289 		spectral_err("Invalid detector id %u, expected is 0 to %u",
3290 			     p_sfft->fft_detector_id,
3291 			     spectral->rparams.num_spectral_detectors);
3292 		return QDF_STATUS_E_FAILURE;
3293 	}
3294 
3295 	spectral_mode = target_if_get_spectral_mode(p_sfft->fft_detector_id,
3296 						    &spectral->rparams);
3297 	if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3298 		spectral_err_rl("No valid Spectral mode for detector id %u",
3299 				p_sfft->fft_detector_id);
3300 		return QDF_STATUS_E_FAILURE;
3301 	}
3302 
3303 	/* Populate the Search FFT Info */
3304 	p_sfft->timestamp = p_fft_report->fft_timestamp;
3305 	p_sfft->last_raw_timestamp = spectral->timestamp_war.
3306 					last_fft_timestamp[spectral_mode];
3307 	ret = target_if_spectral_get_adjusted_timestamp(
3308 						&spectral->timestamp_war,
3309 						p_sfft->timestamp,
3310 						reset_delay,
3311 						spectral_mode,
3312 						&tstamp);
3313 
3314 	if (QDF_IS_STATUS_ERROR(ret))
3315 		return QDF_STATUS_E_FAILURE;
3316 
3317 	p_sfft->adjusted_timestamp =  tstamp;
3318 	/* Timestamp verification */
3319 	target_if_spectral_verify_ts(spectral, data,
3320 				     p_sfft->adjusted_timestamp,
3321 				     p_sfft->fft_detector_id);
3322 
3323 
3324 	p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a,
3325 				       FFT_REPORT_HDR_A_FFT_NUM_SIZE_GEN3,
3326 				       FFT_REPORT_HDR_A_FFT_NUM_POS_GEN3);
3327 
3328 	switch (spectral->rparams.version) {
3329 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
3330 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
3331 				FFT_REPORT_HDR_A_RADAR_CHECK_SIZE_GEN3_V1,
3332 				FFT_REPORT_HDR_A_RADAR_CHECK_POS_GEN3_V1);
3333 		peak_sidx = get_bitfield(
3334 				p_fft_report->hdr_a,
3335 				FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V1,
3336 				FFT_REPORT_HDR_A_PEAK_INDEX_POS_GEN3_V1);
3337 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a,
3338 				FFT_REPORT_HDR_A_CHAIN_INDEX_SIZE_GEN3_V1,
3339 				FFT_REPORT_HDR_A_CHAIN_INDEX_POS_GEN3_V1);
3340 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
3341 				FFT_REPORT_HDR_B_BASE_PWR_SIZE_GEN3_V1,
3342 				FFT_REPORT_HDR_B_BASE_PWR_POS_GEN3_V1);
3343 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
3344 				FFT_REPORT_HDR_B_TOTAL_GAIN_SIZE_GEN3_V1,
3345 				FFT_REPORT_HDR_B_TOTAL_GAIN_POS_GEN3_V1);
3346 		break;
3347 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
3348 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
3349 				FFT_REPORT_HDR_A_RADAR_CHECK_SIZE_GEN3_V2,
3350 				FFT_REPORT_HDR_A_RADAR_CHECK_POS_GEN3_V2);
3351 		peak_sidx = get_bitfield(
3352 				p_fft_report->hdr_a,
3353 				FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V2,
3354 				FFT_REPORT_HDR_A_PEAK_INDEX_POS_GEN3_V2);
3355 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_b,
3356 				FFT_REPORT_HDR_B_CHAIN_INDEX_SIZE_GEN3_V2,
3357 				FFT_REPORT_HDR_B_CHAIN_INDEX_POS_GEN3_V2);
3358 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
3359 				FFT_REPORT_HDR_B_BASE_PWR_SIZE_GEN3_V2,
3360 				FFT_REPORT_HDR_B_BASE_PWR_POS_GEN3_V2);
3361 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
3362 				FFT_REPORT_HDR_B_TOTAL_GAIN_SIZE_GEN3_V2,
3363 				FFT_REPORT_HDR_B_TOTAL_GAIN_POS_GEN3_V2);
3364 		break;
3365 	default:
3366 		spectral_err_rl("Invalid spectral version: %d.",
3367 				spectral->rparams.version);
3368 		return QDF_STATUS_E_INVAL;
3369 	}
3370 
3371 	p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx,
3372 				FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V1);
3373 
3374 	p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
3375 				FFT_REPORT_HDR_C_NUM_STRONG_BINS_SIZE_GEN3,
3376 				FFT_REPORT_HDR_C_NUM_STRONG_BINS_POS_GEN3);
3377 	peak_mag = get_bitfield(p_fft_report->hdr_c,
3378 				FFT_REPORT_HDR_C_PEAK_MAGNITUDE_SIZE_GEN3,
3379 				FFT_REPORT_HDR_C_PEAK_MAGNITUDE_POS_GEN3);
3380 	p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag,
3381 				FFT_REPORT_HDR_C_PEAK_MAGNITUDE_SIZE_GEN3);
3382 	p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
3383 				FFT_REPORT_HDR_C_AVG_PWR_SIZE_GEN3,
3384 				FFT_REPORT_HDR_C_AVG_PWR_POS_GEN3);
3385 	p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
3386 				FFT_REPORT_HDR_C_RELATIVE_PWR_SIZE_GEN3,
3387 				FFT_REPORT_HDR_C_RELATIVE_PWR_POS_GEN3);
3388 
3389 	p_sfft->fft_bin_count =
3390 		target_if_spectral_get_bin_count_after_len_adj(
3391 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3392 			spectral->params[spectral_mode].ss_rpt_mode,
3393 			&spectral->len_adj_swar,
3394 			(size_t *)&p_sfft->fft_bin_size);
3395 
3396 	p_sfft->bin_pwr_data = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
3397 
3398 	/* Apply byte-swap on the FFT bins.
3399 	 * NOTE: Until this point, bytes of the FFT bins could be in
3400 	 *       reverse order on a big-endian machine. If the consumers
3401 	 *       of FFT bins expects bytes in the correct order,
3402 	 *       they should use them only after this point.
3403 	 */
3404 	if (p_sops->byte_swap_fft_bins) {
3405 		ret = p_sops->byte_swap_fft_bins(&spectral->rparams,
3406 						 &p_sfft->bin_pwr_data,
3407 						 p_sfft->fft_bin_count);
3408 		if (QDF_IS_STATUS_ERROR(ret)) {
3409 			spectral_err_rl("Byte-swap on the FFT bins failed");
3410 			return QDF_STATUS_E_FAILURE;
3411 		}
3412 	}
3413 
3414 	return QDF_STATUS_SUCCESS;
3415 }
3416 
3417 /**
3418  * target_if_spectral_populate_samp_params_gen3() - Populate the SAMP params
3419  * for gen3. SAMP params are to be used for populating SAMP msg.
3420  * @spectral: Pointer to spectral object
3421  * @p_sfft: Fields extracted from FFT report
3422  * @sscan_fields: Fields extracted from Summary report
3423  * @report: Pointer to spectral report
3424  * @params: Pointer to Spectral SAMP message fields to be populated
3425  *
3426  * Populate the SAMP params for gen3, which will be used to populate SAMP msg.
3427  *
3428  * Return: Success/Failure
3429  */
3430 static QDF_STATUS
3431 target_if_spectral_populate_samp_params_gen3(
3432 		struct target_if_spectral *spectral,
3433 		struct spectral_search_fft_info_gen3 *p_sfft,
3434 		struct sscan_report_fields_gen3 *sscan_fields,
3435 		struct spectral_report *report,
3436 		struct target_if_samp_msg_params *params)
3437 {
3438 	enum spectral_scan_mode spectral_mode;
3439 	uint8_t chn_idx_lowest_enabled;
3440 	struct wlan_objmgr_vdev *vdev;
3441 	uint8_t vdev_rxchainmask;
3442 
3443 	if (!p_sfft) {
3444 		spectral_err_rl("Invalid pointer to Search FFT report info");
3445 		return QDF_STATUS_E_NULL_VALUE;
3446 	}
3447 	if (!spectral) {
3448 		spectral_err_rl("Spectral LMAC object is null");
3449 		return QDF_STATUS_E_NULL_VALUE;
3450 	}
3451 	if (!sscan_fields) {
3452 		spectral_err_rl("Invalid pointer to Summary report fields");
3453 		return QDF_STATUS_E_NULL_VALUE;
3454 	}
3455 	if (!report) {
3456 		spectral_err_rl("Spectral report is null");
3457 		return QDF_STATUS_E_NULL_VALUE;
3458 	}
3459 	if (!params) {
3460 		spectral_err_rl("SAMP msg params structure is null");
3461 		return QDF_STATUS_E_NULL_VALUE;
3462 	}
3463 
3464 	/* RSSI is in 1/2 dBm steps, Convert it to dBm scale */
3465 	params->rssi = (sscan_fields->inband_pwr_db) >> 1;
3466 
3467 	params->hw_detector_id = p_sfft->fft_detector_id;
3468 	params->raw_timestamp = p_sfft->timestamp;
3469 	params->last_raw_timestamp = p_sfft->last_raw_timestamp;
3470 	params->timestamp = p_sfft->adjusted_timestamp;
3471 	params->reset_delay = report->reset_delay;
3472 
3473 	params->max_mag = p_sfft->fft_peak_mag;
3474 
3475 	spectral_mode = target_if_get_spectral_mode(params->hw_detector_id,
3476 						    &spectral->rparams);
3477 	vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3478 	if (!vdev) {
3479 		spectral_debug("First vdev is NULL");
3480 		return QDF_STATUS_E_FAILURE;
3481 	}
3482 	vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3483 	if (vdev_rxchainmask == 0) {
3484 		spectral_err("Vdev rxchainmask is zero.");
3485 		return QDF_STATUS_E_FAILURE;
3486 	}
3487 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3488 
3489 	chn_idx_lowest_enabled =
3490 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3491 	if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3492 		spectral_err("Invalid chain index, detector id = %u",
3493 			     params->hw_detector_id);
3494 		return QDF_STATUS_E_FAILURE;
3495 	}
3496 	params->noise_floor = report->noisefloor[chn_idx_lowest_enabled];
3497 	params->agc_total_gain = sscan_fields->sscan_agc_total_gain;
3498 	params->gainchange = sscan_fields->sscan_gainchange;
3499 	params->blanking_status = sscan_fields->blanking_status;
3500 	params->pri80ind = sscan_fields->sscan_pri80;
3501 
3502 	params->bin_pwr_data = p_sfft->bin_pwr_data;
3503 
3504 	return QDF_STATUS_SUCCESS;
3505 }
3506 
3507 int
3508 target_if_consume_spectral_report_gen3(
3509 	 struct target_if_spectral *spectral,
3510 	 struct spectral_report *report)
3511 {
3512 	/*
3513 	 * XXX : The classifier do not use all the members of the SAMP
3514 	 *       message data format.
3515 	 *       The classifier only depends upon the following parameters
3516 	 *
3517 	 *          1. Frequency
3518 	 *          2. Spectral RSSI
3519 	 *          3. Bin Power Count
3520 	 *          4. Bin Power values
3521 	 *          5. Spectral Timestamp
3522 	 *          6. MAC Address
3523 	 *
3524 	 *       This function processes the Spectral summary and FFT reports
3525 	 *       and passes the processed information
3526 	 *       target_if_spectral_fill_samp_msg()
3527 	 *       to prepare fully formatted Spectral SAMP message
3528 	 *
3529 	 *       XXX : Need to verify
3530 	 *          1. Order of FFT bin values
3531 	 *
3532 	 */
3533 	struct target_if_samp_msg_params params = {0};
3534 	struct spectral_search_fft_info_gen3 search_fft_info;
3535 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
3536 	struct target_if_spectral_ops *p_sops;
3537 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3538 	uint8_t *data;
3539 	struct sscan_report_fields_gen3 sscan_report_fields = {0};
3540 	QDF_STATUS ret;
3541 	enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
3542 	bool finite_scan = false;
3543 	int det = 0;
3544 	struct sscan_detector_list *det_list;
3545 	struct spectral_data_stats *spectral_dp_stats;
3546 	bool print_fail_msg = true;
3547 
3548 	if (!spectral) {
3549 		spectral_err_rl("Spectral LMAC object is null");
3550 		print_fail_msg = false;
3551 		goto fail;
3552 	}
3553 
3554 	qdf_spin_lock_bh(&spectral->spectral_lock);
3555 	spectral_dp_stats = &spectral->data_stats;
3556 	spectral_dp_stats->consume_spectral_calls++;
3557 
3558 	if (!report) {
3559 		spectral_err_rl("Spectral report is null");
3560 		print_fail_msg = false;
3561 		goto fail_unlock;
3562 	}
3563 
3564 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3565 	data = report->data;
3566 
3567 	/* Apply byte-swap on the headers */
3568 	if (p_sops->byte_swap_headers) {
3569 		ret = p_sops->byte_swap_headers(spectral, data);
3570 		if (QDF_IS_STATUS_ERROR(ret)) {
3571 			spectral_err_rl("Byte-swap on Spectral headers failed");
3572 			goto fail_unlock;
3573 		}
3574 	}
3575 
3576 	/* Validate and Process Spectral scan summary report */
3577 	ret = target_if_consume_sscan_summary_report_gen3(&data,
3578 							  &sscan_report_fields,
3579 							  spectral);
3580 	if (QDF_IS_STATUS_ERROR(ret)) {
3581 		spectral_err_rl("Failed to process Spectral summary report");
3582 		goto fail_unlock;
3583 	}
3584 
3585 	spectral_mode = target_if_get_spectral_mode(
3586 					sscan_report_fields.sscan_detector_id,
3587 					&spectral->rparams);
3588 	if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3589 		spectral_err_rl("No valid Spectral mode for detector id %u",
3590 				sscan_report_fields.sscan_detector_id);
3591 		goto fail_unlock;
3592 	}
3593 
3594 	/* Drop the sample if Spectral is not active for the current mode */
3595 	if (!p_sops->is_spectral_active(spectral, spectral_mode)) {
3596 		spectral_info_rl("Spectral scan is not active");
3597 		print_fail_msg = false;
3598 		goto fail_unlock;
3599 	}
3600 
3601 	/* Validate and Process the search FFT report */
3602 	ret = target_if_process_sfft_report_gen3(
3603 					data, p_sfft,
3604 					spectral,
3605 					sscan_report_fields.sscan_detector_id,
3606 					report->reset_delay);
3607 	if (QDF_IS_STATUS_ERROR(ret)) {
3608 		spectral_err_rl("Failed to process search FFT report");
3609 		goto fail_unlock;
3610 	}
3611 
3612 	qdf_spin_lock_bh(&spectral->detector_list_lock);
3613 	det_list = &spectral->detector_list[spectral_mode]
3614 			[spectral->report_info[spectral_mode].sscan_bw];
3615 	for (det = 0; det < det_list->num_detectors; det++) {
3616 		if (p_sfft->fft_detector_id == det_list->detectors[det])
3617 			break;
3618 		if (det == det_list->num_detectors - 1) {
3619 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
3620 			spectral_info("Incorrect det id %d for given scan mode and channel width",
3621 				      p_sfft->fft_detector_id);
3622 			print_fail_msg = false;
3623 			goto fail_unlock;
3624 		}
3625 	}
3626 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
3627 
3628 	ret = target_if_update_session_info_from_report_ctx(
3629 						spectral,
3630 						p_sfft->fft_bin_size,
3631 						report->cfreq1, report->cfreq2,
3632 						spectral_mode);
3633 	if (QDF_IS_STATUS_ERROR(ret)) {
3634 		spectral_err_rl("Failed to update per-session info");
3635 		goto fail_unlock;
3636 	}
3637 
3638 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
3639 	/* Check FFT report are in order for 160 MHz and 80p80 */
3640 	if (is_ch_width_160_or_80p80(
3641 	    spectral->report_info[spectral_mode].sscan_bw) &&
3642 	    spectral->rparams.fragmentation_160[spectral_mode]) {
3643 		ret = target_if_160mhz_delivery_state_change(
3644 				spectral, spectral_mode,
3645 				p_sfft->fft_detector_id);
3646 		if (ret != QDF_STATUS_SUCCESS) {
3647 			qdf_spin_unlock_bh(
3648 					&spectral->session_report_info_lock);
3649 			goto fail_unlock;
3650 		}
3651 	}
3652 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
3653 
3654 	p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3655 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
3656 		target_if_dump_fft_report_gen3(spectral, spectral_mode,
3657 					       p_fft_report, p_sfft);
3658 
3659 	target_if_spectral_check_buffer_poisoning(spectral, report,
3660 						  p_sfft->fft_bin_count,
3661 						  spectral_mode);
3662 
3663 	/* Populate SAMP params */
3664 	ret = target_if_spectral_populate_samp_params_gen3(
3665 							spectral, p_sfft,
3666 							&sscan_report_fields,
3667 							report, &params);
3668 	if (QDF_IS_STATUS_ERROR(ret)) {
3669 		spectral_err_rl("Failed to populate SAMP params");
3670 		goto fail_unlock;
3671 	}
3672 
3673 	/* Fill SAMP message */
3674 	ret = target_if_spectral_fill_samp_msg(spectral, &params);
3675 	if (QDF_IS_STATUS_ERROR(ret)) {
3676 		spectral_err_rl("Failed to fill the SAMP msg");
3677 		goto fail_unlock;
3678 	}
3679 
3680 	qdf_spin_unlock_bh(&spectral->spectral_lock);
3681 	ret = target_if_spectral_is_finite_scan(spectral, spectral_mode,
3682 						&finite_scan);
3683 	if (QDF_IS_STATUS_ERROR(ret)) {
3684 		spectral_err_rl("Failed to check scan is finite");
3685 		goto fail;
3686 	}
3687 
3688 	if (finite_scan) {
3689 		ret = target_if_spectral_finite_scan_update(spectral,
3690 							    spectral_mode);
3691 		if (QDF_IS_STATUS_ERROR(ret)) {
3692 			spectral_err_rl("Failed to update scan count");
3693 			goto fail;
3694 		}
3695 	}
3696 
3697 	return 0;
3698 fail_unlock:
3699 	qdf_spin_unlock_bh(&spectral->spectral_lock);
3700 fail:
3701 	if (print_fail_msg)
3702 		spectral_err_rl("Error while processing Spectral report");
3703 
3704 	if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
3705 		reset_160mhz_delivery_state_machine(spectral, spectral_mode);
3706 	return -EPERM;
3707 }
3708 
3709 #else
3710 int
3711 target_if_consume_spectral_report_gen3(
3712 	 struct target_if_spectral *spectral,
3713 	 struct spectral_report *report)
3714 {
3715 	/*
3716 	 * XXX : The classifier do not use all the members of the SAMP
3717 	 *       message data format.
3718 	 *       The classifier only depends upon the following parameters
3719 	 *
3720 	 *          1. Frequency (freq, msg->freq)
3721 	 *          2. Spectral RSSI (spectral_rssi,
3722 	 *          msg->samp_data.spectral_rssi)
3723 	 *          3. Bin Power Count (bin_pwr_count,
3724 	 *          msg->samp_data.bin_pwr_count)
3725 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
3726 	 *          5. Spectral Timestamp (spectral_tstamp,
3727 	 *          msg->samp_data.spectral_tstamp)
3728 	 *          6. MAC Address (macaddr, msg->macaddr)
3729 	 *
3730 	 *       This function prepares the params structure and populates it
3731 	 *       with
3732 	 *       relevant values, this is in turn passed to
3733 	 *       spectral_create_samp_msg()
3734 	 *       to prepare fully formatted Spectral SAMP message
3735 	 *
3736 	 *       XXX : Need to verify
3737 	 *          1. Order of FFT bin values
3738 	 *
3739 	 */
3740 	struct target_if_samp_msg_params params = {0};
3741 	struct spectral_search_fft_info_gen3 search_fft_info;
3742 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
3743 	int8_t chn_idx_lowest_enabled  = 0;
3744 	int fft_hdr_length = 0;
3745 	int report_len = 0;
3746 	size_t fft_bin_count;
3747 	size_t fft_bin_size;
3748 	struct target_if_spectral_ops *p_sops =
3749 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
3750 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3751 	int8_t rssi;
3752 	uint8_t *data = report->data;
3753 	struct wlan_objmgr_vdev *vdev;
3754 	uint8_t vdev_rxchainmask;
3755 	struct sscan_report_fields_gen3 sscan_report_fields = {0};
3756 	enum spectral_detector_id detector_id;
3757 	uint8_t dtr_id;
3758 	QDF_STATUS ret;
3759 	enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
3760 	uint8_t *temp;
3761 	bool finite_scan = false;
3762 	uint32_t tstamp;
3763 
3764 	/* Apply byte-swap on the headers */
3765 	if (p_sops->byte_swap_headers) {
3766 		ret = p_sops->byte_swap_headers(spectral, data);
3767 		if (QDF_IS_STATUS_ERROR(ret)) {
3768 			spectral_err_rl("Byte-swap on Spectral headers failed");
3769 			goto fail;
3770 		}
3771 	}
3772 
3773 	/* Process Spectral scan summary report */
3774 	if (target_if_verify_sig_and_tag_gen3(
3775 			spectral, data,
3776 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
3777 		spectral_err_rl("Wrong tag/sig in sscan summary");
3778 		goto fail;
3779 	}
3780 
3781 	ret = target_if_get_detector_id_sscan_summary_report_gen3(data,
3782 								  &dtr_id);
3783 	if (QDF_IS_STATUS_ERROR(ret))
3784 		goto fail;
3785 
3786 	detector_id = dtr_id;
3787 	if (detector_id >= spectral->rparams.num_spectral_detectors) {
3788 		spectral->diag_stats.spectral_invalid_detector_id++;
3789 		spectral_err("Invalid detector id %u, expected is 0/1/2",
3790 			     detector_id);
3791 		goto fail;
3792 	}
3793 
3794 	spectral_mode = target_if_get_spectral_mode(detector_id,
3795 						    &spectral->rparams);
3796 	if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3797 		spectral_err_rl("No valid Spectral mode for detector id %u",
3798 				detector_id);
3799 		goto fail;
3800 	}
3801 
3802 	/* Drop the sample if Spectral is not active for the current mode */
3803 	if (!p_sops->is_spectral_active(spectral, spectral_mode)) {
3804 		spectral_info_rl("Spectral scan is not active");
3805 		goto fail_no_print;
3806 	}
3807 
3808 	ret = target_if_spectral_is_finite_scan(spectral, spectral_mode,
3809 						&finite_scan);
3810 	if (QDF_IS_STATUS_ERROR(ret)) {
3811 		spectral_err_rl("Failed to check scan is finite");
3812 		goto fail;
3813 	}
3814 
3815 	if (finite_scan) {
3816 		ret = target_if_spectral_finite_scan_update(spectral,
3817 							    spectral_mode);
3818 		if (QDF_IS_STATUS_ERROR(ret)) {
3819 			spectral_err_rl("Failed to update scan count");
3820 			goto fail;
3821 		}
3822 	}
3823 
3824 	target_if_consume_sscan_summary_report_gen3(data, &sscan_report_fields,
3825 						    &spectral->rparams);
3826 	/* Advance buf pointer to the search fft report */
3827 	data += sizeof(struct spectral_sscan_summary_report_gen3);
3828 	data += spectral->rparams.ssummary_padding_bytes;
3829 	params.vhtop_ch_freq_seg1 = report->cfreq1;
3830 	params.vhtop_ch_freq_seg2 = report->cfreq2;
3831 
3832 	if (is_primaryseg_expected(spectral, spectral_mode)) {
3833 		/* RSSI is in 1/2 dBm steps, Convert it to dBm scale */
3834 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
3835 		params.agc_total_gain =
3836 			sscan_report_fields.sscan_agc_total_gain;
3837 		params.gainchange = sscan_report_fields.sscan_gainchange;
3838 		params.pri80ind = sscan_report_fields.sscan_pri80;
3839 
3840 		/* Process Spectral search FFT report */
3841 		if (target_if_verify_sig_and_tag_gen3(
3842 				spectral, data,
3843 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3844 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3845 					detector_id);
3846 			goto fail;
3847 		}
3848 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3849 		fft_hdr_length = get_bitfield(
3850 				p_fft_report->fft_hdr_lts,
3851 				SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3852 				SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3853 		if (fft_hdr_length < 16) {
3854 			spectral_err("Wrong TLV length %u, detector id = %d",
3855 				     fft_hdr_length, detector_id);
3856 			goto fail;
3857 		}
3858 
3859 		report_len = (fft_hdr_length + 8);
3860 
3861 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft,
3862 						   &spectral->rparams);
3863 		/* It is expected to have same detector id for
3864 		 * summary and fft report
3865 		 */
3866 		if (detector_id != p_sfft->fft_detector_id) {
3867 			spectral_err_rl
3868 				("Different detid in ssummary(%u) and sfft(%u)",
3869 				 detector_id, p_sfft->fft_detector_id);
3870 			goto fail;
3871 		}
3872 
3873 		if (detector_id > spectral->rparams.num_spectral_detectors) {
3874 			spectral->diag_stats.spectral_invalid_detector_id++;
3875 			spectral_err("Invalid detector id %u, expected is 0/2",
3876 				     detector_id);
3877 			goto fail;
3878 		}
3879 		params.smode = spectral_mode;
3880 
3881 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
3882 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3883 			spectral->params[spectral_mode].ss_rpt_mode,
3884 			&spectral->len_adj_swar, &fft_bin_size);
3885 
3886 		params.last_raw_timestamp = spectral->timestamp_war.
3887 				last_fft_timestamp[spectral_mode];
3888 		params.reset_delay = report->reset_delay;
3889 		params.raw_timestamp = p_sfft->timestamp;
3890 		ret = target_if_spectral_get_adjusted_timestamp(
3891 					&spectral->timestamp_war,
3892 					p_sfft->timestamp, report->reset_delay,
3893 					spectral_mode, &tstamp);
3894 		if (QDF_IS_STATUS_ERROR(ret))
3895 			goto fail;
3896 
3897 		params.tstamp = tstamp;
3898 		params.timestamp_war_offset = spectral->timestamp_war.
3899 				timestamp_war_offset[spectral_mode];
3900 		params.target_reset_count = spectral->timestamp_war.
3901 				target_reset_count;
3902 
3903 		/* Take care of state transitions for 160 MHz and 80p80 */
3904 		if (is_ch_width_160_or_80p80(spectral->ch_width
3905 		    [spectral_mode]) && spectral->rparams.
3906 		    fragmentation_160[spectral_mode]) {
3907 			ret = target_if_160mhz_delivery_state_change(
3908 					spectral, spectral_mode,
3909 					detector_id);
3910 			if (ret != QDF_STATUS_SUCCESS)
3911 				goto fail;
3912 		}
3913 
3914 		params.rssi         = rssi;
3915 
3916 		vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3917 		if (!vdev) {
3918 			spectral_debug("First vdev is NULL");
3919 			reset_160mhz_delivery_state_machine(
3920 						spectral, spectral_mode);
3921 			return -EPERM;
3922 		}
3923 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3924 		if (vdev_rxchainmask == 0) {
3925 			spectral_err("Vdev rxchainmask is zero.");
3926 			goto fail;
3927 		}
3928 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3929 
3930 		chn_idx_lowest_enabled =
3931 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3932 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3933 			spectral_err("Invalid chain index, detector id = %u",
3934 				     detector_id);
3935 			goto fail;
3936 		}
3937 
3938 		params.max_mag  = p_sfft->fft_peak_mag;
3939 
3940 		params.freq = p_sops->get_current_channel(spectral,
3941 							  spectral_mode);
3942 		params.agile_freq1 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3943 				     ss_frequency.cfreq1;
3944 		params.agile_freq2 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3945 				     ss_frequency.cfreq2;
3946 		params.noise_floor =
3947 			report->noisefloor[chn_idx_lowest_enabled];
3948 		temp = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
3949 		if (is_ch_width_160_or_80p80(spectral->ch_width
3950 		    [spectral_mode]) && !spectral->rparams.
3951 		    fragmentation_160[spectral_mode]) {
3952 			struct wlan_objmgr_psoc *psoc;
3953 			struct spectral_fft_bin_markers_160_165mhz *marker;
3954 
3955 			if (!spectral->pdev_obj) {
3956 				spectral_err("pdev is null");
3957 				goto fail;
3958 			}
3959 			psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
3960 			if (!psoc) {
3961 				spectral_err("psoc is null");
3962 				goto fail;
3963 			}
3964 			params.agc_total_gain_sec80 =
3965 				sscan_report_fields.sscan_agc_total_gain;
3966 			params.gainchange_sec80 =
3967 					sscan_report_fields.sscan_gainchange;
3968 			params.raw_timestamp_sec80 = p_sfft->timestamp;
3969 			params.rssi_sec80 = rssi;
3970 			params.noise_floor_sec80    =
3971 				report->noisefloor[chn_idx_lowest_enabled];
3972 			params.max_mag_sec80        = p_sfft->fft_peak_mag;
3973 			params.datalen = fft_hdr_length * 2;
3974 			params.datalen_sec80 = fft_hdr_length * 2;
3975 
3976 			marker = &spectral->rparams.marker[spectral_mode];
3977 			if (!marker->is_valid) {
3978 				/* update stats */
3979 				goto fail_no_print;
3980 			}
3981 			params.bin_pwr_data = temp +
3982 				marker->start_pri80 * fft_bin_size;
3983 			params.pwr_count = marker->num_pri80;
3984 			params.bin_pwr_data_sec80 = temp +
3985 				marker->start_sec80 * fft_bin_size;
3986 			params.pwr_count_sec80 = marker->num_sec80;
3987 			if (spectral->ch_width[spectral_mode] ==
3988 			    CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
3989 			    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
3990 				params.bin_pwr_data_5mhz = temp +
3991 					marker->start_5mhz * fft_bin_size;
3992 				params.pwr_count_5mhz = marker->num_5mhz;
3993 			}
3994 		} else {
3995 			params.bin_pwr_data = temp;
3996 			params.pwr_count = fft_bin_count;
3997 			params.datalen = (fft_hdr_length * 4);
3998 		}
3999 
4000 		/* Apply byte-swap on the FFT bins.
4001 		 * NOTE: Until this point, bytes of the FFT bins could be in
4002 		 *       reverse order on a big-endian machine. If the consumers
4003 		 *       of FFT bins expects bytes in the correct order,
4004 		 *       they should use them only after this point.
4005 		 */
4006 		if (p_sops->byte_swap_fft_bins) {
4007 			ret = p_sops->byte_swap_fft_bins(
4008 						&spectral->rparams,
4009 						temp, fft_bin_count);
4010 			if (QDF_IS_STATUS_ERROR(ret)) {
4011 				spectral_err_rl("Byte-swap on the FFT bins failed");
4012 				goto fail;
4013 			}
4014 		}
4015 
4016 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
4017 			target_if_dump_fft_report_gen3(spectral, spectral_mode,
4018 						       p_fft_report, p_sfft);
4019 
4020 		target_if_spectral_verify_ts(spectral, report->data,
4021 					     params.tstamp);
4022 	} else if (is_secondaryseg_expected(spectral, spectral_mode)) {
4023 		/* RSSI is in 1/2 dBm steps, Convert it to dBm scale */
4024 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
4025 		params.agc_total_gain_sec80 =
4026 			sscan_report_fields.sscan_agc_total_gain;
4027 		params.gainchange_sec80 = sscan_report_fields.sscan_gainchange;
4028 		params.pri80ind_sec80 = sscan_report_fields.sscan_pri80;
4029 
4030 		/* Process Spectral search FFT report */
4031 		if (target_if_verify_sig_and_tag_gen3(
4032 				spectral, data,
4033 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
4034 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
4035 					detector_id);
4036 			goto fail;
4037 		}
4038 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
4039 		fft_hdr_length = get_bitfield(
4040 				p_fft_report->fft_hdr_lts,
4041 				SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
4042 				SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
4043 		if (fft_hdr_length < 16) {
4044 			spectral_err("Wrong TLV length %u, detector id = %u",
4045 				     fft_hdr_length, detector_id);
4046 			goto fail;
4047 		}
4048 
4049 		report_len     = (fft_hdr_length + 8);
4050 
4051 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft,
4052 						   &spectral->rparams);
4053 		/* It is expected to have same detector id for
4054 		 * summary and fft report
4055 		 */
4056 		if (detector_id != p_sfft->fft_detector_id) {
4057 			spectral_err_rl
4058 				("Different detid in ssummary(%u) and sfft(%u)",
4059 				 detector_id, p_sfft->fft_detector_id);
4060 			goto fail;
4061 		}
4062 
4063 		if (detector_id > spectral->rparams.num_spectral_detectors) {
4064 			spectral->diag_stats.spectral_invalid_detector_id++;
4065 			spectral_err("Invalid detector id %u, expected is 1",
4066 				     detector_id);
4067 			goto fail;
4068 		}
4069 		params.smode = spectral_mode;
4070 
4071 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
4072 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
4073 			spectral->params[spectral_mode].ss_rpt_mode,
4074 			&spectral->len_adj_swar, &fft_bin_size);
4075 		params.raw_timestamp_sec80 = p_sfft->timestamp;
4076 
4077 		/* Take care of state transitions for 160 MHz and 80p80 */
4078 		if (is_ch_width_160_or_80p80(spectral->ch_width
4079 		    [spectral_mode]) && spectral->rparams.
4080 		    fragmentation_160[spectral_mode]) {
4081 			ret = target_if_160mhz_delivery_state_change(
4082 					spectral, spectral_mode,
4083 					detector_id);
4084 			if (ret != QDF_STATUS_SUCCESS)
4085 				goto fail;
4086 		}
4087 
4088 		params.rssi_sec80 = rssi;
4089 
4090 		vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
4091 		if (!vdev) {
4092 			spectral_info("First vdev is NULL");
4093 			reset_160mhz_delivery_state_machine
4094 						(spectral, spectral_mode);
4095 			return -EPERM;
4096 		}
4097 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
4098 		if (vdev_rxchainmask == 0) {
4099 			spectral_err("Vdev rxchainmask is zero.");
4100 			goto fail;
4101 		}
4102 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4103 
4104 		chn_idx_lowest_enabled =
4105 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
4106 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
4107 			spectral_err("Invalid chain index");
4108 			goto fail;
4109 		}
4110 
4111 		/* Need to change this as per FW team's inputs */
4112 		params.noise_floor_sec80    =
4113 			report->noisefloor[chn_idx_lowest_enabled];
4114 
4115 		params.max_mag_sec80        = p_sfft->fft_peak_mag;
4116 		/* params.max_index_sec80      = p_sfft->peak_inx; */
4117 		/* XXX Does this definition of datalen *still hold? */
4118 		params.datalen_sec80        = fft_hdr_length * 4;
4119 		params.pwr_count_sec80      = fft_bin_count;
4120 		params.bin_pwr_data_sec80   =
4121 			(uint8_t *)((uint8_t *)p_fft_report +
4122 			 SPECTRAL_FFT_BINS_POS);
4123 
4124 		/* Apply byte-swap on the FFT bins.
4125 		 * NOTE: Until this point, bytes of the FFT bins could be in
4126 		 *       reverse order on a big-endian machine. If the consumers
4127 		 *       of FFT bins expects bytes in the correct order,
4128 		 *       they should use them only after this point.
4129 		 */
4130 		if (p_sops->byte_swap_fft_bins) {
4131 			ret = p_sops->byte_swap_fft_bins(
4132 					&spectral->rparams,
4133 					params.bin_pwr_data_sec80,
4134 					fft_bin_count);
4135 			if (QDF_IS_STATUS_ERROR(ret)) {
4136 				spectral_err_rl("Byte-swap on the FFT bins failed");
4137 				goto fail;
4138 			}
4139 		}
4140 
4141 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
4142 			target_if_dump_fft_report_gen3(spectral, spectral_mode,
4143 						       p_fft_report, p_sfft);
4144 
4145 	} else {
4146 		spectral_err("Spectral state machine in undefined state");
4147 		goto fail;
4148 	}
4149 
4150 	target_if_spectral_check_buffer_poisoning(spectral, report,
4151 						  fft_bin_count, spectral_mode);
4152 	qdf_mem_copy(&params.classifier_params,
4153 		     &spectral->classifier_params,
4154 		     sizeof(struct spectral_classifier_params));
4155 
4156 	target_if_spectral_log_SAMP_param(&params);
4157 	target_if_spectral_create_samp_msg(spectral, &params);
4158 
4159 	return 0;
4160  fail:
4161 	spectral_err_rl("Error while processing Spectral report");
4162 fail_no_print:
4163 	if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
4164 		reset_160mhz_delivery_state_machine(spectral, spectral_mode);
4165 	return -EPERM;
4166 }
4167 #endif /* OPTIMIZED_SAMP_MESSAGE */
4168 
4169 int target_if_spectral_process_report_gen3(
4170 	struct wlan_objmgr_pdev *pdev,
4171 	void *buf)
4172 {
4173 	int ret = 0;
4174 	struct direct_buf_rx_data *payload = buf;
4175 	struct target_if_spectral *spectral;
4176 	struct spectral_report report = {0};
4177 	int samp_msg_index;
4178 	struct spectral_data_stats *spectral_dp_stats;
4179 
4180 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4181 	if (!spectral) {
4182 		spectral_err("Spectral target object is null");
4183 		return -EINVAL;
4184 	}
4185 
4186 	spectral_dp_stats = &spectral->data_stats;
4187 	spectral_dp_stats->spectral_rx_events++;
4188 
4189 	report.data = payload->vaddr;
4190 	if (payload->meta_data_valid) {
4191 		qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor,
4192 			     qdf_min(sizeof(report.noisefloor),
4193 				     sizeof(payload->meta_data.noisefloor)));
4194 		report.reset_delay = payload->meta_data.reset_delay;
4195 		report.cfreq1 = payload->meta_data.cfreq1;
4196 		report.cfreq2 = payload->meta_data.cfreq2;
4197 		report.ch_width = payload->meta_data.ch_width;
4198 	}
4199 
4200 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) {
4201 		spectral_debug("Printing the spectral phyerr buffer for debug");
4202 		spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK",
4203 			       payload->dbr_len,
4204 			       payload->dbr_len,
4205 			       payload->vaddr);
4206 		target_if_spectral_hexdump((unsigned char *)payload->vaddr,
4207 					   1024);
4208 	}
4209 
4210 	samp_msg_index = spectral->spectral_sent_msg;
4211 
4212 	ret = target_if_consume_spectral_report_gen3(spectral, &report);
4213 
4214 	/* Reset debug level when SAMP msg is sent successfully or on error */
4215 	if ((spectral_debug_level & DEBUG_SPECTRAL4) &&
4216 	    (ret != 0 || spectral->spectral_sent_msg == samp_msg_index + 1))
4217 		spectral_debug_level = DEBUG_SPECTRAL;
4218 
4219 	return ret;
4220 }
4221 #else
4222 int target_if_spectral_process_report_gen3(
4223 	struct wlan_objmgr_pdev *pdev,
4224 	void *buf)
4225 {
4226 	spectral_err("Direct dma support is not enabled");
4227 	return -EINVAL;
4228 }
4229 #endif
4230 qdf_export_symbol(target_if_spectral_process_report_gen3);
4231 /* END of spectral GEN III HW specific functions */
4232 
4233 #endif  /* WLAN_CONV_SPECTRAL_ENABLE */
4234