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