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