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