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