xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral_phyerr.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2011,2017-2021 The Linux Foundation. All rights reserved.
3  *
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 comparision 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 comparision 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 comparision 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 = wlan_reg_get_5g_bonded_channel_and_state_for_freq
897 				(spectral->pdev_obj, pri20_freq, CH_WIDTH_80MHZ,
898 				 &bonded_chan_ptr);
899 
900 			if (state == CHANNEL_STATE_DISABLE ||
901 			    state == CHANNEL_STATE_INVALID) {
902 				spectral_err_rl("Channel state is disable or invalid");
903 				return QDF_STATUS_E_FAILURE;
904 			}
905 
906 			if (!bonded_chan_ptr) {
907 				spectral_err_rl("Bonded channel is not found");
908 				return QDF_STATUS_E_FAILURE;
909 			}
910 
911 			/* cfreq1 is the center of the pri80 segment */
912 			*cfreq1 = (bonded_chan_ptr->start_freq +
913 				   bonded_chan_ptr->end_freq) >> 1;
914 
915 			/**
916 			 * cfreq2 is 85MHz away from cfreq1. Whether it is
917 			 * higher or lower depends on pri20_freq's relationship
918 			 * with the reported center frequency.
919 			 */
920 			if (pri20_freq < reported_cfreq1)
921 				*cfreq2 = *cfreq1 + FREQ_OFFSET_85MHZ;
922 			else
923 				*cfreq2 = *cfreq1 - FREQ_OFFSET_85MHZ;
924 	} else {
925 		/* All other cases are reporting the cfreq properly */
926 		*cfreq1 = reported_cfreq1;
927 		*cfreq2 = reported_cfreq2;
928 	}
929 
930 	return QDF_STATUS_SUCCESS;
931 }
932 
933 /**
934  * target_if_populate_det_start_end_freqs() - Populate the start and end
935  * frequencies, on per-detector level.
936  * @spectral: Pointer to target_if spectral internal structure
937  * @smode: Spectral scan mode
938  *
939  * Populate the start and end frequencies, on per-detector level.
940  *
941  * Return: Success/Failure
942  */
943 static QDF_STATUS
944 target_if_populate_det_start_end_freqs(struct target_if_spectral *spectral,
945 				       enum spectral_scan_mode smode)
946 {
947 	struct per_session_report_info *rpt_info;
948 	struct per_session_det_map *det_map;
949 	struct per_session_dest_det_info *dest_det_info;
950 	enum phy_ch_width ch_width;
951 	struct sscan_detector_list *detector_list;
952 	bool is_fragmentation_160;
953 	uint8_t det;
954 	uint32_t cfreq;
955 	uint32_t start_end_freq_arr[2];
956 
957 	if (!spectral) {
958 		spectral_err_rl("Spectral LMAC object is null");
959 		return QDF_STATUS_E_NULL_VALUE;
960 	}
961 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
962 		spectral_err_rl("Invalid Spectral mode");
963 		return QDF_STATUS_E_FAILURE;
964 	}
965 
966 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
967 
968 	ch_width = spectral->report_info[smode].sscan_bw;
969 	is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
970 
971 	rpt_info = &spectral->report_info[smode];
972 
973 	qdf_spin_lock_bh(&spectral->detector_list_lock);
974 	detector_list = &spectral->detector_list[smode][ch_width];
975 
976 	for (det = 0; det < detector_list->num_detectors; det++) {
977 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
978 		det_map = &spectral->det_map
979 				[detector_list->detectors[det]];
980 		dest_det_info = &det_map->dest_det_info[0];
981 
982 		switch (det) {
983 		case 0:
984 			if (ch_width == CH_WIDTH_160MHZ &&
985 			    is_fragmentation_160) {
986 				if (rpt_info->pri20_freq <
987 				    rpt_info->sscan_cfreq1)
988 					cfreq = rpt_info->sscan_cfreq1 -
989 						FREQ_OFFSET_40MHZ;
990 				else
991 					cfreq = rpt_info->sscan_cfreq1 +
992 						FREQ_OFFSET_40MHZ;
993 			} else
994 				cfreq = rpt_info->sscan_cfreq1;
995 			break;
996 
997 		case 1:
998 			if (ch_width == CH_WIDTH_160MHZ &&
999 			    is_fragmentation_160) {
1000 				if (rpt_info->pri20_freq <
1001 				    rpt_info->sscan_cfreq1)
1002 					cfreq = rpt_info->sscan_cfreq1 +
1003 						FREQ_OFFSET_40MHZ;
1004 				else
1005 					cfreq = rpt_info->sscan_cfreq1 -
1006 						FREQ_OFFSET_40MHZ;
1007 			} else
1008 				cfreq = rpt_info->sscan_cfreq2;
1009 			break;
1010 
1011 		default:
1012 			qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1013 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
1014 			qdf_spin_unlock_bh(
1015 					&spectral->session_report_info_lock);
1016 
1017 			return QDF_STATUS_E_FAILURE;
1018 		}
1019 
1020 		/* Set start and end frequencies */
1021 		target_if_spectral_set_start_end_freq(cfreq,
1022 						      ch_width,
1023 						      is_fragmentation_160,
1024 						      start_end_freq_arr);
1025 		dest_det_info->start_freq = start_end_freq_arr[0];
1026 		dest_det_info->end_freq = start_end_freq_arr[1];
1027 
1028 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1029 	}
1030 
1031 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
1032 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1033 
1034 	return QDF_STATUS_SUCCESS;
1035 }
1036 
1037 /**
1038  * target_if_populate_fft_bins_info() - Populate the start and end bin
1039  * indices, on per-detector level.
1040  * @spectral: Pointer to target_if spectral internal structure
1041  * @smode: Spectral scan mode
1042  *
1043  * Populate the start and end bin indices, on per-detector level.
1044  *
1045  * Return: Success/Failure
1046  */
1047 static QDF_STATUS
1048 target_if_populate_fft_bins_info(struct target_if_spectral *spectral,
1049 				 enum spectral_scan_mode smode)
1050 {
1051 	struct per_session_det_map *det_map;
1052 	struct per_session_dest_det_info *dest_det_info;
1053 	enum phy_ch_width ch_width;
1054 	struct sscan_detector_list *detector_list;
1055 	bool is_fragmentation_160;
1056 	uint8_t spectral_fft_size;
1057 	uint8_t rpt_mode;
1058 	uint32_t num_fft_bins;
1059 	uint16_t start_bin;
1060 	uint8_t det;
1061 
1062 	if (!spectral) {
1063 		spectral_err_rl("Spectral LMAC object is null");
1064 		return QDF_STATUS_E_NULL_VALUE;
1065 	}
1066 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1067 		spectral_err_rl("Invalid Spectral mode");
1068 		return QDF_STATUS_E_FAILURE;
1069 	}
1070 
1071 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1072 
1073 	ch_width = spectral->report_info[smode].sscan_bw;
1074 	is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
1075 	spectral_fft_size = spectral->params[smode].ss_fft_size;
1076 	rpt_mode = spectral->params[smode].ss_rpt_mode;
1077 	num_fft_bins =
1078 		target_if_spectral_get_num_fft_bins(spectral_fft_size,
1079 						    rpt_mode);
1080 	if (num_fft_bins < 0) {
1081 		qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1082 		spectral_err_rl("Invalid number of FFT bins %d",
1083 				num_fft_bins);
1084 		return QDF_STATUS_E_FAILURE;
1085 	}
1086 
1087 	qdf_spin_lock_bh(&spectral->detector_list_lock);
1088 	detector_list = &spectral->detector_list[smode][ch_width];
1089 
1090 	for (det = 0; det < detector_list->num_detectors; det++) {
1091 		uint16_t lb_extrabins_offset = 0;
1092 
1093 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
1094 		det_map = &spectral->det_map
1095 				[detector_list->detectors[det]];
1096 		dest_det_info = &det_map->dest_det_info[0];
1097 		dest_det_info->lb_extrabins_num = spectral->lb_edge_extrabins;
1098 		dest_det_info->rb_extrabins_num = spectral->rb_edge_extrabins;
1099 		switch (det) {
1100 		case 0:
1101 			if (ch_width == CH_WIDTH_160MHZ &&
1102 			    is_fragmentation_160 &&
1103 			    spectral->report_info[smode].pri20_freq >
1104 			    spectral->report_info[smode].sscan_cfreq1) {
1105 				start_bin = num_fft_bins;
1106 				lb_extrabins_offset =
1107 					dest_det_info->lb_extrabins_num +
1108 					dest_det_info->rb_extrabins_num;
1109 			} else {
1110 				start_bin = 0;
1111 			}
1112 			break;
1113 		case 1:
1114 			if (ch_width == CH_WIDTH_160MHZ &&
1115 			    is_fragmentation_160 &&
1116 			    spectral->report_info[smode].pri20_freq >
1117 			    spectral->report_info[smode].sscan_cfreq1)
1118 				start_bin = 0;
1119 			else {
1120 				start_bin = num_fft_bins;
1121 				lb_extrabins_offset =
1122 					dest_det_info->lb_extrabins_num +
1123 					dest_det_info->rb_extrabins_num;
1124 			}
1125 			break;
1126 		default:
1127 			qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1128 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
1129 			qdf_spin_unlock_bh(
1130 					&spectral->session_report_info_lock);
1131 
1132 			return QDF_STATUS_E_FAILURE;
1133 		}
1134 		dest_det_info->dest_start_bin_idx = start_bin;
1135 		dest_det_info->dest_end_bin_idx =
1136 					dest_det_info->dest_start_bin_idx +
1137 					num_fft_bins - 1;
1138 		if (dest_det_info->lb_extrabins_num) {
1139 			if (is_ch_width_160_or_80p80(ch_width)) {
1140 				dest_det_info->lb_extrabins_start_idx =
1141 							2 * num_fft_bins +
1142 							lb_extrabins_offset;
1143 			} else {
1144 				dest_det_info->lb_extrabins_start_idx =
1145 								num_fft_bins;
1146 			}
1147 		}
1148 		if (dest_det_info->rb_extrabins_num)
1149 			dest_det_info->rb_extrabins_start_idx =
1150 					dest_det_info->lb_extrabins_start_idx +
1151 					dest_det_info->lb_extrabins_num;
1152 		dest_det_info->src_start_bin_idx = 0;
1153 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1154 	}
1155 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
1156 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1157 
1158 	return QDF_STATUS_SUCCESS;
1159 }
1160 
1161 /**
1162  * target_if_update_session_info_from_report_ctx() - Update per-session
1163  * information from the consume report context. This includes populating start
1164  * and end bin indices, and set the start and end frequency per-detector.
1165  * @spectral: Pointer to target_if spectral internal structure
1166  * @fft_bin_size: Size of 1 FFT bin (in bytes)
1167  * @cfreq1: Center frequency of Detector 1
1168  * @cfreq2: Center frequency of Detector 2
1169  * @smode: Spectral scan mode
1170  *
1171  * Update per-session information from the consume report context.
1172  *
1173  * Return: Success/Failure
1174  */
1175 static QDF_STATUS
1176 target_if_update_session_info_from_report_ctx(
1177 				struct target_if_spectral *spectral,
1178 				uint8_t fft_bin_size,
1179 				uint32_t cfreq1, uint32_t cfreq2,
1180 				enum spectral_scan_mode smode)
1181 {
1182 	struct target_if_spectral_ops *p_sops;
1183 	struct per_session_report_info *rpt_info;
1184 	struct per_session_det_map *det_map;
1185 	struct per_session_dest_det_info *dest_det_info;
1186 	enum phy_ch_width ch_width;
1187 	struct wlan_objmgr_psoc *psoc;
1188 	bool is_fragmentation_160;
1189 	uint32_t start_end_freq_arr[2];
1190 	QDF_STATUS ret;
1191 
1192 	if (!spectral) {
1193 		spectral_err_rl("Spectral LMAC object is null");
1194 		return QDF_STATUS_E_NULL_VALUE;
1195 	}
1196 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1197 		spectral_err_rl("Invalid Spectral mode");
1198 		return QDF_STATUS_E_FAILURE;
1199 	}
1200 	if (!spectral->pdev_obj) {
1201 		spectral_err_rl("Spectral PDEV is null");
1202 		return QDF_STATUS_E_NULL_VALUE;
1203 	}
1204 
1205 	psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
1206 	if (!psoc) {
1207 		spectral_err_rl("psoc is null");
1208 		return QDF_STATUS_E_NULL_VALUE;
1209 	}
1210 
1211 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1212 
1213 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1214 
1215 	rpt_info = &spectral->report_info[smode];
1216 	ch_width = rpt_info->sscan_bw;
1217 	is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
1218 
1219 	rpt_info->pri20_freq = p_sops->get_current_channel(spectral, smode);
1220 	rpt_info->cfreq1 = cfreq1;
1221 	rpt_info->cfreq2 = cfreq2;
1222 
1223 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1224 		spectral_debug("Before conversion: cfreq1: %u cfreq2: %u",
1225 			       rpt_info->cfreq1, rpt_info->cfreq2);
1226 
1227 	ret = target_if_spectral_unify_cfreq_format(
1228 		spectral, &rpt_info->cfreq1, &rpt_info->cfreq2,
1229 		rpt_info->pri20_freq, rpt_info->operating_bw, smode);
1230 
1231 	if (QDF_IS_STATUS_ERROR(ret)) {
1232 		qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1233 		spectral_err_rl("Unable to unify cfreq1/cfreq2");
1234 		return QDF_STATUS_E_FAILURE;
1235 	}
1236 
1237 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1238 		spectral_debug("After conversion: cfreq1: %d cfreq2: %d",
1239 			       rpt_info->cfreq1, rpt_info->cfreq2);
1240 
1241 	/* For Agile mode, sscan_cfreq1 and sscan_cfreq2 are populated
1242 	 * during Spectral start scan
1243 	 */
1244 	if (smode == SPECTRAL_SCAN_MODE_NORMAL) {
1245 		rpt_info->sscan_cfreq1 = rpt_info->cfreq1;
1246 		rpt_info->sscan_cfreq2 = rpt_info->cfreq2;
1247 	}
1248 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1249 
1250 	if (ch_width == CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
1251 	    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
1252 		/* Restricted 80p80 */
1253 		struct spectral_fft_bin_markers_160_165mhz *marker;
1254 		struct sscan_detector_list *detector_list;
1255 
1256 		marker = &spectral->rparams.marker[smode];
1257 		if (!marker->is_valid)
1258 			return QDF_STATUS_E_FAILURE;
1259 
1260 		/**
1261 		 * Restricted 80p80 on Pine has only 1 detector for
1262 		 * normal/agile spectral scan. So, detector_list will
1263 		 * have only one detector
1264 		 */
1265 		qdf_spin_lock_bh(&spectral->detector_list_lock);
1266 		detector_list = &spectral->detector_list[smode][ch_width];
1267 
1268 		qdf_spin_lock_bh(&spectral->session_det_map_lock);
1269 		det_map = &spectral->det_map[detector_list->detectors[0]];
1270 
1271 		dest_det_info = &det_map->dest_det_info[0];
1272 		dest_det_info->dest_start_bin_idx = marker->start_pri80;
1273 		dest_det_info->dest_end_bin_idx =
1274 					dest_det_info->dest_start_bin_idx +
1275 					marker->num_pri80 - 1;
1276 		dest_det_info->src_start_bin_idx = marker->start_pri80 *
1277 						   fft_bin_size;
1278 		/* Set start and end frequencies */
1279 		qdf_spin_lock_bh(&spectral->session_report_info_lock);
1280 		target_if_spectral_set_start_end_freq(rpt_info->sscan_cfreq1,
1281 						      ch_width,
1282 						      is_fragmentation_160,
1283 						      start_end_freq_arr);
1284 		dest_det_info->start_freq = start_end_freq_arr[0];
1285 		dest_det_info->end_freq = start_end_freq_arr[1];
1286 
1287 
1288 		dest_det_info = &det_map->dest_det_info[1];
1289 		dest_det_info->dest_start_bin_idx = marker->start_sec80;
1290 		dest_det_info->dest_end_bin_idx =
1291 					dest_det_info->dest_start_bin_idx +
1292 					marker->num_sec80 - 1;
1293 		dest_det_info->src_start_bin_idx = marker->start_sec80 *
1294 						   fft_bin_size;
1295 		/* Set start and end frequencies */
1296 		target_if_spectral_set_start_end_freq(rpt_info->sscan_cfreq2,
1297 						      ch_width,
1298 						      is_fragmentation_160,
1299 						      start_end_freq_arr);
1300 		dest_det_info->start_freq = start_end_freq_arr[0];
1301 		dest_det_info->end_freq = start_end_freq_arr[1];
1302 
1303 		dest_det_info = &det_map->dest_det_info[2];
1304 		dest_det_info->dest_start_bin_idx = marker->start_5mhz;
1305 		dest_det_info->dest_end_bin_idx =
1306 					dest_det_info->dest_start_bin_idx +
1307 					marker->num_5mhz - 1;
1308 		dest_det_info->src_start_bin_idx = marker->start_5mhz *
1309 						   fft_bin_size;
1310 		/* Set start and end frequencies */
1311 		dest_det_info->start_freq =
1312 				min(det_map->dest_det_info[0].end_freq,
1313 				    det_map->dest_det_info[1].end_freq);
1314 		dest_det_info->end_freq =
1315 				max(det_map->dest_det_info[0].start_freq,
1316 				    det_map->dest_det_info[1].start_freq);
1317 
1318 		qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1319 		qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1320 		qdf_spin_unlock_bh(&spectral->detector_list_lock);
1321 	} else {
1322 		ret = target_if_populate_fft_bins_info(spectral, smode);
1323 		if (QDF_IS_STATUS_ERROR(ret)) {
1324 			spectral_err_rl("Error in populating fft bins info");
1325 			return QDF_STATUS_E_FAILURE;
1326 		}
1327 
1328 		ret = target_if_populate_det_start_end_freqs(spectral, smode);
1329 		if (QDF_IS_STATUS_ERROR(ret)) {
1330 			spectral_err_rl("Failed to populate start/end freqs");
1331 			return QDF_STATUS_E_FAILURE;
1332 		}
1333 	}
1334 
1335 	return QDF_STATUS_SUCCESS;
1336 }
1337 #endif /* OPTIMIZED_SAMP_MESSAGE */
1338 
1339 #ifdef OPTIMIZED_SAMP_MESSAGE
1340 /**
1341  * target_if_spectral_populate_samp_params_gen2() - Populate the SAMP params
1342  * for gen2. SAMP params are to be used for populating SAMP msg.
1343  * @spectral: Pointer to spectral object
1344  * @phyerr_info: Pointer to processed phyerr info
1345  * @params: Pointer to Spectral SAMP message fields to be populated
1346  *
1347  * Populate the SAMP params for gen2, which will be used to populate SAMP msg.
1348  *
1349  * Return: Success/Failure
1350  */
1351 static QDF_STATUS
1352 target_if_spectral_populate_samp_params_gen2(
1353 			struct target_if_spectral *spectral,
1354 			struct spectral_process_phyerr_info_gen2 *phyerr_info,
1355 			struct target_if_samp_msg_params *params)
1356 {
1357 	uint8_t chn_idx_highest_enabled;
1358 	uint8_t chn_idx_lowest_enabled;
1359 	int8_t control_rssi;
1360 	int8_t extension_rssi;
1361 	struct target_if_spectral_rfqual_info *p_rfqual;
1362 	struct spectral_search_fft_info_gen2 *p_sfft;
1363 	struct spectral_phyerr_fft_gen2 *pfft;
1364 	struct target_if_spectral_acs_stats *acs_stats;
1365 	enum phy_ch_width ch_width;
1366 	enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1367 
1368 	if (!spectral) {
1369 		spectral_err_rl("Spectral LMAC object is null");
1370 		return QDF_STATUS_E_NULL_VALUE;
1371 	}
1372 	if (!phyerr_info) {
1373 		spectral_err_rl("Pointer to phyerr info is null");
1374 		return QDF_STATUS_E_NULL_VALUE;
1375 	}
1376 	if (!params) {
1377 		spectral_err_rl("SAMP msg params structure is null");
1378 		return QDF_STATUS_E_NULL_VALUE;
1379 	}
1380 
1381 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1382 	ch_width = spectral->report_info[smode].sscan_bw;
1383 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1384 
1385 	acs_stats = phyerr_info->acs_stats;
1386 	pfft = phyerr_info->pfft;
1387 	p_sfft = phyerr_info->p_sfft;
1388 	p_rfqual = phyerr_info->p_rfqual;
1389 
1390 	params->hw_detector_id = phyerr_info->seg_id;
1391 	params->rssi = p_rfqual->rssi_comb;
1392 	if (spectral->is_sec80_rssi_war_required && phyerr_info->seg_id == 1)
1393 		params->rssi = target_if_get_combrssi_sec80_seg_gen2(spectral,
1394 								     p_sfft);
1395 
1396 	chn_idx_highest_enabled =
1397 		   ((spectral->params[smode].ss_chn_mask & 0x8) ? 3 :
1398 		    (spectral->params[smode].ss_chn_mask & 0x4) ? 2 :
1399 		    (spectral->params[smode].ss_chn_mask & 0x2) ? 1 : 0);
1400 	chn_idx_lowest_enabled =
1401 		   ((spectral->params[smode].ss_chn_mask & 0x1) ? 0 :
1402 		    (spectral->params[smode].ss_chn_mask & 0x2) ? 1 :
1403 		    (spectral->params[smode].ss_chn_mask & 0x4) ? 2 : 3);
1404 	control_rssi =
1405 		p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
1406 	extension_rssi =
1407 		p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
1408 
1409 	if (spectral->upper_is_control)
1410 		params->upper_rssi = control_rssi;
1411 	else
1412 		params->upper_rssi = extension_rssi;
1413 
1414 	if (spectral->lower_is_control)
1415 		params->lower_rssi = control_rssi;
1416 	else
1417 		params->lower_rssi = extension_rssi;
1418 
1419 	if (spectral->sc_spectral_noise_pwr_cal) {
1420 		int idx;
1421 
1422 		for (idx = 0; idx < HOST_MAX_ANTENNA; idx++) {
1423 			params->chain_ctl_rssi[idx] =
1424 				p_rfqual->pc_rssi_info[idx].rssi_pri20;
1425 			params->chain_ext_rssi[idx] =
1426 				p_rfqual->pc_rssi_info[idx].rssi_sec20;
1427 		}
1428 	}
1429 	params->timestamp = (phyerr_info->tsf64 & SPECTRAL_TSMASK);
1430 	params->max_mag = p_sfft->peak_mag;
1431 	params->max_index = p_sfft->peak_inx;
1432 
1433 	/*
1434 	 * For VHT80_80/VHT160, the noise floor for primary
1435 	 * 80MHz segment is populated with the lowest enabled
1436 	 * antenna chain and the noise floor for secondary 80MHz segment
1437 	 * is populated with the highest enabled antenna chain.
1438 	 * For modes upto VHT80, the noise floor is populated with the
1439 	 * one corresponding to the highest enabled antenna chain.
1440 	 */
1441 	if (is_ch_width_160_or_80p80(ch_width) && phyerr_info->seg_id == 0)
1442 		params->noise_floor =
1443 				p_rfqual->noise_floor[chn_idx_lowest_enabled];
1444 	else
1445 		params->noise_floor =
1446 				p_rfqual->noise_floor[chn_idx_highest_enabled];
1447 
1448 	acs_stats->ctrl_nf = params->noise_floor;
1449 	acs_stats->ext_nf = params->noise_floor;
1450 	acs_stats->nfc_ctl_rssi = control_rssi;
1451 	acs_stats->nfc_ext_rssi = extension_rssi;
1452 
1453 	params->bin_pwr_data = (uint8_t *)pfft;
1454 
1455 	return QDF_STATUS_SUCCESS;
1456 }
1457 
1458 int
1459 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
1460 			      uint8_t *data,
1461 			      uint32_t datalen,
1462 			      struct target_if_spectral_rfqual_info *p_rfqual,
1463 			      struct target_if_spectral_chan_info *p_chaninfo,
1464 			      uint64_t tsf64,
1465 			      struct target_if_spectral_acs_stats *acs_stats)
1466 {
1467 	/*
1468 	 * XXX : The classifier do not use all the members of the SAMP
1469 	 *       message data format.
1470 	 *       The classifier only depends upon the following parameters
1471 	 *
1472 	 *          1. Frequency
1473 	 *          2. Spectral RSSI
1474 	 *          3. Bin Power Count
1475 	 *          4. Bin Power values
1476 	 *          5. Spectral Timestamp
1477 	 *          6. MAC Address
1478 	 *
1479 	 *       This function prepares the params structure and populates it
1480 	 *       with relevant values, this is in turn passed to
1481 	 *       spectral_fill_samp_msg()
1482 	 *       to prepare fully formatted Spectral SAMP message
1483 	 *
1484 	 *       XXX : Need to verify
1485 	 *          1. Order of FFT bin values
1486 	 *
1487 	 */
1488 
1489 	struct target_if_samp_msg_params params;
1490 	struct spectral_search_fft_info_gen2 search_fft_info;
1491 	struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
1492 	struct spectral_search_fft_info_gen2 search_fft_info_sec80;
1493 	struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
1494 		&search_fft_info_sec80;
1495 	uint32_t segid_skiplen = 0;
1496 	struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
1497 	struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
1498 	struct spectral_phyerr_fft_gen2 *pfft = NULL;
1499 	struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
1500 	struct spectral_process_phyerr_info_gen2 process_phyerr_fields;
1501 	struct spectral_process_phyerr_info_gen2 *phyerr_info =
1502 						&process_phyerr_fields;
1503 	uint8_t segid;
1504 	uint8_t segid_sec80;
1505 	enum phy_ch_width ch_width;
1506 	QDF_STATUS ret;
1507 	struct target_if_spectral_ops *p_sops;
1508 
1509 	if (!spectral) {
1510 		spectral_err_rl("Spectral LMAC object is null");
1511 		goto fail_no_print;
1512 	}
1513 
1514 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1515 	/* Drop the sample if Spectral is not active */
1516 	if (!p_sops->is_spectral_active(spectral,
1517 					SPECTRAL_SCAN_MODE_NORMAL)) {
1518 		spectral_info_rl("Spectral scan is not active");
1519 		goto fail_no_print;
1520 	}
1521 
1522 	if (!data) {
1523 		spectral_err_rl("Phyerror event buffer is null");
1524 		goto fail;
1525 	}
1526 	if (!p_rfqual) {
1527 		spectral_err_rl("RF quality information is null");
1528 		goto fail;
1529 	}
1530 	if (!p_chaninfo) {
1531 		spectral_err_rl("Channel information is null");
1532 		goto fail;
1533 	}
1534 	if (!acs_stats) {
1535 		spectral_err_rl("ACS stats pointer is null");
1536 		goto fail;
1537 	}
1538 
1539 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
1540 	ch_width = spectral->report_info[SPECTRAL_SCAN_MODE_NORMAL].sscan_bw;
1541 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1542 
1543 	ptlv = (struct spectral_phyerr_tlv_gen2 *)data;
1544 
1545 	if (spectral->is_160_format)
1546 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
1547 
1548 	pfft = (struct spectral_phyerr_fft_gen2 *)(
1549 			data +
1550 			sizeof(struct spectral_phyerr_tlv_gen2) +
1551 			sizeof(struct spectral_phyerr_hdr_gen2) +
1552 			segid_skiplen);
1553 
1554 	/*
1555 	 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
1556 	 * and use this facility inside spectral_dump_phyerr_data()
1557 	 * and supporting functions.
1558 	 */
1559 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1560 		target_if_spectral_dump_phyerr_data_gen2(
1561 					data, datalen,
1562 					spectral->is_160_format);
1563 
1564 	if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1565 		/*
1566 		 * EV# 118023: We tentatively disable the below print
1567 		 * and provide stats instead.
1568 		 */
1569 		spectral->diag_stats.spectral_mismatch++;
1570 		goto fail;
1571 	}
1572 
1573 	qdf_mem_zero(&params, sizeof(params));
1574 
1575 	if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1576 		if (spectral->is_160_format) {
1577 			segid = *((SPECTRAL_SEGID_INFO *)(
1578 				  (uint8_t *)ptlv +
1579 				  sizeof(struct spectral_phyerr_tlv_gen2) +
1580 				  sizeof(struct spectral_phyerr_hdr_gen2)));
1581 
1582 			if (segid != 0) {
1583 				struct spectral_diag_stats *p_diag_stats =
1584 					&spectral->diag_stats;
1585 				p_diag_stats->spectral_vhtseg1id_mismatch++;
1586 				goto fail;
1587 			}
1588 		}
1589 
1590 		target_if_process_sfft_report_gen2(ptlv, ptlv->length,
1591 						   p_sfft);
1592 
1593 		ret = target_if_update_session_info_from_report_ctx(
1594 						spectral, FFT_BIN_SIZE_1BYTE,
1595 						p_chaninfo->center_freq1,
1596 						p_chaninfo->center_freq2,
1597 						SPECTRAL_SCAN_MODE_NORMAL);
1598 		if (QDF_IS_STATUS_ERROR(ret)) {
1599 			spectral_err_rl("Failed to update per-session info");
1600 			goto fail;
1601 		}
1602 
1603 		phyerr_info->p_rfqual = p_rfqual;
1604 		phyerr_info->p_sfft = p_sfft;
1605 		phyerr_info->pfft = pfft;
1606 		phyerr_info->acs_stats = acs_stats;
1607 		phyerr_info->tsf64 = tsf64;
1608 		phyerr_info->seg_id = segid;
1609 
1610 		ret = target_if_spectral_populate_samp_params_gen2(spectral,
1611 								   phyerr_info,
1612 								   &params);
1613 		if (QDF_IS_STATUS_ERROR(ret)) {
1614 			spectral_err_rl("Failed to populate SAMP params");
1615 			goto fail;
1616 		}
1617 
1618 		ret = target_if_spectral_fill_samp_msg(spectral, &params);
1619 		if (QDF_IS_STATUS_ERROR(ret)) {
1620 			spectral_err_rl("Failed to fill the SAMP msg");
1621 			goto fail;
1622 		}
1623 
1624 		if (spectral->is_160_format &&
1625 		    is_ch_width_160_or_80p80(ch_width)) {
1626 			/*
1627 			 * We expect to see one more Search FFT report, and it
1628 			 * should be equal in size to the current one.
1629 			 */
1630 			if (datalen < (
1631 				2 * (sizeof(struct spectral_phyerr_tlv_gen2) +
1632 				     ptlv->length))) {
1633 				struct spectral_diag_stats *p_diag_stats =
1634 					&spectral->diag_stats;
1635 				p_diag_stats->spectral_sec80_sfft_insufflen++;
1636 				goto fail;
1637 			}
1638 
1639 			ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1640 				      data +
1641 				      sizeof(struct spectral_phyerr_tlv_gen2) +
1642 				      ptlv->length);
1643 
1644 			if (ptlv_sec80->signature !=
1645 			    SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1646 				spectral->diag_stats.spectral_mismatch++;
1647 				goto fail;
1648 			}
1649 
1650 			if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1651 				spectral->diag_stats.spectral_no_sec80_sfft++;
1652 				goto fail;
1653 			}
1654 
1655 			segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
1656 				(uint8_t *)ptlv_sec80 +
1657 				sizeof(struct spectral_phyerr_tlv_gen2) +
1658 				sizeof(struct spectral_phyerr_hdr_gen2)));
1659 
1660 			if (segid_sec80 != 1) {
1661 				struct spectral_diag_stats *p_diag_stats =
1662 					&spectral->diag_stats;
1663 				p_diag_stats->spectral_vhtseg2id_mismatch++;
1664 				goto fail;
1665 			}
1666 
1667 			target_if_process_sfft_report_gen2(ptlv_sec80,
1668 							   ptlv_sec80->length,
1669 							   p_sfft_sec80);
1670 
1671 			pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
1672 				((uint8_t *)ptlv_sec80) +
1673 				sizeof(struct spectral_phyerr_tlv_gen2) +
1674 				sizeof(struct spectral_phyerr_hdr_gen2) +
1675 				segid_skiplen);
1676 
1677 			qdf_mem_zero(&params, sizeof(params));
1678 
1679 			phyerr_info->p_rfqual = p_rfqual;
1680 			phyerr_info->p_sfft = p_sfft_sec80;
1681 			phyerr_info->pfft = pfft_sec80;
1682 			phyerr_info->acs_stats = acs_stats;
1683 			phyerr_info->tsf64 = tsf64;
1684 			phyerr_info->seg_id = segid_sec80;
1685 
1686 			ret = target_if_spectral_populate_samp_params_gen2(
1687 							spectral, phyerr_info,
1688 							&params);
1689 			if (QDF_IS_STATUS_ERROR(ret)) {
1690 				spectral_err_rl("Failed to populate SAMP params");
1691 				goto fail;
1692 			}
1693 			ret = target_if_spectral_fill_samp_msg(spectral,
1694 							       &params);
1695 			if (QDF_IS_STATUS_ERROR(ret)) {
1696 				spectral_err_rl("Failed to fill the SAMP msg");
1697 				goto fail;
1698 			}
1699 		}
1700 	}
1701 
1702 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1703 		spectral_debug_level = DEBUG_SPECTRAL;
1704 
1705 	return 0;
1706 
1707 fail:
1708 	spectral_err_rl("Error while processing Spectral report");
1709 
1710 fail_no_print:
1711 	if (spectral_debug_level & DEBUG_SPECTRAL4)
1712 		spectral_debug_level = DEBUG_SPECTRAL;
1713 
1714 	free_samp_msg_skb(spectral, SPECTRAL_SCAN_MODE_NORMAL);
1715 	return -EPERM;
1716 }
1717 
1718 #else
1719 int
1720 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
1721 			      uint8_t *data,
1722 			      uint32_t datalen,
1723 			      struct target_if_spectral_rfqual_info *p_rfqual,
1724 			      struct target_if_spectral_chan_info *p_chaninfo,
1725 			      uint64_t tsf64,
1726 			      struct target_if_spectral_acs_stats *acs_stats)
1727 {
1728 	/*
1729 	 * XXX : The classifier do not use all the members of the SAMP
1730 	 *       message data format.
1731 	 *       The classifier only depends upon the following parameters
1732 	 *
1733 	 *          1. Frequency (freq, msg->freq)
1734 	 *          2. Spectral RSSI (spectral_rssi,
1735 	 *          msg->samp_data.spectral_rssi)
1736 	 *          3. Bin Power Count (bin_pwr_count,
1737 	 *          msg->samp_data.bin_pwr_count)
1738 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
1739 	 *          5. Spectral Timestamp (spectral_tstamp,
1740 	 *          msg->samp_data.spectral_tstamp)
1741 	 *          6. MAC Address (macaddr, msg->macaddr)
1742 	 *
1743 	 *       This function prepares the params structure and populates it
1744 	 *       with
1745 	 *       relevant values, this is in turn passed to
1746 	 *       spectral_create_samp_msg()
1747 	 *       to prepare fully formatted Spectral SAMP message
1748 	 *
1749 	 *       XXX : Need to verify
1750 	 *          1. Order of FFT bin values
1751 	 *
1752 	 */
1753 
1754 	struct target_if_samp_msg_params params;
1755 	struct spectral_search_fft_info_gen2 search_fft_info;
1756 	struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
1757 	struct spectral_search_fft_info_gen2 search_fft_info_sec80;
1758 	struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
1759 		&search_fft_info_sec80;
1760 	uint32_t segid_skiplen = 0;
1761 
1762 	int8_t rssi_up = 0;
1763 	int8_t rssi_low = 0;
1764 
1765 	int8_t chn_idx_highest_enabled = 0;
1766 	int8_t chn_idx_lowest_enabled = 0;
1767 
1768 	uint8_t control_rssi = 0;
1769 	uint8_t extension_rssi = 0;
1770 	uint8_t combined_rssi = 0;
1771 
1772 	uint32_t tstamp = 0;
1773 
1774 	struct target_if_spectral_ops *p_sops =
1775 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1776 
1777 	struct spectral_phyerr_tlv_gen2 *ptlv =
1778 		(struct spectral_phyerr_tlv_gen2 *)data;
1779 	struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
1780 	struct spectral_phyerr_fft_gen2 *pfft = NULL;
1781 	struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
1782 
1783 	uint8_t segid = 0;
1784 	uint8_t segid_sec80 = 0;
1785 	enum phy_ch_width ch_width =
1786 				spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL];
1787 
1788 	if (spectral->is_160_format)
1789 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
1790 
1791 	pfft = (struct spectral_phyerr_fft_gen2 *)(
1792 			data +
1793 			sizeof(struct spectral_phyerr_tlv_gen2) +
1794 			sizeof(struct spectral_phyerr_hdr_gen2) +
1795 			segid_skiplen);
1796 
1797 	/*
1798 	 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
1799 	 * and use this facility inside spectral_dump_phyerr_data()
1800 	 * and supporting functions.
1801 	 */
1802 	if (spectral_debug_level & DEBUG_SPECTRAL2)
1803 		target_if_spectral_dump_phyerr_data_gen2(
1804 					data, datalen,
1805 					spectral->is_160_format);
1806 
1807 	if (spectral_debug_level & DEBUG_SPECTRAL4) {
1808 		target_if_spectral_dump_phyerr_data_gen2(
1809 					data, datalen,
1810 					spectral->is_160_format);
1811 		spectral_debug_level = DEBUG_SPECTRAL;
1812 	}
1813 
1814 	if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1815 		/*
1816 		 * EV# 118023: We tentatively disable the below print
1817 		 * and provide stats instead.
1818 		 */
1819 		spectral->diag_stats.spectral_mismatch++;
1820 		return -EPERM;
1821 	}
1822 
1823 	OS_MEMZERO(&params, sizeof(params));
1824 	/* Gen 2 only supports normal Spectral scan currently */
1825 	params.smode = SPECTRAL_SCAN_MODE_NORMAL;
1826 
1827 	if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1828 		if (spectral->is_160_format) {
1829 			segid = *((SPECTRAL_SEGID_INFO *)(
1830 				  (uint8_t *)ptlv +
1831 				  sizeof(struct spectral_phyerr_tlv_gen2) +
1832 				  sizeof(struct spectral_phyerr_hdr_gen2)));
1833 
1834 			if (segid != 0) {
1835 				struct spectral_diag_stats *p_diag_stats =
1836 					&spectral->diag_stats;
1837 				p_diag_stats->spectral_vhtseg1id_mismatch++;
1838 				return -EPERM;
1839 			}
1840 		}
1841 
1842 		target_if_process_sfft_report_gen2(ptlv, ptlv->length,
1843 						   &search_fft_info);
1844 
1845 		tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
1846 
1847 		combined_rssi = p_rfqual->rssi_comb;
1848 
1849 		if (spectral->upper_is_control)
1850 			rssi_up = control_rssi;
1851 		else
1852 			rssi_up = extension_rssi;
1853 
1854 		if (spectral->lower_is_control)
1855 			rssi_low = control_rssi;
1856 		else
1857 			rssi_low = extension_rssi;
1858 
1859 		params.rssi = p_rfqual->rssi_comb;
1860 		params.lower_rssi = rssi_low;
1861 		params.upper_rssi = rssi_up;
1862 
1863 		if (spectral->sc_spectral_noise_pwr_cal) {
1864 			params.chain_ctl_rssi[0] =
1865 			    p_rfqual->pc_rssi_info[0].rssi_pri20;
1866 			params.chain_ctl_rssi[1] =
1867 			    p_rfqual->pc_rssi_info[1].rssi_pri20;
1868 			params.chain_ctl_rssi[2] =
1869 			    p_rfqual->pc_rssi_info[2].rssi_pri20;
1870 			params.chain_ext_rssi[0] =
1871 			    p_rfqual->pc_rssi_info[0].rssi_sec20;
1872 			params.chain_ext_rssi[1] =
1873 			    p_rfqual->pc_rssi_info[1].rssi_sec20;
1874 			params.chain_ext_rssi[2] =
1875 			    p_rfqual->pc_rssi_info[2].rssi_sec20;
1876 		}
1877 
1878 		/*
1879 		 * XXX : This actually depends on the programmed chain mask
1880 		 *       This value decides the per-chain enable mask to select
1881 		 *       the input ADC for search FTT.
1882 		 *       For modes upto VHT80, if more than one chain is
1883 		 *       enabled, the max valid chain
1884 		 *       is used. LSB corresponds to chain zero.
1885 		 *       For VHT80_80 and VHT160, the lowest enabled chain is
1886 		 *       used for primary
1887 		 *       detection and highest enabled chain is used for
1888 		 *       secondary detection.
1889 		 *
1890 		 * XXX : The current algorithm do not use these control and
1891 		 *       extension channel
1892 		 *       Instead, it just relies on the combined RSSI values
1893 		 *       only.
1894 		 *       For fool-proof detection algorithm, we should take
1895 		 *       these RSSI values in to account.
1896 		 *       This is marked for future enhancements.
1897 		 */
1898 		chn_idx_highest_enabled =
1899 		   ((spectral->params[params.smode].ss_chn_mask & 0x8) ? 3 :
1900 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 :
1901 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 0);
1902 		chn_idx_lowest_enabled =
1903 		   ((spectral->params[params.smode].ss_chn_mask & 0x1) ? 0 :
1904 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 :
1905 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 3);
1906 		control_rssi = (uint8_t)
1907 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
1908 		extension_rssi = (uint8_t)
1909 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
1910 
1911 		params.bwinfo = 0;
1912 		params.tstamp = 0;
1913 		params.max_mag = p_sfft->peak_mag;
1914 
1915 		params.max_index = p_sfft->peak_inx;
1916 		params.max_exp = 0;
1917 		params.peak = 0;
1918 		params.bin_pwr_data = (uint8_t *)pfft;
1919 		params.freq = p_sops->get_current_channel(spectral,
1920 							  params.smode);
1921 		params.freq_loading = 0;
1922 
1923 		params.interf_list.count = 0;
1924 		params.max_lower_index = 0;
1925 		params.max_upper_index = 0;
1926 		params.nb_lower = 0;
1927 		params.nb_upper = 0;
1928 		/*
1929 		 * For modes upto VHT80, the noise floor is populated with the
1930 		 * one corresponding
1931 		 * to the highest enabled antenna chain
1932 		 */
1933 		params.noise_floor =
1934 		    p_rfqual->noise_floor[chn_idx_highest_enabled];
1935 		params.datalen = ptlv->length;
1936 		params.pwr_count = ptlv->length -
1937 		    sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen;
1938 		params.tstamp = (tsf64 & SPECTRAL_TSMASK);
1939 
1940 		acs_stats->ctrl_nf = params.noise_floor;
1941 		acs_stats->ext_nf = params.noise_floor;
1942 		acs_stats->nfc_ctl_rssi = control_rssi;
1943 		acs_stats->nfc_ext_rssi = extension_rssi;
1944 
1945 		if (spectral->is_160_format &&
1946 		    is_ch_width_160_or_80p80(ch_width)) {
1947 			/*
1948 			 * We expect to see one more Search FFT report, and it
1949 			 * should be equal in size to the current one.
1950 			 */
1951 			if (datalen < (
1952 				2 * (
1953 				sizeof(struct spectral_phyerr_tlv_gen2) +
1954 				ptlv->length))) {
1955 				struct spectral_diag_stats *p_diag_stats =
1956 					&spectral->diag_stats;
1957 				p_diag_stats->spectral_sec80_sfft_insufflen++;
1958 				return -EPERM;
1959 			}
1960 
1961 			ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1962 				      data +
1963 				      sizeof(struct spectral_phyerr_tlv_gen2) +
1964 				      ptlv->length);
1965 
1966 			if (ptlv_sec80->signature !=
1967 			    SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1968 				spectral->diag_stats.spectral_mismatch++;
1969 				return -EPERM;
1970 			}
1971 
1972 			if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1973 				spectral->diag_stats.spectral_no_sec80_sfft++;
1974 				return -EPERM;
1975 			}
1976 
1977 			segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
1978 				(uint8_t *)ptlv_sec80 +
1979 				sizeof(struct spectral_phyerr_tlv_gen2) +
1980 				sizeof(struct spectral_phyerr_hdr_gen2)));
1981 
1982 			if (segid_sec80 != 1) {
1983 				struct spectral_diag_stats *p_diag_stats =
1984 					&spectral->diag_stats;
1985 				p_diag_stats->spectral_vhtseg2id_mismatch++;
1986 				return -EPERM;
1987 			}
1988 
1989 			params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
1990 			params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
1991 
1992 			target_if_process_sfft_report_gen2(
1993 				ptlv_sec80,
1994 				ptlv_sec80->length,
1995 				&search_fft_info_sec80);
1996 
1997 			pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
1998 				((uint8_t *)ptlv_sec80) +
1999 				sizeof(struct spectral_phyerr_tlv_gen2) +
2000 				sizeof(struct spectral_phyerr_hdr_gen2) +
2001 				segid_skiplen);
2002 
2003 			/* XXX: Confirm. TBD at SoD. */
2004 			params.rssi_sec80 = p_rfqual->rssi_comb;
2005 			if (spectral->is_sec80_rssi_war_required)
2006 				params.rssi_sec80 =
2007 				    target_if_get_combrssi_sec80_seg_gen2
2008 				    (spectral, &search_fft_info_sec80);
2009 			/* XXX: Determine dynamically. TBD at SoD. */
2010 			/*
2011 			 * For VHT80_80/VHT160, the noise floor for primary
2012 			 * 80MHz segment is populated with the
2013 			 * lowest enabled antenna chain and the noise floor for
2014 			 * secondary 80MHz segment is populated
2015 			 * with the highest enabled antenna chain
2016 			 */
2017 			params.noise_floor_sec80 =
2018 			    p_rfqual->noise_floor[chn_idx_highest_enabled];
2019 			params.noise_floor =
2020 			    p_rfqual->noise_floor[chn_idx_lowest_enabled];
2021 
2022 			params.max_mag_sec80 = p_sfft_sec80->peak_mag;
2023 			params.max_index_sec80 = p_sfft_sec80->peak_inx;
2024 			/* XXX Does this definition of datalen *still hold? */
2025 			params.datalen_sec80 = ptlv_sec80->length;
2026 			params.pwr_count_sec80 =
2027 			    ptlv_sec80->length -
2028 			    sizeof(struct spectral_phyerr_hdr_gen2) -
2029 			    segid_skiplen;
2030 			params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80;
2031 		}
2032 		qdf_mem_copy(&params.classifier_params,
2033 			     &spectral->classifier_params,
2034 			     sizeof(struct spectral_classifier_params));
2035 
2036 		target_if_spectral_log_SAMP_param(&params);
2037 		target_if_spectral_create_samp_msg(spectral, &params);
2038 	}
2039 
2040 	return 0;
2041 }
2042 #endif /* OPTIMIZED_SAMP_MESSAGE */
2043 
2044 int
2045 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr)
2046 {
2047 	uint32_t a = 0;
2048 	uint32_t b = 0;
2049 
2050 	qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int));
2051 	qdf_mem_copy(&b,
2052 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
2053 		     sizeof(int));
2054 
2055 	spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a);
2056 	spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b);
2057 	return 0;
2058 }
2059 
2060 int8_t
2061 target_if_get_combrssi_sec80_seg_gen2(
2062 	struct target_if_spectral *spectral,
2063 	struct spectral_search_fft_info_gen2 *p_sfft_sec80)
2064 {
2065 	uint32_t avgpwr_db = 0;
2066 	uint32_t total_gain_db = 0;
2067 	uint32_t offset = 0;
2068 	int8_t comb_rssi = 0;
2069 
2070 	/* Obtain required parameters for algorithm from search FFT report */
2071 	avgpwr_db = p_sfft_sec80->avgpwr_db;
2072 	total_gain_db = p_sfft_sec80->total_gain_info;
2073 
2074 	/* Calculate offset */
2075 	offset = target_if_get_offset_swar_sec80(
2076 			spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL]);
2077 
2078 	/* Calculate RSSI */
2079 	comb_rssi = ((avgpwr_db - total_gain_db) + offset);
2080 
2081 	return comb_rssi;
2082 }
2083 
2084 int
2085 target_if_spectral_dump_tlv_gen2(
2086 	struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format)
2087 {
2088 	int ret = 0;
2089 
2090 	/*
2091 	 * TODO : Do not delete the following print
2092 	 *        The scripts used to validate Spectral depend on this Print
2093 	 */
2094 	spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)",
2095 		       ptlv->length, ptlv->length);
2096 
2097 	switch (ptlv->tag) {
2098 	case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
2099 		ret =
2100 		    target_if_dump_summary_report_gen2(
2101 			ptlv, ptlv->length, is_160_format);
2102 		break;
2103 
2104 	case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
2105 		ret =
2106 		    target_if_dump_sfft_report_gen2(ptlv, ptlv->length,
2107 						    is_160_format);
2108 		break;
2109 
2110 	case TLV_TAG_ADC_REPORT_GEN2:
2111 		ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length);
2112 		break;
2113 
2114 	default:
2115 		spectral_warn("INVALID TLV");
2116 		ret = -1;
2117 		break;
2118 	}
2119 
2120 	return ret;
2121 }
2122 
2123 int
2124 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen,
2125 					 bool is_160_format)
2126 {
2127 	struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
2128 	uint32_t bytes_processed = 0;
2129 	uint32_t bytes_remaining = datalen;
2130 	uint32_t curr_tlv_complete_size = 0;
2131 
2132 	if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) {
2133 		spectral_err("Total PHY error data length %u too short to contain any TLVs",
2134 			     datalen);
2135 		return -EPERM;
2136 	}
2137 
2138 	while (bytes_processed < datalen) {
2139 		if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) {
2140 			spectral_err("Remaining PHY error data length %u too short to contain a TLV",
2141 				     bytes_remaining);
2142 			return -EPERM;
2143 		}
2144 
2145 		ptlv = (struct spectral_phyerr_tlv_gen2 *)(data +
2146 							   bytes_processed);
2147 
2148 		if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
2149 			spectral_err("Invalid signature 0x%x!",
2150 				     ptlv->signature);
2151 			return -EPERM;
2152 		}
2153 
2154 		curr_tlv_complete_size =
2155 			sizeof(struct spectral_phyerr_tlv_gen2) +
2156 			ptlv->length;
2157 
2158 		if (curr_tlv_complete_size > bytes_remaining) {
2159 			spectral_err("TLV size %d greater than number of bytes remaining %d",
2160 				     curr_tlv_complete_size, bytes_remaining);
2161 			return -EPERM;
2162 		}
2163 
2164 		if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
2165 			return -EPERM;
2166 
2167 		bytes_processed += curr_tlv_complete_size;
2168 		bytes_remaining = datalen - bytes_processed;
2169 	}
2170 
2171 	return 0;
2172 }
2173 
2174 #ifdef DIRECT_BUF_RX_ENABLE
2175 /**
2176  * target_if_get_spectral_mode() - Get Spectral scan mode corresponding to a
2177  * detector id
2178  * @detector_id: detector id in the Spectral report
2179  * @rparams: pointer to report params object
2180  *
2181  * Helper API to get Spectral scan mode from the detector ID. This mapping is
2182  * target specific.
2183  *
2184  * Return: Spectral scan mode
2185  */
2186 static enum spectral_scan_mode
2187 target_if_get_spectral_mode(enum spectral_detector_id detector_id,
2188 			    struct spectral_report_params *rparams)
2189 {
2190 	if (detector_id >= SPECTRAL_DETECTOR_ID_MAX) {
2191 		spectral_err_rl("Invalid detector id %d", detector_id);
2192 		return SPECTRAL_SCAN_MODE_INVALID;
2193 	}
2194 
2195 	return rparams->detid_mode_table[detector_id];
2196 }
2197 
2198 /**
2199  * target_if_spectral_get_bin_count_after_len_adj() - Get number of FFT bins in
2200  * Spectral FFT report
2201  * @fft_bin_len: FFT bin length reported by target
2202  * @rpt_mode: Spectral report mode
2203  * @swar: Spectral FFT bin length adjustments SWAR parameters
2204  * @fft_bin_size: Size of one FFT bin in bytes
2205  *
2206  * Get actual number of FFT bins in the FFT report after adjusting the length
2207  * by applying the SWARs for getting correct length.
2208  *
2209  * Return: FFT bin count
2210  */
2211 static size_t
2212 target_if_spectral_get_bin_count_after_len_adj(
2213 				size_t fft_bin_len, uint8_t rpt_mode,
2214 				struct spectral_fft_bin_len_adj_swar *swar,
2215 				size_t *fft_bin_size)
2216 {
2217 	size_t fft_bin_count = fft_bin_len;
2218 
2219 	if (rpt_mode == 1 && swar->null_fftbin_adj) {
2220 		/*
2221 		 * No FFT bins are expected. Explicitly set FFT bin
2222 		 * count to 0.
2223 		 */
2224 		fft_bin_count = 0;
2225 		*fft_bin_size = 0;
2226 	} else {
2227 		/*
2228 		 * Divide fft bin length by appropriate factor depending
2229 		 * on the value of fftbin_size_war.
2230 		 */
2231 		switch (swar->fftbin_size_war) {
2232 		case SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE:
2233 			fft_bin_count >>= 2;
2234 			*fft_bin_size = 4;
2235 			break;
2236 		case SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE:
2237 			fft_bin_count >>= 1;
2238 			*fft_bin_size = 2;
2239 			/* Ideally we should be dividing fft bin length
2240 			 * by 2. Due to a HW bug, actual length is two
2241 			 * times the expected length.
2242 			 */
2243 			if (swar->packmode_fftbin_size_adj)
2244 				fft_bin_count >>= 1;
2245 			break;
2246 		case SPECTRAL_FFTBIN_SIZE_NO_WAR:
2247 			*fft_bin_size = 1;
2248 			/* No length adjustment */
2249 			break;
2250 		default:
2251 			qdf_assert_always(0);
2252 		}
2253 
2254 		if (rpt_mode == 2 && swar->inband_fftbin_size_adj)
2255 			fft_bin_count >>= 1;
2256 	}
2257 
2258 	return fft_bin_count;
2259 }
2260 
2261 #ifndef OPTIMIZED_SAMP_MESSAGE
2262 /**
2263  * target_if_process_sfft_report_gen3() - Process Search FFT Report for gen3
2264  * @p_fft_report: Pointer to fft report
2265  * @p_sfft: Pointer to search fft report
2266  * @rparams: pointer to report params object
2267  *
2268  * Process Search FFT Report for gen3
2269  *
2270  * Return: Success/Failure
2271  */
2272 static int
2273 target_if_process_sfft_report_gen3(
2274 	struct spectral_phyerr_fft_report_gen3 *p_fft_report,
2275 	struct spectral_search_fft_info_gen3 *p_sfft,
2276 	struct spectral_report_params *rparams)
2277 {
2278 	int32_t peak_sidx = 0;
2279 	int32_t peak_mag;
2280 
2281 	qdf_assert_always(p_fft_report);
2282 	qdf_assert_always(p_sfft);
2283 	qdf_assert_always(rparams);
2284 
2285 	/*
2286 	 * For simplicity, everything is defined as uint32_t (except one).
2287 	 * Proper code will later use the right sizes.
2288 	 */
2289 	/*
2290 	 * For easy comparision between MDK team and OS team, the MDK script
2291 	 * variable names have been used
2292 	 */
2293 
2294 	/* Populate the Search FFT Info */
2295 	p_sfft->timestamp = p_fft_report->fft_timestamp;
2296 
2297 	p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a,
2298 					       2, 0);
2299 	p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2);
2300 
2301 	switch (rparams->version) {
2302 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
2303 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
2304 						       12, 5);
2305 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17);
2306 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28);
2307 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
2308 						       9, 0);
2309 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
2310 							 8, 9);
2311 		break;
2312 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
2313 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
2314 						       14, 5);
2315 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 19);
2316 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_b, 3, 0);
2317 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
2318 						       9, 3);
2319 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
2320 							 8, 12);
2321 		break;
2322 	default:
2323 		qdf_assert_always(0);
2324 	}
2325 
2326 	p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
2327 
2328 	p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
2329 						   8, 0);
2330 	peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8);
2331 	p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
2332 	p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
2333 					     7, 18);
2334 	p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
2335 					     7, 25);
2336 
2337 	return 0;
2338 }
2339 #endif
2340 
2341 /**
2342  * target_if_dump_fft_report_gen3() - Dump FFT Report for gen3
2343  * @spectral: Pointer to Spectral object
2344  * @smode: Spectral scan mode
2345  * @p_fft_report: Pointer to fft report
2346  * @p_sfft: Pointer to search fft report
2347  *
2348  * Dump FFT Report for gen3
2349  *
2350  * Return: void
2351  */
2352 static void
2353 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral,
2354 			enum spectral_scan_mode smode,
2355 			struct spectral_phyerr_fft_report_gen3 *p_fft_report,
2356 			struct spectral_search_fft_info_gen3 *p_sfft)
2357 {
2358 	size_t fft_hdr_length;
2359 	size_t report_len;
2360 	size_t fft_bin_len;
2361 	size_t fft_bin_count;
2362 	size_t fft_bin_size;
2363 	size_t fft_bin_len_inband_tfer = 0;
2364 	uint8_t *fft_bin_buf = NULL;
2365 	size_t fft_bin_buf_size;
2366 	uint8_t tag, signature;
2367 
2368 	qdf_assert_always(spectral);
2369 
2370 	/* There won't be FFT report/bins in report mode 0, so return */
2371 	if (!spectral->params[smode].ss_rpt_mode)
2372 		return;
2373 
2374 	fft_hdr_length = get_bitfield(
2375 				p_fft_report->fft_hdr_lts,
2376 				SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
2377 				SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
2378 
2379 	tag = get_bitfield(p_fft_report->fft_hdr_lts,
2380 			   SPECTRAL_REPORT_LTS_TAG_SIZE_GEN3,
2381 			   SPECTRAL_REPORT_LTS_TAG_POS_GEN3);
2382 
2383 	signature = get_bitfield(p_fft_report->fft_hdr_lts,
2384 				 SPECTRAL_REPORT_LTS_SIGNATURE_SIZE_GEN3,
2385 				 SPECTRAL_REPORT_LTS_SIGNATURE_POS_GEN3);
2386 
2387 	report_len = (fft_hdr_length + 8);
2388 	fft_bin_len = fft_hdr_length - spectral->rparams.fft_report_hdr_len;
2389 	fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
2390 			fft_bin_len,
2391 			spectral->params[smode].ss_rpt_mode,
2392 			&spectral->len_adj_swar, &fft_bin_size);
2393 
2394 	if ((spectral->params[smode].ss_rpt_mode == 2) &&
2395 	    spectral->len_adj_swar.inband_fftbin_size_adj)
2396 		fft_bin_len_inband_tfer = fft_bin_len >> 1;
2397 
2398 	spectral_debug("Spectral FFT Report");
2399 	spectral_debug("fft_timestamp = 0x%x", p_fft_report->fft_timestamp);
2400 	spectral_debug("fft_hdr_length = %zu(32 bit words)",
2401 		       fft_hdr_length >> 2);
2402 	spectral_debug("fft_hdr_tag = 0x%x", tag);
2403 	spectral_debug("fft_hdr_sig = 0x%x", signature);
2404 
2405 	spectral_debug("Length field in search fft report is %zu(0x%zx) bytes",
2406 		       fft_hdr_length, fft_hdr_length);
2407 	spectral_debug("Total length of search fft report is %zu(0x%zx) bytes",
2408 		       report_len, report_len);
2409 	spectral_debug("Target reported fftbins in report is %zu(0x%zx)",
2410 		       fft_bin_len, fft_bin_len);
2411 
2412 	if ((spectral->params[smode].ss_rpt_mode == 1) &&
2413 	    spectral->len_adj_swar.null_fftbin_adj)
2414 		spectral_debug("WAR: Considering number of FFT bins as 0");
2415 	else if ((spectral->params[smode].ss_rpt_mode == 2) &&
2416 		 spectral->len_adj_swar.inband_fftbin_size_adj) {
2417 		spectral_debug("FW fftbins actually transferred (in-band report mode) %zu(0x%zx)",
2418 			       fft_bin_len_inband_tfer,
2419 			       fft_bin_len_inband_tfer);
2420 	}
2421 
2422 	spectral_debug("Actual number of fftbins in report is %zu(0x%zx)",
2423 		       fft_bin_count, fft_bin_count);
2424 
2425 	spectral_debug("fft_detector_id = %u", p_sfft->fft_detector_id);
2426 	spectral_debug("fft_num = %u", p_sfft->fft_num);
2427 	spectral_debug("fft_radar_check = %u", p_sfft->fft_radar_check);
2428 	spectral_debug("fft_peak_sidx = %d",  p_sfft->fft_peak_sidx);
2429 	spectral_debug("fft_chn_idx = %u", p_sfft->fft_chn_idx);
2430 	spectral_debug("fft_base_pwr_db = %u", p_sfft->fft_base_pwr_db);
2431 	spectral_debug("fft_total_gain_db = %u", p_sfft->fft_total_gain_db);
2432 	spectral_debug("fft_num_str_bins_ib = %u", p_sfft->fft_num_str_bins_ib);
2433 	spectral_debug("fft_peak_mag = %d", p_sfft->fft_peak_mag);
2434 	spectral_debug("fft_avgpwr_db = %u", p_sfft->fft_avgpwr_db);
2435 	spectral_debug("fft_relpwr_db = %u", p_sfft->fft_relpwr_db);
2436 
2437 	fft_bin_buf_size = fft_bin_count;
2438 
2439 	if (fft_bin_count > 0) {
2440 		int idx;
2441 
2442 		if (spectral->len_adj_swar.fftbin_size_war ==
2443 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) {
2444 			uint32_t *binptr_32 = (uint32_t *)&p_fft_report->buf;
2445 			uint16_t *fft_bin_buf_16 = NULL;
2446 
2447 			/* Useful width of FFT bin is 10 bits, increasing it to
2448 			 * byte boundary makes it 2 bytes. Hence, buffer to be
2449 			 * allocated should be of size fft_bin_count
2450 			 * multiplied by 2.
2451 			 */
2452 			fft_bin_buf_size <<= 1;
2453 
2454 			fft_bin_buf_16 = (uint16_t *)qdf_mem_malloc(
2455 						fft_bin_buf_size);
2456 			if (!fft_bin_buf_16) {
2457 				spectral_err("Failed to allocate memory");
2458 				return;
2459 			}
2460 
2461 			for (idx = 0; idx < fft_bin_count; idx++)
2462 				fft_bin_buf_16[idx] =
2463 					*((uint16_t *)binptr_32++);
2464 
2465 			fft_bin_buf = (uint8_t *)fft_bin_buf_16;
2466 		} else if (spectral->len_adj_swar.fftbin_size_war ==
2467 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
2468 			uint16_t *binptr_16 = (uint16_t *)&p_fft_report->buf;
2469 			uint16_t *fft_bin_buf_16 = NULL;
2470 
2471 			/* Useful width of FFT bin is 10 bits, increasing it to
2472 			 * byte boundary makes it 2 bytes. Hence, buffer to be
2473 			 * allocated should be of size fft_bin_count
2474 			 * multiplied by 2.
2475 			 */
2476 			fft_bin_buf_size <<= 1;
2477 
2478 			fft_bin_buf_16 = (uint16_t *)qdf_mem_malloc(
2479 						fft_bin_buf_size);
2480 			if (!fft_bin_buf_16) {
2481 				spectral_err("Failed to allocate memory");
2482 				return;
2483 			}
2484 
2485 			for (idx = 0; idx < fft_bin_count; idx++)
2486 				fft_bin_buf_16[idx] = *(binptr_16++);
2487 
2488 			fft_bin_buf = (uint8_t *)fft_bin_buf_16;
2489 		} else {
2490 			fft_bin_buf = (uint8_t *)&p_fft_report->buf;
2491 		}
2492 
2493 		spectral_debug("FFT bin buffer size = %zu", fft_bin_buf_size);
2494 		spectral_debug("FFT bins:");
2495 		target_if_spectral_hexdump(fft_bin_buf, fft_bin_buf_size);
2496 		if ((spectral->len_adj_swar.fftbin_size_war !=
2497 				SPECTRAL_FFTBIN_SIZE_NO_WAR) && fft_bin_buf)
2498 			qdf_mem_free(fft_bin_buf);
2499 	}
2500 }
2501 #endif
2502 
2503 #ifdef OPTIMIZED_SAMP_MESSAGE
2504 QDF_STATUS
2505 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
2506 				       enum spectral_scan_mode smode,
2507 				       uint8_t detector_id) {
2508 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2509 
2510 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2511 		spectral_err_rl("Invalid Spectral mode %d", smode);
2512 		return QDF_STATUS_E_INVAL;
2513 	}
2514 
2515 	if (!is_ch_width_160_or_80p80(spectral->report_info[smode].sscan_bw)) {
2516 		spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
2517 				spectral->report_info[smode].sscan_bw, smode);
2518 		return QDF_STATUS_E_FAILURE;
2519 	}
2520 
2521 	switch (spectral->state_160mhz_delivery[smode]) {
2522 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
2523 		if (detector_id == SPECTRAL_DETECTOR_ID_0)
2524 			spectral->state_160mhz_delivery[smode] =
2525 				SPECTRAL_REPORT_WAIT_SECONDARY80;
2526 		else {
2527 			status = QDF_STATUS_E_FAILURE;
2528 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
2529 		}
2530 		break;
2531 
2532 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
2533 		if (detector_id == SPECTRAL_DETECTOR_ID_1)
2534 			spectral->state_160mhz_delivery[smode] =
2535 				SPECTRAL_REPORT_WAIT_PRIMARY80;
2536 		else {
2537 			spectral->state_160mhz_delivery[smode] =
2538 				SPECTRAL_REPORT_WAIT_PRIMARY80;
2539 			status = QDF_STATUS_E_FAILURE;
2540 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
2541 		}
2542 		break;
2543 
2544 	default:
2545 		break;
2546 	}
2547 
2548 	return status;
2549 }
2550 #else
2551 QDF_STATUS
2552 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
2553 				       enum spectral_scan_mode smode,
2554 				       uint8_t detector_id) {
2555 	QDF_STATUS status = QDF_STATUS_SUCCESS;
2556 
2557 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2558 		spectral_err_rl("Invalid Spectral mode %d", smode);
2559 		return QDF_STATUS_E_INVAL;
2560 	}
2561 
2562 	if (!is_ch_width_160_or_80p80(spectral->ch_width[smode])) {
2563 		spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
2564 				spectral->ch_width[smode], smode);
2565 		return QDF_STATUS_E_FAILURE;
2566 	}
2567 
2568 	switch (spectral->state_160mhz_delivery[smode]) {
2569 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
2570 		if (detector_id == SPECTRAL_DETECTOR_ID_0)
2571 			spectral->state_160mhz_delivery[smode] =
2572 				SPECTRAL_REPORT_RX_PRIMARY80;
2573 		else {
2574 			status = QDF_STATUS_E_FAILURE;
2575 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
2576 		}
2577 		break;
2578 
2579 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
2580 		if (detector_id == SPECTRAL_DETECTOR_ID_1)
2581 			spectral->state_160mhz_delivery[smode] =
2582 				SPECTRAL_REPORT_RX_SECONDARY80;
2583 		else {
2584 			spectral->state_160mhz_delivery[smode] =
2585 				SPECTRAL_REPORT_WAIT_PRIMARY80;
2586 			status = QDF_STATUS_E_FAILURE;
2587 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
2588 		}
2589 		break;
2590 
2591 	case SPECTRAL_REPORT_RX_SECONDARY80:
2592 		/* We don't care about detector id in this state. */
2593 		reset_160mhz_delivery_state_machine(spectral, smode);
2594 		break;
2595 
2596 	case SPECTRAL_REPORT_RX_PRIMARY80:
2597 		/* We don't care about detector id in this state */
2598 		spectral->state_160mhz_delivery[smode] =
2599 				SPECTRAL_REPORT_WAIT_SECONDARY80;
2600 		break;
2601 
2602 	default:
2603 		break;
2604 	}
2605 
2606 	return status;
2607 }
2608 #endif /* OPTIMIZED_SAMP_MESSAGE */
2609 
2610 #ifdef DIRECT_BUF_RX_ENABLE
2611 /**
2612  * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector
2613  * ID from Spectral summary report
2614  * @data: Pointer to Spectral summary report
2615  *
2616  * Return: Detector ID
2617  */
2618 static uint8_t
2619 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data) {
2620 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
2621 	uint8_t detector_id;
2622 
2623 	qdf_assert_always(data);
2624 
2625 	psscan_summary_report =
2626 		(struct spectral_sscan_summary_report_gen3 *)data;
2627 
2628 	detector_id = get_bitfield(
2629 			psscan_summary_report->hdr_a,
2630 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
2631 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
2632 
2633 	return detector_id;
2634 }
2635 
2636 #ifndef OPTIMIZED_SAMP_MESSAGE
2637 /**
2638  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
2639  * report
2640  * @data: Pointer to Spectral summary report
2641  * @fields: Pointer to structure to be populated with extracted fields
2642  * @rparams: Pointer to structure with Spectral report params
2643  *
2644  * Consume Spectral summary report for gen3
2645  *
2646  * Return: void
2647  */
2648 static void
2649 target_if_consume_sscan_summary_report_gen3(
2650 				uint8_t *data,
2651 				struct sscan_report_fields_gen3 *fields,
2652 				struct spectral_report_params *rparams) {
2653 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
2654 
2655 	qdf_assert_always(data);
2656 	qdf_assert_always(fields);
2657 	qdf_assert_always(rparams);
2658 
2659 	psscan_summary_report =
2660 		(struct spectral_sscan_summary_report_gen3 *)data;
2661 
2662 	fields->sscan_agc_total_gain = get_bitfield(
2663 			psscan_summary_report->hdr_a,
2664 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
2665 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
2666 	fields->inband_pwr_db = get_bitfield(
2667 			psscan_summary_report->hdr_a,
2668 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
2669 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
2670 	fields->sscan_pri80 = get_bitfield(
2671 			psscan_summary_report->hdr_a,
2672 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
2673 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
2674 
2675 	switch (rparams->version) {
2676 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
2677 		fields->sscan_gainchange = get_bitfield(
2678 			psscan_summary_report->hdr_b,
2679 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
2680 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
2681 		break;
2682 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
2683 		fields->sscan_gainchange = get_bitfield(
2684 			psscan_summary_report->hdr_c,
2685 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
2686 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
2687 		break;
2688 	default:
2689 		qdf_assert_always(0);
2690 	}
2691 }
2692 #endif
2693 
2694 /**
2695  * target_if_verify_sig_and_tag_gen3() - Verify tag and signature
2696  *                                       of spectral report
2697  * @spectral: Pointer to spectral object
2698  * @data: Pointer to spectral summary report
2699  * @exp_tag: iexpected tag value
2700  *
2701  * Process fft report for gen3
2702  *
2703  * Return: SUCCESS/FAILURE
2704  */
2705 static int
2706 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral,
2707 				  uint8_t *data, uint8_t exp_tag)
2708 {
2709 	uint8_t tag = 0;
2710 	uint8_t signature = 0;
2711 	uint32_t lts;
2712 
2713 	lts = *((uint32_t *)(data + SPECTRAL_PHYERR_HDR_LTS_POS));
2714 	/* Peek into the data to figure out whether
2715 	 *      1) Signature matches the expected value
2716 	 *      2) What is inside the package (TAG ID is used for finding this)
2717 	 */
2718 	tag = get_bitfield(lts,
2719 			   SPECTRAL_REPORT_LTS_TAG_SIZE_GEN3,
2720 			   SPECTRAL_REPORT_LTS_TAG_POS_GEN3);
2721 
2722 	signature = get_bitfield(lts,
2723 				 SPECTRAL_REPORT_LTS_SIGNATURE_SIZE_GEN3,
2724 				 SPECTRAL_REPORT_LTS_SIGNATURE_POS_GEN3);
2725 
2726 
2727 	if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
2728 		spectral->diag_stats.spectral_mismatch++;
2729 		return -EINVAL;
2730 	}
2731 
2732 	if (tag != exp_tag) {
2733 		spectral->diag_stats.spectral_mismatch++;
2734 		return -EINVAL;
2735 	}
2736 
2737 	return 0;
2738 }
2739 
2740 static uint8_t
2741 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)
2742 {
2743 	uint8_t idx;
2744 
2745 	for (idx = 0; idx < DBR_MAX_CHAINS; idx++) {
2746 		if (chainmask & 0x1)
2747 			break;
2748 		chainmask >>= 1;
2749 	}
2750 	return idx;
2751 }
2752 
2753 #ifdef DIRECT_BUF_RX_DEBUG
2754 static void target_if_spectral_check_buffer_poisoning(
2755 	struct target_if_spectral *spectral,
2756 	struct spectral_report *report,
2757 	int num_fft_bins, enum spectral_scan_mode smode)
2758 {
2759 	uint32_t *data;
2760 	size_t len;
2761 	size_t words_to_check =
2762 		sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
2763 	bool poisoned_words_found = false;
2764 
2765 	if (!spectral) {
2766 		spectral_err_rl("Spectral LMAC object is null");
2767 		return;
2768 	}
2769 
2770 	if (!spectral->dbr_buff_debug)
2771 		return;
2772 
2773 	if (!report) {
2774 		spectral_err_rl("Spectral report is null");
2775 		return;
2776 	}
2777 
2778 	/* Add search FFT report */
2779 	if (spectral->params[smode].ss_rpt_mode > 0)
2780 		words_to_check +=
2781 			sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
2782 
2783 	/* Now add the number of FFT bins */
2784 	if (spectral->params[smode].ss_rpt_mode > 1) {
2785 		/* Caller should take care to pass correct number of FFT bins */
2786 		if (spectral->len_adj_swar.fftbin_size_war ==
2787 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
2788 			words_to_check += num_fft_bins;
2789 		else if (spectral->len_adj_swar.fftbin_size_war ==
2790 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE)
2791 			words_to_check += (num_fft_bins >> 1);
2792 	}
2793 
2794 	data = (uint32_t *)report->data;
2795 	for (len = 0; len < words_to_check; ++len) {
2796 		if (*data == MEM_POISON_SIGNATURE) {
2797 			spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK",
2798 				     MEM_POISON_SIGNATURE,
2799 				     (len << 2), report->data);
2800 			poisoned_words_found = true;
2801 			break;
2802 		}
2803 		++data;
2804 	}
2805 
2806 	/* Crash the FW even if one word is poisoned */
2807 	if (poisoned_words_found) {
2808 		spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows",
2809 			     MEM_POISON_SIGNATURE);
2810 		target_if_spectral_hexdump((unsigned char *)report->data,
2811 					   words_to_check << 2);
2812 		spectral_err("Asserting the FW");
2813 		target_if_spectral_fw_hang(spectral);
2814 	}
2815 }
2816 
2817 #ifdef OPTIMIZED_SAMP_MESSAGE
2818 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2819 					 uint8_t *buf, uint32_t current_ts,
2820 					 uint8_t detector_id)
2821 {
2822 	if (!spectral) {
2823 		spectral_err_rl("Spectral LMAC object is null");
2824 		return;
2825 	}
2826 	if (detector_id >= MAX_DETECTORS_PER_PDEV) {
2827 		spectral_err_rl("Spectral detector_id %d exceeds range",
2828 				detector_id);
2829 		return;
2830 	}
2831 
2832 	if (!spectral->dbr_buff_debug)
2833 		return;
2834 
2835 	if (spectral->prev_tstamp[detector_id]) {
2836 		if (current_ts == spectral->prev_tstamp[detector_id]) {
2837 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
2838 				     current_ts, buf);
2839 			target_if_spectral_fw_hang(spectral);
2840 		}
2841 	}
2842 	spectral->prev_tstamp[detector_id] = current_ts;
2843 }
2844 #else
2845 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2846 					 uint8_t *buf, uint32_t current_ts)
2847 {
2848 	if (!spectral) {
2849 		spectral_err_rl("Spectral LMAC object is null");
2850 		return;
2851 	}
2852 
2853 	if (!spectral->dbr_buff_debug)
2854 		return;
2855 
2856 	if (spectral->prev_tstamp) {
2857 		if (current_ts == spectral->prev_tstamp) {
2858 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
2859 				     current_ts, buf);
2860 			target_if_spectral_fw_hang(spectral);
2861 		}
2862 	}
2863 	spectral->prev_tstamp = current_ts;
2864 }
2865 #endif /* OPTIMIZED_SAMP_MESSAGE */
2866 #else
2867 static void target_if_spectral_check_buffer_poisoning(
2868 	struct target_if_spectral *spectral,
2869 	struct spectral_report *report,
2870 	int num_fft_bins, enum spectral_scan_mode smode)
2871 {
2872 }
2873 
2874 #ifdef OPTIMIZED_SAMP_MESSAGE
2875 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2876 					 uint8_t *buf, uint32_t current_ts,
2877 					 uint8_t detector_id)
2878 {
2879 }
2880 #else
2881 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2882 					 uint8_t *buf, uint32_t current_ts)
2883 {
2884 }
2885 #endif /* OPTIMIZED_SAMP_MESSAGE */
2886 #endif
2887 
2888 /**
2889  * target_if_spectral_get_adjusted_timestamp() - Adjust Spectral time
2890  * stamp to account for reset in time stamp due to target reset
2891  * @twar: Spectral time stamp WAR related information
2892  * @raw_timestamp: Spectral time stamp reported by target
2893  * @reset_delay: Reset delay at target
2894  * @smode: Spectral scan mode
2895  *
2896  * Correct time stamp to account for reset in time stamp due to target reset
2897  *
2898  * Return: Adjusted time stamp
2899  */
2900 static uint32_t
2901 target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war *twar,
2902 					  uint32_t raw_timestamp,
2903 					  uint32_t reset_delay,
2904 					  enum spectral_scan_mode smode) {
2905 	qdf_assert_always(smode < SPECTRAL_SCAN_MODE_MAX);
2906 
2907 	if (reset_delay) {
2908 		enum spectral_scan_mode m =
2909 					SPECTRAL_SCAN_MODE_NORMAL;
2910 
2911 		/* Adjust the offset for all the Spectral modes.
2912 		 * Target will be sending the non zero reset delay for
2913 		 * the first Spectral report after reset. This delay is
2914 		 * common for all the Spectral modes.
2915 		 */
2916 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
2917 			twar->timestamp_war_offset[m] += (reset_delay +
2918 					twar->last_fft_timestamp[m]);
2919 		twar->target_reset_count++;
2920 	}
2921 	twar->last_fft_timestamp[smode] = raw_timestamp;
2922 
2923 	return raw_timestamp + twar->timestamp_war_offset[smode];
2924 }
2925 
2926 #ifdef BIG_ENDIAN_HOST
2927 QDF_STATUS target_if_byte_swap_spectral_headers_gen3(
2928 	 struct target_if_spectral *spectral,
2929 	 void *data)
2930 {
2931 	int i;
2932 	uint32_t *ptr32;
2933 	size_t words32;
2934 
2935 	qdf_assert_always(data);
2936 	qdf_assert_always(spectral);
2937 
2938 	ptr32 = (uint32_t *)data;
2939 
2940 	/* Summary Report */
2941 	words32 = sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
2942 	for (i = 0; i < words32; ++i) {
2943 		*ptr32 = qdf_le32_to_cpu(*ptr32);
2944 		++ptr32;
2945 	}
2946 
2947 	/* No need to swap the padding bytes */
2948 	ptr32 += (spectral->rparams.ssumaary_padding_bytes >> 2);
2949 
2950 	/* Search FFT Report */
2951 	words32 = sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
2952 	for (i = 0; i < words32; ++i) {
2953 		*ptr32 = qdf_le32_to_cpu(*ptr32);
2954 		++ptr32;
2955 	}
2956 
2957 	return QDF_STATUS_SUCCESS;
2958 }
2959 
2960 QDF_STATUS target_if_byte_swap_spectral_fft_bins_gen3(
2961 	struct spectral_fft_bin_len_adj_swar *swar,
2962 	void *bin_pwr_data, size_t num_fftbins)
2963 {
2964 	int i;
2965 	uint16_t *binptr_16;
2966 	uint32_t *binptr_32;
2967 
2968 	qdf_assert_always(bin_pwr_data);
2969 	qdf_assert_always(swar);
2970 
2971 	if (swar->fftbin_size_war ==
2972 			SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) {
2973 		binptr_32 = (uint32_t *)bin_pwr_data;
2974 
2975 		for (i = 0; i < num_fftbins; i++) {
2976 			/* Get the useful first 2 bytes of the DWORD */
2977 			binptr_16 = ((uint16_t *)binptr_32);
2978 			/* Byteswap and copy it back */
2979 			*binptr_16 = qdf_le16_to_cpu(*binptr_16);
2980 			++binptr_32; /* Go to next DWORD */
2981 		}
2982 	} else if (swar->fftbin_size_war ==
2983 			SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
2984 		binptr_16 = (uint16_t *)bin_pwr_data;
2985 
2986 		for (i = 0; i < num_fftbins; i++) {
2987 			/* Byteswap the FFT bin and copy it back */
2988 			*binptr_16 = qdf_le16_to_cpu(*binptr_16);
2989 			++binptr_16;
2990 		}
2991 	}
2992 
2993 	return QDF_STATUS_SUCCESS;
2994 }
2995 #endif /* BIG_ENDIAN_HOST */
2996 
2997 #ifdef OPTIMIZED_SAMP_MESSAGE
2998 /**
2999  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
3000  * report
3001  * @data: Pointer to Spectral summary report
3002  * @fields: Pointer to structure to be populated with extracted fields
3003  * @spectral: Pointer to spectral object
3004  *
3005  * Consume Spectral summary report for gen3
3006  *
3007  * Return: Success/Failure
3008  */
3009 static QDF_STATUS
3010 target_if_consume_sscan_summary_report_gen3(
3011 				uint8_t **data,
3012 				struct sscan_report_fields_gen3 *fields,
3013 				struct target_if_spectral *spectral)
3014 {
3015 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
3016 
3017 	if (!data) {
3018 		spectral_err_rl("Summary report buffer is null");
3019 		return QDF_STATUS_E_NULL_VALUE;
3020 	}
3021 
3022 	if (!fields) {
3023 		spectral_err_rl("Invalid pointer to Summary report fields");
3024 		return QDF_STATUS_E_NULL_VALUE;
3025 	}
3026 
3027 	if (!spectral) {
3028 		spectral_err_rl("Spectral LMAC object is null");
3029 		return QDF_STATUS_E_NULL_VALUE;
3030 	}
3031 
3032 	/* Validate Spectral scan summary report */
3033 	if (target_if_verify_sig_and_tag_gen3(
3034 			spectral, *data,
3035 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
3036 		spectral_err_rl("Wrong tag/sig in sscan summary");
3037 		return QDF_STATUS_E_FAILURE;
3038 	}
3039 
3040 	fields->sscan_detector_id =
3041 		target_if_get_detector_id_sscan_summary_report_gen3(*data);
3042 	if (fields->sscan_detector_id >=
3043 	    spectral->rparams.num_spectral_detectors) {
3044 		spectral->diag_stats.spectral_invalid_detector_id++;
3045 		spectral_err_rl("Invalid detector id %u, expected is 0 to %u",
3046 				fields->sscan_detector_id,
3047 				spectral->rparams.num_spectral_detectors);
3048 		return QDF_STATUS_E_FAILURE;
3049 	}
3050 
3051 	psscan_summary_report =
3052 		(struct spectral_sscan_summary_report_gen3 *)*data;
3053 
3054 	fields->sscan_agc_total_gain = get_bitfield(
3055 			psscan_summary_report->hdr_a,
3056 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
3057 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
3058 	fields->inband_pwr_db = get_bitfield(
3059 			psscan_summary_report->hdr_a,
3060 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
3061 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
3062 	fields->sscan_pri80 = get_bitfield(
3063 			psscan_summary_report->hdr_a,
3064 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
3065 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
3066 
3067 	switch (spectral->rparams.version) {
3068 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
3069 		fields->sscan_gainchange = get_bitfield(
3070 			psscan_summary_report->hdr_b,
3071 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
3072 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
3073 		break;
3074 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
3075 		fields->sscan_gainchange = get_bitfield(
3076 			psscan_summary_report->hdr_c,
3077 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
3078 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
3079 		break;
3080 	default:
3081 		qdf_assert_always(0);
3082 	}
3083 
3084 	/* Advance buf pointer to the search fft report */
3085 	*data += sizeof(struct spectral_sscan_summary_report_gen3);
3086 	*data += spectral->rparams.ssumaary_padding_bytes;
3087 
3088 	return QDF_STATUS_SUCCESS;
3089 }
3090 
3091 /**
3092  * target_if_process_sfft_report_gen3() - Validate and Process Search
3093  * FFT Report for gen3
3094  * @data: Pointer to Spectral FFT report
3095  * @p_sfft: Pointer to search fft report
3096  * @spectral: Pointer to spectral object
3097  * @sscan_detector_id: Spectral detector id extracted from Summary report
3098  * @reset_delay: Time taken for warm reset in usec
3099  *
3100  * Validate and Process Search FFT Report for gen3
3101  *
3102  * Return: Success/Failure
3103  */
3104 static QDF_STATUS
3105 target_if_process_sfft_report_gen3(
3106 	uint8_t *data,
3107 	struct spectral_search_fft_info_gen3 *p_sfft,
3108 	struct target_if_spectral *spectral,
3109 	enum spectral_detector_id sscan_detector_id,
3110 	uint32_t reset_delay)
3111 {
3112 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3113 	int32_t peak_sidx = 0;
3114 	int32_t peak_mag;
3115 	int fft_hdr_length = 0;
3116 	struct target_if_spectral_ops *p_sops;
3117 	enum spectral_scan_mode spectral_mode;
3118 	QDF_STATUS ret;
3119 
3120 	if (!data) {
3121 		spectral_err_rl("FFT report buffer is null");
3122 		return QDF_STATUS_E_NULL_VALUE;
3123 	}
3124 
3125 	if (!p_sfft) {
3126 		spectral_err_rl("Invalid pointer to Search FFT report info");
3127 		return QDF_STATUS_E_NULL_VALUE;
3128 	}
3129 
3130 	if (!spectral) {
3131 		spectral_err_rl("Spectral LMAC object is null");
3132 		return QDF_STATUS_E_NULL_VALUE;
3133 	}
3134 
3135 	/*
3136 	 * For easy comparision between MDK team and OS team, the MDK script
3137 	 * variable names have been used
3138 	 */
3139 
3140 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3141 
3142 	/* Validate Spectral search FFT report */
3143 	if (target_if_verify_sig_and_tag_gen3(
3144 			spectral, data, TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3145 		spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3146 				sscan_detector_id);
3147 		return QDF_STATUS_E_FAILURE;
3148 	}
3149 
3150 	p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3151 
3152 	fft_hdr_length = get_bitfield(
3153 			p_fft_report->fft_hdr_lts,
3154 			SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3155 			SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3156 	if (fft_hdr_length < 16) {
3157 		spectral_err("Wrong TLV length %u, detector id = %d",
3158 			     fft_hdr_length, sscan_detector_id);
3159 		return QDF_STATUS_E_FAILURE;
3160 	}
3161 
3162 	p_sfft->fft_detector_id = get_bitfield(
3163 					p_fft_report->hdr_a,
3164 					FFT_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
3165 					FFT_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
3166 
3167 	/* It is expected to have same detector id for
3168 	 * summary and fft report
3169 	 */
3170 	if (sscan_detector_id != p_sfft->fft_detector_id) {
3171 		spectral_err_rl("Different detid in ssummary(%u) and sfft(%u)",
3172 				sscan_detector_id, p_sfft->fft_detector_id);
3173 		return QDF_STATUS_E_FAILURE;
3174 	}
3175 
3176 	if (p_sfft->fft_detector_id >
3177 				spectral->rparams.num_spectral_detectors) {
3178 		spectral->diag_stats.spectral_invalid_detector_id++;
3179 		spectral_err("Invalid detector id %u, expected is 0 to %u",
3180 			     p_sfft->fft_detector_id,
3181 			     spectral->rparams.num_spectral_detectors);
3182 		return QDF_STATUS_E_FAILURE;
3183 	}
3184 
3185 	spectral_mode = target_if_get_spectral_mode(p_sfft->fft_detector_id,
3186 						    &spectral->rparams);
3187 	if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3188 		spectral_err_rl("No valid Spectral mode for detector id %u",
3189 				p_sfft->fft_detector_id);
3190 		return QDF_STATUS_E_FAILURE;
3191 	}
3192 
3193 	/* Populate the Search FFT Info */
3194 	p_sfft->timestamp = p_fft_report->fft_timestamp;
3195 	p_sfft->last_raw_timestamp = spectral->timestamp_war.
3196 					last_fft_timestamp[spectral_mode];
3197 	p_sfft->adjusted_timestamp = target_if_spectral_get_adjusted_timestamp(
3198 						&spectral->timestamp_war,
3199 						p_sfft->timestamp,
3200 						reset_delay,
3201 						spectral_mode);
3202 	/* Timestamp verification */
3203 	target_if_spectral_verify_ts(spectral, data,
3204 				     p_sfft->adjusted_timestamp,
3205 				     p_sfft->fft_detector_id);
3206 
3207 
3208 	p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a,
3209 				       FFT_REPORT_HDR_A_FFT_NUM_SIZE_GEN3,
3210 				       FFT_REPORT_HDR_A_FFT_NUM_POS_GEN3);
3211 
3212 	switch (spectral->rparams.version) {
3213 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
3214 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
3215 				FFT_REPORT_HDR_A_RADAR_CHECK_SIZE_GEN3_V1,
3216 				FFT_REPORT_HDR_A_RADAR_CHECK_POS_GEN3_V1);
3217 		peak_sidx = get_bitfield(
3218 				p_fft_report->hdr_a,
3219 				FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V1,
3220 				FFT_REPORT_HDR_A_PEAK_INDEX_POS_GEN3_V1);
3221 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a,
3222 				FFT_REPORT_HDR_A_CHAIN_INDEX_SIZE_GEN3_V1,
3223 				FFT_REPORT_HDR_A_CHAIN_INDEX_POS_GEN3_V1);
3224 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
3225 				FFT_REPORT_HDR_B_BASE_PWR_SIZE_GEN3_V1,
3226 				FFT_REPORT_HDR_B_BASE_PWR_POS_GEN3_V1);
3227 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
3228 				FFT_REPORT_HDR_B_TOTAL_GAIN_SIZE_GEN3_V1,
3229 				FFT_REPORT_HDR_B_TOTAL_GAIN_POS_GEN3_V1);
3230 		break;
3231 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
3232 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
3233 				FFT_REPORT_HDR_A_RADAR_CHECK_SIZE_GEN3_V2,
3234 				FFT_REPORT_HDR_A_RADAR_CHECK_POS_GEN3_V2);
3235 		peak_sidx = get_bitfield(
3236 				p_fft_report->hdr_a,
3237 				FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V2,
3238 				FFT_REPORT_HDR_A_PEAK_INDEX_POS_GEN3_V2);
3239 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_b,
3240 				FFT_REPORT_HDR_B_CHAIN_INDEX_SIZE_GEN3_V2,
3241 				FFT_REPORT_HDR_B_CHAIN_INDEX_POS_GEN3_V2);
3242 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
3243 				FFT_REPORT_HDR_B_BASE_PWR_SIZE_GEN3_V2,
3244 				FFT_REPORT_HDR_B_BASE_PWR_POS_GEN3_V2);
3245 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
3246 				FFT_REPORT_HDR_B_TOTAL_GAIN_SIZE_GEN3_V2,
3247 				FFT_REPORT_HDR_B_TOTAL_GAIN_POS_GEN3_V2);
3248 		break;
3249 	default:
3250 		qdf_assert_always(0);
3251 	}
3252 
3253 	p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx,
3254 				FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V1);
3255 
3256 	p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
3257 				FFT_REPORT_HDR_C_NUM_STRONG_BINS_SIZE_GEN3,
3258 				FFT_REPORT_HDR_C_NUM_STRONG_BINS_POS_GEN3);
3259 	peak_mag = get_bitfield(p_fft_report->hdr_c,
3260 				FFT_REPORT_HDR_C_PEAK_MAGNITUDE_SIZE_GEN3,
3261 				FFT_REPORT_HDR_C_PEAK_MAGNITUDE_POS_GEN3);
3262 	p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag,
3263 				FFT_REPORT_HDR_C_PEAK_MAGNITUDE_SIZE_GEN3);
3264 	p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
3265 				FFT_REPORT_HDR_C_AVG_PWR_SIZE_GEN3,
3266 				FFT_REPORT_HDR_C_AVG_PWR_POS_GEN3);
3267 	p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
3268 				FFT_REPORT_HDR_C_RELATIVE_PWR_SIZE_GEN3,
3269 				FFT_REPORT_HDR_C_RELATIVE_PWR_POS_GEN3);
3270 
3271 	p_sfft->fft_bin_count =
3272 		target_if_spectral_get_bin_count_after_len_adj(
3273 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3274 			spectral->params[spectral_mode].ss_rpt_mode,
3275 			&spectral->len_adj_swar,
3276 			(size_t *)&p_sfft->fft_bin_size);
3277 
3278 	p_sfft->bin_pwr_data = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
3279 
3280 	/* Apply byte-swap on the FFT bins.
3281 	 * NOTE: Until this point, bytes of the FFT bins could be in
3282 	 *       reverse order on a big-endian machine. If the consumers
3283 	 *       of FFT bins expects bytes in the correct order,
3284 	 *       they should use them only after this point.
3285 	 */
3286 	if (p_sops->byte_swap_fft_bins) {
3287 		ret = p_sops->byte_swap_fft_bins(&spectral->len_adj_swar,
3288 						 &p_sfft->bin_pwr_data,
3289 						 p_sfft->fft_bin_count);
3290 		if (QDF_IS_STATUS_ERROR(ret)) {
3291 			spectral_err_rl("Byte-swap on the FFT bins failed");
3292 			return QDF_STATUS_E_FAILURE;
3293 		}
3294 	}
3295 
3296 	return QDF_STATUS_SUCCESS;
3297 }
3298 
3299 /**
3300  * target_if_spectral_populate_samp_params_gen3() - Populate the SAMP params
3301  * for gen3. SAMP params are to be used for populating SAMP msg.
3302  * @spectral: Pointer to spectral object
3303  * @p_sfft: Fields extracted from FFT report
3304  * @sscan_fields: Fields extracted from Summary report
3305  * @report: Pointer to spectral report
3306  * @params: Pointer to Spectral SAMP message fields to be populated
3307  *
3308  * Populate the SAMP params for gen3, which will be used to populate SAMP msg.
3309  *
3310  * Return: Success/Failure
3311  */
3312 static QDF_STATUS
3313 target_if_spectral_populate_samp_params_gen3(
3314 		struct target_if_spectral *spectral,
3315 		struct spectral_search_fft_info_gen3 *p_sfft,
3316 		struct sscan_report_fields_gen3 *sscan_fields,
3317 		struct spectral_report *report,
3318 		struct target_if_samp_msg_params *params)
3319 {
3320 	enum spectral_scan_mode spectral_mode;
3321 	uint8_t chn_idx_lowest_enabled;
3322 	struct wlan_objmgr_vdev *vdev;
3323 	uint8_t vdev_rxchainmask;
3324 
3325 	if (!p_sfft) {
3326 		spectral_err_rl("Invalid pointer to Search FFT report info");
3327 		return QDF_STATUS_E_NULL_VALUE;
3328 	}
3329 	if (!spectral) {
3330 		spectral_err_rl("Spectral LMAC object is null");
3331 		return QDF_STATUS_E_NULL_VALUE;
3332 	}
3333 	if (!sscan_fields) {
3334 		spectral_err_rl("Invalid pointer to Summary report fields");
3335 		return QDF_STATUS_E_NULL_VALUE;
3336 	}
3337 	if (!report) {
3338 		spectral_err_rl("Spectral report is null");
3339 		return QDF_STATUS_E_NULL_VALUE;
3340 	}
3341 	if (!params) {
3342 		spectral_err_rl("SAMP msg params structure is null");
3343 		return QDF_STATUS_E_NULL_VALUE;
3344 	}
3345 
3346 	/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
3347 	params->rssi = (sscan_fields->inband_pwr_db) >> 1;
3348 
3349 	params->hw_detector_id = p_sfft->fft_detector_id;
3350 	params->raw_timestamp = p_sfft->timestamp;
3351 	params->last_raw_timestamp = p_sfft->last_raw_timestamp;
3352 	params->timestamp = p_sfft->adjusted_timestamp;
3353 	params->reset_delay = report->reset_delay;
3354 
3355 	params->max_mag = p_sfft->fft_peak_mag;
3356 
3357 	spectral_mode = target_if_get_spectral_mode(params->hw_detector_id,
3358 						    &spectral->rparams);
3359 	vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3360 	if (!vdev) {
3361 		spectral_debug("First vdev is NULL");
3362 		return QDF_STATUS_E_FAILURE;
3363 	}
3364 	vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3365 	QDF_ASSERT(vdev_rxchainmask != 0);
3366 	wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3367 
3368 	chn_idx_lowest_enabled =
3369 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3370 	if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3371 		spectral_err("Invalid chain index, detector id = %u",
3372 			     params->hw_detector_id);
3373 		return QDF_STATUS_E_FAILURE;
3374 	}
3375 	params->noise_floor = report->noisefloor[chn_idx_lowest_enabled];
3376 	params->agc_total_gain = sscan_fields->sscan_agc_total_gain;
3377 	params->gainchange = sscan_fields->sscan_gainchange;
3378 	params->pri80ind = sscan_fields->sscan_pri80;
3379 
3380 	params->bin_pwr_data = p_sfft->bin_pwr_data;
3381 
3382 	return QDF_STATUS_SUCCESS;
3383 }
3384 
3385 int
3386 target_if_consume_spectral_report_gen3(
3387 	 struct target_if_spectral *spectral,
3388 	 struct spectral_report *report)
3389 {
3390 	/*
3391 	 * XXX : The classifier do not use all the members of the SAMP
3392 	 *       message data format.
3393 	 *       The classifier only depends upon the following parameters
3394 	 *
3395 	 *          1. Frequency
3396 	 *          2. Spectral RSSI
3397 	 *          3. Bin Power Count
3398 	 *          4. Bin Power values
3399 	 *          5. Spectral Timestamp
3400 	 *          6. MAC Address
3401 	 *
3402 	 *       This function processes the Spectral summary and FFT reports
3403 	 *       and passes the processed information
3404 	 *       target_if_spectral_fill_samp_msg()
3405 	 *       to prepare fully formatted Spectral SAMP message
3406 	 *
3407 	 *       XXX : Need to verify
3408 	 *          1. Order of FFT bin values
3409 	 *
3410 	 */
3411 	struct target_if_samp_msg_params params = {0};
3412 	struct spectral_search_fft_info_gen3 search_fft_info;
3413 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
3414 	struct target_if_spectral_ops *p_sops;
3415 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3416 	uint8_t *data;
3417 	struct sscan_report_fields_gen3 sscan_report_fields = {0};
3418 	QDF_STATUS ret;
3419 	enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
3420 	bool finite_scan = false;
3421 	int det = 0;
3422 	struct sscan_detector_list *det_list;
3423 
3424 	if (!spectral) {
3425 		spectral_err_rl("Spectral LMAC object is null");
3426 		goto fail_no_print;
3427 	}
3428 
3429 	if (!report) {
3430 		spectral_err_rl("Spectral report is null");
3431 		goto fail_no_print;
3432 	}
3433 
3434 	p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3435 	data = report->data;
3436 
3437 	/* Apply byte-swap on the headers */
3438 	if (p_sops->byte_swap_headers) {
3439 		ret = p_sops->byte_swap_headers(spectral, data);
3440 		if (QDF_IS_STATUS_ERROR(ret)) {
3441 			spectral_err_rl("Byte-swap on Spectral headers failed");
3442 			goto fail;
3443 		}
3444 	}
3445 
3446 	/* Validate and Process Spectral scan summary report */
3447 	ret = target_if_consume_sscan_summary_report_gen3(&data,
3448 							  &sscan_report_fields,
3449 							  spectral);
3450 	if (QDF_IS_STATUS_ERROR(ret)) {
3451 		spectral_err_rl("Failed to process Spectral summary report");
3452 		goto fail;
3453 	}
3454 
3455 	spectral_mode = target_if_get_spectral_mode(
3456 					sscan_report_fields.sscan_detector_id,
3457 					&spectral->rparams);
3458 	if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3459 		spectral_err_rl("No valid Spectral mode for detector id %u",
3460 				sscan_report_fields.sscan_detector_id);
3461 		goto fail;
3462 	}
3463 
3464 	/* Drop the sample if Spectral is not active for the current mode */
3465 	if (!p_sops->is_spectral_active(spectral, spectral_mode)) {
3466 		spectral_info_rl("Spectral scan is not active");
3467 		goto fail_no_print;
3468 	}
3469 
3470 	ret = target_if_spectral_is_finite_scan(spectral, spectral_mode,
3471 						&finite_scan);
3472 	if (QDF_IS_STATUS_ERROR(ret)) {
3473 		spectral_err_rl("Failed to check scan is finite");
3474 		goto fail;
3475 	}
3476 
3477 	if (finite_scan) {
3478 		ret = target_if_spectral_finite_scan_update(spectral,
3479 							    spectral_mode);
3480 		if (QDF_IS_STATUS_ERROR(ret)) {
3481 			spectral_err_rl("Failed to update scan count");
3482 			goto fail;
3483 		}
3484 	}
3485 
3486 	/* Validate and Process the search FFT report */
3487 	ret = target_if_process_sfft_report_gen3(
3488 					data, p_sfft,
3489 					spectral,
3490 					sscan_report_fields.sscan_detector_id,
3491 					report->reset_delay);
3492 	if (QDF_IS_STATUS_ERROR(ret)) {
3493 		spectral_err_rl("Failed to process search FFT report");
3494 		goto fail;
3495 	}
3496 
3497 	qdf_spin_lock_bh(&spectral->detector_list_lock);
3498 	det_list = &spectral->detector_list[spectral_mode]
3499 			[spectral->report_info[spectral_mode].sscan_bw];
3500 	for (det = 0; det < det_list->num_detectors; det++) {
3501 		if (p_sfft->fft_detector_id == det_list->detectors[det])
3502 			break;
3503 		if (det == det_list->num_detectors - 1) {
3504 			qdf_spin_unlock_bh(&spectral->detector_list_lock);
3505 			spectral_info("Incorrect det id %d for given scan mode and channel width",
3506 				      p_sfft->fft_detector_id);
3507 			goto fail_no_print;
3508 		}
3509 	}
3510 	qdf_spin_unlock_bh(&spectral->detector_list_lock);
3511 
3512 	ret = target_if_update_session_info_from_report_ctx(
3513 						spectral,
3514 						p_sfft->fft_bin_size,
3515 						report->cfreq1, report->cfreq2,
3516 						spectral_mode);
3517 	if (QDF_IS_STATUS_ERROR(ret)) {
3518 		spectral_err_rl("Failed to update per-session info");
3519 		goto fail;
3520 	}
3521 
3522 	qdf_spin_lock_bh(&spectral->session_report_info_lock);
3523 	/* Check FFT report are in order for 160 MHz and 80p80 */
3524 	if (is_ch_width_160_or_80p80(
3525 	    spectral->report_info[spectral_mode].sscan_bw) &&
3526 	    spectral->rparams.fragmentation_160[spectral_mode]) {
3527 		ret = target_if_160mhz_delivery_state_change(
3528 				spectral, spectral_mode,
3529 				p_sfft->fft_detector_id);
3530 		if (ret != QDF_STATUS_SUCCESS) {
3531 			qdf_spin_unlock_bh(
3532 					&spectral->session_report_info_lock);
3533 			goto fail;
3534 		}
3535 	}
3536 	qdf_spin_unlock_bh(&spectral->session_report_info_lock);
3537 
3538 	p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3539 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
3540 		target_if_dump_fft_report_gen3(spectral, spectral_mode,
3541 					       p_fft_report, p_sfft);
3542 
3543 	target_if_spectral_check_buffer_poisoning(spectral, report,
3544 						  p_sfft->fft_bin_count,
3545 						  spectral_mode);
3546 
3547 	/* Populate SAMP params */
3548 	ret = target_if_spectral_populate_samp_params_gen3(
3549 							spectral, p_sfft,
3550 							&sscan_report_fields,
3551 							report, &params);
3552 	if (QDF_IS_STATUS_ERROR(ret)) {
3553 		spectral_err_rl("Failed to populate SAMP params");
3554 		goto fail;
3555 	}
3556 	/* Fill SAMP message */
3557 	ret = target_if_spectral_fill_samp_msg(spectral, &params);
3558 	if (QDF_IS_STATUS_ERROR(ret)) {
3559 		spectral_err_rl("Failed to fill the SAMP msg");
3560 		goto fail;
3561 	}
3562 
3563 	return 0;
3564  fail:
3565 	spectral_err_rl("Error while processing Spectral report");
3566 fail_no_print:
3567 	if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
3568 		reset_160mhz_delivery_state_machine(spectral, spectral_mode);
3569 	return -EPERM;
3570 }
3571 
3572 #else
3573 int
3574 target_if_consume_spectral_report_gen3(
3575 	 struct target_if_spectral *spectral,
3576 	 struct spectral_report *report)
3577 {
3578 	/*
3579 	 * XXX : The classifier do not use all the members of the SAMP
3580 	 *       message data format.
3581 	 *       The classifier only depends upon the following parameters
3582 	 *
3583 	 *          1. Frequency (freq, msg->freq)
3584 	 *          2. Spectral RSSI (spectral_rssi,
3585 	 *          msg->samp_data.spectral_rssi)
3586 	 *          3. Bin Power Count (bin_pwr_count,
3587 	 *          msg->samp_data.bin_pwr_count)
3588 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
3589 	 *          5. Spectral Timestamp (spectral_tstamp,
3590 	 *          msg->samp_data.spectral_tstamp)
3591 	 *          6. MAC Address (macaddr, msg->macaddr)
3592 	 *
3593 	 *       This function prepares the params structure and populates it
3594 	 *       with
3595 	 *       relevant values, this is in turn passed to
3596 	 *       spectral_create_samp_msg()
3597 	 *       to prepare fully formatted Spectral SAMP message
3598 	 *
3599 	 *       XXX : Need to verify
3600 	 *          1. Order of FFT bin values
3601 	 *
3602 	 */
3603 	struct target_if_samp_msg_params params = {0};
3604 	struct spectral_search_fft_info_gen3 search_fft_info;
3605 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
3606 	int8_t chn_idx_lowest_enabled  = 0;
3607 	int fft_hdr_length = 0;
3608 	int report_len = 0;
3609 	size_t fft_bin_count;
3610 	size_t fft_bin_size;
3611 	struct target_if_spectral_ops *p_sops =
3612 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
3613 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3614 	int8_t rssi;
3615 	uint8_t *data = report->data;
3616 	struct wlan_objmgr_vdev *vdev;
3617 	uint8_t vdev_rxchainmask;
3618 	struct sscan_report_fields_gen3 sscan_report_fields = {0};
3619 	enum spectral_detector_id detector_id;
3620 	QDF_STATUS ret;
3621 	enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
3622 	uint8_t *temp;
3623 	bool finite_scan = false;
3624 
3625 	/* Apply byte-swap on the headers */
3626 	if (p_sops->byte_swap_headers) {
3627 		ret = p_sops->byte_swap_headers(spectral, data);
3628 		if (QDF_IS_STATUS_ERROR(ret)) {
3629 			spectral_err_rl("Byte-swap on Spectral headers failed");
3630 			goto fail;
3631 		}
3632 	}
3633 
3634 	/* Process Spectral scan summary report */
3635 	if (target_if_verify_sig_and_tag_gen3(
3636 			spectral, data,
3637 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
3638 		spectral_err_rl("Wrong tag/sig in sscan summary");
3639 		goto fail;
3640 	}
3641 
3642 	detector_id = target_if_get_detector_id_sscan_summary_report_gen3(data);
3643 	if (detector_id >= spectral->rparams.num_spectral_detectors) {
3644 		spectral->diag_stats.spectral_invalid_detector_id++;
3645 		spectral_err("Invalid detector id %u, expected is 0/1/2",
3646 			     detector_id);
3647 		goto fail;
3648 	}
3649 
3650 	spectral_mode = target_if_get_spectral_mode(detector_id,
3651 						    &spectral->rparams);
3652 	if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3653 		spectral_err_rl("No valid Spectral mode for detector id %u",
3654 				detector_id);
3655 		goto fail;
3656 	}
3657 
3658 	/* Drop the sample if Spectral is not active for the current mode */
3659 	if (!p_sops->is_spectral_active(spectral, spectral_mode)) {
3660 		spectral_info_rl("Spectral scan is not active");
3661 		goto fail_no_print;
3662 	}
3663 
3664 	ret = target_if_spectral_is_finite_scan(spectral, spectral_mode,
3665 						&finite_scan);
3666 	if (QDF_IS_STATUS_ERROR(ret)) {
3667 		spectral_err_rl("Failed to check scan is finite");
3668 		goto fail;
3669 	}
3670 
3671 	if (finite_scan) {
3672 		ret = target_if_spectral_finite_scan_update(spectral,
3673 							    spectral_mode);
3674 		if (QDF_IS_STATUS_ERROR(ret)) {
3675 			spectral_err_rl("Failed to update scan count");
3676 			goto fail;
3677 		}
3678 	}
3679 
3680 	target_if_consume_sscan_summary_report_gen3(data, &sscan_report_fields,
3681 						    &spectral->rparams);
3682 	/* Advance buf pointer to the search fft report */
3683 	data += sizeof(struct spectral_sscan_summary_report_gen3);
3684 	data += spectral->rparams.ssumaary_padding_bytes;
3685 	params.vhtop_ch_freq_seg1 = report->cfreq1;
3686 	params.vhtop_ch_freq_seg2 = report->cfreq2;
3687 
3688 	if (is_primaryseg_expected(spectral, spectral_mode)) {
3689 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
3690 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
3691 		params.agc_total_gain =
3692 			sscan_report_fields.sscan_agc_total_gain;
3693 		params.gainchange = sscan_report_fields.sscan_gainchange;
3694 		params.pri80ind = sscan_report_fields.sscan_pri80;
3695 
3696 		/* Process Spectral search FFT report */
3697 		if (target_if_verify_sig_and_tag_gen3(
3698 				spectral, data,
3699 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3700 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3701 					detector_id);
3702 			goto fail;
3703 		}
3704 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3705 		fft_hdr_length = get_bitfield(
3706 				p_fft_report->fft_hdr_lts,
3707 				SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3708 				SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3709 		if (fft_hdr_length < 16) {
3710 			spectral_err("Wrong TLV length %u, detector id = %d",
3711 				     fft_hdr_length, detector_id);
3712 			goto fail;
3713 		}
3714 
3715 		report_len = (fft_hdr_length + 8);
3716 
3717 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft,
3718 						   &spectral->rparams);
3719 		/* It is expected to have same detector id for
3720 		 * summary and fft report
3721 		 */
3722 		if (detector_id != p_sfft->fft_detector_id) {
3723 			spectral_err_rl
3724 				("Different detid in ssummary(%u) and sfft(%u)",
3725 				 detector_id, p_sfft->fft_detector_id);
3726 			goto fail;
3727 		}
3728 
3729 		if (detector_id > spectral->rparams.num_spectral_detectors) {
3730 			spectral->diag_stats.spectral_invalid_detector_id++;
3731 			spectral_err("Invalid detector id %u, expected is 0/2",
3732 				     detector_id);
3733 			goto fail;
3734 		}
3735 		params.smode = spectral_mode;
3736 
3737 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
3738 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3739 			spectral->params[spectral_mode].ss_rpt_mode,
3740 			&spectral->len_adj_swar, &fft_bin_size);
3741 
3742 		params.last_raw_timestamp = spectral->timestamp_war.
3743 				last_fft_timestamp[spectral_mode];
3744 		params.reset_delay = report->reset_delay;
3745 		params.raw_timestamp = p_sfft->timestamp;
3746 		params.tstamp = target_if_spectral_get_adjusted_timestamp(
3747 					&spectral->timestamp_war,
3748 					p_sfft->timestamp, report->reset_delay,
3749 					spectral_mode);
3750 		params.timestamp_war_offset = spectral->timestamp_war.
3751 				timestamp_war_offset[spectral_mode];
3752 		params.target_reset_count = spectral->timestamp_war.
3753 				target_reset_count;
3754 
3755 		/* Take care of state transitions for 160 MHz and 80p80 */
3756 		if (is_ch_width_160_or_80p80(spectral->ch_width
3757 		    [spectral_mode]) && spectral->rparams.
3758 		    fragmentation_160[spectral_mode]) {
3759 			ret = target_if_160mhz_delivery_state_change(
3760 					spectral, spectral_mode,
3761 					detector_id);
3762 			if (ret != QDF_STATUS_SUCCESS)
3763 				goto fail;
3764 		}
3765 
3766 		params.rssi         = rssi;
3767 
3768 		vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3769 		if (!vdev) {
3770 			spectral_debug("First vdev is NULL");
3771 			reset_160mhz_delivery_state_machine(
3772 						spectral, spectral_mode);
3773 			return -EPERM;
3774 		}
3775 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3776 		QDF_ASSERT(vdev_rxchainmask != 0);
3777 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3778 
3779 		chn_idx_lowest_enabled =
3780 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3781 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3782 			spectral_err("Invalid chain index, detector id = %u",
3783 				     detector_id);
3784 			goto fail;
3785 		}
3786 
3787 		params.max_mag  = p_sfft->fft_peak_mag;
3788 
3789 		params.freq = p_sops->get_current_channel(spectral,
3790 							  spectral_mode);
3791 		params.agile_freq1 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3792 				     ss_frequency.cfreq1;
3793 		params.agile_freq2 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3794 				     ss_frequency.cfreq2;
3795 		params.noise_floor =
3796 			report->noisefloor[chn_idx_lowest_enabled];
3797 		temp = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
3798 		if (is_ch_width_160_or_80p80(spectral->ch_width
3799 		    [spectral_mode]) && !spectral->rparams.
3800 		    fragmentation_160[spectral_mode]) {
3801 			struct wlan_objmgr_psoc *psoc;
3802 			struct spectral_fft_bin_markers_160_165mhz *marker;
3803 
3804 			qdf_assert_always(spectral->pdev_obj);
3805 			psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
3806 			qdf_assert_always(psoc);
3807 
3808 			params.agc_total_gain_sec80 =
3809 				sscan_report_fields.sscan_agc_total_gain;
3810 			params.gainchange_sec80 =
3811 					sscan_report_fields.sscan_gainchange;
3812 			params.raw_timestamp_sec80 = p_sfft->timestamp;
3813 			params.rssi_sec80 = rssi;
3814 			params.noise_floor_sec80    =
3815 				report->noisefloor[chn_idx_lowest_enabled];
3816 			params.max_mag_sec80        = p_sfft->fft_peak_mag;
3817 			params.datalen = fft_hdr_length * 2;
3818 			params.datalen_sec80 = fft_hdr_length * 2;
3819 
3820 			marker = &spectral->rparams.marker[spectral_mode];
3821 			if (!marker->is_valid) {
3822 				/* update stats */
3823 				goto fail_no_print;
3824 			}
3825 			params.bin_pwr_data = temp +
3826 				marker->start_pri80 * fft_bin_size;
3827 			params.pwr_count = marker->num_pri80;
3828 			params.bin_pwr_data_sec80 = temp +
3829 				marker->start_sec80 * fft_bin_size;
3830 			params.pwr_count_sec80 = marker->num_sec80;
3831 			if (spectral->ch_width[spectral_mode] ==
3832 			    CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
3833 			    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
3834 				params.bin_pwr_data_5mhz = temp +
3835 					marker->start_5mhz * fft_bin_size;
3836 				params.pwr_count_5mhz = marker->num_5mhz;
3837 			}
3838 		} else {
3839 			params.bin_pwr_data = temp;
3840 			params.pwr_count = fft_bin_count;
3841 			params.datalen = (fft_hdr_length * 4);
3842 		}
3843 
3844 		/* Apply byte-swap on the FFT bins.
3845 		 * NOTE: Until this point, bytes of the FFT bins could be in
3846 		 *       reverse order on a big-endian machine. If the consumers
3847 		 *       of FFT bins expects bytes in the correct order,
3848 		 *       they should use them only after this point.
3849 		 */
3850 		if (p_sops->byte_swap_fft_bins) {
3851 			ret = p_sops->byte_swap_fft_bins(
3852 						&spectral->len_adj_swar,
3853 						temp, fft_bin_count);
3854 			if (QDF_IS_STATUS_ERROR(ret)) {
3855 				spectral_err_rl("Byte-swap on the FFT bins failed");
3856 				goto fail;
3857 			}
3858 		}
3859 
3860 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
3861 			target_if_dump_fft_report_gen3(spectral, spectral_mode,
3862 						       p_fft_report, p_sfft);
3863 
3864 		target_if_spectral_verify_ts(spectral, report->data,
3865 					     params.tstamp);
3866 	} else if (is_secondaryseg_expected(spectral, spectral_mode)) {
3867 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
3868 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
3869 		params.agc_total_gain_sec80 =
3870 			sscan_report_fields.sscan_agc_total_gain;
3871 		params.gainchange_sec80 = sscan_report_fields.sscan_gainchange;
3872 		params.pri80ind_sec80 = sscan_report_fields.sscan_pri80;
3873 
3874 		/* Process Spectral search FFT report */
3875 		if (target_if_verify_sig_and_tag_gen3(
3876 				spectral, data,
3877 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3878 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3879 					detector_id);
3880 			goto fail;
3881 		}
3882 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3883 		fft_hdr_length = get_bitfield(
3884 				p_fft_report->fft_hdr_lts,
3885 				SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3886 				SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3887 		if (fft_hdr_length < 16) {
3888 			spectral_err("Wrong TLV length %u, detector id = %u",
3889 				     fft_hdr_length, detector_id);
3890 			goto fail;
3891 		}
3892 
3893 		report_len     = (fft_hdr_length + 8);
3894 
3895 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft,
3896 						   &spectral->rparams);
3897 		/* It is expected to have same detector id for
3898 		 * summary and fft report
3899 		 */
3900 		if (detector_id != p_sfft->fft_detector_id) {
3901 			spectral_err_rl
3902 				("Different detid in ssummary(%u) and sfft(%u)",
3903 				 detector_id, p_sfft->fft_detector_id);
3904 			goto fail;
3905 		}
3906 
3907 		if (detector_id > spectral->rparams.num_spectral_detectors) {
3908 			spectral->diag_stats.spectral_invalid_detector_id++;
3909 			spectral_err("Invalid detector id %u, expected is 1",
3910 				     detector_id);
3911 			goto fail;
3912 		}
3913 		params.smode = spectral_mode;
3914 
3915 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
3916 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3917 			spectral->params[spectral_mode].ss_rpt_mode,
3918 			&spectral->len_adj_swar, &fft_bin_size);
3919 		params.raw_timestamp_sec80 = p_sfft->timestamp;
3920 
3921 		/* Take care of state transitions for 160 MHz and 80p80 */
3922 		if (is_ch_width_160_or_80p80(spectral->ch_width
3923 		    [spectral_mode]) && spectral->rparams.
3924 		    fragmentation_160[spectral_mode]) {
3925 			ret = target_if_160mhz_delivery_state_change(
3926 					spectral, spectral_mode,
3927 					detector_id);
3928 			if (ret != QDF_STATUS_SUCCESS)
3929 				goto fail;
3930 		}
3931 
3932 		params.rssi_sec80 = rssi;
3933 
3934 		vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3935 		if (!vdev) {
3936 			spectral_info("First vdev is NULL");
3937 			reset_160mhz_delivery_state_machine
3938 						(spectral, spectral_mode);
3939 			return -EPERM;
3940 		}
3941 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3942 		QDF_ASSERT(vdev_rxchainmask != 0);
3943 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3944 
3945 		chn_idx_lowest_enabled =
3946 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3947 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3948 			spectral_err("Invalid chain index");
3949 			goto fail;
3950 		}
3951 
3952 		/* Need to change this as per FW team's inputs */
3953 		params.noise_floor_sec80    =
3954 			report->noisefloor[chn_idx_lowest_enabled];
3955 
3956 		params.max_mag_sec80        = p_sfft->fft_peak_mag;
3957 		/* params.max_index_sec80      = p_sfft->peak_inx; */
3958 		/* XXX Does this definition of datalen *still hold? */
3959 		params.datalen_sec80        = fft_hdr_length * 4;
3960 		params.pwr_count_sec80      = fft_bin_count;
3961 		params.bin_pwr_data_sec80   =
3962 			(uint8_t *)((uint8_t *)p_fft_report +
3963 			 SPECTRAL_FFT_BINS_POS);
3964 
3965 		/* Apply byte-swap on the FFT bins.
3966 		 * NOTE: Until this point, bytes of the FFT bins could be in
3967 		 *       reverse order on a big-endian machine. If the consumers
3968 		 *       of FFT bins expects bytes in the correct order,
3969 		 *       they should use them only after this point.
3970 		 */
3971 		if (p_sops->byte_swap_fft_bins) {
3972 			ret = p_sops->byte_swap_fft_bins(
3973 					&spectral->len_adj_swar,
3974 					params.bin_pwr_data_sec80,
3975 					fft_bin_count);
3976 			if (QDF_IS_STATUS_ERROR(ret)) {
3977 				spectral_err_rl("Byte-swap on the FFT bins failed");
3978 				goto fail;
3979 			}
3980 		}
3981 
3982 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
3983 			target_if_dump_fft_report_gen3(spectral, spectral_mode,
3984 						       p_fft_report, p_sfft);
3985 
3986 	} else {
3987 		spectral_err("Spectral state machine in undefined state");
3988 		goto fail;
3989 	}
3990 
3991 	target_if_spectral_check_buffer_poisoning(spectral, report,
3992 						  fft_bin_count, spectral_mode);
3993 	qdf_mem_copy(&params.classifier_params,
3994 		     &spectral->classifier_params,
3995 		     sizeof(struct spectral_classifier_params));
3996 
3997 	target_if_spectral_log_SAMP_param(&params);
3998 	target_if_spectral_create_samp_msg(spectral, &params);
3999 
4000 	return 0;
4001  fail:
4002 	spectral_err_rl("Error while processing Spectral report");
4003 fail_no_print:
4004 	if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
4005 		reset_160mhz_delivery_state_machine(spectral, spectral_mode);
4006 	return -EPERM;
4007 }
4008 #endif /* OPTIMIZED_SAMP_MESSAGE */
4009 
4010 int target_if_spectral_process_report_gen3(
4011 	struct wlan_objmgr_pdev *pdev,
4012 	void *buf)
4013 {
4014 	int ret = 0;
4015 	struct direct_buf_rx_data *payload = buf;
4016 	struct target_if_spectral *spectral;
4017 	struct spectral_report report;
4018 	int samp_msg_index;
4019 
4020 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
4021 	if (!spectral) {
4022 		spectral_err("Spectral target object is null");
4023 		return -EINVAL;
4024 	}
4025 
4026 	report.data = payload->vaddr;
4027 	if (payload->meta_data_valid) {
4028 		qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor,
4029 			     qdf_min(sizeof(report.noisefloor),
4030 				     sizeof(payload->meta_data.noisefloor)));
4031 		report.reset_delay = payload->meta_data.reset_delay;
4032 		report.cfreq1 = payload->meta_data.cfreq1;
4033 		report.cfreq2 = payload->meta_data.cfreq2;
4034 		report.ch_width = payload->meta_data.ch_width;
4035 	}
4036 
4037 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) {
4038 		spectral_debug("Printing the spectral phyerr buffer for debug");
4039 		spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK",
4040 			       payload->dbr_len,
4041 			       payload->dbr_len,
4042 			       payload->vaddr);
4043 		target_if_spectral_hexdump((unsigned char *)payload->vaddr,
4044 					   1024);
4045 	}
4046 
4047 	samp_msg_index = spectral->spectral_sent_msg;
4048 
4049 	ret = target_if_consume_spectral_report_gen3(spectral, &report);
4050 
4051 	/* Reset debug level when SAMP msg is sent successfully or on error */
4052 	if ((spectral_debug_level & DEBUG_SPECTRAL4) &&
4053 	    (ret != 0 || spectral->spectral_sent_msg == samp_msg_index + 1))
4054 		spectral_debug_level = DEBUG_SPECTRAL;
4055 
4056 	return ret;
4057 }
4058 #else
4059 int target_if_spectral_process_report_gen3(
4060 	struct wlan_objmgr_pdev *pdev,
4061 	void *buf)
4062 {
4063 	spectral_err("Direct dma support is not enabled");
4064 	return -EINVAL;
4065 }
4066 #endif
4067 qdf_export_symbol(target_if_spectral_process_report_gen3);
4068 /* END of spectral GEN III HW specific functions */
4069 
4070 #endif  /* WLAN_CONV_SPECTRAL_ENABLE */
4071