xref: /wlan-dirver/qca-wifi-host-cmn/target_if/spectral/target_if_spectral_phyerr.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
1 /*
2  * Copyright (c) 2011,2017-2020 The Linux Foundation. All rights reserved.
3  *
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <osdep.h>
21 #include <qdf_types.h>
22 #include <qdf_module.h>
23 #include <wlan_tgt_def_config.h>
24 #include <hif.h>
25 #include <hif_hw_version.h>
26 #include <wmi_unified_api.h>
27 #include <target_if_spectral.h>
28 #include <wlan_lmac_if_def.h>
29 #include <wlan_osif_priv.h>
30 #include <reg_services_public_struct.h>
31 #include <target_if.h>
32 #ifdef DIRECT_BUF_RX_ENABLE
33 #include <target_if_direct_buf_rx_api.h>
34 #endif
35 extern int spectral_debug_level;
36 
37 #ifdef WLAN_CONV_SPECTRAL_ENABLE
38 
39 #define SPECTRAL_HEXDUMP_OCTET_PRINT_SIZE           (3)
40 #define SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE        (16)
41 #define SPECTRAL_HEXDUMP_EXTRA_BUFFER_PER_LINE      (16)
42 
43 /*
44  * Provision for the expected hexdump line size as follows:
45  *
46  * Size per octet multiplied by number of octets per line
47  * +
48  * ASCII representation which is equivalent in print size to number of octets
49  * per line
50  * +
51  * Some extra buffer
52  */
53 #define SPECTRAL_HEXDUMP_LINESIZE                           \
54 		((SPECTRAL_HEXDUMP_OCTET_PRINT_SIZE *       \
55 		  SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) +   \
56 		 SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE +     \
57 		 SPECTRAL_HEXDUMP_EXTRA_BUFFER_PER_LINE)
58 
59 /**
60  * target_if_spectral_hexdump() - Print hexdump of the given buffer
61  * @_buf: Pointer to buffer
62  * @_len: Length of the buffer
63  *
64  * Print the hexdump of buffer upto given length. Print upto
65  * SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE per line, followed by the ASCII
66  * representation of these octets.
67  */
68 static inline void target_if_spectral_hexdump(unsigned char *_buf, int _len)
69 {
70 	int i, mod;
71 	unsigned char ascii[SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE + 1];
72 	unsigned char *pc = (_buf);
73 	char hexdump_line[SPECTRAL_HEXDUMP_LINESIZE + 1];
74 	int loc = 0;
75 
76 	qdf_mem_zero(hexdump_line, sizeof(hexdump_line));
77 
78 	if (_len <= 0) {
79 		spectral_err("buffer len is %d, too short", _len);
80 		return;
81 	}
82 
83 	for (i = 0; i < _len; i++) {
84 		mod = i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE;
85 
86 		if (!mod) {
87 			if (i) {
88 				qdf_assert_always(loc < sizeof(hexdump_line));
89 				loc += snprintf(&hexdump_line[loc],
90 						sizeof(hexdump_line) - loc,
91 						"  %s", ascii);
92 				spectral_debug("%s", hexdump_line);
93 				qdf_mem_zero(hexdump_line,
94 					     sizeof(hexdump_line));
95 				loc = 0;
96 			}
97 		}
98 
99 		qdf_assert_always(loc < sizeof(hexdump_line));
100 		loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
101 				" %02x", pc[i]);
102 
103 		if ((pc[i] < 0x20) || (pc[i] > 0x7e))
104 			ascii[mod] = '.';
105 		else
106 			ascii[mod] = pc[i];
107 		ascii[(mod) + 1] = '\0';
108 	}
109 
110 	while ((i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) != 0) {
111 		qdf_assert_always(loc < sizeof(hexdump_line));
112 		loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
113 				"   ");
114 		i++;
115 	}
116 
117 	qdf_assert_always(loc < sizeof(hexdump_line));
118 	snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, "  %s", ascii);
119 	spectral_debug("%s", hexdump_line);
120 }
121 
122 /**
123  * target_if_print_buf() - Prints given buffer for given length
124  * @pbuf: Pointer to buffer
125  * @len: length
126  *
127  * Prints given buffer for given length
128  *
129  * Return: void
130  */
131 static void
132 target_if_print_buf(uint8_t *pbuf, int len)
133 {
134 	int i = 0;
135 
136 	for (i = 0; i < len; i++) {
137 		spectral_debug("%02X ", pbuf[i]);
138 		if (i % 32 == 31)
139 			spectral_debug("\n");
140 	}
141 }
142 
143 int
144 target_if_spectral_dump_fft(uint8_t *pfft, int fftlen)
145 {
146 	int i = 0;
147 
148 	/*
149 	 * TODO : Do not delete the following print
150 	 *        The scripts used to validate Spectral depend on this Print
151 	 */
152 	spectral_debug("SPECTRAL : FFT Length is 0x%x (%d)", fftlen, fftlen);
153 
154 	spectral_debug("fft_data # ");
155 	for (i = 0; i < fftlen; i++)
156 		spectral_debug("%d ", pfft[i]);
157 	spectral_debug("\n");
158 	return 0;
159 }
160 
161 QDF_STATUS target_if_spectral_fw_hang(struct target_if_spectral *spectral)
162 {
163 	struct crash_inject param;
164 	struct wlan_objmgr_pdev *pdev;
165 	struct wlan_objmgr_psoc *psoc;
166 	struct target_if_psoc_spectral *psoc_spectral;
167 
168 	if (!spectral) {
169 		spectral_err("Spectral LMAC object is null");
170 		return QDF_STATUS_E_INVAL;
171 	}
172 
173 	pdev = spectral->pdev_obj;
174 	if (!pdev) {
175 		spectral_err("pdev is null");
176 		return QDF_STATUS_E_FAILURE;
177 	}
178 
179 	psoc = wlan_pdev_get_psoc(pdev);
180 	if (!psoc) {
181 		spectral_err("psoc is null");
182 		return QDF_STATUS_E_FAILURE;
183 	}
184 
185 	psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
186 	if (!psoc_spectral) {
187 		spectral_err("spectral psoc object is null");
188 		return QDF_STATUS_E_FAILURE;
189 	}
190 
191 	qdf_mem_set(&param, sizeof(param), 0);
192 	param.type = 1; //RECOVERY_SIM_ASSERT
193 
194 	return psoc_spectral->wmi_ops.wmi_spectral_crash_inject(
195 		GET_WMI_HDL_FROM_PDEV(spectral->pdev_obj), &param);
196 }
197 
198 void
199 target_if_dbg_print_samp_param(struct target_if_samp_msg_params *p)
200 {
201 	spectral_debug("\nSAMP Packet : -------------------- START --------------------");
202 	spectral_debug("Freq        = %d", p->freq);
203 	spectral_debug("RSSI        = %d", p->rssi);
204 	spectral_debug("Bin Count   = %d", p->pwr_count);
205 	spectral_debug("Timestamp   = %d", p->tstamp);
206 	spectral_debug("SAMP Packet : -------------------- END -----------------------");
207 }
208 
209 void
210 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg)
211 {
212 	int i = 0;
213 
214 	struct spectral_samp_data *p = &ss_msg->samp_data;
215 	struct spectral_classifier_params *pc = &p->classifier_params;
216 	struct interf_src_rsp *pi = &p->interf_list;
217 
218 	spectral_dbg_line();
219 	spectral_debug("Spectral Message");
220 	spectral_dbg_line();
221 	spectral_debug("Signature   :   0x%x", ss_msg->signature);
222 	spectral_debug("Freq        :   %d", ss_msg->freq);
223 	spectral_debug("Freq load   :   %d", ss_msg->freq_loading);
224 	spectral_debug("Intfnc type :   %d", ss_msg->int_type);
225 	spectral_dbg_line();
226 	spectral_debug("Spectral Data info");
227 	spectral_dbg_line();
228 	spectral_debug("data length     :   %d", p->spectral_data_len);
229 	spectral_debug("rssi            :   %d", p->spectral_rssi);
230 	spectral_debug("combined rssi   :   %d", p->spectral_combined_rssi);
231 	spectral_debug("upper rssi      :   %d", p->spectral_upper_rssi);
232 	spectral_debug("lower rssi      :   %d", p->spectral_lower_rssi);
233 	spectral_debug("bw info         :   %d", p->spectral_bwinfo);
234 	spectral_debug("timestamp       :   %d", p->spectral_tstamp);
235 	spectral_debug("max index       :   %d", p->spectral_max_index);
236 	spectral_debug("max exp         :   %d", p->spectral_max_exp);
237 	spectral_debug("max mag         :   %d", p->spectral_max_mag);
238 	spectral_debug("last timstamp   :   %d", p->spectral_last_tstamp);
239 	spectral_debug("upper max idx   :   %d", p->spectral_upper_max_index);
240 	spectral_debug("lower max idx   :   %d", p->spectral_lower_max_index);
241 	spectral_debug("bin power count :   %d", p->bin_pwr_count);
242 	spectral_dbg_line();
243 	spectral_debug("Classifier info");
244 	spectral_dbg_line();
245 	spectral_debug("20/40 Mode      :   %d", pc->spectral_20_40_mode);
246 	spectral_debug("dc index        :   %d", pc->spectral_dc_index);
247 	spectral_debug("dc in MHz       :   %d", pc->spectral_dc_in_mhz);
248 	spectral_debug("upper channel   :   %d", pc->upper_chan_in_mhz);
249 	spectral_debug("lower channel   :   %d", pc->lower_chan_in_mhz);
250 	spectral_dbg_line();
251 	spectral_debug("Interference info");
252 	spectral_dbg_line();
253 	spectral_debug("inter count     :   %d", pi->count);
254 
255 	for (i = 0; i < pi->count; i++) {
256 		spectral_debug("inter type  :   %d",
257 			       pi->interf[i].interf_type);
258 		spectral_debug("min freq    :   %d",
259 			       pi->interf[i].interf_min_freq);
260 		spectral_debug("max freq    :   %d",
261 			       pi->interf[i].interf_max_freq);
262 	}
263 }
264 
265 uint32_t
266 target_if_get_offset_swar_sec80(uint32_t channel_width)
267 {
268 	uint32_t offset = 0;
269 
270 	switch (channel_width) {
271 	case CH_WIDTH_20MHZ:
272 		offset = OFFSET_CH_WIDTH_20;
273 		break;
274 	case CH_WIDTH_40MHZ:
275 		offset = OFFSET_CH_WIDTH_40;
276 		break;
277 	case CH_WIDTH_80MHZ:
278 		offset = OFFSET_CH_WIDTH_80;
279 		break;
280 	case CH_WIDTH_160MHZ:
281 	case CH_WIDTH_80P80MHZ:
282 		offset = OFFSET_CH_WIDTH_160;
283 		break;
284 	default:
285 		offset = OFFSET_CH_WIDTH_80;
286 		break;
287 	}
288 	return offset;
289 }
290 
291 /**
292  * target_if_dump_summary_report_gen2() - Dump Spectral Summary Report for gen2
293  * @ptlv: Pointer to Spectral Phyerr TLV
294  * @tlvlen: length
295  * @is_160_format: Indicates whether information provided by HW is in altered
296  *                 format for 802.11ac 160/80+80 MHz support (QCA9984 onwards)
297  *
298  * Dump Spectral Summary Report for gen2
299  *
300  * Return: Success/Failure
301  */
302 static int
303 target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
304 				   int tlvlen, bool is_160_format)
305 {
306 	/*
307 	 * For simplicity, everything is defined as uint32_t (except one).
308 	 * Proper code will later use the right sizes.
309 	 */
310 
311 	/*
312 	 * For easy comparision between MDK team and OS team, the MDK script
313 	 * variable names have been used
314 	 */
315 
316 	uint32_t agc_mb_gain;
317 	uint32_t sscan_gidx;
318 	uint32_t agc_total_gain;
319 	uint32_t recent_rfsat;
320 	uint32_t ob_flag;
321 	uint32_t nb_mask;
322 	uint32_t peak_mag;
323 	int16_t peak_inx;
324 
325 	uint32_t ss_summary_A = 0;
326 	uint32_t ss_summary_B = 0;
327 	uint32_t ss_summary_C = 0;
328 	uint32_t ss_summary_D = 0;
329 	uint32_t ss_summary_E = 0;
330 	struct spectral_phyerr_hdr_gen2 *phdr =
331 	    (struct spectral_phyerr_hdr_gen2 *)(
332 		(uint8_t *)ptlv +
333 		sizeof(struct spectral_phyerr_tlv_gen2));
334 
335 	spectral_debug("SPECTRAL : SPECTRAL SUMMARY REPORT");
336 
337 	if (is_160_format) {
338 		if (tlvlen != 20) {
339 			spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
340 				     tlvlen);
341 			target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
342 			return -EPERM;
343 		}
344 
345 		/* Doing copy as the contents may not be aligned */
346 		qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
347 		qdf_mem_copy(&ss_summary_B,
348 			     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
349 			     sizeof(int));
350 		qdf_mem_copy(&ss_summary_C,
351 			     (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
352 			     sizeof(int));
353 		qdf_mem_copy(&ss_summary_D,
354 			     (uint8_t *)((uint8_t *)phdr + 3 * sizeof(int)),
355 			     sizeof(int));
356 		qdf_mem_copy(&ss_summary_E,
357 			     (uint8_t *)((uint8_t *)phdr + 4 * sizeof(int)),
358 			     sizeof(int));
359 
360 		/*
361 		 * The following is adapted from MDK scripts for
362 		 * easier comparability
363 		 */
364 
365 		recent_rfsat = ((ss_summary_A >> 8) & 0x1);
366 		sscan_gidx = (ss_summary_A & 0xff);
367 		spectral_debug("sscan_gidx=%d, is_recent_rfsat=%d",
368 			       sscan_gidx, recent_rfsat);
369 
370 		/* First segment */
371 		agc_mb_gain = ((ss_summary_B >> 10) & 0x7f);
372 		agc_total_gain = (ss_summary_B & 0x3ff);
373 		nb_mask = ((ss_summary_C >> 22) & 0xff);
374 		ob_flag = ((ss_summary_B >> 17) & 0x1);
375 		peak_inx = (ss_summary_C & 0xfff);
376 		if (peak_inx > 2047)
377 			peak_inx = peak_inx - 4096;
378 		peak_mag = ((ss_summary_C >> 12) & 0x3ff);
379 
380 		spectral_debug("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d",
381 			       agc_total_gain, agc_mb_gain);
382 		spectral_debug("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, peak_index_segid0=%d, peak_mag_segid0=%d",
383 			       nb_mask, ob_flag, peak_inx, peak_mag);
384 
385 		/* Second segment */
386 		agc_mb_gain = ((ss_summary_D >> 10) & 0x7f);
387 		agc_total_gain = (ss_summary_D & 0x3ff);
388 		nb_mask = ((ss_summary_E >> 22) & 0xff);
389 		ob_flag = ((ss_summary_D >> 17) & 0x1);
390 		peak_inx = (ss_summary_E & 0xfff);
391 		if (peak_inx > 2047)
392 			peak_inx = peak_inx - 4096;
393 		peak_mag = ((ss_summary_E >> 12) & 0x3ff);
394 
395 		spectral_debug("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d",
396 			       agc_total_gain, agc_mb_gain);
397 		spectral_debug("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, peak_index_segid1=%d, peak_mag_segid1=%d",
398 			       nb_mask, ob_flag, peak_inx, peak_mag);
399 	} else {
400 		if (tlvlen != 8) {
401 			spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
402 				     tlvlen);
403 			target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
404 			return -EPERM;
405 		}
406 
407 		/* Doing copy as the contents may not be aligned */
408 		qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
409 		qdf_mem_copy(&ss_summary_B,
410 			     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
411 			     sizeof(int));
412 
413 		nb_mask = ((ss_summary_B >> 22) & 0xff);
414 		ob_flag = ((ss_summary_B >> 30) & 0x1);
415 		peak_inx = (ss_summary_B & 0xfff);
416 
417 		if (peak_inx > 2047)
418 			peak_inx = peak_inx - 4096;
419 
420 		peak_mag = ((ss_summary_B >> 12) & 0x3ff);
421 		agc_mb_gain = ((ss_summary_A >> 24) & 0x7f);
422 		agc_total_gain = (ss_summary_A & 0x3ff);
423 		sscan_gidx = ((ss_summary_A >> 16) & 0xff);
424 		recent_rfsat = ((ss_summary_B >> 31) & 0x1);
425 
426 		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",
427 			       nb_mask, ob_flag, peak_inx, peak_mag,
428 			       agc_mb_gain, agc_total_gain, sscan_gidx,
429 			       recent_rfsat);
430 	}
431 
432 	return 0;
433 }
434 
435 /**
436  * target_if_process_sfft_report_gen2() - Process Search FFT Report
437  * @ptlv: Pointer to Spectral Phyerr TLV
438  * @tlvlen: length
439  * @p_fft_info: Pointer to search fft info
440  *
441  * Dump Spectral Summary Report for gen2
442  *
443  * Return: Success/Failure
444  */
445 static int
446 target_if_process_sfft_report_gen2(
447 	struct spectral_phyerr_tlv_gen2 *ptlv,
448 	int tlvlen,
449 	struct spectral_search_fft_info_gen2 *p_fft_info)
450 {
451 	/*
452 	 * For simplicity, everything is defined as uint32_t (except one).
453 	 * Proper code will later use the right sizes.
454 	 */
455 	/*
456 	 * For easy comparision between MDK team and OS team, the MDK script
457 	 * variable names have been used
458 	 */
459 	uint32_t relpwr_db;
460 	uint32_t num_str_bins_ib;
461 	uint32_t base_pwr;
462 	uint32_t total_gain_info;
463 
464 	uint32_t fft_chn_idx;
465 	int16_t peak_inx;
466 	uint32_t avgpwr_db;
467 	uint32_t peak_mag;
468 
469 	uint32_t fft_summary_A = 0;
470 	uint32_t fft_summary_B = 0;
471 	uint8_t *tmp = (uint8_t *)ptlv;
472 	struct spectral_phyerr_hdr_gen2 *phdr =
473 	    (struct spectral_phyerr_hdr_gen2 *)(
474 		tmp +
475 		sizeof(struct spectral_phyerr_tlv_gen2));
476 
477 	/* Relook this */
478 	if (tlvlen < 8) {
479 		spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
480 			     tlvlen);
481 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
482 		return -EPERM;
483 	}
484 
485 	/* Doing copy as the contents may not be aligned */
486 	qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
487 	qdf_mem_copy(&fft_summary_B,
488 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
489 		     sizeof(int));
490 
491 	relpwr_db = ((fft_summary_B >> 26) & 0x3f);
492 	num_str_bins_ib = fft_summary_B & 0xff;
493 	base_pwr = ((fft_summary_A >> 14) & 0x1ff);
494 	total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
495 
496 	fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
497 	peak_inx = fft_summary_A & 0xfff;
498 
499 	if (peak_inx > 2047)
500 		peak_inx = peak_inx - 4096;
501 
502 	avgpwr_db = ((fft_summary_B >> 18) & 0xff);
503 	peak_mag = ((fft_summary_B >> 8) & 0x3ff);
504 
505 	/* Populate the Search FFT Info */
506 	if (p_fft_info) {
507 		p_fft_info->relpwr_db = relpwr_db;
508 		p_fft_info->num_str_bins_ib = num_str_bins_ib;
509 		p_fft_info->base_pwr = base_pwr;
510 		p_fft_info->total_gain_info = total_gain_info;
511 		p_fft_info->fft_chn_idx = fft_chn_idx;
512 		p_fft_info->peak_inx = peak_inx;
513 		p_fft_info->avgpwr_db = avgpwr_db;
514 		p_fft_info->peak_mag = peak_mag;
515 	}
516 
517 	return 0;
518 }
519 
520 /**
521  * target_if_dump_adc_report_gen2() - Dump ADC Reports for gen2
522  * @ptlv: Pointer to Spectral Phyerr TLV
523  * @tlvlen: length
524  *
525  * Dump ADC Reports for gen2
526  *
527  * Return: Success/Failure
528  */
529 static int
530 target_if_dump_adc_report_gen2(
531 	struct spectral_phyerr_tlv_gen2 *ptlv, int tlvlen)
532 {
533 	int i;
534 	uint32_t *pdata;
535 	uint32_t data;
536 
537 	/*
538 	 * For simplicity, everything is defined as uint32_t (except one).
539 	 * Proper code will later use the right sizes.
540 	 */
541 	uint32_t samp_fmt;
542 	uint32_t chn_idx;
543 	uint32_t recent_rfsat;
544 	uint32_t agc_mb_gain;
545 	uint32_t agc_total_gain;
546 
547 	uint32_t adc_summary = 0;
548 
549 	uint8_t *ptmp = (uint8_t *)ptlv;
550 
551 	spectral_debug("SPECTRAL : ADC REPORT");
552 
553 	/* Relook this */
554 	if (tlvlen < 4) {
555 		spectral_err("Unexpected TLV length %d for ADC Report! Hexdump follows",
556 			     tlvlen);
557 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
558 		return -EPERM;
559 	}
560 
561 	qdf_mem_copy(&adc_summary, (uint8_t *)(ptlv + 4), sizeof(int));
562 
563 	samp_fmt = ((adc_summary >> 28) & 0x1);
564 	chn_idx = ((adc_summary >> 24) & 0x3);
565 	recent_rfsat = ((adc_summary >> 23) & 0x1);
566 	agc_mb_gain = ((adc_summary >> 16) & 0x7f);
567 	agc_total_gain = adc_summary & 0x3ff;
568 
569 	spectral_debug("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u agc_total_gain=%u",
570 		       samp_fmt, chn_idx, recent_rfsat, agc_mb_gain,
571 		       agc_total_gain);
572 
573 	for (i = 0; i < (tlvlen / 4); i++) {
574 		pdata = (uint32_t *)(ptmp + 4 + i * 4);
575 		data = *pdata;
576 
577 		/* Interpreting capture format 1 */
578 		if (1) {
579 			uint8_t i1;
580 			uint8_t q1;
581 			uint8_t i2;
582 			uint8_t q2;
583 			int8_t si1;
584 			int8_t sq1;
585 			int8_t si2;
586 			int8_t sq2;
587 
588 			i1 = data & 0xff;
589 			q1 = (data >> 8) & 0xff;
590 			i2 = (data >> 16) & 0xff;
591 			q2 = (data >> 24) & 0xff;
592 
593 			if (i1 > 127)
594 				si1 = i1 - 256;
595 			else
596 				si1 = i1;
597 
598 			if (q1 > 127)
599 				sq1 = q1 - 256;
600 			else
601 				sq1 = q1;
602 
603 			if (i2 > 127)
604 				si2 = i2 - 256;
605 			else
606 				si2 = i2;
607 
608 			if (q2 > 127)
609 				sq2 = q2 - 256;
610 			else
611 				sq2 = q2;
612 
613 			spectral_debug("SPECTRAL ADC : Interpreting capture format 1");
614 			spectral_debug("adc_data_format_1 # %d %d %d",
615 				       2 * i, si1, sq1);
616 			spectral_debug("adc_data_format_1 # %d %d %d",
617 				       2 * i + 1, si2, sq2);
618 		}
619 
620 		/* Interpreting capture format 0 */
621 		if (1) {
622 			uint16_t i1;
623 			uint16_t q1;
624 			int16_t si1;
625 			int16_t sq1;
626 
627 			i1 = data & 0xffff;
628 			q1 = (data >> 16) & 0xffff;
629 			if (i1 > 32767)
630 				si1 = i1 - 65536;
631 			else
632 				si1 = i1;
633 
634 			if (q1 > 32767)
635 				sq1 = q1 - 65536;
636 			else
637 				sq1 = q1;
638 			spectral_debug("SPECTRAL ADC : Interpreting capture format 0");
639 			spectral_debug("adc_data_format_2 # %d %d %d",
640 				       i, si1, sq1);
641 		}
642 	}
643 
644 	spectral_debug("\n");
645 
646 	return 0;
647 }
648 
649 /**
650  * target_if_dump_sfft_report_gen2() - Process Search FFT Report for gen2
651  * @ptlv: Pointer to Spectral Phyerr TLV
652  * @tlvlen: length
653  * @is_160_format: Indicates 160 format
654  *
655  * Process Search FFT Report for gen2
656  *
657  * Return: Success/Failure
658  */
659 static int
660 target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
661 				int tlvlen, bool is_160_format)
662 {
663 	int i;
664 	uint32_t fft_mag;
665 
666 	/*
667 	 * For simplicity, everything is defined as uint32_t (except one).
668 	 * Proper code will later use the right sizes.
669 	 */
670 	/*
671 	 * For easy comparision between MDK team and OS team, the MDK script
672 	 * variable names have been used
673 	 */
674 	uint32_t relpwr_db;
675 	uint32_t num_str_bins_ib;
676 	uint32_t base_pwr;
677 	uint32_t total_gain_info;
678 
679 	uint32_t fft_chn_idx;
680 	int16_t peak_inx;
681 	uint32_t avgpwr_db;
682 	uint32_t peak_mag;
683 	uint8_t segid;
684 
685 	uint32_t fft_summary_A = 0;
686 	uint32_t fft_summary_B = 0;
687 	uint32_t fft_summary_C = 0;
688 	uint8_t *tmp = (uint8_t *)ptlv;
689 	struct spectral_phyerr_hdr_gen2 *phdr =
690 	    (struct spectral_phyerr_hdr_gen2 *)(
691 		tmp +
692 		sizeof(struct spectral_phyerr_tlv_gen2));
693 	uint32_t segid_skiplen = 0;
694 
695 	if (is_160_format)
696 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
697 
698 	spectral_debug("SPECTRAL : SEARCH FFT REPORT");
699 
700 	/* Relook this */
701 	if (tlvlen < (8 + segid_skiplen)) {
702 		spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
703 			     tlvlen);
704 		target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
705 		return -EPERM;
706 	}
707 
708 	/* Doing copy as the contents may not be aligned */
709 	qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
710 	qdf_mem_copy(&fft_summary_B,
711 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
712 		     sizeof(int));
713 	if (is_160_format)
714 		qdf_mem_copy(&fft_summary_C,
715 			     (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
716 			     sizeof(int));
717 
718 	relpwr_db = ((fft_summary_B >> 26) & 0x3f);
719 	num_str_bins_ib = fft_summary_B & 0xff;
720 	base_pwr = ((fft_summary_A >> 14) & 0x1ff);
721 	total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
722 
723 	fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
724 	peak_inx = fft_summary_A & 0xfff;
725 
726 	if (peak_inx > 2047)
727 		peak_inx = peak_inx - 4096;
728 
729 	avgpwr_db = ((fft_summary_B >> 18) & 0xff);
730 	peak_mag = ((fft_summary_B >> 8) & 0x3ff);
731 
732 	spectral_debug("Header A = 0x%x Header B = 0x%x",
733 		       phdr->hdr_a, phdr->hdr_b);
734 	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",
735 		       base_pwr, total_gain_info, relpwr_db, num_str_bins_ib,
736 		       fft_chn_idx, peak_inx, avgpwr_db, peak_mag);
737 	if (is_160_format) {
738 		segid = fft_summary_C & 0x1;
739 		spectral_debug("Segment ID: %hhu", segid);
740 	}
741 
742 	spectral_debug("FFT bins:");
743 	for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) {
744 		fft_mag = ((uint8_t *)ptlv)[12 + segid_skiplen + i];
745 		spectral_debug("%d %d, ", i, fft_mag);
746 	}
747 
748 	spectral_debug("\n");
749 
750 	return 0;
751 }
752 
753 #ifdef SPECTRAL_DEBUG_SAMP_MSG
754 /**
755  * target_if_spectral_log_SAMP_param() - Log SAMP parameters
756  * @params: Reference to target_if_samp_msg_params
757  *
758  * API to log spectral SAMP message parameters
759  *
760  * Return: None
761  */
762 static void
763 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
764 {
765 	target_if_dbg_print_samp_param(params);
766 }
767 
768 #else
769 static void
770 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
771 {
772 }
773 #endif
774 
775 int
776 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
777 			      uint8_t *data,
778 			      uint32_t datalen,
779 			      struct target_if_spectral_rfqual_info *p_rfqual,
780 			      struct target_if_spectral_chan_info *p_chaninfo,
781 			      uint64_t tsf64,
782 			      struct target_if_spectral_acs_stats *acs_stats)
783 {
784 	/*
785 	 * XXX : The classifier do not use all the members of the SAMP
786 	 *       message data format.
787 	 *       The classifier only depends upon the following parameters
788 	 *
789 	 *          1. Frequency (freq, msg->freq)
790 	 *          2. Spectral RSSI (spectral_rssi,
791 	 *          msg->samp_data.spectral_rssi)
792 	 *          3. Bin Power Count (bin_pwr_count,
793 	 *          msg->samp_data.bin_pwr_count)
794 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
795 	 *          5. Spectral Timestamp (spectral_tstamp,
796 	 *          msg->samp_data.spectral_tstamp)
797 	 *          6. MAC Address (macaddr, msg->macaddr)
798 	 *
799 	 *       This function prepares the params structure and populates it
800 	 *       with
801 	 *       relevant values, this is in turn passed to
802 	 *       spectral_create_samp_msg()
803 	 *       to prepare fully formatted Spectral SAMP message
804 	 *
805 	 *       XXX : Need to verify
806 	 *          1. Order of FFT bin values
807 	 *
808 	 */
809 
810 	struct target_if_samp_msg_params params;
811 	struct spectral_search_fft_info_gen2 search_fft_info;
812 	struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
813 	struct spectral_search_fft_info_gen2 search_fft_info_sec80;
814 	struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
815 		&search_fft_info_sec80;
816 	uint32_t segid_skiplen = 0;
817 
818 	int8_t rssi_up = 0;
819 	int8_t rssi_low = 0;
820 
821 	int8_t chn_idx_highest_enabled = 0;
822 	int8_t chn_idx_lowest_enabled = 0;
823 
824 	uint8_t control_rssi = 0;
825 	uint8_t extension_rssi = 0;
826 	uint8_t combined_rssi = 0;
827 
828 	uint32_t tstamp = 0;
829 
830 	struct target_if_spectral_ops *p_sops =
831 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
832 
833 	struct spectral_phyerr_tlv_gen2 *ptlv =
834 		(struct spectral_phyerr_tlv_gen2 *)data;
835 	struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
836 	struct spectral_phyerr_fft_gen2 *pfft = NULL;
837 	struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
838 
839 	uint8_t segid = 0;
840 	uint8_t segid_sec80 = 0;
841 	enum phy_ch_width ch_width =
842 				spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL];
843 
844 	if (spectral->is_160_format)
845 		segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
846 
847 	pfft = (struct spectral_phyerr_fft_gen2 *)(
848 			data +
849 			sizeof(struct spectral_phyerr_tlv_gen2) +
850 			sizeof(struct spectral_phyerr_hdr_gen2) +
851 			segid_skiplen);
852 
853 	/*
854 	 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
855 	 * and use this facility inside spectral_dump_phyerr_data()
856 	 * and supporting functions.
857 	 */
858 	if (spectral_debug_level & DEBUG_SPECTRAL2)
859 		target_if_spectral_dump_phyerr_data_gen2(
860 					data, datalen,
861 					spectral->is_160_format);
862 
863 	if (spectral_debug_level & DEBUG_SPECTRAL4) {
864 		target_if_spectral_dump_phyerr_data_gen2(
865 					data, datalen,
866 					spectral->is_160_format);
867 		spectral_debug_level = DEBUG_SPECTRAL;
868 	}
869 
870 	if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
871 		/*
872 		 * EV# 118023: We tentatively disable the below print
873 		 * and provide stats instead.
874 		 */
875 		spectral->diag_stats.spectral_mismatch++;
876 		return -EPERM;
877 	}
878 
879 	OS_MEMZERO(&params, sizeof(params));
880 	/* Gen 2 only supports normal Spectral scan currently */
881 	params.smode = SPECTRAL_SCAN_MODE_NORMAL;
882 
883 	if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
884 		if (spectral->is_160_format) {
885 			segid = *((SPECTRAL_SEGID_INFO *)(
886 				  (uint8_t *)ptlv +
887 				  sizeof(struct spectral_phyerr_tlv_gen2) +
888 				  sizeof(struct spectral_phyerr_hdr_gen2)));
889 
890 			if (segid != 0) {
891 				struct spectral_diag_stats *p_diag_stats =
892 					&spectral->diag_stats;
893 				p_diag_stats->spectral_vhtseg1id_mismatch++;
894 				return -EPERM;
895 			}
896 		}
897 
898 		target_if_process_sfft_report_gen2(ptlv, ptlv->length,
899 						   &search_fft_info);
900 
901 		tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
902 
903 		combined_rssi = p_rfqual->rssi_comb;
904 
905 		if (spectral->upper_is_control)
906 			rssi_up = control_rssi;
907 		else
908 			rssi_up = extension_rssi;
909 
910 		if (spectral->lower_is_control)
911 			rssi_low = control_rssi;
912 		else
913 			rssi_low = extension_rssi;
914 
915 		params.rssi = p_rfqual->rssi_comb;
916 		params.lower_rssi = rssi_low;
917 		params.upper_rssi = rssi_up;
918 
919 		if (spectral->sc_spectral_noise_pwr_cal) {
920 			params.chain_ctl_rssi[0] =
921 			    p_rfqual->pc_rssi_info[0].rssi_pri20;
922 			params.chain_ctl_rssi[1] =
923 			    p_rfqual->pc_rssi_info[1].rssi_pri20;
924 			params.chain_ctl_rssi[2] =
925 			    p_rfqual->pc_rssi_info[2].rssi_pri20;
926 			params.chain_ext_rssi[0] =
927 			    p_rfqual->pc_rssi_info[0].rssi_sec20;
928 			params.chain_ext_rssi[1] =
929 			    p_rfqual->pc_rssi_info[1].rssi_sec20;
930 			params.chain_ext_rssi[2] =
931 			    p_rfqual->pc_rssi_info[2].rssi_sec20;
932 		}
933 
934 		/*
935 		 * XXX : This actually depends on the programmed chain mask
936 		 *       This value decides the per-chain enable mask to select
937 		 *       the input ADC for search FTT.
938 		 *       For modes upto VHT80, if more than one chain is
939 		 *       enabled, the max valid chain
940 		 *       is used. LSB corresponds to chain zero.
941 		 *       For VHT80_80 and VHT160, the lowest enabled chain is
942 		 *       used for primary
943 		 *       detection and highest enabled chain is used for
944 		 *       secondary detection.
945 		 *
946 		 * XXX : The current algorithm do not use these control and
947 		 *       extension channel
948 		 *       Instead, it just relies on the combined RSSI values
949 		 *       only.
950 		 *       For fool-proof detection algorithm, we should take
951 		 *       these RSSI values in to account.
952 		 *       This is marked for future enhancements.
953 		 */
954 		chn_idx_highest_enabled =
955 		   ((spectral->params[params.smode].ss_chn_mask & 0x8) ? 3 :
956 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 :
957 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 0);
958 		chn_idx_lowest_enabled =
959 		   ((spectral->params[params.smode].ss_chn_mask & 0x1) ? 0 :
960 		    (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 :
961 		    (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 3);
962 		control_rssi = (uint8_t)
963 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
964 		extension_rssi = (uint8_t)
965 		    p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
966 
967 		params.bwinfo = 0;
968 		params.tstamp = 0;
969 		params.max_mag = p_sfft->peak_mag;
970 
971 		params.max_index = p_sfft->peak_inx;
972 		params.max_exp = 0;
973 		params.peak = 0;
974 		params.bin_pwr_data = (uint8_t *)pfft;
975 		params.freq = p_sops->get_current_channel(spectral,
976 							  params.smode);
977 		params.freq_loading = 0;
978 
979 		params.interf_list.count = 0;
980 		params.max_lower_index = 0;
981 		params.max_upper_index = 0;
982 		params.nb_lower = 0;
983 		params.nb_upper = 0;
984 		/*
985 		 * For modes upto VHT80, the noise floor is populated with the
986 		 * one corresponding
987 		 * to the highest enabled antenna chain
988 		 */
989 		params.noise_floor =
990 		    p_rfqual->noise_floor[chn_idx_highest_enabled];
991 		params.datalen = ptlv->length;
992 		params.pwr_count = ptlv->length -
993 		    sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen;
994 		params.tstamp = (tsf64 & SPECTRAL_TSMASK);
995 
996 		acs_stats->ctrl_nf = params.noise_floor;
997 		acs_stats->ext_nf = params.noise_floor;
998 		acs_stats->nfc_ctl_rssi = control_rssi;
999 		acs_stats->nfc_ext_rssi = extension_rssi;
1000 
1001 		if (spectral->is_160_format &&
1002 		    is_ch_width_160_or_80p80(ch_width)) {
1003 			/*
1004 			 * We expect to see one more Search FFT report, and it
1005 			 * should be equal in size to the current one.
1006 			 */
1007 			if (datalen < (
1008 				2 * (
1009 				sizeof(struct spectral_phyerr_tlv_gen2) +
1010 				ptlv->length))) {
1011 				struct spectral_diag_stats *p_diag_stats =
1012 					&spectral->diag_stats;
1013 				p_diag_stats->spectral_sec80_sfft_insufflen++;
1014 				return -EPERM;
1015 			}
1016 
1017 			ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1018 				      data +
1019 				      sizeof(struct spectral_phyerr_tlv_gen2) +
1020 				      ptlv->length);
1021 
1022 			if (ptlv_sec80->signature !=
1023 			    SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1024 				spectral->diag_stats.spectral_mismatch++;
1025 				return -EPERM;
1026 			}
1027 
1028 			if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1029 				spectral->diag_stats.spectral_no_sec80_sfft++;
1030 				return -EPERM;
1031 			}
1032 
1033 			segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
1034 				(uint8_t *)ptlv_sec80 +
1035 				sizeof(struct spectral_phyerr_tlv_gen2) +
1036 				sizeof(struct spectral_phyerr_hdr_gen2)));
1037 
1038 			if (segid_sec80 != 1) {
1039 				struct spectral_diag_stats *p_diag_stats =
1040 					&spectral->diag_stats;
1041 				p_diag_stats->spectral_vhtseg2id_mismatch++;
1042 				return -EPERM;
1043 			}
1044 
1045 			params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
1046 			params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
1047 
1048 			target_if_process_sfft_report_gen2(
1049 				ptlv_sec80,
1050 				ptlv_sec80->length,
1051 				&search_fft_info_sec80);
1052 
1053 			pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
1054 				((uint8_t *)ptlv_sec80) +
1055 				sizeof(struct spectral_phyerr_tlv_gen2) +
1056 				sizeof(struct spectral_phyerr_hdr_gen2) +
1057 				segid_skiplen);
1058 
1059 			/* XXX: Confirm. TBD at SoD. */
1060 			params.rssi_sec80 = p_rfqual->rssi_comb;
1061 			if (spectral->is_sec80_rssi_war_required)
1062 				params.rssi_sec80 =
1063 				    target_if_get_combrssi_sec80_seg_gen2
1064 				    (spectral, &search_fft_info_sec80);
1065 			/* XXX: Determine dynamically. TBD at SoD. */
1066 			/*
1067 			 * For VHT80_80/VHT160, the noise floor for primary
1068 			 * 80MHz segment is populated with the
1069 			 * lowest enabled antenna chain and the noise floor for
1070 			 * secondary 80MHz segment is populated
1071 			 * with the highest enabled antenna chain
1072 			 */
1073 			params.noise_floor_sec80 =
1074 			    p_rfqual->noise_floor[chn_idx_highest_enabled];
1075 			params.noise_floor =
1076 			    p_rfqual->noise_floor[chn_idx_lowest_enabled];
1077 
1078 			params.max_mag_sec80 = p_sfft_sec80->peak_mag;
1079 			params.max_index_sec80 = p_sfft_sec80->peak_inx;
1080 			/* XXX Does this definition of datalen *still hold? */
1081 			params.datalen_sec80 = ptlv_sec80->length;
1082 			params.pwr_count_sec80 =
1083 			    ptlv_sec80->length -
1084 			    sizeof(struct spectral_phyerr_hdr_gen2) -
1085 			    segid_skiplen;
1086 			params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80;
1087 		}
1088 		qdf_mem_copy(&params.classifier_params,
1089 			     &spectral->classifier_params,
1090 			     sizeof(struct spectral_classifier_params));
1091 
1092 		target_if_spectral_log_SAMP_param(&params);
1093 		target_if_spectral_create_samp_msg(spectral, &params);
1094 	}
1095 
1096 	return 0;
1097 }
1098 
1099 int
1100 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr)
1101 {
1102 	uint32_t a = 0;
1103 	uint32_t b = 0;
1104 
1105 	qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int));
1106 	qdf_mem_copy(&b,
1107 		     (uint8_t *)((uint8_t *)phdr + sizeof(int)),
1108 		     sizeof(int));
1109 
1110 	spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a);
1111 	spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b);
1112 	return 0;
1113 }
1114 
1115 int8_t
1116 target_if_get_combrssi_sec80_seg_gen2(
1117 	struct target_if_spectral *spectral,
1118 	struct spectral_search_fft_info_gen2 *p_sfft_sec80)
1119 {
1120 	uint32_t avgpwr_db = 0;
1121 	uint32_t total_gain_db = 0;
1122 	uint32_t offset = 0;
1123 	int8_t comb_rssi = 0;
1124 
1125 	/* Obtain required parameters for algorithm from search FFT report */
1126 	avgpwr_db = p_sfft_sec80->avgpwr_db;
1127 	total_gain_db = p_sfft_sec80->total_gain_info;
1128 
1129 	/* Calculate offset */
1130 	offset = target_if_get_offset_swar_sec80(
1131 			spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL]);
1132 
1133 	/* Calculate RSSI */
1134 	comb_rssi = ((avgpwr_db - total_gain_db) + offset);
1135 
1136 	return comb_rssi;
1137 }
1138 
1139 int
1140 target_if_spectral_dump_tlv_gen2(
1141 	struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format)
1142 {
1143 	int ret = 0;
1144 
1145 	/*
1146 	 * TODO : Do not delete the following print
1147 	 *        The scripts used to validate Spectral depend on this Print
1148 	 */
1149 	spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)",
1150 		       ptlv->length, ptlv->length);
1151 
1152 	switch (ptlv->tag) {
1153 	case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
1154 		ret =
1155 		    target_if_dump_summary_report_gen2(
1156 			ptlv, ptlv->length, is_160_format);
1157 		break;
1158 
1159 	case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
1160 		ret =
1161 		    target_if_dump_sfft_report_gen2(ptlv, ptlv->length,
1162 						    is_160_format);
1163 		break;
1164 
1165 	case TLV_TAG_ADC_REPORT_GEN2:
1166 		ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length);
1167 		break;
1168 
1169 	default:
1170 		spectral_warn("INVALID TLV");
1171 		ret = -1;
1172 		break;
1173 	}
1174 
1175 	return ret;
1176 }
1177 
1178 int
1179 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen,
1180 					 bool is_160_format)
1181 {
1182 	struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
1183 	uint32_t bytes_processed = 0;
1184 	uint32_t bytes_remaining = datalen;
1185 	uint32_t curr_tlv_complete_size = 0;
1186 
1187 	if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) {
1188 		spectral_err("Total PHY error data length %u too short to contain any TLVs",
1189 			     datalen);
1190 		return -EPERM;
1191 	}
1192 
1193 	while (bytes_processed < datalen) {
1194 		if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) {
1195 			spectral_err("Remaining PHY error data length %u too short to contain a TLV",
1196 				     bytes_remaining);
1197 			return -EPERM;
1198 		}
1199 
1200 		ptlv = (struct spectral_phyerr_tlv_gen2 *)(data +
1201 							   bytes_processed);
1202 
1203 		if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1204 			spectral_err("Invalid signature 0x%x!",
1205 				     ptlv->signature);
1206 			return -EPERM;
1207 		}
1208 
1209 		curr_tlv_complete_size =
1210 			sizeof(struct spectral_phyerr_tlv_gen2) +
1211 			ptlv->length;
1212 
1213 		if (curr_tlv_complete_size > bytes_remaining) {
1214 			spectral_err("TLV size %d greater than number of bytes remaining %d",
1215 				     curr_tlv_complete_size, bytes_remaining);
1216 			return -EPERM;
1217 		}
1218 
1219 		if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
1220 			return -EPERM;
1221 
1222 		bytes_processed += curr_tlv_complete_size;
1223 		bytes_remaining = datalen - bytes_processed;
1224 	}
1225 
1226 	return 0;
1227 }
1228 
1229 #ifdef DIRECT_BUF_RX_ENABLE
1230 /**
1231  * target_if_get_spectral_mode() - Get Spectral scan mode corresponding to a
1232  * detector id
1233  * @detector_id: detector id in the Spectral report
1234  * @rparams: pointer to report params object
1235  *
1236  * Helper API to get Spectral scan mode from the detector ID. This mapping is
1237  * target specific.
1238  *
1239  * Return: Spectral scan mode
1240  */
1241 static enum spectral_scan_mode
1242 target_if_get_spectral_mode(enum spectral_detector_id detector_id,
1243 			    struct spectral_report_params *rparams)
1244 {
1245 	if (detector_id >= SPECTRAL_DETECTOR_ID_MAX) {
1246 		spectral_err_rl("Invalid detector id %d", detector_id);
1247 		return SPECTRAL_SCAN_MODE_INVALID;
1248 	}
1249 
1250 	return rparams->detid_mode_table[detector_id];
1251 }
1252 
1253 /**
1254  * target_if_spectral_get_bin_count_after_len_adj() - Get number of FFT bins in
1255  * Spectral FFT report
1256  * @fft_bin_len: FFT bin length reported by target
1257  * @rpt_mode: Spectral report mode
1258  * @swar: Spectral FFT bin length adjustments SWAR parameters
1259  * @fft_bin_size: Size of one FFT bin in bytes
1260  *
1261  * Get actual number of FFT bins in the FFT report after adjusting the length
1262  * by applying the SWARs for getting correct length.
1263  *
1264  * Return: FFT bin count
1265  */
1266 static size_t
1267 target_if_spectral_get_bin_count_after_len_adj(
1268 				size_t fft_bin_len, uint8_t rpt_mode,
1269 				struct spectral_fft_bin_len_adj_swar *swar,
1270 				size_t *fft_bin_size)
1271 {
1272 	size_t fft_bin_count = fft_bin_len;
1273 
1274 	if (rpt_mode == 1 && swar->null_fftbin_adj) {
1275 		/*
1276 		 * No FFT bins are expected. Explicitly set FFT bin
1277 		 * count to 0.
1278 		 */
1279 		fft_bin_count = 0;
1280 		*fft_bin_size = 0;
1281 	} else {
1282 		/*
1283 		 * Divide fft bin length by appropriate factor depending
1284 		 * on the value of fftbin_size_war.
1285 		 */
1286 		switch (swar->fftbin_size_war) {
1287 		case SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE:
1288 			fft_bin_count >>= 2;
1289 			*fft_bin_size = 4;
1290 			break;
1291 		case SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE:
1292 			fft_bin_count >>= 1;
1293 			*fft_bin_size = 2;
1294 			/* Ideally we should be dividing fft bin length
1295 			 * by 2. Due to a HW bug, actual length is two
1296 			 * times the expected length.
1297 			 */
1298 			if (swar->packmode_fftbin_size_adj)
1299 				fft_bin_count >>= 1;
1300 			break;
1301 		case SPECTRAL_FFTBIN_SIZE_NO_WAR:
1302 			*fft_bin_size = 1;
1303 			/* No length adjustment */
1304 			break;
1305 		default:
1306 			qdf_assert_always(0);
1307 		}
1308 
1309 		if (rpt_mode == 2 && swar->inband_fftbin_size_adj)
1310 			fft_bin_count >>= 1;
1311 	}
1312 
1313 	return fft_bin_count;
1314 }
1315 
1316 /**
1317  * target_if_process_sfft_report_gen3() - Process Search FFT Report for gen3
1318  * @p_fft_report: Pointer to fft report
1319  * @p_sfft: Pointer to search fft report
1320  *
1321  * Process Search FFT Report for gen3
1322  *
1323  * Return: Success/Failure
1324  */
1325 static int
1326 target_if_process_sfft_report_gen3(
1327 	struct spectral_phyerr_fft_report_gen3 *p_fft_report,
1328 	struct spectral_search_fft_info_gen3 *p_sfft)
1329 {
1330 	/*
1331 	 * For simplicity, everything is defined as uint32_t (except one).
1332 	 * Proper code will later use the right sizes.
1333 	 */
1334 	/*
1335 	 * For easy comparision between MDK team and OS team, the MDK script
1336 	 * variable names have been used
1337 	 */
1338 	int32_t peak_sidx;
1339 	int32_t peak_mag;
1340 
1341 	/* Populate the Search FFT Info */
1342 	if (p_sfft) {
1343 		p_sfft->timestamp = p_fft_report->fft_timestamp;
1344 
1345 		p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a,
1346 						       2, 0);
1347 		p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2);
1348 		p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
1349 						       12, 5);
1350 
1351 		peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17);
1352 		p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
1353 		p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28);
1354 
1355 		p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
1356 						       9, 0);
1357 		p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
1358 							 8, 9);
1359 
1360 		p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
1361 							   8, 0);
1362 		peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8);
1363 		p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
1364 		p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
1365 						     7, 18);
1366 		p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
1367 						     7, 25);
1368 	}
1369 
1370 	return 0;
1371 }
1372 
1373 /**
1374  * target_if_dump_fft_report_gen3() - Dump FFT Report for gen3
1375  * @spectral: Pointer to Spectral object
1376  * @smode: Spectral scan mode
1377  * @p_fft_report: Pointer to fft report
1378  * @p_sfft: Pointer to search fft report
1379  *
1380  * Dump FFT Report for gen3
1381  *
1382  * Return: void
1383  */
1384 static void
1385 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral,
1386 			enum spectral_scan_mode smode,
1387 			struct spectral_phyerr_fft_report_gen3 *p_fft_report,
1388 			struct spectral_search_fft_info_gen3 *p_sfft)
1389 {
1390 	size_t fft_hdr_length = (p_fft_report->fft_hdr_length * 4);
1391 	size_t report_len = (fft_hdr_length + 8);
1392 	size_t fft_bin_len;
1393 	size_t fft_bin_count;
1394 	size_t fft_bin_size;
1395 	size_t fft_bin_len_inband_tfer = 0;
1396 	uint8_t *fft_bin_buf = NULL;
1397 
1398 	fft_bin_len = fft_hdr_length - spectral->rparams.fft_report_hdr_len;
1399 	fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
1400 			fft_bin_len,
1401 			spectral->params[smode].ss_rpt_mode,
1402 			&spectral->len_adj_swar, &fft_bin_size);
1403 
1404 	if ((spectral->params[smode].ss_rpt_mode == 2) &&
1405 	    spectral->len_adj_swar.inband_fftbin_size_adj)
1406 		fft_bin_len_inband_tfer = fft_bin_len >> 1;
1407 
1408 	spectral_debug("Spectral FFT Report");
1409 	spectral_debug("fft_timestamp = 0x%x", p_fft_report->fft_timestamp);
1410 	spectral_debug("fft_hdr_length = %u(32 bit words)",
1411 		       p_fft_report->fft_hdr_length);
1412 	spectral_debug("fft_hdr_tag = 0x%x", p_fft_report->fft_hdr_tag);
1413 	spectral_debug("fft_hdr_sig = 0x%x", p_fft_report->fft_hdr_sig);
1414 
1415 	spectral_debug("Length field in search fft report is %zu(0x%zx) bytes",
1416 		       fft_hdr_length, fft_hdr_length);
1417 	spectral_debug("Total length of search fft report is %zu(0x%zx) bytes",
1418 		       report_len, report_len);
1419 	spectral_debug("Target reported fftbins in report is %zu(0x%zx)",
1420 		       fft_bin_len, fft_bin_len);
1421 
1422 	if ((spectral->params[smode].ss_rpt_mode == 1) &&
1423 	    spectral->len_adj_swar.null_fftbin_adj)
1424 		spectral_debug("WAR: Considering number of FFT bins as 0");
1425 	else if ((spectral->params[smode].ss_rpt_mode == 2) &&
1426 		 spectral->len_adj_swar.inband_fftbin_size_adj) {
1427 		spectral_debug("FW fftbins actually transferred (in-band report mode) %zu(0x%zx)",
1428 			       fft_bin_len_inband_tfer,
1429 			       fft_bin_len_inband_tfer);
1430 	}
1431 
1432 	spectral_debug("Actual number of fftbins in report is %zu(0x%zx)",
1433 		       fft_bin_count, fft_bin_count);
1434 
1435 	spectral_debug("fft_detector_id = %u", p_sfft->fft_detector_id);
1436 	spectral_debug("fft_num = %u", p_sfft->fft_num);
1437 	spectral_debug("fft_radar_check = %u", p_sfft->fft_radar_check);
1438 	spectral_debug("fft_peak_sidx = %d",  p_sfft->fft_peak_sidx);
1439 	spectral_debug("fft_chn_idx = %u", p_sfft->fft_chn_idx);
1440 	spectral_debug("fft_base_pwr_db = %u", p_sfft->fft_base_pwr_db);
1441 	spectral_debug("fft_total_gain_db = %u", p_sfft->fft_total_gain_db);
1442 	spectral_debug("fft_num_str_bins_ib = %u", p_sfft->fft_num_str_bins_ib);
1443 	spectral_debug("fft_peak_mag = %d", p_sfft->fft_peak_mag);
1444 	spectral_debug("fft_avgpwr_db = %u", p_sfft->fft_avgpwr_db);
1445 	spectral_debug("fft_relpwr_db = %u", p_sfft->fft_relpwr_db);
1446 
1447 	if (fft_bin_count > 0) {
1448 		int idx;
1449 
1450 		spectral_debug("FFT bins:");
1451 		if (spectral->len_adj_swar.fftbin_size_war ==
1452 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) {
1453 			uint32_t *binptr_32 = (uint32_t *)&p_fft_report->buf;
1454 
1455 			fft_bin_buf = (uint8_t *)qdf_mem_malloc(MAX_NUM_BINS);
1456 			if (!fft_bin_buf) {
1457 				spectral_err("Failed to allocate memory");
1458 				return;
1459 			}
1460 			for (idx = 0; idx < fft_bin_count; idx++)
1461 				fft_bin_buf[idx] = *(binptr_32++);
1462 		} else if (spectral->len_adj_swar.fftbin_size_war ==
1463 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) {
1464 			uint16_t *binptr_16 = (uint16_t *)&p_fft_report->buf;
1465 
1466 			fft_bin_buf = (uint8_t *)qdf_mem_malloc(MAX_NUM_BINS);
1467 			if (!fft_bin_buf) {
1468 				spectral_err("Failed to allocate memory");
1469 				return;
1470 			}
1471 			for (idx = 0; idx < fft_bin_count; idx++)
1472 				fft_bin_buf[idx] = *(binptr_16++);
1473 		} else {
1474 			fft_bin_buf = (uint8_t *)&p_fft_report->buf;
1475 		}
1476 		target_if_spectral_hexdump(fft_bin_buf, fft_bin_count);
1477 		if ((spectral->len_adj_swar.fftbin_size_war !=
1478 				SPECTRAL_FFTBIN_SIZE_NO_WAR) && fft_bin_buf)
1479 			qdf_mem_free(fft_bin_buf);
1480 	}
1481 }
1482 #endif
1483 
1484 QDF_STATUS
1485 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
1486 				       enum spectral_scan_mode smode,
1487 				       uint8_t detector_id) {
1488 	QDF_STATUS status = QDF_STATUS_SUCCESS;
1489 
1490 	if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1491 		spectral_err_rl("Invalid Spectral mode %d", smode);
1492 		return QDF_STATUS_E_INVAL;
1493 	}
1494 
1495 	if (!is_ch_width_160_or_80p80(spectral->ch_width[smode])) {
1496 		spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
1497 				spectral->ch_width[smode], smode);
1498 		return QDF_STATUS_E_FAILURE;
1499 	}
1500 
1501 	switch (spectral->state_160mhz_delivery[smode]) {
1502 	case SPECTRAL_REPORT_WAIT_PRIMARY80:
1503 		if (detector_id == SPECTRAL_DETECTOR_ID_0)
1504 			spectral->state_160mhz_delivery[smode] =
1505 				SPECTRAL_REPORT_RX_PRIMARY80;
1506 		else {
1507 			status = QDF_STATUS_E_FAILURE;
1508 			spectral->diag_stats.spectral_vhtseg1id_mismatch++;
1509 		}
1510 		break;
1511 
1512 	case SPECTRAL_REPORT_WAIT_SECONDARY80:
1513 		if (detector_id == SPECTRAL_DETECTOR_ID_1)
1514 			spectral->state_160mhz_delivery[smode] =
1515 				SPECTRAL_REPORT_RX_SECONDARY80;
1516 		else {
1517 			spectral->state_160mhz_delivery[smode] =
1518 				SPECTRAL_REPORT_WAIT_PRIMARY80;
1519 			status = QDF_STATUS_E_FAILURE;
1520 			spectral->diag_stats.spectral_vhtseg2id_mismatch++;
1521 		}
1522 		break;
1523 
1524 	case SPECTRAL_REPORT_RX_SECONDARY80:
1525 		/* We don't care about detector id in this state. */
1526 		reset_160mhz_delivery_state_machine(spectral, smode);
1527 		break;
1528 
1529 	case SPECTRAL_REPORT_RX_PRIMARY80:
1530 		/* We don't care about detector id in this state */
1531 		spectral->state_160mhz_delivery[smode] =
1532 				SPECTRAL_REPORT_WAIT_SECONDARY80;
1533 		break;
1534 
1535 	default:
1536 		break;
1537 	}
1538 
1539 	return status;
1540 }
1541 
1542 #ifdef DIRECT_BUF_RX_ENABLE
1543 /**
1544  * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector
1545  * ID from Spectral summary report
1546  * @data: Pointer to Spectral summary report
1547  *
1548  * Return: Detector ID
1549  */
1550 static uint8_t
1551 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data) {
1552 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
1553 	uint8_t detector_id;
1554 
1555 	qdf_assert_always(data);
1556 
1557 	psscan_summary_report =
1558 		(struct spectral_sscan_summary_report_gen3 *)data;
1559 
1560 	detector_id = get_bitfield(
1561 			psscan_summary_report->hdr_a,
1562 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
1563 			SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
1564 
1565 	return detector_id;
1566 }
1567 
1568 /**
1569  * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
1570  * report
1571  * @data: Pointer to Spectral summary report
1572  * @fields: Pointer to structure to be populated with extracted fields
1573  * @rparams: Pointer to structure with Spectral report params
1574  *
1575  * Consume Spectral summary report for gen3
1576  *
1577  * Return: void
1578  */
1579 static void
1580 target_if_consume_sscan_summary_report_gen3(
1581 				uint8_t *data,
1582 				struct sscan_report_fields_gen3 *fields,
1583 				struct spectral_report_params *rparams) {
1584 	struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
1585 
1586 	qdf_assert_always(data);
1587 	qdf_assert_always(fields);
1588 	qdf_assert_always(rparams);
1589 
1590 	psscan_summary_report =
1591 		(struct spectral_sscan_summary_report_gen3 *)data;
1592 
1593 	fields->sscan_agc_total_gain = get_bitfield(
1594 			psscan_summary_report->hdr_a,
1595 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
1596 			SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
1597 	fields->inband_pwr_db = get_bitfield(
1598 			psscan_summary_report->hdr_a,
1599 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
1600 			SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
1601 	fields->sscan_pri80 = get_bitfield(
1602 			psscan_summary_report->hdr_a,
1603 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
1604 			SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
1605 
1606 	switch (rparams->version) {
1607 	case SPECTRAL_REPORT_FORMAT_VERSION_1:
1608 		fields->sscan_gainchange = get_bitfield(
1609 			psscan_summary_report->hdr_b,
1610 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
1611 			SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
1612 		break;
1613 	case SPECTRAL_REPORT_FORMAT_VERSION_2:
1614 		fields->sscan_gainchange = get_bitfield(
1615 			psscan_summary_report->hdr_c,
1616 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
1617 			SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
1618 		break;
1619 	default:
1620 		qdf_assert_always(0);
1621 	}
1622 }
1623 
1624 /**
1625  * target_if_verify_sig_and_tag_gen3() - Verify tag and signature
1626  *                                       of spectral report
1627  * @spectral: Pointer to spectral object
1628  * @data: Pointer to spectral summary report
1629  * @exp_tag: iexpected tag value
1630  *
1631  * Process fft report for gen3
1632  *
1633  * Return: SUCCESS/FAILURE
1634  */
1635 static int
1636 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral,
1637 				  uint8_t *data, uint8_t exp_tag)
1638 {
1639 	uint8_t tag = 0;
1640 	uint8_t signature = 0;
1641 
1642 	/* Peek into the data to figure out whether
1643 	 *      1) Signature matches the expected value
1644 	 *      2) What is inside the package (TAG ID is used for finding this)
1645 	 */
1646 	tag = *(data + PHYERR_HDR_TAG_POS);
1647 	signature = *(data + PHYERR_HDR_SIG_POS);
1648 
1649 	if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
1650 		spectral->diag_stats.spectral_mismatch++;
1651 		return -EINVAL;
1652 	}
1653 
1654 	if (tag != exp_tag) {
1655 		spectral->diag_stats.spectral_mismatch++;
1656 		return -EINVAL;
1657 	}
1658 
1659 	return 0;
1660 }
1661 
1662 static uint8_t
1663 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)
1664 {
1665 	uint8_t idx;
1666 
1667 	for (idx = 0; idx < DBR_MAX_CHAINS; idx++) {
1668 		if (chainmask & 0x1)
1669 			break;
1670 		chainmask >>= 1;
1671 	}
1672 	return idx;
1673 }
1674 
1675 #ifdef DIRECT_BUF_RX_DEBUG
1676 static void target_if_spectral_check_buffer_poisoning(
1677 	struct target_if_spectral *spectral,
1678 	struct spectral_report *report,
1679 	int num_fft_bins, enum spectral_scan_mode smode)
1680 {
1681 	uint32_t *data;
1682 	size_t len;
1683 	size_t words_to_check =
1684 		sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
1685 	bool poisoned_words_found = false;
1686 
1687 	if (!spectral) {
1688 		spectral_err_rl("Spectral LMAC object is null");
1689 		return;
1690 	}
1691 
1692 	if (!spectral->dbr_buff_debug)
1693 		return;
1694 
1695 	if (!report) {
1696 		spectral_err_rl("Spectral report is null");
1697 		return;
1698 	}
1699 
1700 	/* Add search FFT report */
1701 	if (spectral->params[smode].ss_rpt_mode > 0)
1702 		words_to_check +=
1703 			sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
1704 
1705 	/* Now add the number of FFT bins */
1706 	if (spectral->params[smode].ss_rpt_mode > 1) {
1707 		/* Caller should take care to pass correct number of FFT bins */
1708 		if (spectral->len_adj_swar.fftbin_size_war ==
1709 				SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
1710 			words_to_check += num_fft_bins;
1711 		else if (spectral->len_adj_swar.fftbin_size_war ==
1712 				SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE)
1713 			words_to_check += (num_fft_bins >> 1);
1714 	}
1715 
1716 	data = (uint32_t *)report->data;
1717 	for (len = 0; len < words_to_check; ++len) {
1718 		if (*data == MEM_POISON_SIGNATURE) {
1719 			spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK",
1720 				     MEM_POISON_SIGNATURE,
1721 				     (len << 2), report->data);
1722 			poisoned_words_found = true;
1723 			break;
1724 		}
1725 		++data;
1726 	}
1727 
1728 	/* Crash the FW even if one word is poisoned */
1729 	if (poisoned_words_found) {
1730 		spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows",
1731 			     MEM_POISON_SIGNATURE);
1732 		target_if_spectral_hexdump((unsigned char *)report->data,
1733 					   words_to_check << 2);
1734 		spectral_err("Asserting the FW");
1735 		target_if_spectral_fw_hang(spectral);
1736 	}
1737 }
1738 
1739 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
1740 					 uint8_t *buf, uint32_t current_ts)
1741 {
1742 	if (!spectral) {
1743 		spectral_err_rl("Spectral LMAC object is null");
1744 		return;
1745 	}
1746 
1747 	if (!spectral->dbr_buff_debug)
1748 		return;
1749 
1750 	if (spectral->prev_tstamp) {
1751 		if (current_ts == spectral->prev_tstamp) {
1752 			spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
1753 				     current_ts, buf);
1754 			target_if_spectral_fw_hang(spectral);
1755 		}
1756 	}
1757 	spectral->prev_tstamp = current_ts;
1758 }
1759 #else
1760 static void target_if_spectral_check_buffer_poisoning(
1761 	struct target_if_spectral *spectral,
1762 	struct spectral_report *report,
1763 	int num_fft_bins, enum spectral_scan_mode smode)
1764 {
1765 }
1766 
1767 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
1768 					 uint8_t *buf, uint32_t current_ts)
1769 {
1770 }
1771 #endif
1772 
1773 /**
1774  * target_if_spectral_get_adjusted_timestamp() - Adjust Spectral time
1775  * stamp to account for reset in time stamp due to target reset
1776  * @twar: Spectral time stamp WAR related information
1777  * @raw_timestamp: Spectral time stamp reported by target
1778  * @reset_delay: Reset delay at target
1779  * @smode: Spectral scan mode
1780  *
1781  * Correct time stamp to account for reset in time stamp due to target reset
1782  *
1783  * Return: Adjusted time stamp
1784  */
1785 static uint32_t
1786 target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war *twar,
1787 					  uint32_t raw_timestamp,
1788 					  uint32_t reset_delay,
1789 					  enum spectral_scan_mode smode) {
1790 	qdf_assert_always(smode < SPECTRAL_SCAN_MODE_MAX);
1791 
1792 	if (reset_delay) {
1793 		enum spectral_scan_mode m =
1794 					SPECTRAL_SCAN_MODE_NORMAL;
1795 
1796 		/* Adjust the offset for all the Spectral modes.
1797 		 * Target will be sending the non zero reset delay for
1798 		 * the first Spectral report after reset. This delay is
1799 		 * common for all the Spectral modes.
1800 		 */
1801 		for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
1802 			twar->timestamp_war_offset[m] += (reset_delay +
1803 					twar->last_fft_timestamp[m]);
1804 		twar->target_reset_count++;
1805 	}
1806 	twar->last_fft_timestamp[smode] = raw_timestamp;
1807 
1808 	return raw_timestamp + twar->timestamp_war_offset[smode];
1809 }
1810 
1811 int
1812 target_if_consume_spectral_report_gen3(
1813 	 struct target_if_spectral *spectral,
1814 	 struct spectral_report *report)
1815 {
1816 	/*
1817 	 * XXX : The classifier do not use all the members of the SAMP
1818 	 *       message data format.
1819 	 *       The classifier only depends upon the following parameters
1820 	 *
1821 	 *          1. Frequency (freq, msg->freq)
1822 	 *          2. Spectral RSSI (spectral_rssi,
1823 	 *          msg->samp_data.spectral_rssi)
1824 	 *          3. Bin Power Count (bin_pwr_count,
1825 	 *          msg->samp_data.bin_pwr_count)
1826 	 *          4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
1827 	 *          5. Spectral Timestamp (spectral_tstamp,
1828 	 *          msg->samp_data.spectral_tstamp)
1829 	 *          6. MAC Address (macaddr, msg->macaddr)
1830 	 *
1831 	 *       This function prepares the params structure and populates it
1832 	 *       with
1833 	 *       relevant values, this is in turn passed to
1834 	 *       spectral_create_samp_msg()
1835 	 *       to prepare fully formatted Spectral SAMP message
1836 	 *
1837 	 *       XXX : Need to verify
1838 	 *          1. Order of FFT bin values
1839 	 *
1840 	 */
1841 	struct target_if_samp_msg_params params = {0};
1842 	struct spectral_search_fft_info_gen3 search_fft_info;
1843 	struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
1844 	int8_t chn_idx_lowest_enabled  = 0;
1845 	int fft_hdr_length = 0;
1846 	int report_len = 0;
1847 	size_t fft_bin_count;
1848 	size_t fft_bin_size;
1849 	struct target_if_spectral_ops *p_sops =
1850 		GET_TARGET_IF_SPECTRAL_OPS(spectral);
1851 	struct spectral_phyerr_fft_report_gen3 *p_fft_report;
1852 	int8_t rssi;
1853 	uint8_t *data = report->data;
1854 	struct wlan_objmgr_vdev *vdev;
1855 	uint8_t vdev_rxchainmask;
1856 	struct sscan_report_fields_gen3 sscan_report_fields = {0};
1857 	enum spectral_detector_id detector_id;
1858 	QDF_STATUS ret;
1859 	enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
1860 	uint8_t *temp;
1861 
1862 	/* Process Spectral scan summary report */
1863 	if (target_if_verify_sig_and_tag_gen3(
1864 			spectral, data,
1865 			TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
1866 		spectral_err_rl("Wrong tag/sig in sscan summary");
1867 		goto fail;
1868 	}
1869 
1870 	detector_id = target_if_get_detector_id_sscan_summary_report_gen3(data);
1871 	if (detector_id >= spectral->rparams.num_spectral_detectors) {
1872 		spectral->diag_stats.spectral_invalid_detector_id++;
1873 		spectral_err("Invalid detector id %u, expected is 0/1/2",
1874 			     detector_id);
1875 		goto fail;
1876 	}
1877 
1878 	spectral_mode = target_if_get_spectral_mode(detector_id,
1879 						    &spectral->rparams);
1880 	if (spectral_mode == SPECTRAL_SCAN_MODE_INVALID) {
1881 		spectral_err_rl("No valid Spectral mode for detector id %u",
1882 				detector_id);
1883 		goto fail;
1884 	}
1885 
1886 	target_if_consume_sscan_summary_report_gen3(data, &sscan_report_fields,
1887 						    &spectral->rparams);
1888 	/* Advance buf pointer to the search fft report */
1889 	data += sizeof(struct spectral_sscan_summary_report_gen3);
1890 	data += spectral->rparams.ssumaary_padding_bytes;
1891 	params.vhtop_ch_freq_seg1 = report->cfreq1;
1892 	params.vhtop_ch_freq_seg2 = report->cfreq2;
1893 
1894 	if (is_primaryseg_expected(spectral, spectral_mode)) {
1895 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
1896 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
1897 		params.agc_total_gain =
1898 			sscan_report_fields.sscan_agc_total_gain;
1899 		params.gainchange = sscan_report_fields.sscan_gainchange;
1900 		params.pri80ind = sscan_report_fields.sscan_pri80;
1901 
1902 		/* Process Spectral search FFT report */
1903 		if (target_if_verify_sig_and_tag_gen3(
1904 				spectral, data,
1905 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
1906 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
1907 					detector_id);
1908 			goto fail;
1909 		}
1910 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
1911 		fft_hdr_length = p_fft_report->fft_hdr_length * 4;
1912 		if (fft_hdr_length < 16) {
1913 			spectral_err("Wrong TLV length %u, detector id = %d",
1914 				     fft_hdr_length, detector_id);
1915 			goto fail;
1916 		}
1917 
1918 		report_len = (fft_hdr_length + 8);
1919 
1920 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft);
1921 		/* It is expected to have same detector id for
1922 		 * summary and fft report
1923 		 */
1924 		if (detector_id != p_sfft->fft_detector_id) {
1925 			spectral_err_rl
1926 				("Different detid in ssummary(%u) and sfft(%u)",
1927 				 detector_id, p_sfft->fft_detector_id);
1928 			goto fail;
1929 		}
1930 
1931 		if (detector_id > spectral->rparams.num_spectral_detectors) {
1932 			spectral->diag_stats.spectral_invalid_detector_id++;
1933 			spectral_err("Invalid detector id %u, expected is 0/2",
1934 				     detector_id);
1935 			goto fail;
1936 		}
1937 		params.smode = spectral_mode;
1938 
1939 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
1940 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
1941 			spectral->params[spectral_mode].ss_rpt_mode,
1942 			&spectral->len_adj_swar, &fft_bin_size);
1943 
1944 		params.last_raw_timestamp = spectral->timestamp_war.
1945 				last_fft_timestamp[spectral_mode];
1946 		params.reset_delay = report->reset_delay;
1947 		params.raw_timestamp = p_sfft->timestamp;
1948 		params.tstamp = target_if_spectral_get_adjusted_timestamp(
1949 					&spectral->timestamp_war,
1950 					p_sfft->timestamp, report->reset_delay,
1951 					spectral_mode);
1952 		params.timestamp_war_offset = spectral->timestamp_war.
1953 				timestamp_war_offset[spectral_mode];
1954 		params.target_reset_count = spectral->timestamp_war.
1955 				target_reset_count;
1956 
1957 		/* Take care of state transitions for 160 MHz and 80p80 */
1958 		if (is_ch_width_160_or_80p80(spectral->ch_width
1959 		    [spectral_mode]) && spectral->rparams.
1960 		    fragmentation_160[spectral_mode]) {
1961 			ret = target_if_160mhz_delivery_state_change(
1962 					spectral, spectral_mode,
1963 					detector_id);
1964 			if (ret != QDF_STATUS_SUCCESS)
1965 				goto fail;
1966 		}
1967 
1968 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1969 			target_if_dump_fft_report_gen3(spectral, spectral_mode,
1970 						       p_fft_report, p_sfft);
1971 
1972 		params.rssi         = rssi;
1973 
1974 		vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
1975 		if (!vdev) {
1976 			spectral_info("First vdev is NULL");
1977 			reset_160mhz_delivery_state_machine(
1978 						spectral, spectral_mode);
1979 			return -EPERM;
1980 		}
1981 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
1982 		QDF_ASSERT(vdev_rxchainmask != 0);
1983 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
1984 
1985 		chn_idx_lowest_enabled =
1986 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
1987 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
1988 			spectral_err("Invalid chain index, detector id = %u",
1989 				     detector_id);
1990 			goto fail;
1991 		}
1992 
1993 		params.max_mag  = p_sfft->fft_peak_mag;
1994 
1995 		params.freq = p_sops->get_current_channel(spectral,
1996 							  spectral_mode);
1997 		params.agile_freq1 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
1998 				     ss_frequency.cfreq1;
1999 		params.agile_freq2 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
2000 				     ss_frequency.cfreq2;
2001 		params.noise_floor =
2002 			report->noisefloor[chn_idx_lowest_enabled];
2003 		temp = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
2004 		if (is_ch_width_160_or_80p80(spectral->ch_width
2005 		    [spectral_mode]) && !spectral->rparams.
2006 		    fragmentation_160[spectral_mode]) {
2007 			struct wlan_objmgr_psoc *psoc;
2008 			struct spectral_fft_bin_markers_160_165mhz *marker;
2009 
2010 			qdf_assert_always(spectral->pdev_obj);
2011 			psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
2012 			qdf_assert_always(psoc);
2013 
2014 			params.agc_total_gain_sec80 =
2015 				sscan_report_fields.sscan_agc_total_gain;
2016 			params.gainchange_sec80 =
2017 					sscan_report_fields.sscan_gainchange;
2018 			params.raw_timestamp_sec80 = p_sfft->timestamp;
2019 			params.rssi_sec80 = rssi;
2020 			params.noise_floor_sec80    =
2021 				report->noisefloor[chn_idx_lowest_enabled];
2022 			params.max_mag_sec80        = p_sfft->fft_peak_mag;
2023 			params.datalen = fft_hdr_length * 2;
2024 			params.datalen_sec80 = fft_hdr_length * 2;
2025 
2026 			marker = &spectral->rparams.marker[spectral_mode];
2027 			qdf_assert_always(marker->is_valid);
2028 			params.bin_pwr_data = temp +
2029 				marker->start_pri80 * fft_bin_size;
2030 			params.pwr_count = marker->num_pri80;
2031 			params.bin_pwr_data_sec80 = temp +
2032 				marker->start_sec80 * fft_bin_size;
2033 			params.pwr_count_sec80 = marker->num_sec80;
2034 			if (spectral->ch_width[spectral_mode] ==
2035 			    CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
2036 			    psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
2037 				params.bin_pwr_data_5mhz = temp +
2038 					marker->start_5mhz * fft_bin_size;
2039 				params.pwr_count_5mhz = marker->num_5mhz;
2040 			}
2041 		} else {
2042 			params.bin_pwr_data = temp;
2043 			params.pwr_count = fft_bin_count;
2044 			params.datalen = (fft_hdr_length * 4);
2045 		}
2046 
2047 		target_if_spectral_verify_ts(spectral, report->data,
2048 					     params.tstamp);
2049 	} else if (is_secondaryseg_expected(spectral, spectral_mode)) {
2050 		/* RSSI is in 1/2 dBm steps, Covert it to dBm scale */
2051 		rssi = (sscan_report_fields.inband_pwr_db) >> 1;
2052 		params.agc_total_gain_sec80 =
2053 			sscan_report_fields.sscan_agc_total_gain;
2054 		params.gainchange_sec80 = sscan_report_fields.sscan_gainchange;
2055 		params.pri80ind_sec80 = sscan_report_fields.sscan_pri80;
2056 
2057 		/* Process Spectral search FFT report */
2058 		if (target_if_verify_sig_and_tag_gen3(
2059 				spectral, data,
2060 				TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
2061 			spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
2062 					detector_id);
2063 			goto fail;
2064 		}
2065 		p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
2066 		fft_hdr_length = p_fft_report->fft_hdr_length * 4;
2067 		if (fft_hdr_length < 16) {
2068 			spectral_err("Wrong TLV length %u, detector id = %u",
2069 				     fft_hdr_length, detector_id);
2070 			goto fail;
2071 		}
2072 
2073 		report_len     = (fft_hdr_length + 8);
2074 
2075 		target_if_process_sfft_report_gen3(p_fft_report, p_sfft);
2076 		/* It is expected to have same detector id for
2077 		 * summary and fft report
2078 		 */
2079 		if (detector_id != p_sfft->fft_detector_id) {
2080 			spectral_err_rl
2081 				("Different detid in ssummary(%u) and sfft(%u)",
2082 				 detector_id, p_sfft->fft_detector_id);
2083 			goto fail;
2084 		}
2085 
2086 		if (detector_id > spectral->rparams.num_spectral_detectors) {
2087 			spectral->diag_stats.spectral_invalid_detector_id++;
2088 			spectral_err("Invalid detector id %u, expected is 1",
2089 				     detector_id);
2090 			goto fail;
2091 		}
2092 		params.smode = spectral_mode;
2093 
2094 		fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
2095 			fft_hdr_length - spectral->rparams.fft_report_hdr_len,
2096 			spectral->params[spectral_mode].ss_rpt_mode,
2097 			&spectral->len_adj_swar, &fft_bin_size);
2098 		params.raw_timestamp_sec80 = p_sfft->timestamp;
2099 
2100 		/* Take care of state transitions for 160 MHz and 80p80 */
2101 		if (is_ch_width_160_or_80p80(spectral->ch_width
2102 		    [spectral_mode]) && spectral->rparams.
2103 		    fragmentation_160[spectral_mode]) {
2104 			ret = target_if_160mhz_delivery_state_change(
2105 					spectral, spectral_mode,
2106 					detector_id);
2107 			if (ret != QDF_STATUS_SUCCESS)
2108 				goto fail;
2109 		}
2110 
2111 		if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
2112 			target_if_dump_fft_report_gen3(spectral, spectral_mode,
2113 						       p_fft_report, p_sfft);
2114 
2115 		params.rssi_sec80 = rssi;
2116 
2117 		vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
2118 		if (!vdev) {
2119 			spectral_info("First vdev is NULL");
2120 			reset_160mhz_delivery_state_machine
2121 						(spectral, spectral_mode);
2122 			return -EPERM;
2123 		}
2124 		vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
2125 		QDF_ASSERT(vdev_rxchainmask != 0);
2126 		wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
2127 
2128 		chn_idx_lowest_enabled =
2129 		target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
2130 		if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
2131 			spectral_err("Invalid chain index");
2132 			goto fail;
2133 		}
2134 
2135 		/* Need to change this as per FW team's inputs */
2136 		params.noise_floor_sec80    =
2137 			report->noisefloor[chn_idx_lowest_enabled];
2138 
2139 		params.max_mag_sec80        = p_sfft->fft_peak_mag;
2140 		/* params.max_index_sec80      = p_sfft->peak_inx; */
2141 		/* XXX Does this definition of datalen *still hold? */
2142 		params.datalen_sec80        = fft_hdr_length * 4;
2143 		params.pwr_count_sec80      = fft_bin_count;
2144 		params.bin_pwr_data_sec80   =
2145 			(uint8_t *)((uint8_t *)p_fft_report +
2146 			 SPECTRAL_FFT_BINS_POS);
2147 	} else {
2148 		spectral_err("Spectral state machine in undefined state");
2149 		goto fail;
2150 	}
2151 
2152 	target_if_spectral_check_buffer_poisoning(spectral, report,
2153 						  fft_bin_count, spectral_mode);
2154 	qdf_mem_copy(&params.classifier_params,
2155 		     &spectral->classifier_params,
2156 		     sizeof(struct spectral_classifier_params));
2157 
2158 	target_if_spectral_log_SAMP_param(&params);
2159 	target_if_spectral_create_samp_msg(spectral, &params);
2160 
2161 	return 0;
2162  fail:
2163 	spectral_err_rl("Error while processing Spectral report");
2164 	if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
2165 		reset_160mhz_delivery_state_machine(spectral, spectral_mode);
2166 	return -EPERM;
2167 }
2168 
2169 int target_if_spectral_process_report_gen3(
2170 	struct wlan_objmgr_pdev *pdev,
2171 	void *buf)
2172 {
2173 	int ret = 0;
2174 	struct direct_buf_rx_data *payload = buf;
2175 	struct target_if_spectral *spectral;
2176 	struct spectral_report report;
2177 
2178 	spectral = get_target_if_spectral_handle_from_pdev(pdev);
2179 	if (!spectral) {
2180 		spectral_err("Spectral target object is null");
2181 		return -EINVAL;
2182 	}
2183 
2184 	report.data = payload->vaddr;
2185 	if (payload->meta_data_valid) {
2186 		qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor,
2187 			     qdf_min(sizeof(report.noisefloor),
2188 				     sizeof(payload->meta_data.noisefloor)));
2189 		report.reset_delay = payload->meta_data.reset_delay;
2190 		report.cfreq1 = payload->meta_data.cfreq1;
2191 		report.cfreq2 = payload->meta_data.cfreq2;
2192 		report.ch_width = payload->meta_data.ch_width;
2193 	}
2194 
2195 	if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) {
2196 		spectral_debug("Printing the spectral phyerr buffer for debug");
2197 		spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK",
2198 			       payload->dbr_len,
2199 			       payload->dbr_len,
2200 			       payload->vaddr);
2201 		target_if_spectral_hexdump((unsigned char *)payload->vaddr,
2202 					   1024);
2203 	}
2204 
2205 	ret = target_if_consume_spectral_report_gen3(spectral, &report);
2206 
2207 	if (spectral_debug_level & DEBUG_SPECTRAL4)
2208 		spectral_debug_level = DEBUG_SPECTRAL;
2209 
2210 	return ret;
2211 }
2212 #else
2213 int target_if_spectral_process_report_gen3(
2214 	struct wlan_objmgr_pdev *pdev,
2215 	void *buf)
2216 {
2217 	spectral_err("Direct dma support is not enabled");
2218 	return -EINVAL;
2219 }
2220 #endif
2221 qdf_export_symbol(target_if_spectral_process_report_gen3);
2222 /* END of spectral GEN III HW specific functions */
2223 
2224 #endif  /* WLAN_CONV_SPECTRAL_ENABLE */
2225