1 /* 2 * Copyright (c) 2011,2017-2019 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 int 1198 target_if_process_sfft_report_gen3( 1199 struct spectral_phyerr_fft_report_gen3 *p_fft_report, 1200 struct spectral_search_fft_info_gen3 *p_sfft) 1201 { 1202 /* 1203 * For simplicity, everything is defined as uint32_t (except one). 1204 * Proper code will later use the right sizes. 1205 */ 1206 /* 1207 * For easy comparision between MDK team and OS team, the MDK script 1208 * variable names have been used 1209 */ 1210 int32_t peak_sidx; 1211 int32_t peak_mag; 1212 1213 /* Populate the Search FFT Info */ 1214 if (p_sfft) { 1215 p_sfft->timestamp = p_fft_report->fft_timestamp; 1216 1217 p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a, 1218 2, 0); 1219 p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2); 1220 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a, 1221 12, 5); 1222 1223 peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17); 1224 p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11); 1225 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28); 1226 1227 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b, 1228 9, 0); 1229 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b, 1230 8, 9); 1231 1232 p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c, 1233 8, 0); 1234 peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8); 1235 p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10); 1236 p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c, 1237 7, 18); 1238 p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c, 1239 7, 25); 1240 } 1241 1242 return 0; 1243 } 1244 1245 int 1246 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral, 1247 enum spectral_scan_mode smode, 1248 struct spectral_phyerr_fft_report_gen3 *p_fft_report, 1249 struct spectral_search_fft_info_gen3 *p_sfft) 1250 { 1251 int i = 0; 1252 int fft_mag = 0; 1253 int fft_hdr_length = (p_fft_report->fft_hdr_length * 4); 1254 int report_len = (fft_hdr_length + 8); 1255 int fft_bin_len = (fft_hdr_length - 16); 1256 int fft_bin_len_to_dump = fft_bin_len; 1257 int fft_bin_len_adj = 0; 1258 int fft_bin_len_inband_tfer = 0; 1259 1260 if ((spectral->params[smode].ss_rpt_mode == 1) && 1261 spectral->null_fftbin_adj) { 1262 /* fft_bin_len_adj is intentionally left at 0. */ 1263 fft_bin_len_to_dump = 0; 1264 } else { 1265 /* 1266 * Divide fft bin length by appropriate factor depending 1267 * on the value of fftbin_size_war. 1268 */ 1269 if (spectral->fftbin_size_war == 1270 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) 1271 fft_bin_len_adj = fft_bin_len >> 2; 1272 else if (spectral->fftbin_size_war == 1273 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) { 1274 /* Ideally we should be dividing fft bin length by 2. 1275 * Due to a HW bug, actual length is two times the 1276 * expected length. 1277 */ 1278 fft_bin_len_adj = fft_bin_len >> 2; 1279 } else 1280 fft_bin_len_adj = fft_bin_len; 1281 1282 if ((spectral->params[smode].ss_rpt_mode == 2) && 1283 spectral->inband_fftbin_size_adj) { 1284 fft_bin_len_adj >>= 1; 1285 fft_bin_len_inband_tfer = fft_bin_len >> 1; 1286 fft_bin_len_to_dump = fft_bin_len_inband_tfer; 1287 } 1288 } 1289 1290 spectral_debug("#############################################################"); 1291 spectral_debug("Spectral search fft_report"); 1292 spectral_debug("fft_timestamp = 0x%x\nfft_hdr_length = %d(32 bit words)\nfft_hdr_tag = 0x%x\nfft_hdr_sig = 0x%x", 1293 p_fft_report->fft_timestamp, 1294 p_fft_report->fft_hdr_length, 1295 p_fft_report->fft_hdr_tag, p_fft_report->fft_hdr_sig); 1296 1297 spectral_debug("Length field in search fft report is %d(0x%x) bytes", 1298 fft_hdr_length, fft_hdr_length); 1299 spectral_debug("Total length of search fft report is %d(0x%x) bytes", 1300 report_len, report_len); 1301 spectral_debug("Target reported fftbins in report is %d(0x%x)", 1302 fft_bin_len, 1303 fft_bin_len); 1304 1305 if ((spectral->params[smode].ss_rpt_mode == 1) && 1306 spectral->null_fftbin_adj) 1307 spectral_debug("WAR: Considering number of FFT bins as 0"); 1308 else if ((spectral->params[smode].ss_rpt_mode == 2) && 1309 spectral->inband_fftbin_size_adj) { 1310 spectral_debug("FW fftbins actually transferred (in-band report mode) " 1311 "%d(0x%x)", 1312 fft_bin_len_inband_tfer, fft_bin_len_inband_tfer); 1313 } 1314 1315 spectral_debug("Actual number of fftbins in report is %d(0x%x)\n", 1316 fft_bin_len_adj, fft_bin_len_adj); 1317 1318 spectral_debug("fft_detector_id = %u\nfft_num = %u\nfft_radar_check = %u\nfft_peak_sidx = %d\nfft_chn_idx = %u\nfft_base_pwr_db = %u\nfft_total_gain_db = %u\nfft_num_str_bins_ib = %u\nfft_peak_mag = %d\nfft_avgpwr_db = %u\nfft_relpwr_db = %u", 1319 p_sfft->fft_detector_id, 1320 p_sfft->fft_num, 1321 p_sfft->fft_radar_check, 1322 p_sfft->fft_peak_sidx, 1323 p_sfft->fft_chn_idx, 1324 p_sfft->fft_base_pwr_db, 1325 p_sfft->fft_total_gain_db, 1326 p_sfft->fft_num_str_bins_ib, 1327 p_sfft->fft_peak_mag, 1328 p_sfft->fft_avgpwr_db, p_sfft->fft_relpwr_db); 1329 1330 if (fft_bin_len_to_dump > 0) { 1331 spectral_debug("FFT bins:"); 1332 for (i = 0; i < fft_bin_len_to_dump; i++) { 1333 if (i % 16 == 0) 1334 spectral_debug("\n%d :", i); 1335 fft_mag = 1336 ((uint8_t *)p_fft_report)[SPECTRAL_FFT_BINS_POS + i]; 1337 spectral_debug("%d ", fft_mag); 1338 } 1339 } 1340 spectral_debug("\n"); 1341 spectral_debug("#############################################################"); 1342 1343 return 0; 1344 } 1345 1346 QDF_STATUS 1347 target_if_160mhz_delivery_state_change(struct target_if_spectral *spectral, 1348 uint8_t detector_id) { 1349 QDF_STATUS status = QDF_STATUS_SUCCESS; 1350 1351 if (spectral->ch_width != CH_WIDTH_160MHZ) 1352 return QDF_STATUS_E_FAILURE; 1353 1354 /* agile reports should not be coupled with 160 MHz state machine 1355 * for normal Spectral 1356 */ 1357 if (detector_id == SPECTRAL_DETECTOR_AGILE) 1358 return QDF_STATUS_SUCCESS; 1359 1360 switch (spectral->state_160mhz_delivery) { 1361 case SPECTRAL_REPORT_WAIT_PRIMARY80: 1362 if (detector_id == SPECTRAL_DETECTOR_PRIMARY) 1363 spectral->state_160mhz_delivery = 1364 SPECTRAL_REPORT_RX_PRIMARY80; 1365 else { 1366 status = QDF_STATUS_E_FAILURE; 1367 spectral->diag_stats.spectral_vhtseg1id_mismatch++; 1368 } 1369 break; 1370 1371 case SPECTRAL_REPORT_WAIT_SECONDARY80: 1372 if (detector_id == SPECTRAL_DETECTOR_SECONDARY) 1373 spectral->state_160mhz_delivery = 1374 SPECTRAL_REPORT_RX_SECONDARY80; 1375 else { 1376 spectral->state_160mhz_delivery = 1377 SPECTRAL_REPORT_WAIT_PRIMARY80; 1378 status = QDF_STATUS_E_FAILURE; 1379 spectral->diag_stats.spectral_vhtseg2id_mismatch++; 1380 } 1381 break; 1382 1383 case SPECTRAL_REPORT_RX_SECONDARY80: 1384 /* We don't care about detector id in this state. */ 1385 reset_160mhz_delivery_state_machine(spectral, 1386 SPECTRAL_SCAN_MODE_NORMAL); 1387 break; 1388 1389 case SPECTRAL_REPORT_RX_PRIMARY80: 1390 /* We don't care about detector id in this state */ 1391 spectral->state_160mhz_delivery = 1392 SPECTRAL_REPORT_WAIT_SECONDARY80; 1393 break; 1394 1395 default: 1396 break; 1397 } 1398 1399 return status; 1400 } 1401 1402 #ifdef DIRECT_BUF_RX_ENABLE 1403 /** 1404 * target_if_get_detector_id_sscan_summary_report_gen3() - Get Spectral detector 1405 * ID from Spectral summary report 1406 * @data: Pointer to Spectral summary report 1407 * 1408 * Return: Detector ID 1409 */ 1410 static uint8_t 1411 target_if_get_detector_id_sscan_summary_report_gen3(uint8_t *data) { 1412 struct spectral_sscan_summary_report_gen3 *psscan_summary_report; 1413 uint8_t detector_id; 1414 1415 qdf_assert_always(data); 1416 1417 psscan_summary_report = 1418 (struct spectral_sscan_summary_report_gen3 *)data; 1419 1420 detector_id = get_bitfield( 1421 psscan_summary_report->hdr_a, 1422 SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_SIZE_GEN3, 1423 SSCAN_SUMMARY_REPORT_HDR_A_DETECTOR_ID_POS_GEN3); 1424 1425 return detector_id; 1426 } 1427 1428 /** 1429 * target_if_consume_sscan_summary_report_gen3() - Consume Spectral summary 1430 * report 1431 * @spectral: Pointer to Spectral object 1432 * @data: Pointer to Spectral summary report 1433 * @fields: Pointer to structure to be populated with extracted fields 1434 * 1435 * Consume Spectral summary report for gen3 1436 * 1437 * Return: void 1438 */ 1439 static void 1440 target_if_consume_sscan_summary_report_gen3(struct target_if_spectral *spectral, 1441 uint8_t *data, 1442 struct sscan_report_fields_gen3 1443 *fields) { 1444 struct spectral_sscan_summary_report_gen3 *psscan_summary_report; 1445 1446 qdf_assert_always(spectral); 1447 qdf_assert_always(data); 1448 qdf_assert_always(fields); 1449 1450 psscan_summary_report = 1451 (struct spectral_sscan_summary_report_gen3 *)data; 1452 1453 fields->sscan_agc_total_gain = get_bitfield( 1454 psscan_summary_report->hdr_a, 1455 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_SIZE_GEN3, 1456 SSCAN_SUMMARY_REPORT_HDR_A_AGC_TOTAL_GAIN_POS_GEN3); 1457 fields->inband_pwr_db = get_bitfield( 1458 psscan_summary_report->hdr_a, 1459 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_SIZE_GEN3, 1460 SSCAN_SUMMARY_REPORT_HDR_A_INBAND_PWR_DB_POS_GEN3); 1461 fields->sscan_pri80 = get_bitfield( 1462 psscan_summary_report->hdr_a, 1463 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_SIZE_GEN3, 1464 SSCAN_SUMMARY_REPORT_HDR_A_PRI80_POS_GEN3); 1465 fields->sscan_gainchange = get_bitfield( 1466 psscan_summary_report->hdr_b, 1467 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_SIZE_GEN3, 1468 SSCAN_SUMMARY_REPORT_HDR_B_GAINCHANGE_POS_GEN3); 1469 } 1470 1471 /** 1472 * target_if_verify_sig_and_tag_gen3() - Verify tag and signature 1473 * of spectral report 1474 * @spectral: Pointer to spectral object 1475 * @data: Pointer to spectral summary report 1476 * @exp_tag: iexpected tag value 1477 * 1478 * Process fft report for gen3 1479 * 1480 * Return: SUCCESS/FAILURE 1481 */ 1482 static int 1483 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral, 1484 uint8_t *data, uint8_t exp_tag) 1485 { 1486 uint8_t tag = 0; 1487 uint8_t signature = 0; 1488 1489 /* Peek into the data to figure out whether 1490 * 1) Signature matches the expected value 1491 * 2) What is inside the package (TAG ID is used for finding this) 1492 */ 1493 tag = *(data + PHYERR_HDR_TAG_POS); 1494 signature = *(data + PHYERR_HDR_SIG_POS); 1495 1496 if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) { 1497 spectral->diag_stats.spectral_mismatch++; 1498 return -EINVAL; 1499 } 1500 1501 if (tag != exp_tag) { 1502 spectral->diag_stats.spectral_mismatch++; 1503 return -EINVAL; 1504 } 1505 1506 return 0; 1507 } 1508 1509 static uint8_t 1510 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask) 1511 { 1512 uint8_t idx; 1513 1514 for (idx = 0; idx < DBR_MAX_CHAINS; idx++) { 1515 if (chainmask & 0x1) 1516 break; 1517 chainmask >>= 1; 1518 } 1519 return idx; 1520 } 1521 1522 static QDF_STATUS 1523 target_if_get_spectral_mode(enum spectral_detector_id detector_id, 1524 enum spectral_scan_mode *smode) { 1525 switch (detector_id) { 1526 case SPECTRAL_DETECTOR_PRIMARY: 1527 case SPECTRAL_DETECTOR_SECONDARY: 1528 *smode = SPECTRAL_SCAN_MODE_NORMAL; 1529 break; 1530 1531 case SPECTRAL_DETECTOR_AGILE: 1532 *smode = SPECTRAL_SCAN_MODE_AGILE; 1533 break; 1534 1535 default: 1536 spectral_err("Invalid Spectral detector id"); 1537 return QDF_STATUS_E_FAILURE; 1538 } 1539 1540 return QDF_STATUS_SUCCESS; 1541 } 1542 1543 int 1544 target_if_consume_spectral_report_gen3( 1545 struct target_if_spectral *spectral, 1546 struct spectral_report *report) 1547 { 1548 /* 1549 * XXX : The classifier do not use all the members of the SAMP 1550 * message data format. 1551 * The classifier only depends upon the following parameters 1552 * 1553 * 1. Frequency (freq, msg->freq) 1554 * 2. Spectral RSSI (spectral_rssi, 1555 * msg->samp_data.spectral_rssi) 1556 * 3. Bin Power Count (bin_pwr_count, 1557 * msg->samp_data.bin_pwr_count) 1558 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0] 1559 * 5. Spectral Timestamp (spectral_tstamp, 1560 * msg->samp_data.spectral_tstamp) 1561 * 6. MAC Address (macaddr, msg->macaddr) 1562 * 1563 * This function prepares the params structure and populates it 1564 * with 1565 * relevant values, this is in turn passed to 1566 * spectral_create_samp_msg() 1567 * to prepare fully formatted Spectral SAMP message 1568 * 1569 * XXX : Need to verify 1570 * 1. Order of FFT bin values 1571 * 1572 */ 1573 uint64_t tsf64 = 0; 1574 struct target_if_samp_msg_params params = {0}; 1575 struct spectral_search_fft_info_gen3 search_fft_info; 1576 struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info; 1577 int8_t chn_idx_lowest_enabled = 0; 1578 int fft_hdr_length = 0; 1579 int report_len = 0; 1580 int fft_bin_len = 0; 1581 struct target_if_spectral_ops *p_sops = 1582 GET_TARGET_IF_SPECTRAL_OPS(spectral); 1583 struct spectral_phyerr_fft_report_gen3 *p_fft_report; 1584 int8_t rssi; 1585 uint8_t *data = report->data; 1586 struct wlan_objmgr_vdev *vdev; 1587 uint8_t vdev_rxchainmask; 1588 struct sscan_report_fields_gen3 sscan_report_fields; 1589 enum spectral_detector_id detector_id; 1590 QDF_STATUS ret; 1591 1592 params.smode = SPECTRAL_SCAN_MODE_NORMAL; 1593 1594 /* Process Spectral scan summary report */ 1595 if (target_if_verify_sig_and_tag_gen3( 1596 spectral, data, 1597 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) { 1598 spectral_err_rl("Wrong tag/sig in sscan summary"); 1599 goto fail; 1600 } 1601 1602 detector_id = target_if_get_detector_id_sscan_summary_report_gen3(data); 1603 if (detector_id > SPECTRAL_DETECTOR_AGILE) { 1604 spectral->diag_stats.spectral_invalid_detector_id++; 1605 spectral_err("Invalid detector id %u, expected is 0/1/2", 1606 detector_id); 1607 goto fail; 1608 } 1609 target_if_consume_sscan_summary_report_gen3(spectral, data, 1610 &sscan_report_fields); 1611 /* Advance buf pointer to the search fft report */ 1612 data += sizeof(struct spectral_sscan_summary_report_gen3); 1613 1614 if ((detector_id == SPECTRAL_DETECTOR_AGILE) || 1615 is_primaryseg_expected(spectral)) { 1616 /* RSSI is in 1/2 dBm steps, Covert it to dBm scale */ 1617 rssi = (sscan_report_fields.inband_pwr_db) >> 1; 1618 params.agc_total_gain = 1619 sscan_report_fields.sscan_agc_total_gain; 1620 params.gainchange = sscan_report_fields.sscan_gainchange; 1621 params.pri80ind = sscan_report_fields.sscan_pri80; 1622 1623 /* Process Spectral search FFT report */ 1624 if (target_if_verify_sig_and_tag_gen3( 1625 spectral, data, 1626 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) { 1627 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u", 1628 detector_id); 1629 goto fail; 1630 } 1631 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data; 1632 fft_hdr_length = p_fft_report->fft_hdr_length * 4; 1633 if (fft_hdr_length < 16) { 1634 spectral_err("Wrong TLV length %u, detector id = %d", 1635 fft_hdr_length, detector_id); 1636 goto fail; 1637 } 1638 1639 report_len = (fft_hdr_length + 8); 1640 1641 target_if_process_sfft_report_gen3(p_fft_report, p_sfft); 1642 /* It is expected to have same detector id for 1643 * summary and fft report 1644 */ 1645 if (detector_id != p_sfft->fft_detector_id) { 1646 spectral_err_rl 1647 ("Different detid in ssummary(%u) and sfft(%u)", 1648 detector_id, p_sfft->fft_detector_id); 1649 goto fail; 1650 } 1651 1652 if (detector_id > SPECTRAL_DETECTOR_AGILE) { 1653 spectral->diag_stats.spectral_invalid_detector_id++; 1654 spectral_err("Invalid detector id %u, expected is 0/2", 1655 detector_id); 1656 goto fail; 1657 } 1658 1659 ret = target_if_get_spectral_mode(detector_id, ¶ms.smode); 1660 if (QDF_IS_STATUS_ERROR(ret)) { 1661 spectral_err_rl("Failed to get mode from detid= %u", 1662 detector_id); 1663 goto fail; 1664 } 1665 1666 if ((spectral->params[params.smode].ss_rpt_mode == 1) && 1667 spectral->null_fftbin_adj) { 1668 /* 1669 * No FFT bins are expected. Explicitly set FFT bin 1670 * length to 0. 1671 */ 1672 fft_bin_len = 0; 1673 } else { 1674 fft_bin_len = (fft_hdr_length - 16); 1675 1676 /* 1677 * Divide fft bin length by appropriate factor depending 1678 * on the value of fftbin_size_war. 1679 */ 1680 if (spectral->fftbin_size_war == 1681 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) 1682 fft_bin_len >>= 2; 1683 else if (spectral->fftbin_size_war == 1684 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) { 1685 /* Ideally we should be dividing fft bin length 1686 * by 2. Due to a HW bug, actual length is two 1687 * times the expected length. 1688 */ 1689 fft_bin_len >>= 2; 1690 } 1691 if ((spectral->params[params.smode].ss_rpt_mode == 2) && 1692 spectral->inband_fftbin_size_adj) { 1693 fft_bin_len >>= 1; 1694 } 1695 } 1696 1697 if (report->reset_delay) { 1698 enum spectral_scan_mode mode = 1699 SPECTRAL_SCAN_MODE_NORMAL; 1700 1701 /* Adjust the offset for all the Spectral modes. 1702 * Target will be sending the non zero reset delay for 1703 * the first Spectral report after reset. This delay is 1704 * common for all the Spectral modes. 1705 */ 1706 for (; mode < SPECTRAL_SCAN_MODE_MAX; mode++) 1707 spectral->timestamp_war_offset[mode] += 1708 (report->reset_delay + 1709 spectral->last_fft_timestamp[mode]); 1710 } 1711 tsf64 = p_sfft->timestamp; 1712 spectral->last_fft_timestamp[params.smode] = p_sfft->timestamp; 1713 tsf64 += spectral->timestamp_war_offset[params.smode]; 1714 1715 /* Take care of state transitions for 160 MHz and 80p80 */ 1716 if (spectral->ch_width == CH_WIDTH_160MHZ) { 1717 ret = target_if_160mhz_delivery_state_change( 1718 spectral, 1719 detector_id); 1720 if (ret != QDF_STATUS_SUCCESS) 1721 goto fail; 1722 } 1723 1724 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) 1725 target_if_dump_fft_report_gen3(spectral, params.smode, 1726 p_fft_report, p_sfft); 1727 1728 params.rssi = rssi; 1729 1730 vdev = target_if_spectral_get_vdev(spectral); 1731 if (!vdev) { 1732 spectral_info("First vdev is NULL"); 1733 reset_160mhz_delivery_state_machine 1734 (spectral, 1735 SPECTRAL_SCAN_MODE_NORMAL); 1736 return -EPERM; 1737 } 1738 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev); 1739 QDF_ASSERT(vdev_rxchainmask != 0); 1740 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1741 1742 chn_idx_lowest_enabled = 1743 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask); 1744 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) { 1745 spectral_err("Invalid chain index, detector id = %u", 1746 detector_id); 1747 goto fail; 1748 } 1749 1750 params.max_mag = p_sfft->fft_peak_mag; 1751 1752 params.bin_pwr_data = (uint8_t *)((uint8_t *)p_fft_report + 1753 SPECTRAL_FFT_BINS_POS); 1754 params.freq = p_sops->get_current_channel(spectral); 1755 1756 if (params.smode == SPECTRAL_SCAN_MODE_AGILE) 1757 params.agile_freq = 1758 spectral->params[params.smode].ss_frequency; 1759 1760 /* 1761 * For modes upto VHT80, the noise floor is populated with 1762 * the one corresponding 1763 * to the highest enabled antenna chain 1764 */ 1765 /* TODO: Fill proper values once FW provides them*/ 1766 params.noise_floor = 1767 report->noisefloor[chn_idx_lowest_enabled]; 1768 params.datalen = (fft_hdr_length * 4); 1769 params.pwr_count = fft_bin_len; 1770 params.tstamp = (tsf64 & SPECTRAL_TSMASK); 1771 } else if (is_secondaryseg_expected(spectral)) { 1772 /* RSSI is in 1/2 dBm steps, Covert it to dBm scale */ 1773 rssi = (sscan_report_fields.inband_pwr_db) >> 1; 1774 params.agc_total_gain_sec80 = 1775 sscan_report_fields.sscan_agc_total_gain; 1776 params.gainchange_sec80 = sscan_report_fields.sscan_gainchange; 1777 params.pri80ind_sec80 = sscan_report_fields.sscan_pri80; 1778 1779 /* Process Spectral search FFT report */ 1780 if (target_if_verify_sig_and_tag_gen3( 1781 spectral, data, 1782 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) { 1783 spectral_err_rl("Unexpected tag/sig in sfft, detid= %u", 1784 detector_id); 1785 goto fail; 1786 } 1787 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data; 1788 fft_hdr_length = p_fft_report->fft_hdr_length * 4; 1789 if (fft_hdr_length < 16) { 1790 spectral_err("Wrong TLV length %u, detector id = %u", 1791 fft_hdr_length, detector_id); 1792 goto fail; 1793 } 1794 1795 report_len = (fft_hdr_length + 8); 1796 1797 target_if_process_sfft_report_gen3(p_fft_report, p_sfft); 1798 /* It is expected to have same detector id for 1799 * summary and fft report 1800 */ 1801 if (detector_id != p_sfft->fft_detector_id) { 1802 spectral_err_rl 1803 ("Different detid in ssummary(%u) and sfft(%u)", 1804 detector_id, p_sfft->fft_detector_id); 1805 goto fail; 1806 } 1807 1808 if (detector_id > SPECTRAL_DETECTOR_AGILE) { 1809 spectral->diag_stats.spectral_invalid_detector_id++; 1810 spectral_err("Invalid detector id %u, expected is 1", 1811 detector_id); 1812 goto fail; 1813 } 1814 1815 ret = target_if_get_spectral_mode(detector_id, ¶ms.smode); 1816 if (QDF_IS_STATUS_ERROR(ret)) { 1817 spectral_err("Failed to get mode from detid= %u", 1818 detector_id); 1819 goto fail; 1820 } 1821 1822 if ((spectral->params[params.smode].ss_rpt_mode == 1) && 1823 spectral->null_fftbin_adj) { 1824 /* 1825 * No FFT bins are expected. Explicitly set FFT bin 1826 * length to 0. 1827 */ 1828 fft_bin_len = 0; 1829 } else { 1830 fft_bin_len = (fft_hdr_length - 16); 1831 1832 /* 1833 * Divide fft bin length by appropriate factor depending 1834 * on the value of fftbin_size_war. 1835 */ 1836 if (spectral->fftbin_size_war == 1837 SPECTRAL_FFTBIN_SIZE_WAR_4BYTE_TO_1BYTE) 1838 fft_bin_len >>= 2; 1839 else if (spectral->fftbin_size_war == 1840 SPECTRAL_FFTBIN_SIZE_WAR_2BYTE_TO_1BYTE) { 1841 /* Ideally we should be dividing fft bin length 1842 * by 2. Due to a HW bug, actual length is two 1843 * times the expected length. 1844 */ 1845 fft_bin_len >>= 2; 1846 } 1847 1848 if ((spectral->params[params.smode].ss_rpt_mode == 2) && 1849 spectral->inband_fftbin_size_adj) { 1850 fft_bin_len >>= 1; 1851 } 1852 } 1853 1854 /* Take care of state transitions for 160 MHz and 80p80 */ 1855 if (spectral->ch_width == CH_WIDTH_160MHZ) { 1856 ret = target_if_160mhz_delivery_state_change( 1857 spectral, 1858 detector_id); 1859 if (ret != QDF_STATUS_SUCCESS) 1860 goto fail; 1861 } 1862 1863 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) 1864 target_if_dump_fft_report_gen3(spectral, params.smode, 1865 p_fft_report, p_sfft); 1866 1867 params.vhtop_ch_freq_seg1 = 0; 1868 params.vhtop_ch_freq_seg2 = 0; 1869 1870 params.rssi_sec80 = rssi; 1871 1872 vdev = target_if_spectral_get_vdev(spectral); 1873 if (!vdev) { 1874 spectral_info("First vdev is NULL"); 1875 reset_160mhz_delivery_state_machine 1876 (spectral, 1877 SPECTRAL_SCAN_MODE_NORMAL); 1878 return -EPERM; 1879 } 1880 vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev); 1881 QDF_ASSERT(vdev_rxchainmask != 0); 1882 wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID); 1883 1884 chn_idx_lowest_enabled = 1885 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask); 1886 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) { 1887 spectral_err("Invalid chain index"); 1888 goto fail; 1889 } 1890 1891 /* Need to change this as per FW team's inputs */ 1892 params.noise_floor_sec80 = 1893 report->noisefloor[chn_idx_lowest_enabled]; 1894 1895 params.max_mag_sec80 = p_sfft->fft_peak_mag; 1896 /* params.max_index_sec80 = p_sfft->peak_inx; */ 1897 /* XXX Does this definition of datalen *still hold? */ 1898 params.datalen_sec80 = fft_hdr_length * 4; 1899 params.pwr_count_sec80 = fft_bin_len; 1900 params.bin_pwr_data_sec80 = 1901 (uint8_t *)((uint8_t *)p_fft_report + 1902 SPECTRAL_FFT_BINS_POS); 1903 } else { 1904 spectral_err("Spectral state machine in undefined state"); 1905 goto fail; 1906 } 1907 1908 qdf_mem_copy(¶ms.classifier_params, 1909 &spectral->classifier_params, 1910 sizeof(struct spectral_classifier_params)); 1911 1912 target_if_spectral_log_SAMP_param(¶ms); 1913 target_if_spectral_create_samp_msg(spectral, ¶ms); 1914 1915 return 0; 1916 1917 fail: 1918 spectral_err_rl("Error while processing Spectral report"); 1919 reset_160mhz_delivery_state_machine(spectral, 1920 SPECTRAL_SCAN_MODE_NORMAL); 1921 return -EPERM; 1922 } 1923 1924 int target_if_spectral_process_report_gen3( 1925 struct wlan_objmgr_pdev *pdev, 1926 void *buf) 1927 { 1928 int ret = 0; 1929 struct direct_buf_rx_data *payload = buf; 1930 struct target_if_spectral *spectral; 1931 struct spectral_report report; 1932 1933 spectral = get_target_if_spectral_handle_from_pdev(pdev); 1934 if (!spectral) { 1935 spectral_err("Spectral target object is null"); 1936 return -EINVAL; 1937 } 1938 1939 report.data = payload->vaddr; 1940 if (payload->meta_data_valid) { 1941 qdf_mem_copy(report.noisefloor, payload->meta_data.noisefloor, 1942 qdf_min(sizeof(report.noisefloor), 1943 sizeof(payload->meta_data.noisefloor))); 1944 report.reset_delay = payload->meta_data.reset_delay; 1945 } 1946 1947 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) { 1948 spectral_debug("Printing the spectral phyerr buffer for debug"); 1949 spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK", 1950 payload->dbr_len, 1951 payload->dbr_len, 1952 payload->vaddr); 1953 target_if_spectral_hexdump((unsigned char *)payload->vaddr, 1954 1024); 1955 } 1956 1957 ret = target_if_consume_spectral_report_gen3(spectral, &report); 1958 1959 if (spectral_debug_level & DEBUG_SPECTRAL4) 1960 spectral_debug_level = DEBUG_SPECTRAL; 1961 1962 return ret; 1963 } 1964 #else 1965 int target_if_spectral_process_report_gen3( 1966 struct wlan_objmgr_pdev *pdev, 1967 void *buf) 1968 { 1969 spectral_err("Direct dma support is not enabled"); 1970 return -EINVAL; 1971 } 1972 #endif 1973 qdf_export_symbol(target_if_spectral_process_report_gen3); 1974 /* END of spectral GEN III HW specific functions */ 1975 1976 #endif /* WLAN_CONV_SPECTRAL_ENABLE */ 1977