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