xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral_phyerr.c (revision bea437e2293c3d4fb1b5704fcf633aedac996962)
1 /*
2  * Copyright (c) 2011,2017-2019 The Linux Foundation. All rights reserved.
3  *
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <osdep.h>
21 #include <qdf_types.h>
22 #include <qdf_module.h>
23 #include <wlan_tgt_def_config.h>
24 #include <hif.h>
25 #include <hif_hw_version.h>
26 #include <wmi_unified_api.h>
27 #include <target_if_spectral.h>
28 #include <wlan_lmac_if_def.h>
29 #include <wlan_osif_priv.h>
30 #include <reg_services_public_struct.h>
31 #include <target_if.h>
32 #ifdef DIRECT_BUF_RX_ENABLE
33 #include <target_if_direct_buf_rx_api.h>
34 #endif
35 extern int spectral_debug_level;
36 
37 #ifdef WLAN_CONV_SPECTRAL_ENABLE
38 
39 #define SPECTRAL_HEXDUMP_OCTET_PRINT_SIZE           (3)
40 #define SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE        (16)
41 #define SPECTRAL_HEXDUMP_EXTRA_BUFFER_PER_LINE      (16)
42 
43 /*
44  * Provision for the expected hexdump line size as follows:
45  *
46  * Size per octet multiplied by number of octets per line
47  * +
48  * ASCII representation which is equivalent in print size to number of octets
49  * per line
50  * +
51  * Some extra buffer
52  */
53 #define SPECTRAL_HEXDUMP_LINESIZE                           \
54 		((SPECTRAL_HEXDUMP_OCTET_PRINT_SIZE *       \
55 		  SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) +   \
56 		 SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE +     \
57 		 SPECTRAL_HEXDUMP_EXTRA_BUFFER_PER_LINE)
58 
59 /**
60  * target_if_spectral_hexdump() - Print hexdump of the given buffer
61  * @_buf: Pointer to buffer
62  * @_len: Length of the buffer
63  *
64  * Print the hexdump of buffer upto given length. Print upto
65  * SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE per line, followed by the ASCII
66  * representation of these octets.
67  */
68 static inline void target_if_spectral_hexdump(unsigned char *_buf, int _len)
69 {
70 	int i, mod;
71 	unsigned char ascii[SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE + 1];
72 	unsigned char *pc = (_buf);
73 	char hexdump_line[SPECTRAL_HEXDUMP_LINESIZE + 1];
74 	int loc = 0;
75 
76 	qdf_mem_zero(hexdump_line, sizeof(hexdump_line));
77 
78 	for (i = 0; i < _len; i++) {
79 		mod = i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE;
80 
81 		if (!mod) {
82 			if (i) {
83 				qdf_assert_always(loc < sizeof(hexdump_line));
84 				loc += snprintf(&hexdump_line[loc],
85 						sizeof(hexdump_line) - loc,
86 						"  %s", ascii);
87 				spectral_debug("%s", hexdump_line);
88 				qdf_mem_zero(hexdump_line,
89 					     sizeof(hexdump_line));
90 				loc = 0;
91 			}
92 		}
93 
94 		qdf_assert_always(loc < sizeof(hexdump_line));
95 		loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
96 				" %02x", pc[i]);
97 
98 		if ((pc[i] < 0x20) || (pc[i] > 0x7e))
99 			ascii[mod] = '.';
100 		else
101 			ascii[mod] = pc[i];
102 		ascii[(mod) + 1] = '\0';
103 	}
104 
105 	while ((i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) != 0) {
106 		qdf_assert_always(loc < sizeof(hexdump_line));
107 		loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
108 				"   ");
109 		i++;
110 	}
111 
112 	qdf_assert_always(loc < sizeof(hexdump_line));
113 	snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, "  %s", ascii);
114 	spectral_debug("%s", hexdump_line);
115 }
116 
117 /**
118  * target_if_print_buf() - Prints given buffer for given length
119  * @pbuf: Pointer to buffer
120  * @len: length
121  *
122  * Prints given buffer for given length
123  *
124  * Return: void
125  */
126 static void
127 target_if_print_buf(uint8_t *pbuf, int len)
128 {
129 	int i = 0;
130 
131 	for (i = 0; i < len; i++) {
132 		spectral_debug("%02X ", pbuf[i]);
133 		if (i % 32 == 31)
134 			spectral_debug("\n");
135 	}
136 }
137 
138 int
139 target_if_spectral_dump_fft(uint8_t *pfft, int fftlen)
140 {
141 	int i = 0;
142 
143 	/*
144 	 * TODO : Do not delete the following print
145 	 *        The scripts used to validate Spectral depend on this Print
146 	 */
147 	spectral_debug("SPECTRAL : FFT Length is 0x%x (%d)", fftlen, fftlen);
148 
149 	spectral_debug("fft_data # ");
150 	for (i = 0; i < fftlen; i++)
151 		spectral_debug("%d ", pfft[i]);
152 	spectral_debug("\n");
153 	return 0;
154 }
155 
156 QDF_STATUS target_if_spectral_fw_hang(struct target_if_spectral *spectral)
157 {
158 	struct crash_inject param;
159 
160 	if (!spectral) {
161 		spectral_err("Spectral LMAC object is null");
162 		return QDF_STATUS_E_INVAL;
163 	}
164 	qdf_mem_set(&param, sizeof(param), 0);
165 	param.type = 1; //RECOVERY_SIM_ASSERT
166 
167 	return spectral->param_wmi_cmd_ops.wmi_spectral_crash_inject(
168 		GET_WMI_HDL_FROM_PDEV(spectral->pdev_obj), &param);
169 }
170 
171 void
172 target_if_dbg_print_samp_param(struct target_if_samp_msg_params *p)
173 {
174 	spectral_debug("\nSAMP Packet : -------------------- START --------------------");
175 	spectral_debug("Freq        = %d", p->freq);
176 	spectral_debug("RSSI        = %d", p->rssi);
177 	spectral_debug("Bin Count   = %d", p->pwr_count);
178 	spectral_debug("Timestamp   = %d", p->tstamp);
179 	spectral_debug("SAMP Packet : -------------------- END -----------------------");
180 }
181 
182 void
183 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg)
184 {
185 	int i = 0;
186 
187 	struct spectral_samp_data *p = &ss_msg->samp_data;
188 	struct spectral_classifier_params *pc = &p->classifier_params;
189 	struct interf_src_rsp *pi = &p->interf_list;
190 
191 	spectral_dbg_line();
192 	spectral_debug("Spectral Message");
193 	spectral_dbg_line();
194 	spectral_debug("Signature   :   0x%x", ss_msg->signature);
195 	spectral_debug("Freq        :   %d", ss_msg->freq);
196 	spectral_debug("Freq load   :   %d", ss_msg->freq_loading);
197 	spectral_debug("Intfnc type :   %d", ss_msg->int_type);
198 	spectral_dbg_line();
199 	spectral_debug("Spectral Data info");
200 	spectral_dbg_line();
201 	spectral_debug("data length     :   %d", p->spectral_data_len);
202 	spectral_debug("rssi            :   %d", p->spectral_rssi);
203 	spectral_debug("combined rssi   :   %d", p->spectral_combined_rssi);
204 	spectral_debug("upper rssi      :   %d", p->spectral_upper_rssi);
205 	spectral_debug("lower rssi      :   %d", p->spectral_lower_rssi);
206 	spectral_debug("bw info         :   %d", p->spectral_bwinfo);
207 	spectral_debug("timestamp       :   %d", p->spectral_tstamp);
208 	spectral_debug("max index       :   %d", p->spectral_max_index);
209 	spectral_debug("max exp         :   %d", p->spectral_max_exp);
210 	spectral_debug("max mag         :   %d", p->spectral_max_mag);
211 	spectral_debug("last timstamp   :   %d", p->spectral_last_tstamp);
212 	spectral_debug("upper max idx   :   %d", p->spectral_upper_max_index);
213 	spectral_debug("lower max idx   :   %d", p->spectral_lower_max_index);
214 	spectral_debug("bin power count :   %d", p->bin_pwr_count);
215 	spectral_dbg_line();
216 	spectral_debug("Classifier info");
217 	spectral_dbg_line();
218 	spectral_debug("20/40 Mode      :   %d", pc->spectral_20_40_mode);
219 	spectral_debug("dc index        :   %d", pc->spectral_dc_index);
220 	spectral_debug("dc in MHz       :   %d", pc->spectral_dc_in_mhz);
221 	spectral_debug("upper channel   :   %d", pc->upper_chan_in_mhz);
222 	spectral_debug("lower channel   :   %d", pc->lower_chan_in_mhz);
223 	spectral_dbg_line();
224 	spectral_debug("Interference info");
225 	spectral_dbg_line();
226 	spectral_debug("inter count     :   %d", pi->count);
227 
228 	for (i = 0; i < pi->count; i++) {
229 		spectral_debug("inter type  :   %d",
230 			       pi->interf[i].interf_type);
231 		spectral_debug("min freq    :   %d",
232 			       pi->interf[i].interf_min_freq);
233 		spectral_debug("max freq    :   %d",
234 			       pi->interf[i].interf_max_freq);
235 	}
236 }
237 
238 uint32_t
239 target_if_get_offset_swar_sec80(uint32_t channel_width)
240 {
241 	uint32_t offset = 0;
242 
243 	switch (channel_width) {
244 	case CH_WIDTH_20MHZ:
245 		offset = OFFSET_CH_WIDTH_20;
246 		break;
247 	case CH_WIDTH_40MHZ:
248 		offset = OFFSET_CH_WIDTH_40;
249 		break;
250 	case CH_WIDTH_80MHZ:
251 		offset = OFFSET_CH_WIDTH_80;
252 		break;
253 	case CH_WIDTH_160MHZ:
254 		offset = OFFSET_CH_WIDTH_160;
255 		break;
256 	default:
257 		offset = OFFSET_CH_WIDTH_80;
258 		break;
259 	}
260 	return offset;
261 }
262 
263 /**
264  * target_if_dump_summary_report_gen2() - Dump Spectral Summary Report for gen2
265  * @ptlv: Pointer to Spectral Phyerr TLV
266  * @tlvlen: length
267  * @is_160_format: Indicates whether information provided by HW is in altered
268  *                 format for 802.11ac 160/80+80 MHz support (QCA9984 onwards)
269  *
270  * Dump Spectral Summary Report for gen2
271  *
272  * Return: Success/Failure
273  */
274 static int
275 target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
276 				   int tlvlen, bool is_160_format)
277 {
278 	/*
279 	 * For simplicity, everything is defined as uint32_t (except one).
280 	 * Proper code will later use the right sizes.
281 	 */
282 
283 	/*
284 	 * For easy comparision between MDK team and OS team, the MDK script
285 	 * variable names have been used
286 	 */
287 
288 	uint32_t agc_mb_gain;
289 	uint32_t sscan_gidx;
290 	uint32_t agc_total_gain;
291 	uint32_t recent_rfsat;
292 	uint32_t ob_flag;
293 	uint32_t nb_mask;
294 	uint32_t peak_mag;
295 	int16_t peak_inx;
296 
297 	uint32_t ss_summary_A = 0;
298 	uint32_t ss_summary_B = 0;
299 	uint32_t ss_summary_C = 0;
300 	uint32_t ss_summary_D = 0;
301 	uint32_t ss_summary_E = 0;
302 	struct spectral_phyerr_hdr_gen2 *phdr =
303 	    (struct spectral_phyerr_hdr_gen2 *)(
304 		(uint8_t *)ptlv +
305 		sizeof(struct spectral_phyerr_tlv_gen2));
306 
307 	spectral_debug("SPECTRAL : SPECTRAL SUMMARY REPORT");
308 
309 	if (is_160_format) {
310 		if (tlvlen != 20) {
311 			spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
312 				     tlvlen);
313 			target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
314 			return -EPERM;
315 		}
316 
317 		/* Doing copy as the contents may not be aligned */
318 		qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
319 		qdf_mem_copy(&ss_summary_B,
320 			     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
321 			     sizeof(int));
322 		qdf_mem_copy(&ss_summary_C,
323 			     (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
324 			     sizeof(int));
325 		qdf_mem_copy(&ss_summary_D,
326 			     (uint8_t *)((uint8_t *)phdr + 3 * sizeof(int)),
327 			     sizeof(int));
328 		qdf_mem_copy(&ss_summary_E,
329 			     (uint8_t *)((uint8_t *)phdr + 4 * sizeof(int)),
330 			     sizeof(int));
331 
332 		/*
333 		 * The following is adapted from MDK scripts for
334 		 * easier comparability
335 		 */
336 
337 		recent_rfsat = ((ss_summary_A >> 8) & 0x1);
338 		sscan_gidx = (ss_summary_A & 0xff);
339 		spectral_debug("sscan_gidx=%d, is_recent_rfsat=%d",
340 			       sscan_gidx, recent_rfsat);
341 
342 		/* First segment */
343 		agc_mb_gain = ((ss_summary_B >> 10) & 0x7f);
344 		agc_total_gain = (ss_summary_B & 0x3ff);
345 		nb_mask = ((ss_summary_C >> 22) & 0xff);
346 		ob_flag = ((ss_summary_B >> 17) & 0x1);
347 		peak_inx = (ss_summary_C & 0xfff);
348 		if (peak_inx > 2047)
349 			peak_inx = peak_inx - 4096;
350 		peak_mag = ((ss_summary_C >> 12) & 0x3ff);
351 
352 		spectral_debug("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d",
353 			       agc_total_gain, agc_mb_gain);
354 		spectral_debug("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, peak_index_segid0=%d, peak_mag_segid0=%d",
355 			       nb_mask, ob_flag, peak_inx, peak_mag);
356 
357 		/* Second segment */
358 		agc_mb_gain = ((ss_summary_D >> 10) & 0x7f);
359 		agc_total_gain = (ss_summary_D & 0x3ff);
360 		nb_mask = ((ss_summary_E >> 22) & 0xff);
361 		ob_flag = ((ss_summary_D >> 17) & 0x1);
362 		peak_inx = (ss_summary_E & 0xfff);
363 		if (peak_inx > 2047)
364 			peak_inx = peak_inx - 4096;
365 		peak_mag = ((ss_summary_E >> 12) & 0x3ff);
366 
367 		spectral_debug("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d",
368 			       agc_total_gain, agc_mb_gain);
369 		spectral_debug("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, peak_index_segid1=%d, peak_mag_segid1=%d",
370 			       nb_mask, ob_flag, peak_inx, peak_mag);
371 	} else {
372 		if (tlvlen != 8) {
373 			spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
374 				     tlvlen);
375 			target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
376 			return -EPERM;
377 		}
378 
379 		/* Doing copy as the contents may not be aligned */
380 		qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
381 		qdf_mem_copy(&ss_summary_B,
382 			     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
383 			     sizeof(int));
384 
385 		nb_mask = ((ss_summary_B >> 22) & 0xff);
386 		ob_flag = ((ss_summary_B >> 30) & 0x1);
387 		peak_inx = (ss_summary_B & 0xfff);
388 
389 		if (peak_inx > 2047)
390 			peak_inx = peak_inx - 4096;
391 
392 		peak_mag = ((ss_summary_B >> 12) & 0x3ff);
393 		agc_mb_gain = ((ss_summary_A >> 24) & 0x7f);
394 		agc_total_gain = (ss_summary_A & 0x3ff);
395 		sscan_gidx = ((ss_summary_A >> 16) & 0xff);
396 		recent_rfsat = ((ss_summary_B >> 31) & 0x1);
397 
398 		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",
399 			       nb_mask, ob_flag, peak_inx, peak_mag,
400 			       agc_mb_gain, agc_total_gain, sscan_gidx,
401 			       recent_rfsat);
402 	}
403 
404 	return 0;
405 }
406 
407 /**
408  * target_if_process_sfft_report_gen2() - Process Search FFT Report
409  * @ptlv: Pointer to Spectral Phyerr TLV
410  * @tlvlen: length
411  * @p_fft_info: Pointer to search fft info
412  *
413  * Dump Spectral Summary Report for gen2
414  *
415  * Return: Success/Failure
416  */
417 static int
418 target_if_process_sfft_report_gen2(
419 	struct spectral_phyerr_tlv_gen2 *ptlv,
420 	int tlvlen,
421 	struct spectral_search_fft_info_gen2 *p_fft_info)
422 {
423 	/*
424 	 * For simplicity, everything is defined as uint32_t (except one).
425 	 * Proper code will later use the right sizes.
426 	 */
427 	/*
428 	 * For easy comparision between MDK team and OS team, the MDK script
429 	 * variable names have been used
430 	 */
431 	uint32_t relpwr_db;
432 	uint32_t num_str_bins_ib;
433 	uint32_t base_pwr;
434 	uint32_t total_gain_info;
435 
436 	uint32_t fft_chn_idx;
437 	int16_t peak_inx;
438 	uint32_t avgpwr_db;
439 	uint32_t peak_mag;
440 
441 	uint32_t fft_summary_A = 0;
442 	uint32_t fft_summary_B = 0;
443 	uint8_t *tmp = (uint8_t *)ptlv;
444 	struct spectral_phyerr_hdr_gen2 *phdr =
445 	    (struct spectral_phyerr_hdr_gen2 *)(
446 		tmp +
447 		sizeof(struct spectral_phyerr_tlv_gen2));
448 
449 	/* Relook this */
450 	if (tlvlen < 8) {
451 		spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
452 			     tlvlen);
453 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
454 		return -EPERM;
455 	}
456 
457 	/* Doing copy as the contents may not be aligned */
458 	qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
459 	qdf_mem_copy(&fft_summary_B,
460 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
461 		     sizeof(int));
462 
463 	relpwr_db = ((fft_summary_B >> 26) & 0x3f);
464 	num_str_bins_ib = fft_summary_B & 0xff;
465 	base_pwr = ((fft_summary_A >> 14) & 0x1ff);
466 	total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
467 
468 	fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
469 	peak_inx = fft_summary_A & 0xfff;
470 
471 	if (peak_inx > 2047)
472 		peak_inx = peak_inx - 4096;
473 
474 	avgpwr_db = ((fft_summary_B >> 18) & 0xff);
475 	peak_mag = ((fft_summary_B >> 8) & 0x3ff);
476 
477 	/* Populate the Search FFT Info */
478 	if (p_fft_info) {
479 		p_fft_info->relpwr_db = relpwr_db;
480 		p_fft_info->num_str_bins_ib = num_str_bins_ib;
481 		p_fft_info->base_pwr = base_pwr;
482 		p_fft_info->total_gain_info = total_gain_info;
483 		p_fft_info->fft_chn_idx = fft_chn_idx;
484 		p_fft_info->peak_inx = peak_inx;
485 		p_fft_info->avgpwr_db = avgpwr_db;
486 		p_fft_info->peak_mag = peak_mag;
487 	}
488 
489 	return 0;
490 }
491 
492 /**
493  * target_if_dump_adc_report_gen2() - Dump ADC Reports for gen2
494  * @ptlv: Pointer to Spectral Phyerr TLV
495  * @tlvlen: length
496  *
497  * Dump ADC Reports for gen2
498  *
499  * Return: Success/Failure
500  */
501 static int
502 target_if_dump_adc_report_gen2(
503 	struct spectral_phyerr_tlv_gen2 *ptlv, int tlvlen)
504 {
505 	int i;
506 	uint32_t *pdata;
507 	uint32_t data;
508 
509 	/*
510 	 * For simplicity, everything is defined as uint32_t (except one).
511 	 * Proper code will later use the right sizes.
512 	 */
513 	uint32_t samp_fmt;
514 	uint32_t chn_idx;
515 	uint32_t recent_rfsat;
516 	uint32_t agc_mb_gain;
517 	uint32_t agc_total_gain;
518 
519 	uint32_t adc_summary = 0;
520 
521 	uint8_t *ptmp = (uint8_t *)ptlv;
522 
523 	spectral_debug("SPECTRAL : ADC REPORT");
524 
525 	/* Relook this */
526 	if (tlvlen < 4) {
527 		spectral_err("Unexpected TLV length %d for ADC Report! Hexdump follows",
528 			     tlvlen);
529 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
530 		return -EPERM;
531 	}
532 
533 	qdf_mem_copy(&adc_summary, (uint8_t *)(ptlv + 4), sizeof(int));
534 
535 	samp_fmt = ((adc_summary >> 28) & 0x1);
536 	chn_idx = ((adc_summary >> 24) & 0x3);
537 	recent_rfsat = ((adc_summary >> 23) & 0x1);
538 	agc_mb_gain = ((adc_summary >> 16) & 0x7f);
539 	agc_total_gain = adc_summary & 0x3ff;
540 
541 	spectral_debug("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u agc_total_gain=%u",
542 		       samp_fmt, chn_idx, recent_rfsat, agc_mb_gain,
543 		       agc_total_gain);
544 
545 	for (i = 0; i < (tlvlen / 4); i++) {
546 		pdata = (uint32_t *)(ptmp + 4 + i * 4);
547 		data = *pdata;
548 
549 		/* Interpreting capture format 1 */
550 		if (1) {
551 			uint8_t i1;
552 			uint8_t q1;
553 			uint8_t i2;
554 			uint8_t q2;
555 			int8_t si1;
556 			int8_t sq1;
557 			int8_t si2;
558 			int8_t sq2;
559 
560 			i1 = data & 0xff;
561 			q1 = (data >> 8) & 0xff;
562 			i2 = (data >> 16) & 0xff;
563 			q2 = (data >> 24) & 0xff;
564 
565 			if (i1 > 127)
566 				si1 = i1 - 256;
567 			else
568 				si1 = i1;
569 
570 			if (q1 > 127)
571 				sq1 = q1 - 256;
572 			else
573 				sq1 = q1;
574 
575 			if (i2 > 127)
576 				si2 = i2 - 256;
577 			else
578 				si2 = i2;
579 
580 			if (q2 > 127)
581 				sq2 = q2 - 256;
582 			else
583 				sq2 = q2;
584 
585 			spectral_debug("SPECTRAL ADC : Interpreting capture format 1");
586 			spectral_debug("adc_data_format_1 # %d %d %d",
587 				       2 * i, si1, sq1);
588 			spectral_debug("adc_data_format_1 # %d %d %d",
589 				       2 * i + 1, si2, sq2);
590 		}
591 
592 		/* Interpreting capture format 0 */
593 		if (1) {
594 			uint16_t i1;
595 			uint16_t q1;
596 			int16_t si1;
597 			int16_t sq1;
598 
599 			i1 = data & 0xffff;
600 			q1 = (data >> 16) & 0xffff;
601 			if (i1 > 32767)
602 				si1 = i1 - 65536;
603 			else
604 				si1 = i1;
605 
606 			if (q1 > 32767)
607 				sq1 = q1 - 65536;
608 			else
609 				sq1 = q1;
610 			spectral_debug("SPECTRAL ADC : Interpreting capture format 0");
611 			spectral_debug("adc_data_format_2 # %d %d %d",
612 				       i, si1, sq1);
613 		}
614 	}
615 
616 	spectral_debug("\n");
617 
618 	return 0;
619 }
620 
621 /**
622  * target_if_dump_sfft_report_gen2() - Process Search FFT Report for gen2
623  * @ptlv: Pointer to Spectral Phyerr TLV
624  * @tlvlen: length
625  * @is_160_format: Indicates 160 format
626  *
627  * Process Search FFT Report for gen2
628  *
629  * Return: Success/Failure
630  */
631 static int
632 target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
633 				int tlvlen, bool is_160_format)
634 {
635 	int i;
636 	uint32_t fft_mag;
637 
638 	/*
639 	 * For simplicity, everything is defined as uint32_t (except one).
640 	 * Proper code will later use the right sizes.
641 	 */
642 	/*
643 	 * For easy comparision between MDK team and OS team, the MDK script
644 	 * variable names have been used
645 	 */
646 	uint32_t relpwr_db;
647 	uint32_t num_str_bins_ib;
648 	uint32_t base_pwr;
649 	uint32_t total_gain_info;
650 
651 	uint32_t fft_chn_idx;
652 	int16_t peak_inx;
653 	uint32_t avgpwr_db;
654 	uint32_t peak_mag;
655 	uint8_t segid;
656 
657 	uint32_t fft_summary_A = 0;
658 	uint32_t fft_summary_B = 0;
659 	uint32_t fft_summary_C = 0;
660 	uint8_t *tmp = (uint8_t *)ptlv;
661 	struct spectral_phyerr_hdr_gen2 *phdr =
662 	    (struct spectral_phyerr_hdr_gen2 *)(
663 		tmp +
664 		sizeof(struct spectral_phyerr_tlv_gen2));
665 	uint32_t segid_skiplen = 0;
666 
667 	if (is_160_format)
668 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
669 
670 	spectral_debug("SPECTRAL : SEARCH FFT REPORT");
671 
672 	/* Relook this */
673 	if (tlvlen < (8 + segid_skiplen)) {
674 		spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
675 			     tlvlen);
676 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
677 		return -EPERM;
678 	}
679 
680 	/* Doing copy as the contents may not be aligned */
681 	qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
682 	qdf_mem_copy(&fft_summary_B,
683 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
684 		     sizeof(int));
685 	if (is_160_format)
686 		qdf_mem_copy(&fft_summary_C,
687 			     (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
688 			     sizeof(int));
689 
690 	relpwr_db = ((fft_summary_B >> 26) & 0x3f);
691 	num_str_bins_ib = fft_summary_B & 0xff;
692 	base_pwr = ((fft_summary_A >> 14) & 0x1ff);
693 	total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
694 
695 	fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
696 	peak_inx = fft_summary_A & 0xfff;
697 
698 	if (peak_inx > 2047)
699 		peak_inx = peak_inx - 4096;
700 
701 	avgpwr_db = ((fft_summary_B >> 18) & 0xff);
702 	peak_mag = ((fft_summary_B >> 8) & 0x3ff);
703 
704 	spectral_debug("Header A = 0x%x Header B = 0x%x",
705 		       phdr->hdr_a, phdr->hdr_b);
706 	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",
707 		       base_pwr, total_gain_info, relpwr_db, num_str_bins_ib,
708 		       fft_chn_idx, peak_inx, avgpwr_db, peak_mag);
709 	if (is_160_format) {
710 		segid = fft_summary_C & 0x1;
711 		spectral_debug("Segment ID: %hhu", segid);
712 	}
713 
714 	spectral_debug("FFT bins:");
715 	for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) {
716 		fft_mag = ((uint8_t *)ptlv)[12 + segid_skiplen + i];
717 		spectral_debug("%d %d, ", i, fft_mag);
718 	}
719 
720 	spectral_debug("\n");
721 
722 	return 0;
723 }
724 
725 #ifdef SPECTRAL_DEBUG_SAMP_MSG
726 /**
727  * target_if_spectral_log_SAMP_param() - Log SAMP parameters
728  * @params: Reference to target_if_samp_msg_params
729  *
730  * API to log spectral SAMP message parameters
731  *
732  * Return: None
733  */
734 static void
735 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
736 {
737 	target_if_dbg_print_samp_param(params);
738 }
739 
740 #else
741 static void
742 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
743 {
744 }
745 #endif
746 
747 int
748 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
749 			      uint8_t *data,
750 			      uint32_t datalen,
751 			      struct target_if_spectral_rfqual_info *p_rfqual,
752 			      struct target_if_spectral_chan_info *p_chaninfo,
753 			      uint64_t tsf64,
754 			      struct target_if_spectral_acs_stats *acs_stats)
755 {
756 	/*
757 	 * XXX : The classifier do not use all the members of the SAMP
758 	 *       message data format.
759 	 *       The classifier only depends upon the following parameters
760 	 *
761 	 *          1. Frequency (freq, msg->freq)
762 	 *          2. Spectral RSSI (spectral_rssi,
763 	 *          msg->samp_data.spectral_rssi)
764 	 *          3. Bin Power Count (bin_pwr_count,
765 	 *          msg->samp_data.bin_pwr_count)
766 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
767 	 *          5. Spectral Timestamp (spectral_tstamp,
768 	 *          msg->samp_data.spectral_tstamp)
769 	 *          6. MAC Address (macaddr, msg->macaddr)
770 	 *
771 	 *       This function prepares the params structure and populates it
772 	 *       with
773 	 *       relevant values, this is in turn passed to
774 	 *       spectral_create_samp_msg()
775 	 *       to prepare fully formatted Spectral SAMP message
776 	 *
777 	 *       XXX : Need to verify
778 	 *          1. Order of FFT bin values
779 	 *
780 	 */
781 
782 	struct target_if_samp_msg_params params;
783 	struct spectral_search_fft_info_gen2 search_fft_info;
784 	struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
785 	struct spectral_search_fft_info_gen2 search_fft_info_sec80;
786 	struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
787 		&search_fft_info_sec80;
788 	uint32_t segid_skiplen = 0;
789 
790 	int8_t rssi_up = 0;
791 	int8_t rssi_low = 0;
792 
793 	int8_t chn_idx_highest_enabled = 0;
794 	int8_t chn_idx_lowest_enabled = 0;
795 
796 	uint8_t control_rssi = 0;
797 	uint8_t extension_rssi = 0;
798 	uint8_t combined_rssi = 0;
799 
800 	uint32_t tstamp = 0;
801 
802 	struct target_if_spectral_ops *p_sops =
803 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
804 
805 	struct spectral_phyerr_tlv_gen2 *ptlv =
806 		(struct spectral_phyerr_tlv_gen2 *)data;
807 	struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
808 	struct spectral_phyerr_fft_gen2 *pfft = NULL;
809 	struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
810 
811 	uint8_t segid = 0;
812 	uint8_t segid_sec80 = 0;
813 
814 	if (spectral->is_160_format)
815 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
816 
817 	pfft = (struct spectral_phyerr_fft_gen2 *)(
818 			data +
819 			sizeof(struct spectral_phyerr_tlv_gen2) +
820 			sizeof(struct spectral_phyerr_hdr_gen2) +
821 			segid_skiplen);
822 
823 	/*
824 	 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
825 	 * and use this facility inside spectral_dump_phyerr_data()
826 	 * and supporting functions.
827 	 */
828 	if (spectral_debug_level & DEBUG_SPECTRAL2)
829 		target_if_spectral_dump_phyerr_data_gen2(
830 					data, datalen,
831 					spectral->is_160_format);
832 
833 	if (spectral_debug_level & DEBUG_SPECTRAL4) {
834 		target_if_spectral_dump_phyerr_data_gen2(
835 					data, datalen,
836 					spectral->is_160_format);
837 		spectral_debug_level = DEBUG_SPECTRAL;
838 	}
839 
840 	if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
841 		/*
842 		 * EV# 118023: We tentatively disable the below print
843 		 * and provide stats instead.
844 		 */
845 		spectral->diag_stats.spectral_mismatch++;
846 		return -EPERM;
847 	}
848 
849 	OS_MEMZERO(&params, sizeof(params));
850 	/* Gen 2 only supports normal Spectral scan currently */
851 	params.smode = SPECTRAL_SCAN_MODE_NORMAL;
852 
853 	if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
854 		if (spectral->is_160_format) {
855 			segid = *((SPECTRAL_SEGID_INFO *)(
856 				  (uint8_t *)ptlv +
857 				  sizeof(struct spectral_phyerr_tlv_gen2) +
858 				  sizeof(struct spectral_phyerr_hdr_gen2)));
859 
860 			if (segid != 0) {
861 				struct spectral_diag_stats *p_diag_stats =
862 					&spectral->diag_stats;
863 				p_diag_stats->spectral_vhtseg1id_mismatch++;
864 				return -EPERM;
865 			}
866 		}
867 
868 		target_if_process_sfft_report_gen2(ptlv, ptlv->length,
869 						   &search_fft_info);
870 
871 		tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
872 
873 		combined_rssi = p_rfqual->rssi_comb;
874 
875 		if (spectral->upper_is_control)
876 			rssi_up = control_rssi;
877 		else
878 			rssi_up = extension_rssi;
879 
880 		if (spectral->lower_is_control)
881 			rssi_low = control_rssi;
882 		else
883 			rssi_low = extension_rssi;
884 
885 		params.rssi = p_rfqual->rssi_comb;
886 		params.lower_rssi = rssi_low;
887 		params.upper_rssi = rssi_up;
888 
889 		if (spectral->sc_spectral_noise_pwr_cal) {
890 			params.chain_ctl_rssi[0] =
891 			    p_rfqual->pc_rssi_info[0].rssi_pri20;
892 			params.chain_ctl_rssi[1] =
893 			    p_rfqual->pc_rssi_info[1].rssi_pri20;
894 			params.chain_ctl_rssi[2] =
895 			    p_rfqual->pc_rssi_info[2].rssi_pri20;
896 			params.chain_ext_rssi[0] =
897 			    p_rfqual->pc_rssi_info[0].rssi_sec20;
898 			params.chain_ext_rssi[1] =
899 			    p_rfqual->pc_rssi_info[1].rssi_sec20;
900 			params.chain_ext_rssi[2] =
901 			    p_rfqual->pc_rssi_info[2].rssi_sec20;
902 		}
903 
904 		/*
905 		 * XXX : This actually depends on the programmed chain mask
906 		 *       This value decides the per-chain enable mask to select
907 		 *       the input ADC for search FTT.
908 		 *       For modes upto VHT80, if more than one chain is
909 		 *       enabled, the max valid chain
910 		 *       is used. LSB corresponds to chain zero.
911 		 *       For VHT80_80 and VHT160, the lowest enabled chain is
912 		 *       used for primary
913 		 *       detection and highest enabled chain is used for
914 		 *       secondary detection.
915 		 *
916 		 * XXX : The current algorithm do not use these control and
917 		 *       extension channel
918 		 *       Instead, it just relies on the combined RSSI values
919 		 *       only.
920 		 *       For fool-proof detection algorithm, we should take
921 		 *       these RSSI values in to account.
922 		 *       This is marked for future enhancements.
923 		 */
924 		chn_idx_highest_enabled =
925 		   ((spectral->params[params.smode].ss_chn_mask & 0x8) ? 3 :
926 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 :
927 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 0);
928 		chn_idx_lowest_enabled =
929 		   ((spectral->params[params.smode].ss_chn_mask & 0x1) ? 0 :
930 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 :
931 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 3);
932 		control_rssi = (uint8_t)
933 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
934 		extension_rssi = (uint8_t)
935 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
936 
937 		params.bwinfo = 0;
938 		params.tstamp = 0;
939 		params.max_mag = p_sfft->peak_mag;
940 
941 		params.max_index = p_sfft->peak_inx;
942 		params.max_exp = 0;
943 		params.peak = 0;
944 		params.bin_pwr_data = (uint8_t *)pfft;
945 		params.freq = p_sops->get_current_channel(spectral);
946 		params.freq_loading = 0;
947 
948 		params.interf_list.count = 0;
949 		params.max_lower_index = 0;
950 		params.max_upper_index = 0;
951 		params.nb_lower = 0;
952 		params.nb_upper = 0;
953 		/*
954 		 * For modes upto VHT80, the noise floor is populated with the
955 		 * one corresponding
956 		 * to the highest enabled antenna chain
957 		 */
958 		params.noise_floor =
959 		    p_rfqual->noise_floor[chn_idx_highest_enabled];
960 		params.datalen = ptlv->length;
961 		params.pwr_count = ptlv->length -
962 		    sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen;
963 		params.tstamp = (tsf64 & SPECTRAL_TSMASK);
964 
965 		acs_stats->ctrl_nf = params.noise_floor;
966 		acs_stats->ext_nf = params.noise_floor;
967 		acs_stats->nfc_ctl_rssi = control_rssi;
968 		acs_stats->nfc_ext_rssi = extension_rssi;
969 
970 		if (spectral->is_160_format &&
971 		    spectral->ch_width == CH_WIDTH_160MHZ) {
972 			/*
973 			 * We expect to see one more Search FFT report, and it
974 			 * should be equal in size to the current one.
975 			 */
976 			if (datalen < (
977 				2 * (
978 				sizeof(struct spectral_phyerr_tlv_gen2) +
979 				ptlv->length))) {
980 				struct spectral_diag_stats *p_diag_stats =
981 					&spectral->diag_stats;
982 				p_diag_stats->spectral_sec80_sfft_insufflen++;
983 				return -EPERM;
984 			}
985 
986 			ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
987 				      data +
988 				      sizeof(struct spectral_phyerr_tlv_gen2) +
989 				      ptlv->length);
990 
991 			if (ptlv_sec80->signature !=
992 			    SPECTRAL_PHYERR_SIGNATURE_GEN2) {
993 				spectral->diag_stats.spectral_mismatch++;
994 				return -EPERM;
995 			}
996 
997 			if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
998 				spectral->diag_stats.spectral_no_sec80_sfft++;
999 				return -EPERM;
1000 			}
1001 
1002 			segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
1003 				(uint8_t *)ptlv_sec80 +
1004 				sizeof(struct spectral_phyerr_tlv_gen2) +
1005 				sizeof(struct spectral_phyerr_hdr_gen2)));
1006 
1007 			if (segid_sec80 != 1) {
1008 				struct spectral_diag_stats *p_diag_stats =
1009 					&spectral->diag_stats;
1010 				p_diag_stats->spectral_vhtseg2id_mismatch++;
1011 				return -EPERM;
1012 			}
1013 
1014 			params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
1015 			params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
1016 
1017 			target_if_process_sfft_report_gen2(
1018 				ptlv_sec80,
1019 				ptlv_sec80->length,
1020 				&search_fft_info_sec80);
1021 
1022 			pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
1023 				((uint8_t *)ptlv_sec80) +
1024 				sizeof(struct spectral_phyerr_tlv_gen2) +
1025 				sizeof(struct spectral_phyerr_hdr_gen2) +
1026 				segid_skiplen);
1027 
1028 			/* XXX: Confirm. TBD at SoD. */
1029 			params.rssi_sec80 = p_rfqual->rssi_comb;
1030 			if (spectral->is_sec80_rssi_war_required)
1031 				params.rssi_sec80 =
1032 				    target_if_get_combrssi_sec80_seg_gen2
1033 				    (spectral, &search_fft_info_sec80);
1034 			/* XXX: Determine dynamically. TBD at SoD. */
1035 			/*
1036 			 * For VHT80_80/VHT160, the noise floor for primary
1037 			 * 80MHz segment is populated with the
1038 			 * lowest enabled antenna chain and the noise floor for
1039 			 * secondary 80MHz segment is populated
1040 			 * with the highest enabled antenna chain
1041 			 */
1042 			params.noise_floor_sec80 =
1043 			    p_rfqual->noise_floor[chn_idx_highest_enabled];
1044 			params.noise_floor =
1045 			    p_rfqual->noise_floor[chn_idx_lowest_enabled];
1046 
1047 			params.max_mag_sec80 = p_sfft_sec80->peak_mag;
1048 			params.max_index_sec80 = p_sfft_sec80->peak_inx;
1049 			/* XXX Does this definition of datalen *still hold? */
1050 			params.datalen_sec80 = ptlv_sec80->length;
1051 			params.pwr_count_sec80 =
1052 			    ptlv_sec80->length -
1053 			    sizeof(struct spectral_phyerr_hdr_gen2) -
1054 			    segid_skiplen;
1055 			params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80;
1056 		}
1057 		qdf_mem_copy(&params.classifier_params,
1058 			     &spectral->classifier_params,
1059 			     sizeof(struct spectral_classifier_params));
1060 
1061 		target_if_spectral_log_SAMP_param(&params);
1062 		target_if_spectral_create_samp_msg(spectral, &params);
1063 	}
1064 
1065 	return 0;
1066 }
1067 
1068 int
1069 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr)
1070 {
1071 	uint32_t a = 0;
1072 	uint32_t b = 0;
1073 
1074 	qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int));
1075 	qdf_mem_copy(&b,
1076 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
1077 		     sizeof(int));
1078 
1079 	spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a);
1080 	spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b);
1081 	return 0;
1082 }
1083 
1084 int8_t
1085 target_if_get_combrssi_sec80_seg_gen2(
1086 	struct target_if_spectral *spectral,
1087 	struct spectral_search_fft_info_gen2 *p_sfft_sec80)
1088 {
1089 	uint32_t avgpwr_db = 0;
1090 	uint32_t total_gain_db = 0;
1091 	uint32_t offset = 0;
1092 	int8_t comb_rssi = 0;
1093 
1094 	/* Obtain required parameters for algorithm from search FFT report */
1095 	avgpwr_db = p_sfft_sec80->avgpwr_db;
1096 	total_gain_db = p_sfft_sec80->total_gain_info;
1097 
1098 	/* Calculate offset */
1099 	offset = target_if_get_offset_swar_sec80(spectral->ch_width);
1100 
1101 	/* Calculate RSSI */
1102 	comb_rssi = ((avgpwr_db - total_gain_db) + offset);
1103 
1104 	return comb_rssi;
1105 }
1106 
1107 int
1108 target_if_spectral_dump_tlv_gen2(
1109 	struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format)
1110 {
1111 	int ret = 0;
1112 
1113 	/*
1114 	 * TODO : Do not delete the following print
1115 	 *        The scripts used to validate Spectral depend on this Print
1116 	 */
1117 	spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)",
1118 		       ptlv->length, ptlv->length);
1119 
1120 	switch (ptlv->tag) {
1121 	case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
1122 		ret =
1123 		    target_if_dump_summary_report_gen2(
1124 			ptlv, ptlv->length, is_160_format);
1125 		break;
1126 
1127 	case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
1128 		ret =
1129 		    target_if_dump_sfft_report_gen2(ptlv, ptlv->length,
1130 						    is_160_format);
1131 		break;
1132 
1133 	case TLV_TAG_ADC_REPORT_GEN2:
1134 		ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length);
1135 		break;
1136 
1137 	default:
1138 		spectral_warn("INVALID TLV");
1139 		ret = -1;
1140 		break;
1141 	}
1142 
1143 	return ret;
1144 }
1145 
1146 int
1147 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen,
1148 					 bool is_160_format)
1149 {
1150 	struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
1151 	uint32_t bytes_processed = 0;
1152 	uint32_t bytes_remaining = datalen;
1153 	uint32_t curr_tlv_complete_size = 0;
1154 
1155 	if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) {
1156 		spectral_err("Total PHY error data length %u too short to contain any TLVs",
1157 			     datalen);
1158 		return -EPERM;
1159 	}
1160 
1161 	while (bytes_processed < datalen) {
1162 		if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) {
1163 			spectral_err("Remaining PHY error data length %u too short to contain a TLV",
1164 				     bytes_remaining);
1165 			return -EPERM;
1166 		}
1167 
1168 		ptlv = (struct spectral_phyerr_tlv_gen2 *)(data +
1169 							   bytes_processed);
1170 
1171 		if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1172 			spectral_err("Invalid signature 0x%x!",
1173 				     ptlv->signature);
1174 			return -EPERM;
1175 		}
1176 
1177 		curr_tlv_complete_size =
1178 			sizeof(struct spectral_phyerr_tlv_gen2) +
1179 			ptlv->length;
1180 
1181 		if (curr_tlv_complete_size > bytes_remaining) {
1182 			spectral_err("TLV size %d greater than number of bytes remaining %d",
1183 				     curr_tlv_complete_size, bytes_remaining);
1184 			return -EPERM;
1185 		}
1186 
1187 		if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
1188 			return -EPERM;
1189 
1190 		bytes_processed += curr_tlv_complete_size;
1191 		bytes_remaining = datalen - bytes_processed;
1192 	}
1193 
1194 	return 0;
1195 }
1196 
1197 int
1198 target_if_process_sfft_report_gen3(
1199 	struct spectral_phyerr_fft_report_gen3 *p_fft_report,
1200 	struct spectral_search_fft_info_gen3 *p_sfft)
1201 {
1202 	/*
1203 	 * For simplicity, everything is defined as uint32_t (except one).
1204 	 * Proper code will later use the right sizes.
1205 	 */
1206 	/*
1207 	 * For easy comparision between MDK team and OS team, the MDK script
1208 	 * variable names have been used
1209 	 */
1210 	int32_t peak_sidx;
1211 	int32_t peak_mag;
1212 
1213 	/* Populate the Search FFT Info */
1214 	if (p_sfft) {
1215 		p_sfft->timestamp = p_fft_report->fft_timestamp;
1216 
1217 		p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a,
1218 						       2, 0);
1219 		p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2);
1220 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
1221 						       12, 5);
1222 
1223 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17);
1224 		p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
1225 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28);
1226 
1227 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
1228 						       9, 0);
1229 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
1230 							 8, 9);
1231 
1232 		p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
1233 							   8, 0);
1234 		peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8);
1235 		p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
1236 		p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
1237 						     7, 18);
1238 		p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
1239 						     7, 25);
1240 	}
1241 
1242 	return 0;
1243 }
1244 
1245 int
1246 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral,
1247 			enum spectral_scan_mode smode,
1248 			struct spectral_phyerr_fft_report_gen3 *p_fft_report,
1249 			struct spectral_search_fft_info_gen3 *p_sfft)
1250 {
1251 	int i = 0;
1252 	int fft_mag = 0;
1253 	int fft_hdr_length = (p_fft_report->fft_hdr_length * 4);
1254 	int report_len = (fft_hdr_length + 8);
1255 	int fft_bin_len = (fft_hdr_length - 16);
1256 	int fft_bin_len_to_dump = fft_bin_len;
1257 	int fft_bin_len_adj = 0;
1258 	int fft_bin_len_inband_tfer = 0;
1259 
1260 	if ((spectral->params[smode].ss_rpt_mode == 1) &&
1261 	    spectral->null_fftbin_adj) {
1262 		/* fft_bin_len_adj is intentionally left at 0. */
1263 		fft_bin_len_to_dump = 0;
1264 	} else {
1265 		/*
1266 		 * Divide fft bin length by appropriate factor depending
1267 		 * on the value of fftbin_size_war.
1268 		 */
1269 		if (spectral->fftbin_size_war ==
1270 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
1271 			fft_bin_len_adj = fft_bin_len >> 2;
1272 		else if (spectral->fftbin_size_war ==
1273 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
1274 			/* Ideally we should be dividing fft bin length by 2.
1275 			 * Due to a HW bug, actual length is two times the
1276 			 * expected length.
1277 			 */
1278 			fft_bin_len_adj = fft_bin_len >> 2;
1279 		} else
1280 			fft_bin_len_adj = fft_bin_len;
1281 
1282 		if ((spectral->params[smode].ss_rpt_mode == 2) &&
1283 		    spectral->inband_fftbin_size_adj) {
1284 			fft_bin_len_adj >>= 1;
1285 			fft_bin_len_inband_tfer = fft_bin_len >> 1;
1286 			fft_bin_len_to_dump = fft_bin_len_inband_tfer;
1287 		}
1288 	}
1289 
1290 	spectral_debug("#############################################################");
1291 	spectral_debug("Spectral search fft_report");
1292 	spectral_debug("fft_timestamp  = 0x%x\nfft_hdr_length = %d(32 bit words)\nfft_hdr_tag    = 0x%x\nfft_hdr_sig    = 0x%x",
1293 		       p_fft_report->fft_timestamp,
1294 		       p_fft_report->fft_hdr_length,
1295 		       p_fft_report->fft_hdr_tag, p_fft_report->fft_hdr_sig);
1296 
1297 	spectral_debug("Length field in search fft report is %d(0x%x) bytes",
1298 		       fft_hdr_length, fft_hdr_length);
1299 	spectral_debug("Total length of search fft report is %d(0x%x) bytes",
1300 		       report_len, report_len);
1301 	spectral_debug("Target reported fftbins in report is %d(0x%x)",
1302 		       fft_bin_len,
1303 		       fft_bin_len);
1304 
1305 	if ((spectral->params[smode].ss_rpt_mode == 1) &&
1306 	    spectral->null_fftbin_adj)
1307 		spectral_debug("WAR: Considering number of FFT bins as 0");
1308 	else if ((spectral->params[smode].ss_rpt_mode == 2) &&
1309 		 spectral->inband_fftbin_size_adj) {
1310 		spectral_debug("FW fftbins actually transferred (in-band report mode) "
1311 					"%d(0x%x)",
1312 					fft_bin_len_inband_tfer, fft_bin_len_inband_tfer);
1313 	}
1314 
1315 	spectral_debug("Actual number of fftbins in report is %d(0x%x)\n",
1316 			fft_bin_len_adj, fft_bin_len_adj);
1317 
1318 	spectral_debug("fft_detector_id = %u\nfft_num = %u\nfft_radar_check = %u\nfft_peak_sidx = %d\nfft_chn_idx = %u\nfft_base_pwr_db = %u\nfft_total_gain_db   = %u\nfft_num_str_bins_ib = %u\nfft_peak_mag   = %d\nfft_avgpwr_db  = %u\nfft_relpwr_db  = %u",
1319 		       p_sfft->fft_detector_id,
1320 		       p_sfft->fft_num,
1321 		       p_sfft->fft_radar_check,
1322 		       p_sfft->fft_peak_sidx,
1323 		       p_sfft->fft_chn_idx,
1324 		       p_sfft->fft_base_pwr_db,
1325 		       p_sfft->fft_total_gain_db,
1326 		       p_sfft->fft_num_str_bins_ib,
1327 		       p_sfft->fft_peak_mag,
1328 		       p_sfft->fft_avgpwr_db, p_sfft->fft_relpwr_db);
1329 
1330 	if (fft_bin_len_to_dump > 0) {
1331 		spectral_debug("FFT bins:");
1332 		for (i = 0; i < fft_bin_len_to_dump; i++) {
1333 			if (i % 16 == 0)
1334 				spectral_debug("\n%d :", i);
1335 			fft_mag =
1336 			   ((uint8_t *)p_fft_report)[SPECTRAL_FFT_BINS_POS + i];
1337 			spectral_debug("%d ", fft_mag);
1338 		}
1339 	}
1340 	spectral_debug("\n");
1341 	spectral_debug("#############################################################");
1342 
1343 	return 0;
1344 }
1345 
1346 QDF_STATUS
1347 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
1348 				       uint8_t detector_id) {
1349 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1350 
1351 	if (spectral->ch_width != CH_WIDTH_160MHZ)
1352 		return QDF_STATUS_E_FAILURE;
1353 
1354 	/* agile reports should not be coupled with 160 MHz state machine
1355 	 * for normal Spectral
1356 	 */
1357 	if (detector_id == SPECTRAL_DETECTOR_AGILE)
1358 		return QDF_STATUS_SUCCESS;
1359 
1360 	switch (spectral->state_160mhz_delivery) {
1361 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
1362 		if (detector_id == SPECTRAL_DETECTOR_PRIMARY)
1363 			spectral->state_160mhz_delivery =
1364 				SPECTRAL_REPORT_RX_PRIMARY80;
1365 		else {
1366 			status = QDF_STATUS_E_FAILURE;
1367 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
1368 		}
1369 		break;
1370 
1371 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
1372 		if (detector_id == SPECTRAL_DETECTOR_SECONDARY)
1373 			spectral->state_160mhz_delivery =
1374 				SPECTRAL_REPORT_RX_SECONDARY80;
1375 		else {
1376 			spectral->state_160mhz_delivery =
1377 				SPECTRAL_REPORT_WAIT_PRIMARY80;
1378 			status = QDF_STATUS_E_FAILURE;
1379 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
1380 		}
1381 		break;
1382 
1383 	case SPECTRAL_REPORT_RX_SECONDARY80:
1384 		/* We don't care about detector id in this state. */
1385 		reset_160mhz_delivery_state_machine(spectral,
1386 						    SPECTRAL_SCAN_MODE_NORMAL);
1387 		break;
1388 
1389 	case SPECTRAL_REPORT_RX_PRIMARY80:
1390 		/* We don't care about detector id in this state */
1391 		spectral->state_160mhz_delivery =
1392 				SPECTRAL_REPORT_WAIT_SECONDARY80;
1393 		break;
1394 
1395 	default:
1396 		break;
1397 	}
1398 
1399 	return status;
1400 }
1401 
1402 #ifdef DIRECT_BUF_RX_ENABLE
1403 /**
1404  * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector
1405  * ID from Spectral summary report
1406  * @data: Pointer to Spectral summary report
1407  *
1408  * Return: Detector ID
1409  */
1410 static uint8_t
1411 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data) {
1412 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
1413 	uint8_t detector_id;
1414 
1415 	qdf_assert_always(data);
1416 
1417 	psscan_summary_report =
1418 		(struct spectral_sscan_summary_report_gen3 *)data;
1419 
1420 	detector_id = get_bitfield(
1421 			psscan_summary_report->hdr_a,
1422 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
1423 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
1424 
1425 	return detector_id;
1426 }
1427 
1428 /**
1429  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
1430  * report
1431  * @spectral: Pointer to Spectral object
1432  * @data: Pointer to Spectral summary report
1433  * @fields: Pointer to structure to be populated with extracted fields
1434  *
1435  * Consume Spectral summary report for gen3
1436  *
1437  * Return: void
1438  */
1439 static void
1440 target_if_consume_sscan_summary_report_gen3(struct target_if_spectral *spectral,
1441 					    uint8_t *data,
1442 					    struct sscan_report_fields_gen3
1443 						*fields) {
1444 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
1445 
1446 	qdf_assert_always(spectral);
1447 	qdf_assert_always(data);
1448 	qdf_assert_always(fields);
1449 
1450 	psscan_summary_report =
1451 		(struct spectral_sscan_summary_report_gen3 *)data;
1452 
1453 	fields->sscan_agc_total_gain = get_bitfield(
1454 			psscan_summary_report->hdr_a,
1455 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
1456 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
1457 	fields->inband_pwr_db = get_bitfield(
1458 			psscan_summary_report->hdr_a,
1459 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
1460 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
1461 	fields->sscan_pri80 = get_bitfield(
1462 			psscan_summary_report->hdr_a,
1463 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
1464 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
1465 	fields->sscan_gainchange = get_bitfield(
1466 			psscan_summary_report->hdr_b,
1467 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3,
1468 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3);
1469 }
1470 
1471 /**
1472  * target_if_verify_sig_and_tag_gen3() - Verify tag and signature
1473  *                                       of spectral report
1474  * @spectral: Pointer to spectral object
1475  * @data: Pointer to spectral summary report
1476  * @exp_tag: iexpected tag value
1477  *
1478  * Process fft report for gen3
1479  *
1480  * Return: SUCCESS/FAILURE
1481  */
1482 static int
1483 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral,
1484 				  uint8_t *data, uint8_t exp_tag)
1485 {
1486 	uint8_t tag = 0;
1487 	uint8_t signature = 0;
1488 
1489 	/* Peek into the data to figure out whether
1490 	 *      1) Signature matches the expected value
1491 	 *      2) What is inside the package (TAG ID is used for finding this)
1492 	 */
1493 	tag = *(data + PHYERR_HDR_TAG_POS);
1494 	signature = *(data + PHYERR_HDR_SIG_POS);
1495 
1496 	if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
1497 		spectral->diag_stats.spectral_mismatch++;
1498 		return -EINVAL;
1499 	}
1500 
1501 	if (tag != exp_tag) {
1502 		spectral->diag_stats.spectral_mismatch++;
1503 		return -EINVAL;
1504 	}
1505 
1506 	return 0;
1507 }
1508 
1509 static uint8_t
1510 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)
1511 {
1512 	uint8_t idx;
1513 
1514 	for (idx = 0; idx < DBR_MAX_CHAINS; idx++) {
1515 		if (chainmask & 0x1)
1516 			break;
1517 		chainmask >>= 1;
1518 	}
1519 	return idx;
1520 }
1521 
1522 static QDF_STATUS
1523 target_if_get_spectral_mode(enum spectral_detector_id detector_id,
1524 			    enum spectral_scan_mode *smode) {
1525 	switch (detector_id) {
1526 	case SPECTRAL_DETECTOR_PRIMARY:
1527 	case SPECTRAL_DETECTOR_SECONDARY:
1528 		*smode = SPECTRAL_SCAN_MODE_NORMAL;
1529 		break;
1530 
1531 	case SPECTRAL_DETECTOR_AGILE:
1532 		*smode = SPECTRAL_SCAN_MODE_AGILE;
1533 		break;
1534 
1535 	default:
1536 		spectral_err("Invalid Spectral detector id");
1537 		return QDF_STATUS_E_FAILURE;
1538 	}
1539 
1540 	return QDF_STATUS_SUCCESS;
1541 }
1542 
1543 #ifdef DIRECT_BUF_RX_DEBUG
1544 static void target_if_spectral_check_buffer_poisoning(
1545 	struct target_if_spectral *spectral,
1546 	struct spectral_report *report,
1547 	int num_fft_bins, enum spectral_scan_mode smode)
1548 {
1549 	uint32_t *data;
1550 	size_t len;
1551 	size_t words_to_check =
1552 		sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
1553 	bool poisoned_words_found = false;
1554 
1555 	if (!spectral) {
1556 		spectral_err_rl("Spectral LMAC object is null");
1557 		return;
1558 	}
1559 
1560 	if (!spectral->dbr_buff_debug)
1561 		return;
1562 
1563 	if (!report) {
1564 		spectral_err_rl("Spectral report is null");
1565 		return;
1566 	}
1567 
1568 	/* Add search FFT report */
1569 	if (spectral->params[smode].ss_rpt_mode > 0)
1570 		words_to_check +=
1571 			sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
1572 
1573 	/* Now add the number of FFT bins */
1574 	if (spectral->params[smode].ss_rpt_mode > 1) {
1575 		/* Caller should take care to pass correct number of FFT bins */
1576 		if (spectral->fftbin_size_war ==
1577 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
1578 			words_to_check += num_fft_bins;
1579 		else if (spectral->fftbin_size_war ==
1580 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE)
1581 			words_to_check += (num_fft_bins >> 1);
1582 	}
1583 
1584 	data = (uint32_t *)report->data;
1585 	for (len = 0; len < words_to_check; ++len) {
1586 		if (*data == MEM_POISON_SIGNATURE) {
1587 			spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK",
1588 				     MEM_POISON_SIGNATURE,
1589 				     (len << 2), report->data);
1590 			poisoned_words_found = true;
1591 			break;
1592 		}
1593 		++data;
1594 	}
1595 
1596 	/* Crash the FW even if one word is poisoned */
1597 	if (poisoned_words_found) {
1598 		spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows",
1599 			     MEM_POISON_SIGNATURE);
1600 		target_if_spectral_hexdump((unsigned char *)report->data,
1601 					   words_to_check << 2);
1602 		spectral_err("Asserting the FW");
1603 		target_if_spectral_fw_hang(spectral);
1604 	}
1605 }
1606 
1607 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
1608 					 uint8_t *buf, uint32_t current_ts)
1609 {
1610 	if (!spectral) {
1611 		spectral_err_rl("Spectral LMAC object is null");
1612 		return;
1613 	}
1614 
1615 	if (!spectral->dbr_buff_debug)
1616 		return;
1617 
1618 	if (spectral->prev_tstamp) {
1619 		if (current_ts == spectral->prev_tstamp) {
1620 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
1621 				     current_ts, buf);
1622 			target_if_spectral_fw_hang(spectral);
1623 		}
1624 	}
1625 	spectral->prev_tstamp = current_ts;
1626 }
1627 #else
1628 static void target_if_spectral_check_buffer_poisoning(
1629 	struct target_if_spectral *spectral,
1630 	struct spectral_report *report,
1631 	int num_fft_bins, enum spectral_scan_mode smode)
1632 {
1633 }
1634 
1635 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
1636 					 uint8_t *buf, uint32_t current_ts)
1637 {
1638 }
1639 #endif
1640 
1641 int
1642 target_if_consume_spectral_report_gen3(
1643 	 struct target_if_spectral *spectral,
1644 	 struct spectral_report *report)
1645 {
1646 	/*
1647 	 * XXX : The classifier do not use all the members of the SAMP
1648 	 *       message data format.
1649 	 *       The classifier only depends upon the following parameters
1650 	 *
1651 	 *          1. Frequency (freq, msg->freq)
1652 	 *          2. Spectral RSSI (spectral_rssi,
1653 	 *          msg->samp_data.spectral_rssi)
1654 	 *          3. Bin Power Count (bin_pwr_count,
1655 	 *          msg->samp_data.bin_pwr_count)
1656 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
1657 	 *          5. Spectral Timestamp (spectral_tstamp,
1658 	 *          msg->samp_data.spectral_tstamp)
1659 	 *          6. MAC Address (macaddr, msg->macaddr)
1660 	 *
1661 	 *       This function prepares the params structure and populates it
1662 	 *       with
1663 	 *       relevant values, this is in turn passed to
1664 	 *       spectral_create_samp_msg()
1665 	 *       to prepare fully formatted Spectral SAMP message
1666 	 *
1667 	 *       XXX : Need to verify
1668 	 *          1. Order of FFT bin values
1669 	 *
1670 	 */
1671 	uint64_t tsf64 = 0;
1672 	struct target_if_samp_msg_params params = {0};
1673 	struct spectral_search_fft_info_gen3 search_fft_info;
1674 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
1675 	int8_t chn_idx_lowest_enabled  = 0;
1676 	int fft_hdr_length = 0;
1677 	int report_len = 0;
1678 	int fft_bin_len = 0;
1679 	struct target_if_spectral_ops *p_sops =
1680 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1681 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
1682 	int8_t rssi;
1683 	uint8_t *data = report->data;
1684 	struct wlan_objmgr_vdev *vdev;
1685 	uint8_t vdev_rxchainmask;
1686 	struct sscan_report_fields_gen3 sscan_report_fields;
1687 	enum spectral_detector_id detector_id;
1688 	QDF_STATUS ret;
1689 
1690 	params.smode = SPECTRAL_SCAN_MODE_NORMAL;
1691 
1692 	/* Process Spectral scan summary report */
1693 	if (target_if_verify_sig_and_tag_gen3(
1694 			spectral, data,
1695 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
1696 		spectral_err_rl("Wrong tag/sig in sscan summary");
1697 		goto fail;
1698 	}
1699 
1700 	detector_id = target_if_get_detector_id_sscan_summary_report_gen3(data);
1701 	if (detector_id > SPECTRAL_DETECTOR_AGILE) {
1702 		spectral->diag_stats.spectral_invalid_detector_id++;
1703 		spectral_err("Invalid detector id %u, expected is 0/1/2",
1704 			     detector_id);
1705 		goto fail;
1706 	}
1707 	target_if_consume_sscan_summary_report_gen3(spectral, data,
1708 						    &sscan_report_fields);
1709 	/* Advance buf pointer to the search fft report */
1710 	data += sizeof(struct spectral_sscan_summary_report_gen3);
1711 
1712 	if ((detector_id == SPECTRAL_DETECTOR_AGILE) ||
1713 	    is_primaryseg_expected(spectral)) {
1714 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
1715 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
1716 		params.agc_total_gain =
1717 			sscan_report_fields.sscan_agc_total_gain;
1718 		params.gainchange = sscan_report_fields.sscan_gainchange;
1719 		params.pri80ind = sscan_report_fields.sscan_pri80;
1720 
1721 		/* Process Spectral search FFT report */
1722 		if (target_if_verify_sig_and_tag_gen3(
1723 				spectral, data,
1724 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
1725 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
1726 					detector_id);
1727 			goto fail;
1728 		}
1729 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
1730 		fft_hdr_length = p_fft_report->fft_hdr_length * 4;
1731 		if (fft_hdr_length < 16) {
1732 			spectral_err("Wrong TLV length %u, detector id = %d",
1733 				     fft_hdr_length, detector_id);
1734 			goto fail;
1735 		}
1736 
1737 		report_len = (fft_hdr_length + 8);
1738 
1739 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft);
1740 		/* It is expected to have same detector id for
1741 		 * summary and fft report
1742 		 */
1743 		if (detector_id != p_sfft->fft_detector_id) {
1744 			spectral_err_rl
1745 				("Different detid in ssummary(%u) and sfft(%u)",
1746 				 detector_id, p_sfft->fft_detector_id);
1747 			goto fail;
1748 		}
1749 
1750 		if (detector_id > SPECTRAL_DETECTOR_AGILE) {
1751 			spectral->diag_stats.spectral_invalid_detector_id++;
1752 			spectral_err("Invalid detector id %u, expected is 0/2",
1753 				     detector_id);
1754 			goto fail;
1755 		}
1756 
1757 		ret = target_if_get_spectral_mode(detector_id, &params.smode);
1758 		if (QDF_IS_STATUS_ERROR(ret)) {
1759 			spectral_err_rl("Failed to get mode from detid= %u",
1760 					detector_id);
1761 			goto fail;
1762 		}
1763 
1764 		if ((spectral->params[params.smode].ss_rpt_mode == 1) &&
1765 		    spectral->null_fftbin_adj) {
1766 			/*
1767 			 * No FFT bins are expected. Explicitly set FFT bin
1768 			 * length to 0.
1769 			 */
1770 			fft_bin_len = 0;
1771 		} else {
1772 			fft_bin_len = (fft_hdr_length - 16);
1773 
1774 			/*
1775 			 * Divide fft bin length by appropriate factor depending
1776 			 * on the value of fftbin_size_war.
1777 			 */
1778 			if (spectral->fftbin_size_war ==
1779 					SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
1780 				fft_bin_len >>= 2;
1781 			else if (spectral->fftbin_size_war ==
1782 				 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
1783 				/* Ideally we should be dividing fft bin length
1784 				 * by 2. Due to a HW bug, actual length is two
1785 				 * times the expected length.
1786 				 */
1787 				fft_bin_len >>= 2;
1788 			}
1789 			if ((spectral->params[params.smode].ss_rpt_mode == 2) &&
1790 			    spectral->inband_fftbin_size_adj) {
1791 				fft_bin_len >>= 1;
1792 			}
1793 		}
1794 
1795 		params.last_raw_timestamp =
1796 				spectral->last_fft_timestamp[params.smode];
1797 		params.reset_delay = 0;
1798 
1799 		if (report->reset_delay) {
1800 			enum spectral_scan_mode mode =
1801 						SPECTRAL_SCAN_MODE_NORMAL;
1802 
1803 			/* Adjust the offset for all the Spectral modes.
1804 			 * Target will be sending the non zero reset delay for
1805 			 * the first Spectral report after reset. This delay is
1806 			 * common for all the Spectral modes.
1807 			 */
1808 			for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++)
1809 				spectral->timestamp_war_offset[mode] +=
1810 					(report->reset_delay +
1811 					 spectral->last_fft_timestamp[mode]);
1812 			params.reset_delay = report->reset_delay;
1813 			spectral->target_reset_count++;
1814 		}
1815 		params.target_reset_count = spectral->target_reset_count;
1816 		params.timestamp_war_offset =
1817 				   spectral->timestamp_war_offset[params.smode];
1818 		tsf64 = p_sfft->timestamp;
1819 		params.raw_timestamp = tsf64;
1820 		spectral->last_fft_timestamp[params.smode] = p_sfft->timestamp;
1821 		tsf64 += spectral->timestamp_war_offset[params.smode];
1822 
1823 		/* Take care of state transitions for 160 MHz and 80p80 */
1824 		if (spectral->ch_width == CH_WIDTH_160MHZ) {
1825 			ret = target_if_160mhz_delivery_state_change(
1826 					spectral,
1827 					detector_id);
1828 			if (ret != QDF_STATUS_SUCCESS)
1829 				goto fail;
1830 		}
1831 
1832 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1833 			target_if_dump_fft_report_gen3(spectral, params.smode,
1834 						       p_fft_report, p_sfft);
1835 
1836 		params.rssi         = rssi;
1837 
1838 		vdev = target_if_spectral_get_vdev(spectral);
1839 		if (!vdev) {
1840 			spectral_info("First vdev is NULL");
1841 			reset_160mhz_delivery_state_machine
1842 						(spectral,
1843 						 SPECTRAL_SCAN_MODE_NORMAL);
1844 			return -EPERM;
1845 		}
1846 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
1847 		QDF_ASSERT(vdev_rxchainmask != 0);
1848 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1849 
1850 		chn_idx_lowest_enabled =
1851 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
1852 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
1853 			spectral_err("Invalid chain index, detector id = %u",
1854 				     detector_id);
1855 			goto fail;
1856 		}
1857 
1858 		params.max_mag  = p_sfft->fft_peak_mag;
1859 
1860 		params.bin_pwr_data = (uint8_t *)((uint8_t *)p_fft_report +
1861 						   SPECTRAL_FFT_BINS_POS);
1862 		params.freq = p_sops->get_current_channel(spectral);
1863 
1864 		if (params.smode == SPECTRAL_SCAN_MODE_AGILE)
1865 			params.agile_freq =
1866 				spectral->params[params.smode].ss_frequency;
1867 
1868 		/*
1869 		 * For modes upto VHT80, the noise floor is populated with
1870 		 * the one corresponding
1871 		 * to the highest enabled antenna chain
1872 		 */
1873 		/* TODO:  Fill proper values once FW provides them*/
1874 		params.noise_floor       =
1875 			report->noisefloor[chn_idx_lowest_enabled];
1876 		params.datalen           = (fft_hdr_length * 4);
1877 		params.pwr_count         = fft_bin_len;
1878 		params.tstamp            = (tsf64 & SPECTRAL_TSMASK);
1879 
1880 		target_if_spectral_verify_ts(spectral, report->data,
1881 					     params.tstamp);
1882 	} else if (is_secondaryseg_expected(spectral)) {
1883 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
1884 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
1885 		params.agc_total_gain_sec80 =
1886 			sscan_report_fields.sscan_agc_total_gain;
1887 		params.gainchange_sec80 = sscan_report_fields.sscan_gainchange;
1888 		params.pri80ind_sec80 = sscan_report_fields.sscan_pri80;
1889 
1890 		/* Process Spectral search FFT report */
1891 		if (target_if_verify_sig_and_tag_gen3(
1892 				spectral, data,
1893 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
1894 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
1895 					detector_id);
1896 			goto fail;
1897 		}
1898 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
1899 		fft_hdr_length = p_fft_report->fft_hdr_length * 4;
1900 		if (fft_hdr_length < 16) {
1901 			spectral_err("Wrong TLV length %u, detector id = %u",
1902 				     fft_hdr_length, detector_id);
1903 			goto fail;
1904 		}
1905 
1906 		report_len     = (fft_hdr_length + 8);
1907 
1908 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft);
1909 		/* It is expected to have same detector id for
1910 		 * summary and fft report
1911 		 */
1912 		if (detector_id != p_sfft->fft_detector_id) {
1913 			spectral_err_rl
1914 				("Different detid in ssummary(%u) and sfft(%u)",
1915 				 detector_id, p_sfft->fft_detector_id);
1916 			goto fail;
1917 		}
1918 
1919 		if (detector_id > SPECTRAL_DETECTOR_AGILE) {
1920 			spectral->diag_stats.spectral_invalid_detector_id++;
1921 			spectral_err("Invalid detector id %u, expected is 1",
1922 				     detector_id);
1923 			goto fail;
1924 		}
1925 
1926 		ret = target_if_get_spectral_mode(detector_id, &params.smode);
1927 		if (QDF_IS_STATUS_ERROR(ret)) {
1928 			spectral_err("Failed to get mode from detid= %u",
1929 				     detector_id);
1930 			goto fail;
1931 		}
1932 
1933 		if ((spectral->params[params.smode].ss_rpt_mode == 1) &&
1934 		    spectral->null_fftbin_adj) {
1935 			/*
1936 			 * No FFT bins are expected. Explicitly set FFT bin
1937 			 * length to 0.
1938 			 */
1939 			fft_bin_len = 0;
1940 		} else {
1941 			fft_bin_len = (fft_hdr_length - 16);
1942 
1943 			/*
1944 			 * Divide fft bin length by appropriate factor depending
1945 			 * on the value of fftbin_size_war.
1946 			 */
1947 			if (spectral->fftbin_size_war ==
1948 					SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
1949 				fft_bin_len >>= 2;
1950 			else if (spectral->fftbin_size_war ==
1951 				 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
1952 				/* Ideally we should be dividing fft bin length
1953 				 * by 2. Due to a HW bug, actual length is two
1954 				 * times the expected length.
1955 				 */
1956 				fft_bin_len >>= 2;
1957 			}
1958 
1959 			if ((spectral->params[params.smode].ss_rpt_mode == 2) &&
1960 			    spectral->inband_fftbin_size_adj) {
1961 				fft_bin_len >>= 1;
1962 			}
1963 		}
1964 
1965 		params.raw_timestamp_sec80 = p_sfft->timestamp;
1966 
1967 		/* Take care of state transitions for 160 MHz and 80p80 */
1968 		if (spectral->ch_width == CH_WIDTH_160MHZ) {
1969 			ret = target_if_160mhz_delivery_state_change(
1970 					spectral,
1971 					detector_id);
1972 			if (ret != QDF_STATUS_SUCCESS)
1973 				goto fail;
1974 		}
1975 
1976 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1977 			target_if_dump_fft_report_gen3(spectral, params.smode,
1978 						       p_fft_report, p_sfft);
1979 
1980 		params.vhtop_ch_freq_seg1 = 0;
1981 		params.vhtop_ch_freq_seg2 = 0;
1982 
1983 		params.rssi_sec80 = rssi;
1984 
1985 		vdev = target_if_spectral_get_vdev(spectral);
1986 		if (!vdev) {
1987 			spectral_info("First vdev is NULL");
1988 			reset_160mhz_delivery_state_machine
1989 						(spectral,
1990 						 SPECTRAL_SCAN_MODE_NORMAL);
1991 			return -EPERM;
1992 		}
1993 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
1994 		QDF_ASSERT(vdev_rxchainmask != 0);
1995 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1996 
1997 		chn_idx_lowest_enabled =
1998 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
1999 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
2000 			spectral_err("Invalid chain index");
2001 			goto fail;
2002 		}
2003 
2004 		/* Need to change this as per FW team's inputs */
2005 		params.noise_floor_sec80    =
2006 			report->noisefloor[chn_idx_lowest_enabled];
2007 
2008 		params.max_mag_sec80        = p_sfft->fft_peak_mag;
2009 		/* params.max_index_sec80      = p_sfft->peak_inx; */
2010 		/* XXX Does this definition of datalen *still hold? */
2011 		params.datalen_sec80        = fft_hdr_length * 4;
2012 		params.pwr_count_sec80      = fft_bin_len;
2013 		params.bin_pwr_data_sec80   =
2014 			(uint8_t *)((uint8_t *)p_fft_report +
2015 			 SPECTRAL_FFT_BINS_POS);
2016 	} else {
2017 		spectral_err("Spectral state machine in undefined state");
2018 		goto fail;
2019 	}
2020 
2021 	target_if_spectral_check_buffer_poisoning(spectral, report,
2022 						  fft_bin_len, params.smode);
2023 	qdf_mem_copy(&params.classifier_params,
2024 		     &spectral->classifier_params,
2025 		     sizeof(struct spectral_classifier_params));
2026 
2027 	target_if_spectral_log_SAMP_param(&params);
2028 	target_if_spectral_create_samp_msg(spectral, &params);
2029 
2030 	return 0;
2031  fail:
2032 	spectral_err_rl("Error while processing Spectral report");
2033 	reset_160mhz_delivery_state_machine(spectral,
2034 					    SPECTRAL_SCAN_MODE_NORMAL);
2035 	return -EPERM;
2036 }
2037 
2038 int target_if_spectral_process_report_gen3(
2039 	struct wlan_objmgr_pdev *pdev,
2040 	void *buf)
2041 {
2042 	int ret = 0;
2043 	struct direct_buf_rx_data *payload = buf;
2044 	struct target_if_spectral *spectral;
2045 	struct spectral_report report;
2046 
2047 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2048 	if (!spectral) {
2049 		spectral_err("Spectral target object is null");
2050 		return -EINVAL;
2051 	}
2052 
2053 	report.data = payload->vaddr;
2054 	if (payload->meta_data_valid) {
2055 		qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor,
2056 			     qdf_min(sizeof(report.noisefloor),
2057 				     sizeof(payload->meta_data.noisefloor)));
2058 		report.reset_delay = payload->meta_data.reset_delay;
2059 	}
2060 
2061 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) {
2062 		spectral_debug("Printing the spectral phyerr buffer for debug");
2063 		spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK",
2064 			       payload->dbr_len,
2065 			       payload->dbr_len,
2066 			       payload->vaddr);
2067 		target_if_spectral_hexdump((unsigned char *)payload->vaddr,
2068 					   1024);
2069 	}
2070 
2071 	ret = target_if_consume_spectral_report_gen3(spectral, &report);
2072 
2073 	if (spectral_debug_level & DEBUG_SPECTRAL4)
2074 		spectral_debug_level = DEBUG_SPECTRAL;
2075 
2076 	return ret;
2077 }
2078 #else
2079 int target_if_spectral_process_report_gen3(
2080 	struct wlan_objmgr_pdev *pdev,
2081 	void *buf)
2082 {
2083 	spectral_err("Direct dma support is not enabled");
2084 	return -EINVAL;
2085 }
2086 #endif
2087 qdf_export_symbol(target_if_spectral_process_report_gen3);
2088 /* END of spectral GEN III HW specific functions */
2089 
2090 #endif  /* WLAN_CONV_SPECTRAL_ENABLE */
2091