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