1 /* 2 * Copyright (c) 2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "qdf_types.h" 19 #include "hal_be_hw_headers.h" 20 #include "dp_types.h" 21 #include "hal_be_tx.h" 22 #include "hal_api.h" 23 #include "qdf_trace.h" 24 #include "hal_be_api_mon.h" 25 #include "dp_internal.h" 26 #include "qdf_mem.h" /* qdf_mem_malloc,free */ 27 #include "dp_mon.h" 28 #include <dp_mon_2.0.h> 29 #include <dp_tx_mon_2.0.h> 30 #include <dp_be.h> 31 #include <hal_be_api_mon.h> 32 #include <dp_mon_filter_2.0.h> 33 #include "dp_ratetable.h" 34 #ifdef QCA_SUPPORT_LITE_MONITOR 35 #include "dp_lite_mon.h" 36 #endif 37 38 #define MAX_TX_MONITOR_STUCK 50 39 40 #ifdef TXMON_DEBUG 41 /* 42 * dp_tx_mon_debug_statu() - API to display tx monitor status 43 * @tx_mon_be - pointer to dp_pdev_tx_monitor_be 44 * @work_done - tx monitor work done 45 * 46 * Return: void 47 */ 48 static inline void 49 dp_tx_mon_debug_status(struct dp_pdev_tx_monitor_be *tx_mon_be, 50 uint32_t work_done) 51 { 52 if (tx_mon_be->mode && !work_done) 53 tx_mon_be->stats.tx_mon_stuck++; 54 else if (tx_mon_be->mode && work_done) 55 tx_mon_be->stats.tx_mon_stuck = 0; 56 57 if (tx_mon_be->stats.tx_mon_stuck > MAX_TX_MONITOR_STUCK) { 58 dp_mon_warn("Tx monitor block got stuck!!!!!"); 59 tx_mon_be->stats.tx_mon_stuck = 0; 60 tx_mon_be->stats.total_tx_mon_stuck++; 61 } 62 63 dp_mon_debug_rl("tx_ppdu_info[%u :D %u] STATUS[R %llu: F %llu] PKT_BUF[R %llu: F %llu : P %llu : S %llu]", 64 tx_mon_be->tx_ppdu_info_list_depth, 65 tx_mon_be->defer_ppdu_info_list_depth, 66 tx_mon_be->stats.status_buf_recv, 67 tx_mon_be->stats.status_buf_free, 68 tx_mon_be->stats.pkt_buf_recv, 69 tx_mon_be->stats.pkt_buf_free, 70 tx_mon_be->stats.pkt_buf_processed, 71 tx_mon_be->stats.pkt_buf_to_stack); 72 } 73 74 #else 75 /* 76 * dp_tx_mon_debug_statu() - API to display tx monitor status 77 * @tx_mon_be - pointer to dp_pdev_tx_monitor_be 78 * @work_done - tx monitor work done 79 * 80 * Return: void 81 */ 82 static inline void 83 dp_tx_mon_debug_status(struct dp_pdev_tx_monitor_be *tx_mon_be, 84 uint32_t work_done) 85 { 86 if (tx_mon_be->mode && !work_done) 87 tx_mon_be->stats.tx_mon_stuck++; 88 else if (tx_mon_be->mode && work_done) 89 tx_mon_be->stats.tx_mon_stuck = 0; 90 91 if (tx_mon_be->stats.tx_mon_stuck > MAX_TX_MONITOR_STUCK) { 92 dp_mon_warn("Tx monitor block got stuck!!!!!"); 93 tx_mon_be->stats.tx_mon_stuck = 0; 94 tx_mon_be->stats.total_tx_mon_stuck++; 95 } 96 } 97 #endif 98 99 static inline uint32_t 100 dp_tx_mon_srng_process_2_0(struct dp_soc *soc, struct dp_intr *int_ctx, 101 uint32_t mac_id, uint32_t quota) 102 { 103 struct dp_pdev *pdev = dp_get_pdev_for_lmac_id(soc, mac_id); 104 void *tx_mon_dst_ring_desc; 105 hal_soc_handle_t hal_soc; 106 void *mon_dst_srng; 107 struct dp_mon_pdev *mon_pdev; 108 struct dp_mon_pdev_be *mon_pdev_be; 109 uint32_t work_done = 0; 110 struct dp_mon_soc *mon_soc = soc->monitor_soc; 111 struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 112 struct dp_pdev_tx_monitor_be *tx_mon_be = NULL; 113 struct dp_mon_desc_pool *tx_mon_desc_pool = &mon_soc_be->tx_desc_mon; 114 struct dp_tx_mon_desc_list mon_desc_list; 115 uint32_t replenish_cnt = 0; 116 117 if (!pdev) { 118 dp_mon_err("%pK: pdev is null for mac_id = %d", soc, mac_id); 119 return work_done; 120 } 121 122 mon_pdev = pdev->monitor_pdev; 123 mon_dst_srng = mon_soc_be->tx_mon_dst_ring[mac_id].hal_srng; 124 125 if (!mon_dst_srng || !hal_srng_initialized(mon_dst_srng)) { 126 dp_mon_err("%pK: : HAL Monitor Destination Ring Init Failed -- %pK", 127 soc, mon_dst_srng); 128 return work_done; 129 } 130 131 mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 132 if (qdf_unlikely(!mon_pdev_be)) 133 return work_done; 134 135 tx_mon_be = &mon_pdev_be->tx_monitor_be; 136 hal_soc = soc->hal_soc; 137 138 qdf_assert((hal_soc && pdev)); 139 140 qdf_spin_lock_bh(&mon_pdev->mon_lock); 141 mon_desc_list.desc_list = NULL; 142 mon_desc_list.tail = NULL; 143 mon_desc_list.tx_mon_reap_cnt = 0; 144 145 if (qdf_unlikely(dp_srng_access_start(int_ctx, soc, mon_dst_srng))) { 146 dp_mon_err("%s %d : HAL Mon Dest Ring access Failed -- %pK", 147 __func__, __LINE__, mon_dst_srng); 148 qdf_spin_unlock_bh(&mon_pdev->mon_lock); 149 return work_done; 150 } 151 152 while (qdf_likely((tx_mon_dst_ring_desc = 153 (void *)hal_srng_dst_peek(hal_soc, mon_dst_srng)) 154 && quota--)) { 155 struct hal_mon_desc hal_mon_tx_desc = {0}; 156 struct dp_mon_desc *mon_desc = NULL; 157 qdf_frag_t status_frag = NULL; 158 uint32_t end_offset = 0; 159 160 hal_be_get_mon_dest_status(soc->hal_soc, 161 tx_mon_dst_ring_desc, 162 &hal_mon_tx_desc); 163 164 if (hal_mon_tx_desc.empty_descriptor) { 165 /* update stats counter */ 166 dp_mon_debug("P_ID:%d INIT:%d E_DESC:%d R_ID:%d L_CNT:%d DROP[PPDU:%d MPDU:%d TLV:%d] E_O_PPDU:%d", 167 hal_mon_tx_desc.ppdu_id, 168 hal_mon_tx_desc.initiator, 169 hal_mon_tx_desc.empty_descriptor, 170 hal_mon_tx_desc.ring_id, 171 hal_mon_tx_desc.looping_count, 172 hal_mon_tx_desc.ppdu_drop_count, 173 hal_mon_tx_desc.mpdu_drop_count, 174 hal_mon_tx_desc.tlv_drop_count, 175 hal_mon_tx_desc.end_of_ppdu_dropped); 176 177 tx_mon_be->stats.ppdu_drop_cnt += 178 hal_mon_tx_desc.ppdu_drop_count; 179 tx_mon_be->stats.mpdu_drop_cnt += 180 hal_mon_tx_desc.mpdu_drop_count; 181 tx_mon_be->stats.tlv_drop_cnt += 182 hal_mon_tx_desc.tlv_drop_count; 183 work_done++; 184 hal_srng_dst_get_next(hal_soc, mon_dst_srng); 185 continue; 186 } 187 188 dp_mon_debug("P_ID:%d INIT:%d E_DESC:%d R_ID:%d L_CNT:%d BUF_ADDR: 0x%llx E_OFF: %d E_REA: %d", 189 hal_mon_tx_desc.ppdu_id, 190 hal_mon_tx_desc.initiator, 191 hal_mon_tx_desc.empty_descriptor, 192 hal_mon_tx_desc.ring_id, 193 hal_mon_tx_desc.looping_count, 194 hal_mon_tx_desc.buf_addr, 195 hal_mon_tx_desc.end_offset, 196 hal_mon_tx_desc.end_reason); 197 198 mon_desc = (struct dp_mon_desc *)(uintptr_t)(hal_mon_tx_desc.buf_addr); 199 qdf_assert_always(mon_desc); 200 201 if (!mon_desc->unmapped) { 202 qdf_mem_unmap_page(soc->osdev, mon_desc->paddr, 203 DP_MON_DATA_BUFFER_SIZE, 204 QDF_DMA_FROM_DEVICE); 205 mon_desc->unmapped = 1; 206 } 207 208 if (mon_desc->magic != DP_MON_DESC_MAGIC) { 209 dp_mon_err("Invalid monitor descriptor"); 210 qdf_assert_always(0); 211 } 212 213 end_offset = hal_mon_tx_desc.end_offset; 214 215 status_frag = (qdf_frag_t)(mon_desc->buf_addr); 216 mon_desc->buf_addr = NULL; 217 /* increment reap count */ 218 ++mon_desc_list.tx_mon_reap_cnt; 219 220 /* add the mon_desc to free list */ 221 dp_mon_add_to_free_desc_list(&mon_desc_list.desc_list, 222 &mon_desc_list.tail, mon_desc); 223 224 225 if (qdf_unlikely(!status_frag)) { 226 dp_mon_debug("P_ID:%d INIT:%d E_DESC:%d R_ID:%d L_CNT:%d BUF_ADDR: 0x%llx E_OFF: %d E_REA: %d", 227 hal_mon_tx_desc.ppdu_id, 228 hal_mon_tx_desc.initiator, 229 hal_mon_tx_desc.empty_descriptor, 230 hal_mon_tx_desc.ring_id, 231 hal_mon_tx_desc.looping_count, 232 hal_mon_tx_desc.buf_addr, 233 hal_mon_tx_desc.end_offset, 234 hal_mon_tx_desc.end_reason); 235 236 work_done++; 237 hal_srng_dst_get_next(hal_soc, mon_dst_srng); 238 continue; 239 } 240 241 tx_mon_be->stats.status_buf_recv++; 242 243 if ((hal_mon_tx_desc.end_reason == HAL_MON_FLUSH_DETECTED) || 244 (hal_mon_tx_desc.end_reason == HAL_MON_PPDU_TRUNCATED)) { 245 tx_mon_be->be_ppdu_id = hal_mon_tx_desc.ppdu_id; 246 247 dp_tx_mon_update_end_reason(mon_pdev, 248 hal_mon_tx_desc.ppdu_id, 249 hal_mon_tx_desc.end_reason); 250 /* check and free packet buffer from status buffer */ 251 dp_tx_mon_status_free_packet_buf(pdev, status_frag, 252 end_offset, 253 &mon_desc_list); 254 255 tx_mon_be->stats.status_buf_free++; 256 qdf_frag_free(status_frag); 257 258 work_done++; 259 hal_srng_dst_get_next(hal_soc, mon_dst_srng); 260 continue; 261 } 262 263 dp_tx_process_pktlog_be(soc, pdev, 264 status_frag, 265 end_offset); 266 267 dp_tx_mon_process_status_tlv(soc, pdev, 268 &hal_mon_tx_desc, 269 status_frag, 270 end_offset, 271 &mon_desc_list); 272 273 work_done++; 274 hal_srng_dst_get_next(hal_soc, mon_dst_srng); 275 } 276 dp_srng_access_end(int_ctx, soc, mon_dst_srng); 277 278 if (mon_desc_list.tx_mon_reap_cnt) { 279 dp_mon_buffers_replenish(soc, &mon_soc_be->tx_mon_buf_ring, 280 tx_mon_desc_pool, 281 mon_desc_list.tx_mon_reap_cnt, 282 &mon_desc_list.desc_list, 283 &mon_desc_list.tail, 284 &replenish_cnt); 285 } 286 qdf_spin_unlock_bh(&mon_pdev->mon_lock); 287 dp_mon_debug("mac_id: %d, work_done:%d tx_monitor_reap_cnt:%d", 288 mac_id, work_done, mon_desc_list.tx_mon_reap_cnt); 289 290 tx_mon_be->stats.total_tx_mon_reap_cnt += mon_desc_list.tx_mon_reap_cnt; 291 tx_mon_be->stats.totat_tx_mon_replenish_cnt += replenish_cnt; 292 dp_tx_mon_debug_status(tx_mon_be, work_done); 293 294 return work_done; 295 } 296 297 uint32_t 298 dp_tx_mon_process_2_0(struct dp_soc *soc, struct dp_intr *int_ctx, 299 uint32_t mac_id, uint32_t quota) 300 { 301 uint32_t work_done; 302 303 work_done = dp_tx_mon_srng_process_2_0(soc, int_ctx, mac_id, quota); 304 305 return work_done; 306 } 307 308 void 309 dp_tx_mon_print_ring_stat_2_0(struct dp_pdev *pdev) 310 { 311 struct dp_soc *soc = pdev->soc; 312 struct dp_mon_soc *mon_soc = soc->monitor_soc; 313 struct dp_mon_soc_be *mon_soc_be = 314 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 315 int lmac_id; 316 317 lmac_id = dp_get_lmac_id_for_pdev_id(soc, 0, pdev->pdev_id); 318 dp_print_ring_stat_from_hal(soc, &mon_soc_be->tx_mon_buf_ring, 319 TX_MONITOR_BUF); 320 dp_print_ring_stat_from_hal(soc, &mon_soc_be->tx_mon_dst_ring[lmac_id], 321 TX_MONITOR_DST); 322 } 323 324 void 325 dp_tx_mon_buf_desc_pool_deinit(struct dp_soc *soc) 326 { 327 struct dp_mon_soc *mon_soc = soc->monitor_soc; 328 struct dp_mon_soc_be *mon_soc_be = 329 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 330 331 dp_mon_desc_pool_deinit(&mon_soc_be->tx_desc_mon); 332 } 333 334 QDF_STATUS 335 dp_tx_mon_buf_desc_pool_init(struct dp_soc *soc) 336 { 337 struct dp_mon_soc *mon_soc = soc->monitor_soc; 338 struct dp_mon_soc_be *mon_soc_be = 339 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 340 uint32_t num_entries; 341 342 num_entries = 343 wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc->wlan_cfg_ctx); 344 345 return dp_mon_desc_pool_init(&mon_soc_be->tx_desc_mon, num_entries); 346 } 347 348 void dp_tx_mon_buf_desc_pool_free(struct dp_soc *soc) 349 { 350 struct dp_mon_soc *mon_soc = soc->monitor_soc; 351 struct dp_mon_soc_be *mon_soc_be = 352 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 353 354 if (mon_soc_be) 355 dp_mon_desc_pool_free(soc, &mon_soc_be->tx_desc_mon, 356 DP_MON_TX_DESC_POOL_TYPE); 357 } 358 359 QDF_STATUS dp_tx_mon_soc_init_2_0(struct dp_soc *soc) 360 { 361 struct dp_mon_soc *mon_soc = soc->monitor_soc; 362 struct dp_mon_soc_be *mon_soc_be = 363 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 364 365 if (dp_srng_init(soc, &mon_soc_be->tx_mon_buf_ring, 366 TX_MONITOR_BUF, 0, 0)) { 367 dp_mon_err("%pK: " RNG_ERR "tx_mon_buf_ring", soc); 368 goto fail; 369 } 370 371 if (dp_tx_mon_buf_desc_pool_init(soc)) { 372 dp_mon_err("%pK: " RNG_ERR "tx mon desc pool init", soc); 373 goto fail; 374 } 375 376 return QDF_STATUS_SUCCESS; 377 fail: 378 return QDF_STATUS_E_FAILURE; 379 } 380 381 void dp_tx_mon_soc_deinit_2_0(struct dp_soc *soc, uint32_t lmac_id) 382 { 383 struct dp_mon_soc *mon_soc = soc->monitor_soc; 384 struct dp_mon_soc_be *mon_soc_be = 385 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 386 387 dp_tx_mon_buffers_free(soc); 388 dp_tx_mon_buf_desc_pool_deinit(soc); 389 dp_srng_deinit(soc, &mon_soc_be->tx_mon_buf_ring, TX_MONITOR_BUF, 0); 390 } 391 392 QDF_STATUS 393 dp_tx_mon_buf_desc_pool_alloc(struct dp_soc *soc) 394 { 395 struct dp_mon_desc_pool *tx_mon_desc_pool; 396 int entries; 397 struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx; 398 struct dp_mon_soc *mon_soc = soc->monitor_soc; 399 struct dp_mon_soc_be *mon_soc_be = 400 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 401 402 soc_cfg_ctx = soc->wlan_cfg_ctx; 403 404 entries = wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc_cfg_ctx); 405 406 407 tx_mon_desc_pool = &mon_soc_be->tx_desc_mon; 408 409 qdf_print("%s:%d tx mon buf desc pool entries: %d", __func__, __LINE__, entries); 410 return dp_mon_desc_pool_alloc(soc, DP_MON_TX_DESC_POOL_TYPE, 411 entries, tx_mon_desc_pool); 412 } 413 414 void 415 dp_tx_mon_buffers_free(struct dp_soc *soc) 416 { 417 struct dp_mon_desc_pool *tx_mon_desc_pool; 418 struct dp_mon_soc *mon_soc = soc->monitor_soc; 419 struct dp_mon_soc_be *mon_soc_be = 420 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 421 422 tx_mon_desc_pool = &mon_soc_be->tx_desc_mon; 423 424 dp_mon_pool_frag_unmap_and_free(soc, tx_mon_desc_pool); 425 } 426 427 QDF_STATUS 428 dp_tx_mon_buffers_alloc(struct dp_soc *soc, uint32_t size) 429 { 430 struct dp_srng *mon_buf_ring; 431 struct dp_mon_desc_pool *tx_mon_desc_pool; 432 union dp_mon_desc_list_elem_t *desc_list = NULL; 433 union dp_mon_desc_list_elem_t *tail = NULL; 434 struct dp_mon_soc *mon_soc = soc->monitor_soc; 435 struct dp_mon_soc_be *mon_soc_be = 436 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 437 438 mon_buf_ring = &mon_soc_be->tx_mon_buf_ring; 439 440 tx_mon_desc_pool = &mon_soc_be->tx_desc_mon; 441 442 return dp_mon_buffers_replenish(soc, mon_buf_ring, 443 tx_mon_desc_pool, 444 size, 445 &desc_list, &tail, NULL); 446 } 447 448 #ifdef WLAN_TX_PKT_CAPTURE_ENH_BE 449 450 /* 451 * dp_tx_mon_nbuf_get_num_frag() - get total number of fragments 452 * @buf: Network buf instance 453 * 454 * Return: number of fragments 455 */ 456 static inline 457 uint32_t dp_tx_mon_nbuf_get_num_frag(qdf_nbuf_t nbuf) 458 { 459 uint32_t num_frag = 0; 460 461 if (qdf_unlikely(!nbuf)) 462 return num_frag; 463 464 num_frag = qdf_nbuf_get_nr_frags_in_fraglist(nbuf); 465 466 return num_frag; 467 } 468 469 /* 470 * dp_tx_mon_free_usr_mpduq() - API to free user mpduq 471 * @tx_ppdu_info - pointer to tx_ppdu_info 472 * @usr_idx - user index 473 * @tx_mon_be - pointer to tx capture be 474 * 475 * Return: void 476 */ 477 void dp_tx_mon_free_usr_mpduq(struct dp_tx_ppdu_info *tx_ppdu_info, 478 uint8_t usr_idx, 479 struct dp_pdev_tx_monitor_be *tx_mon_be) 480 { 481 qdf_nbuf_queue_t *mpdu_q; 482 uint32_t num_frag = 0; 483 qdf_nbuf_t buf = NULL; 484 485 if (qdf_unlikely(!tx_ppdu_info)) 486 return; 487 488 mpdu_q = &TXMON_PPDU_USR(tx_ppdu_info, usr_idx, mpdu_q); 489 490 while ((buf = qdf_nbuf_queue_remove(mpdu_q)) != NULL) { 491 num_frag += dp_tx_mon_nbuf_get_num_frag(buf); 492 qdf_nbuf_free(buf); 493 } 494 tx_mon_be->stats.pkt_buf_free += num_frag; 495 } 496 497 /* 498 * dp_tx_mon_free_ppdu_info() - API to free dp_tx_ppdu_info 499 * @tx_ppdu_info - pointer to tx_ppdu_info 500 * @tx_mon_be - pointer to tx capture be 501 * 502 * Return: void 503 */ 504 void dp_tx_mon_free_ppdu_info(struct dp_tx_ppdu_info *tx_ppdu_info, 505 struct dp_pdev_tx_monitor_be *tx_mon_be) 506 { 507 uint32_t user = 0; 508 509 for (; user < TXMON_PPDU_HAL(tx_ppdu_info, num_users); user++) { 510 qdf_nbuf_queue_t *mpdu_q; 511 uint32_t num_frag = 0; 512 qdf_nbuf_t buf = NULL; 513 514 mpdu_q = &TXMON_PPDU_USR(tx_ppdu_info, user, mpdu_q); 515 516 while ((buf = qdf_nbuf_queue_remove(mpdu_q)) != NULL) { 517 num_frag += dp_tx_mon_nbuf_get_num_frag(buf); 518 qdf_nbuf_free(buf); 519 } 520 tx_mon_be->stats.pkt_buf_free += num_frag; 521 } 522 523 TXMON_PPDU_HAL(tx_ppdu_info, is_used) = 0; 524 qdf_mem_free(tx_ppdu_info); 525 } 526 527 /* 528 * dp_tx_mon_get_ppdu_info() - API to allocate dp_tx_ppdu_info 529 * @pdev - pdev handle 530 * @type - type of ppdu_info data or protection 531 * @num_user - number user in a ppdu_info 532 * @ppdu_id - ppdu_id number 533 * 534 * Return: pointer to dp_tx_ppdu_info 535 */ 536 struct dp_tx_ppdu_info *dp_tx_mon_get_ppdu_info(struct dp_pdev *pdev, 537 enum tx_ppdu_info_type type, 538 uint8_t num_user, 539 uint32_t ppdu_id) 540 { 541 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 542 struct dp_mon_pdev_be *mon_pdev_be = 543 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 544 struct dp_pdev_tx_monitor_be *tx_mon_be = 545 &mon_pdev_be->tx_monitor_be; 546 struct dp_tx_ppdu_info *tx_ppdu_info; 547 size_t sz_ppdu_info = 0; 548 uint8_t i; 549 550 /* allocate new tx_ppdu_info */ 551 sz_ppdu_info = (sizeof(struct dp_tx_ppdu_info) + 552 (sizeof(struct mon_rx_user_status) * num_user)); 553 554 tx_ppdu_info = (struct dp_tx_ppdu_info *)qdf_mem_malloc(sz_ppdu_info); 555 if (!tx_ppdu_info) { 556 dp_mon_err("allocation of tx_ppdu_info type[%d] failed!!!", 557 type); 558 return NULL; 559 } 560 561 TXMON_PPDU_HAL(tx_ppdu_info, is_used) = 0; 562 TXMON_PPDU_HAL(tx_ppdu_info, num_users) = num_user; 563 TXMON_PPDU_HAL(tx_ppdu_info, ppdu_id) = ppdu_id; 564 TXMON_PPDU(tx_ppdu_info, ppdu_id) = ppdu_id; 565 566 for (i = 0; i < num_user; i++) { 567 qdf_nbuf_queue_t *mpdu_q; 568 569 mpdu_q = &TXMON_PPDU_USR(tx_ppdu_info, i, mpdu_q); 570 qdf_nbuf_queue_init(mpdu_q); 571 } 572 573 /* assign tx_ppdu_info to monitor pdev for reference */ 574 if (type == TX_PROT_PPDU_INFO) { 575 qdf_mem_zero(&tx_mon_be->prot_status_info, sizeof(struct hal_tx_status_info)); 576 tx_mon_be->tx_prot_ppdu_info = tx_ppdu_info; 577 TXMON_PPDU_HAL(tx_ppdu_info, is_data) = 0; 578 } else { 579 qdf_mem_zero(&tx_mon_be->data_status_info, sizeof(struct hal_tx_status_info)); 580 tx_mon_be->tx_data_ppdu_info = tx_ppdu_info; 581 TXMON_PPDU_HAL(tx_ppdu_info, is_data) = 1; 582 } 583 584 return tx_ppdu_info; 585 } 586 587 /* 588 * dp_print_pdev_tx_monitor_stats_2_0: print tx capture stats 589 * @pdev: DP PDEV handle 590 * 591 * return: void 592 */ 593 void dp_print_pdev_tx_monitor_stats_2_0(struct dp_pdev *pdev) 594 { 595 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 596 struct dp_mon_pdev_be *mon_pdev_be = 597 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 598 struct dp_pdev_tx_monitor_be *tx_mon_be = 599 &mon_pdev_be->tx_monitor_be; 600 struct dp_tx_monitor_drop_stats stats = {0}; 601 602 qdf_mem_copy(&stats, &tx_mon_be->stats, 603 sizeof(struct dp_tx_monitor_drop_stats)); 604 605 /* TX monitor stats needed for beryllium */ 606 DP_PRINT_STATS("\n\tTX Capture BE stats mode[%d]:", tx_mon_be->mode); 607 DP_PRINT_STATS("\tbuffer pending : %u", tx_mon_be->last_frag_q_idx); 608 DP_PRINT_STATS("\treplenish count: %llu", 609 stats.totat_tx_mon_replenish_cnt); 610 DP_PRINT_STATS("\treap count : %llu", stats.total_tx_mon_reap_cnt); 611 DP_PRINT_STATS("\tmonitor stuck : %u", stats.total_tx_mon_stuck); 612 DP_PRINT_STATS("\tStatus buffer"); 613 DP_PRINT_STATS("\t\treceived : %llu", stats.status_buf_recv); 614 DP_PRINT_STATS("\t\tfree : %llu", stats.status_buf_free); 615 DP_PRINT_STATS("\tPacket buffer"); 616 DP_PRINT_STATS("\t\treceived : %llu", stats.pkt_buf_recv); 617 DP_PRINT_STATS("\t\tfree : %llu", stats.pkt_buf_free); 618 DP_PRINT_STATS("\t\tprocessed : %llu", stats.pkt_buf_processed); 619 DP_PRINT_STATS("\t\tto stack : %llu", stats.pkt_buf_to_stack); 620 DP_PRINT_STATS("\tppdu info"); 621 DP_PRINT_STATS("\t\tthreshold : %llu", stats.ppdu_info_drop_th); 622 DP_PRINT_STATS("\t\tflush : %llu", stats.ppdu_info_drop_flush); 623 DP_PRINT_STATS("\t\ttruncated : %llu", stats.ppdu_info_drop_trunc); 624 DP_PRINT_STATS("\tDrop stats"); 625 DP_PRINT_STATS("\t\tppdu drop : %llu", stats.ppdu_drop_cnt); 626 DP_PRINT_STATS("\t\tmpdu drop : %llu", stats.mpdu_drop_cnt); 627 DP_PRINT_STATS("\t\ttlv drop : %llu", stats.tlv_drop_cnt); 628 } 629 630 #ifdef QCA_SUPPORT_LITE_MONITOR 631 static void dp_lite_mon_free_tx_peers(struct dp_pdev *pdev) 632 { 633 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 634 struct dp_mon_pdev_be *mon_pdev_be = 635 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 636 struct dp_lite_mon_tx_config *lite_mon_tx_config; 637 638 lite_mon_tx_config = mon_pdev_be->lite_mon_tx_config; 639 qdf_spin_lock_bh(&lite_mon_tx_config->lite_mon_tx_lock); 640 dp_lite_mon_free_peers(pdev, &lite_mon_tx_config->tx_config); 641 qdf_spin_unlock_bh(&lite_mon_tx_config->lite_mon_tx_lock); 642 } 643 #else 644 static void dp_lite_mon_free_tx_peers(struct dp_pdev *pdev) 645 { 646 } 647 #endif 648 649 /* 650 * dp_config_enh_tx_monitor_2_0()- API to enable/disable enhanced tx capture 651 * @pdev_handle: DP_PDEV handle 652 * @val: user provided value 653 * 654 * Return: QDF_STATUS 655 */ 656 QDF_STATUS 657 dp_config_enh_tx_monitor_2_0(struct dp_pdev *pdev, uint8_t val) 658 { 659 struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx; 660 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 661 struct dp_mon_pdev_be *mon_pdev_be = 662 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 663 struct dp_pdev_tx_monitor_be *tx_mon_be = 664 &mon_pdev_be->tx_monitor_be; 665 struct dp_soc *soc = pdev->soc; 666 uint16_t num_of_buffers; 667 QDF_STATUS status; 668 669 soc_cfg_ctx = soc->wlan_cfg_ctx; 670 switch (val) { 671 case TX_MON_BE_DISABLE: 672 { 673 tx_mon_be->mode = TX_MON_BE_DISABLE; 674 mon_pdev_be->tx_mon_mode = 0; 675 mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_64B; 676 /* Free any peers that were added for tx peer filtering */ 677 dp_lite_mon_free_tx_peers(pdev); 678 break; 679 } 680 case TX_MON_BE_FULL_CAPTURE: 681 { 682 num_of_buffers = wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc_cfg_ctx); 683 status = dp_vdev_set_monitor_mode_buf_rings_tx_2_0(pdev, 684 num_of_buffers); 685 if (status != QDF_STATUS_SUCCESS) { 686 dp_mon_err("Tx monitor buffer allocation failed"); 687 return status; 688 } 689 qdf_mem_zero(&tx_mon_be->stats, 690 sizeof(struct dp_tx_monitor_drop_stats)); 691 tx_mon_be->last_tsft = 0; 692 tx_mon_be->last_ppdu_timestamp = 0; 693 tx_mon_be->mode = TX_MON_BE_FULL_CAPTURE; 694 mon_pdev_be->tx_mon_mode = 1; 695 mon_pdev_be->tx_mon_filter_length = DEFAULT_DMA_LENGTH; 696 break; 697 } 698 case TX_MON_BE_PEER_FILTER: 699 { 700 status = dp_vdev_set_monitor_mode_buf_rings_tx_2_0(pdev, 701 DP_MON_RING_FILL_LEVEL_DEFAULT); 702 if (status != QDF_STATUS_SUCCESS) { 703 dp_mon_err("Tx monitor buffer allocation failed"); 704 return status; 705 } 706 tx_mon_be->mode = TX_MON_BE_PEER_FILTER; 707 mon_pdev_be->tx_mon_mode = 2; 708 mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_256B; 709 break; 710 } 711 default: 712 { 713 return QDF_STATUS_E_INVAL; 714 } 715 } 716 717 dp_mon_info("Tx monitor mode:%d mon_mode_flag:%d config_length:%d", 718 tx_mon_be->mode, mon_pdev_be->tx_mon_mode, 719 mon_pdev_be->tx_mon_filter_length); 720 721 dp_mon_filter_setup_tx_mon_mode(pdev); 722 dp_tx_mon_filter_update(pdev); 723 724 return QDF_STATUS_SUCCESS; 725 } 726 727 /* 728 * dp_peer_set_tx_capture_enabled_2_0() - add tx monitor peer filter 729 * @pdev: Datapath PDEV handle 730 * @peer: Datapath PEER handle 731 * @is_tx_pkt_cap_enable: flag for tx capture enable/disable 732 * @peer_mac: peer mac address 733 * 734 * Return: status 735 */ 736 QDF_STATUS dp_peer_set_tx_capture_enabled_2_0(struct dp_pdev *pdev_handle, 737 struct dp_peer *peer_handle, 738 uint8_t is_tx_pkt_cap_enable, 739 uint8_t *peer_mac) 740 { 741 return QDF_STATUS_SUCCESS; 742 } 743 744 #ifdef QCA_SUPPORT_LITE_MONITOR 745 static void dp_fill_lite_mon_vdev(struct cdp_tx_indication_info *tx_cap_info, 746 struct dp_mon_pdev_be *mon_pdev_be) 747 { 748 struct dp_lite_mon_config *config; 749 struct dp_vdev *lite_mon_vdev; 750 751 config = &mon_pdev_be->lite_mon_tx_config->tx_config; 752 lite_mon_vdev = config->lite_mon_vdev; 753 754 if (lite_mon_vdev) 755 tx_cap_info->osif_vdev = lite_mon_vdev->osif_vdev; 756 } 757 758 /** 759 * dp_lite_mon_filter_ppdu() - Filter frames at ppdu level 760 * @mpdu_count: mpdu count in the nbuf queue 761 * @level: Lite monitor filter level 762 * 763 * Return: QDF_STATUS 764 */ 765 static inline QDF_STATUS 766 dp_lite_mon_filter_ppdu(uint8_t mpdu_count, uint8_t level) 767 { 768 if (level == CDP_LITE_MON_LEVEL_PPDU && mpdu_count > 1) 769 return QDF_STATUS_E_CANCELED; 770 771 return QDF_STATUS_SUCCESS; 772 } 773 774 /** 775 * dp_lite_mon_filter_peer() - filter frames with peer 776 * @config: Lite monitor configuration 777 * @wh: Pointer to ieee80211_frame 778 * 779 * Return: QDF_STATUS 780 */ 781 static inline QDF_STATUS 782 dp_lite_mon_filter_peer(struct dp_lite_mon_tx_config *config, 783 struct ieee80211_frame_min_one *wh) 784 { 785 struct dp_lite_mon_peer *peer; 786 787 /* Return here if sw peer filtering is not required or if peer count 788 * is zero 789 */ 790 if (!config->sw_peer_filtering || !config->tx_config.peer_count) 791 return QDF_STATUS_SUCCESS; 792 793 TAILQ_FOREACH(peer, &config->tx_config.peer_list, peer_list_elem) { 794 if (!qdf_mem_cmp(&peer->peer_mac.raw[0], 795 &wh->i_addr1[0], QDF_MAC_ADDR_SIZE)) { 796 return QDF_STATUS_SUCCESS; 797 } 798 } 799 800 return QDF_STATUS_E_ABORTED; 801 } 802 803 /** 804 * dp_lite_mon_filter_subtype() - filter frames with subtype 805 * @config: Lite monitor configuration 806 * @wh: Pointer to ieee80211_frame 807 * 808 * Return: QDF_STATUS 809 */ 810 static inline QDF_STATUS 811 dp_lite_mon_filter_subtype(struct dp_lite_mon_tx_config *config, 812 struct ieee80211_frame_min_one *wh) 813 { 814 uint16_t mgmt_filter, ctrl_filter, data_filter, type, subtype; 815 uint8_t is_mcast = 0; 816 817 /* Return here if subtype filtering is not required */ 818 if (!config->subtype_filtering) 819 return QDF_STATUS_SUCCESS; 820 821 mgmt_filter = config->tx_config.mgmt_filter[DP_MON_FRM_FILTER_MODE_FP]; 822 ctrl_filter = config->tx_config.ctrl_filter[DP_MON_FRM_FILTER_MODE_FP]; 823 data_filter = config->tx_config.data_filter[DP_MON_FRM_FILTER_MODE_FP]; 824 825 type = (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 826 subtype = ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >> 827 IEEE80211_FC0_SUBTYPE_SHIFT); 828 829 switch (type) { 830 case QDF_IEEE80211_FC0_TYPE_MGT: 831 if (mgmt_filter >> subtype & 0x1) 832 return QDF_STATUS_SUCCESS; 833 else 834 return QDF_STATUS_E_ABORTED; 835 case QDF_IEEE80211_FC0_TYPE_CTL: 836 if (ctrl_filter >> subtype & 0x1) 837 return QDF_STATUS_SUCCESS; 838 else 839 return QDF_STATUS_E_ABORTED; 840 case QDF_IEEE80211_FC0_TYPE_DATA: 841 is_mcast = DP_FRAME_IS_MULTICAST(wh->i_addr1); 842 if ((is_mcast && (data_filter & FILTER_DATA_MCAST)) || 843 (!is_mcast && (data_filter & FILTER_DATA_UCAST))) 844 return QDF_STATUS_SUCCESS; 845 return QDF_STATUS_E_ABORTED; 846 default: 847 return QDF_STATUS_E_INVAL; 848 } 849 } 850 851 /** 852 * dp_lite_mon_filter_peer_subtype() - filter frames with subtype and peer 853 * @config: Lite monitor configuration 854 * @buf: Pointer to nbuf 855 * 856 * Return: QDF_STATUS 857 */ 858 static inline QDF_STATUS 859 dp_lite_mon_filter_peer_subtype(struct dp_lite_mon_tx_config *config, 860 qdf_nbuf_t buf) 861 { 862 struct ieee80211_frame_min_one *wh; 863 qdf_nbuf_t nbuf; 864 QDF_STATUS ret; 865 866 /* Return here if subtype and peer filtering is not required */ 867 if (!config->subtype_filtering && !config->sw_peer_filtering && 868 !config->tx_config.peer_count) 869 return QDF_STATUS_SUCCESS; 870 871 if (dp_tx_mon_nbuf_get_num_frag(buf)) { 872 wh = (struct ieee80211_frame_min_one *)qdf_nbuf_get_frag_addr(buf, 0); 873 } else { 874 nbuf = qdf_nbuf_get_ext_list(buf); 875 if (nbuf) 876 wh = (struct ieee80211_frame_min_one *)qdf_nbuf_data(nbuf); 877 else 878 return QDF_STATUS_E_INVAL; 879 } 880 881 ret = dp_lite_mon_filter_subtype(config, wh); 882 if (ret) 883 return ret; 884 885 ret = dp_lite_mon_filter_peer(config, wh); 886 if (ret) 887 return ret; 888 889 return QDF_STATUS_SUCCESS; 890 } 891 892 /** 893 * dp_tx_lite_mon_filtering() - Additional filtering for lite monitor 894 * @pdev: Pointer to physical device 895 * @tx_ppdu_info: pointer to dp_tx_ppdu_info structure 896 * @buf: qdf nbuf structure of buffer 897 * @mpdu_count: mpdu count in the nbuf queue 898 * 899 * Return: QDF_STATUS 900 */ 901 static inline QDF_STATUS 902 dp_tx_lite_mon_filtering(struct dp_pdev *pdev, 903 struct dp_tx_ppdu_info *tx_ppdu_info, 904 qdf_nbuf_t buf, int mpdu_count) 905 { 906 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 907 struct dp_mon_pdev_be *mon_pdev_be = 908 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 909 struct dp_lite_mon_tx_config *config = 910 mon_pdev_be->lite_mon_tx_config; 911 QDF_STATUS ret; 912 913 if (!dp_lite_mon_is_tx_enabled(mon_pdev) && 914 !config->tx_config.peer_count) 915 return QDF_STATUS_SUCCESS; 916 917 /* PPDU level filtering */ 918 ret = dp_lite_mon_filter_ppdu(mpdu_count, config->tx_config.level); 919 if (ret) 920 return ret; 921 922 /* Subtype and peer filtering */ 923 ret = dp_lite_mon_filter_peer_subtype(config, buf); 924 if (ret) 925 return ret; 926 927 return QDF_STATUS_SUCCESS; 928 } 929 930 #else 931 static void dp_fill_lite_mon_vdev(struct cdp_tx_indication_info *tx_cap_info, 932 struct dp_mon_pdev_be *mon_pdev_be) 933 { 934 } 935 936 /** 937 * dp_tx_lite_mon_filtering() - Additional filtering for lite monitor 938 * @pdev: Pointer to physical device 939 * @tx_ppdu_info: pointer to dp_tx_ppdu_info structure 940 * @buf: qdf nbuf structure of buffer 941 * @mpdu_count: mpdu count in the nbuf queue 942 * 943 * Return: QDF_STATUS 944 */ 945 static inline QDF_STATUS 946 dp_tx_lite_mon_filtering(struct dp_pdev *pdev, 947 struct dp_tx_ppdu_info *tx_ppdu_info, 948 qdf_nbuf_t buf, int mpdu_count) 949 { 950 return QDF_STATUS_SUCCESS; 951 } 952 #endif 953 954 #ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE 955 /** 956 * dp_tx_mon_lpc_type_filtering() - Additional filtering for lpc 957 * @pdev: Pointer to physical device 958 * @tx_ppdu_info: pointer to dp_tx_ppdu_info structure 959 * @buf: qdf nbuf structure of buffer 960 * 961 * Return: QDF_STATUS 962 */ 963 static inline QDF_STATUS 964 dp_tx_mon_lpc_type_filtering(struct dp_pdev *pdev, 965 struct dp_tx_ppdu_info *tx_ppdu_info, 966 qdf_nbuf_t buf) 967 { 968 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 969 qdf_nbuf_t nbuf; 970 struct ieee80211_frame_min_one *wh; 971 uint16_t mgmt_filter, ctrl_filter, data_filter, type; 972 973 if (qdf_unlikely(!IS_LOCAL_PKT_CAPTURE_RUNNING(mon_pdev, 974 is_local_pkt_capture_running))) 975 return QDF_STATUS_E_ABORTED; 976 977 if (dp_tx_mon_nbuf_get_num_frag(buf)) { 978 wh = (struct ieee80211_frame_min_one *)qdf_nbuf_get_frag_addr(buf, 0); 979 } else { 980 nbuf = qdf_nbuf_get_ext_list(buf); 981 if (nbuf) 982 wh = (struct ieee80211_frame_min_one *)qdf_nbuf_data(nbuf); 983 else 984 return QDF_STATUS_E_ABORTED; 985 } 986 987 mgmt_filter = mon_pdev->fp_mgmt_filter; 988 ctrl_filter = mon_pdev->fp_ctrl_filter; 989 data_filter = mon_pdev->fp_data_filter; 990 991 type = (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 992 993 switch (type) { 994 case QDF_IEEE80211_FC0_TYPE_MGT: 995 return mgmt_filter ? QDF_STATUS_SUCCESS : QDF_STATUS_E_ABORTED; 996 case QDF_IEEE80211_FC0_TYPE_CTL: 997 return ctrl_filter ? QDF_STATUS_SUCCESS : QDF_STATUS_E_ABORTED; 998 case QDF_IEEE80211_FC0_TYPE_DATA: 999 return data_filter ? QDF_STATUS_SUCCESS : QDF_STATUS_E_ABORTED; 1000 default: 1001 return QDF_STATUS_E_ABORTED; 1002 } 1003 1004 return QDF_STATUS_SUCCESS; 1005 } 1006 1007 static int 1008 dp_tx_handle_local_pkt_capture(struct dp_pdev *pdev, qdf_nbuf_t nbuf) 1009 { 1010 struct dp_mon_vdev *mon_vdev; 1011 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 1012 1013 if (!mon_pdev->mvdev) { 1014 dp_mon_err("Monitor vdev is NULL !!"); 1015 return 1; 1016 } 1017 1018 mon_vdev = mon_pdev->mvdev->monitor_vdev; 1019 1020 if (mon_vdev && mon_vdev->osif_rx_mon) 1021 mon_vdev->osif_rx_mon(mon_pdev->mvdev->osif_vdev, nbuf, NULL); 1022 1023 return 0; 1024 } 1025 #else 1026 static int 1027 dp_tx_handle_local_pkt_capture(struct dp_pdev *pdev, qdf_nbuf_t nbuf) 1028 { 1029 return 0; 1030 } 1031 1032 static inline QDF_STATUS 1033 dp_tx_mon_lpc_type_filtering(struct dp_pdev *pdev, 1034 struct dp_tx_ppdu_info *tx_ppdu_info, 1035 qdf_nbuf_t buf) 1036 { 1037 return QDF_STATUS_SUCCESS; 1038 } 1039 1040 #endif 1041 1042 /** 1043 * dp_tx_mon_send_to_stack() - API to send to stack 1044 * @pdev: pdev Handle 1045 * @mpdu: pointer to mpdu 1046 * @num_frag: number of frag in mpdu 1047 * @ppdu_id: ppdu id of the mpdu 1048 * 1049 * Return: void 1050 */ 1051 static void 1052 dp_tx_mon_send_to_stack(struct dp_pdev *pdev, qdf_nbuf_t mpdu, 1053 uint32_t num_frag, uint32_t ppdu_id) 1054 { 1055 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 1056 struct dp_mon_pdev_be *mon_pdev_be = 1057 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 1058 struct dp_pdev_tx_monitor_be *tx_mon_be = 1059 &mon_pdev_be->tx_monitor_be; 1060 struct cdp_tx_indication_info tx_capture_info = {0}; 1061 1062 tx_mon_be->stats.pkt_buf_to_stack += num_frag; 1063 1064 tx_capture_info.radiotap_done = 1; 1065 tx_capture_info.mpdu_nbuf = mpdu; 1066 tx_capture_info.mpdu_info.ppdu_id = ppdu_id; 1067 1068 if (qdf_unlikely(IS_LOCAL_PKT_CAPTURE_RUNNING(mon_pdev, 1069 is_local_pkt_capture_running))) { 1070 int ret = dp_tx_handle_local_pkt_capture(pdev, mpdu); 1071 1072 /* 1073 * On error, free the memory here, 1074 * otherwise it will be freed by the network stack 1075 */ 1076 if (ret) 1077 qdf_nbuf_free(mpdu); 1078 return; 1079 } else if (!dp_lite_mon_is_tx_enabled(mon_pdev)) { 1080 dp_wdi_event_handler(WDI_EVENT_TX_PKT_CAPTURE, 1081 pdev->soc, 1082 &tx_capture_info, 1083 HTT_INVALID_PEER, 1084 WDI_NO_VAL, 1085 pdev->pdev_id); 1086 } else { 1087 dp_fill_lite_mon_vdev(&tx_capture_info, mon_pdev_be); 1088 dp_wdi_event_handler(WDI_EVENT_LITE_MON_TX, 1089 pdev->soc, 1090 &tx_capture_info, 1091 HTT_INVALID_PEER, 1092 WDI_NO_VAL, 1093 pdev->pdev_id); 1094 } 1095 if (tx_capture_info.mpdu_nbuf) 1096 qdf_nbuf_free(tx_capture_info.mpdu_nbuf); 1097 } 1098 1099 /** 1100 * dp_tx_mon_send_per_usr_mpdu() - API to send per usr mpdu to stack 1101 * @pdev: pdev Handle 1102 * @ppdu_info: pointer to dp_tx_ppdu_info 1103 * @user_idx: current user index 1104 * 1105 * Return: void 1106 */ 1107 static void 1108 dp_tx_mon_send_per_usr_mpdu(struct dp_pdev *pdev, 1109 struct dp_tx_ppdu_info *ppdu_info, 1110 uint8_t user_idx) 1111 { 1112 qdf_nbuf_queue_t *usr_mpdu_q = NULL; 1113 qdf_nbuf_t buf = NULL; 1114 uint8_t mpdu_count = 0; 1115 1116 usr_mpdu_q = &TXMON_PPDU_USR(ppdu_info, user_idx, mpdu_q); 1117 1118 while ((buf = qdf_nbuf_queue_remove(usr_mpdu_q)) != NULL) { 1119 uint32_t num_frag = dp_tx_mon_nbuf_get_num_frag(buf); 1120 1121 ppdu_info->hal_txmon.rx_status.rx_user_status = 1122 &ppdu_info->hal_txmon.rx_user_status[user_idx]; 1123 1124 if (dp_tx_lite_mon_filtering(pdev, ppdu_info, buf, 1125 ++mpdu_count) || 1126 dp_tx_mon_lpc_type_filtering(pdev, ppdu_info, buf)) { 1127 qdf_nbuf_free(buf); 1128 continue; 1129 } 1130 1131 qdf_nbuf_update_radiotap(&ppdu_info->hal_txmon.rx_status, 1132 buf, qdf_nbuf_headroom(buf)); 1133 1134 dp_tx_mon_send_to_stack(pdev, buf, num_frag, 1135 TXMON_PPDU(ppdu_info, ppdu_id)); 1136 } 1137 } 1138 1139 #define PHY_MEDIUM_MHZ 960 1140 #define PHY_TIMESTAMP_WRAP (0xFFFFFFFF / PHY_MEDIUM_MHZ) 1141 1142 /** 1143 * dp_populate_tsft_from_phy_timestamp() - API to get tsft from phy timestamp 1144 * @pdev: pdev Handle 1145 * @ppdu_info: ppdi_info Handle 1146 * 1147 * Return: QDF_STATUS 1148 */ 1149 static QDF_STATUS 1150 dp_populate_tsft_from_phy_timestamp(struct dp_pdev *pdev, 1151 struct dp_tx_ppdu_info *ppdu_info) 1152 { 1153 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 1154 struct dp_mon_pdev_be *mon_pdev_be = 1155 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 1156 struct dp_pdev_tx_monitor_be *tx_mon_be = 1157 &mon_pdev_be->tx_monitor_be; 1158 uint64_t tsft = 0; 1159 uint32_t ppdu_timestamp = 0; 1160 1161 tsft = TXMON_PPDU_COM(ppdu_info, tsft); 1162 ppdu_timestamp = TXMON_PPDU_COM(ppdu_info, ppdu_timestamp); 1163 1164 if (tsft && ppdu_timestamp) { 1165 /* update tsft and ppdu timestamp */ 1166 tx_mon_be->last_tsft = tsft; 1167 tx_mon_be->last_ppdu_timestamp = ppdu_timestamp; 1168 } else if (!tx_mon_be->last_ppdu_timestamp || !tx_mon_be->last_tsft) { 1169 return QDF_STATUS_E_EMPTY; 1170 } 1171 1172 if (!tsft && ppdu_timestamp) { 1173 /* response window */ 1174 uint32_t cur_usec = ppdu_timestamp / PHY_MEDIUM_MHZ; 1175 uint32_t last_usec = (tx_mon_be->last_ppdu_timestamp / 1176 PHY_MEDIUM_MHZ); 1177 uint32_t diff = 0; 1178 1179 if (last_usec < cur_usec) { 1180 diff = cur_usec - last_usec; 1181 tsft = tx_mon_be->last_tsft + diff; 1182 } else { 1183 diff = (PHY_TIMESTAMP_WRAP - last_usec) + cur_usec; 1184 tsft = tx_mon_be->last_tsft + diff; 1185 } 1186 TXMON_PPDU_COM(ppdu_info, tsft) = tsft; 1187 /* update tsft and ppdu timestamp */ 1188 tx_mon_be->last_tsft = tsft; 1189 tx_mon_be->last_ppdu_timestamp = ppdu_timestamp; 1190 } 1191 1192 if (!TXMON_PPDU_COM(ppdu_info, tsft) && 1193 !TXMON_PPDU_COM(ppdu_info, ppdu_timestamp)) 1194 return QDF_STATUS_E_EMPTY; 1195 1196 return QDF_STATUS_SUCCESS; 1197 } 1198 1199 /** 1200 * dp_tx_mon_update_channel_freq() - API to update channel frequency and number 1201 * @pdev: pdev Handle 1202 * @soc: soc Handle 1203 * @freq: Frequency 1204 * 1205 * Return: void 1206 */ 1207 static inline void 1208 dp_tx_mon_update_channel_freq(struct dp_pdev *pdev, struct dp_soc *soc, 1209 uint16_t freq) 1210 { 1211 if (soc && soc->cdp_soc.ol_ops->freq_to_channel) { 1212 uint8_t c_num; 1213 1214 c_num = soc->cdp_soc.ol_ops->freq_to_channel(soc->ctrl_psoc, 1215 pdev->pdev_id, 1216 freq); 1217 pdev->operating_channel.num = c_num; 1218 } 1219 1220 if (soc && soc->cdp_soc.ol_ops->freq_to_band) { 1221 uint8_t band; 1222 1223 band = soc->cdp_soc.ol_ops->freq_to_band(soc->ctrl_psoc, 1224 pdev->pdev_id, 1225 freq); 1226 pdev->operating_channel.band = band; 1227 } 1228 } 1229 1230 /** 1231 * dp_tx_mon_update_radiotap() - API to update radiotap information 1232 * @pdev: pdev Handle 1233 * @ppdu_info: pointer to dp_tx_ppdu_info 1234 * 1235 * Return: void 1236 */ 1237 static void 1238 dp_tx_mon_update_radiotap(struct dp_pdev *pdev, 1239 struct dp_tx_ppdu_info *ppdu_info) 1240 { 1241 uint32_t usr_idx = 0; 1242 uint32_t num_users = 0; 1243 1244 num_users = TXMON_PPDU_HAL(ppdu_info, num_users); 1245 1246 if (qdf_unlikely(TXMON_PPDU_COM(ppdu_info, chan_freq) == 0 && 1247 TXMON_PPDU_COM(ppdu_info, chan_num) == 0)) { 1248 TXMON_PPDU_COM(ppdu_info, chan_freq) = 1249 pdev->operating_channel.freq; 1250 TXMON_PPDU_COM(ppdu_info, chan_num) = 1251 pdev->operating_channel.num; 1252 } else if (TXMON_PPDU_COM(ppdu_info, chan_freq) != 0 && 1253 TXMON_PPDU_COM(ppdu_info, chan_num) == 0) { 1254 uint16_t freq = TXMON_PPDU_COM(ppdu_info, chan_freq); 1255 1256 if (qdf_unlikely(pdev->operating_channel.freq != freq)) { 1257 dp_tx_mon_update_channel_freq(pdev, pdev->soc, freq); 1258 pdev->operating_channel.freq = freq; 1259 } 1260 TXMON_PPDU_COM(ppdu_info, 1261 chan_num) = pdev->operating_channel.num; 1262 } 1263 1264 if (QDF_STATUS_SUCCESS != 1265 dp_populate_tsft_from_phy_timestamp(pdev, ppdu_info)) 1266 return; 1267 1268 /* update mlo timestamp */ 1269 TXMON_PPDU_COM(ppdu_info, tsft) = 1270 (TXMON_PPDU_COM(ppdu_info, tsft) + 1271 pdev->timestamp.mlo_offset_lo_us + 1272 ((uint64_t)pdev->timestamp.mlo_offset_hi_us << 32)); 1273 1274 for (usr_idx = 0; usr_idx < num_users; usr_idx++) { 1275 qdf_nbuf_queue_t *mpdu_q = NULL; 1276 1277 /* set AMPDU flag if number mpdu is more than 1 */ 1278 mpdu_q = &TXMON_PPDU_USR(ppdu_info, usr_idx, mpdu_q); 1279 if (mpdu_q && (qdf_nbuf_queue_len(mpdu_q) > 1)) { 1280 TXMON_PPDU_COM(ppdu_info, 1281 rs_flags) |= IEEE80211_AMPDU_FLAG; 1282 TXMON_PPDU_USR(ppdu_info, usr_idx, is_ampdu) = 1; 1283 } 1284 1285 if (qdf_unlikely(!TXMON_PPDU_COM(ppdu_info, rate))) { 1286 uint32_t rate = 0; 1287 uint32_t rix = 0; 1288 uint16_t ratecode = 0; 1289 1290 rate = dp_getrateindex(TXMON_PPDU_COM(ppdu_info, sgi), 1291 TXMON_PPDU_USR(ppdu_info, 1292 usr_idx, mcs), 1293 TXMON_PPDU_COM(ppdu_info, nss), 1294 TXMON_PPDU_COM(ppdu_info, 1295 preamble_type), 1296 TXMON_PPDU_COM(ppdu_info, bw), 1297 0, 1298 &rix, &ratecode); 1299 1300 /* update rate */ 1301 TXMON_PPDU_COM(ppdu_info, rate) = rate; 1302 } 1303 1304 dp_tx_mon_send_per_usr_mpdu(pdev, ppdu_info, usr_idx); 1305 } 1306 } 1307 1308 /** 1309 * dp_tx_mon_ppdu_process - Deferred PPDU stats handler 1310 * @context: Opaque work context (PDEV) 1311 * 1312 * Return: none 1313 */ 1314 static void dp_tx_mon_ppdu_process(void *context) 1315 { 1316 struct dp_pdev *pdev = (struct dp_pdev *)context; 1317 struct dp_mon_pdev *mon_pdev; 1318 struct dp_mon_pdev_be *mon_pdev_be; 1319 struct dp_tx_ppdu_info *defer_ppdu_info = NULL; 1320 struct dp_tx_ppdu_info *defer_ppdu_info_next = NULL; 1321 struct dp_pdev_tx_monitor_be *tx_mon_be; 1322 1323 /* sanity check */ 1324 if (qdf_unlikely(!pdev)) 1325 return; 1326 1327 mon_pdev = pdev->monitor_pdev; 1328 1329 if (qdf_unlikely(!mon_pdev)) 1330 return; 1331 1332 mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 1333 if (qdf_unlikely(!mon_pdev_be)) 1334 return; 1335 1336 tx_mon_be = &mon_pdev_be->tx_monitor_be; 1337 if (qdf_unlikely(TX_MON_BE_DISABLE == tx_mon_be->mode && 1338 !dp_lite_mon_is_tx_enabled(mon_pdev))) 1339 return; 1340 1341 /* take lock here */ 1342 qdf_spin_lock_bh(&tx_mon_be->tx_mon_list_lock); 1343 STAILQ_CONCAT(&tx_mon_be->defer_tx_ppdu_info_queue, 1344 &tx_mon_be->tx_ppdu_info_queue); 1345 tx_mon_be->defer_ppdu_info_list_depth += 1346 tx_mon_be->tx_ppdu_info_list_depth; 1347 tx_mon_be->tx_ppdu_info_list_depth = 0; 1348 qdf_spin_unlock_bh(&tx_mon_be->tx_mon_list_lock); 1349 1350 STAILQ_FOREACH_SAFE(defer_ppdu_info, 1351 &tx_mon_be->defer_tx_ppdu_info_queue, 1352 tx_ppdu_info_queue_elem, defer_ppdu_info_next) { 1353 /* remove dp_tx_ppdu_info from the list */ 1354 STAILQ_REMOVE(&tx_mon_be->defer_tx_ppdu_info_queue, 1355 defer_ppdu_info, 1356 dp_tx_ppdu_info, 1357 tx_ppdu_info_queue_elem); 1358 tx_mon_be->defer_ppdu_info_list_depth--; 1359 1360 dp_tx_mon_update_radiotap(pdev, defer_ppdu_info); 1361 1362 /* free the ppdu_info */ 1363 dp_tx_mon_free_ppdu_info(defer_ppdu_info, tx_mon_be); 1364 defer_ppdu_info = NULL; 1365 } 1366 } 1367 1368 void dp_tx_ppdu_stats_attach_2_0(struct dp_pdev *pdev) 1369 { 1370 struct dp_mon_pdev *mon_pdev; 1371 struct dp_mon_pdev_be *mon_pdev_be; 1372 struct dp_pdev_tx_monitor_be *tx_mon_be; 1373 1374 if (qdf_unlikely(!pdev)) 1375 return; 1376 1377 mon_pdev = pdev->monitor_pdev; 1378 1379 if (qdf_unlikely(!mon_pdev)) 1380 return; 1381 1382 mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 1383 if (qdf_unlikely(!mon_pdev_be)) 1384 return; 1385 1386 tx_mon_be = &mon_pdev_be->tx_monitor_be; 1387 1388 STAILQ_INIT(&tx_mon_be->tx_ppdu_info_queue); 1389 tx_mon_be->tx_ppdu_info_list_depth = 0; 1390 1391 STAILQ_INIT(&tx_mon_be->defer_tx_ppdu_info_queue); 1392 tx_mon_be->defer_ppdu_info_list_depth = 0; 1393 1394 qdf_spinlock_create(&tx_mon_be->tx_mon_list_lock); 1395 /* Work queue setup for TX MONITOR post handling */ 1396 qdf_create_work(0, &tx_mon_be->post_ppdu_work, 1397 dp_tx_mon_ppdu_process, pdev); 1398 1399 tx_mon_be->post_ppdu_workqueue = 1400 qdf_alloc_unbound_workqueue("tx_mon_ppdu_work_queue"); 1401 } 1402 1403 void dp_tx_ppdu_stats_detach_2_0(struct dp_pdev *pdev) 1404 { 1405 struct dp_mon_pdev *mon_pdev; 1406 struct dp_mon_pdev_be *mon_pdev_be; 1407 struct dp_pdev_tx_monitor_be *tx_mon_be; 1408 struct dp_tx_ppdu_info *tx_ppdu_info = NULL; 1409 struct dp_tx_ppdu_info *tx_ppdu_info_next = NULL; 1410 1411 if (qdf_unlikely(!pdev)) 1412 return; 1413 1414 mon_pdev = pdev->monitor_pdev; 1415 1416 if (qdf_unlikely(!mon_pdev)) 1417 return; 1418 1419 mon_pdev_be = dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 1420 if (qdf_unlikely(!mon_pdev_be)) 1421 return; 1422 1423 tx_mon_be = &mon_pdev_be->tx_monitor_be; 1424 /* TODO: disable tx_monitor, to avoid further packet from HW */ 1425 dp_monitor_config_enh_tx_capture(pdev, TX_MON_BE_DISABLE); 1426 1427 /* flush workqueue */ 1428 qdf_flush_workqueue(0, tx_mon_be->post_ppdu_workqueue); 1429 qdf_destroy_workqueue(0, tx_mon_be->post_ppdu_workqueue); 1430 1431 /* 1432 * TODO: iterate both tx_ppdu_info and defer_ppdu_info_list 1433 * free the tx_ppdu_info and decrement depth 1434 */ 1435 qdf_spin_lock_bh(&tx_mon_be->tx_mon_list_lock); 1436 STAILQ_FOREACH_SAFE(tx_ppdu_info, 1437 &tx_mon_be->tx_ppdu_info_queue, 1438 tx_ppdu_info_queue_elem, tx_ppdu_info_next) { 1439 /* remove dp_tx_ppdu_info from the list */ 1440 STAILQ_REMOVE(&tx_mon_be->tx_ppdu_info_queue, tx_ppdu_info, 1441 dp_tx_ppdu_info, tx_ppdu_info_queue_elem); 1442 /* decrement list length */ 1443 tx_mon_be->tx_ppdu_info_list_depth--; 1444 /* free tx_ppdu_info */ 1445 dp_tx_mon_free_ppdu_info(tx_ppdu_info, tx_mon_be); 1446 } 1447 qdf_spin_unlock_bh(&tx_mon_be->tx_mon_list_lock); 1448 1449 qdf_spin_lock_bh(&tx_mon_be->tx_mon_list_lock); 1450 STAILQ_FOREACH_SAFE(tx_ppdu_info, 1451 &tx_mon_be->defer_tx_ppdu_info_queue, 1452 tx_ppdu_info_queue_elem, tx_ppdu_info_next) { 1453 /* remove dp_tx_ppdu_info from the list */ 1454 STAILQ_REMOVE(&tx_mon_be->defer_tx_ppdu_info_queue, 1455 tx_ppdu_info, 1456 dp_tx_ppdu_info, tx_ppdu_info_queue_elem); 1457 /* decrement list length */ 1458 tx_mon_be->defer_ppdu_info_list_depth--; 1459 /* free tx_ppdu_info */ 1460 dp_tx_mon_free_ppdu_info(tx_ppdu_info, tx_mon_be); 1461 } 1462 qdf_spin_unlock_bh(&tx_mon_be->tx_mon_list_lock); 1463 1464 qdf_spinlock_destroy(&tx_mon_be->tx_mon_list_lock); 1465 } 1466 #endif /* WLAN_TX_PKT_CAPTURE_ENH_BE */ 1467 1468 #if (defined(WIFI_MONITOR_SUPPORT) && defined(WLAN_TX_MON_CORE_DEBUG)) 1469 /* 1470 * dp_config_enh_tx_core_monitor_2_0()- API to validate core framework 1471 * @pdev_handle: DP_PDEV handle 1472 * @val: user provided value 1473 * 1474 * Return: QDF_STATUS 1475 */ 1476 QDF_STATUS 1477 dp_config_enh_tx_core_monitor_2_0(struct dp_pdev *pdev, uint8_t val) 1478 { 1479 struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx; 1480 struct dp_mon_pdev *mon_pdev = pdev->monitor_pdev; 1481 struct dp_mon_pdev_be *mon_pdev_be = 1482 dp_get_be_mon_pdev_from_dp_mon_pdev(mon_pdev); 1483 struct dp_pdev_tx_monitor_be *tx_mon_be = 1484 &mon_pdev_be->tx_monitor_be; 1485 struct dp_soc *soc = pdev->soc; 1486 uint16_t num_of_buffers; 1487 QDF_STATUS status; 1488 1489 soc_cfg_ctx = soc->wlan_cfg_ctx; 1490 switch (val) { 1491 case TX_MON_BE_FRM_WRK_DISABLE: 1492 { 1493 tx_mon_be->mode = val; 1494 mon_pdev_be->tx_mon_mode = 0; 1495 mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_64B; 1496 break; 1497 } 1498 case TX_MON_BE_FRM_WRK_FULL_CAPTURE: 1499 { 1500 num_of_buffers = wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc_cfg_ctx); 1501 status = dp_vdev_set_monitor_mode_buf_rings_tx_2_0(pdev, 1502 num_of_buffers); 1503 if (status != QDF_STATUS_SUCCESS) { 1504 dp_mon_err("Tx monitor buffer allocation failed"); 1505 return status; 1506 } 1507 tx_mon_be->mode = val; 1508 qdf_mem_zero(&tx_mon_be->stats, 1509 sizeof(struct dp_tx_monitor_drop_stats)); 1510 tx_mon_be->mode = val; 1511 mon_pdev_be->tx_mon_mode = 1; 1512 mon_pdev_be->tx_mon_filter_length = DEFAULT_DMA_LENGTH; 1513 break; 1514 } 1515 case TX_MON_BE_FRM_WRK_128B_CAPTURE: 1516 { 1517 status = dp_vdev_set_monitor_mode_buf_rings_tx_2_0(pdev, 1518 DP_MON_RING_FILL_LEVEL_DEFAULT); 1519 if (status != QDF_STATUS_SUCCESS) { 1520 dp_mon_err("Tx monitor buffer allocation failed"); 1521 return status; 1522 } 1523 tx_mon_be->mode = val; 1524 mon_pdev_be->tx_mon_mode = 1; 1525 mon_pdev_be->tx_mon_filter_length = DMA_LENGTH_128B; 1526 break; 1527 } 1528 default: 1529 { 1530 return QDF_STATUS_E_INVAL; 1531 } 1532 } 1533 1534 dp_mon_debug("Tx monitor mode:%d mon_mode_flag:%d config_length:%d", 1535 tx_mon_be->mode, mon_pdev_be->tx_mon_mode, 1536 mon_pdev_be->tx_mon_filter_length); 1537 1538 /* send HTT msg to configure TLV based on mode */ 1539 dp_mon_filter_setup_tx_mon_mode(pdev); 1540 dp_tx_mon_filter_update(pdev); 1541 1542 return QDF_STATUS_SUCCESS; 1543 } 1544 #endif 1545 1546 #ifdef WLAN_PKT_CAPTURE_TX_2_0 1547 QDF_STATUS dp_tx_mon_pdev_htt_srng_setup_2_0(struct dp_soc *soc, 1548 struct dp_pdev *pdev, 1549 int mac_id, 1550 int mac_for_pdev) 1551 { 1552 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1553 struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1554 1555 return htt_srng_setup(soc->htt_handle, mac_for_pdev, 1556 mon_soc_be->tx_mon_dst_ring[mac_id].hal_srng, 1557 TX_MONITOR_DST); 1558 } 1559 1560 QDF_STATUS dp_tx_mon_soc_htt_srng_setup_2_0(struct dp_soc *soc, 1561 int mac_id) 1562 { 1563 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1564 struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1565 1566 hal_set_low_threshold(mon_soc_be->tx_mon_buf_ring.hal_srng, 0); 1567 return htt_srng_setup(soc->htt_handle, mac_id, 1568 mon_soc_be->tx_mon_buf_ring.hal_srng, 1569 TX_MONITOR_BUF); 1570 } 1571 1572 QDF_STATUS dp_tx_mon_pdev_rings_alloc_2_0(struct dp_pdev *pdev, uint32_t lmac_id) 1573 { 1574 struct dp_soc *soc = pdev->soc; 1575 int entries; 1576 struct wlan_cfg_dp_pdev_ctxt *pdev_cfg_ctx; 1577 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1578 struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1579 1580 pdev_cfg_ctx = pdev->wlan_cfg_ctx; 1581 entries = wlan_cfg_get_dma_tx_mon_dest_ring_size(pdev_cfg_ctx); 1582 1583 return dp_srng_alloc(soc, &mon_soc_be->tx_mon_dst_ring[lmac_id], 1584 TX_MONITOR_DST, entries, 0); 1585 } 1586 1587 void dp_tx_mon_pdev_rings_free_2_0(struct dp_pdev *pdev, uint32_t lmac_id) 1588 { 1589 struct dp_soc *soc = pdev->soc; 1590 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1591 struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1592 1593 dp_srng_free(soc, &mon_soc_be->tx_mon_dst_ring[lmac_id]); 1594 } 1595 1596 QDF_STATUS dp_tx_mon_pdev_rings_init_2_0(struct dp_pdev *pdev, uint32_t lmac_id) 1597 { 1598 struct dp_soc *soc = pdev->soc; 1599 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1600 struct dp_mon_soc_be *mon_soc_be = dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1601 1602 return dp_srng_init(soc, &mon_soc_be->tx_mon_dst_ring[lmac_id], 1603 TX_MONITOR_DST, pdev->pdev_id, lmac_id); 1604 } 1605 1606 void dp_tx_mon_pdev_rings_deinit_2_0(struct dp_pdev *pdev, uint32_t lmac_id) 1607 { 1608 struct dp_soc *soc = pdev->soc; 1609 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1610 struct dp_mon_soc_be *mon_soc_be = 1611 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1612 1613 dp_srng_deinit(soc, &mon_soc_be->tx_mon_dst_ring[lmac_id], 1614 TX_MONITOR_DST, pdev->pdev_id); 1615 } 1616 1617 QDF_STATUS dp_tx_mon_soc_attach_2_0(struct dp_soc *soc, uint32_t lmac_id) 1618 { 1619 int entries; 1620 struct wlan_cfg_dp_soc_ctxt *soc_cfg_ctx = soc->wlan_cfg_ctx; 1621 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1622 struct dp_mon_soc_be *mon_soc_be = 1623 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1624 1625 entries = wlan_cfg_get_dp_soc_tx_mon_buf_ring_size(soc_cfg_ctx); 1626 qdf_print("%s:%d tx mon buf entries: %d", __func__, __LINE__, entries); 1627 1628 return dp_srng_alloc(soc, &mon_soc_be->tx_mon_buf_ring, 1629 TX_MONITOR_BUF, entries, 0); 1630 } 1631 1632 QDF_STATUS dp_tx_mon_soc_detach_2_0(struct dp_soc *soc, uint32_t lmac_id) 1633 { 1634 struct dp_mon_soc *mon_soc = soc->monitor_soc; 1635 struct dp_mon_soc_be *mon_soc_be = 1636 dp_get_be_mon_soc_from_dp_mon_soc(mon_soc); 1637 1638 if (!mon_soc_be) { 1639 dp_mon_err("DP MON SOC NULL"); 1640 return QDF_STATUS_E_FAILURE; 1641 } 1642 1643 dp_tx_mon_buf_desc_pool_free(soc); 1644 dp_srng_free(soc, &mon_soc_be->tx_mon_buf_ring); 1645 return QDF_STATUS_SUCCESS; 1646 } 1647 1648 #endif 1649