1 /* 2 * Copyright (c) 2011,2017-2020 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 for (i = 0; i < _len; i++) { 79 mod = i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE; 80 81 if (!mod) { 82 if (i) { 83 qdf_assert_always(loc < sizeof(hexdump_line)); 84 loc += snprintf(&hexdump_line[loc], 85 sizeof(hexdump_line) - loc, 86 " %s", ascii); 87 spectral_debug("%s", hexdump_line); 88 qdf_mem_zero(hexdump_line, 89 sizeof(hexdump_line)); 90 loc = 0; 91 } 92 } 93 94 qdf_assert_always(loc < sizeof(hexdump_line)); 95 loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, 96 " %02x", pc[i]); 97 98 if ((pc[i] < 0x20) || (pc[i] > 0x7e)) 99 ascii[mod] = '.'; 100 else 101 ascii[mod] = pc[i]; 102 ascii[(mod) + 1] = '\0'; 103 } 104 105 while ((i % SPECTRAL_HEXDUMP_NUM_OCTETS_PER_LINE) != 0) { 106 qdf_assert_always(loc < sizeof(hexdump_line)); 107 loc += snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, 108 " "); 109 i++; 110 } 111 112 qdf_assert_always(loc < sizeof(hexdump_line)); 113 snprintf(&hexdump_line[loc], sizeof(hexdump_line) - loc, " %s", ascii); 114 spectral_debug("%s", hexdump_line); 115 } 116 117 /** 118 * target_if_print_buf() - Prints given buffer for given length 119 * @pbuf: Pointer to buffer 120 * @len: length 121 * 122 * Prints given buffer for given length 123 * 124 * Return: void 125 */ 126 static void 127 target_if_print_buf(uint8_t *pbuf, int len) 128 { 129 int i = 0; 130 131 for (i = 0; i < len; i++) { 132 spectral_debug("%02X ", pbuf[i]); 133 if (i % 32 == 31) 134 spectral_debug("\n"); 135 } 136 } 137 138 int 139 target_if_spectral_dump_fft(uint8_t *pfft, int fftlen) 140 { 141 int i = 0; 142 143 /* 144 * TODO : Do not delete the following print 145 * The scripts used to validate Spectral depend on this Print 146 */ 147 spectral_debug("SPECTRAL : FFT Length is 0x%x (%d)", fftlen, fftlen); 148 149 spectral_debug("fft_data # "); 150 for (i = 0; i < fftlen; i++) 151 spectral_debug("%d ", pfft[i]); 152 spectral_debug("\n"); 153 return 0; 154 } 155 156 QDF_STATUS target_if_spectral_fw_hang(struct target_if_spectral *spectral) 157 { 158 struct crash_inject param; 159 160 if (!spectral) { 161 spectral_err("Spectral LMAC object is null"); 162 return QDF_STATUS_E_INVAL; 163 } 164 qdf_mem_set(¶m, sizeof(param), 0); 165 param.type = 1; //RECOVERY_SIM_ASSERT 166 167 return spectral->param_wmi_cmd_ops.wmi_spectral_crash_inject( 168 GET_WMI_HDL_FROM_PDEV(spectral->pdev_obj), ¶m); 169 } 170 171 void 172 target_if_dbg_print_samp_param(struct target_if_samp_msg_params *p) 173 { 174 spectral_debug("\nSAMP Packet : -------------------- START --------------------"); 175 spectral_debug("Freq = %d", p->freq); 176 spectral_debug("RSSI = %d", p->rssi); 177 spectral_debug("Bin Count = %d", p->pwr_count); 178 spectral_debug("Timestamp = %d", p->tstamp); 179 spectral_debug("SAMP Packet : -------------------- END -----------------------"); 180 } 181 182 void 183 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg) 184 { 185 int i = 0; 186 187 struct spectral_samp_data *p = &ss_msg->samp_data; 188 struct spectral_classifier_params *pc = &p->classifier_params; 189 struct interf_src_rsp *pi = &p->interf_list; 190 191 spectral_dbg_line(); 192 spectral_debug("Spectral Message"); 193 spectral_dbg_line(); 194 spectral_debug("Signature : 0x%x", ss_msg->signature); 195 spectral_debug("Freq : %d", ss_msg->freq); 196 spectral_debug("Freq load : %d", ss_msg->freq_loading); 197 spectral_debug("Intfnc type : %d", ss_msg->int_type); 198 spectral_dbg_line(); 199 spectral_debug("Spectral Data info"); 200 spectral_dbg_line(); 201 spectral_debug("data length : %d", p->spectral_data_len); 202 spectral_debug("rssi : %d", p->spectral_rssi); 203 spectral_debug("combined rssi : %d", p->spectral_combined_rssi); 204 spectral_debug("upper rssi : %d", p->spectral_upper_rssi); 205 spectral_debug("lower rssi : %d", p->spectral_lower_rssi); 206 spectral_debug("bw info : %d", p->spectral_bwinfo); 207 spectral_debug("timestamp : %d", p->spectral_tstamp); 208 spectral_debug("max index : %d", p->spectral_max_index); 209 spectral_debug("max exp : %d", p->spectral_max_exp); 210 spectral_debug("max mag : %d", p->spectral_max_mag); 211 spectral_debug("last timstamp : %d", p->spectral_last_tstamp); 212 spectral_debug("upper max idx : %d", p->spectral_upper_max_index); 213 spectral_debug("lower max idx : %d", p->spectral_lower_max_index); 214 spectral_debug("bin power count : %d", p->bin_pwr_count); 215 spectral_dbg_line(); 216 spectral_debug("Classifier info"); 217 spectral_dbg_line(); 218 spectral_debug("20/40 Mode : %d", pc->spectral_20_40_mode); 219 spectral_debug("dc index : %d", pc->spectral_dc_index); 220 spectral_debug("dc in MHz : %d", pc->spectral_dc_in_mhz); 221 spectral_debug("upper channel : %d", pc->upper_chan_in_mhz); 222 spectral_debug("lower channel : %d", pc->lower_chan_in_mhz); 223 spectral_dbg_line(); 224 spectral_debug("Interference info"); 225 spectral_dbg_line(); 226 spectral_debug("inter count : %d", pi->count); 227 228 for (i = 0; i < pi->count; i++) { 229 spectral_debug("inter type : %d", 230 pi->interf[i].interf_type); 231 spectral_debug("min freq : %d", 232 pi->interf[i].interf_min_freq); 233 spectral_debug("max freq : %d", 234 pi->interf[i].interf_max_freq); 235 } 236 } 237 238 uint32_t 239 target_if_get_offset_swar_sec80(uint32_t channel_width) 240 { 241 uint32_t offset = 0; 242 243 switch (channel_width) { 244 case CH_WIDTH_20MHZ: 245 offset = OFFSET_CH_WIDTH_20; 246 break; 247 case CH_WIDTH_40MHZ: 248 offset = OFFSET_CH_WIDTH_40; 249 break; 250 case CH_WIDTH_80MHZ: 251 offset = OFFSET_CH_WIDTH_80; 252 break; 253 case CH_WIDTH_160MHZ: 254 offset = OFFSET_CH_WIDTH_160; 255 break; 256 default: 257 offset = OFFSET_CH_WIDTH_80; 258 break; 259 } 260 return offset; 261 } 262 263 /** 264 * target_if_dump_summary_report_gen2() - Dump Spectral Summary Report for gen2 265 * @ptlv: Pointer to Spectral Phyerr TLV 266 * @tlvlen: length 267 * @is_160_format: Indicates whether information provided by HW is in altered 268 * format for 802.11ac 160/80+80 MHz support (QCA9984 onwards) 269 * 270 * Dump Spectral Summary Report for gen2 271 * 272 * Return: Success/Failure 273 */ 274 static int 275 target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv, 276 int tlvlen, bool is_160_format) 277 { 278 /* 279 * For simplicity, everything is defined as uint32_t (except one). 280 * Proper code will later use the right sizes. 281 */ 282 283 /* 284 * For easy comparision between MDK team and OS team, the MDK script 285 * variable names have been used 286 */ 287 288 uint32_t agc_mb_gain; 289 uint32_t sscan_gidx; 290 uint32_t agc_total_gain; 291 uint32_t recent_rfsat; 292 uint32_t ob_flag; 293 uint32_t nb_mask; 294 uint32_t peak_mag; 295 int16_t peak_inx; 296 297 uint32_t ss_summary_A = 0; 298 uint32_t ss_summary_B = 0; 299 uint32_t ss_summary_C = 0; 300 uint32_t ss_summary_D = 0; 301 uint32_t ss_summary_E = 0; 302 struct spectral_phyerr_hdr_gen2 *phdr = 303 (struct spectral_phyerr_hdr_gen2 *)( 304 (uint8_t *)ptlv + 305 sizeof(struct spectral_phyerr_tlv_gen2)); 306 307 spectral_debug("SPECTRAL : SPECTRAL SUMMARY REPORT"); 308 309 if (is_160_format) { 310 if (tlvlen != 20) { 311 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 312 tlvlen); 313 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 314 return -EPERM; 315 } 316 317 /* Doing copy as the contents may not be aligned */ 318 qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int)); 319 qdf_mem_copy(&ss_summary_B, 320 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 321 sizeof(int)); 322 qdf_mem_copy(&ss_summary_C, 323 (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)), 324 sizeof(int)); 325 qdf_mem_copy(&ss_summary_D, 326 (uint8_t *)((uint8_t *)phdr + 3 * sizeof(int)), 327 sizeof(int)); 328 qdf_mem_copy(&ss_summary_E, 329 (uint8_t *)((uint8_t *)phdr + 4 * sizeof(int)), 330 sizeof(int)); 331 332 /* 333 * The following is adapted from MDK scripts for 334 * easier comparability 335 */ 336 337 recent_rfsat = ((ss_summary_A >> 8) & 0x1); 338 sscan_gidx = (ss_summary_A & 0xff); 339 spectral_debug("sscan_gidx=%d, is_recent_rfsat=%d", 340 sscan_gidx, recent_rfsat); 341 342 /* First segment */ 343 agc_mb_gain = ((ss_summary_B >> 10) & 0x7f); 344 agc_total_gain = (ss_summary_B & 0x3ff); 345 nb_mask = ((ss_summary_C >> 22) & 0xff); 346 ob_flag = ((ss_summary_B >> 17) & 0x1); 347 peak_inx = (ss_summary_C & 0xfff); 348 if (peak_inx > 2047) 349 peak_inx = peak_inx - 4096; 350 peak_mag = ((ss_summary_C >> 12) & 0x3ff); 351 352 spectral_debug("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d", 353 agc_total_gain, agc_mb_gain); 354 spectral_debug("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, peak_index_segid0=%d, peak_mag_segid0=%d", 355 nb_mask, ob_flag, peak_inx, peak_mag); 356 357 /* Second segment */ 358 agc_mb_gain = ((ss_summary_D >> 10) & 0x7f); 359 agc_total_gain = (ss_summary_D & 0x3ff); 360 nb_mask = ((ss_summary_E >> 22) & 0xff); 361 ob_flag = ((ss_summary_D >> 17) & 0x1); 362 peak_inx = (ss_summary_E & 0xfff); 363 if (peak_inx > 2047) 364 peak_inx = peak_inx - 4096; 365 peak_mag = ((ss_summary_E >> 12) & 0x3ff); 366 367 spectral_debug("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d", 368 agc_total_gain, agc_mb_gain); 369 spectral_debug("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, peak_index_segid1=%d, peak_mag_segid1=%d", 370 nb_mask, ob_flag, peak_inx, peak_mag); 371 } else { 372 if (tlvlen != 8) { 373 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 374 tlvlen); 375 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 376 return -EPERM; 377 } 378 379 /* Doing copy as the contents may not be aligned */ 380 qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int)); 381 qdf_mem_copy(&ss_summary_B, 382 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 383 sizeof(int)); 384 385 nb_mask = ((ss_summary_B >> 22) & 0xff); 386 ob_flag = ((ss_summary_B >> 30) & 0x1); 387 peak_inx = (ss_summary_B & 0xfff); 388 389 if (peak_inx > 2047) 390 peak_inx = peak_inx - 4096; 391 392 peak_mag = ((ss_summary_B >> 12) & 0x3ff); 393 agc_mb_gain = ((ss_summary_A >> 24) & 0x7f); 394 agc_total_gain = (ss_summary_A & 0x3ff); 395 sscan_gidx = ((ss_summary_A >> 16) & 0xff); 396 recent_rfsat = ((ss_summary_B >> 31) & 0x1); 397 398 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", 399 nb_mask, ob_flag, peak_inx, peak_mag, 400 agc_mb_gain, agc_total_gain, sscan_gidx, 401 recent_rfsat); 402 } 403 404 return 0; 405 } 406 407 /** 408 * target_if_process_sfft_report_gen2() - Process Search FFT Report 409 * @ptlv: Pointer to Spectral Phyerr TLV 410 * @tlvlen: length 411 * @p_fft_info: Pointer to search fft info 412 * 413 * Dump Spectral Summary Report for gen2 414 * 415 * Return: Success/Failure 416 */ 417 static int 418 target_if_process_sfft_report_gen2( 419 struct spectral_phyerr_tlv_gen2 *ptlv, 420 int tlvlen, 421 struct spectral_search_fft_info_gen2 *p_fft_info) 422 { 423 /* 424 * For simplicity, everything is defined as uint32_t (except one). 425 * Proper code will later use the right sizes. 426 */ 427 /* 428 * For easy comparision between MDK team and OS team, the MDK script 429 * variable names have been used 430 */ 431 uint32_t relpwr_db; 432 uint32_t num_str_bins_ib; 433 uint32_t base_pwr; 434 uint32_t total_gain_info; 435 436 uint32_t fft_chn_idx; 437 int16_t peak_inx; 438 uint32_t avgpwr_db; 439 uint32_t peak_mag; 440 441 uint32_t fft_summary_A = 0; 442 uint32_t fft_summary_B = 0; 443 uint8_t *tmp = (uint8_t *)ptlv; 444 struct spectral_phyerr_hdr_gen2 *phdr = 445 (struct spectral_phyerr_hdr_gen2 *)( 446 tmp + 447 sizeof(struct spectral_phyerr_tlv_gen2)); 448 449 /* Relook this */ 450 if (tlvlen < 8) { 451 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 452 tlvlen); 453 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 454 return -EPERM; 455 } 456 457 /* Doing copy as the contents may not be aligned */ 458 qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int)); 459 qdf_mem_copy(&fft_summary_B, 460 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 461 sizeof(int)); 462 463 relpwr_db = ((fft_summary_B >> 26) & 0x3f); 464 num_str_bins_ib = fft_summary_B & 0xff; 465 base_pwr = ((fft_summary_A >> 14) & 0x1ff); 466 total_gain_info = ((fft_summary_A >> 23) & 0x1ff); 467 468 fft_chn_idx = ((fft_summary_A >> 12) & 0x3); 469 peak_inx = fft_summary_A & 0xfff; 470 471 if (peak_inx > 2047) 472 peak_inx = peak_inx - 4096; 473 474 avgpwr_db = ((fft_summary_B >> 18) & 0xff); 475 peak_mag = ((fft_summary_B >> 8) & 0x3ff); 476 477 /* Populate the Search FFT Info */ 478 if (p_fft_info) { 479 p_fft_info->relpwr_db = relpwr_db; 480 p_fft_info->num_str_bins_ib = num_str_bins_ib; 481 p_fft_info->base_pwr = base_pwr; 482 p_fft_info->total_gain_info = total_gain_info; 483 p_fft_info->fft_chn_idx = fft_chn_idx; 484 p_fft_info->peak_inx = peak_inx; 485 p_fft_info->avgpwr_db = avgpwr_db; 486 p_fft_info->peak_mag = peak_mag; 487 } 488 489 return 0; 490 } 491 492 /** 493 * target_if_dump_adc_report_gen2() - Dump ADC Reports for gen2 494 * @ptlv: Pointer to Spectral Phyerr TLV 495 * @tlvlen: length 496 * 497 * Dump ADC Reports for gen2 498 * 499 * Return: Success/Failure 500 */ 501 static int 502 target_if_dump_adc_report_gen2( 503 struct spectral_phyerr_tlv_gen2 *ptlv, int tlvlen) 504 { 505 int i; 506 uint32_t *pdata; 507 uint32_t data; 508 509 /* 510 * For simplicity, everything is defined as uint32_t (except one). 511 * Proper code will later use the right sizes. 512 */ 513 uint32_t samp_fmt; 514 uint32_t chn_idx; 515 uint32_t recent_rfsat; 516 uint32_t agc_mb_gain; 517 uint32_t agc_total_gain; 518 519 uint32_t adc_summary = 0; 520 521 uint8_t *ptmp = (uint8_t *)ptlv; 522 523 spectral_debug("SPECTRAL : ADC REPORT"); 524 525 /* Relook this */ 526 if (tlvlen < 4) { 527 spectral_err("Unexpected TLV length %d for ADC Report! Hexdump follows", 528 tlvlen); 529 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 530 return -EPERM; 531 } 532 533 qdf_mem_copy(&adc_summary, (uint8_t *)(ptlv + 4), sizeof(int)); 534 535 samp_fmt = ((adc_summary >> 28) & 0x1); 536 chn_idx = ((adc_summary >> 24) & 0x3); 537 recent_rfsat = ((adc_summary >> 23) & 0x1); 538 agc_mb_gain = ((adc_summary >> 16) & 0x7f); 539 agc_total_gain = adc_summary & 0x3ff; 540 541 spectral_debug("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u agc_total_gain=%u", 542 samp_fmt, chn_idx, recent_rfsat, agc_mb_gain, 543 agc_total_gain); 544 545 for (i = 0; i < (tlvlen / 4); i++) { 546 pdata = (uint32_t *)(ptmp + 4 + i * 4); 547 data = *pdata; 548 549 /* Interpreting capture format 1 */ 550 if (1) { 551 uint8_t i1; 552 uint8_t q1; 553 uint8_t i2; 554 uint8_t q2; 555 int8_t si1; 556 int8_t sq1; 557 int8_t si2; 558 int8_t sq2; 559 560 i1 = data & 0xff; 561 q1 = (data >> 8) & 0xff; 562 i2 = (data >> 16) & 0xff; 563 q2 = (data >> 24) & 0xff; 564 565 if (i1 > 127) 566 si1 = i1 - 256; 567 else 568 si1 = i1; 569 570 if (q1 > 127) 571 sq1 = q1 - 256; 572 else 573 sq1 = q1; 574 575 if (i2 > 127) 576 si2 = i2 - 256; 577 else 578 si2 = i2; 579 580 if (q2 > 127) 581 sq2 = q2 - 256; 582 else 583 sq2 = q2; 584 585 spectral_debug("SPECTRAL ADC : Interpreting capture format 1"); 586 spectral_debug("adc_data_format_1 # %d %d %d", 587 2 * i, si1, sq1); 588 spectral_debug("adc_data_format_1 # %d %d %d", 589 2 * i + 1, si2, sq2); 590 } 591 592 /* Interpreting capture format 0 */ 593 if (1) { 594 uint16_t i1; 595 uint16_t q1; 596 int16_t si1; 597 int16_t sq1; 598 599 i1 = data & 0xffff; 600 q1 = (data >> 16) & 0xffff; 601 if (i1 > 32767) 602 si1 = i1 - 65536; 603 else 604 si1 = i1; 605 606 if (q1 > 32767) 607 sq1 = q1 - 65536; 608 else 609 sq1 = q1; 610 spectral_debug("SPECTRAL ADC : Interpreting capture format 0"); 611 spectral_debug("adc_data_format_2 # %d %d %d", 612 i, si1, sq1); 613 } 614 } 615 616 spectral_debug("\n"); 617 618 return 0; 619 } 620 621 /** 622 * target_if_dump_sfft_report_gen2() - Process Search FFT Report for gen2 623 * @ptlv: Pointer to Spectral Phyerr TLV 624 * @tlvlen: length 625 * @is_160_format: Indicates 160 format 626 * 627 * Process Search FFT Report for gen2 628 * 629 * Return: Success/Failure 630 */ 631 static int 632 target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv, 633 int tlvlen, bool is_160_format) 634 { 635 int i; 636 uint32_t fft_mag; 637 638 /* 639 * For simplicity, everything is defined as uint32_t (except one). 640 * Proper code will later use the right sizes. 641 */ 642 /* 643 * For easy comparision between MDK team and OS team, the MDK script 644 * variable names have been used 645 */ 646 uint32_t relpwr_db; 647 uint32_t num_str_bins_ib; 648 uint32_t base_pwr; 649 uint32_t total_gain_info; 650 651 uint32_t fft_chn_idx; 652 int16_t peak_inx; 653 uint32_t avgpwr_db; 654 uint32_t peak_mag; 655 uint8_t segid; 656 657 uint32_t fft_summary_A = 0; 658 uint32_t fft_summary_B = 0; 659 uint32_t fft_summary_C = 0; 660 uint8_t *tmp = (uint8_t *)ptlv; 661 struct spectral_phyerr_hdr_gen2 *phdr = 662 (struct spectral_phyerr_hdr_gen2 *)( 663 tmp + 664 sizeof(struct spectral_phyerr_tlv_gen2)); 665 uint32_t segid_skiplen = 0; 666 667 if (is_160_format) 668 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO); 669 670 spectral_debug("SPECTRAL : SEARCH FFT REPORT"); 671 672 /* Relook this */ 673 if (tlvlen < (8 + segid_skiplen)) { 674 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 675 tlvlen); 676 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 677 return -EPERM; 678 } 679 680 /* Doing copy as the contents may not be aligned */ 681 qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int)); 682 qdf_mem_copy(&fft_summary_B, 683 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 684 sizeof(int)); 685 if (is_160_format) 686 qdf_mem_copy(&fft_summary_C, 687 (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)), 688 sizeof(int)); 689 690 relpwr_db = ((fft_summary_B >> 26) & 0x3f); 691 num_str_bins_ib = fft_summary_B & 0xff; 692 base_pwr = ((fft_summary_A >> 14) & 0x1ff); 693 total_gain_info = ((fft_summary_A >> 23) & 0x1ff); 694 695 fft_chn_idx = ((fft_summary_A >> 12) & 0x3); 696 peak_inx = fft_summary_A & 0xfff; 697 698 if (peak_inx > 2047) 699 peak_inx = peak_inx - 4096; 700 701 avgpwr_db = ((fft_summary_B >> 18) & 0xff); 702 peak_mag = ((fft_summary_B >> 8) & 0x3ff); 703 704 spectral_debug("Header A = 0x%x Header B = 0x%x", 705 phdr->hdr_a, phdr->hdr_b); 706 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", 707 base_pwr, total_gain_info, relpwr_db, num_str_bins_ib, 708 fft_chn_idx, peak_inx, avgpwr_db, peak_mag); 709 if (is_160_format) { 710 segid = fft_summary_C & 0x1; 711 spectral_debug("Segment ID: %hhu", segid); 712 } 713 714 spectral_debug("FFT bins:"); 715 for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) { 716 fft_mag = ((uint8_t *)ptlv)[12 + segid_skiplen + i]; 717 spectral_debug("%d %d, ", i, fft_mag); 718 } 719 720 spectral_debug("\n"); 721 722 return 0; 723 } 724 725 #ifdef SPECTRAL_DEBUG_SAMP_MSG 726 /** 727 * target_if_spectral_log_SAMP_param() - Log SAMP parameters 728 * @params: Reference to target_if_samp_msg_params 729 * 730 * API to log spectral SAMP message parameters 731 * 732 * Return: None 733 */ 734 static void 735 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params) 736 { 737 target_if_dbg_print_samp_param(params); 738 } 739 740 #else 741 static void 742 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params) 743 { 744 } 745 #endif 746 747 int 748 target_if_process_phyerr_gen2(struct target_if_spectral *spectral, 749 uint8_t *data, 750 uint32_t datalen, 751 struct target_if_spectral_rfqual_info *p_rfqual, 752 struct target_if_spectral_chan_info *p_chaninfo, 753 uint64_t tsf64, 754 struct target_if_spectral_acs_stats *acs_stats) 755 { 756 /* 757 * XXX : The classifier do not use all the members of the SAMP 758 * message data format. 759 * The classifier only depends upon the following parameters 760 * 761 * 1. Frequency (freq, msg->freq) 762 * 2. Spectral RSSI (spectral_rssi, 763 * msg->samp_data.spectral_rssi) 764 * 3. Bin Power Count (bin_pwr_count, 765 * msg->samp_data.bin_pwr_count) 766 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0] 767 * 5. Spectral Timestamp (spectral_tstamp, 768 * msg->samp_data.spectral_tstamp) 769 * 6. MAC Address (macaddr, msg->macaddr) 770 * 771 * This function prepares the params structure and populates it 772 * with 773 * relevant values, this is in turn passed to 774 * spectral_create_samp_msg() 775 * to prepare fully formatted Spectral SAMP message 776 * 777 * XXX : Need to verify 778 * 1. Order of FFT bin values 779 * 780 */ 781 782 struct target_if_samp_msg_params params; 783 struct spectral_search_fft_info_gen2 search_fft_info; 784 struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info; 785 struct spectral_search_fft_info_gen2 search_fft_info_sec80; 786 struct spectral_search_fft_info_gen2 *p_sfft_sec80 = 787 &search_fft_info_sec80; 788 uint32_t segid_skiplen = 0; 789 790 int8_t rssi_up = 0; 791 int8_t rssi_low = 0; 792 793 int8_t chn_idx_highest_enabled = 0; 794 int8_t chn_idx_lowest_enabled = 0; 795 796 uint8_t control_rssi = 0; 797 uint8_t extension_rssi = 0; 798 uint8_t combined_rssi = 0; 799 800 uint32_t tstamp = 0; 801 802 struct target_if_spectral_ops *p_sops = 803 GET_TARGET_IF_SPECTRAL_OPS(spectral); 804 805 struct spectral_phyerr_tlv_gen2 *ptlv = 806 (struct spectral_phyerr_tlv_gen2 *)data; 807 struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL; 808 struct spectral_phyerr_fft_gen2 *pfft = NULL; 809 struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL; 810 811 uint8_t segid = 0; 812 uint8_t segid_sec80 = 0; 813 814 if (spectral->is_160_format) 815 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO); 816 817 pfft = (struct spectral_phyerr_fft_gen2 *)( 818 data + 819 sizeof(struct spectral_phyerr_tlv_gen2) + 820 sizeof(struct spectral_phyerr_hdr_gen2) + 821 segid_skiplen); 822 823 /* 824 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level, 825 * and use this facility inside spectral_dump_phyerr_data() 826 * and supporting functions. 827 */ 828 if (spectral_debug_level & DEBUG_SPECTRAL2) 829 target_if_spectral_dump_phyerr_data_gen2( 830 data, datalen, 831 spectral->is_160_format); 832 833 if (spectral_debug_level & DEBUG_SPECTRAL4) { 834 target_if_spectral_dump_phyerr_data_gen2( 835 data, datalen, 836 spectral->is_160_format); 837 spectral_debug_level = DEBUG_SPECTRAL; 838 } 839 840 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) { 841 /* 842 * EV# 118023: We tentatively disable the below print 843 * and provide stats instead. 844 */ 845 spectral->diag_stats.spectral_mismatch++; 846 return -EPERM; 847 } 848 849 OS_MEMZERO(¶ms, sizeof(params)); 850 /* Gen 2 only supports normal Spectral scan currently */ 851 params.smode = SPECTRAL_SCAN_MODE_NORMAL; 852 853 if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) { 854 if (spectral->is_160_format) { 855 segid = *((SPECTRAL_SEGID_INFO *)( 856 (uint8_t *)ptlv + 857 sizeof(struct spectral_phyerr_tlv_gen2) + 858 sizeof(struct spectral_phyerr_hdr_gen2))); 859 860 if (segid != 0) { 861 struct spectral_diag_stats *p_diag_stats = 862 &spectral->diag_stats; 863 p_diag_stats->spectral_vhtseg1id_mismatch++; 864 return -EPERM; 865 } 866 } 867 868 target_if_process_sfft_report_gen2(ptlv, ptlv->length, 869 &search_fft_info); 870 871 tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK; 872 873 combined_rssi = p_rfqual->rssi_comb; 874 875 if (spectral->upper_is_control) 876 rssi_up = control_rssi; 877 else 878 rssi_up = extension_rssi; 879 880 if (spectral->lower_is_control) 881 rssi_low = control_rssi; 882 else 883 rssi_low = extension_rssi; 884 885 params.rssi = p_rfqual->rssi_comb; 886 params.lower_rssi = rssi_low; 887 params.upper_rssi = rssi_up; 888 889 if (spectral->sc_spectral_noise_pwr_cal) { 890 params.chain_ctl_rssi[0] = 891 p_rfqual->pc_rssi_info[0].rssi_pri20; 892 params.chain_ctl_rssi[1] = 893 p_rfqual->pc_rssi_info[1].rssi_pri20; 894 params.chain_ctl_rssi[2] = 895 p_rfqual->pc_rssi_info[2].rssi_pri20; 896 params.chain_ext_rssi[0] = 897 p_rfqual->pc_rssi_info[0].rssi_sec20; 898 params.chain_ext_rssi[1] = 899 p_rfqual->pc_rssi_info[1].rssi_sec20; 900 params.chain_ext_rssi[2] = 901 p_rfqual->pc_rssi_info[2].rssi_sec20; 902 } 903 904 /* 905 * XXX : This actually depends on the programmed chain mask 906 * This value decides the per-chain enable mask to select 907 * the input ADC for search FTT. 908 * For modes upto VHT80, if more than one chain is 909 * enabled, the max valid chain 910 * is used. LSB corresponds to chain zero. 911 * For VHT80_80 and VHT160, the lowest enabled chain is 912 * used for primary 913 * detection and highest enabled chain is used for 914 * secondary detection. 915 * 916 * XXX : The current algorithm do not use these control and 917 * extension channel 918 * Instead, it just relies on the combined RSSI values 919 * only. 920 * For fool-proof detection algorithm, we should take 921 * these RSSI values in to account. 922 * This is marked for future enhancements. 923 */ 924 chn_idx_highest_enabled = 925 ((spectral->params[params.smode].ss_chn_mask & 0x8) ? 3 : 926 (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 927 (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 0); 928 chn_idx_lowest_enabled = 929 ((spectral->params[params.smode].ss_chn_mask & 0x1) ? 0 : 930 (spectral->params[params.smode].ss_chn_mask & 0x2) ? 1 : 931 (spectral->params[params.smode].ss_chn_mask & 0x4) ? 2 : 3); 932 control_rssi = (uint8_t) 933 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20; 934 extension_rssi = (uint8_t) 935 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20; 936 937 params.bwinfo = 0; 938 params.tstamp = 0; 939 params.max_mag = p_sfft->peak_mag; 940 941 params.max_index = p_sfft->peak_inx; 942 params.max_exp = 0; 943 params.peak = 0; 944 params.bin_pwr_data = (uint8_t *)pfft; 945 params.freq = p_sops->get_current_channel(spectral); 946 params.freq_loading = 0; 947 948 params.interf_list.count = 0; 949 params.max_lower_index = 0; 950 params.max_upper_index = 0; 951 params.nb_lower = 0; 952 params.nb_upper = 0; 953 /* 954 * For modes upto VHT80, the noise floor is populated with the 955 * one corresponding 956 * to the highest enabled antenna chain 957 */ 958 params.noise_floor = 959 p_rfqual->noise_floor[chn_idx_highest_enabled]; 960 params.datalen = ptlv->length; 961 params.pwr_count = ptlv->length - 962 sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen; 963 params.tstamp = (tsf64 & SPECTRAL_TSMASK); 964 965 acs_stats->ctrl_nf = params.noise_floor; 966 acs_stats->ext_nf = params.noise_floor; 967 acs_stats->nfc_ctl_rssi = control_rssi; 968 acs_stats->nfc_ext_rssi = extension_rssi; 969 970 if (spectral->is_160_format && 971 spectral->ch_width == CH_WIDTH_160MHZ) { 972 /* 973 * We expect to see one more Search FFT report, and it 974 * should be equal in size to the current one. 975 */ 976 if (datalen < ( 977 2 * ( 978 sizeof(struct spectral_phyerr_tlv_gen2) + 979 ptlv->length))) { 980 struct spectral_diag_stats *p_diag_stats = 981 &spectral->diag_stats; 982 p_diag_stats->spectral_sec80_sfft_insufflen++; 983 return -EPERM; 984 } 985 986 ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)( 987 data + 988 sizeof(struct spectral_phyerr_tlv_gen2) + 989 ptlv->length); 990 991 if (ptlv_sec80->signature != 992 SPECTRAL_PHYERR_SIGNATURE_GEN2) { 993 spectral->diag_stats.spectral_mismatch++; 994 return -EPERM; 995 } 996 997 if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) { 998 spectral->diag_stats.spectral_no_sec80_sfft++; 999 return -EPERM; 1000 } 1001 1002 segid_sec80 = *((SPECTRAL_SEGID_INFO *)( 1003 (uint8_t *)ptlv_sec80 + 1004 sizeof(struct spectral_phyerr_tlv_gen2) + 1005 sizeof(struct spectral_phyerr_hdr_gen2))); 1006 1007 if (segid_sec80 != 1) { 1008 struct spectral_diag_stats *p_diag_stats = 1009 &spectral->diag_stats; 1010 p_diag_stats->spectral_vhtseg2id_mismatch++; 1011 return -EPERM; 1012 } 1013 1014 params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1; 1015 params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2; 1016 1017 target_if_process_sfft_report_gen2( 1018 ptlv_sec80, 1019 ptlv_sec80->length, 1020 &search_fft_info_sec80); 1021 1022 pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)( 1023 ((uint8_t *)ptlv_sec80) + 1024 sizeof(struct spectral_phyerr_tlv_gen2) + 1025 sizeof(struct spectral_phyerr_hdr_gen2) + 1026 segid_skiplen); 1027 1028 /* XXX: Confirm. TBD at SoD. */ 1029 params.rssi_sec80 = p_rfqual->rssi_comb; 1030 if (spectral->is_sec80_rssi_war_required) 1031 params.rssi_sec80 = 1032 target_if_get_combrssi_sec80_seg_gen2 1033 (spectral, &search_fft_info_sec80); 1034 /* XXX: Determine dynamically. TBD at SoD. */ 1035 /* 1036 * For VHT80_80/VHT160, the noise floor for primary 1037 * 80MHz segment is populated with the 1038 * lowest enabled antenna chain and the noise floor for 1039 * secondary 80MHz segment is populated 1040 * with the highest enabled antenna chain 1041 */ 1042 params.noise_floor_sec80 = 1043 p_rfqual->noise_floor[chn_idx_highest_enabled]; 1044 params.noise_floor = 1045 p_rfqual->noise_floor[chn_idx_lowest_enabled]; 1046 1047 params.max_mag_sec80 = p_sfft_sec80->peak_mag; 1048 params.max_index_sec80 = p_sfft_sec80->peak_inx; 1049 /* XXX Does this definition of datalen *still hold? */ 1050 params.datalen_sec80 = ptlv_sec80->length; 1051 params.pwr_count_sec80 = 1052 ptlv_sec80->length - 1053 sizeof(struct spectral_phyerr_hdr_gen2) - 1054 segid_skiplen; 1055 params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80; 1056 } 1057 qdf_mem_copy(¶ms.classifier_params, 1058 &spectral->classifier_params, 1059 sizeof(struct spectral_classifier_params)); 1060 1061 target_if_spectral_log_SAMP_param(¶ms); 1062 target_if_spectral_create_samp_msg(spectral, ¶ms); 1063 } 1064 1065 return 0; 1066 } 1067 1068 int 1069 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr) 1070 { 1071 uint32_t a = 0; 1072 uint32_t b = 0; 1073 1074 qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int)); 1075 qdf_mem_copy(&b, 1076 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 1077 sizeof(int)); 1078 1079 spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a); 1080 spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b); 1081 return 0; 1082 } 1083 1084 int8_t 1085 target_if_get_combrssi_sec80_seg_gen2( 1086 struct target_if_spectral *spectral, 1087 struct spectral_search_fft_info_gen2 *p_sfft_sec80) 1088 { 1089 uint32_t avgpwr_db = 0; 1090 uint32_t total_gain_db = 0; 1091 uint32_t offset = 0; 1092 int8_t comb_rssi = 0; 1093 1094 /* Obtain required parameters for algorithm from search FFT report */ 1095 avgpwr_db = p_sfft_sec80->avgpwr_db; 1096 total_gain_db = p_sfft_sec80->total_gain_info; 1097 1098 /* Calculate offset */ 1099 offset = target_if_get_offset_swar_sec80(spectral->ch_width); 1100 1101 /* Calculate RSSI */ 1102 comb_rssi = ((avgpwr_db - total_gain_db) + offset); 1103 1104 return comb_rssi; 1105 } 1106 1107 int 1108 target_if_spectral_dump_tlv_gen2( 1109 struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format) 1110 { 1111 int ret = 0; 1112 1113 /* 1114 * TODO : Do not delete the following print 1115 * The scripts used to validate Spectral depend on this Print 1116 */ 1117 spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)", 1118 ptlv->length, ptlv->length); 1119 1120 switch (ptlv->tag) { 1121 case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2: 1122 ret = 1123 target_if_dump_summary_report_gen2( 1124 ptlv, ptlv->length, is_160_format); 1125 break; 1126 1127 case TLV_TAG_SEARCH_FFT_REPORT_GEN2: 1128 ret = 1129 target_if_dump_sfft_report_gen2(ptlv, ptlv->length, 1130 is_160_format); 1131 break; 1132 1133 case TLV_TAG_ADC_REPORT_GEN2: 1134 ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length); 1135 break; 1136 1137 default: 1138 spectral_warn("INVALID TLV"); 1139 ret = -1; 1140 break; 1141 } 1142 1143 return ret; 1144 } 1145 1146 int 1147 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen, 1148 bool is_160_format) 1149 { 1150 struct spectral_phyerr_tlv_gen2 *ptlv = NULL; 1151 uint32_t bytes_processed = 0; 1152 uint32_t bytes_remaining = datalen; 1153 uint32_t curr_tlv_complete_size = 0; 1154 1155 if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) { 1156 spectral_err("Total PHY error data length %u too short to contain any TLVs", 1157 datalen); 1158 return -EPERM; 1159 } 1160 1161 while (bytes_processed < datalen) { 1162 if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) { 1163 spectral_err("Remaining PHY error data length %u too short to contain a TLV", 1164 bytes_remaining); 1165 return -EPERM; 1166 } 1167 1168 ptlv = (struct spectral_phyerr_tlv_gen2 *)(data + 1169 bytes_processed); 1170 1171 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) { 1172 spectral_err("Invalid signature 0x%x!", 1173 ptlv->signature); 1174 return -EPERM; 1175 } 1176 1177 curr_tlv_complete_size = 1178 sizeof(struct spectral_phyerr_tlv_gen2) + 1179 ptlv->length; 1180 1181 if (curr_tlv_complete_size > bytes_remaining) { 1182 spectral_err("TLV size %d greater than number of bytes remaining %d", 1183 curr_tlv_complete_size, bytes_remaining); 1184 return -EPERM; 1185 } 1186 1187 if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1) 1188 return -EPERM; 1189 1190 bytes_processed += curr_tlv_complete_size; 1191 bytes_remaining = datalen - bytes_processed; 1192 } 1193 1194 return 0; 1195 } 1196 1197 #ifdef DIRECT_BUF_RX_ENABLE 1198 /** 1199 * target_if_spectral_get_bin_count_after_len_adj() - Get number of FFT bins in 1200 * Spectral FFT report 1201 * @fft_bin_len: FFT bin length reported by target 1202 * @rpt_mode: Spectral report mode 1203 * @swar: Spectral FFT bin length adjustments SWAR parameters 1204 * 1205 * Get actual number of FFT bins in the FFT report after adjusting the length 1206 * by applying the SWARs for getting correct length. 1207 * 1208 * Return: FFT bin count 1209 */ 1210 static size_t 1211 target_if_spectral_get_bin_count_after_len_adj( 1212 size_t fft_bin_len, uint8_t rpt_mode, 1213 struct spectral_fft_bin_len_adj_swar *swar) 1214 { 1215 size_t fft_bin_count = fft_bin_len; 1216 1217 if (rpt_mode == 1 && swar->null_fftbin_adj) { 1218 /* 1219 * No FFT bins are expected. Explicitly set FFT bin 1220 * count to 0. 1221 */ 1222 fft_bin_count = 0; 1223 } else { 1224 /* 1225 * Divide fft bin length by appropriate factor depending 1226 * on the value of fftbin_size_war. 1227 */ 1228 switch (swar->fftbin_size_war) { 1229 case SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE: 1230 fft_bin_count >>= 2; 1231 break; 1232 case SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE: 1233 fft_bin_count >>= 1; 1234 /* Ideally we should be dividing fft bin length 1235 * by 2. Due to a HW bug, actual length is two 1236 * times the expected length. 1237 */ 1238 if (swar->packmode_fftbin_size_adj) 1239 fft_bin_count >>= 1; 1240 break; 1241 case SPECTRAL_FFTBIN_SIZE_NO_WAR: 1242 /* No length adjustment */ 1243 break; 1244 default: 1245 qdf_assert_always(0); 1246 } 1247 1248 if (rpt_mode == 2 && swar->inband_fftbin_size_adj) 1249 fft_bin_count >>= 1; 1250 } 1251 1252 return fft_bin_count; 1253 } 1254 1255 /** 1256 * target_if_process_sfft_report_gen3() - Process Search FFT Report for gen3 1257 * @p_fft_report: Pointer to fft report 1258 * @p_sfft: Pointer to search fft report 1259 * 1260 * Process Search FFT Report for gen3 1261 * 1262 * Return: Success/Failure 1263 */ 1264 static int 1265 target_if_process_sfft_report_gen3( 1266 struct spectral_phyerr_fft_report_gen3 *p_fft_report, 1267 struct spectral_search_fft_info_gen3 *p_sfft) 1268 { 1269 /* 1270 * For simplicity, everything is defined as uint32_t (except one). 1271 * Proper code will later use the right sizes. 1272 */ 1273 /* 1274 * For easy comparision between MDK team and OS team, the MDK script 1275 * variable names have been used 1276 */ 1277 int32_t peak_sidx; 1278 int32_t peak_mag; 1279 1280 /* Populate the Search FFT Info */ 1281 if (p_sfft) { 1282 p_sfft->timestamp = p_fft_report->fft_timestamp; 1283 1284 p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a, 1285 2, 0); 1286 p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2); 1287 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a, 1288 12, 5); 1289 1290 peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17); 1291 p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11); 1292 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28); 1293 1294 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b, 1295 9, 0); 1296 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b, 1297 8, 9); 1298 1299 p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c, 1300 8, 0); 1301 peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8); 1302 p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10); 1303 p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c, 1304 7, 18); 1305 p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c, 1306 7, 25); 1307 } 1308 1309 return 0; 1310 } 1311 1312 /** 1313 * target_if_dump_fft_report_gen3() - Dump FFT Report for gen3 1314 * @spectral: Pointer to Spectral object 1315 * @smode: Spectral scan mode 1316 * @p_fft_report: Pointer to fft report 1317 * @p_sfft: Pointer to search fft report 1318 * 1319 * Dump FFT Report for gen3 1320 * 1321 * Return: void 1322 */ 1323 static void 1324 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral, 1325 enum spectral_scan_mode smode, 1326 struct spectral_phyerr_fft_report_gen3 *p_fft_report, 1327 struct spectral_search_fft_info_gen3 *p_sfft) 1328 { 1329 size_t fft_hdr_length = (p_fft_report->fft_hdr_length * 4); 1330 size_t report_len = (fft_hdr_length + 8); 1331 size_t fft_bin_len; 1332 size_t fft_bin_count; 1333 size_t fft_bin_len_inband_tfer = 0; 1334 uint8_t *fft_bin_buf = NULL; 1335 1336 fft_bin_len = fft_hdr_length - spectral->rparams.fft_report_hdr_len; 1337 fft_bin_count = target_if_spectral_get_bin_count_after_len_adj( 1338 fft_bin_len, 1339 spectral->params[smode].ss_rpt_mode, 1340 &spectral->len_adj_swar); 1341 1342 if ((spectral->params[smode].ss_rpt_mode == 2) && 1343 spectral->len_adj_swar.inband_fftbin_size_adj) 1344 fft_bin_len_inband_tfer = fft_bin_len >> 1; 1345 1346 spectral_debug("Spectral FFT Report"); 1347 spectral_debug("fft_timestamp = 0x%x", p_fft_report->fft_timestamp); 1348 spectral_debug("fft_hdr_length = %u(32 bit words)", 1349 p_fft_report->fft_hdr_length); 1350 spectral_debug("fft_hdr_tag = 0x%x", p_fft_report->fft_hdr_tag); 1351 spectral_debug("fft_hdr_sig = 0x%x", p_fft_report->fft_hdr_sig); 1352 1353 spectral_debug("Length field in search fft report is %zu(0x%zx) bytes", 1354 fft_hdr_length, fft_hdr_length); 1355 spectral_debug("Total length of search fft report is %zu(0x%zx) bytes", 1356 report_len, report_len); 1357 spectral_debug("Target reported fftbins in report is %zu(0x%zx)", 1358 fft_bin_len, fft_bin_len); 1359 1360 if ((spectral->params[smode].ss_rpt_mode == 1) && 1361 spectral->len_adj_swar.null_fftbin_adj) 1362 spectral_debug("WAR: Considering number of FFT bins as 0"); 1363 else if ((spectral->params[smode].ss_rpt_mode == 2) && 1364 spectral->len_adj_swar.inband_fftbin_size_adj) { 1365 spectral_debug("FW fftbins actually transferred (in-band report mode) %zu(0x%zx)", 1366 fft_bin_len_inband_tfer, 1367 fft_bin_len_inband_tfer); 1368 } 1369 1370 spectral_debug("Actual number of fftbins in report is %zu(0x%zx)", 1371 fft_bin_count, fft_bin_count); 1372 1373 spectral_debug("fft_detector_id = %u", p_sfft->fft_detector_id); 1374 spectral_debug("fft_num = %u", p_sfft->fft_num); 1375 spectral_debug("fft_radar_check = %u", p_sfft->fft_radar_check); 1376 spectral_debug("fft_peak_sidx = %d", p_sfft->fft_peak_sidx); 1377 spectral_debug("fft_chn_idx = %u", p_sfft->fft_chn_idx); 1378 spectral_debug("fft_base_pwr_db = %u", p_sfft->fft_base_pwr_db); 1379 spectral_debug("fft_total_gain_db = %u", p_sfft->fft_total_gain_db); 1380 spectral_debug("fft_num_str_bins_ib = %u", p_sfft->fft_num_str_bins_ib); 1381 spectral_debug("fft_peak_mag = %d", p_sfft->fft_peak_mag); 1382 spectral_debug("fft_avgpwr_db = %u", p_sfft->fft_avgpwr_db); 1383 spectral_debug("fft_relpwr_db = %u", p_sfft->fft_relpwr_db); 1384 1385 if (fft_bin_count > 0) { 1386 int idx; 1387 1388 spectral_debug("FFT bins:"); 1389 if (spectral->len_adj_swar.fftbin_size_war == 1390 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) { 1391 uint32_t *binptr_32 = (uint32_t *)&p_fft_report->buf; 1392 1393 fft_bin_buf = (uint8_t *)qdf_mem_malloc(MAX_NUM_BINS); 1394 for (idx = 0; idx < fft_bin_count; idx++) 1395 fft_bin_buf[idx] = *(binptr_32++); 1396 } else if (spectral->len_adj_swar.fftbin_size_war == 1397 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) { 1398 uint16_t *binptr_16 = (uint16_t *)&p_fft_report->buf; 1399 1400 fft_bin_buf = (uint8_t *)qdf_mem_malloc(MAX_NUM_BINS); 1401 for (idx = 0; idx < fft_bin_count; idx++) 1402 fft_bin_buf[idx] = *(binptr_16++); 1403 } else { 1404 fft_bin_buf = (uint8_t *)&p_fft_report->buf; 1405 } 1406 target_if_spectral_hexdump(fft_bin_buf, fft_bin_count); 1407 if ((spectral->len_adj_swar.fftbin_size_war != 1408 SPECTRAL_FFTBIN_SIZE_NO_WAR) && fft_bin_buf) 1409 qdf_mem_free(fft_bin_buf); 1410 } 1411 } 1412 #endif 1413 1414 QDF_STATUS 1415 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral, 1416 uint8_t detector_id) { 1417 QDF_STATUS status = QDF_STATUS_SUCCESS; 1418 1419 if (spectral->ch_width != CH_WIDTH_160MHZ) 1420 return QDF_STATUS_E_FAILURE; 1421 1422 /* agile reports should not be coupled with 160 MHz state machine 1423 * for normal Spectral 1424 */ 1425 if (detector_id == SPECTRAL_DETECTOR_AGILE) 1426 return QDF_STATUS_SUCCESS; 1427 1428 switch (spectral->state_160mhz_delivery) { 1429 case SPECTRAL_REPORT_WAIT_PRIMARY80: 1430 if (detector_id == SPECTRAL_DETECTOR_PRIMARY) 1431 spectral->state_160mhz_delivery = 1432 SPECTRAL_REPORT_RX_PRIMARY80; 1433 else { 1434 status = QDF_STATUS_E_FAILURE; 1435 spectral->diag_stats.spectral_vhtseg1id_mismatch++; 1436 } 1437 break; 1438 1439 case SPECTRAL_REPORT_WAIT_SECONDARY80: 1440 if (detector_id == SPECTRAL_DETECTOR_SECONDARY) 1441 spectral->state_160mhz_delivery = 1442 SPECTRAL_REPORT_RX_SECONDARY80; 1443 else { 1444 spectral->state_160mhz_delivery = 1445 SPECTRAL_REPORT_WAIT_PRIMARY80; 1446 status = QDF_STATUS_E_FAILURE; 1447 spectral->diag_stats.spectral_vhtseg2id_mismatch++; 1448 } 1449 break; 1450 1451 case SPECTRAL_REPORT_RX_SECONDARY80: 1452 /* We don't care about detector id in this state. */ 1453 reset_160mhz_delivery_state_machine(spectral, 1454 SPECTRAL_SCAN_MODE_NORMAL); 1455 break; 1456 1457 case SPECTRAL_REPORT_RX_PRIMARY80: 1458 /* We don't care about detector id in this state */ 1459 spectral->state_160mhz_delivery = 1460 SPECTRAL_REPORT_WAIT_SECONDARY80; 1461 break; 1462 1463 default: 1464 break; 1465 } 1466 1467 return status; 1468 } 1469 1470 #ifdef DIRECT_BUF_RX_ENABLE 1471 /** 1472 * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector 1473 * ID from Spectral summary report 1474 * @data: Pointer to Spectral summary report 1475 * 1476 * Return: Detector ID 1477 */ 1478 static uint8_t 1479 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data) { 1480 struct spectral_sscan_summary_report_gen3 *psscan_summary_report; 1481 uint8_t detector_id; 1482 1483 qdf_assert_always(data); 1484 1485 psscan_summary_report = 1486 (struct spectral_sscan_summary_report_gen3 *)data; 1487 1488 detector_id = get_bitfield( 1489 psscan_summary_report->hdr_a, 1490 SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3, 1491 SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3); 1492 1493 return detector_id; 1494 } 1495 1496 /** 1497 * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary 1498 * report 1499 * @data: Pointer to Spectral summary report 1500 * @fields: Pointer to structure to be populated with extracted fields 1501 * @rparams: Pointer to structure with Spectral report params 1502 * 1503 * Consume Spectral summary report for gen3 1504 * 1505 * Return: void 1506 */ 1507 static void 1508 target_if_consume_sscan_summary_report_gen3( 1509 uint8_t *data, 1510 struct sscan_report_fields_gen3 *fields, 1511 struct spectral_report_params *rparams) { 1512 struct spectral_sscan_summary_report_gen3 *psscan_summary_report; 1513 1514 qdf_assert_always(data); 1515 qdf_assert_always(fields); 1516 qdf_assert_always(rparams); 1517 1518 psscan_summary_report = 1519 (struct spectral_sscan_summary_report_gen3 *)data; 1520 1521 fields->sscan_agc_total_gain = get_bitfield( 1522 psscan_summary_report->hdr_a, 1523 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3, 1524 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3); 1525 fields->inband_pwr_db = get_bitfield( 1526 psscan_summary_report->hdr_a, 1527 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3, 1528 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3); 1529 fields->sscan_pri80 = get_bitfield( 1530 psscan_summary_report->hdr_a, 1531 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3, 1532 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3); 1533 1534 switch (rparams->version) { 1535 case SPECTRAL_REPORT_FORMAT_VERSION_1: 1536 fields->sscan_gainchange = get_bitfield( 1537 psscan_summary_report->hdr_b, 1538 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3_V1, 1539 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3_V1); 1540 break; 1541 case SPECTRAL_REPORT_FORMAT_VERSION_2: 1542 fields->sscan_gainchange = get_bitfield( 1543 psscan_summary_report->hdr_c, 1544 SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_SIZE_GEN3_V2, 1545 SSCAN_SUMMARY_REPORT_HDR_C_GAINCHANGE_POS_GEN3_V2); 1546 break; 1547 default: 1548 qdf_assert_always(0); 1549 } 1550 } 1551 1552 /** 1553 * target_if_verify_sig_and_tag_gen3() - Verify tag and signature 1554 * of spectral report 1555 * @spectral: Pointer to spectral object 1556 * @data: Pointer to spectral summary report 1557 * @exp_tag: iexpected tag value 1558 * 1559 * Process fft report for gen3 1560 * 1561 * Return: SUCCESS/FAILURE 1562 */ 1563 static int 1564 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral, 1565 uint8_t *data, uint8_t exp_tag) 1566 { 1567 uint8_t tag = 0; 1568 uint8_t signature = 0; 1569 1570 /* Peek into the data to figure out whether 1571 * 1) Signature matches the expected value 1572 * 2) What is inside the package (TAG ID is used for finding this) 1573 */ 1574 tag = *(data + PHYERR_HDR_TAG_POS); 1575 signature = *(data + PHYERR_HDR_SIG_POS); 1576 1577 if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) { 1578 spectral->diag_stats.spectral_mismatch++; 1579 return -EINVAL; 1580 } 1581 1582 if (tag != exp_tag) { 1583 spectral->diag_stats.spectral_mismatch++; 1584 return -EINVAL; 1585 } 1586 1587 return 0; 1588 } 1589 1590 static uint8_t 1591 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask) 1592 { 1593 uint8_t idx; 1594 1595 for (idx = 0; idx < DBR_MAX_CHAINS; idx++) { 1596 if (chainmask & 0x1) 1597 break; 1598 chainmask >>= 1; 1599 } 1600 return idx; 1601 } 1602 1603 static QDF_STATUS 1604 target_if_get_spectral_mode(enum spectral_detector_id detector_id, 1605 enum spectral_scan_mode *smode) { 1606 switch (detector_id) { 1607 case SPECTRAL_DETECTOR_PRIMARY: 1608 case SPECTRAL_DETECTOR_SECONDARY: 1609 *smode = SPECTRAL_SCAN_MODE_NORMAL; 1610 break; 1611 1612 case SPECTRAL_DETECTOR_AGILE: 1613 *smode = SPECTRAL_SCAN_MODE_AGILE; 1614 break; 1615 1616 default: 1617 spectral_err("Invalid Spectral detector id"); 1618 return QDF_STATUS_E_FAILURE; 1619 } 1620 1621 return QDF_STATUS_SUCCESS; 1622 } 1623 1624 #ifdef DIRECT_BUF_RX_DEBUG 1625 static void target_if_spectral_check_buffer_poisoning( 1626 struct target_if_spectral *spectral, 1627 struct spectral_report *report, 1628 int num_fft_bins, enum spectral_scan_mode smode) 1629 { 1630 uint32_t *data; 1631 size_t len; 1632 size_t words_to_check = 1633 sizeof(struct spectral_sscan_summary_report_gen3) >> 2; 1634 bool poisoned_words_found = false; 1635 1636 if (!spectral) { 1637 spectral_err_rl("Spectral LMAC object is null"); 1638 return; 1639 } 1640 1641 if (!spectral->dbr_buff_debug) 1642 return; 1643 1644 if (!report) { 1645 spectral_err_rl("Spectral report is null"); 1646 return; 1647 } 1648 1649 /* Add search FFT report */ 1650 if (spectral->params[smode].ss_rpt_mode > 0) 1651 words_to_check += 1652 sizeof(struct spectral_phyerr_fft_report_gen3) >> 2; 1653 1654 /* Now add the number of FFT bins */ 1655 if (spectral->params[smode].ss_rpt_mode > 1) { 1656 /* Caller should take care to pass correct number of FFT bins */ 1657 if (spectral->len_adj_swar.fftbin_size_war == 1658 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) 1659 words_to_check += num_fft_bins; 1660 else if (spectral->len_adj_swar.fftbin_size_war == 1661 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) 1662 words_to_check += (num_fft_bins >> 1); 1663 } 1664 1665 data = (uint32_t *)report->data; 1666 for (len = 0; len < words_to_check; ++len) { 1667 if (*data == MEM_POISON_SIGNATURE) { 1668 spectral_err("Pattern(%x) found in Spectral search FFT report at position %zu in the buffer %pK", 1669 MEM_POISON_SIGNATURE, 1670 (len << 2), report->data); 1671 poisoned_words_found = true; 1672 break; 1673 } 1674 ++data; 1675 } 1676 1677 /* Crash the FW even if one word is poisoned */ 1678 if (poisoned_words_found) { 1679 spectral_err("Pattern(%x) found in Spectral report, Hex dump of the sfft follows", 1680 MEM_POISON_SIGNATURE); 1681 target_if_spectral_hexdump((unsigned char *)report->data, 1682 words_to_check << 2); 1683 spectral_err("Asserting the FW"); 1684 target_if_spectral_fw_hang(spectral); 1685 } 1686 } 1687 1688 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral, 1689 uint8_t *buf, uint32_t current_ts) 1690 { 1691 if (!spectral) { 1692 spectral_err_rl("Spectral LMAC object is null"); 1693 return; 1694 } 1695 1696 if (!spectral->dbr_buff_debug) 1697 return; 1698 1699 if (spectral->prev_tstamp) { 1700 if (current_ts == spectral->prev_tstamp) { 1701 spectral_err("Spectral timestamp(%u) in the current buffer(%pK) is equal to the previous timestamp, same report DMAed twice? Asserting the FW", 1702 current_ts, buf); 1703 target_if_spectral_fw_hang(spectral); 1704 } 1705 } 1706 spectral->prev_tstamp = current_ts; 1707 } 1708 #else 1709 static void target_if_spectral_check_buffer_poisoning( 1710 struct target_if_spectral *spectral, 1711 struct spectral_report *report, 1712 int num_fft_bins, enum spectral_scan_mode smode) 1713 { 1714 } 1715 1716 static void target_if_spectral_verify_ts(struct target_if_spectral *spectral, 1717 uint8_t *buf, uint32_t current_ts) 1718 { 1719 } 1720 #endif 1721 1722 /** 1723 * target_if_spectral_get_adjusted_timestamp() - Adjust Spectral time 1724 * stamp to account for reset in time stamp due to target reset 1725 * @twar: Spectral time stamp WAR related information 1726 * @raw_timestamp: Spectral time stamp reported by target 1727 * @reset_delay: Reset delay at target 1728 * @smode: Spectral scan mode 1729 * 1730 * Correct time stamp to account for reset in time stamp due to target reset 1731 * 1732 * Return: Adjusted time stamp 1733 */ 1734 static uint32_t 1735 target_if_spectral_get_adjusted_timestamp(struct spectral_timestamp_war *twar, 1736 uint32_t raw_timestamp, 1737 uint32_t reset_delay, 1738 enum spectral_scan_mode smode) { 1739 qdf_assert_always(smode < SPECTRAL_SCAN_MODE_MAX); 1740 1741 if (reset_delay) { 1742 enum spectral_scan_mode m = 1743 SPECTRAL_SCAN_MODE_NORMAL; 1744 1745 /* Adjust the offset for all the Spectral modes. 1746 * Target will be sending the non zero reset delay for 1747 * the first Spectral report after reset. This delay is 1748 * common for all the Spectral modes. 1749 */ 1750 for (; m < SPECTRAL_SCAN_MODE_MAX; m++) 1751 twar->timestamp_war_offset[m] += (reset_delay + 1752 twar->last_fft_timestamp[m]); 1753 twar->target_reset_count++; 1754 } 1755 twar->last_fft_timestamp[smode] = raw_timestamp; 1756 1757 return raw_timestamp + twar->timestamp_war_offset[smode]; 1758 } 1759 1760 int 1761 target_if_consume_spectral_report_gen3( 1762 struct target_if_spectral *spectral, 1763 struct spectral_report *report) 1764 { 1765 /* 1766 * XXX : The classifier do not use all the members of the SAMP 1767 * message data format. 1768 * The classifier only depends upon the following parameters 1769 * 1770 * 1. Frequency (freq, msg->freq) 1771 * 2. Spectral RSSI (spectral_rssi, 1772 * msg->samp_data.spectral_rssi) 1773 * 3. Bin Power Count (bin_pwr_count, 1774 * msg->samp_data.bin_pwr_count) 1775 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0] 1776 * 5. Spectral Timestamp (spectral_tstamp, 1777 * msg->samp_data.spectral_tstamp) 1778 * 6. MAC Address (macaddr, msg->macaddr) 1779 * 1780 * This function prepares the params structure and populates it 1781 * with 1782 * relevant values, this is in turn passed to 1783 * spectral_create_samp_msg() 1784 * to prepare fully formatted Spectral SAMP message 1785 * 1786 * XXX : Need to verify 1787 * 1. Order of FFT bin values 1788 * 1789 */ 1790 struct target_if_samp_msg_params params = {0}; 1791 struct spectral_search_fft_info_gen3 search_fft_info; 1792 struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info; 1793 int8_t chn_idx_lowest_enabled = 0; 1794 int fft_hdr_length = 0; 1795 int report_len = 0; 1796 size_t fft_bin_count; 1797 struct target_if_spectral_ops *p_sops = 1798 GET_TARGET_IF_SPECTRAL_OPS(spectral); 1799 struct spectral_phyerr_fft_report_gen3 *p_fft_report; 1800 int8_t rssi; 1801 uint8_t *data = report->data; 1802 struct wlan_objmgr_vdev *vdev; 1803 uint8_t vdev_rxchainmask; 1804 struct sscan_report_fields_gen3 sscan_report_fields = {0}; 1805 enum spectral_detector_id detector_id; 1806 QDF_STATUS ret; 1807 1808 params.smode = SPECTRAL_SCAN_MODE_NORMAL; 1809 1810 /* Process Spectral scan summary report */ 1811 if (target_if_verify_sig_and_tag_gen3( 1812 spectral, data, 1813 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) { 1814 spectral_err_rl("Wrong tag/sig in sscan summary"); 1815 goto fail; 1816 } 1817 1818 detector_id = target_if_get_detector_id_sscan_summary_report_gen3(data); 1819 if (detector_id > SPECTRAL_DETECTOR_AGILE) { 1820 spectral->diag_stats.spectral_invalid_detector_id++; 1821 spectral_err("Invalid detector id %u, expected is 0/1/2", 1822 detector_id); 1823 goto fail; 1824 } 1825 target_if_consume_sscan_summary_report_gen3(data, &sscan_report_fields, 1826 &spectral->rparams); 1827 /* Advance buf pointer to the search fft report */ 1828 data += sizeof(struct spectral_sscan_summary_report_gen3); 1829 data += spectral->rparams.ssumaary_padding_bytes; 1830 1831 if ((detector_id == SPECTRAL_DETECTOR_AGILE) || 1832 is_primaryseg_expected(spectral)) { 1833 /* RSSI is in 1/2 dBm steps, Covert it to dBm scale */ 1834 rssi = (sscan_report_fields.inband_pwr_db) >> 1; 1835 params.agc_total_gain = 1836 sscan_report_fields.sscan_agc_total_gain; 1837 params.gainchange = sscan_report_fields.sscan_gainchange; 1838 params.pri80ind = sscan_report_fields.sscan_pri80; 1839 1840 /* Process Spectral search FFT report */ 1841 if (target_if_verify_sig_and_tag_gen3( 1842 spectral, data, 1843 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) { 1844 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u", 1845 detector_id); 1846 goto fail; 1847 } 1848 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data; 1849 fft_hdr_length = p_fft_report->fft_hdr_length * 4; 1850 if (fft_hdr_length < 16) { 1851 spectral_err("Wrong TLV length %u, detector id = %d", 1852 fft_hdr_length, detector_id); 1853 goto fail; 1854 } 1855 1856 report_len = (fft_hdr_length + 8); 1857 1858 target_if_process_sfft_report_gen3(p_fft_report, p_sfft); 1859 /* It is expected to have same detector id for 1860 * summary and fft report 1861 */ 1862 if (detector_id != p_sfft->fft_detector_id) { 1863 spectral_err_rl 1864 ("Different detid in ssummary(%u) and sfft(%u)", 1865 detector_id, p_sfft->fft_detector_id); 1866 goto fail; 1867 } 1868 1869 if (detector_id > SPECTRAL_DETECTOR_AGILE) { 1870 spectral->diag_stats.spectral_invalid_detector_id++; 1871 spectral_err("Invalid detector id %u, expected is 0/2", 1872 detector_id); 1873 goto fail; 1874 } 1875 1876 ret = target_if_get_spectral_mode(detector_id, ¶ms.smode); 1877 if (QDF_IS_STATUS_ERROR(ret)) { 1878 spectral_err_rl("Failed to get mode from detid= %u", 1879 detector_id); 1880 goto fail; 1881 } 1882 1883 fft_bin_count = target_if_spectral_get_bin_count_after_len_adj( 1884 fft_hdr_length - spectral->rparams.fft_report_hdr_len, 1885 spectral->params[params.smode].ss_rpt_mode, 1886 &spectral->len_adj_swar); 1887 1888 params.last_raw_timestamp = spectral->timestamp_war. 1889 last_fft_timestamp[params.smode]; 1890 params.reset_delay = report->reset_delay; 1891 params.raw_timestamp = p_sfft->timestamp; 1892 params.tstamp = target_if_spectral_get_adjusted_timestamp( 1893 &spectral->timestamp_war, 1894 p_sfft->timestamp, report->reset_delay, 1895 params.smode); 1896 params.timestamp_war_offset = spectral->timestamp_war. 1897 timestamp_war_offset[params.smode]; 1898 params.target_reset_count = spectral->timestamp_war. 1899 target_reset_count; 1900 1901 /* Take care of state transitions for 160 MHz and 80p80 */ 1902 if (spectral->ch_width == CH_WIDTH_160MHZ) { 1903 ret = target_if_160mhz_delivery_state_change( 1904 spectral, 1905 detector_id); 1906 if (ret != QDF_STATUS_SUCCESS) 1907 goto fail; 1908 } 1909 1910 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) 1911 target_if_dump_fft_report_gen3(spectral, params.smode, 1912 p_fft_report, p_sfft); 1913 1914 params.rssi = rssi; 1915 1916 vdev = target_if_spectral_get_vdev(spectral); 1917 if (!vdev) { 1918 spectral_info("First vdev is NULL"); 1919 reset_160mhz_delivery_state_machine 1920 (spectral, 1921 SPECTRAL_SCAN_MODE_NORMAL); 1922 return -EPERM; 1923 } 1924 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev); 1925 QDF_ASSERT(vdev_rxchainmask != 0); 1926 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1927 1928 chn_idx_lowest_enabled = 1929 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask); 1930 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) { 1931 spectral_err("Invalid chain index, detector id = %u", 1932 detector_id); 1933 goto fail; 1934 } 1935 1936 params.max_mag = p_sfft->fft_peak_mag; 1937 1938 params.bin_pwr_data = (uint8_t *)((uint8_t *)p_fft_report + 1939 SPECTRAL_FFT_BINS_POS); 1940 params.freq = p_sops->get_current_channel(spectral); 1941 1942 if (params.smode == SPECTRAL_SCAN_MODE_AGILE) 1943 params.agile_freq = 1944 spectral->params[params.smode].ss_frequency; 1945 1946 /* 1947 * For modes upto VHT80, the noise floor is populated with 1948 * the one corresponding 1949 * to the highest enabled antenna chain 1950 */ 1951 /* TODO: Fill proper values once FW provides them*/ 1952 params.noise_floor = 1953 report->noisefloor[chn_idx_lowest_enabled]; 1954 params.datalen = (fft_hdr_length * 4); 1955 params.pwr_count = fft_bin_count; 1956 1957 target_if_spectral_verify_ts(spectral, report->data, 1958 params.tstamp); 1959 } else if (is_secondaryseg_expected(spectral)) { 1960 /* RSSI is in 1/2 dBm steps, Covert it to dBm scale */ 1961 rssi = (sscan_report_fields.inband_pwr_db) >> 1; 1962 params.agc_total_gain_sec80 = 1963 sscan_report_fields.sscan_agc_total_gain; 1964 params.gainchange_sec80 = sscan_report_fields.sscan_gainchange; 1965 params.pri80ind_sec80 = sscan_report_fields.sscan_pri80; 1966 1967 /* Process Spectral search FFT report */ 1968 if (target_if_verify_sig_and_tag_gen3( 1969 spectral, data, 1970 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) { 1971 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u", 1972 detector_id); 1973 goto fail; 1974 } 1975 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data; 1976 fft_hdr_length = p_fft_report->fft_hdr_length * 4; 1977 if (fft_hdr_length < 16) { 1978 spectral_err("Wrong TLV length %u, detector id = %u", 1979 fft_hdr_length, detector_id); 1980 goto fail; 1981 } 1982 1983 report_len = (fft_hdr_length + 8); 1984 1985 target_if_process_sfft_report_gen3(p_fft_report, p_sfft); 1986 /* It is expected to have same detector id for 1987 * summary and fft report 1988 */ 1989 if (detector_id != p_sfft->fft_detector_id) { 1990 spectral_err_rl 1991 ("Different detid in ssummary(%u) and sfft(%u)", 1992 detector_id, p_sfft->fft_detector_id); 1993 goto fail; 1994 } 1995 1996 if (detector_id > SPECTRAL_DETECTOR_AGILE) { 1997 spectral->diag_stats.spectral_invalid_detector_id++; 1998 spectral_err("Invalid detector id %u, expected is 1", 1999 detector_id); 2000 goto fail; 2001 } 2002 2003 ret = target_if_get_spectral_mode(detector_id, ¶ms.smode); 2004 if (QDF_IS_STATUS_ERROR(ret)) { 2005 spectral_err("Failed to get mode from detid= %u", 2006 detector_id); 2007 goto fail; 2008 } 2009 2010 fft_bin_count = target_if_spectral_get_bin_count_after_len_adj( 2011 fft_hdr_length - spectral->rparams.fft_report_hdr_len, 2012 spectral->params[params.smode].ss_rpt_mode, 2013 &spectral->len_adj_swar); 2014 params.raw_timestamp_sec80 = p_sfft->timestamp; 2015 2016 /* Take care of state transitions for 160 MHz and 80p80 */ 2017 if (spectral->ch_width == CH_WIDTH_160MHZ) { 2018 ret = target_if_160mhz_delivery_state_change( 2019 spectral, 2020 detector_id); 2021 if (ret != QDF_STATUS_SUCCESS) 2022 goto fail; 2023 } 2024 2025 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) 2026 target_if_dump_fft_report_gen3(spectral, params.smode, 2027 p_fft_report, p_sfft); 2028 2029 params.vhtop_ch_freq_seg1 = 0; 2030 params.vhtop_ch_freq_seg2 = 0; 2031 2032 params.rssi_sec80 = rssi; 2033 2034 vdev = target_if_spectral_get_vdev(spectral); 2035 if (!vdev) { 2036 spectral_info("First vdev is NULL"); 2037 reset_160mhz_delivery_state_machine 2038 (spectral, 2039 SPECTRAL_SCAN_MODE_NORMAL); 2040 return -EPERM; 2041 } 2042 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev); 2043 QDF_ASSERT(vdev_rxchainmask != 0); 2044 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 2045 2046 chn_idx_lowest_enabled = 2047 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask); 2048 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) { 2049 spectral_err("Invalid chain index"); 2050 goto fail; 2051 } 2052 2053 /* Need to change this as per FW team's inputs */ 2054 params.noise_floor_sec80 = 2055 report->noisefloor[chn_idx_lowest_enabled]; 2056 2057 params.max_mag_sec80 = p_sfft->fft_peak_mag; 2058 /* params.max_index_sec80 = p_sfft->peak_inx; */ 2059 /* XXX Does this definition of datalen *still hold? */ 2060 params.datalen_sec80 = fft_hdr_length * 4; 2061 params.pwr_count_sec80 = fft_bin_count; 2062 params.bin_pwr_data_sec80 = 2063 (uint8_t *)((uint8_t *)p_fft_report + 2064 SPECTRAL_FFT_BINS_POS); 2065 } else { 2066 spectral_err("Spectral state machine in undefined state"); 2067 goto fail; 2068 } 2069 2070 target_if_spectral_check_buffer_poisoning(spectral, report, 2071 fft_bin_count, params.smode); 2072 qdf_mem_copy(¶ms.classifier_params, 2073 &spectral->classifier_params, 2074 sizeof(struct spectral_classifier_params)); 2075 2076 target_if_spectral_log_SAMP_param(¶ms); 2077 target_if_spectral_create_samp_msg(spectral, ¶ms); 2078 2079 return 0; 2080 fail: 2081 spectral_err_rl("Error while processing Spectral report"); 2082 reset_160mhz_delivery_state_machine(spectral, 2083 SPECTRAL_SCAN_MODE_NORMAL); 2084 return -EPERM; 2085 } 2086 2087 int target_if_spectral_process_report_gen3( 2088 struct wlan_objmgr_pdev *pdev, 2089 void *buf) 2090 { 2091 int ret = 0; 2092 struct direct_buf_rx_data *payload = buf; 2093 struct target_if_spectral *spectral; 2094 struct spectral_report report; 2095 2096 spectral = get_target_if_spectral_handle_from_pdev(pdev); 2097 if (!spectral) { 2098 spectral_err("Spectral target object is null"); 2099 return -EINVAL; 2100 } 2101 2102 report.data = payload->vaddr; 2103 if (payload->meta_data_valid) { 2104 qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor, 2105 qdf_min(sizeof(report.noisefloor), 2106 sizeof(payload->meta_data.noisefloor))); 2107 report.reset_delay = payload->meta_data.reset_delay; 2108 } 2109 2110 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) { 2111 spectral_debug("Printing the spectral phyerr buffer for debug"); 2112 spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK", 2113 payload->dbr_len, 2114 payload->dbr_len, 2115 payload->vaddr); 2116 target_if_spectral_hexdump((unsigned char *)payload->vaddr, 2117 1024); 2118 } 2119 2120 ret = target_if_consume_spectral_report_gen3(spectral, &report); 2121 2122 if (spectral_debug_level & DEBUG_SPECTRAL4) 2123 spectral_debug_level = DEBUG_SPECTRAL; 2124 2125 return ret; 2126 } 2127 #else 2128 int target_if_spectral_process_report_gen3( 2129 struct wlan_objmgr_pdev *pdev, 2130 void *buf) 2131 { 2132 spectral_err("Direct dma support is not enabled"); 2133 return -EINVAL; 2134 } 2135 #endif 2136 qdf_export_symbol(target_if_spectral_process_report_gen3); 2137 /* END of spectral GEN III HW specific functions */ 2138 2139 #endif /* WLAN_CONV_SPECTRAL_ENABLE */ 2140