1 /*
2 * Copyright (c) 2011,2017-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
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 */
target_if_spectral_hexdump(unsigned char * _buf,int _len)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 if (loc >= sizeof(hexdump_line)) {
89 spectral_err("loc index is %u, greater than hexdump_line array size",
90 loc);
91 return;
92 }
93 loc += snprintf(&hexdump_line[loc],
94 sizeof(hexdump_line) - loc,
95 " %s", ascii);
96 spectral_debug("%s", hexdump_line);
97 qdf_mem_zero(hexdump_line,
98 sizeof(hexdump_line));
99 loc = 0;
100 }
101 }
102
103 if (loc >= sizeof(hexdump_line)) {
104 spectral_err("loc index is %u, greater than hexdump_line array size",
105 loc);
106 return;
107 }
108 loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
109 " %02x", pc[i]);
110
111 if ((pc[i] < 0x20) || (pc[i] > 0x7e))
112 ascii[mod] = '.';
113 else
114 ascii[mod] = pc[i];
115 ascii[(mod) + 1] = '\0';
116 }
117
118 while ((i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) != 0) {
119 if (loc >= sizeof(hexdump_line)) {
120 spectral_err("loc index is %u, greater than hexdump_line array size",
121 loc);
122 return;
123 }
124 loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc,
125 " ");
126 i++;
127 }
128
129 if (loc >= sizeof(hexdump_line)) {
130 spectral_err("loc index is %u, greater than hexdump_line array size",
131 loc);
132 return;
133 }
134 snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, " %s", ascii);
135 spectral_debug("%s", hexdump_line);
136 }
137
138 /**
139 * target_if_print_buf() - Prints given buffer for given length
140 * @pbuf: Pointer to buffer
141 * @len: length
142 *
143 * Prints given buffer for given length
144 *
145 * Return: void
146 */
147 static void
target_if_print_buf(uint8_t * pbuf,int len)148 target_if_print_buf(uint8_t *pbuf, int len)
149 {
150 int i = 0;
151
152 for (i = 0; i < len; i++) {
153 spectral_debug("%02X ", pbuf[i]);
154 if (i % 32 == 31)
155 spectral_debug("\n");
156 }
157 }
158
159 int
target_if_spectral_dump_fft(uint8_t * pfft,int fftlen)160 target_if_spectral_dump_fft(uint8_t *pfft, int fftlen)
161 {
162 int i = 0;
163
164 /*
165 * TODO : Do not delete the following print
166 * The scripts used to validate Spectral depend on this Print
167 */
168 spectral_debug("SPECTRAL : FFT Length is 0x%x (%d)", fftlen, fftlen);
169
170 spectral_debug("fft_data # ");
171 for (i = 0; i < fftlen; i++)
172 spectral_debug("%d ", pfft[i]);
173 spectral_debug("\n");
174 return 0;
175 }
176
target_if_spectral_fw_hang(struct target_if_spectral * spectral)177 QDF_STATUS target_if_spectral_fw_hang(struct target_if_spectral *spectral)
178 {
179 struct crash_inject param;
180 struct wlan_objmgr_pdev *pdev;
181 struct wlan_objmgr_psoc *psoc;
182 struct target_if_psoc_spectral *psoc_spectral;
183
184 if (!spectral) {
185 spectral_err("Spectral LMAC object is null");
186 return QDF_STATUS_E_INVAL;
187 }
188
189 pdev = spectral->pdev_obj;
190 if (!pdev) {
191 spectral_err("pdev is null");
192 return QDF_STATUS_E_FAILURE;
193 }
194
195 psoc = wlan_pdev_get_psoc(pdev);
196 if (!psoc) {
197 spectral_err("psoc is null");
198 return QDF_STATUS_E_FAILURE;
199 }
200
201 psoc_spectral = get_target_if_spectral_handle_from_psoc(psoc);
202 if (!psoc_spectral) {
203 spectral_err("spectral psoc object is null");
204 return QDF_STATUS_E_FAILURE;
205 }
206
207 qdf_mem_set(¶m, sizeof(param), 0);
208 param.type = 1; //RECOVERY_SIM_ASSERT
209
210 return psoc_spectral->wmi_ops.wmi_spectral_crash_inject(
211 GET_WMI_HDL_FROM_PDEV(spectral->pdev_obj), ¶m);
212 }
213
214 #ifdef OPTIMIZED_SAMP_MESSAGE
215 void
target_if_dbg_print_samp_msg(struct spectral_samp_msg * ss_msg)216 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg)
217 {
218 int span, det;
219 struct samp_detector_info *det_info;
220 struct samp_freq_span_info *span_info;
221
222 spectral_dbg_line();
223 spectral_debug("Spectral Message");
224 spectral_dbg_line();
225 spectral_debug("Signature : 0x%x", ss_msg->signature);
226 spectral_debug("Freq : %u", ss_msg->pri20_freq);
227 spectral_debug("sscan width : %d", ss_msg->sscan_bw);
228 spectral_debug("sscan cfreq1 : %u", ss_msg->sscan_cfreq1);
229 spectral_debug("sscan cfreq2 : %u", ss_msg->sscan_cfreq2);
230 spectral_debug("bin power count : %d", ss_msg->bin_pwr_count);
231 spectral_debug("Number of spans : %d", ss_msg->num_freq_spans);
232 spectral_dbg_line();
233 for (span = 0; span < ss_msg->num_freq_spans; span++) {
234 span_info = &ss_msg->freq_span_info[span];
235 spectral_debug("-------- Span ID : %d --------", span);
236 spectral_debug("Number of detectors : %d",
237 span_info->num_detectors);
238 spectral_dbg_line();
239 for (det = 0; det < span_info->num_detectors; det++) {
240 det_info = &span_info->detector_info[det];
241 spectral_debug("------ Detector ID : %d ------", det);
242 spectral_dbg_line();
243 spectral_debug("RSSI : %d", det_info->rssi);
244 spectral_debug("Timestamp : %u",
245 det_info->timestamp);
246 spectral_debug("Start bin index : %d",
247 det_info->start_bin_idx);
248 spectral_debug("End bin index : %d",
249 det_info->end_bin_idx);
250 spectral_debug("Start frequency : %d",
251 det_info->start_frequency);
252 spectral_debug("End frequency : %d",
253 det_info->end_frequency);
254 spectral_dbg_line();
255 }
256 }
257 }
258 #else
259 void
target_if_dbg_print_samp_param(struct target_if_samp_msg_params * p)260 target_if_dbg_print_samp_param(struct target_if_samp_msg_params *p)
261 {
262 spectral_debug("\nSAMP Packet : -------------------- START --------------------");
263 spectral_debug("Freq = %d", p->freq);
264 spectral_debug("RSSI = %d", p->rssi);
265 spectral_debug("Bin Count = %d", p->pwr_count);
266 spectral_debug("Timestamp = %d", p->tstamp);
267 spectral_debug("SAMP Packet : -------------------- END -----------------------");
268 }
269
270 void
target_if_dbg_print_samp_msg(struct spectral_samp_msg * ss_msg)271 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg)
272 {
273 int i = 0;
274
275 struct spectral_samp_data *p = &ss_msg->samp_data;
276 struct spectral_classifier_params *pc = &p->classifier_params;
277 struct interf_src_rsp *pi = &p->interf_list;
278
279 spectral_dbg_line();
280 spectral_debug("Spectral Message");
281 spectral_dbg_line();
282 spectral_debug("Signature : 0x%x", ss_msg->signature);
283 spectral_debug("Freq : %d", ss_msg->freq);
284 spectral_debug("Freq load : %d", ss_msg->freq_loading);
285 spectral_debug("Intfnc type : %d", ss_msg->int_type);
286 spectral_dbg_line();
287 spectral_debug("Spectral Data info");
288 spectral_dbg_line();
289 spectral_debug("data length : %d", p->spectral_data_len);
290 spectral_debug("rssi : %d", p->spectral_rssi);
291 spectral_debug("combined rssi : %d", p->spectral_combined_rssi);
292 spectral_debug("upper rssi : %d", p->spectral_upper_rssi);
293 spectral_debug("lower rssi : %d", p->spectral_lower_rssi);
294 spectral_debug("bw info : %d", p->spectral_bwinfo);
295 spectral_debug("timestamp : %d", p->spectral_tstamp);
296 spectral_debug("max index : %d", p->spectral_max_index);
297 spectral_debug("max exp : %d", p->spectral_max_exp);
298 spectral_debug("max mag : %d", p->spectral_max_mag);
299 spectral_debug("last timstamp : %d", p->spectral_last_tstamp);
300 spectral_debug("upper max idx : %d", p->spectral_upper_max_index);
301 spectral_debug("lower max idx : %d", p->spectral_lower_max_index);
302 spectral_debug("bin power count : %d", p->bin_pwr_count);
303 spectral_dbg_line();
304 spectral_debug("Classifier info");
305 spectral_dbg_line();
306 spectral_debug("20/40 Mode : %d", pc->spectral_20_40_mode);
307 spectral_debug("dc index : %d", pc->spectral_dc_index);
308 spectral_debug("dc in MHz : %d", pc->spectral_dc_in_mhz);
309 spectral_debug("upper channel : %d", pc->upper_chan_in_mhz);
310 spectral_debug("lower channel : %d", pc->lower_chan_in_mhz);
311 spectral_dbg_line();
312 spectral_debug("Interference info");
313 spectral_dbg_line();
314 spectral_debug("inter count : %d", pi->count);
315
316 for (i = 0; i < pi->count; i++) {
317 spectral_debug("inter type : %d",
318 pi->interf[i].interf_type);
319 spectral_debug("min freq : %d",
320 pi->interf[i].interf_min_freq);
321 spectral_debug("max freq : %d",
322 pi->interf[i].interf_max_freq);
323 }
324 }
325 #endif /* OPTIMIZED_SAMP_MESSAGE */
326
327 uint32_t
target_if_get_offset_swar_sec80(uint32_t channel_width)328 target_if_get_offset_swar_sec80(uint32_t channel_width)
329 {
330 uint32_t offset = 0;
331
332 switch (channel_width) {
333 case CH_WIDTH_20MHZ:
334 offset = OFFSET_CH_WIDTH_20;
335 break;
336 case CH_WIDTH_40MHZ:
337 offset = OFFSET_CH_WIDTH_40;
338 break;
339 case CH_WIDTH_80MHZ:
340 offset = OFFSET_CH_WIDTH_80;
341 break;
342 case CH_WIDTH_160MHZ:
343 case CH_WIDTH_80P80MHZ:
344 offset = OFFSET_CH_WIDTH_160;
345 break;
346 default:
347 offset = OFFSET_CH_WIDTH_80;
348 break;
349 }
350 return offset;
351 }
352
353 /**
354 * target_if_dump_summary_report_gen2() - Dump Spectral Summary Report for gen2
355 * @ptlv: Pointer to Spectral Phyerr TLV
356 * @tlvlen: length
357 * @is_160_format: Indicates whether information provided by HW is in altered
358 * format for 802.11ac 160/80+80 MHz support (QCA9984 onwards)
359 *
360 * Dump Spectral Summary Report for gen2
361 *
362 * Return: Success/Failure
363 */
364 static int
target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 * ptlv,int tlvlen,bool is_160_format)365 target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
366 int tlvlen, bool is_160_format)
367 {
368 /*
369 * For simplicity, everything is defined as uint32_t (except one).
370 * Proper code will later use the right sizes.
371 */
372
373 /*
374 * For easy comparison between MDK team and OS team, the MDK script
375 * variable names have been used
376 */
377
378 uint32_t agc_mb_gain;
379 uint32_t sscan_gidx;
380 uint32_t agc_total_gain;
381 uint32_t recent_rfsat;
382 uint32_t ob_flag;
383 uint32_t nb_mask;
384 uint32_t peak_mag;
385 int16_t peak_inx;
386
387 uint32_t ss_summary_A = 0;
388 uint32_t ss_summary_B = 0;
389 uint32_t ss_summary_C = 0;
390 uint32_t ss_summary_D = 0;
391 uint32_t ss_summary_E = 0;
392 struct spectral_phyerr_hdr_gen2 *phdr =
393 (struct spectral_phyerr_hdr_gen2 *)(
394 (uint8_t *)ptlv +
395 sizeof(struct spectral_phyerr_tlv_gen2));
396
397 spectral_debug("SPECTRAL : SPECTRAL SUMMARY REPORT");
398
399 if (is_160_format) {
400 if (tlvlen != 20) {
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 qdf_mem_copy(&ss_summary_C,
413 (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
414 sizeof(int));
415 qdf_mem_copy(&ss_summary_D,
416 (uint8_t *)((uint8_t *)phdr + 3 * sizeof(int)),
417 sizeof(int));
418 qdf_mem_copy(&ss_summary_E,
419 (uint8_t *)((uint8_t *)phdr + 4 * sizeof(int)),
420 sizeof(int));
421
422 /*
423 * The following is adapted from MDK scripts for
424 * easier comparability
425 */
426
427 recent_rfsat = ((ss_summary_A >> 8) & 0x1);
428 sscan_gidx = (ss_summary_A & 0xff);
429 spectral_debug("sscan_gidx=%d, is_recent_rfsat=%d",
430 sscan_gidx, recent_rfsat);
431
432 /* First segment */
433 agc_mb_gain = ((ss_summary_B >> 10) & 0x7f);
434 agc_total_gain = (ss_summary_B & 0x3ff);
435 nb_mask = ((ss_summary_C >> 22) & 0xff);
436 ob_flag = ((ss_summary_B >> 17) & 0x1);
437 peak_inx = (ss_summary_C & 0xfff);
438 if (peak_inx > 2047)
439 peak_inx = peak_inx - 4096;
440 peak_mag = ((ss_summary_C >> 12) & 0x3ff);
441
442 spectral_debug("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d",
443 agc_total_gain, agc_mb_gain);
444 spectral_debug("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, peak_index_segid0=%d, peak_mag_segid0=%d",
445 nb_mask, ob_flag, peak_inx, peak_mag);
446
447 /* Second segment */
448 agc_mb_gain = ((ss_summary_D >> 10) & 0x7f);
449 agc_total_gain = (ss_summary_D & 0x3ff);
450 nb_mask = ((ss_summary_E >> 22) & 0xff);
451 ob_flag = ((ss_summary_D >> 17) & 0x1);
452 peak_inx = (ss_summary_E & 0xfff);
453 if (peak_inx > 2047)
454 peak_inx = peak_inx - 4096;
455 peak_mag = ((ss_summary_E >> 12) & 0x3ff);
456
457 spectral_debug("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d",
458 agc_total_gain, agc_mb_gain);
459 spectral_debug("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, peak_index_segid1=%d, peak_mag_segid1=%d",
460 nb_mask, ob_flag, peak_inx, peak_mag);
461 } else {
462 if (tlvlen != 8) {
463 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
464 tlvlen);
465 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
466 return -EPERM;
467 }
468
469 /* Doing copy as the contents may not be aligned */
470 qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int));
471 qdf_mem_copy(&ss_summary_B,
472 (uint8_t *)((uint8_t *)phdr + sizeof(int)),
473 sizeof(int));
474
475 nb_mask = ((ss_summary_B >> 22) & 0xff);
476 ob_flag = ((ss_summary_B >> 30) & 0x1);
477 peak_inx = (ss_summary_B & 0xfff);
478
479 if (peak_inx > 2047)
480 peak_inx = peak_inx - 4096;
481
482 peak_mag = ((ss_summary_B >> 12) & 0x3ff);
483 agc_mb_gain = ((ss_summary_A >> 24) & 0x7f);
484 agc_total_gain = (ss_summary_A & 0x3ff);
485 sscan_gidx = ((ss_summary_A >> 16) & 0xff);
486 recent_rfsat = ((ss_summary_B >> 31) & 0x1);
487
488 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",
489 nb_mask, ob_flag, peak_inx, peak_mag,
490 agc_mb_gain, agc_total_gain, sscan_gidx,
491 recent_rfsat);
492 }
493
494 return 0;
495 }
496
497 /**
498 * target_if_process_sfft_report_gen2() - Process Search FFT Report
499 * @ptlv: Pointer to Spectral Phyerr TLV
500 * @tlvlen: length
501 * @p_fft_info: Pointer to search fft info
502 *
503 * Dump Spectral Summary Report for gen2
504 *
505 * Return: Success/Failure
506 */
507 static int
target_if_process_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 * ptlv,int tlvlen,struct spectral_search_fft_info_gen2 * p_fft_info)508 target_if_process_sfft_report_gen2(
509 struct spectral_phyerr_tlv_gen2 *ptlv,
510 int tlvlen,
511 struct spectral_search_fft_info_gen2 *p_fft_info)
512 {
513 /*
514 * For simplicity, everything is defined as uint32_t (except one).
515 * Proper code will later use the right sizes.
516 */
517 /*
518 * For easy comparison between MDK team and OS team, the MDK script
519 * variable names have been used
520 */
521 uint32_t relpwr_db;
522 uint32_t num_str_bins_ib;
523 uint32_t base_pwr;
524 uint32_t total_gain_info;
525
526 uint32_t fft_chn_idx;
527 int16_t peak_inx;
528 uint32_t avgpwr_db;
529 uint32_t peak_mag;
530
531 uint32_t fft_summary_A = 0;
532 uint32_t fft_summary_B = 0;
533 uint8_t *tmp = (uint8_t *)ptlv;
534 struct spectral_phyerr_hdr_gen2 *phdr =
535 (struct spectral_phyerr_hdr_gen2 *)(
536 tmp +
537 sizeof(struct spectral_phyerr_tlv_gen2));
538
539 /* Relook this */
540 if (tlvlen < 8) {
541 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
542 tlvlen);
543 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
544 return -EPERM;
545 }
546
547 /* Doing copy as the contents may not be aligned */
548 qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
549 qdf_mem_copy(&fft_summary_B,
550 (uint8_t *)((uint8_t *)phdr + sizeof(int)),
551 sizeof(int));
552
553 relpwr_db = ((fft_summary_B >> 26) & 0x3f);
554 num_str_bins_ib = fft_summary_B & 0xff;
555 base_pwr = ((fft_summary_A >> 14) & 0x1ff);
556 total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
557
558 fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
559 peak_inx = fft_summary_A & 0xfff;
560
561 if (peak_inx > 2047)
562 peak_inx = peak_inx - 4096;
563
564 avgpwr_db = ((fft_summary_B >> 18) & 0xff);
565 peak_mag = ((fft_summary_B >> 8) & 0x3ff);
566
567 /* Populate the Search FFT Info */
568 if (p_fft_info) {
569 p_fft_info->relpwr_db = relpwr_db;
570 p_fft_info->num_str_bins_ib = num_str_bins_ib;
571 p_fft_info->base_pwr = base_pwr;
572 p_fft_info->total_gain_info = total_gain_info;
573 p_fft_info->fft_chn_idx = fft_chn_idx;
574 p_fft_info->peak_inx = peak_inx;
575 p_fft_info->avgpwr_db = avgpwr_db;
576 p_fft_info->peak_mag = peak_mag;
577 }
578
579 return 0;
580 }
581
582 /**
583 * target_if_dump_adc_report_gen2() - Dump ADC Reports for gen2
584 * @ptlv: Pointer to Spectral Phyerr TLV
585 * @tlvlen: length
586 *
587 * Dump ADC Reports for gen2
588 *
589 * Return: Success/Failure
590 */
591 static int
target_if_dump_adc_report_gen2(struct spectral_phyerr_tlv_gen2 * ptlv,int tlvlen)592 target_if_dump_adc_report_gen2(
593 struct spectral_phyerr_tlv_gen2 *ptlv, int tlvlen)
594 {
595 int i;
596 uint32_t *pdata;
597 uint32_t data;
598
599 /*
600 * For simplicity, everything is defined as uint32_t (except one).
601 * Proper code will later use the right sizes.
602 */
603 uint32_t samp_fmt;
604 uint32_t chn_idx;
605 uint32_t recent_rfsat;
606 uint32_t agc_mb_gain;
607 uint32_t agc_total_gain;
608
609 uint32_t adc_summary = 0;
610
611 uint8_t *ptmp = (uint8_t *)ptlv;
612
613 spectral_debug("SPECTRAL : ADC REPORT");
614
615 /* Relook this */
616 if (tlvlen < 4) {
617 spectral_err("Unexpected TLV length %d for ADC Report! Hexdump follows",
618 tlvlen);
619 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
620 return -EPERM;
621 }
622
623 qdf_mem_copy(&adc_summary, (uint8_t *)(ptlv + 4), sizeof(int));
624
625 samp_fmt = ((adc_summary >> 28) & 0x1);
626 chn_idx = ((adc_summary >> 24) & 0x3);
627 recent_rfsat = ((adc_summary >> 23) & 0x1);
628 agc_mb_gain = ((adc_summary >> 16) & 0x7f);
629 agc_total_gain = adc_summary & 0x3ff;
630
631 spectral_debug("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u agc_total_gain=%u",
632 samp_fmt, chn_idx, recent_rfsat, agc_mb_gain,
633 agc_total_gain);
634
635 for (i = 0; i < (tlvlen / 4); i++) {
636 pdata = (uint32_t *)(ptmp + 4 + i * 4);
637 data = *pdata;
638
639 /* Interpreting capture format 1 */
640 if (1) {
641 uint8_t i1;
642 uint8_t q1;
643 uint8_t i2;
644 uint8_t q2;
645 int8_t si1;
646 int8_t sq1;
647 int8_t si2;
648 int8_t sq2;
649
650 i1 = data & 0xff;
651 q1 = (data >> 8) & 0xff;
652 i2 = (data >> 16) & 0xff;
653 q2 = (data >> 24) & 0xff;
654
655 if (i1 > 127)
656 si1 = i1 - 256;
657 else
658 si1 = i1;
659
660 if (q1 > 127)
661 sq1 = q1 - 256;
662 else
663 sq1 = q1;
664
665 if (i2 > 127)
666 si2 = i2 - 256;
667 else
668 si2 = i2;
669
670 if (q2 > 127)
671 sq2 = q2 - 256;
672 else
673 sq2 = q2;
674
675 spectral_debug("SPECTRAL ADC : Interpreting capture format 1");
676 spectral_debug("adc_data_format_1 # %d %d %d",
677 2 * i, si1, sq1);
678 spectral_debug("adc_data_format_1 # %d %d %d",
679 2 * i + 1, si2, sq2);
680 }
681
682 /* Interpreting capture format 0 */
683 if (1) {
684 uint16_t i1;
685 uint16_t q1;
686 int16_t si1;
687 int16_t sq1;
688
689 i1 = data & 0xffff;
690 q1 = (data >> 16) & 0xffff;
691 if (i1 > 32767)
692 si1 = i1 - 65536;
693 else
694 si1 = i1;
695
696 if (q1 > 32767)
697 sq1 = q1 - 65536;
698 else
699 sq1 = q1;
700 spectral_debug("SPECTRAL ADC : Interpreting capture format 0");
701 spectral_debug("adc_data_format_2 # %d %d %d",
702 i, si1, sq1);
703 }
704 }
705
706 spectral_debug("\n");
707
708 return 0;
709 }
710
711 /**
712 * target_if_dump_sfft_report_gen2() - Process Search FFT Report for gen2
713 * @ptlv: Pointer to Spectral Phyerr TLV
714 * @tlvlen: length
715 * @is_160_format: Indicates 160 format
716 *
717 * Process Search FFT Report for gen2
718 *
719 * Return: Success/Failure
720 */
721 static int
target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 * ptlv,int tlvlen,bool is_160_format)722 target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv,
723 int tlvlen, bool is_160_format)
724 {
725 int i;
726 uint32_t fft_mag;
727
728 /*
729 * For simplicity, everything is defined as uint32_t (except one).
730 * Proper code will later use the right sizes.
731 */
732 /*
733 * For easy comparison between MDK team and OS team, the MDK script
734 * variable names have been used
735 */
736 uint32_t relpwr_db;
737 uint32_t num_str_bins_ib;
738 uint32_t base_pwr;
739 uint32_t total_gain_info;
740
741 uint32_t fft_chn_idx;
742 int16_t peak_inx;
743 uint32_t avgpwr_db;
744 uint32_t peak_mag;
745 uint8_t segid;
746
747 uint32_t fft_summary_A = 0;
748 uint32_t fft_summary_B = 0;
749 uint32_t fft_summary_C = 0;
750 uint8_t *tmp = (uint8_t *)ptlv;
751 struct spectral_phyerr_hdr_gen2 *phdr =
752 (struct spectral_phyerr_hdr_gen2 *)(
753 tmp +
754 sizeof(struct spectral_phyerr_tlv_gen2));
755 uint32_t segid_skiplen = 0;
756
757 if (is_160_format)
758 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
759
760 spectral_debug("SPECTRAL : SEARCH FFT REPORT");
761
762 /* Relook this */
763 if (tlvlen < (8 + segid_skiplen)) {
764 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows",
765 tlvlen);
766 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4);
767 return -EPERM;
768 }
769
770 /* Doing copy as the contents may not be aligned */
771 qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int));
772 qdf_mem_copy(&fft_summary_B,
773 (uint8_t *)((uint8_t *)phdr + sizeof(int)),
774 sizeof(int));
775 if (is_160_format)
776 qdf_mem_copy(&fft_summary_C,
777 (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)),
778 sizeof(int));
779
780 relpwr_db = ((fft_summary_B >> 26) & 0x3f);
781 num_str_bins_ib = fft_summary_B & 0xff;
782 base_pwr = ((fft_summary_A >> 14) & 0x1ff);
783 total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
784
785 fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
786 peak_inx = fft_summary_A & 0xfff;
787
788 if (peak_inx > 2047)
789 peak_inx = peak_inx - 4096;
790
791 avgpwr_db = ((fft_summary_B >> 18) & 0xff);
792 peak_mag = ((fft_summary_B >> 8) & 0x3ff);
793
794 spectral_debug("Header A = 0x%x Header B = 0x%x",
795 phdr->hdr_a, phdr->hdr_b);
796 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",
797 base_pwr, total_gain_info, relpwr_db, num_str_bins_ib,
798 fft_chn_idx, peak_inx, avgpwr_db, peak_mag);
799 if (is_160_format) {
800 segid = fft_summary_C & 0x1;
801 spectral_debug("Segment ID: %hhu", segid);
802 }
803
804 spectral_debug("FFT bins:");
805 for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) {
806 fft_mag = ((uint8_t *)ptlv)[12 + segid_skiplen + i];
807 spectral_debug("%d %d, ", i, fft_mag);
808 }
809
810 spectral_debug("\n");
811
812 return 0;
813 }
814
815 #ifndef OPTIMIZED_SAMP_MESSAGE
816 #ifdef SPECTRAL_DEBUG_SAMP_MSG
817 /**
818 * target_if_spectral_log_SAMP_param() - Log SAMP parameters
819 * @params: Reference to target_if_samp_msg_params
820 *
821 * API to log spectral SAMP message parameters
822 *
823 * Return: None
824 */
825 static void
target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params * params)826 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
827 {
828 target_if_dbg_print_samp_param(params);
829 }
830
831 #else
832 static void
target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params * params)833 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params)
834 {
835 }
836 #endif
837 #endif /* OPTIMIZED_SAMP_MESSAGE */
838
839 #ifdef OPTIMIZED_SAMP_MESSAGE
840 /**
841 * target_if_spectral_unify_cfreq_format() - Unify the cfreq representations.
842 * @spectral: Pointer to target_if spectral internal structure
843 * @cfreq1: cfreq1 value received in the Spectral report
844 * @cfreq2: cfreq2 value received in the Spectral report
845 * @pri20_freq: Primary 20MHz frequency of operation
846 * @ch_width: channel width. If the center frequencies are of operating channel,
847 * pass the operating channel width, else pass the sscan channel width.
848 * @smode: Spectral scan mode
849 *
850 * This API converts the cfreq1 and cfreq2 representations as follows.
851 * For a contiguous channel, cfreq1 will represent the center of the entire
852 * span and cfreq2 will be 0. For a discontiguous channel like 80p80, cfreq1
853 * will represent the center of primary segment whereas cfreq2 will
854 * represent the center of secondary segment.
855 *
856 * Return: Success/Failure
857 */
858 static QDF_STATUS
target_if_spectral_unify_cfreq_format(struct target_if_spectral * spectral,uint32_t * cfreq1,uint32_t * cfreq2,uint32_t pri20_freq,enum phy_ch_width ch_width,enum spectral_scan_mode smode)859 target_if_spectral_unify_cfreq_format(struct target_if_spectral *spectral,
860 uint32_t *cfreq1, uint32_t *cfreq2,
861 uint32_t pri20_freq,
862 enum phy_ch_width ch_width,
863 enum spectral_scan_mode smode)
864
865 {
866 uint32_t reported_cfreq1, reported_cfreq2;
867 struct wlan_objmgr_psoc *psoc;
868
869 if (!spectral) {
870 spectral_err_rl("Spectral LMAC object is null");
871 return QDF_STATUS_E_NULL_VALUE;
872 }
873 if (!spectral->pdev_obj) {
874 spectral_err_rl("Spectral PDEV is null");
875 return QDF_STATUS_E_NULL_VALUE;
876 }
877
878 psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
879 if (!psoc) {
880 spectral_err_rl("psoc is null");
881 return QDF_STATUS_E_NULL_VALUE;
882 }
883
884 reported_cfreq1 = *cfreq1;
885 reported_cfreq2 = *cfreq2;
886
887 if (ch_width == CH_WIDTH_160MHZ &&
888 spectral->rparams.fragmentation_160[smode]) {
889 /* cfreq should be 0 for 160MHz as it is contiguous */
890 *cfreq2 = 0;
891
892 /**
893 * For gen3 chipsets that use fragmentation, cfreq1 is center of
894 * pri80, and cfreq2 is center of sec80. Averaging them gives
895 * the center of the 160MHz span.
896 * Whereas gen2 chipsets report the center of the 160MHz span in
897 * cfreq2 itself.
898 */
899 if (spectral->spectral_gen == SPECTRAL_GEN3)
900 *cfreq1 = (reported_cfreq1 + reported_cfreq2) >> 1;
901 else
902 *cfreq1 = reported_cfreq2;
903 } else if (ch_width == CH_WIDTH_80P80MHZ &&
904 wlan_psoc_nif_fw_ext_cap_get(
905 psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
906 /* In restricted 80p80 case */
907 const struct bonded_channel_freq
908 *bonded_chan_ptr = NULL;
909 enum channel_state state;
910
911 /* Get the 80MHz channel containing the pri20 freq */
912 state =
913 wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode
914 (spectral->pdev_obj, pri20_freq, CH_WIDTH_80MHZ,
915 &bonded_chan_ptr, REG_CURRENT_PWR_MODE,
916 NO_SCHANS_PUNC);
917
918 if (state == CHANNEL_STATE_DISABLE ||
919 state == CHANNEL_STATE_INVALID) {
920 spectral_err_rl("Channel state is disable or invalid");
921 return QDF_STATUS_E_FAILURE;
922 }
923
924 if (!bonded_chan_ptr) {
925 spectral_err_rl("Bonded channel is not found");
926 return QDF_STATUS_E_FAILURE;
927 }
928
929 /* cfreq1 is the center of the pri80 segment */
930 *cfreq1 = (bonded_chan_ptr->start_freq +
931 bonded_chan_ptr->end_freq) >> 1;
932
933 /**
934 * cfreq2 is 85MHz away from cfreq1. Whether it is
935 * higher or lower depends on pri20_freq's relationship
936 * with the reported center frequency.
937 */
938 if (pri20_freq < reported_cfreq1)
939 *cfreq2 = *cfreq1 + FREQ_OFFSET_85MHZ;
940 else
941 *cfreq2 = *cfreq1 - FREQ_OFFSET_85MHZ;
942 } else {
943 /* All other cases are reporting the cfreq properly */
944 *cfreq1 = reported_cfreq1;
945 *cfreq2 = reported_cfreq2;
946 }
947
948 return QDF_STATUS_SUCCESS;
949 }
950
951 /**
952 * target_if_populate_det_start_end_freqs() - Populate the start and end
953 * frequencies, on per-detector level.
954 * @spectral: Pointer to target_if spectral internal structure
955 * @smode: Spectral scan mode
956 *
957 * Populate the start and end frequencies, on per-detector level.
958 *
959 * Return: Success/Failure
960 */
961 static QDF_STATUS
target_if_populate_det_start_end_freqs(struct target_if_spectral * spectral,enum spectral_scan_mode smode)962 target_if_populate_det_start_end_freqs(struct target_if_spectral *spectral,
963 enum spectral_scan_mode smode)
964 {
965 struct per_session_report_info *rpt_info;
966 struct per_session_det_map *det_map;
967 struct per_session_dest_det_info *dest_det_info;
968 enum phy_ch_width ch_width;
969 struct sscan_detector_list *detector_list;
970 bool is_fragmentation_160;
971 uint8_t det;
972 uint32_t cfreq;
973 uint32_t start_end_freq_arr[2];
974
975 if (!spectral) {
976 spectral_err_rl("Spectral LMAC object is null");
977 return QDF_STATUS_E_NULL_VALUE;
978 }
979 if (smode >= SPECTRAL_SCAN_MODE_MAX) {
980 spectral_err_rl("Invalid Spectral mode");
981 return QDF_STATUS_E_FAILURE;
982 }
983
984 qdf_spin_lock_bh(&spectral->session_report_info_lock);
985
986 ch_width = spectral->report_info[smode].sscan_bw;
987 is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
988
989 rpt_info = &spectral->report_info[smode];
990
991 qdf_spin_lock_bh(&spectral->detector_list_lock);
992 detector_list = &spectral->detector_list[smode][ch_width];
993
994 for (det = 0; det < detector_list->num_detectors; det++) {
995 qdf_spin_lock_bh(&spectral->session_det_map_lock);
996 det_map = &spectral->det_map
997 [detector_list->detectors[det]];
998 dest_det_info = &det_map->dest_det_info[0];
999
1000 switch (det) {
1001 case 0:
1002 if (ch_width == CH_WIDTH_160MHZ &&
1003 is_fragmentation_160) {
1004 if (rpt_info->pri20_freq <
1005 rpt_info->sscan_cfreq1)
1006 cfreq = rpt_info->sscan_cfreq1 -
1007 FREQ_OFFSET_40MHZ;
1008 else
1009 cfreq = rpt_info->sscan_cfreq1 +
1010 FREQ_OFFSET_40MHZ;
1011 } else
1012 cfreq = rpt_info->sscan_cfreq1;
1013 break;
1014
1015 case 1:
1016 if (ch_width == CH_WIDTH_160MHZ &&
1017 is_fragmentation_160) {
1018 if (rpt_info->pri20_freq <
1019 rpt_info->sscan_cfreq1)
1020 cfreq = rpt_info->sscan_cfreq1 +
1021 FREQ_OFFSET_40MHZ;
1022 else
1023 cfreq = rpt_info->sscan_cfreq1 -
1024 FREQ_OFFSET_40MHZ;
1025 } else
1026 cfreq = rpt_info->sscan_cfreq2;
1027 break;
1028
1029 default:
1030 qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1031 qdf_spin_unlock_bh(&spectral->detector_list_lock);
1032 qdf_spin_unlock_bh(
1033 &spectral->session_report_info_lock);
1034
1035 return QDF_STATUS_E_FAILURE;
1036 }
1037
1038 /* Set start and end frequencies */
1039 target_if_spectral_set_start_end_freq(cfreq,
1040 ch_width,
1041 is_fragmentation_160,
1042 start_end_freq_arr);
1043 dest_det_info->start_freq = start_end_freq_arr[0];
1044 dest_det_info->end_freq = start_end_freq_arr[1];
1045
1046 qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1047 }
1048
1049 qdf_spin_unlock_bh(&spectral->detector_list_lock);
1050 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1051
1052 return QDF_STATUS_SUCCESS;
1053 }
1054
1055 QDF_STATUS
target_if_populate_fft_bins_info(struct target_if_spectral * spectral,enum spectral_scan_mode smode)1056 target_if_populate_fft_bins_info(struct target_if_spectral *spectral,
1057 enum spectral_scan_mode smode)
1058 {
1059 struct per_session_det_map *det_map;
1060 struct per_session_dest_det_info *dest_det_info;
1061 enum phy_ch_width ch_width;
1062 struct sscan_detector_list *detector_list;
1063 bool is_fragmentation_160;
1064 uint8_t spectral_fft_size;
1065 uint8_t rpt_mode;
1066 uint32_t num_fft_bins;
1067 uint16_t start_bin;
1068 uint8_t det;
1069
1070 if (!spectral) {
1071 spectral_err_rl("Spectral LMAC object is null");
1072 return QDF_STATUS_E_NULL_VALUE;
1073 }
1074 if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1075 spectral_err_rl("Invalid Spectral mode");
1076 return QDF_STATUS_E_FAILURE;
1077 }
1078
1079 qdf_spin_lock_bh(&spectral->session_report_info_lock);
1080
1081 ch_width = spectral->report_info[smode].sscan_bw;
1082 is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
1083 spectral_fft_size = spectral->params[smode].ss_fft_size;
1084 rpt_mode = spectral->params[smode].ss_rpt_mode;
1085 num_fft_bins =
1086 target_if_spectral_get_num_fft_bins(spectral_fft_size,
1087 rpt_mode);
1088 if (num_fft_bins < 0) {
1089 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1090 spectral_err_rl("Invalid number of FFT bins %d",
1091 num_fft_bins);
1092 return QDF_STATUS_E_FAILURE;
1093 }
1094
1095 qdf_spin_lock_bh(&spectral->detector_list_lock);
1096 detector_list = &spectral->detector_list[smode][ch_width];
1097
1098 for (det = 0; det < detector_list->num_detectors; det++) {
1099 uint16_t lb_extrabins_offset = 0;
1100
1101 qdf_spin_lock_bh(&spectral->session_det_map_lock);
1102 det_map = &spectral->det_map
1103 [detector_list->detectors[det]];
1104 dest_det_info = &det_map->dest_det_info[0];
1105 dest_det_info->lb_extrabins_num = spectral->lb_edge_extrabins;
1106 dest_det_info->rb_extrabins_num = spectral->rb_edge_extrabins;
1107 switch (det) {
1108 case 0:
1109 if (ch_width == CH_WIDTH_160MHZ &&
1110 is_fragmentation_160 &&
1111 spectral->report_info[smode].pri20_freq >
1112 spectral->report_info[smode].sscan_cfreq1) {
1113 start_bin = num_fft_bins;
1114 lb_extrabins_offset =
1115 dest_det_info->lb_extrabins_num +
1116 dest_det_info->rb_extrabins_num;
1117 } else {
1118 start_bin = 0;
1119 }
1120 break;
1121 case 1:
1122 if (ch_width == CH_WIDTH_160MHZ &&
1123 is_fragmentation_160 &&
1124 spectral->report_info[smode].pri20_freq >
1125 spectral->report_info[smode].sscan_cfreq1)
1126 start_bin = 0;
1127 else {
1128 start_bin = num_fft_bins;
1129 lb_extrabins_offset =
1130 dest_det_info->lb_extrabins_num +
1131 dest_det_info->rb_extrabins_num;
1132 }
1133 break;
1134 default:
1135 qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1136 qdf_spin_unlock_bh(&spectral->detector_list_lock);
1137 qdf_spin_unlock_bh(
1138 &spectral->session_report_info_lock);
1139
1140 return QDF_STATUS_E_FAILURE;
1141 }
1142 dest_det_info->dest_start_bin_idx = start_bin;
1143 dest_det_info->dest_end_bin_idx =
1144 dest_det_info->dest_start_bin_idx;
1145 if (num_fft_bins > 0)
1146 dest_det_info->dest_end_bin_idx += (num_fft_bins - 1);
1147
1148 if (dest_det_info->lb_extrabins_num) {
1149 if (is_ch_width_160_or_80p80(ch_width)) {
1150 dest_det_info->lb_extrabins_start_idx =
1151 2 * num_fft_bins +
1152 lb_extrabins_offset;
1153 } else {
1154 dest_det_info->lb_extrabins_start_idx =
1155 num_fft_bins;
1156 }
1157 }
1158 if (dest_det_info->rb_extrabins_num)
1159 dest_det_info->rb_extrabins_start_idx =
1160 dest_det_info->lb_extrabins_start_idx +
1161 dest_det_info->lb_extrabins_num;
1162 dest_det_info->src_start_bin_idx = 0;
1163 qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1164 }
1165 qdf_spin_unlock_bh(&spectral->detector_list_lock);
1166 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1167
1168 return QDF_STATUS_SUCCESS;
1169 }
1170
1171 /**
1172 * target_if_update_session_info_from_report_ctx() - Update per-session
1173 * information from the consume report context. This includes populating start
1174 * and end bin indices, and set the start and end frequency per-detector.
1175 * @spectral: Pointer to target_if spectral internal structure
1176 * @fft_bin_size: Size of 1 FFT bin (in bytes)
1177 * @cfreq1: Center frequency of Detector 1
1178 * @cfreq2: Center frequency of Detector 2
1179 * @smode: Spectral scan mode
1180 *
1181 * Update per-session information from the consume report context.
1182 *
1183 * Return: Success/Failure
1184 */
1185 static QDF_STATUS
target_if_update_session_info_from_report_ctx(struct target_if_spectral * spectral,uint8_t fft_bin_size,uint32_t cfreq1,uint32_t cfreq2,enum spectral_scan_mode smode)1186 target_if_update_session_info_from_report_ctx(
1187 struct target_if_spectral *spectral,
1188 uint8_t fft_bin_size,
1189 uint32_t cfreq1, uint32_t cfreq2,
1190 enum spectral_scan_mode smode)
1191 {
1192 struct target_if_spectral_ops *p_sops;
1193 struct per_session_report_info *rpt_info;
1194 struct per_session_det_map *det_map;
1195 struct per_session_dest_det_info *dest_det_info;
1196 enum phy_ch_width ch_width;
1197 struct wlan_objmgr_psoc *psoc;
1198 bool is_fragmentation_160;
1199 uint32_t start_end_freq_arr[2];
1200 QDF_STATUS ret;
1201 bool is_session_info_expected;
1202
1203 if (!spectral) {
1204 spectral_err_rl("Spectral LMAC object is null");
1205 return QDF_STATUS_E_NULL_VALUE;
1206 }
1207
1208 ret = spectral_is_session_info_expected_from_target(
1209 spectral->pdev_obj,
1210 &is_session_info_expected);
1211 if (QDF_IS_STATUS_ERROR(ret)) {
1212 spectral_err_rl("Failed to check if session info is expected");
1213 return ret;
1214 }
1215
1216 /* If FW sends this information, use it, no need to get it from here */
1217 if (is_session_info_expected)
1218 return QDF_STATUS_SUCCESS;
1219
1220 if (smode >= SPECTRAL_SCAN_MODE_MAX) {
1221 spectral_err_rl("Invalid Spectral mode");
1222 return QDF_STATUS_E_FAILURE;
1223 }
1224 if (!spectral->pdev_obj) {
1225 spectral_err_rl("Spectral PDEV is null");
1226 return QDF_STATUS_E_NULL_VALUE;
1227 }
1228
1229 psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
1230 if (!psoc) {
1231 spectral_err_rl("psoc is null");
1232 return QDF_STATUS_E_NULL_VALUE;
1233 }
1234
1235 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1236
1237 qdf_spin_lock_bh(&spectral->session_report_info_lock);
1238
1239 rpt_info = &spectral->report_info[smode];
1240 ch_width = rpt_info->sscan_bw;
1241 is_fragmentation_160 = spectral->rparams.fragmentation_160[smode];
1242
1243 rpt_info->pri20_freq = p_sops->get_current_channel(spectral, smode);
1244 rpt_info->cfreq1 = cfreq1;
1245 rpt_info->cfreq2 = cfreq2;
1246
1247 if (spectral_debug_level & DEBUG_SPECTRAL4)
1248 spectral_debug("Before conversion: cfreq1: %u cfreq2: %u",
1249 rpt_info->cfreq1, rpt_info->cfreq2);
1250
1251 ret = target_if_spectral_unify_cfreq_format(
1252 spectral, &rpt_info->cfreq1, &rpt_info->cfreq2,
1253 rpt_info->pri20_freq, rpt_info->operating_bw, smode);
1254
1255 if (QDF_IS_STATUS_ERROR(ret)) {
1256 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1257 spectral_err_rl("Unable to unify cfreq1/cfreq2");
1258 return QDF_STATUS_E_FAILURE;
1259 }
1260
1261 if (spectral_debug_level & DEBUG_SPECTRAL4)
1262 spectral_debug("After conversion: cfreq1: %d cfreq2: %d",
1263 rpt_info->cfreq1, rpt_info->cfreq2);
1264
1265 /* For Agile mode, sscan_cfreq1 and sscan_cfreq2 are populated
1266 * during Spectral start scan
1267 */
1268 if (smode == SPECTRAL_SCAN_MODE_NORMAL) {
1269 rpt_info->sscan_cfreq1 = rpt_info->cfreq1;
1270 rpt_info->sscan_cfreq2 = rpt_info->cfreq2;
1271 }
1272 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1273
1274 if (ch_width == CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
1275 psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
1276 /* Restricted 80p80 */
1277 struct spectral_fft_bin_markers_160_165mhz *marker;
1278 struct sscan_detector_list *detector_list;
1279
1280 marker = &spectral->rparams.marker[smode];
1281 if (!marker->is_valid)
1282 return QDF_STATUS_E_FAILURE;
1283
1284 /**
1285 * Restricted 80p80 on Pine has only 1 detector for
1286 * normal/agile spectral scan. So, detector_list will
1287 * have only one detector
1288 */
1289 qdf_spin_lock_bh(&spectral->detector_list_lock);
1290 detector_list = &spectral->detector_list[smode][ch_width];
1291
1292 qdf_spin_lock_bh(&spectral->session_det_map_lock);
1293 det_map = &spectral->det_map[detector_list->detectors[0]];
1294
1295 dest_det_info = &det_map->dest_det_info[0];
1296 dest_det_info->dest_start_bin_idx = marker->start_pri80;
1297 dest_det_info->dest_end_bin_idx =
1298 dest_det_info->dest_start_bin_idx +
1299 marker->num_pri80 - 1;
1300 dest_det_info->src_start_bin_idx = marker->start_pri80 *
1301 fft_bin_size;
1302 /* Set start and end frequencies */
1303 qdf_spin_lock_bh(&spectral->session_report_info_lock);
1304 target_if_spectral_set_start_end_freq(rpt_info->sscan_cfreq1,
1305 ch_width,
1306 is_fragmentation_160,
1307 start_end_freq_arr);
1308 dest_det_info->start_freq = start_end_freq_arr[0];
1309 dest_det_info->end_freq = start_end_freq_arr[1];
1310
1311
1312 dest_det_info = &det_map->dest_det_info[1];
1313 dest_det_info->dest_start_bin_idx = marker->start_sec80;
1314 dest_det_info->dest_end_bin_idx =
1315 dest_det_info->dest_start_bin_idx +
1316 marker->num_sec80 - 1;
1317 dest_det_info->src_start_bin_idx = marker->start_sec80 *
1318 fft_bin_size;
1319 /* Set start and end frequencies */
1320 target_if_spectral_set_start_end_freq(rpt_info->sscan_cfreq2,
1321 ch_width,
1322 is_fragmentation_160,
1323 start_end_freq_arr);
1324 dest_det_info->start_freq = start_end_freq_arr[0];
1325 dest_det_info->end_freq = start_end_freq_arr[1];
1326
1327 dest_det_info = &det_map->dest_det_info[2];
1328 dest_det_info->dest_start_bin_idx = marker->start_5mhz;
1329 dest_det_info->dest_end_bin_idx =
1330 dest_det_info->dest_start_bin_idx +
1331 marker->num_5mhz - 1;
1332 dest_det_info->src_start_bin_idx = marker->start_5mhz *
1333 fft_bin_size;
1334 /* Set start and end frequencies */
1335 dest_det_info->start_freq =
1336 min(det_map->dest_det_info[0].end_freq,
1337 det_map->dest_det_info[1].end_freq);
1338 dest_det_info->end_freq =
1339 max(det_map->dest_det_info[0].start_freq,
1340 det_map->dest_det_info[1].start_freq);
1341
1342 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1343 qdf_spin_unlock_bh(&spectral->session_det_map_lock);
1344 qdf_spin_unlock_bh(&spectral->detector_list_lock);
1345 } else {
1346 ret = target_if_populate_fft_bins_info(spectral, smode);
1347 if (QDF_IS_STATUS_ERROR(ret)) {
1348 spectral_err_rl("Error in populating fft bins info");
1349 return QDF_STATUS_E_FAILURE;
1350 }
1351
1352 ret = target_if_populate_det_start_end_freqs(spectral, smode);
1353 if (QDF_IS_STATUS_ERROR(ret)) {
1354 spectral_err_rl("Failed to populate start/end freqs");
1355 return QDF_STATUS_E_FAILURE;
1356 }
1357 }
1358
1359 return QDF_STATUS_SUCCESS;
1360 }
1361 #endif /* OPTIMIZED_SAMP_MESSAGE */
1362
1363 #ifdef OPTIMIZED_SAMP_MESSAGE
1364 /**
1365 * target_if_spectral_populate_samp_params_gen2() - Populate the SAMP params
1366 * for gen2. SAMP params are to be used for populating SAMP msg.
1367 * @spectral: Pointer to spectral object
1368 * @phyerr_info: Pointer to processed phyerr info
1369 * @params: Pointer to Spectral SAMP message fields to be populated
1370 *
1371 * Populate the SAMP params for gen2, which will be used to populate SAMP msg.
1372 *
1373 * Return: Success/Failure
1374 */
1375 static QDF_STATUS
target_if_spectral_populate_samp_params_gen2(struct target_if_spectral * spectral,struct spectral_process_phyerr_info_gen2 * phyerr_info,struct target_if_samp_msg_params * params)1376 target_if_spectral_populate_samp_params_gen2(
1377 struct target_if_spectral *spectral,
1378 struct spectral_process_phyerr_info_gen2 *phyerr_info,
1379 struct target_if_samp_msg_params *params)
1380 {
1381 uint8_t chn_idx_highest_enabled;
1382 uint8_t chn_idx_lowest_enabled;
1383 int8_t control_rssi;
1384 int8_t extension_rssi;
1385 struct target_if_spectral_rfqual_info *p_rfqual;
1386 struct spectral_search_fft_info_gen2 *p_sfft;
1387 struct spectral_phyerr_fft_gen2 *pfft;
1388 struct target_if_spectral_acs_stats *acs_stats;
1389 enum phy_ch_width ch_width;
1390 enum spectral_scan_mode smode = SPECTRAL_SCAN_MODE_NORMAL;
1391
1392 if (!spectral) {
1393 spectral_err_rl("Spectral LMAC object is null");
1394 return QDF_STATUS_E_NULL_VALUE;
1395 }
1396 if (!phyerr_info) {
1397 spectral_err_rl("Pointer to phyerr info is null");
1398 return QDF_STATUS_E_NULL_VALUE;
1399 }
1400 if (!params) {
1401 spectral_err_rl("SAMP msg params structure is null");
1402 return QDF_STATUS_E_NULL_VALUE;
1403 }
1404
1405 qdf_spin_lock_bh(&spectral->session_report_info_lock);
1406 ch_width = spectral->report_info[smode].sscan_bw;
1407 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1408
1409 acs_stats = phyerr_info->acs_stats;
1410 pfft = phyerr_info->pfft;
1411 p_sfft = phyerr_info->p_sfft;
1412 p_rfqual = phyerr_info->p_rfqual;
1413
1414 params->hw_detector_id = phyerr_info->seg_id;
1415 params->rssi = p_rfqual->rssi_comb;
1416 if (spectral->is_sec80_rssi_war_required && phyerr_info->seg_id == 1)
1417 params->rssi = target_if_get_combrssi_sec80_seg_gen2(spectral,
1418 p_sfft);
1419
1420 chn_idx_highest_enabled =
1421 ((spectral->params[smode].ss_chn_mask & 0x8) ? 3 :
1422 (spectral->params[smode].ss_chn_mask & 0x4) ? 2 :
1423 (spectral->params[smode].ss_chn_mask & 0x2) ? 1 : 0);
1424 chn_idx_lowest_enabled =
1425 ((spectral->params[smode].ss_chn_mask & 0x1) ? 0 :
1426 (spectral->params[smode].ss_chn_mask & 0x2) ? 1 :
1427 (spectral->params[smode].ss_chn_mask & 0x4) ? 2 : 3);
1428 control_rssi =
1429 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
1430 extension_rssi =
1431 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
1432
1433 if (spectral->upper_is_control)
1434 params->upper_rssi = control_rssi;
1435 else
1436 params->upper_rssi = extension_rssi;
1437
1438 if (spectral->lower_is_control)
1439 params->lower_rssi = control_rssi;
1440 else
1441 params->lower_rssi = extension_rssi;
1442
1443 if (spectral->sc_spectral_noise_pwr_cal) {
1444 int idx;
1445
1446 for (idx = 0; idx < HOST_MAX_ANTENNA; idx++) {
1447 params->chain_ctl_rssi[idx] =
1448 p_rfqual->pc_rssi_info[idx].rssi_pri20;
1449 params->chain_ext_rssi[idx] =
1450 p_rfqual->pc_rssi_info[idx].rssi_sec20;
1451 }
1452 }
1453 params->timestamp = (phyerr_info->tsf64 & SPECTRAL_TSMASK);
1454 params->max_mag = p_sfft->peak_mag;
1455 params->max_index = p_sfft->peak_inx;
1456
1457 /*
1458 * For VHT80_80/VHT160, the noise floor for primary
1459 * 80MHz segment is populated with the lowest enabled
1460 * antenna chain and the noise floor for secondary 80MHz segment
1461 * is populated with the highest enabled antenna chain.
1462 * For modes upto VHT80, the noise floor is populated with the
1463 * one corresponding to the highest enabled antenna chain.
1464 */
1465 if (is_ch_width_160_or_80p80(ch_width) && phyerr_info->seg_id == 0)
1466 params->noise_floor =
1467 p_rfqual->noise_floor[chn_idx_lowest_enabled];
1468 else
1469 params->noise_floor =
1470 p_rfqual->noise_floor[chn_idx_highest_enabled];
1471
1472 acs_stats->ctrl_nf = params->noise_floor;
1473 acs_stats->ext_nf = params->noise_floor;
1474 acs_stats->nfc_ctl_rssi = control_rssi;
1475 acs_stats->nfc_ext_rssi = extension_rssi;
1476
1477 params->bin_pwr_data = (uint8_t *)pfft;
1478
1479 return QDF_STATUS_SUCCESS;
1480 }
1481
1482 int
target_if_process_phyerr_gen2(struct target_if_spectral * spectral,uint8_t * data,uint32_t datalen,struct target_if_spectral_rfqual_info * p_rfqual,struct target_if_spectral_chan_info * p_chaninfo,uint64_t tsf64,struct target_if_spectral_acs_stats * acs_stats)1483 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
1484 uint8_t *data,
1485 uint32_t datalen,
1486 struct target_if_spectral_rfqual_info *p_rfqual,
1487 struct target_if_spectral_chan_info *p_chaninfo,
1488 uint64_t tsf64,
1489 struct target_if_spectral_acs_stats *acs_stats)
1490 {
1491 /*
1492 * XXX : The classifier do not use all the members of the SAMP
1493 * message data format.
1494 * The classifier only depends upon the following parameters
1495 *
1496 * 1. Frequency
1497 * 2. Spectral RSSI
1498 * 3. Bin Power Count
1499 * 4. Bin Power values
1500 * 5. Spectral Timestamp
1501 * 6. MAC Address
1502 *
1503 * This function prepares the params structure and populates it
1504 * with relevant values, this is in turn passed to
1505 * spectral_fill_samp_msg()
1506 * to prepare fully formatted Spectral SAMP message
1507 *
1508 * XXX : Need to verify
1509 * 1. Order of FFT bin values
1510 *
1511 */
1512
1513 struct target_if_samp_msg_params params;
1514 struct spectral_search_fft_info_gen2 search_fft_info;
1515 struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
1516 struct spectral_search_fft_info_gen2 search_fft_info_sec80;
1517 struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
1518 &search_fft_info_sec80;
1519 uint32_t segid_skiplen = 0;
1520 struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
1521 struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
1522 struct spectral_phyerr_fft_gen2 *pfft = NULL;
1523 struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
1524 struct spectral_process_phyerr_info_gen2 process_phyerr_fields;
1525 struct spectral_process_phyerr_info_gen2 *phyerr_info =
1526 &process_phyerr_fields;
1527 uint8_t segid = 0;
1528 uint8_t segid_sec80;
1529 enum phy_ch_width ch_width;
1530 QDF_STATUS ret;
1531 struct target_if_spectral_ops *p_sops;
1532
1533 if (!spectral) {
1534 spectral_err_rl("Spectral LMAC object is null");
1535 return -EPERM;
1536 }
1537
1538 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
1539 /* Drop the sample if Spectral is not active */
1540 if (!p_sops->is_spectral_active(spectral,
1541 SPECTRAL_SCAN_MODE_NORMAL)) {
1542 spectral_info_rl("Spectral scan is not active");
1543 goto fail_no_print;
1544 }
1545
1546 if (!data) {
1547 spectral_err_rl("Phyerror event buffer is null");
1548 goto fail;
1549 }
1550 if (!p_rfqual) {
1551 spectral_err_rl("RF quality information is null");
1552 goto fail;
1553 }
1554 if (!p_chaninfo) {
1555 spectral_err_rl("Channel information is null");
1556 goto fail;
1557 }
1558 if (!acs_stats) {
1559 spectral_err_rl("ACS stats pointer is null");
1560 goto fail;
1561 }
1562
1563 qdf_spin_lock_bh(&spectral->session_report_info_lock);
1564 ch_width = spectral->report_info[SPECTRAL_SCAN_MODE_NORMAL].sscan_bw;
1565 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
1566
1567 ptlv = (struct spectral_phyerr_tlv_gen2 *)data;
1568
1569 if (spectral->is_160_format)
1570 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
1571
1572 pfft = (struct spectral_phyerr_fft_gen2 *)(
1573 data +
1574 sizeof(struct spectral_phyerr_tlv_gen2) +
1575 sizeof(struct spectral_phyerr_hdr_gen2) +
1576 segid_skiplen);
1577
1578 /*
1579 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
1580 * and use this facility inside spectral_dump_phyerr_data()
1581 * and supporting functions.
1582 */
1583 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
1584 target_if_spectral_dump_phyerr_data_gen2(
1585 data, datalen,
1586 spectral->is_160_format);
1587
1588 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1589 /*
1590 * EV# 118023: We tentatively disable the below print
1591 * and provide stats instead.
1592 */
1593 spectral->diag_stats.spectral_mismatch++;
1594 goto fail;
1595 }
1596
1597 qdf_mem_zero(¶ms, sizeof(params));
1598
1599 if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1600 if (spectral->is_160_format) {
1601 segid = *((SPECTRAL_SEGID_INFO *)(
1602 (uint8_t *)ptlv +
1603 sizeof(struct spectral_phyerr_tlv_gen2) +
1604 sizeof(struct spectral_phyerr_hdr_gen2)));
1605
1606 if (segid != 0) {
1607 struct spectral_diag_stats *p_diag_stats =
1608 &spectral->diag_stats;
1609 p_diag_stats->spectral_vhtseg1id_mismatch++;
1610 goto fail;
1611 }
1612 }
1613
1614 target_if_process_sfft_report_gen2(ptlv, ptlv->length,
1615 p_sfft);
1616
1617 ret = target_if_update_session_info_from_report_ctx(
1618 spectral, FFT_BIN_SIZE_1BYTE,
1619 p_chaninfo->center_freq1,
1620 p_chaninfo->center_freq2,
1621 SPECTRAL_SCAN_MODE_NORMAL);
1622 if (QDF_IS_STATUS_ERROR(ret)) {
1623 spectral_err_rl("Failed to update per-session info");
1624 goto fail;
1625 }
1626
1627 phyerr_info->p_rfqual = p_rfqual;
1628 phyerr_info->p_sfft = p_sfft;
1629 phyerr_info->pfft = pfft;
1630 phyerr_info->acs_stats = acs_stats;
1631 phyerr_info->tsf64 = tsf64;
1632 phyerr_info->seg_id = segid;
1633
1634 ret = target_if_spectral_populate_samp_params_gen2(spectral,
1635 phyerr_info,
1636 ¶ms);
1637 if (QDF_IS_STATUS_ERROR(ret)) {
1638 spectral_err_rl("Failed to populate SAMP params");
1639 goto fail;
1640 }
1641
1642 ret = target_if_spectral_fill_samp_msg(spectral, ¶ms);
1643 if (QDF_IS_STATUS_ERROR(ret)) {
1644 spectral_err_rl("Failed to fill the SAMP msg");
1645 goto fail;
1646 }
1647
1648 if (spectral->is_160_format &&
1649 is_ch_width_160_or_80p80(ch_width)) {
1650 /*
1651 * We expect to see one more Search FFT report, and it
1652 * should be equal in size to the current one.
1653 */
1654 if (datalen < (
1655 2 * (sizeof(struct spectral_phyerr_tlv_gen2) +
1656 ptlv->length))) {
1657 struct spectral_diag_stats *p_diag_stats =
1658 &spectral->diag_stats;
1659 p_diag_stats->spectral_sec80_sfft_insufflen++;
1660 goto fail;
1661 }
1662
1663 ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1664 data +
1665 sizeof(struct spectral_phyerr_tlv_gen2) +
1666 ptlv->length);
1667
1668 if (ptlv_sec80->signature !=
1669 SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1670 spectral->diag_stats.spectral_mismatch++;
1671 goto fail;
1672 }
1673
1674 if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1675 spectral->diag_stats.spectral_no_sec80_sfft++;
1676 goto fail;
1677 }
1678
1679 segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
1680 (uint8_t *)ptlv_sec80 +
1681 sizeof(struct spectral_phyerr_tlv_gen2) +
1682 sizeof(struct spectral_phyerr_hdr_gen2)));
1683
1684 if (segid_sec80 != 1) {
1685 struct spectral_diag_stats *p_diag_stats =
1686 &spectral->diag_stats;
1687 p_diag_stats->spectral_vhtseg2id_mismatch++;
1688 goto fail;
1689 }
1690
1691 target_if_process_sfft_report_gen2(ptlv_sec80,
1692 ptlv_sec80->length,
1693 p_sfft_sec80);
1694
1695 pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
1696 ((uint8_t *)ptlv_sec80) +
1697 sizeof(struct spectral_phyerr_tlv_gen2) +
1698 sizeof(struct spectral_phyerr_hdr_gen2) +
1699 segid_skiplen);
1700
1701 qdf_mem_zero(¶ms, sizeof(params));
1702
1703 phyerr_info->p_rfqual = p_rfqual;
1704 phyerr_info->p_sfft = p_sfft_sec80;
1705 phyerr_info->pfft = pfft_sec80;
1706 phyerr_info->acs_stats = acs_stats;
1707 phyerr_info->tsf64 = tsf64;
1708 phyerr_info->seg_id = segid_sec80;
1709
1710 ret = target_if_spectral_populate_samp_params_gen2(
1711 spectral, phyerr_info,
1712 ¶ms);
1713 if (QDF_IS_STATUS_ERROR(ret)) {
1714 spectral_err_rl("Failed to populate SAMP params");
1715 goto fail;
1716 }
1717 ret = target_if_spectral_fill_samp_msg(spectral,
1718 ¶ms);
1719 if (QDF_IS_STATUS_ERROR(ret)) {
1720 spectral_err_rl("Failed to fill the SAMP msg");
1721 goto fail;
1722 }
1723 }
1724 }
1725
1726 if (spectral_debug_level & DEBUG_SPECTRAL4)
1727 spectral_debug_level = DEBUG_SPECTRAL;
1728
1729 return 0;
1730
1731 fail:
1732 spectral_err_rl("Error while processing Spectral report");
1733
1734 fail_no_print:
1735 if (spectral_debug_level & DEBUG_SPECTRAL4)
1736 spectral_debug_level = DEBUG_SPECTRAL;
1737
1738 free_samp_msg_skb(spectral, SPECTRAL_SCAN_MODE_NORMAL);
1739 return -EPERM;
1740 }
1741
1742 #else
1743 int
target_if_process_phyerr_gen2(struct target_if_spectral * spectral,uint8_t * data,uint32_t datalen,struct target_if_spectral_rfqual_info * p_rfqual,struct target_if_spectral_chan_info * p_chaninfo,uint64_t tsf64,struct target_if_spectral_acs_stats * acs_stats)1744 target_if_process_phyerr_gen2(struct target_if_spectral *spectral,
1745 uint8_t *data,
1746 uint32_t datalen,
1747 struct target_if_spectral_rfqual_info *p_rfqual,
1748 struct target_if_spectral_chan_info *p_chaninfo,
1749 uint64_t tsf64,
1750 struct target_if_spectral_acs_stats *acs_stats)
1751 {
1752 /*
1753 * XXX : The classifier do not use all the members of the SAMP
1754 * message data format.
1755 * The classifier only depends upon the following parameters
1756 *
1757 * 1. Frequency (freq, msg->freq)
1758 * 2. Spectral RSSI (spectral_rssi,
1759 * msg->samp_data.spectral_rssi)
1760 * 3. Bin Power Count (bin_pwr_count,
1761 * msg->samp_data.bin_pwr_count)
1762 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
1763 * 5. Spectral Timestamp (spectral_tstamp,
1764 * msg->samp_data.spectral_tstamp)
1765 * 6. MAC Address (macaddr, msg->macaddr)
1766 *
1767 * This function prepares the params structure and populates it
1768 * with
1769 * relevant values, this is in turn passed to
1770 * spectral_create_samp_msg()
1771 * to prepare fully formatted Spectral SAMP message
1772 *
1773 * XXX : Need to verify
1774 * 1. Order of FFT bin values
1775 *
1776 */
1777
1778 struct target_if_samp_msg_params params;
1779 struct spectral_search_fft_info_gen2 search_fft_info;
1780 struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info;
1781 struct spectral_search_fft_info_gen2 search_fft_info_sec80;
1782 struct spectral_search_fft_info_gen2 *p_sfft_sec80 =
1783 &search_fft_info_sec80;
1784 uint32_t segid_skiplen = 0;
1785
1786 int8_t rssi_up = 0;
1787 int8_t rssi_low = 0;
1788
1789 int8_t chn_idx_highest_enabled = 0;
1790 int8_t chn_idx_lowest_enabled = 0;
1791
1792 uint8_t control_rssi = 0;
1793 uint8_t extension_rssi = 0;
1794 uint8_t combined_rssi = 0;
1795
1796 uint32_t tstamp = 0;
1797
1798 struct target_if_spectral_ops *p_sops =
1799 GET_TARGET_IF_SPECTRAL_OPS(spectral);
1800
1801 struct spectral_phyerr_tlv_gen2 *ptlv =
1802 (struct spectral_phyerr_tlv_gen2 *)data;
1803 struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL;
1804 struct spectral_phyerr_fft_gen2 *pfft = NULL;
1805 struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL;
1806
1807 uint8_t segid = 0;
1808 uint8_t segid_sec80 = 0;
1809 enum phy_ch_width ch_width =
1810 spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL];
1811
1812 if (spectral->is_160_format)
1813 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
1814
1815 pfft = (struct spectral_phyerr_fft_gen2 *)(
1816 data +
1817 sizeof(struct spectral_phyerr_tlv_gen2) +
1818 sizeof(struct spectral_phyerr_hdr_gen2) +
1819 segid_skiplen);
1820
1821 /*
1822 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
1823 * and use this facility inside spectral_dump_phyerr_data()
1824 * and supporting functions.
1825 */
1826 if (spectral_debug_level & DEBUG_SPECTRAL2)
1827 target_if_spectral_dump_phyerr_data_gen2(
1828 data, datalen,
1829 spectral->is_160_format);
1830
1831 if (spectral_debug_level & DEBUG_SPECTRAL4) {
1832 target_if_spectral_dump_phyerr_data_gen2(
1833 data, datalen,
1834 spectral->is_160_format);
1835 spectral_debug_level = DEBUG_SPECTRAL;
1836 }
1837
1838 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1839 /*
1840 * EV# 118023: We tentatively disable the below print
1841 * and provide stats instead.
1842 */
1843 spectral->diag_stats.spectral_mismatch++;
1844 return -EPERM;
1845 }
1846
1847 OS_MEMZERO(¶ms, sizeof(params));
1848 /* Gen 2 only supports normal Spectral scan currently */
1849 params.smode = SPECTRAL_SCAN_MODE_NORMAL;
1850
1851 if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1852 if (spectral->is_160_format) {
1853 segid = *((SPECTRAL_SEGID_INFO *)(
1854 (uint8_t *)ptlv +
1855 sizeof(struct spectral_phyerr_tlv_gen2) +
1856 sizeof(struct spectral_phyerr_hdr_gen2)));
1857
1858 if (segid != 0) {
1859 struct spectral_diag_stats *p_diag_stats =
1860 &spectral->diag_stats;
1861 p_diag_stats->spectral_vhtseg1id_mismatch++;
1862 return -EPERM;
1863 }
1864 }
1865
1866 target_if_process_sfft_report_gen2(ptlv, ptlv->length,
1867 &search_fft_info);
1868
1869 tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
1870
1871 combined_rssi = p_rfqual->rssi_comb;
1872
1873 if (spectral->upper_is_control)
1874 rssi_up = control_rssi;
1875 else
1876 rssi_up = extension_rssi;
1877
1878 if (spectral->lower_is_control)
1879 rssi_low = control_rssi;
1880 else
1881 rssi_low = extension_rssi;
1882
1883 params.rssi = p_rfqual->rssi_comb;
1884 params.lower_rssi = rssi_low;
1885 params.upper_rssi = rssi_up;
1886
1887 if (spectral->sc_spectral_noise_pwr_cal) {
1888 params.chain_ctl_rssi[0] =
1889 p_rfqual->pc_rssi_info[0].rssi_pri20;
1890 params.chain_ctl_rssi[1] =
1891 p_rfqual->pc_rssi_info[1].rssi_pri20;
1892 params.chain_ctl_rssi[2] =
1893 p_rfqual->pc_rssi_info[2].rssi_pri20;
1894 params.chain_ext_rssi[0] =
1895 p_rfqual->pc_rssi_info[0].rssi_sec20;
1896 params.chain_ext_rssi[1] =
1897 p_rfqual->pc_rssi_info[1].rssi_sec20;
1898 params.chain_ext_rssi[2] =
1899 p_rfqual->pc_rssi_info[2].rssi_sec20;
1900 }
1901
1902 /*
1903 * XXX : This actually depends on the programmed chain mask
1904 * This value decides the per-chain enable mask to select
1905 * the input ADC for search FTT.
1906 * For modes upto VHT80, if more than one chain is
1907 * enabled, the max valid chain
1908 * is used. LSB corresponds to chain zero.
1909 * For VHT80_80 and VHT160, the lowest enabled chain is
1910 * used for primary
1911 * detection and highest enabled chain is used for
1912 * secondary detection.
1913 *
1914 * XXX : The current algorithm do not use these control and
1915 * extension channel
1916 * Instead, it just relies on the combined RSSI values
1917 * only.
1918 * For fool-proof detection algorithm, we should take
1919 * these RSSI values in to account.
1920 * This is marked for future enhancements.
1921 */
1922 chn_idx_highest_enabled =
1923 ((spectral->params[params.smode].ss_chn_mask & 0x8) ? 3 :
1924 (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 :
1925 (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 0);
1926 chn_idx_lowest_enabled =
1927 ((spectral->params[params.smode].ss_chn_mask & 0x1) ? 0 :
1928 (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 :
1929 (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 3);
1930 control_rssi = (uint8_t)
1931 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
1932 extension_rssi = (uint8_t)
1933 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
1934
1935 params.bwinfo = 0;
1936 params.tstamp = 0;
1937 params.max_mag = p_sfft->peak_mag;
1938
1939 params.max_index = p_sfft->peak_inx;
1940 params.max_exp = 0;
1941 params.peak = 0;
1942 params.bin_pwr_data = (uint8_t *)pfft;
1943 params.freq = p_sops->get_current_channel(spectral,
1944 params.smode);
1945 params.freq_loading = 0;
1946
1947 params.interf_list.count = 0;
1948 params.max_lower_index = 0;
1949 params.max_upper_index = 0;
1950 params.nb_lower = 0;
1951 params.nb_upper = 0;
1952 /*
1953 * For modes upto VHT80, the noise floor is populated with the
1954 * one corresponding
1955 * to the highest enabled antenna chain
1956 */
1957 params.noise_floor =
1958 p_rfqual->noise_floor[chn_idx_highest_enabled];
1959 params.datalen = ptlv->length;
1960 params.pwr_count = ptlv->length -
1961 sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen;
1962 params.tstamp = (tsf64 & SPECTRAL_TSMASK);
1963
1964 acs_stats->ctrl_nf = params.noise_floor;
1965 acs_stats->ext_nf = params.noise_floor;
1966 acs_stats->nfc_ctl_rssi = control_rssi;
1967 acs_stats->nfc_ext_rssi = extension_rssi;
1968
1969 if (spectral->is_160_format &&
1970 is_ch_width_160_or_80p80(ch_width)) {
1971 /*
1972 * We expect to see one more Search FFT report, and it
1973 * should be equal in size to the current one.
1974 */
1975 if (datalen < (
1976 2 * (
1977 sizeof(struct spectral_phyerr_tlv_gen2) +
1978 ptlv->length))) {
1979 struct spectral_diag_stats *p_diag_stats =
1980 &spectral->diag_stats;
1981 p_diag_stats->spectral_sec80_sfft_insufflen++;
1982 return -EPERM;
1983 }
1984
1985 ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)(
1986 data +
1987 sizeof(struct spectral_phyerr_tlv_gen2) +
1988 ptlv->length);
1989
1990 if (ptlv_sec80->signature !=
1991 SPECTRAL_PHYERR_SIGNATURE_GEN2) {
1992 spectral->diag_stats.spectral_mismatch++;
1993 return -EPERM;
1994 }
1995
1996 if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
1997 spectral->diag_stats.spectral_no_sec80_sfft++;
1998 return -EPERM;
1999 }
2000
2001 segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
2002 (uint8_t *)ptlv_sec80 +
2003 sizeof(struct spectral_phyerr_tlv_gen2) +
2004 sizeof(struct spectral_phyerr_hdr_gen2)));
2005
2006 if (segid_sec80 != 1) {
2007 struct spectral_diag_stats *p_diag_stats =
2008 &spectral->diag_stats;
2009 p_diag_stats->spectral_vhtseg2id_mismatch++;
2010 return -EPERM;
2011 }
2012
2013 params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
2014 params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
2015
2016 target_if_process_sfft_report_gen2(
2017 ptlv_sec80,
2018 ptlv_sec80->length,
2019 &search_fft_info_sec80);
2020
2021 pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)(
2022 ((uint8_t *)ptlv_sec80) +
2023 sizeof(struct spectral_phyerr_tlv_gen2) +
2024 sizeof(struct spectral_phyerr_hdr_gen2) +
2025 segid_skiplen);
2026
2027 /* XXX: Confirm. TBD at SoD. */
2028 params.rssi_sec80 = p_rfqual->rssi_comb;
2029 if (spectral->is_sec80_rssi_war_required)
2030 params.rssi_sec80 =
2031 target_if_get_combrssi_sec80_seg_gen2
2032 (spectral, &search_fft_info_sec80);
2033 /* XXX: Determine dynamically. TBD at SoD. */
2034 /*
2035 * For VHT80_80/VHT160, the noise floor for primary
2036 * 80MHz segment is populated with the
2037 * lowest enabled antenna chain and the noise floor for
2038 * secondary 80MHz segment is populated
2039 * with the highest enabled antenna chain
2040 */
2041 params.noise_floor_sec80 =
2042 p_rfqual->noise_floor[chn_idx_highest_enabled];
2043 params.noise_floor =
2044 p_rfqual->noise_floor[chn_idx_lowest_enabled];
2045
2046 params.max_mag_sec80 = p_sfft_sec80->peak_mag;
2047 params.max_index_sec80 = p_sfft_sec80->peak_inx;
2048 /* XXX Does this definition of datalen *still hold? */
2049 params.datalen_sec80 = ptlv_sec80->length;
2050 params.pwr_count_sec80 =
2051 ptlv_sec80->length -
2052 sizeof(struct spectral_phyerr_hdr_gen2) -
2053 segid_skiplen;
2054 params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80;
2055 }
2056 qdf_mem_copy(¶ms.classifier_params,
2057 &spectral->classifier_params,
2058 sizeof(struct spectral_classifier_params));
2059
2060 target_if_spectral_log_SAMP_param(¶ms);
2061 target_if_spectral_create_samp_msg(spectral, ¶ms);
2062 }
2063
2064 return 0;
2065 }
2066 #endif /* OPTIMIZED_SAMP_MESSAGE */
2067
2068 int
target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 * phdr)2069 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr)
2070 {
2071 uint32_t a = 0;
2072 uint32_t b = 0;
2073
2074 qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int));
2075 qdf_mem_copy(&b,
2076 (uint8_t *)((uint8_t *)phdr + sizeof(int)),
2077 sizeof(int));
2078
2079 spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a);
2080 spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b);
2081 return 0;
2082 }
2083
2084 int8_t
target_if_get_combrssi_sec80_seg_gen2(struct target_if_spectral * spectral,struct spectral_search_fft_info_gen2 * p_sfft_sec80)2085 target_if_get_combrssi_sec80_seg_gen2(
2086 struct target_if_spectral *spectral,
2087 struct spectral_search_fft_info_gen2 *p_sfft_sec80)
2088 {
2089 uint32_t avgpwr_db = 0;
2090 uint32_t total_gain_db = 0;
2091 uint32_t offset = 0;
2092 int8_t comb_rssi = 0;
2093
2094 /* Obtain required parameters for algorithm from search FFT report */
2095 avgpwr_db = p_sfft_sec80->avgpwr_db;
2096 total_gain_db = p_sfft_sec80->total_gain_info;
2097
2098 /* Calculate offset */
2099 offset = target_if_get_offset_swar_sec80(
2100 spectral->ch_width[SPECTRAL_SCAN_MODE_NORMAL]);
2101
2102 /* Calculate RSSI */
2103 comb_rssi = ((avgpwr_db - total_gain_db) + offset);
2104
2105 return comb_rssi;
2106 }
2107
2108 int
target_if_spectral_dump_tlv_gen2(struct spectral_phyerr_tlv_gen2 * ptlv,bool is_160_format)2109 target_if_spectral_dump_tlv_gen2(
2110 struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format)
2111 {
2112 int ret = 0;
2113
2114 /*
2115 * TODO : Do not delete the following print
2116 * The scripts used to validate Spectral depend on this Print
2117 */
2118 spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)",
2119 ptlv->length, ptlv->length);
2120
2121 switch (ptlv->tag) {
2122 case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
2123 ret =
2124 target_if_dump_summary_report_gen2(
2125 ptlv, ptlv->length, is_160_format);
2126 break;
2127
2128 case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
2129 ret =
2130 target_if_dump_sfft_report_gen2(ptlv, ptlv->length,
2131 is_160_format);
2132 break;
2133
2134 case TLV_TAG_ADC_REPORT_GEN2:
2135 ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length);
2136 break;
2137
2138 default:
2139 spectral_warn("INVALID TLV");
2140 ret = -1;
2141 break;
2142 }
2143
2144 return ret;
2145 }
2146
2147 int
target_if_spectral_dump_phyerr_data_gen2(uint8_t * data,uint32_t datalen,bool is_160_format)2148 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen,
2149 bool is_160_format)
2150 {
2151 struct spectral_phyerr_tlv_gen2 *ptlv = NULL;
2152 uint32_t bytes_processed = 0;
2153 uint32_t bytes_remaining = datalen;
2154 uint32_t curr_tlv_complete_size = 0;
2155
2156 if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) {
2157 spectral_err("Total PHY error data length %u too short to contain any TLVs",
2158 datalen);
2159 return -EPERM;
2160 }
2161
2162 while (bytes_processed < datalen) {
2163 if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) {
2164 spectral_err("Remaining PHY error data length %u too short to contain a TLV",
2165 bytes_remaining);
2166 return -EPERM;
2167 }
2168
2169 ptlv = (struct spectral_phyerr_tlv_gen2 *)(data +
2170 bytes_processed);
2171
2172 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
2173 spectral_err("Invalid signature 0x%x!",
2174 ptlv->signature);
2175 return -EPERM;
2176 }
2177
2178 curr_tlv_complete_size =
2179 sizeof(struct spectral_phyerr_tlv_gen2) +
2180 ptlv->length;
2181
2182 if (curr_tlv_complete_size > bytes_remaining) {
2183 spectral_err("TLV size %d greater than number of bytes remaining %d",
2184 curr_tlv_complete_size, bytes_remaining);
2185 return -EPERM;
2186 }
2187
2188 if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
2189 return -EPERM;
2190
2191 bytes_processed += curr_tlv_complete_size;
2192 bytes_remaining = datalen - bytes_processed;
2193 }
2194
2195 return 0;
2196 }
2197
2198 QDF_STATUS
target_if_spectral_copy_fft_bins(struct target_if_spectral * spectral,const void * src_fft_buf,void * dest_fft_buf,uint32_t fft_bin_count,uint32_t * bytes_copied,uint16_t pwr_format)2199 target_if_spectral_copy_fft_bins(struct target_if_spectral *spectral,
2200 const void *src_fft_buf,
2201 void *dest_fft_buf,
2202 uint32_t fft_bin_count,
2203 uint32_t *bytes_copied,
2204 uint16_t pwr_format)
2205 {
2206 uint16_t idx, dword_idx, fft_bin_idx;
2207 uint8_t num_bins_per_dword, hw_fft_bin_width_bits;
2208 uint32_t num_dwords;
2209 uint16_t fft_bin_val;
2210 struct spectral_report_params *rparams;
2211 const uint32_t *dword_ptr;
2212 uint32_t dword;
2213 uint8_t *fft_bin_buf;
2214
2215 *bytes_copied = 0;
2216
2217 if (!spectral) {
2218 spectral_err("spectral lmac object is NULL");
2219 return QDF_STATUS_E_NULL_VALUE;
2220 }
2221
2222 if (!src_fft_buf) {
2223 spectral_err("source fft bin buffer is NULL");
2224 return QDF_STATUS_E_NULL_VALUE;
2225 }
2226
2227 if (!dest_fft_buf) {
2228 spectral_err("destination fft bin buffer is NULL");
2229 return QDF_STATUS_E_NULL_VALUE;
2230 }
2231
2232 rparams = &spectral->rparams;
2233 num_bins_per_dword = SPECTRAL_DWORD_SIZE / rparams->hw_fft_bin_width;
2234 num_dwords = fft_bin_count / num_bins_per_dword;
2235 hw_fft_bin_width_bits = rparams->hw_fft_bin_width * QDF_CHAR_BIT;
2236
2237 fft_bin_idx = 0;
2238 dword_ptr = src_fft_buf;
2239 fft_bin_buf = dest_fft_buf;
2240 for (dword_idx = 0; dword_idx < num_dwords; dword_idx++) {
2241 dword = *dword_ptr++; /* Read a DWORD */
2242 for (idx = 0; idx < num_bins_per_dword; idx++) {
2243 /**
2244 * If we use QDF_GET_BITS, when hw_fft_bin_width_bits is
2245 * 32, on certain platforms, we could end up doing a
2246 * 32-bit left shift operation on 32-bit constant
2247 * integer '1'. As per C standard, result of shifting an
2248 * operand by a count greater than or equal to width
2249 * (in bits) of the operand is undefined.
2250 * If we use QDF_GET_BITS_64, we can avoid that.
2251 */
2252 fft_bin_val = (uint16_t)QDF_GET_BITS64(
2253 dword,
2254 idx * hw_fft_bin_width_bits,
2255 hw_fft_bin_width_bits);
2256
2257 fft_bin_buf[fft_bin_idx++] =
2258 clamp_fft_bin_value(fft_bin_val, pwr_format);
2259 }
2260 }
2261
2262 *bytes_copied = num_dwords * SPECTRAL_DWORD_SIZE;
2263
2264 return QDF_STATUS_SUCCESS;
2265 }
2266
2267 #ifdef DIRECT_BUF_RX_ENABLE
2268 /**
2269 * target_if_get_spectral_mode() - Get Spectral scan mode corresponding to a
2270 * detector id
2271 * @detector_id: detector id in the Spectral report
2272 * @rparams: pointer to report params object
2273 *
2274 * Helper API to get Spectral scan mode from the detector ID. This mapping is
2275 * target specific.
2276 *
2277 * Return: Spectral scan mode
2278 */
2279 static enum spectral_scan_mode
target_if_get_spectral_mode(enum spectral_detector_id detector_id,struct spectral_report_params * rparams)2280 target_if_get_spectral_mode(enum spectral_detector_id detector_id,
2281 struct spectral_report_params *rparams)
2282 {
2283 if (detector_id >= SPECTRAL_DETECTOR_ID_MAX) {
2284 spectral_err_rl("Invalid detector id %d", detector_id);
2285 return SPECTRAL_SCAN_MODE_INVALID;
2286 }
2287
2288 return rparams->detid_mode_table[detector_id];
2289 }
2290
2291 /**
2292 * target_if_spectral_get_bin_count_after_len_adj() - Get number of FFT bins in
2293 * Spectral FFT report
2294 * @fft_bin_len: FFT bin length reported by target
2295 * @rpt_mode: Spectral report mode
2296 * @swar: Spectral FFT bin length adjustments SWAR parameters
2297 * @fft_bin_size: Size of one FFT bin in bytes
2298 *
2299 * Get actual number of FFT bins in the FFT report after adjusting the length
2300 * by applying the SWARs for getting correct length.
2301 *
2302 * Return: FFT bin count
2303 */
2304 static size_t
target_if_spectral_get_bin_count_after_len_adj(size_t fft_bin_len,uint8_t rpt_mode,struct spectral_fft_bin_len_adj_swar * swar,size_t * fft_bin_size)2305 target_if_spectral_get_bin_count_after_len_adj(
2306 size_t fft_bin_len, uint8_t rpt_mode,
2307 struct spectral_fft_bin_len_adj_swar *swar,
2308 size_t *fft_bin_size)
2309 {
2310 size_t fft_bin_count = fft_bin_len;
2311
2312 if (rpt_mode == 1 && swar->null_fftbin_adj) {
2313 /*
2314 * No FFT bins are expected. Explicitly set FFT bin
2315 * count to 0.
2316 */
2317 fft_bin_count = 0;
2318 *fft_bin_size = 0;
2319 } else {
2320 /*
2321 * Divide fft bin length by appropriate factor depending
2322 * on the value of fftbin_size_war.
2323 */
2324 switch (swar->fftbin_size_war) {
2325 case SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE:
2326 fft_bin_count >>= 2;
2327 *fft_bin_size = 4;
2328 break;
2329 case SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE:
2330 fft_bin_count >>= 1;
2331 *fft_bin_size = 2;
2332 /* Ideally we should be dividing fft bin length
2333 * by 2. Due to a HW bug, actual length is two
2334 * times the expected length.
2335 */
2336 if (swar->packmode_fftbin_size_adj)
2337 fft_bin_count >>= 1;
2338 break;
2339 case SPECTRAL_FFTBIN_SIZE_NO_WAR:
2340 fallthrough;
2341 default:
2342 *fft_bin_size = 1;
2343 /* No length adjustment */
2344 }
2345
2346 if (rpt_mode == 2 && swar->inband_fftbin_size_adj)
2347 fft_bin_count >>= 1;
2348 }
2349
2350 return fft_bin_count;
2351 }
2352
2353 #ifndef OPTIMIZED_SAMP_MESSAGE
2354 /**
2355 * target_if_process_sfft_report_gen3() - Process Search FFT Report for gen3
2356 * @p_fft_report: Pointer to fft report
2357 * @p_sfft: Pointer to search fft report
2358 * @rparams: pointer to report params object
2359 *
2360 * Process Search FFT Report for gen3
2361 *
2362 * Return: Success/Failure
2363 */
2364 static int
target_if_process_sfft_report_gen3(struct spectral_phyerr_fft_report_gen3 * p_fft_report,struct spectral_search_fft_info_gen3 * p_sfft,struct spectral_report_params * rparams)2365 target_if_process_sfft_report_gen3(
2366 struct spectral_phyerr_fft_report_gen3 *p_fft_report,
2367 struct spectral_search_fft_info_gen3 *p_sfft,
2368 struct spectral_report_params *rparams)
2369 {
2370 int32_t peak_sidx = 0;
2371 int32_t peak_mag;
2372
2373 if (!p_fft_report || !p_sfft || !rparams) {
2374 spectral_err("null params: p_fft_report %pK p_sfft %pK rparams %pK",
2375 p_fft_report, p_sfft, rparams);
2376 return -EINVAL;
2377 }
2378
2379 /*
2380 * For simplicity, everything is defined as uint32_t (except one).
2381 * Proper code will later use the right sizes.
2382 */
2383 /*
2384 * For easy comparison between MDK team and OS team, the MDK script
2385 * variable names have been used
2386 */
2387
2388 /* Populate the Search FFT Info */
2389 p_sfft->timestamp = p_fft_report->fft_timestamp;
2390
2391 p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a,
2392 2, 0);
2393 p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2);
2394
2395 switch (rparams->version) {
2396 case SPECTRAL_REPORT_FORMAT_VERSION_1:
2397 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
2398 12, 5);
2399 peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17);
2400 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28);
2401 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
2402 9, 0);
2403 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
2404 8, 9);
2405 break;
2406 case SPECTRAL_REPORT_FORMAT_VERSION_2:
2407 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
2408 14, 5);
2409 peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 19);
2410 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_b, 3, 0);
2411 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
2412 9, 3);
2413 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
2414 8, 12);
2415 break;
2416 default:
2417 spectral_err_rl("Invalid spectral report format: %d",
2418 rparams->version);
2419 return -EINVAL;
2420 }
2421
2422 p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
2423
2424 p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
2425 8, 0);
2426 peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8);
2427 p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
2428 p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
2429 7, 18);
2430 p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
2431 7, 25);
2432
2433 return 0;
2434 }
2435 #endif
2436
2437 /**
2438 * target_if_dump_fft_report_gen3() - Dump FFT Report for gen3
2439 * @spectral: Pointer to Spectral object
2440 * @smode: Spectral scan mode
2441 * @p_fft_report: Pointer to fft report
2442 * @p_sfft: Pointer to search fft report
2443 *
2444 * Dump FFT Report for gen3
2445 *
2446 * Return: void
2447 */
2448 static void
target_if_dump_fft_report_gen3(struct target_if_spectral * spectral,enum spectral_scan_mode smode,struct spectral_phyerr_fft_report_gen3 * p_fft_report,struct spectral_search_fft_info_gen3 * p_sfft)2449 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral,
2450 enum spectral_scan_mode smode,
2451 struct spectral_phyerr_fft_report_gen3 *p_fft_report,
2452 struct spectral_search_fft_info_gen3 *p_sfft)
2453 {
2454 size_t fft_hdr_length;
2455 size_t report_len;
2456 size_t fft_bin_len;
2457 size_t fft_bin_count;
2458 size_t fft_bin_size;
2459 size_t fft_bin_len_inband_tfer = 0;
2460 uint8_t tag, signature;
2461
2462 if (!spectral) {
2463 spectral_err_rl("spectral pointer is null.");
2464 return;
2465 }
2466
2467 /* There won't be FFT report/bins in report mode 0, so return */
2468 if (!spectral->params[smode].ss_rpt_mode)
2469 return;
2470
2471 fft_hdr_length = get_bitfield(
2472 p_fft_report->fft_hdr_lts,
2473 SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
2474 SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
2475
2476 tag = get_bitfield(p_fft_report->fft_hdr_lts,
2477 SPECTRAL_REPORT_LTS_TAG_SIZE_GEN3,
2478 SPECTRAL_REPORT_LTS_TAG_POS_GEN3);
2479
2480 signature = get_bitfield(p_fft_report->fft_hdr_lts,
2481 SPECTRAL_REPORT_LTS_SIGNATURE_SIZE_GEN3,
2482 SPECTRAL_REPORT_LTS_SIGNATURE_POS_GEN3);
2483
2484 report_len = (fft_hdr_length + 8);
2485 fft_bin_len = fft_hdr_length - spectral->rparams.fft_report_hdr_len;
2486 fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
2487 fft_bin_len,
2488 spectral->params[smode].ss_rpt_mode,
2489 &spectral->len_adj_swar, &fft_bin_size);
2490
2491 if ((spectral->params[smode].ss_rpt_mode == 2) &&
2492 spectral->len_adj_swar.inband_fftbin_size_adj)
2493 fft_bin_len_inband_tfer = fft_bin_len >> 1;
2494
2495 spectral_debug("Spectral FFT Report");
2496 spectral_debug("fft_timestamp = 0x%x", p_fft_report->fft_timestamp);
2497 spectral_debug("fft_hdr_length = %zu(32 bit words)",
2498 fft_hdr_length >> 2);
2499 spectral_debug("fft_hdr_tag = 0x%x", tag);
2500 spectral_debug("fft_hdr_sig = 0x%x", signature);
2501
2502 spectral_debug("Length field in search fft report is %zu(0x%zx) bytes",
2503 fft_hdr_length, fft_hdr_length);
2504 spectral_debug("Total length of search fft report is %zu(0x%zx) bytes",
2505 report_len, report_len);
2506 spectral_debug("Target reported fftbins in report is %zu(0x%zx)",
2507 fft_bin_len, fft_bin_len);
2508
2509 if ((spectral->params[smode].ss_rpt_mode == 1) &&
2510 spectral->len_adj_swar.null_fftbin_adj)
2511 spectral_debug("WAR: Considering number of FFT bins as 0");
2512 else if ((spectral->params[smode].ss_rpt_mode == 2) &&
2513 spectral->len_adj_swar.inband_fftbin_size_adj) {
2514 spectral_debug("FW fftbins actually transferred (in-band report mode) %zu(0x%zx)",
2515 fft_bin_len_inband_tfer,
2516 fft_bin_len_inband_tfer);
2517 }
2518
2519 spectral_debug("Actual number of fftbins in report is %zu(0x%zx)",
2520 fft_bin_count, fft_bin_count);
2521
2522 spectral_debug("fft_detector_id = %u", p_sfft->fft_detector_id);
2523 spectral_debug("fft_num = %u", p_sfft->fft_num);
2524 spectral_debug("fft_radar_check = %u", p_sfft->fft_radar_check);
2525 spectral_debug("fft_peak_sidx = %d", p_sfft->fft_peak_sidx);
2526 spectral_debug("fft_chn_idx = %u", p_sfft->fft_chn_idx);
2527 spectral_debug("fft_base_pwr_db = %u", p_sfft->fft_base_pwr_db);
2528 spectral_debug("fft_total_gain_db = %u", p_sfft->fft_total_gain_db);
2529 spectral_debug("fft_num_str_bins_ib = %u", p_sfft->fft_num_str_bins_ib);
2530 spectral_debug("fft_peak_mag = %d", p_sfft->fft_peak_mag);
2531 spectral_debug("fft_avgpwr_db = %u", p_sfft->fft_avgpwr_db);
2532 spectral_debug("fft_relpwr_db = %u", p_sfft->fft_relpwr_db);
2533
2534 if (fft_bin_count > 0) {
2535 uint8_t *fft_bin_buf;
2536 uint32_t bytes_copied;
2537 QDF_STATUS status;
2538
2539 fft_bin_buf = qdf_mem_malloc(fft_bin_count);
2540 if (!fft_bin_buf) {
2541 spectral_err_rl("memory allocation failed");
2542 return;
2543 }
2544
2545 status = target_if_spectral_copy_fft_bins(
2546 spectral, &p_fft_report->buf,
2547 fft_bin_buf, fft_bin_count, &bytes_copied,
2548 spectral->params[smode].ss_pwr_format);
2549 if (QDF_IS_STATUS_ERROR(status)) {
2550 spectral_err_rl("Unable to populate FFT bins");
2551 qdf_mem_free(fft_bin_buf);
2552 return;
2553 }
2554
2555 spectral_debug("FFT bin buffer size = %zu", fft_bin_count);
2556 spectral_debug("FFT bins:");
2557 target_if_spectral_hexdump(fft_bin_buf, fft_bin_count);
2558 qdf_mem_free(fft_bin_buf);
2559 }
2560 }
2561 #endif
2562
2563 #ifdef OPTIMIZED_SAMP_MESSAGE
2564 QDF_STATUS
target_if_160mhz_delivery_state_change(struct target_if_spectral * spectral,enum spectral_scan_mode smode,uint8_t detector_id)2565 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
2566 enum spectral_scan_mode smode,
2567 uint8_t detector_id) {
2568 QDF_STATUS status = QDF_STATUS_SUCCESS;
2569
2570 if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2571 spectral_err_rl("Invalid Spectral mode %d", smode);
2572 return QDF_STATUS_E_INVAL;
2573 }
2574
2575 if (!is_ch_width_160_or_80p80(spectral->report_info[smode].sscan_bw)) {
2576 spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
2577 spectral->report_info[smode].sscan_bw, smode);
2578 return QDF_STATUS_E_FAILURE;
2579 }
2580
2581 switch (spectral->state_160mhz_delivery[smode]) {
2582 case SPECTRAL_REPORT_WAIT_PRIMARY80:
2583 if (detector_id == SPECTRAL_DETECTOR_ID_0)
2584 spectral->state_160mhz_delivery[smode] =
2585 SPECTRAL_REPORT_WAIT_SECONDARY80;
2586 else {
2587 status = QDF_STATUS_E_FAILURE;
2588 spectral->diag_stats.spectral_vhtseg1id_mismatch++;
2589 }
2590 break;
2591
2592 case SPECTRAL_REPORT_WAIT_SECONDARY80:
2593 if (detector_id == SPECTRAL_DETECTOR_ID_1)
2594 spectral->state_160mhz_delivery[smode] =
2595 SPECTRAL_REPORT_WAIT_PRIMARY80;
2596 else {
2597 spectral->state_160mhz_delivery[smode] =
2598 SPECTRAL_REPORT_WAIT_PRIMARY80;
2599 status = QDF_STATUS_E_FAILURE;
2600 spectral->diag_stats.spectral_vhtseg2id_mismatch++;
2601 }
2602 break;
2603
2604 default:
2605 break;
2606 }
2607
2608 return status;
2609 }
2610 #else
2611 QDF_STATUS
target_if_160mhz_delivery_state_change(struct target_if_spectral * spectral,enum spectral_scan_mode smode,uint8_t detector_id)2612 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral,
2613 enum spectral_scan_mode smode,
2614 uint8_t detector_id) {
2615 QDF_STATUS status = QDF_STATUS_SUCCESS;
2616
2617 if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2618 spectral_err_rl("Invalid Spectral mode %d", smode);
2619 return QDF_STATUS_E_INVAL;
2620 }
2621
2622 if (!is_ch_width_160_or_80p80(spectral->ch_width[smode])) {
2623 spectral_err_rl("Scan BW %d is not 160/80p80 for mode %d",
2624 spectral->ch_width[smode], smode);
2625 return QDF_STATUS_E_FAILURE;
2626 }
2627
2628 switch (spectral->state_160mhz_delivery[smode]) {
2629 case SPECTRAL_REPORT_WAIT_PRIMARY80:
2630 if (detector_id == SPECTRAL_DETECTOR_ID_0)
2631 spectral->state_160mhz_delivery[smode] =
2632 SPECTRAL_REPORT_RX_PRIMARY80;
2633 else {
2634 status = QDF_STATUS_E_FAILURE;
2635 spectral->diag_stats.spectral_vhtseg1id_mismatch++;
2636 }
2637 break;
2638
2639 case SPECTRAL_REPORT_WAIT_SECONDARY80:
2640 if (detector_id == SPECTRAL_DETECTOR_ID_1)
2641 spectral->state_160mhz_delivery[smode] =
2642 SPECTRAL_REPORT_RX_SECONDARY80;
2643 else {
2644 spectral->state_160mhz_delivery[smode] =
2645 SPECTRAL_REPORT_WAIT_PRIMARY80;
2646 status = QDF_STATUS_E_FAILURE;
2647 spectral->diag_stats.spectral_vhtseg2id_mismatch++;
2648 }
2649 break;
2650
2651 case SPECTRAL_REPORT_RX_SECONDARY80:
2652 /* We don't care about detector id in this state. */
2653 reset_160mhz_delivery_state_machine(spectral, smode);
2654 break;
2655
2656 case SPECTRAL_REPORT_RX_PRIMARY80:
2657 /* We don't care about detector id in this state */
2658 spectral->state_160mhz_delivery[smode] =
2659 SPECTRAL_REPORT_WAIT_SECONDARY80;
2660 break;
2661
2662 default:
2663 break;
2664 }
2665
2666 return status;
2667 }
2668 #endif /* OPTIMIZED_SAMP_MESSAGE */
2669
2670 #ifdef DIRECT_BUF_RX_ENABLE
2671 /**
2672 * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector
2673 * ID from Spectral summary report
2674 * @data: Pointer to Spectral summary report
2675 * @detector_id: Pointer to detector id
2676 *
2677 * Return: QDF_STATUS
2678 */
2679 static QDF_STATUS
target_if_get_detector_id_sscan_summary_report_gen3(uint8_t * data,uint8_t * detector_id)2680 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data,
2681 uint8_t *detector_id)
2682 {
2683 struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
2684
2685 if (!data) {
2686 spectral_err("Argument(data) is null.");
2687 return QDF_STATUS_E_NULL_VALUE;
2688 }
2689
2690 psscan_summary_report =
2691 (struct spectral_sscan_summary_report_gen3 *)data;
2692
2693 *detector_id = get_bitfield(
2694 psscan_summary_report->hdr_a,
2695 SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
2696 SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
2697
2698 return QDF_STATUS_SUCCESS;
2699 }
2700
2701 #ifndef OPTIMIZED_SAMP_MESSAGE
2702 /**
2703 * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
2704 * report
2705 * @data: Pointer to Spectral summary report
2706 * @fields: Pointer to structure to be populated with extracted fields
2707 * @rparams: Pointer to structure with Spectral report params
2708 *
2709 * Consume Spectral summary report for gen3
2710 *
2711 * Return: void
2712 */
2713 static void
target_if_consume_sscan_summary_report_gen3(uint8_t * data,struct sscan_report_fields_gen3 * fields,struct spectral_report_params * rparams)2714 target_if_consume_sscan_summary_report_gen3(
2715 uint8_t *data,
2716 struct sscan_report_fields_gen3 *fields,
2717 struct spectral_report_params *rparams) {
2718 struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
2719
2720 if (!data || !fields || !rparams) {
2721 spectral_err("null arguments: data %pK, fields %pK, rparams %pK.",
2722 data, fields, rparams);
2723 return;
2724 }
2725
2726 psscan_summary_report =
2727 (struct spectral_sscan_summary_report_gen3 *)data;
2728
2729 fields->sscan_agc_total_gain = get_bitfield(
2730 psscan_summary_report->hdr_a,
2731 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
2732 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
2733 fields->inband_pwr_db = get_bitfield(
2734 psscan_summary_report->hdr_a,
2735 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
2736 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
2737 fields->sscan_pri80 = get_bitfield(
2738 psscan_summary_report->hdr_a,
2739 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
2740 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
2741
2742 switch (rparams->version) {
2743 case SPECTRAL_REPORT_FORMAT_VERSION_1:
2744 fields->sscan_gainchange = get_bitfield(
2745 psscan_summary_report->hdr_b,
2746 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
2747 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
2748 break;
2749 case SPECTRAL_REPORT_FORMAT_VERSION_2:
2750 fields->sscan_gainchange = get_bitfield(
2751 psscan_summary_report->hdr_c,
2752 SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
2753 SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
2754 break;
2755 default:
2756 spectral_err("Invalid spectral report format version: %d.",
2757 rparams->version);
2758 return;
2759 }
2760 }
2761 #endif
2762
2763 /**
2764 * target_if_verify_sig_and_tag_gen3() - Verify tag and signature
2765 * of spectral report
2766 * @spectral: Pointer to spectral object
2767 * @data: Pointer to spectral summary report
2768 * @exp_tag: iexpected tag value
2769 *
2770 * Process fft report for gen3
2771 *
2772 * Return: SUCCESS/FAILURE
2773 */
2774 static int
target_if_verify_sig_and_tag_gen3(struct target_if_spectral * spectral,uint8_t * data,uint8_t exp_tag)2775 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral,
2776 uint8_t *data, uint8_t exp_tag)
2777 {
2778 uint8_t tag = 0;
2779 uint8_t signature = 0;
2780 uint32_t lts;
2781
2782 lts = *((uint32_t *)(data + SPECTRAL_PHYERR_HDR_LTS_POS));
2783 /* Peek into the data to figure out whether
2784 * 1) Signature matches the expected value
2785 * 2) What is inside the package (TAG ID is used for finding this)
2786 */
2787 tag = get_bitfield(lts,
2788 SPECTRAL_REPORT_LTS_TAG_SIZE_GEN3,
2789 SPECTRAL_REPORT_LTS_TAG_POS_GEN3);
2790
2791 signature = get_bitfield(lts,
2792 SPECTRAL_REPORT_LTS_SIGNATURE_SIZE_GEN3,
2793 SPECTRAL_REPORT_LTS_SIGNATURE_POS_GEN3);
2794
2795
2796 if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
2797 spectral->diag_stats.spectral_mismatch++;
2798 return -EINVAL;
2799 }
2800
2801 if (tag != exp_tag) {
2802 spectral->diag_stats.spectral_mismatch++;
2803 return -EINVAL;
2804 }
2805
2806 return 0;
2807 }
2808
2809 static uint8_t
target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)2810 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask)
2811 {
2812 uint8_t idx;
2813
2814 for (idx = 0; idx < DBR_MAX_CHAINS; idx++) {
2815 if (chainmask & 0x1)
2816 break;
2817 chainmask >>= 1;
2818 }
2819 return idx;
2820 }
2821
2822 #ifdef DIRECT_BUF_RX_DEBUG
target_if_spectral_check_buffer_poisoning(struct target_if_spectral * spectral,struct spectral_report * report,int num_fft_bins,enum spectral_scan_mode smode)2823 static void target_if_spectral_check_buffer_poisoning(
2824 struct target_if_spectral *spectral,
2825 struct spectral_report *report,
2826 int num_fft_bins, enum spectral_scan_mode smode)
2827 {
2828 uint32_t *data;
2829 size_t len;
2830 size_t words_to_check =
2831 sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
2832 bool poisoned_words_found = false;
2833
2834 if (!spectral) {
2835 spectral_err_rl("Spectral LMAC object is null");
2836 return;
2837 }
2838
2839 if (!spectral->dbr_buff_debug)
2840 return;
2841
2842 if (!report) {
2843 spectral_err_rl("Spectral report is null");
2844 return;
2845 }
2846
2847 /* Add search FFT report */
2848 if (spectral->params[smode].ss_rpt_mode > 0)
2849 words_to_check +=
2850 sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
2851
2852 /* Now add the number of FFT bins */
2853 if (spectral->params[smode].ss_rpt_mode > 1) {
2854 /* Caller should take care to pass correct number of FFT bins */
2855 if (spectral->len_adj_swar.fftbin_size_war ==
2856 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE)
2857 words_to_check += num_fft_bins;
2858 else if (spectral->len_adj_swar.fftbin_size_war ==
2859 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE)
2860 words_to_check += (num_fft_bins >> 1);
2861 }
2862
2863 data = (uint32_t *)report->data;
2864 for (len = 0; len < words_to_check; ++len) {
2865 if (*data == MEM_POISON_SIGNATURE) {
2866 spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK",
2867 MEM_POISON_SIGNATURE,
2868 (len << 2), report->data);
2869 poisoned_words_found = true;
2870 break;
2871 }
2872 ++data;
2873 }
2874
2875 /* Crash the FW even if one word is poisoned */
2876 if (poisoned_words_found) {
2877 spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows",
2878 MEM_POISON_SIGNATURE);
2879 target_if_spectral_hexdump((unsigned char *)report->data,
2880 words_to_check << 2);
2881 spectral_err("Asserting the FW");
2882 target_if_spectral_fw_hang(spectral);
2883 }
2884 }
2885
2886 #ifdef OPTIMIZED_SAMP_MESSAGE
target_if_spectral_verify_ts(struct target_if_spectral * spectral,uint8_t * buf,uint32_t current_ts,uint8_t detector_id)2887 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2888 uint8_t *buf, uint32_t current_ts,
2889 uint8_t detector_id)
2890 {
2891 if (!spectral) {
2892 spectral_err_rl("Spectral LMAC object is null");
2893 return;
2894 }
2895 if (detector_id >= MAX_DETECTORS_PER_PDEV) {
2896 spectral_err_rl("Spectral detector_id %d exceeds range",
2897 detector_id);
2898 return;
2899 }
2900
2901 if (!spectral->dbr_buff_debug)
2902 return;
2903
2904 if (spectral->prev_tstamp[detector_id]) {
2905 if (current_ts == spectral->prev_tstamp[detector_id]) {
2906 spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
2907 current_ts, buf);
2908 target_if_spectral_fw_hang(spectral);
2909 }
2910 }
2911 spectral->prev_tstamp[detector_id] = current_ts;
2912 }
2913 #else
target_if_spectral_verify_ts(struct target_if_spectral * spectral,uint8_t * buf,uint32_t current_ts)2914 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2915 uint8_t *buf, uint32_t current_ts)
2916 {
2917 if (!spectral) {
2918 spectral_err_rl("Spectral LMAC object is null");
2919 return;
2920 }
2921
2922 if (!spectral->dbr_buff_debug)
2923 return;
2924
2925 if (spectral->prev_tstamp) {
2926 if (current_ts == spectral->prev_tstamp) {
2927 spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW",
2928 current_ts, buf);
2929 target_if_spectral_fw_hang(spectral);
2930 }
2931 }
2932 spectral->prev_tstamp = current_ts;
2933 }
2934 #endif /* OPTIMIZED_SAMP_MESSAGE */
2935 #else
target_if_spectral_check_buffer_poisoning(struct target_if_spectral * spectral,struct spectral_report * report,int num_fft_bins,enum spectral_scan_mode smode)2936 static void target_if_spectral_check_buffer_poisoning(
2937 struct target_if_spectral *spectral,
2938 struct spectral_report *report,
2939 int num_fft_bins, enum spectral_scan_mode smode)
2940 {
2941 }
2942
2943 #ifdef OPTIMIZED_SAMP_MESSAGE
target_if_spectral_verify_ts(struct target_if_spectral * spectral,uint8_t * buf,uint32_t current_ts,uint8_t detector_id)2944 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2945 uint8_t *buf, uint32_t current_ts,
2946 uint8_t detector_id)
2947 {
2948 }
2949 #else
target_if_spectral_verify_ts(struct target_if_spectral * spectral,uint8_t * buf,uint32_t current_ts)2950 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral,
2951 uint8_t *buf, uint32_t current_ts)
2952 {
2953 }
2954 #endif /* OPTIMIZED_SAMP_MESSAGE */
2955 #endif
2956
2957 /**
2958 * target_if_spectral_get_adjusted_timestamp() - Adjust Spectral time
2959 * stamp to account for reset in time stamp due to target reset
2960 * @twar: Spectral time stamp WAR related information
2961 * @raw_timestamp: Spectral time stamp reported by target
2962 * @reset_delay: Reset delay at target
2963 * @smode: Spectral scan mode
2964 * @tstamp: Pointer to adjusted timestamp
2965 *
2966 * Correct time stamp to account for reset in time stamp due to target reset
2967 *
2968 * Return: QDF_STATUS
2969 */
2970 static QDF_STATUS
target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war * twar,uint32_t raw_timestamp,uint32_t reset_delay,enum spectral_scan_mode smode,uint32_t * tstamp)2971 target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war *twar,
2972 uint32_t raw_timestamp,
2973 uint32_t reset_delay,
2974 enum spectral_scan_mode smode,
2975 uint32_t *tstamp)
2976 {
2977 if (smode >= SPECTRAL_SCAN_MODE_MAX) {
2978 spectral_err("Invalid spectral scan mode: %d", smode);
2979 return QDF_STATUS_E_INVAL;
2980 }
2981
2982 if (reset_delay) {
2983 enum spectral_scan_mode m =
2984 SPECTRAL_SCAN_MODE_NORMAL;
2985
2986 /* Adjust the offset for all the Spectral modes.
2987 * Target will be sending the non zero reset delay for
2988 * the first Spectral report after reset. This delay is
2989 * common for all the Spectral modes.
2990 */
2991 for (; m < SPECTRAL_SCAN_MODE_MAX; m++)
2992 twar->timestamp_war_offset[m] += (reset_delay +
2993 twar->last_fft_timestamp[m]);
2994 twar->target_reset_count++;
2995 }
2996 twar->last_fft_timestamp[smode] = raw_timestamp;
2997
2998 *tstamp = raw_timestamp + twar->timestamp_war_offset[smode];
2999
3000 return QDF_STATUS_SUCCESS;
3001 }
3002
3003 #ifdef BIG_ENDIAN_HOST
target_if_byte_swap_spectral_headers_gen3(struct target_if_spectral * spectral,void * data)3004 QDF_STATUS target_if_byte_swap_spectral_headers_gen3(
3005 struct target_if_spectral *spectral,
3006 void *data)
3007 {
3008 int i;
3009 uint32_t *ptr32;
3010 size_t words32;
3011
3012 if (!data || !spectral) {
3013 spectral_err_rl("null params: data %pK, spectral %pK.",
3014 data, spectral);
3015 return QDF_STATUS_E_NULL_VALUE;
3016 }
3017
3018 ptr32 = (uint32_t *)data;
3019
3020 /* Summary Report */
3021 words32 = sizeof(struct spectral_sscan_summary_report_gen3) >> 2;
3022 for (i = 0; i < words32; ++i) {
3023 *ptr32 = qdf_le32_to_cpu(*ptr32);
3024 ++ptr32;
3025 }
3026
3027 /* No need to swap the padding bytes */
3028 ptr32 += (spectral->rparams.ssummary_padding_bytes >> 2);
3029
3030 /* Search FFT Report */
3031 words32 = sizeof(struct spectral_phyerr_fft_report_gen3) >> 2;
3032 for (i = 0; i < words32; ++i) {
3033 *ptr32 = qdf_le32_to_cpu(*ptr32);
3034 ++ptr32;
3035 }
3036
3037 return QDF_STATUS_SUCCESS;
3038 }
3039
target_if_byte_swap_spectral_fft_bins_gen3(const struct spectral_report_params * rparams,void * bin_pwr_data,size_t num_fftbins)3040 QDF_STATUS target_if_byte_swap_spectral_fft_bins_gen3(
3041 const struct spectral_report_params *rparams,
3042 void *bin_pwr_data, size_t num_fftbins)
3043 {
3044 uint16_t dword_idx, num_dwords;
3045 uint8_t num_bins_per_dword;
3046 uint32_t *dword_ptr;
3047
3048 if (!bin_pwr_data || !rparams) {
3049 spectral_err_rl("null params, bin_pwr_data %pK, rparams %pK.",
3050 bin_pwr_data, rparams);
3051 return QDF_STATUS_E_NULL_VALUE;
3052 }
3053
3054 num_bins_per_dword = SPECTRAL_DWORD_SIZE / rparams->hw_fft_bin_width;
3055 num_dwords = num_fftbins / num_bins_per_dword;
3056 dword_ptr = (uint32_t *)bin_pwr_data;
3057
3058 for (dword_idx = 0; dword_idx < num_dwords; dword_idx++) {
3059 /* Read a DWORD, byteswap it, and copy it back */
3060 *dword_ptr = qdf_le32_to_cpu(*dword_ptr);
3061 ++dword_ptr;
3062 }
3063
3064 return QDF_STATUS_SUCCESS;
3065 }
3066 #endif /* BIG_ENDIAN_HOST */
3067
3068 #ifdef OPTIMIZED_SAMP_MESSAGE
3069 /**
3070 * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary
3071 * report
3072 * @data: Pointer to Spectral summary report
3073 * @fields: Pointer to structure to be populated with extracted fields
3074 * @spectral: Pointer to spectral object
3075 *
3076 * Consume Spectral summary report for gen3
3077 *
3078 * Return: QDF_STATUS
3079 */
3080 static QDF_STATUS
target_if_consume_sscan_summary_report_gen3(uint8_t ** data,struct sscan_report_fields_gen3 * fields,struct target_if_spectral * spectral)3081 target_if_consume_sscan_summary_report_gen3(
3082 uint8_t **data,
3083 struct sscan_report_fields_gen3 *fields,
3084 struct target_if_spectral *spectral)
3085 {
3086 struct spectral_sscan_summary_report_gen3 *psscan_summary_report;
3087 struct spectral_sscan_summary_report_padding_gen3_v2 *padding;
3088 bool scan_radio_blanking;
3089 QDF_STATUS ret;
3090 uint8_t dtr_id;
3091
3092 if (!data) {
3093 spectral_err_rl("Summary report buffer is null");
3094 return QDF_STATUS_E_NULL_VALUE;
3095 }
3096
3097 if (!fields) {
3098 spectral_err_rl("Invalid pointer to Summary report fields");
3099 return QDF_STATUS_E_NULL_VALUE;
3100 }
3101
3102 if (!spectral) {
3103 spectral_err_rl("Spectral LMAC object is null");
3104 return QDF_STATUS_E_NULL_VALUE;
3105 }
3106
3107 /* Validate Spectral scan summary report */
3108 if (target_if_verify_sig_and_tag_gen3(
3109 spectral, *data,
3110 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
3111 spectral_err_rl("Wrong tag/sig in sscan summary");
3112 return QDF_STATUS_E_FAILURE;
3113 }
3114
3115 ret = target_if_get_detector_id_sscan_summary_report_gen3(*data,
3116 &dtr_id);
3117 if (QDF_IS_STATUS_ERROR(ret))
3118 return QDF_STATUS_E_FAILURE;
3119
3120 fields->sscan_detector_id = dtr_id;
3121 if (fields->sscan_detector_id >=
3122 spectral->rparams.num_spectral_detectors) {
3123 spectral->diag_stats.spectral_invalid_detector_id++;
3124 spectral_err_rl("Invalid detector id %u, expected is 0 to %u",
3125 fields->sscan_detector_id,
3126 spectral->rparams.num_spectral_detectors);
3127 return QDF_STATUS_E_FAILURE;
3128 }
3129
3130 psscan_summary_report =
3131 (struct spectral_sscan_summary_report_gen3 *)*data;
3132
3133 fields->sscan_agc_total_gain = get_bitfield(
3134 psscan_summary_report->hdr_a,
3135 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3,
3136 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3);
3137 fields->inband_pwr_db = get_bitfield(
3138 psscan_summary_report->hdr_a,
3139 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3,
3140 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3);
3141 fields->sscan_pri80 = get_bitfield(
3142 psscan_summary_report->hdr_a,
3143 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3,
3144 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3);
3145
3146 switch (spectral->rparams.version) {
3147 case SPECTRAL_REPORT_FORMAT_VERSION_1:
3148 fields->sscan_gainchange = get_bitfield(
3149 psscan_summary_report->hdr_b,
3150 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1,
3151 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1);
3152 break;
3153 case SPECTRAL_REPORT_FORMAT_VERSION_2:
3154 fields->sscan_gainchange = get_bitfield(
3155 psscan_summary_report->hdr_c,
3156 SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2,
3157 SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2);
3158 break;
3159 default:
3160 spectral_err_rl("Invalid spectral version: %d.",
3161 spectral->rparams.version);
3162 return QDF_STATUS_E_INVAL;
3163 }
3164
3165 /* Advance buf pointer to the search fft report */
3166 *data += sizeof(struct spectral_sscan_summary_report_gen3);
3167
3168 if (!spectral->rparams.ssummary_padding_bytes)
3169 return QDF_STATUS_SUCCESS;
3170
3171 scan_radio_blanking =
3172 wlan_pdev_nif_feat_ext_cap_get(spectral->pdev_obj,
3173 WLAN_PDEV_FEXT_SCAN_BLANKING_EN);
3174 padding = (struct spectral_sscan_summary_report_padding_gen3_v2 *)*data;
3175
3176 if (scan_radio_blanking) {
3177 uint32_t blanking_tag;
3178 uint8_t blanking_tag_size;
3179 uint8_t blanking_tag_pos;
3180
3181 blanking_tag_size =
3182 SSCAN_SUMMARY_REPORT_PAD_HDR_A_BLANKING_SIZE_GEN3_V2;
3183 blanking_tag_pos =
3184 SSCAN_SUMMARY_REPORT_PAD_HDR_A_BLANKING_POS_GEN3_V2;
3185 blanking_tag = get_bitfield(padding->hdr_a, blanking_tag_size,
3186 blanking_tag_pos);
3187
3188 if (blanking_tag ==
3189 SSCAN_SUMMARY_REPORT_PAD_HDR_A_BLANKING_TAG_GEN3_V2)
3190 fields->blanking_status = 1;
3191 else
3192 fields->blanking_status = 0;
3193 }
3194
3195 *data += sizeof(struct spectral_sscan_summary_report_padding_gen3_v2);
3196
3197 return QDF_STATUS_SUCCESS;
3198 }
3199
3200 /**
3201 * target_if_process_sfft_report_gen3() - Validate and Process Search
3202 * FFT Report for gen3
3203 * @data: Pointer to Spectral FFT report
3204 * @p_sfft: Pointer to search fft report
3205 * @spectral: Pointer to spectral object
3206 * @sscan_detector_id: Spectral detector id extracted from Summary report
3207 * @reset_delay: Time taken for warm reset in usec
3208 *
3209 * Validate and Process Search FFT Report for gen3
3210 *
3211 * Return: Success/Failure
3212 */
3213 static QDF_STATUS
target_if_process_sfft_report_gen3(uint8_t * data,struct spectral_search_fft_info_gen3 * p_sfft,struct target_if_spectral * spectral,enum spectral_detector_id sscan_detector_id,uint32_t reset_delay)3214 target_if_process_sfft_report_gen3(
3215 uint8_t *data,
3216 struct spectral_search_fft_info_gen3 *p_sfft,
3217 struct target_if_spectral *spectral,
3218 enum spectral_detector_id sscan_detector_id,
3219 uint32_t reset_delay)
3220 {
3221 struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3222 int32_t peak_sidx = 0;
3223 int32_t peak_mag;
3224 int fft_hdr_length = 0;
3225 uint32_t tstamp;
3226 struct target_if_spectral_ops *p_sops;
3227 enum spectral_scan_mode spectral_mode;
3228 QDF_STATUS ret;
3229
3230 if (!data) {
3231 spectral_err_rl("FFT report buffer is null");
3232 return QDF_STATUS_E_NULL_VALUE;
3233 }
3234
3235 if (!p_sfft) {
3236 spectral_err_rl("Invalid pointer to Search FFT report info");
3237 return QDF_STATUS_E_NULL_VALUE;
3238 }
3239
3240 if (!spectral) {
3241 spectral_err_rl("Spectral LMAC object is null");
3242 return QDF_STATUS_E_NULL_VALUE;
3243 }
3244
3245 /*
3246 * For easy comparison between MDK team and OS team, the MDK script
3247 * variable names have been used
3248 */
3249
3250 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3251
3252 /* Validate Spectral search FFT report */
3253 if (target_if_verify_sig_and_tag_gen3(
3254 spectral, data, TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3255 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3256 sscan_detector_id);
3257 return QDF_STATUS_E_FAILURE;
3258 }
3259
3260 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3261
3262 fft_hdr_length = get_bitfield(
3263 p_fft_report->fft_hdr_lts,
3264 SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3265 SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3266 if (fft_hdr_length < 16) {
3267 spectral_err("Wrong TLV length %u, detector id = %d",
3268 fft_hdr_length, sscan_detector_id);
3269 return QDF_STATUS_E_FAILURE;
3270 }
3271
3272 p_sfft->fft_detector_id = get_bitfield(
3273 p_fft_report->hdr_a,
3274 FFT_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3,
3275 FFT_REPORT_HDR_A_DETECTOR_ID_POS_GEN3);
3276
3277 /* It is expected to have same detector id for
3278 * summary and fft report
3279 */
3280 if (sscan_detector_id != p_sfft->fft_detector_id) {
3281 spectral_err_rl("Different detid in ssummary(%u) and sfft(%u)",
3282 sscan_detector_id, p_sfft->fft_detector_id);
3283 return QDF_STATUS_E_FAILURE;
3284 }
3285
3286 if (p_sfft->fft_detector_id >
3287 spectral->rparams.num_spectral_detectors) {
3288 spectral->diag_stats.spectral_invalid_detector_id++;
3289 spectral_err("Invalid detector id %u, expected is 0 to %u",
3290 p_sfft->fft_detector_id,
3291 spectral->rparams.num_spectral_detectors);
3292 return QDF_STATUS_E_FAILURE;
3293 }
3294
3295 spectral_mode = target_if_get_spectral_mode(p_sfft->fft_detector_id,
3296 &spectral->rparams);
3297 if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3298 spectral_err_rl("No valid Spectral mode for detector id %u",
3299 p_sfft->fft_detector_id);
3300 return QDF_STATUS_E_FAILURE;
3301 }
3302
3303 /* Populate the Search FFT Info */
3304 p_sfft->timestamp = p_fft_report->fft_timestamp;
3305 p_sfft->last_raw_timestamp = spectral->timestamp_war.
3306 last_fft_timestamp[spectral_mode];
3307 ret = target_if_spectral_get_adjusted_timestamp(
3308 &spectral->timestamp_war,
3309 p_sfft->timestamp,
3310 reset_delay,
3311 spectral_mode,
3312 &tstamp);
3313
3314 if (QDF_IS_STATUS_ERROR(ret))
3315 return QDF_STATUS_E_FAILURE;
3316
3317 p_sfft->adjusted_timestamp = tstamp;
3318 /* Timestamp verification */
3319 target_if_spectral_verify_ts(spectral, data,
3320 p_sfft->adjusted_timestamp,
3321 p_sfft->fft_detector_id);
3322
3323
3324 p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a,
3325 FFT_REPORT_HDR_A_FFT_NUM_SIZE_GEN3,
3326 FFT_REPORT_HDR_A_FFT_NUM_POS_GEN3);
3327
3328 switch (spectral->rparams.version) {
3329 case SPECTRAL_REPORT_FORMAT_VERSION_1:
3330 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
3331 FFT_REPORT_HDR_A_RADAR_CHECK_SIZE_GEN3_V1,
3332 FFT_REPORT_HDR_A_RADAR_CHECK_POS_GEN3_V1);
3333 peak_sidx = get_bitfield(
3334 p_fft_report->hdr_a,
3335 FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V1,
3336 FFT_REPORT_HDR_A_PEAK_INDEX_POS_GEN3_V1);
3337 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a,
3338 FFT_REPORT_HDR_A_CHAIN_INDEX_SIZE_GEN3_V1,
3339 FFT_REPORT_HDR_A_CHAIN_INDEX_POS_GEN3_V1);
3340 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
3341 FFT_REPORT_HDR_B_BASE_PWR_SIZE_GEN3_V1,
3342 FFT_REPORT_HDR_B_BASE_PWR_POS_GEN3_V1);
3343 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
3344 FFT_REPORT_HDR_B_TOTAL_GAIN_SIZE_GEN3_V1,
3345 FFT_REPORT_HDR_B_TOTAL_GAIN_POS_GEN3_V1);
3346 break;
3347 case SPECTRAL_REPORT_FORMAT_VERSION_2:
3348 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a,
3349 FFT_REPORT_HDR_A_RADAR_CHECK_SIZE_GEN3_V2,
3350 FFT_REPORT_HDR_A_RADAR_CHECK_POS_GEN3_V2);
3351 peak_sidx = get_bitfield(
3352 p_fft_report->hdr_a,
3353 FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V2,
3354 FFT_REPORT_HDR_A_PEAK_INDEX_POS_GEN3_V2);
3355 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_b,
3356 FFT_REPORT_HDR_B_CHAIN_INDEX_SIZE_GEN3_V2,
3357 FFT_REPORT_HDR_B_CHAIN_INDEX_POS_GEN3_V2);
3358 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b,
3359 FFT_REPORT_HDR_B_BASE_PWR_SIZE_GEN3_V2,
3360 FFT_REPORT_HDR_B_BASE_PWR_POS_GEN3_V2);
3361 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b,
3362 FFT_REPORT_HDR_B_TOTAL_GAIN_SIZE_GEN3_V2,
3363 FFT_REPORT_HDR_B_TOTAL_GAIN_POS_GEN3_V2);
3364 break;
3365 default:
3366 spectral_err_rl("Invalid spectral version: %d.",
3367 spectral->rparams.version);
3368 return QDF_STATUS_E_INVAL;
3369 }
3370
3371 p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx,
3372 FFT_REPORT_HDR_A_PEAK_INDEX_SIZE_GEN3_V1);
3373
3374 p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c,
3375 FFT_REPORT_HDR_C_NUM_STRONG_BINS_SIZE_GEN3,
3376 FFT_REPORT_HDR_C_NUM_STRONG_BINS_POS_GEN3);
3377 peak_mag = get_bitfield(p_fft_report->hdr_c,
3378 FFT_REPORT_HDR_C_PEAK_MAGNITUDE_SIZE_GEN3,
3379 FFT_REPORT_HDR_C_PEAK_MAGNITUDE_POS_GEN3);
3380 p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag,
3381 FFT_REPORT_HDR_C_PEAK_MAGNITUDE_SIZE_GEN3);
3382 p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c,
3383 FFT_REPORT_HDR_C_AVG_PWR_SIZE_GEN3,
3384 FFT_REPORT_HDR_C_AVG_PWR_POS_GEN3);
3385 p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c,
3386 FFT_REPORT_HDR_C_RELATIVE_PWR_SIZE_GEN3,
3387 FFT_REPORT_HDR_C_RELATIVE_PWR_POS_GEN3);
3388
3389 p_sfft->fft_bin_count =
3390 target_if_spectral_get_bin_count_after_len_adj(
3391 fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3392 spectral->params[spectral_mode].ss_rpt_mode,
3393 &spectral->len_adj_swar,
3394 (size_t *)&p_sfft->fft_bin_size);
3395
3396 p_sfft->bin_pwr_data = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
3397
3398 /* Apply byte-swap on the FFT bins.
3399 * NOTE: Until this point, bytes of the FFT bins could be in
3400 * reverse order on a big-endian machine. If the consumers
3401 * of FFT bins expects bytes in the correct order,
3402 * they should use them only after this point.
3403 */
3404 if (p_sops->byte_swap_fft_bins) {
3405 ret = p_sops->byte_swap_fft_bins(&spectral->rparams,
3406 &p_sfft->bin_pwr_data,
3407 p_sfft->fft_bin_count);
3408 if (QDF_IS_STATUS_ERROR(ret)) {
3409 spectral_err_rl("Byte-swap on the FFT bins failed");
3410 return QDF_STATUS_E_FAILURE;
3411 }
3412 }
3413
3414 return QDF_STATUS_SUCCESS;
3415 }
3416
3417 /**
3418 * target_if_spectral_populate_samp_params_gen3() - Populate the SAMP params
3419 * for gen3. SAMP params are to be used for populating SAMP msg.
3420 * @spectral: Pointer to spectral object
3421 * @p_sfft: Fields extracted from FFT report
3422 * @sscan_fields: Fields extracted from Summary report
3423 * @report: Pointer to spectral report
3424 * @params: Pointer to Spectral SAMP message fields to be populated
3425 *
3426 * Populate the SAMP params for gen3, which will be used to populate SAMP msg.
3427 *
3428 * Return: Success/Failure
3429 */
3430 static QDF_STATUS
target_if_spectral_populate_samp_params_gen3(struct target_if_spectral * spectral,struct spectral_search_fft_info_gen3 * p_sfft,struct sscan_report_fields_gen3 * sscan_fields,struct spectral_report * report,struct target_if_samp_msg_params * params)3431 target_if_spectral_populate_samp_params_gen3(
3432 struct target_if_spectral *spectral,
3433 struct spectral_search_fft_info_gen3 *p_sfft,
3434 struct sscan_report_fields_gen3 *sscan_fields,
3435 struct spectral_report *report,
3436 struct target_if_samp_msg_params *params)
3437 {
3438 enum spectral_scan_mode spectral_mode;
3439 uint8_t chn_idx_lowest_enabled;
3440 struct wlan_objmgr_vdev *vdev;
3441 uint8_t vdev_rxchainmask;
3442
3443 if (!p_sfft) {
3444 spectral_err_rl("Invalid pointer to Search FFT report info");
3445 return QDF_STATUS_E_NULL_VALUE;
3446 }
3447 if (!spectral) {
3448 spectral_err_rl("Spectral LMAC object is null");
3449 return QDF_STATUS_E_NULL_VALUE;
3450 }
3451 if (!sscan_fields) {
3452 spectral_err_rl("Invalid pointer to Summary report fields");
3453 return QDF_STATUS_E_NULL_VALUE;
3454 }
3455 if (!report) {
3456 spectral_err_rl("Spectral report is null");
3457 return QDF_STATUS_E_NULL_VALUE;
3458 }
3459 if (!params) {
3460 spectral_err_rl("SAMP msg params structure is null");
3461 return QDF_STATUS_E_NULL_VALUE;
3462 }
3463
3464 /* RSSI is in 1/2 dBm steps, Convert it to dBm scale */
3465 params->rssi = (sscan_fields->inband_pwr_db) >> 1;
3466
3467 params->hw_detector_id = p_sfft->fft_detector_id;
3468 params->raw_timestamp = p_sfft->timestamp;
3469 params->last_raw_timestamp = p_sfft->last_raw_timestamp;
3470 params->timestamp = p_sfft->adjusted_timestamp;
3471 params->reset_delay = report->reset_delay;
3472
3473 params->max_mag = p_sfft->fft_peak_mag;
3474
3475 spectral_mode = target_if_get_spectral_mode(params->hw_detector_id,
3476 &spectral->rparams);
3477 vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3478 if (!vdev) {
3479 spectral_debug("First vdev is NULL");
3480 return QDF_STATUS_E_FAILURE;
3481 }
3482 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3483 if (vdev_rxchainmask == 0) {
3484 spectral_err("Vdev rxchainmask is zero.");
3485 return QDF_STATUS_E_FAILURE;
3486 }
3487 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3488
3489 chn_idx_lowest_enabled =
3490 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3491 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3492 spectral_err("Invalid chain index, detector id = %u",
3493 params->hw_detector_id);
3494 return QDF_STATUS_E_FAILURE;
3495 }
3496 params->noise_floor = report->noisefloor[chn_idx_lowest_enabled];
3497 params->agc_total_gain = sscan_fields->sscan_agc_total_gain;
3498 params->gainchange = sscan_fields->sscan_gainchange;
3499 params->blanking_status = sscan_fields->blanking_status;
3500 params->pri80ind = sscan_fields->sscan_pri80;
3501
3502 params->bin_pwr_data = p_sfft->bin_pwr_data;
3503
3504 return QDF_STATUS_SUCCESS;
3505 }
3506
3507 int
target_if_consume_spectral_report_gen3(struct target_if_spectral * spectral,struct spectral_report * report)3508 target_if_consume_spectral_report_gen3(
3509 struct target_if_spectral *spectral,
3510 struct spectral_report *report)
3511 {
3512 /*
3513 * XXX : The classifier do not use all the members of the SAMP
3514 * message data format.
3515 * The classifier only depends upon the following parameters
3516 *
3517 * 1. Frequency
3518 * 2. Spectral RSSI
3519 * 3. Bin Power Count
3520 * 4. Bin Power values
3521 * 5. Spectral Timestamp
3522 * 6. MAC Address
3523 *
3524 * This function processes the Spectral summary and FFT reports
3525 * and passes the processed information
3526 * target_if_spectral_fill_samp_msg()
3527 * to prepare fully formatted Spectral SAMP message
3528 *
3529 * XXX : Need to verify
3530 * 1. Order of FFT bin values
3531 *
3532 */
3533 struct target_if_samp_msg_params params = {0};
3534 struct spectral_search_fft_info_gen3 search_fft_info;
3535 struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
3536 struct target_if_spectral_ops *p_sops;
3537 struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3538 uint8_t *data;
3539 struct sscan_report_fields_gen3 sscan_report_fields = {0};
3540 QDF_STATUS ret;
3541 enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
3542 bool finite_scan = false;
3543 int det = 0;
3544 struct sscan_detector_list *det_list;
3545 struct spectral_data_stats *spectral_dp_stats;
3546 bool print_fail_msg = true;
3547
3548 if (!spectral) {
3549 spectral_err_rl("Spectral LMAC object is null");
3550 print_fail_msg = false;
3551 goto fail;
3552 }
3553
3554 qdf_spin_lock_bh(&spectral->spectral_lock);
3555 spectral_dp_stats = &spectral->data_stats;
3556 spectral_dp_stats->consume_spectral_calls++;
3557
3558 if (!report) {
3559 spectral_err_rl("Spectral report is null");
3560 print_fail_msg = false;
3561 goto fail_unlock;
3562 }
3563
3564 p_sops = GET_TARGET_IF_SPECTRAL_OPS(spectral);
3565 data = report->data;
3566
3567 /* Apply byte-swap on the headers */
3568 if (p_sops->byte_swap_headers) {
3569 ret = p_sops->byte_swap_headers(spectral, data);
3570 if (QDF_IS_STATUS_ERROR(ret)) {
3571 spectral_err_rl("Byte-swap on Spectral headers failed");
3572 goto fail_unlock;
3573 }
3574 }
3575
3576 /* Validate and Process Spectral scan summary report */
3577 ret = target_if_consume_sscan_summary_report_gen3(&data,
3578 &sscan_report_fields,
3579 spectral);
3580 if (QDF_IS_STATUS_ERROR(ret)) {
3581 spectral_err_rl("Failed to process Spectral summary report");
3582 goto fail_unlock;
3583 }
3584
3585 spectral_mode = target_if_get_spectral_mode(
3586 sscan_report_fields.sscan_detector_id,
3587 &spectral->rparams);
3588 if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3589 spectral_err_rl("No valid Spectral mode for detector id %u",
3590 sscan_report_fields.sscan_detector_id);
3591 goto fail_unlock;
3592 }
3593
3594 /* Drop the sample if Spectral is not active for the current mode */
3595 if (!p_sops->is_spectral_active(spectral, spectral_mode)) {
3596 spectral_info_rl("Spectral scan is not active");
3597 print_fail_msg = false;
3598 goto fail_unlock;
3599 }
3600
3601 /* Validate and Process the search FFT report */
3602 ret = target_if_process_sfft_report_gen3(
3603 data, p_sfft,
3604 spectral,
3605 sscan_report_fields.sscan_detector_id,
3606 report->reset_delay);
3607 if (QDF_IS_STATUS_ERROR(ret)) {
3608 spectral_err_rl("Failed to process search FFT report");
3609 goto fail_unlock;
3610 }
3611
3612 qdf_spin_lock_bh(&spectral->detector_list_lock);
3613 det_list = &spectral->detector_list[spectral_mode]
3614 [spectral->report_info[spectral_mode].sscan_bw];
3615 for (det = 0; det < det_list->num_detectors; det++) {
3616 if (p_sfft->fft_detector_id == det_list->detectors[det])
3617 break;
3618 if (det == det_list->num_detectors - 1) {
3619 qdf_spin_unlock_bh(&spectral->detector_list_lock);
3620 spectral_info("Incorrect det id %d for given scan mode and channel width",
3621 p_sfft->fft_detector_id);
3622 print_fail_msg = false;
3623 goto fail_unlock;
3624 }
3625 }
3626 qdf_spin_unlock_bh(&spectral->detector_list_lock);
3627
3628 ret = target_if_update_session_info_from_report_ctx(
3629 spectral,
3630 p_sfft->fft_bin_size,
3631 report->cfreq1, report->cfreq2,
3632 spectral_mode);
3633 if (QDF_IS_STATUS_ERROR(ret)) {
3634 spectral_err_rl("Failed to update per-session info");
3635 goto fail_unlock;
3636 }
3637
3638 qdf_spin_lock_bh(&spectral->session_report_info_lock);
3639 /* Check FFT report are in order for 160 MHz and 80p80 */
3640 if (is_ch_width_160_or_80p80(
3641 spectral->report_info[spectral_mode].sscan_bw) &&
3642 spectral->rparams.fragmentation_160[spectral_mode]) {
3643 ret = target_if_160mhz_delivery_state_change(
3644 spectral, spectral_mode,
3645 p_sfft->fft_detector_id);
3646 if (ret != QDF_STATUS_SUCCESS) {
3647 qdf_spin_unlock_bh(
3648 &spectral->session_report_info_lock);
3649 goto fail_unlock;
3650 }
3651 }
3652 qdf_spin_unlock_bh(&spectral->session_report_info_lock);
3653
3654 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3655 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
3656 target_if_dump_fft_report_gen3(spectral, spectral_mode,
3657 p_fft_report, p_sfft);
3658
3659 target_if_spectral_check_buffer_poisoning(spectral, report,
3660 p_sfft->fft_bin_count,
3661 spectral_mode);
3662
3663 /* Populate SAMP params */
3664 ret = target_if_spectral_populate_samp_params_gen3(
3665 spectral, p_sfft,
3666 &sscan_report_fields,
3667 report, ¶ms);
3668 if (QDF_IS_STATUS_ERROR(ret)) {
3669 spectral_err_rl("Failed to populate SAMP params");
3670 goto fail_unlock;
3671 }
3672
3673 /* Fill SAMP message */
3674 ret = target_if_spectral_fill_samp_msg(spectral, ¶ms);
3675 if (QDF_IS_STATUS_ERROR(ret)) {
3676 spectral_err_rl("Failed to fill the SAMP msg");
3677 goto fail_unlock;
3678 }
3679
3680 qdf_spin_unlock_bh(&spectral->spectral_lock);
3681 ret = target_if_spectral_is_finite_scan(spectral, spectral_mode,
3682 &finite_scan);
3683 if (QDF_IS_STATUS_ERROR(ret)) {
3684 spectral_err_rl("Failed to check scan is finite");
3685 goto fail;
3686 }
3687
3688 if (finite_scan) {
3689 ret = target_if_spectral_finite_scan_update(spectral,
3690 spectral_mode);
3691 if (QDF_IS_STATUS_ERROR(ret)) {
3692 spectral_err_rl("Failed to update scan count");
3693 goto fail;
3694 }
3695 }
3696
3697 return 0;
3698 fail_unlock:
3699 qdf_spin_unlock_bh(&spectral->spectral_lock);
3700 fail:
3701 if (print_fail_msg)
3702 spectral_err_rl("Error while processing Spectral report");
3703
3704 if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
3705 reset_160mhz_delivery_state_machine(spectral, spectral_mode);
3706 return -EPERM;
3707 }
3708
3709 #else
3710 int
target_if_consume_spectral_report_gen3(struct target_if_spectral * spectral,struct spectral_report * report)3711 target_if_consume_spectral_report_gen3(
3712 struct target_if_spectral *spectral,
3713 struct spectral_report *report)
3714 {
3715 /*
3716 * XXX : The classifier do not use all the members of the SAMP
3717 * message data format.
3718 * The classifier only depends upon the following parameters
3719 *
3720 * 1. Frequency (freq, msg->freq)
3721 * 2. Spectral RSSI (spectral_rssi,
3722 * msg->samp_data.spectral_rssi)
3723 * 3. Bin Power Count (bin_pwr_count,
3724 * msg->samp_data.bin_pwr_count)
3725 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
3726 * 5. Spectral Timestamp (spectral_tstamp,
3727 * msg->samp_data.spectral_tstamp)
3728 * 6. MAC Address (macaddr, msg->macaddr)
3729 *
3730 * This function prepares the params structure and populates it
3731 * with
3732 * relevant values, this is in turn passed to
3733 * spectral_create_samp_msg()
3734 * to prepare fully formatted Spectral SAMP message
3735 *
3736 * XXX : Need to verify
3737 * 1. Order of FFT bin values
3738 *
3739 */
3740 struct target_if_samp_msg_params params = {0};
3741 struct spectral_search_fft_info_gen3 search_fft_info;
3742 struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
3743 int8_t chn_idx_lowest_enabled = 0;
3744 int fft_hdr_length = 0;
3745 int report_len = 0;
3746 size_t fft_bin_count;
3747 size_t fft_bin_size;
3748 struct target_if_spectral_ops *p_sops =
3749 GET_TARGET_IF_SPECTRAL_OPS(spectral);
3750 struct spectral_phyerr_fft_report_gen3 *p_fft_report;
3751 int8_t rssi;
3752 uint8_t *data = report->data;
3753 struct wlan_objmgr_vdev *vdev;
3754 uint8_t vdev_rxchainmask;
3755 struct sscan_report_fields_gen3 sscan_report_fields = {0};
3756 enum spectral_detector_id detector_id;
3757 uint8_t dtr_id;
3758 QDF_STATUS ret;
3759 enum spectral_scan_mode spectral_mode = SPECTRAL_SCAN_MODE_INVALID;
3760 uint8_t *temp;
3761 bool finite_scan = false;
3762 uint32_t tstamp;
3763
3764 /* Apply byte-swap on the headers */
3765 if (p_sops->byte_swap_headers) {
3766 ret = p_sops->byte_swap_headers(spectral, data);
3767 if (QDF_IS_STATUS_ERROR(ret)) {
3768 spectral_err_rl("Byte-swap on Spectral headers failed");
3769 goto fail;
3770 }
3771 }
3772
3773 /* Process Spectral scan summary report */
3774 if (target_if_verify_sig_and_tag_gen3(
3775 spectral, data,
3776 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) {
3777 spectral_err_rl("Wrong tag/sig in sscan summary");
3778 goto fail;
3779 }
3780
3781 ret = target_if_get_detector_id_sscan_summary_report_gen3(data,
3782 &dtr_id);
3783 if (QDF_IS_STATUS_ERROR(ret))
3784 goto fail;
3785
3786 detector_id = dtr_id;
3787 if (detector_id >= spectral->rparams.num_spectral_detectors) {
3788 spectral->diag_stats.spectral_invalid_detector_id++;
3789 spectral_err("Invalid detector id %u, expected is 0/1/2",
3790 detector_id);
3791 goto fail;
3792 }
3793
3794 spectral_mode = target_if_get_spectral_mode(detector_id,
3795 &spectral->rparams);
3796 if (spectral_mode >= SPECTRAL_SCAN_MODE_MAX) {
3797 spectral_err_rl("No valid Spectral mode for detector id %u",
3798 detector_id);
3799 goto fail;
3800 }
3801
3802 /* Drop the sample if Spectral is not active for the current mode */
3803 if (!p_sops->is_spectral_active(spectral, spectral_mode)) {
3804 spectral_info_rl("Spectral scan is not active");
3805 goto fail_no_print;
3806 }
3807
3808 ret = target_if_spectral_is_finite_scan(spectral, spectral_mode,
3809 &finite_scan);
3810 if (QDF_IS_STATUS_ERROR(ret)) {
3811 spectral_err_rl("Failed to check scan is finite");
3812 goto fail;
3813 }
3814
3815 if (finite_scan) {
3816 ret = target_if_spectral_finite_scan_update(spectral,
3817 spectral_mode);
3818 if (QDF_IS_STATUS_ERROR(ret)) {
3819 spectral_err_rl("Failed to update scan count");
3820 goto fail;
3821 }
3822 }
3823
3824 target_if_consume_sscan_summary_report_gen3(data, &sscan_report_fields,
3825 &spectral->rparams);
3826 /* Advance buf pointer to the search fft report */
3827 data += sizeof(struct spectral_sscan_summary_report_gen3);
3828 data += spectral->rparams.ssummary_padding_bytes;
3829 params.vhtop_ch_freq_seg1 = report->cfreq1;
3830 params.vhtop_ch_freq_seg2 = report->cfreq2;
3831
3832 if (is_primaryseg_expected(spectral, spectral_mode)) {
3833 /* RSSI is in 1/2 dBm steps, Convert it to dBm scale */
3834 rssi = (sscan_report_fields.inband_pwr_db) >> 1;
3835 params.agc_total_gain =
3836 sscan_report_fields.sscan_agc_total_gain;
3837 params.gainchange = sscan_report_fields.sscan_gainchange;
3838 params.pri80ind = sscan_report_fields.sscan_pri80;
3839
3840 /* Process Spectral search FFT report */
3841 if (target_if_verify_sig_and_tag_gen3(
3842 spectral, data,
3843 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
3844 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
3845 detector_id);
3846 goto fail;
3847 }
3848 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
3849 fft_hdr_length = get_bitfield(
3850 p_fft_report->fft_hdr_lts,
3851 SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
3852 SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
3853 if (fft_hdr_length < 16) {
3854 spectral_err("Wrong TLV length %u, detector id = %d",
3855 fft_hdr_length, detector_id);
3856 goto fail;
3857 }
3858
3859 report_len = (fft_hdr_length + 8);
3860
3861 target_if_process_sfft_report_gen3(p_fft_report, p_sfft,
3862 &spectral->rparams);
3863 /* It is expected to have same detector id for
3864 * summary and fft report
3865 */
3866 if (detector_id != p_sfft->fft_detector_id) {
3867 spectral_err_rl
3868 ("Different detid in ssummary(%u) and sfft(%u)",
3869 detector_id, p_sfft->fft_detector_id);
3870 goto fail;
3871 }
3872
3873 if (detector_id > spectral->rparams.num_spectral_detectors) {
3874 spectral->diag_stats.spectral_invalid_detector_id++;
3875 spectral_err("Invalid detector id %u, expected is 0/2",
3876 detector_id);
3877 goto fail;
3878 }
3879 params.smode = spectral_mode;
3880
3881 fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
3882 fft_hdr_length - spectral->rparams.fft_report_hdr_len,
3883 spectral->params[spectral_mode].ss_rpt_mode,
3884 &spectral->len_adj_swar, &fft_bin_size);
3885
3886 params.last_raw_timestamp = spectral->timestamp_war.
3887 last_fft_timestamp[spectral_mode];
3888 params.reset_delay = report->reset_delay;
3889 params.raw_timestamp = p_sfft->timestamp;
3890 ret = target_if_spectral_get_adjusted_timestamp(
3891 &spectral->timestamp_war,
3892 p_sfft->timestamp, report->reset_delay,
3893 spectral_mode, &tstamp);
3894 if (QDF_IS_STATUS_ERROR(ret))
3895 goto fail;
3896
3897 params.tstamp = tstamp;
3898 params.timestamp_war_offset = spectral->timestamp_war.
3899 timestamp_war_offset[spectral_mode];
3900 params.target_reset_count = spectral->timestamp_war.
3901 target_reset_count;
3902
3903 /* Take care of state transitions for 160 MHz and 80p80 */
3904 if (is_ch_width_160_or_80p80(spectral->ch_width
3905 [spectral_mode]) && spectral->rparams.
3906 fragmentation_160[spectral_mode]) {
3907 ret = target_if_160mhz_delivery_state_change(
3908 spectral, spectral_mode,
3909 detector_id);
3910 if (ret != QDF_STATUS_SUCCESS)
3911 goto fail;
3912 }
3913
3914 params.rssi = rssi;
3915
3916 vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
3917 if (!vdev) {
3918 spectral_debug("First vdev is NULL");
3919 reset_160mhz_delivery_state_machine(
3920 spectral, spectral_mode);
3921 return -EPERM;
3922 }
3923 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
3924 if (vdev_rxchainmask == 0) {
3925 spectral_err("Vdev rxchainmask is zero.");
3926 goto fail;
3927 }
3928 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
3929
3930 chn_idx_lowest_enabled =
3931 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
3932 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
3933 spectral_err("Invalid chain index, detector id = %u",
3934 detector_id);
3935 goto fail;
3936 }
3937
3938 params.max_mag = p_sfft->fft_peak_mag;
3939
3940 params.freq = p_sops->get_current_channel(spectral,
3941 spectral_mode);
3942 params.agile_freq1 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3943 ss_frequency.cfreq1;
3944 params.agile_freq2 = spectral->params[SPECTRAL_SCAN_MODE_AGILE].
3945 ss_frequency.cfreq2;
3946 params.noise_floor =
3947 report->noisefloor[chn_idx_lowest_enabled];
3948 temp = (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS;
3949 if (is_ch_width_160_or_80p80(spectral->ch_width
3950 [spectral_mode]) && !spectral->rparams.
3951 fragmentation_160[spectral_mode]) {
3952 struct wlan_objmgr_psoc *psoc;
3953 struct spectral_fft_bin_markers_160_165mhz *marker;
3954
3955 if (!spectral->pdev_obj) {
3956 spectral_err("pdev is null");
3957 goto fail;
3958 }
3959 psoc = wlan_pdev_get_psoc(spectral->pdev_obj);
3960 if (!psoc) {
3961 spectral_err("psoc is null");
3962 goto fail;
3963 }
3964 params.agc_total_gain_sec80 =
3965 sscan_report_fields.sscan_agc_total_gain;
3966 params.gainchange_sec80 =
3967 sscan_report_fields.sscan_gainchange;
3968 params.raw_timestamp_sec80 = p_sfft->timestamp;
3969 params.rssi_sec80 = rssi;
3970 params.noise_floor_sec80 =
3971 report->noisefloor[chn_idx_lowest_enabled];
3972 params.max_mag_sec80 = p_sfft->fft_peak_mag;
3973 params.datalen = fft_hdr_length * 2;
3974 params.datalen_sec80 = fft_hdr_length * 2;
3975
3976 marker = &spectral->rparams.marker[spectral_mode];
3977 if (!marker->is_valid) {
3978 /* update stats */
3979 goto fail_no_print;
3980 }
3981 params.bin_pwr_data = temp +
3982 marker->start_pri80 * fft_bin_size;
3983 params.pwr_count = marker->num_pri80;
3984 params.bin_pwr_data_sec80 = temp +
3985 marker->start_sec80 * fft_bin_size;
3986 params.pwr_count_sec80 = marker->num_sec80;
3987 if (spectral->ch_width[spectral_mode] ==
3988 CH_WIDTH_80P80MHZ && wlan_psoc_nif_fw_ext_cap_get(
3989 psoc, WLAN_SOC_RESTRICTED_80P80_SUPPORT)) {
3990 params.bin_pwr_data_5mhz = temp +
3991 marker->start_5mhz * fft_bin_size;
3992 params.pwr_count_5mhz = marker->num_5mhz;
3993 }
3994 } else {
3995 params.bin_pwr_data = temp;
3996 params.pwr_count = fft_bin_count;
3997 params.datalen = (fft_hdr_length * 4);
3998 }
3999
4000 /* Apply byte-swap on the FFT bins.
4001 * NOTE: Until this point, bytes of the FFT bins could be in
4002 * reverse order on a big-endian machine. If the consumers
4003 * of FFT bins expects bytes in the correct order,
4004 * they should use them only after this point.
4005 */
4006 if (p_sops->byte_swap_fft_bins) {
4007 ret = p_sops->byte_swap_fft_bins(
4008 &spectral->rparams,
4009 temp, fft_bin_count);
4010 if (QDF_IS_STATUS_ERROR(ret)) {
4011 spectral_err_rl("Byte-swap on the FFT bins failed");
4012 goto fail;
4013 }
4014 }
4015
4016 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
4017 target_if_dump_fft_report_gen3(spectral, spectral_mode,
4018 p_fft_report, p_sfft);
4019
4020 target_if_spectral_verify_ts(spectral, report->data,
4021 params.tstamp);
4022 } else if (is_secondaryseg_expected(spectral, spectral_mode)) {
4023 /* RSSI is in 1/2 dBm steps, Convert it to dBm scale */
4024 rssi = (sscan_report_fields.inband_pwr_db) >> 1;
4025 params.agc_total_gain_sec80 =
4026 sscan_report_fields.sscan_agc_total_gain;
4027 params.gainchange_sec80 = sscan_report_fields.sscan_gainchange;
4028 params.pri80ind_sec80 = sscan_report_fields.sscan_pri80;
4029
4030 /* Process Spectral search FFT report */
4031 if (target_if_verify_sig_and_tag_gen3(
4032 spectral, data,
4033 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) {
4034 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u",
4035 detector_id);
4036 goto fail;
4037 }
4038 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data;
4039 fft_hdr_length = get_bitfield(
4040 p_fft_report->fft_hdr_lts,
4041 SPECTRAL_REPORT_LTS_HDR_LENGTH_SIZE_GEN3,
4042 SPECTRAL_REPORT_LTS_HDR_LENGTH_POS_GEN3) * 4;
4043 if (fft_hdr_length < 16) {
4044 spectral_err("Wrong TLV length %u, detector id = %u",
4045 fft_hdr_length, detector_id);
4046 goto fail;
4047 }
4048
4049 report_len = (fft_hdr_length + 8);
4050
4051 target_if_process_sfft_report_gen3(p_fft_report, p_sfft,
4052 &spectral->rparams);
4053 /* It is expected to have same detector id for
4054 * summary and fft report
4055 */
4056 if (detector_id != p_sfft->fft_detector_id) {
4057 spectral_err_rl
4058 ("Different detid in ssummary(%u) and sfft(%u)",
4059 detector_id, p_sfft->fft_detector_id);
4060 goto fail;
4061 }
4062
4063 if (detector_id > spectral->rparams.num_spectral_detectors) {
4064 spectral->diag_stats.spectral_invalid_detector_id++;
4065 spectral_err("Invalid detector id %u, expected is 1",
4066 detector_id);
4067 goto fail;
4068 }
4069 params.smode = spectral_mode;
4070
4071 fft_bin_count = target_if_spectral_get_bin_count_after_len_adj(
4072 fft_hdr_length - spectral->rparams.fft_report_hdr_len,
4073 spectral->params[spectral_mode].ss_rpt_mode,
4074 &spectral->len_adj_swar, &fft_bin_size);
4075 params.raw_timestamp_sec80 = p_sfft->timestamp;
4076
4077 /* Take care of state transitions for 160 MHz and 80p80 */
4078 if (is_ch_width_160_or_80p80(spectral->ch_width
4079 [spectral_mode]) && spectral->rparams.
4080 fragmentation_160[spectral_mode]) {
4081 ret = target_if_160mhz_delivery_state_change(
4082 spectral, spectral_mode,
4083 detector_id);
4084 if (ret != QDF_STATUS_SUCCESS)
4085 goto fail;
4086 }
4087
4088 params.rssi_sec80 = rssi;
4089
4090 vdev = target_if_spectral_get_vdev(spectral, spectral_mode);
4091 if (!vdev) {
4092 spectral_info("First vdev is NULL");
4093 reset_160mhz_delivery_state_machine
4094 (spectral, spectral_mode);
4095 return -EPERM;
4096 }
4097 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
4098 if (vdev_rxchainmask == 0) {
4099 spectral_err("Vdev rxchainmask is zero.");
4100 goto fail;
4101 }
4102 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
4103
4104 chn_idx_lowest_enabled =
4105 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask);
4106 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) {
4107 spectral_err("Invalid chain index");
4108 goto fail;
4109 }
4110
4111 /* Need to change this as per FW team's inputs */
4112 params.noise_floor_sec80 =
4113 report->noisefloor[chn_idx_lowest_enabled];
4114
4115 params.max_mag_sec80 = p_sfft->fft_peak_mag;
4116 /* params.max_index_sec80 = p_sfft->peak_inx; */
4117 /* XXX Does this definition of datalen *still hold? */
4118 params.datalen_sec80 = fft_hdr_length * 4;
4119 params.pwr_count_sec80 = fft_bin_count;
4120 params.bin_pwr_data_sec80 =
4121 (uint8_t *)((uint8_t *)p_fft_report +
4122 SPECTRAL_FFT_BINS_POS);
4123
4124 /* Apply byte-swap on the FFT bins.
4125 * NOTE: Until this point, bytes of the FFT bins could be in
4126 * reverse order on a big-endian machine. If the consumers
4127 * of FFT bins expects bytes in the correct order,
4128 * they should use them only after this point.
4129 */
4130 if (p_sops->byte_swap_fft_bins) {
4131 ret = p_sops->byte_swap_fft_bins(
4132 &spectral->rparams,
4133 params.bin_pwr_data_sec80,
4134 fft_bin_count);
4135 if (QDF_IS_STATUS_ERROR(ret)) {
4136 spectral_err_rl("Byte-swap on the FFT bins failed");
4137 goto fail;
4138 }
4139 }
4140
4141 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4))
4142 target_if_dump_fft_report_gen3(spectral, spectral_mode,
4143 p_fft_report, p_sfft);
4144
4145 } else {
4146 spectral_err("Spectral state machine in undefined state");
4147 goto fail;
4148 }
4149
4150 target_if_spectral_check_buffer_poisoning(spectral, report,
4151 fft_bin_count, spectral_mode);
4152 qdf_mem_copy(¶ms.classifier_params,
4153 &spectral->classifier_params,
4154 sizeof(struct spectral_classifier_params));
4155
4156 target_if_spectral_log_SAMP_param(¶ms);
4157 target_if_spectral_create_samp_msg(spectral, ¶ms);
4158
4159 return 0;
4160 fail:
4161 spectral_err_rl("Error while processing Spectral report");
4162 fail_no_print:
4163 if (spectral_mode != SPECTRAL_SCAN_MODE_INVALID)
4164 reset_160mhz_delivery_state_machine(spectral, spectral_mode);
4165 return -EPERM;
4166 }
4167 #endif /* OPTIMIZED_SAMP_MESSAGE */
4168
target_if_spectral_process_report_gen3(struct wlan_objmgr_pdev * pdev,void * buf)4169 int target_if_spectral_process_report_gen3(
4170 struct wlan_objmgr_pdev *pdev,
4171 void *buf)
4172 {
4173 int ret = 0;
4174 struct direct_buf_rx_data *payload = buf;
4175 struct target_if_spectral *spectral;
4176 struct spectral_report report = {0};
4177 int samp_msg_index;
4178 struct spectral_data_stats *spectral_dp_stats;
4179
4180 spectral = get_target_if_spectral_handle_from_pdev(pdev);
4181 if (!spectral) {
4182 spectral_err("Spectral target object is null");
4183 return -EINVAL;
4184 }
4185
4186 spectral_dp_stats = &spectral->data_stats;
4187 spectral_dp_stats->spectral_rx_events++;
4188
4189 report.data = payload->vaddr;
4190 if (payload->meta_data_valid) {
4191 qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor,
4192 qdf_min(sizeof(report.noisefloor),
4193 sizeof(payload->meta_data.noisefloor)));
4194 report.reset_delay = payload->meta_data.reset_delay;
4195 report.cfreq1 = payload->meta_data.cfreq1;
4196 report.cfreq2 = payload->meta_data.cfreq2;
4197 report.ch_width = payload->meta_data.ch_width;
4198 }
4199
4200 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) {
4201 spectral_debug("Printing the spectral phyerr buffer for debug");
4202 spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK",
4203 payload->dbr_len,
4204 payload->dbr_len,
4205 payload->vaddr);
4206 target_if_spectral_hexdump((unsigned char *)payload->vaddr,
4207 1024);
4208 }
4209
4210 samp_msg_index = spectral->spectral_sent_msg;
4211
4212 ret = target_if_consume_spectral_report_gen3(spectral, &report);
4213
4214 /* Reset debug level when SAMP msg is sent successfully or on error */
4215 if ((spectral_debug_level & DEBUG_SPECTRAL4) &&
4216 (ret != 0 || spectral->spectral_sent_msg == samp_msg_index + 1))
4217 spectral_debug_level = DEBUG_SPECTRAL;
4218
4219 return ret;
4220 }
4221 #else
target_if_spectral_process_report_gen3(struct wlan_objmgr_pdev * pdev,void * buf)4222 int target_if_spectral_process_report_gen3(
4223 struct wlan_objmgr_pdev *pdev,
4224 void *buf)
4225 {
4226 spectral_err("Direct dma support is not enabled");
4227 return -EINVAL;
4228 }
4229 #endif
4230 qdf_export_symbol(target_if_spectral_process_report_gen3);
4231 /* END of spectral GEN III HW specific functions */
4232
4233 #endif /* WLAN_CONV_SPECTRAL_ENABLE */
4234