1 /* 2 * Copyright (c) 2011,2017-2018 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 #ifdef CONFIG_WIN 31 #include <osif_rawmode_sim.h> 32 #endif /*CONFIG_WIN*/ 33 #include <reg_services_public_struct.h> 34 #include <target_if_direct_buf_rx_api.h> 35 extern int spectral_debug_level; 36 37 #ifdef WLAN_CONV_SPECTRAL_ENABLE 38 39 /** 40 * target_if_print_buf() - Prints given buffer for given length 41 * @pbuf: Pointer to buffer 42 * @len: length 43 * 44 * Prints given buffer for given length 45 * 46 * Return: void 47 */ 48 static void 49 target_if_print_buf(uint8_t *pbuf, int len) 50 { 51 int i = 0; 52 53 for (i = 0; i < len; i++) { 54 spectral_debug("%02X ", pbuf[i]); 55 if (i % 32 == 31) 56 spectral_debug("\n"); 57 } 58 } 59 60 int 61 target_if_spectral_dump_fft(uint8_t *pfft, int fftlen) 62 { 63 int i = 0; 64 65 /* 66 * TODO : Do not delete the following print 67 * The scripts used to validate Spectral depend on this Print 68 */ 69 spectral_debug("SPECTRAL : FFT Length is 0x%x (%d)", fftlen, fftlen); 70 71 spectral_debug("fft_data # "); 72 for (i = 0; i < fftlen; i++) 73 spectral_debug("%d ", pfft[i]); 74 spectral_debug("\n"); 75 return 0; 76 } 77 78 /** 79 * target_if_spectral_send_tlv_to_host() - Send the TLV information to Host 80 * @spectral: Pointer to target_if spectral object 81 * @data: Pointer to the TLV 82 * @datalen: data length 83 * 84 * Send the TLV information to Host 85 * 86 * Return: Success or failure 87 */ 88 int 89 target_if_spectral_send_tlv_to_host(struct target_if_spectral *spectral, 90 uint8_t *data, uint32_t datalen) 91 { 92 int status = true; 93 void *nl_data = spectral->nl_cb.get_nbuff(spectral->pdev_obj); 94 95 if (nl_data) { 96 memcpy(nl_data, data, datalen); 97 if (spectral->send_phy_data(spectral->pdev_obj) == 0) 98 spectral->spectral_sent_msg++; 99 } else { 100 status = false; 101 } 102 return status; 103 } 104 105 void 106 target_if_dbg_print_samp_param(struct target_if_samp_msg_params *p) 107 { 108 spectral_debug("\nSAMP Packet : -------------------- START --------------------"); 109 spectral_debug("Freq = %d", p->freq); 110 spectral_debug("RSSI = %d", p->rssi); 111 spectral_debug("Bin Count = %d", p->pwr_count); 112 spectral_debug("Timestamp = %d", p->tstamp); 113 spectral_debug("SAMP Packet : -------------------- END -----------------------"); 114 } 115 116 void 117 target_if_dbg_print_samp_msg(struct spectral_samp_msg *ss_msg) 118 { 119 int i = 0; 120 121 struct spectral_samp_data *p = &ss_msg->samp_data; 122 struct spectral_classifier_params *pc = &p->classifier_params; 123 struct interf_src_rsp *pi = &p->interf_list; 124 125 spectral_dbg_line(); 126 spectral_debug("Spectral Message"); 127 spectral_dbg_line(); 128 spectral_debug("Signature : 0x%x", ss_msg->signature); 129 spectral_debug("Freq : %d", ss_msg->freq); 130 spectral_debug("Freq load : %d", ss_msg->freq_loading); 131 spectral_debug("Intfnc type : %d", ss_msg->int_type); 132 spectral_dbg_line(); 133 spectral_debug("Spectral Data info"); 134 spectral_dbg_line(); 135 spectral_debug("data length : %d", p->spectral_data_len); 136 spectral_debug("rssi : %d", p->spectral_rssi); 137 spectral_debug("combined rssi : %d", p->spectral_combined_rssi); 138 spectral_debug("upper rssi : %d", p->spectral_upper_rssi); 139 spectral_debug("lower rssi : %d", p->spectral_lower_rssi); 140 spectral_debug("bw info : %d", p->spectral_bwinfo); 141 spectral_debug("timestamp : %d", p->spectral_tstamp); 142 spectral_debug("max index : %d", p->spectral_max_index); 143 spectral_debug("max exp : %d", p->spectral_max_exp); 144 spectral_debug("max mag : %d", p->spectral_max_mag); 145 spectral_debug("last timstamp : %d", p->spectral_last_tstamp); 146 spectral_debug("upper max idx : %d", p->spectral_upper_max_index); 147 spectral_debug("lower max idx : %d", p->spectral_lower_max_index); 148 spectral_debug("bin power count : %d", p->bin_pwr_count); 149 spectral_dbg_line(); 150 spectral_debug("Classifier info"); 151 spectral_dbg_line(); 152 spectral_debug("20/40 Mode : %d", pc->spectral_20_40_mode); 153 spectral_debug("dc index : %d", pc->spectral_dc_index); 154 spectral_debug("dc in MHz : %d", pc->spectral_dc_in_mhz); 155 spectral_debug("upper channel : %d", pc->upper_chan_in_mhz); 156 spectral_debug("lower channel : %d", pc->lower_chan_in_mhz); 157 spectral_dbg_line(); 158 spectral_debug("Interference info"); 159 spectral_dbg_line(); 160 spectral_debug("inter count : %d", pi->count); 161 162 for (i = 0; i < pi->count; i++) { 163 spectral_debug("inter type : %d", 164 pi->interf[i].interf_type); 165 spectral_debug("min freq : %d", 166 pi->interf[i].interf_min_freq); 167 spectral_debug("max freq : %d", 168 pi->interf[i].interf_max_freq); 169 } 170 } 171 172 uint32_t 173 target_if_get_offset_swar_sec80(uint32_t channel_width) 174 { 175 uint32_t offset = 0; 176 177 switch (channel_width) { 178 case CH_WIDTH_20MHZ: 179 offset = OFFSET_CH_WIDTH_20; 180 break; 181 case CH_WIDTH_40MHZ: 182 offset = OFFSET_CH_WIDTH_40; 183 break; 184 case CH_WIDTH_80MHZ: 185 offset = OFFSET_CH_WIDTH_80; 186 break; 187 case CH_WIDTH_160MHZ: 188 offset = OFFSET_CH_WIDTH_160; 189 break; 190 default: 191 offset = OFFSET_CH_WIDTH_80; 192 break; 193 } 194 return offset; 195 } 196 197 /** 198 * target_if_dump_summary_report_gen2() - Dump Spectral Summary Report for gen2 199 * @ptlv: Pointer to Spectral Phyerr TLV 200 * @tlvlen: length 201 * @is_160_format: Indicates whether information provided by HW is in altered 202 * format for 802.11ac 160/80+80 MHz support (QCA9984 onwards) 203 * 204 * Dump Spectral Summary Report for gen2 205 * 206 * Return: Success/Failure 207 */ 208 static int 209 target_if_dump_summary_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv, 210 int tlvlen, bool is_160_format) 211 { 212 /* 213 * For simplicity, everything is defined as uint32_t (except one). 214 * Proper code will later use the right sizes. 215 */ 216 217 /* 218 * For easy comparision between MDK team and OS team, the MDK script 219 * variable names have been used 220 */ 221 222 uint32_t agc_mb_gain; 223 uint32_t sscan_gidx; 224 uint32_t agc_total_gain; 225 uint32_t recent_rfsat; 226 uint32_t ob_flag; 227 uint32_t nb_mask; 228 uint32_t peak_mag; 229 int16_t peak_inx; 230 231 uint32_t ss_summary_A = 0; 232 uint32_t ss_summary_B = 0; 233 uint32_t ss_summary_C = 0; 234 uint32_t ss_summary_D = 0; 235 uint32_t ss_summary_E = 0; 236 struct spectral_phyerr_hdr_gen2 *phdr = 237 (struct spectral_phyerr_hdr_gen2 *)( 238 (uint8_t *)ptlv + 239 sizeof(struct spectral_phyerr_tlv_gen2)); 240 241 spectral_debug("SPECTRAL : SPECTRAL SUMMARY REPORT"); 242 243 if (is_160_format) { 244 if (tlvlen != 20) { 245 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 246 tlvlen); 247 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 248 return -EPERM; 249 } 250 251 /* Doing copy as the contents may not be aligned */ 252 qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int)); 253 qdf_mem_copy(&ss_summary_B, 254 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 255 sizeof(int)); 256 qdf_mem_copy(&ss_summary_C, 257 (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)), 258 sizeof(int)); 259 qdf_mem_copy(&ss_summary_D, 260 (uint8_t *)((uint8_t *)phdr + 3 * sizeof(int)), 261 sizeof(int)); 262 qdf_mem_copy(&ss_summary_E, 263 (uint8_t *)((uint8_t *)phdr + 4 * sizeof(int)), 264 sizeof(int)); 265 266 /* 267 * The following is adapted from MDK scripts for 268 * easier comparability 269 */ 270 271 recent_rfsat = ((ss_summary_A >> 8) & 0x1); 272 sscan_gidx = (ss_summary_A & 0xff); 273 spectral_debug("sscan_gidx=%d, is_recent_rfsat=%d", 274 sscan_gidx, recent_rfsat); 275 276 /* First segment */ 277 agc_mb_gain = ((ss_summary_B >> 10) & 0x7f); 278 agc_total_gain = (ss_summary_B & 0x3ff); 279 nb_mask = ((ss_summary_C >> 22) & 0xff); 280 ob_flag = ((ss_summary_B >> 17) & 0x1); 281 peak_inx = (ss_summary_C & 0xfff); 282 if (peak_inx > 2047) 283 peak_inx = peak_inx - 4096; 284 peak_mag = ((ss_summary_C >> 12) & 0x3ff); 285 286 spectral_debug("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d", 287 agc_total_gain, agc_mb_gain); 288 spectral_debug("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, peak_index_segid0=%d, peak_mag_segid0=%d", 289 nb_mask, ob_flag, peak_inx, peak_mag); 290 291 /* Second segment */ 292 agc_mb_gain = ((ss_summary_D >> 10) & 0x7f); 293 agc_total_gain = (ss_summary_D & 0x3ff); 294 nb_mask = ((ss_summary_E >> 22) & 0xff); 295 ob_flag = ((ss_summary_D >> 17) & 0x1); 296 peak_inx = (ss_summary_E & 0xfff); 297 if (peak_inx > 2047) 298 peak_inx = peak_inx - 4096; 299 peak_mag = ((ss_summary_E >> 12) & 0x3ff); 300 301 spectral_debug("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d", 302 agc_total_gain, agc_mb_gain); 303 spectral_debug("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, peak_index_segid1=%d, peak_mag_segid1=%d", 304 nb_mask, ob_flag, peak_inx, peak_mag); 305 } else { 306 if (tlvlen != 8) { 307 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 308 tlvlen); 309 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 310 return -EPERM; 311 } 312 313 /* Doing copy as the contents may not be aligned */ 314 qdf_mem_copy(&ss_summary_A, (uint8_t *)phdr, sizeof(int)); 315 qdf_mem_copy(&ss_summary_B, 316 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 317 sizeof(int)); 318 319 nb_mask = ((ss_summary_B >> 22) & 0xff); 320 ob_flag = ((ss_summary_B >> 30) & 0x1); 321 peak_inx = (ss_summary_B & 0xfff); 322 323 if (peak_inx > 2047) 324 peak_inx = peak_inx - 4096; 325 326 peak_mag = ((ss_summary_B >> 12) & 0x3ff); 327 agc_mb_gain = ((ss_summary_A >> 24) & 0x7f); 328 agc_total_gain = (ss_summary_A & 0x3ff); 329 sscan_gidx = ((ss_summary_A >> 16) & 0xff); 330 recent_rfsat = ((ss_summary_B >> 31) & 0x1); 331 332 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", 333 nb_mask, ob_flag, peak_inx, peak_mag, 334 agc_mb_gain, agc_total_gain, sscan_gidx, 335 recent_rfsat); 336 } 337 338 return 0; 339 } 340 341 /** 342 * target_if_process_sfft_report_gen2() - Process Search FFT Report 343 * @ptlv: Pointer to Spectral Phyerr TLV 344 * @tlvlen: length 345 * @p_fft_info: Pointer to search fft info 346 * 347 * Dump Spectral Summary Report for gen2 348 * 349 * Return: Success/Failure 350 */ 351 static int 352 target_if_process_sfft_report_gen2( 353 struct spectral_phyerr_tlv_gen2 *ptlv, 354 int tlvlen, 355 struct spectral_search_fft_info_gen2 *p_fft_info) 356 { 357 /* 358 * For simplicity, everything is defined as uint32_t (except one). 359 * Proper code will later use the right sizes. 360 */ 361 /* 362 * For easy comparision between MDK team and OS team, the MDK script 363 * variable names have been used 364 */ 365 uint32_t relpwr_db; 366 uint32_t num_str_bins_ib; 367 uint32_t base_pwr; 368 uint32_t total_gain_info; 369 370 uint32_t fft_chn_idx; 371 int16_t peak_inx; 372 uint32_t avgpwr_db; 373 uint32_t peak_mag; 374 375 uint32_t fft_summary_A = 0; 376 uint32_t fft_summary_B = 0; 377 uint8_t *tmp = (uint8_t *)ptlv; 378 struct spectral_phyerr_hdr_gen2 *phdr = 379 (struct spectral_phyerr_hdr_gen2 *)( 380 tmp + 381 sizeof(struct spectral_phyerr_tlv_gen2)); 382 383 /* Relook this */ 384 if (tlvlen < 8) { 385 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 386 tlvlen); 387 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 388 return -EPERM; 389 } 390 391 /* Doing copy as the contents may not be aligned */ 392 qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int)); 393 qdf_mem_copy(&fft_summary_B, 394 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 395 sizeof(int)); 396 397 relpwr_db = ((fft_summary_B >> 26) & 0x3f); 398 num_str_bins_ib = fft_summary_B & 0xff; 399 base_pwr = ((fft_summary_A >> 14) & 0x1ff); 400 total_gain_info = ((fft_summary_A >> 23) & 0x1ff); 401 402 fft_chn_idx = ((fft_summary_A >> 12) & 0x3); 403 peak_inx = fft_summary_A & 0xfff; 404 405 if (peak_inx > 2047) 406 peak_inx = peak_inx - 4096; 407 408 avgpwr_db = ((fft_summary_B >> 18) & 0xff); 409 peak_mag = ((fft_summary_B >> 8) & 0x3ff); 410 411 /* Populate the Search FFT Info */ 412 if (p_fft_info) { 413 p_fft_info->relpwr_db = relpwr_db; 414 p_fft_info->num_str_bins_ib = num_str_bins_ib; 415 p_fft_info->base_pwr = base_pwr; 416 p_fft_info->total_gain_info = total_gain_info; 417 p_fft_info->fft_chn_idx = fft_chn_idx; 418 p_fft_info->peak_inx = peak_inx; 419 p_fft_info->avgpwr_db = avgpwr_db; 420 p_fft_info->peak_mag = peak_mag; 421 } 422 423 return 0; 424 } 425 426 /** 427 * target_if_dump_adc_report_gen2() - Dump ADC Reports for gen2 428 * @ptlv: Pointer to Spectral Phyerr TLV 429 * @tlvlen: length 430 * 431 * Dump ADC Reports for gen2 432 * 433 * Return: Success/Failure 434 */ 435 static int 436 target_if_dump_adc_report_gen2( 437 struct spectral_phyerr_tlv_gen2 *ptlv, int tlvlen) 438 { 439 int i; 440 uint32_t *pdata; 441 uint32_t data; 442 443 /* 444 * For simplicity, everything is defined as uint32_t (except one). 445 * Proper code will later use the right sizes. 446 */ 447 uint32_t samp_fmt; 448 uint32_t chn_idx; 449 uint32_t recent_rfsat; 450 uint32_t agc_mb_gain; 451 uint32_t agc_total_gain; 452 453 uint32_t adc_summary = 0; 454 455 uint8_t *ptmp = (uint8_t *)ptlv; 456 457 spectral_debug("SPECTRAL : ADC REPORT"); 458 459 /* Relook this */ 460 if (tlvlen < 4) { 461 spectral_err("Unexpected TLV length %d for ADC Report! Hexdump follows", 462 tlvlen); 463 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 464 return -EPERM; 465 } 466 467 qdf_mem_copy(&adc_summary, (uint8_t *)(ptlv + 4), sizeof(int)); 468 469 samp_fmt = ((adc_summary >> 28) & 0x1); 470 chn_idx = ((adc_summary >> 24) & 0x3); 471 recent_rfsat = ((adc_summary >> 23) & 0x1); 472 agc_mb_gain = ((adc_summary >> 16) & 0x7f); 473 agc_total_gain = adc_summary & 0x3ff; 474 475 spectral_debug("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u agc_total_gain=%u", 476 samp_fmt, chn_idx, recent_rfsat, agc_mb_gain, 477 agc_total_gain); 478 479 for (i = 0; i < (tlvlen / 4); i++) { 480 pdata = (uint32_t *)(ptmp + 4 + i * 4); 481 data = *pdata; 482 483 /* Interpreting capture format 1 */ 484 if (1) { 485 uint8_t i1; 486 uint8_t q1; 487 uint8_t i2; 488 uint8_t q2; 489 int8_t si1; 490 int8_t sq1; 491 int8_t si2; 492 int8_t sq2; 493 494 i1 = data & 0xff; 495 q1 = (data >> 8) & 0xff; 496 i2 = (data >> 16) & 0xff; 497 q2 = (data >> 24) & 0xff; 498 499 if (i1 > 127) 500 si1 = i1 - 256; 501 else 502 si1 = i1; 503 504 if (q1 > 127) 505 sq1 = q1 - 256; 506 else 507 sq1 = q1; 508 509 if (i2 > 127) 510 si2 = i2 - 256; 511 else 512 si2 = i2; 513 514 if (q2 > 127) 515 sq2 = q2 - 256; 516 else 517 sq2 = q2; 518 519 spectral_debug("SPECTRAL ADC : Interpreting capture format 1"); 520 spectral_debug("adc_data_format_1 # %d %d %d", 521 2 * i, si1, sq1); 522 spectral_debug("adc_data_format_1 # %d %d %d", 523 2 * i + 1, si2, sq2); 524 } 525 526 /* Interpreting capture format 0 */ 527 if (1) { 528 uint16_t i1; 529 uint16_t q1; 530 int16_t si1; 531 int16_t sq1; 532 533 i1 = data & 0xffff; 534 q1 = (data >> 16) & 0xffff; 535 if (i1 > 32767) 536 si1 = i1 - 65536; 537 else 538 si1 = i1; 539 540 if (q1 > 32767) 541 sq1 = q1 - 65536; 542 else 543 sq1 = q1; 544 spectral_debug("SPECTRAL ADC : Interpreting capture format 0"); 545 spectral_debug("adc_data_format_2 # %d %d %d", 546 i, si1, sq1); 547 } 548 } 549 550 spectral_debug("\n"); 551 552 return 0; 553 } 554 555 /** 556 * target_if_dump_sfft_report_gen2() - Process Search FFT Report for gen2 557 * @ptlv: Pointer to Spectral Phyerr TLV 558 * @tlvlen: length 559 * @is_160_format: Indicates 160 format 560 * 561 * Process Search FFT Report for gen2 562 * 563 * Return: Success/Failure 564 */ 565 static int 566 target_if_dump_sfft_report_gen2(struct spectral_phyerr_tlv_gen2 *ptlv, 567 int tlvlen, bool is_160_format) 568 { 569 int i; 570 uint32_t fft_mag; 571 572 /* 573 * For simplicity, everything is defined as uint32_t (except one). 574 * Proper code will later use the right sizes. 575 */ 576 /* 577 * For easy comparision between MDK team and OS team, the MDK script 578 * variable names have been used 579 */ 580 uint32_t relpwr_db; 581 uint32_t num_str_bins_ib; 582 uint32_t base_pwr; 583 uint32_t total_gain_info; 584 585 uint32_t fft_chn_idx; 586 int16_t peak_inx; 587 uint32_t avgpwr_db; 588 uint32_t peak_mag; 589 uint8_t segid; 590 591 uint32_t fft_summary_A = 0; 592 uint32_t fft_summary_B = 0; 593 uint32_t fft_summary_C = 0; 594 uint8_t *tmp = (uint8_t *)ptlv; 595 struct spectral_phyerr_hdr_gen2 *phdr = 596 (struct spectral_phyerr_hdr_gen2 *)( 597 tmp + 598 sizeof(struct spectral_phyerr_tlv_gen2)); 599 uint32_t segid_skiplen = 0; 600 601 if (is_160_format) 602 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO); 603 604 spectral_debug("SPECTRAL : SEARCH FFT REPORT"); 605 606 /* Relook this */ 607 if (tlvlen < (8 + segid_skiplen)) { 608 spectral_err("Unexpected TLV length %d for Spectral Summary Report! Hexdump follows", 609 tlvlen); 610 target_if_print_buf((uint8_t *)ptlv, tlvlen + 4); 611 return -EPERM; 612 } 613 614 /* Doing copy as the contents may not be aligned */ 615 qdf_mem_copy(&fft_summary_A, (uint8_t *)phdr, sizeof(int)); 616 qdf_mem_copy(&fft_summary_B, 617 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 618 sizeof(int)); 619 if (is_160_format) 620 qdf_mem_copy(&fft_summary_C, 621 (uint8_t *)((uint8_t *)phdr + 2 * sizeof(int)), 622 sizeof(int)); 623 624 relpwr_db = ((fft_summary_B >> 26) & 0x3f); 625 num_str_bins_ib = fft_summary_B & 0xff; 626 base_pwr = ((fft_summary_A >> 14) & 0x1ff); 627 total_gain_info = ((fft_summary_A >> 23) & 0x1ff); 628 629 fft_chn_idx = ((fft_summary_A >> 12) & 0x3); 630 peak_inx = fft_summary_A & 0xfff; 631 632 if (peak_inx > 2047) 633 peak_inx = peak_inx - 4096; 634 635 avgpwr_db = ((fft_summary_B >> 18) & 0xff); 636 peak_mag = ((fft_summary_B >> 8) & 0x3ff); 637 638 spectral_debug("Header A = 0x%x Header B = 0x%x", 639 phdr->hdr_a, phdr->hdr_b); 640 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", 641 base_pwr, total_gain_info, relpwr_db, num_str_bins_ib, 642 fft_chn_idx, peak_inx, avgpwr_db, peak_mag); 643 if (is_160_format) { 644 segid = fft_summary_C & 0x1; 645 spectral_debug("Segment ID: %hhu", segid); 646 } 647 648 spectral_debug("FFT bins:"); 649 for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) { 650 fft_mag = ((uint8_t *)ptlv)[12 + segid_skiplen + i]; 651 spectral_debug("%d %d, ", i, fft_mag); 652 } 653 654 spectral_debug("\n"); 655 656 return 0; 657 } 658 659 #ifdef SPECTRAL_DEBUG_SAMP_MSG 660 /** 661 * target_if_spectral_log_SAMP_param() - Log SAMP parameters 662 * @params: Reference to target_if_samp_msg_params 663 * 664 * API to log spectral SAMP message parameters 665 * 666 * Return: None 667 */ 668 static void 669 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params) 670 { 671 target_if_dbg_print_samp_param(params); 672 } 673 674 #else 675 static void 676 target_if_spectral_log_SAMP_param(struct target_if_samp_msg_params *params) 677 { 678 } 679 #endif 680 681 int 682 target_if_process_phyerr_gen2(struct target_if_spectral *spectral, 683 uint8_t *data, 684 uint32_t datalen, 685 struct target_if_spectral_rfqual_info *p_rfqual, 686 struct target_if_spectral_chan_info *p_chaninfo, 687 uint64_t tsf64, 688 struct target_if_spectral_acs_stats *acs_stats) 689 { 690 /* 691 * XXX : The classifier do not use all the members of the SAMP 692 * message data format. 693 * The classifier only depends upon the following parameters 694 * 695 * 1. Frequency (freq, msg->freq) 696 * 2. Spectral RSSI (spectral_rssi, 697 * msg->samp_data.spectral_rssi) 698 * 3. Bin Power Count (bin_pwr_count, 699 * msg->samp_data.bin_pwr_count) 700 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0] 701 * 5. Spectral Timestamp (spectral_tstamp, 702 * msg->samp_data.spectral_tstamp) 703 * 6. MAC Address (macaddr, msg->macaddr) 704 * 705 * This function prepares the params structure and populates it 706 * with 707 * relevant values, this is in turn passed to 708 * spectral_create_samp_msg() 709 * to prepare fully formatted Spectral SAMP message 710 * 711 * XXX : Need to verify 712 * 1. Order of FFT bin values 713 * 714 */ 715 716 struct target_if_samp_msg_params params; 717 struct spectral_search_fft_info_gen2 search_fft_info; 718 struct spectral_search_fft_info_gen2 *p_sfft = &search_fft_info; 719 struct spectral_search_fft_info_gen2 search_fft_info_sec80; 720 struct spectral_search_fft_info_gen2 *p_sfft_sec80 = 721 &search_fft_info_sec80; 722 uint32_t segid_skiplen = 0; 723 724 int8_t rssi_up = 0; 725 int8_t rssi_low = 0; 726 727 int8_t chn_idx_highest_enabled = 0; 728 int8_t chn_idx_lowest_enabled = 0; 729 730 uint8_t control_rssi = 0; 731 uint8_t extension_rssi = 0; 732 uint8_t combined_rssi = 0; 733 734 uint32_t tstamp = 0; 735 736 struct target_if_spectral_ops *p_sops = 737 GET_TARGET_IF_SPECTRAL_OPS(spectral); 738 739 struct spectral_phyerr_tlv_gen2 *ptlv = 740 (struct spectral_phyerr_tlv_gen2 *)data; 741 struct spectral_phyerr_tlv_gen2 *ptlv_sec80 = NULL; 742 struct spectral_phyerr_fft_gen2 *pfft = NULL; 743 struct spectral_phyerr_fft_gen2 *pfft_sec80 = NULL; 744 745 uint8_t segid = 0; 746 uint8_t segid_sec80 = 0; 747 748 if (spectral->is_160_format) 749 segid_skiplen = sizeof(SPECTRAL_SEGID_INFO); 750 751 pfft = (struct spectral_phyerr_fft_gen2 *)( 752 data + 753 sizeof(struct spectral_phyerr_tlv_gen2) + 754 sizeof(struct spectral_phyerr_hdr_gen2) + 755 segid_skiplen); 756 757 /* 758 * XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level, 759 * and use this facility inside spectral_dump_phyerr_data() 760 * and supporting functions. 761 */ 762 if (spectral_debug_level & DEBUG_SPECTRAL2) 763 target_if_spectral_dump_phyerr_data_gen2( 764 data, datalen, 765 spectral->is_160_format); 766 767 if (spectral_debug_level & DEBUG_SPECTRAL4) { 768 target_if_spectral_dump_phyerr_data_gen2( 769 data, datalen, 770 spectral->is_160_format); 771 spectral_debug_level = DEBUG_SPECTRAL; 772 } 773 774 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) { 775 /* 776 * EV# 118023: We tentatively disable the below print 777 * and provide stats instead. 778 */ 779 spectral->diag_stats.spectral_mismatch++; 780 return -EPERM; 781 } 782 783 OS_MEMZERO(¶ms, sizeof(params)); 784 785 if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) { 786 if (spectral->is_160_format) { 787 segid = *((SPECTRAL_SEGID_INFO *)( 788 (uint8_t *)ptlv + 789 sizeof(struct spectral_phyerr_tlv_gen2) + 790 sizeof(struct spectral_phyerr_hdr_gen2))); 791 792 if (segid != 0) { 793 struct spectral_diag_stats *p_diag_stats = 794 &spectral->diag_stats; 795 p_diag_stats->spectral_vhtseg1id_mismatch++; 796 return -EPERM; 797 } 798 } 799 800 target_if_process_sfft_report_gen2(ptlv, ptlv->length, 801 &search_fft_info); 802 803 tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK; 804 805 combined_rssi = p_rfqual->rssi_comb; 806 807 if (spectral->upper_is_control) 808 rssi_up = control_rssi; 809 else 810 rssi_up = extension_rssi; 811 812 if (spectral->lower_is_control) 813 rssi_low = control_rssi; 814 else 815 rssi_low = extension_rssi; 816 817 params.rssi = p_rfqual->rssi_comb; 818 params.lower_rssi = rssi_low; 819 params.upper_rssi = rssi_up; 820 821 if (spectral->sc_spectral_noise_pwr_cal) { 822 params.chain_ctl_rssi[0] = 823 p_rfqual->pc_rssi_info[0].rssi_pri20; 824 params.chain_ctl_rssi[1] = 825 p_rfqual->pc_rssi_info[1].rssi_pri20; 826 params.chain_ctl_rssi[2] = 827 p_rfqual->pc_rssi_info[2].rssi_pri20; 828 params.chain_ext_rssi[0] = 829 p_rfqual->pc_rssi_info[0].rssi_sec20; 830 params.chain_ext_rssi[1] = 831 p_rfqual->pc_rssi_info[1].rssi_sec20; 832 params.chain_ext_rssi[2] = 833 p_rfqual->pc_rssi_info[2].rssi_sec20; 834 } 835 836 /* 837 * XXX : This actually depends on the programmed chain mask 838 * This value decides the per-chain enable mask to select 839 * the input ADC for search FTT. 840 * For modes upto VHT80, if more than one chain is 841 * enabled, the max valid chain 842 * is used. LSB corresponds to chain zero. 843 * For VHT80_80 and VHT160, the lowest enabled chain is 844 * used for primary 845 * detection and highest enabled chain is used for 846 * secondary detection. 847 * 848 * XXX : The current algorithm do not use these control and 849 * extension channel 850 * Instead, it just relies on the combined RSSI values 851 * only. 852 * For fool-proof detection algorithm, we should take 853 * these RSSI values in to account. 854 * This is marked for future enhancements. 855 */ 856 chn_idx_highest_enabled = 857 ((spectral->params.ss_chn_mask & 0x8) ? 3 : 858 (spectral->params.ss_chn_mask & 0x4) ? 2 : 859 (spectral->params.ss_chn_mask & 0x2) ? 1 : 0); 860 chn_idx_lowest_enabled = 861 ((spectral->params.ss_chn_mask & 0x1) ? 0 : 862 (spectral->params.ss_chn_mask & 0x2) ? 1 : 863 (spectral->params.ss_chn_mask & 0x4) ? 2 : 3); 864 control_rssi = (uint8_t) 865 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20; 866 extension_rssi = (uint8_t) 867 p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20; 868 869 params.bwinfo = 0; 870 params.tstamp = 0; 871 params.max_mag = p_sfft->peak_mag; 872 873 params.max_index = p_sfft->peak_inx; 874 params.max_exp = 0; 875 params.peak = 0; 876 params.bin_pwr_data = (uint8_t *)pfft; 877 params.freq = p_sops->get_current_channel(spectral); 878 params.freq_loading = 0; 879 880 params.interf_list.count = 0; 881 params.max_lower_index = 0; 882 params.max_upper_index = 0; 883 params.nb_lower = 0; 884 params.nb_upper = 0; 885 /* 886 * For modes upto VHT80, the noise floor is populated with the 887 * one corresponding 888 * to the highest enabled antenna chain 889 */ 890 params.noise_floor = 891 p_rfqual->noise_floor[chn_idx_highest_enabled]; 892 params.datalen = ptlv->length; 893 params.pwr_count = ptlv->length - 894 sizeof(struct spectral_phyerr_hdr_gen2) - segid_skiplen; 895 params.tstamp = (tsf64 & SPECTRAL_TSMASK); 896 897 acs_stats->ctrl_nf = params.noise_floor; 898 acs_stats->ext_nf = params.noise_floor; 899 acs_stats->nfc_ctl_rssi = control_rssi; 900 acs_stats->nfc_ext_rssi = extension_rssi; 901 902 if (spectral->is_160_format && 903 spectral->ch_width == CH_WIDTH_160MHZ) { 904 /* 905 * We expect to see one more Search FFT report, and it 906 * should be equal in size to the current one. 907 */ 908 if (datalen < ( 909 2 * ( 910 sizeof(struct spectral_phyerr_tlv_gen2) + 911 ptlv->length))) { 912 struct spectral_diag_stats *p_diag_stats = 913 &spectral->diag_stats; 914 p_diag_stats->spectral_sec80_sfft_insufflen++; 915 return -EPERM; 916 } 917 918 ptlv_sec80 = (struct spectral_phyerr_tlv_gen2 *)( 919 data + 920 sizeof(struct spectral_phyerr_tlv_gen2) + 921 ptlv->length); 922 923 if (ptlv_sec80->signature != 924 SPECTRAL_PHYERR_SIGNATURE_GEN2) { 925 spectral->diag_stats.spectral_mismatch++; 926 return -EPERM; 927 } 928 929 if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) { 930 spectral->diag_stats.spectral_no_sec80_sfft++; 931 return -EPERM; 932 } 933 934 segid_sec80 = *((SPECTRAL_SEGID_INFO *)( 935 (uint8_t *)ptlv_sec80 + 936 sizeof(struct spectral_phyerr_tlv_gen2) + 937 sizeof(struct spectral_phyerr_hdr_gen2))); 938 939 if (segid_sec80 != 1) { 940 struct spectral_diag_stats *p_diag_stats = 941 &spectral->diag_stats; 942 p_diag_stats->spectral_vhtseg2id_mismatch++; 943 return -EPERM; 944 } 945 946 params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1; 947 params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2; 948 949 target_if_process_sfft_report_gen2( 950 ptlv_sec80, 951 ptlv_sec80->length, 952 &search_fft_info_sec80); 953 954 pfft_sec80 = (struct spectral_phyerr_fft_gen2 *)( 955 ((uint8_t *)ptlv_sec80) + 956 sizeof(struct spectral_phyerr_tlv_gen2) + 957 sizeof(struct spectral_phyerr_hdr_gen2) + 958 segid_skiplen); 959 960 /* XXX: Confirm. TBD at SoD. */ 961 params.rssi_sec80 = p_rfqual->rssi_comb; 962 if (spectral->is_sec80_rssi_war_required) 963 params.rssi_sec80 = 964 target_if_get_combrssi_sec80_seg_gen2 965 (spectral, &search_fft_info_sec80); 966 /* XXX: Determine dynamically. TBD at SoD. */ 967 /* 968 * For VHT80_80/VHT160, the noise floor for primary 969 * 80MHz segment is populated with the 970 * lowest enabled antenna chain and the noise floor for 971 * secondary 80MHz segment is populated 972 * with the highest enabled antenna chain 973 */ 974 params.noise_floor_sec80 = 975 p_rfqual->noise_floor[chn_idx_highest_enabled]; 976 params.noise_floor = 977 p_rfqual->noise_floor[chn_idx_lowest_enabled]; 978 979 params.max_mag_sec80 = p_sfft_sec80->peak_mag; 980 params.max_index_sec80 = p_sfft_sec80->peak_inx; 981 /* XXX Does this definition of datalen *still hold? */ 982 params.datalen_sec80 = ptlv_sec80->length; 983 params.pwr_count_sec80 = 984 ptlv_sec80->length - 985 sizeof(struct spectral_phyerr_hdr_gen2) - 986 segid_skiplen; 987 params.bin_pwr_data_sec80 = (uint8_t *)pfft_sec80; 988 } 989 qdf_mem_copy(¶ms.classifier_params, 990 &spectral->classifier_params, 991 sizeof(struct spectral_classifier_params)); 992 993 target_if_spectral_log_SAMP_param(¶ms); 994 target_if_spectral_create_samp_msg(spectral, ¶ms); 995 } 996 997 return 0; 998 } 999 1000 int 1001 target_if_spectral_dump_hdr_gen2(struct spectral_phyerr_hdr_gen2 *phdr) 1002 { 1003 uint32_t a = 0; 1004 uint32_t b = 0; 1005 1006 qdf_mem_copy(&a, (uint8_t *)phdr, sizeof(int)); 1007 qdf_mem_copy(&b, 1008 (uint8_t *)((uint8_t *)phdr + sizeof(int)), 1009 sizeof(int)); 1010 1011 spectral_debug("SPECTRAL : HEADER A 0x%x (%d)", a, a); 1012 spectral_debug("SPECTRAL : HEADER B 0x%x (%d)", b, b); 1013 return 0; 1014 } 1015 1016 int8_t 1017 target_if_get_combrssi_sec80_seg_gen2( 1018 struct target_if_spectral *spectral, 1019 struct spectral_search_fft_info_gen2 *p_sfft_sec80) 1020 { 1021 uint32_t avgpwr_db = 0; 1022 uint32_t total_gain_db = 0; 1023 uint32_t offset = 0; 1024 int8_t comb_rssi = 0; 1025 1026 /* Obtain required parameters for algorithm from search FFT report */ 1027 avgpwr_db = p_sfft_sec80->avgpwr_db; 1028 total_gain_db = p_sfft_sec80->total_gain_info; 1029 1030 /* Calculate offset */ 1031 offset = target_if_get_offset_swar_sec80(spectral->ch_width); 1032 1033 /* Calculate RSSI */ 1034 comb_rssi = ((avgpwr_db - total_gain_db) + offset); 1035 1036 return comb_rssi; 1037 } 1038 1039 int 1040 target_if_spectral_dump_tlv_gen2( 1041 struct spectral_phyerr_tlv_gen2 *ptlv, bool is_160_format) 1042 { 1043 int ret = 0; 1044 1045 /* 1046 * TODO : Do not delete the following print 1047 * The scripts used to validate Spectral depend on this Print 1048 */ 1049 spectral_debug("SPECTRAL : TLV Length is 0x%x (%d)", 1050 ptlv->length, ptlv->length); 1051 1052 switch (ptlv->tag) { 1053 case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2: 1054 ret = 1055 target_if_dump_summary_report_gen2( 1056 ptlv, ptlv->length, is_160_format); 1057 break; 1058 1059 case TLV_TAG_SEARCH_FFT_REPORT_GEN2: 1060 ret = 1061 target_if_dump_sfft_report_gen2(ptlv, ptlv->length, 1062 is_160_format); 1063 break; 1064 1065 case TLV_TAG_ADC_REPORT_GEN2: 1066 ret = target_if_dump_adc_report_gen2(ptlv, ptlv->length); 1067 break; 1068 1069 default: 1070 spectral_warn("INVALID TLV"); 1071 ret = -1; 1072 break; 1073 } 1074 1075 return ret; 1076 } 1077 1078 int 1079 target_if_spectral_dump_phyerr_data_gen2(uint8_t *data, uint32_t datalen, 1080 bool is_160_format) 1081 { 1082 struct spectral_phyerr_tlv_gen2 *ptlv = NULL; 1083 uint32_t bytes_processed = 0; 1084 uint32_t bytes_remaining = datalen; 1085 uint32_t curr_tlv_complete_size = 0; 1086 1087 if (datalen < sizeof(struct spectral_phyerr_tlv_gen2)) { 1088 spectral_err("Total PHY error data length %u too short to contain any TLVs", 1089 datalen); 1090 return -EPERM; 1091 } 1092 1093 while (bytes_processed < datalen) { 1094 if (bytes_remaining < sizeof(struct spectral_phyerr_tlv_gen2)) { 1095 spectral_err("Remaining PHY error data length %u too short to contain a TLV", 1096 bytes_remaining); 1097 return -EPERM; 1098 } 1099 1100 ptlv = (struct spectral_phyerr_tlv_gen2 *)(data + 1101 bytes_processed); 1102 1103 if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) { 1104 spectral_err("Invalid signature 0x%x!", 1105 ptlv->signature); 1106 return -EPERM; 1107 } 1108 1109 curr_tlv_complete_size = 1110 sizeof(struct spectral_phyerr_tlv_gen2) + 1111 ptlv->length; 1112 1113 if (curr_tlv_complete_size > bytes_remaining) { 1114 spectral_err("TLV size %d greater than number of bytes remaining %d", 1115 curr_tlv_complete_size, bytes_remaining); 1116 return -EPERM; 1117 } 1118 1119 if (target_if_spectral_dump_tlv_gen2(ptlv, is_160_format) == -1) 1120 return -EPERM; 1121 1122 bytes_processed += curr_tlv_complete_size; 1123 bytes_remaining = datalen - bytes_processed; 1124 } 1125 1126 return 0; 1127 } 1128 1129 int 1130 target_if_process_sfft_report_gen3( 1131 struct spectral_phyerr_fft_report_gen3 *p_fft_report, 1132 struct spectral_search_fft_info_gen3 *p_sfft) 1133 { 1134 /* 1135 * For simplicity, everything is defined as uint32_t (except one). 1136 * Proper code will later use the right sizes. 1137 */ 1138 /* 1139 * For easy comparision between MDK team and OS team, the MDK script 1140 * variable names have been used 1141 */ 1142 int32_t peak_sidx; 1143 int32_t peak_mag; 1144 1145 /* Populate the Search FFT Info */ 1146 if (p_sfft) { 1147 p_sfft->timestamp = p_fft_report->fft_timestamp; 1148 1149 p_sfft->fft_detector_id = get_bitfield(p_fft_report->hdr_a, 1150 2, 0); 1151 p_sfft->fft_num = get_bitfield(p_fft_report->hdr_a, 3, 2); 1152 p_sfft->fft_radar_check = get_bitfield(p_fft_report->hdr_a, 1153 12, 5); 1154 1155 peak_sidx = get_bitfield(p_fft_report->hdr_a, 11, 17); 1156 p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11); 1157 p_sfft->fft_chn_idx = get_bitfield(p_fft_report->hdr_a, 3, 28); 1158 1159 p_sfft->fft_base_pwr_db = get_bitfield(p_fft_report->hdr_b, 1160 9, 0); 1161 p_sfft->fft_total_gain_db = get_bitfield(p_fft_report->hdr_b, 1162 8, 9); 1163 1164 p_sfft->fft_num_str_bins_ib = get_bitfield(p_fft_report->hdr_c, 1165 8, 0); 1166 peak_mag = get_bitfield(p_fft_report->hdr_c, 10, 8); 1167 p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10); 1168 p_sfft->fft_avgpwr_db = get_bitfield(p_fft_report->hdr_c, 1169 7, 18); 1170 p_sfft->fft_relpwr_db = get_bitfield(p_fft_report->hdr_c, 1171 7, 25); 1172 } 1173 1174 return 0; 1175 } 1176 1177 int 1178 target_if_dump_fft_report_gen3(struct target_if_spectral *spectral, 1179 struct spectral_phyerr_fft_report_gen3 *p_fft_report, 1180 struct spectral_search_fft_info_gen3 *p_sfft) 1181 { 1182 int i = 0; 1183 int fft_mag = 0; 1184 int fft_hdr_length = (p_fft_report->fft_hdr_length * 4); 1185 int report_len = (fft_hdr_length + 8); 1186 int fft_bin_len = (fft_hdr_length - 16); 1187 int fft_bin_len_adj = fft_bin_len >> 2; 1188 int fft_bin_len_inband_tfer = 0; 1189 int fft_bin_len_to_dump = fft_bin_len; 1190 1191 if ((spectral->params.ss_rpt_mode == 2) && 1192 spectral->inband_fftbin_size_adj) { 1193 fft_bin_len_adj >>= 1; 1194 fft_bin_len_inband_tfer = fft_bin_len >> 1; 1195 fft_bin_len_to_dump = fft_bin_len_inband_tfer; 1196 } 1197 1198 spectral_debug("#############################################################"); 1199 spectral_debug("Spectral search fft_report"); 1200 spectral_debug("fft_timestamp = 0x%x\nfft_hdr_length = %d(32 bit words)\nfft_hdr_tag = 0x%x\nfft_hdr_sig = 0x%x", 1201 p_fft_report->fft_timestamp, 1202 p_fft_report->fft_hdr_length, 1203 p_fft_report->fft_hdr_tag, p_fft_report->fft_hdr_sig); 1204 1205 spectral_debug("Length field in search fft report is %d(0x%x) bytes", 1206 fft_hdr_length, fft_hdr_length); 1207 spectral_debug("Total length of search fft report is %d(0x%x) bytes", 1208 report_len, report_len); 1209 spectral_debug("FW reported fftbins in report is %d(0x%x)", fft_bin_len, 1210 fft_bin_len); 1211 if ((spectral->params.ss_rpt_mode == 2) && 1212 spectral->inband_fftbin_size_adj) { 1213 spectral_debug("FW fftbins actually transferred (in-band report mode) " 1214 "%d(0x%x)", 1215 fft_bin_len_inband_tfer, fft_bin_len_inband_tfer); 1216 } 1217 spectral_debug("Actual number of fftbins in report is %d(0x%x)\n", 1218 fft_bin_len_adj, fft_bin_len_adj); 1219 1220 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", 1221 p_sfft->fft_detector_id, 1222 p_sfft->fft_num, 1223 p_sfft->fft_radar_check, 1224 p_sfft->fft_peak_sidx, 1225 p_sfft->fft_chn_idx, 1226 p_sfft->fft_base_pwr_db, 1227 p_sfft->fft_total_gain_db, 1228 p_sfft->fft_num_str_bins_ib, 1229 p_sfft->fft_peak_mag, 1230 p_sfft->fft_avgpwr_db, p_sfft->fft_relpwr_db); 1231 1232 spectral_debug("FFT bins:"); 1233 for (i = 0; i < fft_bin_len_to_dump; i++) { 1234 if (i % 16 == 0) 1235 spectral_debug("\n%d :", i); 1236 fft_mag = 1237 ((uint8_t *)p_fft_report)[SPECTRAL_FFT_BINS_POS + i]; 1238 spectral_debug("%d ", fft_mag); 1239 } 1240 spectral_debug("\n"); 1241 spectral_debug("#############################################################"); 1242 1243 return 0; 1244 } 1245 1246 #ifdef DIRECT_BUF_RX_ENABLE 1247 /** 1248 * target_if_consume_sscan_report_gen3() - Consume spectral summary report 1249 * @spectral: Pointer to spectral object 1250 * @data: Pointer to spectral summary 1251 * 1252 * Consume spectral summary report for gen3 1253 * 1254 * Return: void 1255 */ 1256 static void 1257 target_if_consume_sscan_report_gen3(struct target_if_spectral *spectral, 1258 uint8_t *data, 1259 struct sscan_report_fields_gen3 *fields) { 1260 struct spectral_sscan_report_gen3 *psscan_report; 1261 1262 psscan_report = (struct spectral_sscan_report_gen3 *)data; 1263 fields->sscan_agc_total_gain = get_bitfield(psscan_report->hdr_a, 8, 0); 1264 fields->inband_pwr_db = get_bitfield(psscan_report->hdr_a, 10, 18); 1265 fields->sscan_gainchange = get_bitfield(psscan_report->hdr_b, 1, 30); 1266 } 1267 1268 /** 1269 * target_if_verify_sig_and_tag_gen3() - Verify tag and signature 1270 * of spectral report 1271 * @spectral: Pointer to spectral object 1272 * @data: Pointer to spectral summary report 1273 * @exp_tag: iexpected tag value 1274 * 1275 * Process fft report for gen3 1276 * 1277 * Return: SUCCESS/FAILURE 1278 */ 1279 static int 1280 target_if_verify_sig_and_tag_gen3(struct target_if_spectral *spectral, 1281 uint8_t *data, uint8_t exp_tag) 1282 { 1283 uint8_t tag = 0; 1284 uint8_t signature = 0; 1285 1286 /* Peek into the data to figure out whether 1287 * 1) Signature matches the expected value 1288 * 2) What is inside the package (TAG ID is used for finding this) 1289 */ 1290 tag = *(data + PHYERR_HDR_TAG_POS); 1291 signature = *(data + PHYERR_HDR_SIG_POS); 1292 1293 if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) { 1294 if (spectral_debug_level & DEBUG_SPECTRAL4) 1295 spectral_err("Unexpected sig %x in spectral phyerror", 1296 signature); 1297 spectral_err("Expected sig is %x\n", 1298 SPECTRAL_PHYERR_SIGNATURE_GEN3); 1299 spectral->diag_stats.spectral_mismatch++; 1300 return -EINVAL; 1301 } 1302 1303 if (tag != exp_tag) { 1304 if (spectral_debug_level & DEBUG_SPECTRAL4) 1305 spectral_err("Unexpected tag %x in spectral phyerror", 1306 tag); 1307 spectral_err("Expected tag is %x\n", exp_tag); 1308 spectral->diag_stats.spectral_mismatch++; 1309 return -EINVAL; 1310 } 1311 1312 return 0; 1313 } 1314 1315 static uint8_t 1316 target_if_spectral_get_lowest_chn_idx(uint8_t chainmask) 1317 { 1318 uint8_t idx; 1319 1320 for (idx = 0; idx < DBR_MAX_CHAINS; idx++) { 1321 if (chainmask & 0x1) 1322 break; 1323 chainmask >>= 1; 1324 } 1325 return idx; 1326 } 1327 1328 int 1329 target_if_consume_spectral_report_gen3( 1330 struct target_if_spectral *spectral, 1331 struct spectral_report *report) 1332 { 1333 /* 1334 * XXX : The classifier do not use all the members of the SAMP 1335 * message data format. 1336 * The classifier only depends upon the following parameters 1337 * 1338 * 1. Frequency (freq, msg->freq) 1339 * 2. Spectral RSSI (spectral_rssi, 1340 * msg->samp_data.spectral_rssi) 1341 * 3. Bin Power Count (bin_pwr_count, 1342 * msg->samp_data.bin_pwr_count) 1343 * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0] 1344 * 5. Spectral Timestamp (spectral_tstamp, 1345 * msg->samp_data.spectral_tstamp) 1346 * 6. MAC Address (macaddr, msg->macaddr) 1347 * 1348 * This function prepares the params structure and populates it 1349 * with 1350 * relevant values, this is in turn passed to 1351 * spectral_create_samp_msg() 1352 * to prepare fully formatted Spectral SAMP message 1353 * 1354 * XXX : Need to verify 1355 * 1. Order of FFT bin values 1356 * 1357 */ 1358 uint64_t tsf64 = 0; 1359 struct target_if_samp_msg_params params; 1360 struct spectral_search_fft_info_gen3 search_fft_info; 1361 struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info; 1362 int8_t rssi_up = 0; 1363 int8_t rssi_low = 0; 1364 int8_t chn_idx_lowest_enabled = 0; 1365 uint8_t control_rssi = 0; 1366 uint8_t extension_rssi = 0; 1367 int fft_hdr_length = 0; 1368 int report_len = 0; 1369 int fft_bin_len = 0; 1370 struct target_if_spectral_ops *p_sops = 1371 GET_TARGET_IF_SPECTRAL_OPS(spectral); 1372 struct spectral_phyerr_fft_report_gen3 *p_fft_report; 1373 int8_t rssi; 1374 uint8_t *data = report->data; 1375 struct wlan_objmgr_vdev *vdev; 1376 uint8_t vdev_rxchainmask; 1377 struct sscan_report_fields_gen3 sscan_report_fields; 1378 1379 OS_MEMZERO(¶ms, sizeof(params)); 1380 1381 if (target_if_verify_sig_and_tag_gen3( 1382 spectral, data, 1383 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) 1384 goto fail; 1385 target_if_consume_sscan_report_gen3(spectral, data, 1386 &sscan_report_fields); 1387 /* RSSI is in 1/2 dBm steps, Covert it to dBm scale */ 1388 rssi = (sscan_report_fields.inband_pwr_db) >> 1; 1389 params.agc_total_gain = sscan_report_fields.sscan_agc_total_gain; 1390 params.gainchange = sscan_report_fields.sscan_gainchange; 1391 /* Advance buf pointer to the search fft report */ 1392 data += sizeof(struct spectral_sscan_report_gen3); 1393 1394 if (target_if_verify_sig_and_tag_gen3( 1395 spectral, data, 1396 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) 1397 goto fail; 1398 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)data; 1399 fft_hdr_length = p_fft_report->fft_hdr_length * 4; 1400 if (fft_hdr_length < 16) { 1401 spectral_err("Unexpected TLV length %u for FFT Report! Hexdump follows", 1402 fft_hdr_length); 1403 goto fail; 1404 } 1405 1406 report_len = (fft_hdr_length + 8); 1407 1408 fft_bin_len = (fft_hdr_length - 16); 1409 fft_bin_len >>= 2; 1410 if ((spectral->params.ss_rpt_mode == 2) && 1411 spectral->inband_fftbin_size_adj) { 1412 fft_bin_len >>= 1; 1413 } 1414 1415 tsf64 = p_fft_report->fft_timestamp; 1416 1417 target_if_process_sfft_report_gen3(p_fft_report, p_sfft); 1418 1419 if (p_sfft->fft_detector_id != 0) { 1420 spectral_err("Expected segid is 0 but we got %d", 1421 p_sfft->fft_detector_id); 1422 spectral->diag_stats.spectral_vhtseg1id_mismatch++; 1423 goto fail; 1424 } 1425 1426 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) 1427 target_if_dump_fft_report_gen3(spectral, p_fft_report, p_sfft); 1428 1429 if (spectral->upper_is_control) 1430 rssi_up = control_rssi; 1431 else 1432 rssi_up = extension_rssi; 1433 1434 if (spectral->lower_is_control) 1435 rssi_low = control_rssi; 1436 else 1437 rssi_low = extension_rssi; 1438 1439 params.rssi = rssi; 1440 params.lower_rssi = rssi_low; 1441 params.upper_rssi = rssi_up; 1442 1443 if (spectral->sc_spectral_noise_pwr_cal) { 1444 /* Fill 0's till FW provides them */ 1445 params.chain_ctl_rssi[0] = 0; 1446 params.chain_ctl_rssi[1] = 0; 1447 params.chain_ctl_rssi[2] = 0; 1448 params.chain_ext_rssi[0] = 0; 1449 params.chain_ext_rssi[1] = 0; 1450 params.chain_ext_rssi[2] = 0; 1451 } 1452 1453 vdev = target_if_spectral_get_vdev(spectral); 1454 if (!vdev) 1455 return -ENOENT; 1456 1457 vdev_rxchainmask = 1458 wlan_vdev_mlme_get_rxchainmask(vdev); 1459 QDF_ASSERT(vdev_rxchainmask != 0); 1460 wlan_objmgr_vdev_release_ref(vdev, 1461 WLAN_SPECTRAL_ID); 1462 1463 chn_idx_lowest_enabled = 1464 target_if_spectral_get_lowest_chn_idx(vdev_rxchainmask); 1465 if (chn_idx_lowest_enabled >= DBR_MAX_CHAINS) 1466 return -EINVAL; 1467 1468 control_rssi = 0; 1469 extension_rssi = 0; 1470 1471 params.bwinfo = 0; 1472 params.tstamp = 0; 1473 params.max_mag = p_sfft->fft_peak_mag; 1474 1475 /* params.max_index = p_sfft->peak_inx; */ 1476 params.max_exp = 0; 1477 params.peak = 0; 1478 params.bin_pwr_data = (uint8_t *)((uint8_t *)p_fft_report + 1479 SPECTRAL_FFT_BINS_POS); 1480 params.freq = p_sops->get_current_channel(spectral); 1481 params.freq_loading = 0; 1482 1483 params.interf_list.count = 0; 1484 params.max_lower_index = 0; 1485 params.max_upper_index = 0; 1486 params.nb_lower = 0; 1487 params.nb_upper = 0; 1488 /* 1489 * For modes upto VHT80, the noise floor is populated with the one 1490 * corresponding 1491 * to the highest enabled antenna chain 1492 */ 1493 /* TODO: Fill proper values once FW provides them*/ 1494 params.noise_floor = report->noisefloor[chn_idx_lowest_enabled]; 1495 params.datalen = (fft_hdr_length * 4); 1496 params.pwr_count = fft_bin_len; 1497 params.tstamp = (tsf64 & SPECTRAL_TSMASK); 1498 1499 if (spectral->ch_width == CH_WIDTH_160MHZ) { 1500 /* We expect to see one more Search FFT report, and it should be 1501 * equal in size to the current one. 1502 */ 1503 /* Advance to the secondary 80 Mhz spectral report */ 1504 data += report_len; 1505 1506 if (target_if_verify_sig_and_tag_gen3( 1507 spectral, data, 1508 TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3) != 0) 1509 goto fail; 1510 target_if_consume_sscan_report_gen3(spectral, data, 1511 &sscan_report_fields); 1512 /* RSSI is in 1/2 dBm steps, Covert it to dBm scale */ 1513 rssi = (sscan_report_fields.inband_pwr_db) >> 1; 1514 params.agc_total_gain_sec80 = 1515 sscan_report_fields.sscan_agc_total_gain; 1516 params.gainchange_sec80 = sscan_report_fields.sscan_gainchange; 1517 /* Advance buf pointer to the search fft report */ 1518 data += sizeof(struct spectral_sscan_report_gen3); 1519 1520 if (target_if_verify_sig_and_tag_gen3( 1521 spectral, data, 1522 TLV_TAG_SEARCH_FFT_REPORT_GEN3) != 0) 1523 goto fail; 1524 p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)(data); 1525 fft_hdr_length = p_fft_report->fft_hdr_length * 4; 1526 report_len = (fft_hdr_length + 8); 1527 1528 fft_bin_len = (fft_hdr_length - 16); 1529 fft_bin_len >>= 2; 1530 if ((spectral->params.ss_rpt_mode == 2) && 1531 spectral->inband_fftbin_size_adj) { 1532 fft_bin_len >>= 1; 1533 } 1534 1535 target_if_process_sfft_report_gen3(p_fft_report, p_sfft); 1536 1537 if (p_sfft->fft_detector_id != 1) { 1538 spectral_err("Expected segid is 1 but we got %d", 1539 p_sfft->fft_detector_id); 1540 spectral->diag_stats.spectral_vhtseg2id_mismatch++; 1541 goto fail; 1542 } 1543 1544 if (spectral_debug_level & 1545 (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) 1546 target_if_dump_fft_report_gen3(spectral, p_fft_report, p_sfft); 1547 1548 params.vhtop_ch_freq_seg1 = 0; 1549 params.vhtop_ch_freq_seg2 = 0; 1550 1551 /* XXX: Confirm. TBD at SoD. */ 1552 params.rssi_sec80 = rssi; 1553 1554 /* XXX: Determine dynamically. TBD at SoD. */ 1555 1556 /* 1557 * For VHT80_80/VHT160,the noise floor for primary 80MHz segment 1558 * populated with the 1559 * lowest enabled antenna chain and the nf for secondary 80MHz 1560 * segment is populated 1561 * with the highest enabled antenna chain 1562 */ 1563 /* TODO: Fill proper values once FW provides them*/ 1564 params.noise_floor_sec80 = DUMMY_NF_VALUE; 1565 params.noise_floor = DUMMY_NF_VALUE; 1566 1567 params.max_mag_sec80 = p_sfft->fft_peak_mag; 1568 /* params.max_index_sec80 = p_sfft->peak_inx; */ 1569 /* XXX Does this definition of datalen *still hold? */ 1570 params.datalen_sec80 = fft_hdr_length; 1571 params.pwr_count_sec80 = fft_bin_len; 1572 params.bin_pwr_data_sec80 = (u_int8_t *)( 1573 (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS); 1574 } 1575 1576 qdf_mem_copy(¶ms.classifier_params, 1577 &spectral->classifier_params, 1578 sizeof(struct spectral_classifier_params)); 1579 1580 target_if_spectral_log_SAMP_param(¶ms); 1581 target_if_spectral_create_samp_msg(spectral, ¶ms); 1582 1583 return 0; 1584 1585 fail: 1586 spectral_err("Error in function while processing search fft report"); 1587 return -EPERM; 1588 } 1589 1590 int target_if_spectral_process_report_gen3( 1591 struct wlan_objmgr_pdev *pdev, 1592 void *buf) 1593 { 1594 int ret = 0; 1595 struct direct_buf_rx_data *payload = buf; 1596 struct target_if_spectral *spectral; 1597 struct spectral_report report; 1598 1599 spectral = get_target_if_spectral_handle_from_pdev(pdev); 1600 if (spectral == NULL) { 1601 spectral_err("Spectral target object is null"); 1602 return -EINVAL; 1603 } 1604 1605 report.data = payload->vaddr; 1606 if (payload->meta_data_valid) 1607 qdf_mem_copy(report.noisefloor, &payload->meta_data, 1608 sizeof(payload->meta_data)); 1609 1610 if (spectral_debug_level & (DEBUG_SPECTRAL2 | DEBUG_SPECTRAL4)) { 1611 spectral_debug("Printing the spectral phyerr buffer for debug"); 1612 spectral_debug("Datalength of buffer = 0x%zx(%zd) bufptr = 0x%pK", 1613 payload->dbr_len, 1614 payload->dbr_len, 1615 payload->vaddr); 1616 #ifdef CONFIG_WIN 1617 RAWSIM_PKT_HEXDUMP((unsigned char *)payload->vaddr, 1024); 1618 #endif 1619 } 1620 1621 ret = target_if_consume_spectral_report_gen3(spectral, &report); 1622 1623 if (spectral_debug_level & DEBUG_SPECTRAL4) 1624 spectral_debug_level = DEBUG_SPECTRAL; 1625 1626 return ret; 1627 } 1628 #else 1629 int target_if_spectral_process_report_gen3( 1630 struct wlan_objmgr_pdev *pdev, 1631 void *buf) 1632 { 1633 spectral_err("Direct dma support is not enabled"); 1634 return -EINVAL; 1635 } 1636 #endif 1637 qdf_export_symbol(target_if_spectral_process_report_gen3); 1638 /* END of spectral GEN III HW specific functions */ 1639 1640 #endif /* WLAN_CONV_SPECTRAL_ENABLE */ 1641