xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral_phyerr.c (revision f28396d060cff5c6519f883cb28ae0116ce479f1)
1 /*
2  * Copyright (c) 2011,2017-2020 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 #ifdef DIRECT_BUF_RX_ENABLE
1198 /**
1199  * target_if_spectral_get_bin_count_after_len_adj() - Get number of FFT bins in
1200  * Spectral FFT report
1201  * @fft_bin_len: FFT bin length reported by target
1202  * @rpt_mode: Spectral report mode
1203  * @swar: Spectral FFT bin length adjustments SWAR parameters
1204  *
1205  * Get actual number of FFT bins in the FFT report after adjusting the length
1206  * by applying the SWARs for getting correct length.
1207  *
1208  * Return: FFT bin count
1209  */
1210 static size_t
1211 target_if_spectral_get_bin_count_after_len_adj(
1212 				size_t fft_bin_len, uint8_t rpt_mode,
1213 				struct spectral_fft_bin_len_adj_swar *swar)
1214 {
1215 	size_t fft_bin_count = fft_bin_len;
1216 
1217 	if (rpt_mode == 1 && swar->null_fftbin_adj) {
1218 		/*
1219 		 * No FFT bins are expected. Explicitly set FFT bin
1220 		 * count to 0.
1221 		 */
1222 		fft_bin_count = 0;
1223 	} else {
1224 		/*
1225 		 * Divide fft bin length by appropriate factor depending
1226 		 * on the value of fftbin_size_war.
1227 		 */
1228 		switch (swar->fftbin_size_war) {
1229 		case SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE:
1230 			fft_bin_count >>= 2;
1231 			break;
1232 		case SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE:
1233 			fft_bin_count >>= 1;
1234 			/* Ideally we should be dividing fft bin length
1235 			 * by 2. Due to a HW bug, actual length is two
1236 			 * times the expected length.
1237 			 */
1238 			if (swar->packmode_fftbin_size_adj)
1239 				fft_bin_count >>= 1;
1240 			break;
1241 		case SPECTRAL_FFTBIN_SIZE_NO_WAR:
1242 			/* No length adjustment */
1243 			break;
1244 		default:
1245 			qdf_assert_always(0);
1246 		}
1247 
1248 		if (rpt_mode == 2 && swar->inband_fftbin_size_adj)
1249 			fft_bin_count >>= 1;
1250 	}
1251 
1252 	return fft_bin_count;
1253 }
1254 
1255 /**
1256  * target_if_process_sfft_report_gen3() - Process Search FFT Report for gen3
1257  * @p_fft_report: Pointer to fft report
1258  * @p_sfft: Pointer to search fft report
1259  *
1260  * Process Search FFT Report for gen3
1261  *
1262  * Return: Success/Failure
1263  */
1264 static int
1265 target_if_process_sfft_report_gen3(
1266 	struct spectral_phyerr_fft_report_gen3 *p_fft_report,
1267 	struct spectral_search_fft_info_gen3 *p_sfft)
1268 {
1269 	/*
1270 	 * For simplicity, everything is defined as uint32_t (except one).
1271 	 * Proper code will later use the right sizes.
1272 	 */
1273 	/*
1274 	 * For easy comparision between MDK team and OS team, the MDK script
1275 	 * variable names have been used
1276 	 */
1277 	int32_t peak_sidx;
1278 	int32_t peak_mag;
1279 
1280 	/* Populate the Search FFT Info */
1281 	if (p_sfft) {
1282 		p_sfft->timestamp = p_fft_report->fft_timestamp;
1283 
1284 		p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a,
1285 						       2, 0);
1286 		p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2);
1287 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
1288 						       12, 5);
1289 
1290 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17);
1291 		p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
1292 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28);
1293 
1294 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
1295 						       9, 0);
1296 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
1297 							 8, 9);
1298 
1299 		p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
1300 							   8, 0);
1301 		peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8);
1302 		p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
1303 		p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
1304 						     7, 18);
1305 		p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
1306 						     7, 25);
1307 	}
1308 
1309 	return 0;
1310 }
1311 
1312 /**
1313  * target_if_dump_fft_report_gen3() - Dump FFT Report for gen3
1314  * @spectral: Pointer to Spectral object
1315  * @smode: Spectral scan mode
1316  * @p_fft_report: Pointer to fft report
1317  * @p_sfft: Pointer to search fft report
1318  *
1319  * Dump FFT Report for gen3
1320  *
1321  * Return: void
1322  */
1323 static void
1324 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral,
1325 			enum spectral_scan_mode smode,
1326 			struct spectral_phyerr_fft_report_gen3 *p_fft_report,
1327 			struct spectral_search_fft_info_gen3 *p_sfft)
1328 {
1329 	size_t fft_hdr_length = (p_fft_report->fft_hdr_length * 4);
1330 	size_t report_len = (fft_hdr_length + 8);
1331 	size_t fft_bin_len;
1332 	size_t fft_bin_count;
1333 	size_t fft_bin_len_inband_tfer = 0;
1334 	uint8_t *fft_bin_buf = NULL;
1335 
1336 	fft_bin_len = fft_hdr_length - spectral->rparams.fft_report_hdr_len;
1337 	fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
1338 			fft_bin_len,
1339 			spectral->params[smode].ss_rpt_mode,
1340 			&spectral->len_adj_swar);
1341 
1342 	if ((spectral->params[smode].ss_rpt_mode == 2) &&
1343 	    spectral->len_adj_swar.inband_fftbin_size_adj)
1344 		fft_bin_len_inband_tfer = fft_bin_len >> 1;
1345 
1346 	spectral_debug("Spectral FFT Report");
1347 	spectral_debug("fft_timestamp = 0x%x", p_fft_report->fft_timestamp);
1348 	spectral_debug("fft_hdr_length = %u(32 bit words)",
1349 		       p_fft_report->fft_hdr_length);
1350 	spectral_debug("fft_hdr_tag = 0x%x", p_fft_report->fft_hdr_tag);
1351 	spectral_debug("fft_hdr_sig = 0x%x", p_fft_report->fft_hdr_sig);
1352 
1353 	spectral_debug("Length field in search fft report is %zu(0x%zx) bytes",
1354 		       fft_hdr_length, fft_hdr_length);
1355 	spectral_debug("Total length of search fft report is %zu(0x%zx) bytes",
1356 		       report_len, report_len);
1357 	spectral_debug("Target reported fftbins in report is %zu(0x%zx)",
1358 		       fft_bin_len, fft_bin_len);
1359 
1360 	if ((spectral->params[smode].ss_rpt_mode == 1) &&
1361 	    spectral->len_adj_swar.null_fftbin_adj)
1362 		spectral_debug("WAR: Considering number of FFT bins as 0");
1363 	else if ((spectral->params[smode].ss_rpt_mode == 2) &&
1364 		 spectral->len_adj_swar.inband_fftbin_size_adj) {
1365 		spectral_debug("FW fftbins actually transferred (in-band report mode) %zu(0x%zx)",
1366 			       fft_bin_len_inband_tfer,
1367 			       fft_bin_len_inband_tfer);
1368 	}
1369 
1370 	spectral_debug("Actual number of fftbins in report is %zu(0x%zx)",
1371 		       fft_bin_count, fft_bin_count);
1372 
1373 	spectral_debug("fft_detector_id = %u", p_sfft->fft_detector_id);
1374 	spectral_debug("fft_num = %u", p_sfft->fft_num);
1375 	spectral_debug("fft_radar_check = %u", p_sfft->fft_radar_check);
1376 	spectral_debug("fft_peak_sidx = %d",  p_sfft->fft_peak_sidx);
1377 	spectral_debug("fft_chn_idx = %u", p_sfft->fft_chn_idx);
1378 	spectral_debug("fft_base_pwr_db = %u", p_sfft->fft_base_pwr_db);
1379 	spectral_debug("fft_total_gain_db = %u", p_sfft->fft_total_gain_db);
1380 	spectral_debug("fft_num_str_bins_ib = %u", p_sfft->fft_num_str_bins_ib);
1381 	spectral_debug("fft_peak_mag = %d", p_sfft->fft_peak_mag);
1382 	spectral_debug("fft_avgpwr_db = %u", p_sfft->fft_avgpwr_db);
1383 	spectral_debug("fft_relpwr_db = %u", p_sfft->fft_relpwr_db);
1384 
1385 	if (fft_bin_count > 0) {
1386 		int idx;
1387 
1388 		spectral_debug("FFT bins:");
1389 		if (spectral->len_adj_swar.fftbin_size_war ==
1390 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) {
1391 			uint32_t *binptr_32 = (uint32_t *)&p_fft_report->buf;
1392 
1393 			fft_bin_buf = (uint8_t *)qdf_mem_malloc(MAX_NUM_BINS);
1394 			for (idx = 0; idx < fft_bin_count; idx++)
1395 				fft_bin_buf[idx] = *(binptr_32++);
1396 		} else if (spectral->len_adj_swar.fftbin_size_war ==
1397 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
1398 			uint16_t *binptr_16 = (uint16_t *)&p_fft_report->buf;
1399 
1400 			fft_bin_buf = (uint8_t *)qdf_mem_malloc(MAX_NUM_BINS);
1401 			for (idx = 0; idx < fft_bin_count; idx++)
1402 				fft_bin_buf[idx] = *(binptr_16++);
1403 		} else {
1404 			fft_bin_buf = (uint8_t *)&p_fft_report->buf;
1405 		}
1406 		target_if_spectral_hexdump(fft_bin_buf, fft_bin_count);
1407 		if ((spectral->len_adj_swar.fftbin_size_war !=
1408 				SPECTRAL_FFTBIN_SIZE_NO_WAR) && fft_bin_buf)
1409 			qdf_mem_free(fft_bin_buf);
1410 	}
1411 }
1412 #endif
1413 
1414 QDF_STATUS
1415 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
1416 				       uint8_t detector_id) {
1417 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1418 
1419 	if (spectral->ch_width != CH_WIDTH_160MHZ)
1420 		return QDF_STATUS_E_FAILURE;
1421 
1422 	/* agile reports should not be coupled with 160 MHz state machine
1423 	 * for normal Spectral
1424 	 */
1425 	if (detector_id == SPECTRAL_DETECTOR_AGILE)
1426 		return QDF_STATUS_SUCCESS;
1427 
1428 	switch (spectral->state_160mhz_delivery) {
1429 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
1430 		if (detector_id == SPECTRAL_DETECTOR_PRIMARY)
1431 			spectral->state_160mhz_delivery =
1432 				SPECTRAL_REPORT_RX_PRIMARY80;
1433 		else {
1434 			status = QDF_STATUS_E_FAILURE;
1435 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
1436 		}
1437 		break;
1438 
1439 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
1440 		if (detector_id == SPECTRAL_DETECTOR_SECONDARY)
1441 			spectral->state_160mhz_delivery =
1442 				SPECTRAL_REPORT_RX_SECONDARY80;
1443 		else {
1444 			spectral->state_160mhz_delivery =
1445 				SPECTRAL_REPORT_WAIT_PRIMARY80;
1446 			status = QDF_STATUS_E_FAILURE;
1447 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
1448 		}
1449 		break;
1450 
1451 	case SPECTRAL_REPORT_RX_SECONDARY80:
1452 		/* We don't care about detector id in this state. */
1453 		reset_160mhz_delivery_state_machine(spectral,
1454 						    SPECTRAL_SCAN_MODE_NORMAL);
1455 		break;
1456 
1457 	case SPECTRAL_REPORT_RX_PRIMARY80:
1458 		/* We don't care about detector id in this state */
1459 		spectral->state_160mhz_delivery =
1460 				SPECTRAL_REPORT_WAIT_SECONDARY80;
1461 		break;
1462 
1463 	default:
1464 		break;
1465 	}
1466 
1467 	return status;
1468 }
1469 
1470 #ifdef DIRECT_BUF_RX_ENABLE
1471 /**
1472  * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector
1473  * ID from Spectral summary report
1474  * @data: Pointer to Spectral summary report
1475  *
1476  * Return: Detector ID
1477  */
1478 static uint8_t
1479 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data) {
1480 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
1481 	uint8_t detector_id;
1482 
1483 	qdf_assert_always(data);
1484 
1485 	psscan_summary_report =
1486 		(struct spectral_sscan_summary_report_gen3 *)data;
1487 
1488 	detector_id = get_bitfield(
1489 			psscan_summary_report->hdr_a,
1490 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
1491 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
1492 
1493 	return detector_id;
1494 }
1495 
1496 /**
1497  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
1498  * report
1499  * @data: Pointer to Spectral summary report
1500  * @fields: Pointer to structure to be populated with extracted fields
1501  * @rparams: Pointer to structure with Spectral report params
1502  *
1503  * Consume Spectral summary report for gen3
1504  *
1505  * Return: void
1506  */
1507 static void
1508 target_if_consume_sscan_summary_report_gen3(
1509 				uint8_t *data,
1510 				struct sscan_report_fields_gen3 *fields,
1511 				struct spectral_report_params *rparams) {
1512 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
1513 
1514 	qdf_assert_always(data);
1515 	qdf_assert_always(fields);
1516 	qdf_assert_always(rparams);
1517 
1518 	psscan_summary_report =
1519 		(struct spectral_sscan_summary_report_gen3 *)data;
1520 
1521 	fields->sscan_agc_total_gain = get_bitfield(
1522 			psscan_summary_report->hdr_a,
1523 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
1524 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
1525 	fields->inband_pwr_db = get_bitfield(
1526 			psscan_summary_report->hdr_a,
1527 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
1528 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
1529 	fields->sscan_pri80 = get_bitfield(
1530 			psscan_summary_report->hdr_a,
1531 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
1532 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
1533 
1534 	switch (rparams->version) {
1535 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
1536 		fields->sscan_gainchange = get_bitfield(
1537 			psscan_summary_report->hdr_b,
1538 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
1539 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
1540 		break;
1541 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
1542 		fields->sscan_gainchange = get_bitfield(
1543 			psscan_summary_report->hdr_c,
1544 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
1545 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
1546 		break;
1547 	default:
1548 		qdf_assert_always(0);
1549 	}
1550 }
1551 
1552 /**
1553  * target_if_verify_sig_and_tag_gen3() - Verify tag and signature
1554  *                                       of spectral report
1555  * @spectral: Pointer to spectral object
1556  * @data: Pointer to spectral summary report
1557  * @exp_tag: iexpected tag value
1558  *
1559  * Process fft report for gen3
1560  *
1561  * Return: SUCCESS/FAILURE
1562  */
1563 static int
1564 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral,
1565 				  uint8_t *data, uint8_t exp_tag)
1566 {
1567 	uint8_t tag = 0;
1568 	uint8_t signature = 0;
1569 
1570 	/* Peek into the data to figure out whether
1571 	 *      1) Signature matches the expected value
1572 	 *      2) What is inside the package (TAG ID is used for finding this)
1573 	 */
1574 	tag = *(data + PHYERR_HDR_TAG_POS);
1575 	signature = *(data + PHYERR_HDR_SIG_POS);
1576 
1577 	if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
1578 		spectral->diag_stats.spectral_mismatch++;
1579 		return -EINVAL;
1580 	}
1581 
1582 	if (tag != exp_tag) {
1583 		spectral->diag_stats.spectral_mismatch++;
1584 		return -EINVAL;
1585 	}
1586 
1587 	return 0;
1588 }
1589 
1590 static uint8_t
1591 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)
1592 {
1593 	uint8_t idx;
1594 
1595 	for (idx = 0; idx < DBR_MAX_CHAINS; idx++) {
1596 		if (chainmask & 0x1)
1597 			break;
1598 		chainmask >>= 1;
1599 	}
1600 	return idx;
1601 }
1602 
1603 static QDF_STATUS
1604 target_if_get_spectral_mode(enum spectral_detector_id detector_id,
1605 			    enum spectral_scan_mode *smode) {
1606 	switch (detector_id) {
1607 	case SPECTRAL_DETECTOR_PRIMARY:
1608 	case SPECTRAL_DETECTOR_SECONDARY:
1609 		*smode = SPECTRAL_SCAN_MODE_NORMAL;
1610 		break;
1611 
1612 	case SPECTRAL_DETECTOR_AGILE:
1613 		*smode = SPECTRAL_SCAN_MODE_AGILE;
1614 		break;
1615 
1616 	default:
1617 		spectral_err("Invalid Spectral detector id");
1618 		return QDF_STATUS_E_FAILURE;
1619 	}
1620 
1621 	return QDF_STATUS_SUCCESS;
1622 }
1623 
1624 #ifdef DIRECT_BUF_RX_DEBUG
1625 static void target_if_spectral_check_buffer_poisoning(
1626 	struct target_if_spectral *spectral,
1627 	struct spectral_report *report,
1628 	int num_fft_bins, enum spectral_scan_mode smode)
1629 {
1630 	uint32_t *data;
1631 	size_t len;
1632 	size_t words_to_check =
1633 		sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
1634 	bool poisoned_words_found = false;
1635 
1636 	if (!spectral) {
1637 		spectral_err_rl("Spectral LMAC object is null");
1638 		return;
1639 	}
1640 
1641 	if (!spectral->dbr_buff_debug)
1642 		return;
1643 
1644 	if (!report) {
1645 		spectral_err_rl("Spectral report is null");
1646 		return;
1647 	}
1648 
1649 	/* Add search FFT report */
1650 	if (spectral->params[smode].ss_rpt_mode > 0)
1651 		words_to_check +=
1652 			sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
1653 
1654 	/* Now add the number of FFT bins */
1655 	if (spectral->params[smode].ss_rpt_mode > 1) {
1656 		/* Caller should take care to pass correct number of FFT bins */
1657 		if (spectral->len_adj_swar.fftbin_size_war ==
1658 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
1659 			words_to_check += num_fft_bins;
1660 		else if (spectral->len_adj_swar.fftbin_size_war ==
1661 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE)
1662 			words_to_check += (num_fft_bins >> 1);
1663 	}
1664 
1665 	data = (uint32_t *)report->data;
1666 	for (len = 0; len < words_to_check; ++len) {
1667 		if (*data == MEM_POISON_SIGNATURE) {
1668 			spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK",
1669 				     MEM_POISON_SIGNATURE,
1670 				     (len << 2), report->data);
1671 			poisoned_words_found = true;
1672 			break;
1673 		}
1674 		++data;
1675 	}
1676 
1677 	/* Crash the FW even if one word is poisoned */
1678 	if (poisoned_words_found) {
1679 		spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows",
1680 			     MEM_POISON_SIGNATURE);
1681 		target_if_spectral_hexdump((unsigned char *)report->data,
1682 					   words_to_check << 2);
1683 		spectral_err("Asserting the FW");
1684 		target_if_spectral_fw_hang(spectral);
1685 	}
1686 }
1687 
1688 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
1689 					 uint8_t *buf, uint32_t current_ts)
1690 {
1691 	if (!spectral) {
1692 		spectral_err_rl("Spectral LMAC object is null");
1693 		return;
1694 	}
1695 
1696 	if (!spectral->dbr_buff_debug)
1697 		return;
1698 
1699 	if (spectral->prev_tstamp) {
1700 		if (current_ts == spectral->prev_tstamp) {
1701 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
1702 				     current_ts, buf);
1703 			target_if_spectral_fw_hang(spectral);
1704 		}
1705 	}
1706 	spectral->prev_tstamp = current_ts;
1707 }
1708 #else
1709 static void target_if_spectral_check_buffer_poisoning(
1710 	struct target_if_spectral *spectral,
1711 	struct spectral_report *report,
1712 	int num_fft_bins, enum spectral_scan_mode smode)
1713 {
1714 }
1715 
1716 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
1717 					 uint8_t *buf, uint32_t current_ts)
1718 {
1719 }
1720 #endif
1721 
1722 /**
1723  * target_if_spectral_get_adjusted_timestamp() - Adjust Spectral time
1724  * stamp to account for reset in time stamp due to target reset
1725  * @twar: Spectral time stamp WAR related information
1726  * @raw_timestamp: Spectral time stamp reported by target
1727  * @reset_delay: Reset delay at target
1728  * @smode: Spectral scan mode
1729  *
1730  * Correct time stamp to account for reset in time stamp due to target reset
1731  *
1732  * Return: Adjusted time stamp
1733  */
1734 static uint32_t
1735 target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war *twar,
1736 					  uint32_t raw_timestamp,
1737 					  uint32_t reset_delay,
1738 					  enum spectral_scan_mode smode) {
1739 	qdf_assert_always(smode < SPECTRAL_SCAN_MODE_MAX);
1740 
1741 	if (reset_delay) {
1742 		enum spectral_scan_mode m =
1743 					SPECTRAL_SCAN_MODE_NORMAL;
1744 
1745 		/* Adjust the offset for all the Spectral modes.
1746 		 * Target will be sending the non zero reset delay for
1747 		 * the first Spectral report after reset. This delay is
1748 		 * common for all the Spectral modes.
1749 		 */
1750 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
1751 			twar->timestamp_war_offset[m] += (reset_delay +
1752 					twar->last_fft_timestamp[m]);
1753 		twar->target_reset_count++;
1754 	}
1755 	twar->last_fft_timestamp[smode] = raw_timestamp;
1756 
1757 	return raw_timestamp + twar->timestamp_war_offset[smode];
1758 }
1759 
1760 int
1761 target_if_consume_spectral_report_gen3(
1762 	 struct target_if_spectral *spectral,
1763 	 struct spectral_report *report)
1764 {
1765 	/*
1766 	 * XXX : The classifier do not use all the members of the SAMP
1767 	 *       message data format.
1768 	 *       The classifier only depends upon the following parameters
1769 	 *
1770 	 *          1. Frequency (freq, msg->freq)
1771 	 *          2. Spectral RSSI (spectral_rssi,
1772 	 *          msg->samp_data.spectral_rssi)
1773 	 *          3. Bin Power Count (bin_pwr_count,
1774 	 *          msg->samp_data.bin_pwr_count)
1775 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
1776 	 *          5. Spectral Timestamp (spectral_tstamp,
1777 	 *          msg->samp_data.spectral_tstamp)
1778 	 *          6. MAC Address (macaddr, msg->macaddr)
1779 	 *
1780 	 *       This function prepares the params structure and populates it
1781 	 *       with
1782 	 *       relevant values, this is in turn passed to
1783 	 *       spectral_create_samp_msg()
1784 	 *       to prepare fully formatted Spectral SAMP message
1785 	 *
1786 	 *       XXX : Need to verify
1787 	 *          1. Order of FFT bin values
1788 	 *
1789 	 */
1790 	struct target_if_samp_msg_params params = {0};
1791 	struct spectral_search_fft_info_gen3 search_fft_info;
1792 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
1793 	int8_t chn_idx_lowest_enabled  = 0;
1794 	int fft_hdr_length = 0;
1795 	int report_len = 0;
1796 	size_t fft_bin_count;
1797 	struct target_if_spectral_ops *p_sops =
1798 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1799 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
1800 	int8_t rssi;
1801 	uint8_t *data = report->data;
1802 	struct wlan_objmgr_vdev *vdev;
1803 	uint8_t vdev_rxchainmask;
1804 	struct sscan_report_fields_gen3 sscan_report_fields = {0};
1805 	enum spectral_detector_id detector_id;
1806 	QDF_STATUS ret;
1807 
1808 	params.smode = SPECTRAL_SCAN_MODE_NORMAL;
1809 
1810 	/* Process Spectral scan summary report */
1811 	if (target_if_verify_sig_and_tag_gen3(
1812 			spectral, data,
1813 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
1814 		spectral_err_rl("Wrong tag/sig in sscan summary");
1815 		goto fail;
1816 	}
1817 
1818 	detector_id = target_if_get_detector_id_sscan_summary_report_gen3(data);
1819 	if (detector_id > SPECTRAL_DETECTOR_AGILE) {
1820 		spectral->diag_stats.spectral_invalid_detector_id++;
1821 		spectral_err("Invalid detector id %u, expected is 0/1/2",
1822 			     detector_id);
1823 		goto fail;
1824 	}
1825 	target_if_consume_sscan_summary_report_gen3(data, &sscan_report_fields,
1826 						    &spectral->rparams);
1827 	/* Advance buf pointer to the search fft report */
1828 	data += sizeof(struct spectral_sscan_summary_report_gen3);
1829 	data += spectral->rparams.ssumaary_padding_bytes;
1830 
1831 	if ((detector_id == SPECTRAL_DETECTOR_AGILE) ||
1832 	    is_primaryseg_expected(spectral)) {
1833 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
1834 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
1835 		params.agc_total_gain =
1836 			sscan_report_fields.sscan_agc_total_gain;
1837 		params.gainchange = sscan_report_fields.sscan_gainchange;
1838 		params.pri80ind = sscan_report_fields.sscan_pri80;
1839 
1840 		/* Process Spectral search FFT report */
1841 		if (target_if_verify_sig_and_tag_gen3(
1842 				spectral, data,
1843 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
1844 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
1845 					detector_id);
1846 			goto fail;
1847 		}
1848 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
1849 		fft_hdr_length = p_fft_report->fft_hdr_length * 4;
1850 		if (fft_hdr_length < 16) {
1851 			spectral_err("Wrong TLV length %u, detector id = %d",
1852 				     fft_hdr_length, detector_id);
1853 			goto fail;
1854 		}
1855 
1856 		report_len = (fft_hdr_length + 8);
1857 
1858 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft);
1859 		/* It is expected to have same detector id for
1860 		 * summary and fft report
1861 		 */
1862 		if (detector_id != p_sfft->fft_detector_id) {
1863 			spectral_err_rl
1864 				("Different detid in ssummary(%u) and sfft(%u)",
1865 				 detector_id, p_sfft->fft_detector_id);
1866 			goto fail;
1867 		}
1868 
1869 		if (detector_id > SPECTRAL_DETECTOR_AGILE) {
1870 			spectral->diag_stats.spectral_invalid_detector_id++;
1871 			spectral_err("Invalid detector id %u, expected is 0/2",
1872 				     detector_id);
1873 			goto fail;
1874 		}
1875 
1876 		ret = target_if_get_spectral_mode(detector_id, &params.smode);
1877 		if (QDF_IS_STATUS_ERROR(ret)) {
1878 			spectral_err_rl("Failed to get mode from detid= %u",
1879 					detector_id);
1880 			goto fail;
1881 		}
1882 
1883 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
1884 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
1885 			spectral->params[params.smode].ss_rpt_mode,
1886 			&spectral->len_adj_swar);
1887 
1888 		params.last_raw_timestamp = spectral->timestamp_war.
1889 				last_fft_timestamp[params.smode];
1890 		params.reset_delay = report->reset_delay;
1891 		params.raw_timestamp = p_sfft->timestamp;
1892 		params.tstamp = target_if_spectral_get_adjusted_timestamp(
1893 					&spectral->timestamp_war,
1894 					p_sfft->timestamp, report->reset_delay,
1895 					params.smode);
1896 		params.timestamp_war_offset = spectral->timestamp_war.
1897 				timestamp_war_offset[params.smode];
1898 		params.target_reset_count = spectral->timestamp_war.
1899 				target_reset_count;
1900 
1901 		/* Take care of state transitions for 160 MHz and 80p80 */
1902 		if (spectral->ch_width == CH_WIDTH_160MHZ) {
1903 			ret = target_if_160mhz_delivery_state_change(
1904 					spectral,
1905 					detector_id);
1906 			if (ret != QDF_STATUS_SUCCESS)
1907 				goto fail;
1908 		}
1909 
1910 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1911 			target_if_dump_fft_report_gen3(spectral, params.smode,
1912 						       p_fft_report, p_sfft);
1913 
1914 		params.rssi         = rssi;
1915 
1916 		vdev = target_if_spectral_get_vdev(spectral);
1917 		if (!vdev) {
1918 			spectral_info("First vdev is NULL");
1919 			reset_160mhz_delivery_state_machine
1920 						(spectral,
1921 						 SPECTRAL_SCAN_MODE_NORMAL);
1922 			return -EPERM;
1923 		}
1924 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
1925 		QDF_ASSERT(vdev_rxchainmask != 0);
1926 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1927 
1928 		chn_idx_lowest_enabled =
1929 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
1930 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
1931 			spectral_err("Invalid chain index, detector id = %u",
1932 				     detector_id);
1933 			goto fail;
1934 		}
1935 
1936 		params.max_mag  = p_sfft->fft_peak_mag;
1937 
1938 		params.bin_pwr_data = (uint8_t *)((uint8_t *)p_fft_report +
1939 						   SPECTRAL_FFT_BINS_POS);
1940 		params.freq = p_sops->get_current_channel(spectral);
1941 
1942 		if (params.smode == SPECTRAL_SCAN_MODE_AGILE)
1943 			params.agile_freq =
1944 				spectral->params[params.smode].ss_frequency;
1945 
1946 		/*
1947 		 * For modes upto VHT80, the noise floor is populated with
1948 		 * the one corresponding
1949 		 * to the highest enabled antenna chain
1950 		 */
1951 		/* TODO:  Fill proper values once FW provides them*/
1952 		params.noise_floor       =
1953 			report->noisefloor[chn_idx_lowest_enabled];
1954 		params.datalen           = (fft_hdr_length * 4);
1955 		params.pwr_count         = fft_bin_count;
1956 
1957 		target_if_spectral_verify_ts(spectral, report->data,
1958 					     params.tstamp);
1959 	} else if (is_secondaryseg_expected(spectral)) {
1960 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
1961 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
1962 		params.agc_total_gain_sec80 =
1963 			sscan_report_fields.sscan_agc_total_gain;
1964 		params.gainchange_sec80 = sscan_report_fields.sscan_gainchange;
1965 		params.pri80ind_sec80 = sscan_report_fields.sscan_pri80;
1966 
1967 		/* Process Spectral search FFT report */
1968 		if (target_if_verify_sig_and_tag_gen3(
1969 				spectral, data,
1970 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
1971 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
1972 					detector_id);
1973 			goto fail;
1974 		}
1975 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
1976 		fft_hdr_length = p_fft_report->fft_hdr_length * 4;
1977 		if (fft_hdr_length < 16) {
1978 			spectral_err("Wrong TLV length %u, detector id = %u",
1979 				     fft_hdr_length, detector_id);
1980 			goto fail;
1981 		}
1982 
1983 		report_len     = (fft_hdr_length + 8);
1984 
1985 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft);
1986 		/* It is expected to have same detector id for
1987 		 * summary and fft report
1988 		 */
1989 		if (detector_id != p_sfft->fft_detector_id) {
1990 			spectral_err_rl
1991 				("Different detid in ssummary(%u) and sfft(%u)",
1992 				 detector_id, p_sfft->fft_detector_id);
1993 			goto fail;
1994 		}
1995 
1996 		if (detector_id > SPECTRAL_DETECTOR_AGILE) {
1997 			spectral->diag_stats.spectral_invalid_detector_id++;
1998 			spectral_err("Invalid detector id %u, expected is 1",
1999 				     detector_id);
2000 			goto fail;
2001 		}
2002 
2003 		ret = target_if_get_spectral_mode(detector_id, &params.smode);
2004 		if (QDF_IS_STATUS_ERROR(ret)) {
2005 			spectral_err("Failed to get mode from detid= %u",
2006 				     detector_id);
2007 			goto fail;
2008 		}
2009 
2010 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
2011 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
2012 			spectral->params[params.smode].ss_rpt_mode,
2013 			&spectral->len_adj_swar);
2014 		params.raw_timestamp_sec80 = p_sfft->timestamp;
2015 
2016 		/* Take care of state transitions for 160 MHz and 80p80 */
2017 		if (spectral->ch_width == CH_WIDTH_160MHZ) {
2018 			ret = target_if_160mhz_delivery_state_change(
2019 					spectral,
2020 					detector_id);
2021 			if (ret != QDF_STATUS_SUCCESS)
2022 				goto fail;
2023 		}
2024 
2025 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
2026 			target_if_dump_fft_report_gen3(spectral, params.smode,
2027 						       p_fft_report, p_sfft);
2028 
2029 		params.vhtop_ch_freq_seg1 = 0;
2030 		params.vhtop_ch_freq_seg2 = 0;
2031 
2032 		params.rssi_sec80 = rssi;
2033 
2034 		vdev = target_if_spectral_get_vdev(spectral);
2035 		if (!vdev) {
2036 			spectral_info("First vdev is NULL");
2037 			reset_160mhz_delivery_state_machine
2038 						(spectral,
2039 						 SPECTRAL_SCAN_MODE_NORMAL);
2040 			return -EPERM;
2041 		}
2042 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
2043 		QDF_ASSERT(vdev_rxchainmask != 0);
2044 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2045 
2046 		chn_idx_lowest_enabled =
2047 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
2048 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
2049 			spectral_err("Invalid chain index");
2050 			goto fail;
2051 		}
2052 
2053 		/* Need to change this as per FW team's inputs */
2054 		params.noise_floor_sec80    =
2055 			report->noisefloor[chn_idx_lowest_enabled];
2056 
2057 		params.max_mag_sec80        = p_sfft->fft_peak_mag;
2058 		/* params.max_index_sec80      = p_sfft->peak_inx; */
2059 		/* XXX Does this definition of datalen *still hold? */
2060 		params.datalen_sec80        = fft_hdr_length * 4;
2061 		params.pwr_count_sec80      = fft_bin_count;
2062 		params.bin_pwr_data_sec80   =
2063 			(uint8_t *)((uint8_t *)p_fft_report +
2064 			 SPECTRAL_FFT_BINS_POS);
2065 	} else {
2066 		spectral_err("Spectral state machine in undefined state");
2067 		goto fail;
2068 	}
2069 
2070 	target_if_spectral_check_buffer_poisoning(spectral, report,
2071 						  fft_bin_count, params.smode);
2072 	qdf_mem_copy(&params.classifier_params,
2073 		     &spectral->classifier_params,
2074 		     sizeof(struct spectral_classifier_params));
2075 
2076 	target_if_spectral_log_SAMP_param(&params);
2077 	target_if_spectral_create_samp_msg(spectral, &params);
2078 
2079 	return 0;
2080  fail:
2081 	spectral_err_rl("Error while processing Spectral report");
2082 	reset_160mhz_delivery_state_machine(spectral,
2083 					    SPECTRAL_SCAN_MODE_NORMAL);
2084 	return -EPERM;
2085 }
2086 
2087 int target_if_spectral_process_report_gen3(
2088 	struct wlan_objmgr_pdev *pdev,
2089 	void *buf)
2090 {
2091 	int ret = 0;
2092 	struct direct_buf_rx_data *payload = buf;
2093 	struct target_if_spectral *spectral;
2094 	struct spectral_report report;
2095 
2096 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2097 	if (!spectral) {
2098 		spectral_err("Spectral target object is null");
2099 		return -EINVAL;
2100 	}
2101 
2102 	report.data = payload->vaddr;
2103 	if (payload->meta_data_valid) {
2104 		qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor,
2105 			     qdf_min(sizeof(report.noisefloor),
2106 				     sizeof(payload->meta_data.noisefloor)));
2107 		report.reset_delay = payload->meta_data.reset_delay;
2108 	}
2109 
2110 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) {
2111 		spectral_debug("Printing the spectral phyerr buffer for debug");
2112 		spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK",
2113 			       payload->dbr_len,
2114 			       payload->dbr_len,
2115 			       payload->vaddr);
2116 		target_if_spectral_hexdump((unsigned char *)payload->vaddr,
2117 					   1024);
2118 	}
2119 
2120 	ret = target_if_consume_spectral_report_gen3(spectral, &report);
2121 
2122 	if (spectral_debug_level & DEBUG_SPECTRAL4)
2123 		spectral_debug_level = DEBUG_SPECTRAL;
2124 
2125 	return ret;
2126 }
2127 #else
2128 int target_if_spectral_process_report_gen3(
2129 	struct wlan_objmgr_pdev *pdev,
2130 	void *buf)
2131 {
2132 	spectral_err("Direct dma support is not enabled");
2133 	return -EINVAL;
2134 }
2135 #endif
2136 qdf_export_symbol(target_if_spectral_process_report_gen3);
2137 /* END of spectral GEN III HW specific functions */
2138 
2139 #endif  /* WLAN_CONV_SPECTRAL_ENABLE */
2140