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