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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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