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