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