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