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