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