From 4dc399fb8b98dfc6281aede1b9da441b1f666465 Mon Sep 17 00:00:00 2001 From: Vevek Venkatesan Date: Fri, 23 Apr 2021 10:37:47 +0530 Subject: [PATCH] qcacmn: add Tx descriptor history in Tx and comp rings Add the history support to log Tx descriptors programmed in Tx and completion HW rings. Change-Id: I60954c93e2595e7dad1251c459eed8afc761e917 CRs-Fixed: 2924614 --- dp/wifi3.0/dp_main.c | 58 +++++++++++++++++ dp/wifi3.0/dp_tx.c | 144 ++++++++++++++++++++++++++++++++++++++++++ dp/wifi3.0/dp_tx.h | 2 + dp/wifi3.0/dp_types.h | 42 ++++++++++++ 4 files changed, 246 insertions(+) diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 66a323bfc2ff..2403837b02a3 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -4298,6 +4298,62 @@ static inline void dp_soc_rx_history_detach(struct dp_soc *soc) } #endif +#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY +/** + * dp_soc_tx_history_attach() - Attach the ring history record buffers + * @soc: DP soc structure + * + * This function allocates the memory for recording the tx tcl ring and + * the tx comp ring entries. There is no error returned in case + * of allocation failure since the record function checks if the history is + * initialized or not. We do not want to fail the driver load in case of + * failure to allocate memory for debug history. + * + * Returns: None + */ +static void dp_soc_tx_history_attach(struct dp_soc *soc) +{ + uint32_t tx_tcl_hist_size; + uint32_t tx_comp_hist_size; + + tx_tcl_hist_size = sizeof(*soc->tx_tcl_history); + soc->tx_tcl_history = dp_context_alloc_mem(soc, DP_TX_TCL_HIST_TYPE, + tx_tcl_hist_size); + if (soc->tx_tcl_history) + qdf_atomic_init(&soc->tx_tcl_history->index); + + tx_comp_hist_size = sizeof(*soc->tx_comp_history); + soc->tx_comp_history = dp_context_alloc_mem(soc, DP_TX_COMP_HIST_TYPE, + tx_comp_hist_size); + if (soc->tx_comp_history) + qdf_atomic_init(&soc->tx_comp_history->index); +} + +/** + * dp_soc_tx_history_detach() - Detach the ring history record buffers + * @soc: DP soc structure + * + * This function frees the memory for recording the tx tcl ring and + * the tx comp ring entries. + * + * Returns: None + */ +static void dp_soc_tx_history_detach(struct dp_soc *soc) +{ + dp_context_free_mem(soc, DP_TX_TCL_HIST_TYPE, soc->tx_tcl_history); + dp_context_free_mem(soc, DP_TX_COMP_HIST_TYPE, soc->tx_comp_history); +} + +#else +static inline void dp_soc_tx_history_attach(struct dp_soc *soc) +{ +} + +static inline void dp_soc_tx_history_detach(struct dp_soc *soc) +{ +} +#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */ + /* * dp_pdev_attach_wifi3() - attach txrx pdev * @txrx_soc: Datapath SOC handle @@ -4863,6 +4919,7 @@ static void dp_soc_detach(struct cdp_soc_t *txrx_soc) dp_hw_link_desc_pool_banks_free(soc, WLAN_INVALID_PDEV_ID); wlan_cfg_soc_detach(soc->wlan_cfg_ctx); dp_soc_tx_hw_desc_history_detach(soc); + dp_soc_tx_history_detach(soc); dp_soc_rx_history_detach(soc); if (soc->mon_vdev_timer_state & MON_VDEV_TIMER_INIT) { qdf_timer_free(&soc->mon_vdev_timer); @@ -12156,6 +12213,7 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc, dp_soc_tx_hw_desc_history_attach(soc); dp_soc_rx_history_attach(soc); + dp_soc_tx_history_attach(soc); wlan_set_srng_cfg(&soc->wlan_srng_cfg); soc->wlan_cfg_ctx = wlan_cfg_soc_attach(soc->ctrl_psoc); if (!soc->wlan_cfg_ctx) { diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 219a52adc5b4..2c4bfadbfd56 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -189,6 +189,124 @@ dp_tx_outstanding_dec(struct dp_pdev *pdev) } #endif //QCA_TX_LIMIT_CHECK +#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY +static inline enum dp_tx_event_type dp_tx_get_event_type(uint32_t flags) +{ + enum dp_tx_event_type type; + + if (flags & DP_TX_DESC_FLAG_FLUSH) + type = DP_TX_DESC_FLUSH; + else if (flags & DP_TX_DESC_FLAG_TX_COMP_ERR) + type = DP_TX_COMP_UNMAP_ERR; + else if (flags & DP_TX_DESC_FLAG_COMPLETED_TX) + type = DP_TX_COMP_UNMAP; + else + type = DP_TX_DESC_UNMAP; + + return type; +} + +static inline void +dp_tx_desc_history_add(struct dp_soc *soc, dma_addr_t paddr, + qdf_nbuf_t skb, uint32_t sw_cookie, + enum dp_tx_event_type type) +{ + struct dp_tx_desc_event *entry; + uint32_t idx; + + if (qdf_unlikely(!soc->tx_tcl_history || !soc->tx_comp_history)) + return; + + switch (type) { + case DP_TX_COMP_UNMAP: + case DP_TX_COMP_UNMAP_ERR: + case DP_TX_COMP_MSDU_EXT: + idx = dp_history_get_next_index(&soc->tx_comp_history->index, + DP_TX_COMP_HISTORY_SIZE); + entry = &soc->tx_comp_history->entry[idx]; + break; + case DP_TX_DESC_MAP: + case DP_TX_DESC_UNMAP: + case DP_TX_DESC_COOKIE: + case DP_TX_DESC_FLUSH: + idx = dp_history_get_next_index(&soc->tx_tcl_history->index, + DP_TX_TCL_HISTORY_SIZE); + entry = &soc->tx_tcl_history->entry[idx]; + break; + default: + dp_info_rl("Invalid dp_tx_event_type: %d", type); + return; + } + + entry->skb = skb; + entry->paddr = paddr; + entry->sw_cookie = sw_cookie; + entry->type = type; + entry->ts = qdf_get_log_timestamp(); +} + +static inline void +dp_tx_tso_seg_history_add(struct dp_soc *soc, + struct qdf_tso_seg_elem_t *tso_seg, + qdf_nbuf_t skb, uint32_t sw_cookie, + enum dp_tx_event_type type) +{ + int i; + + for (i = 1; i < tso_seg->seg.num_frags; i++) { + dp_tx_desc_history_add(soc, tso_seg->seg.tso_frags[i].paddr, + skb, sw_cookie, type); + } + + if (!tso_seg->next) + dp_tx_desc_history_add(soc, tso_seg->seg.tso_frags[0].paddr, + skb, 0xFFFFFFFF, type); +} + +static inline void +dp_tx_tso_history_add(struct dp_soc *soc, struct qdf_tso_info_t tso_info, + qdf_nbuf_t skb, uint32_t sw_cookie, + enum dp_tx_event_type type) +{ + struct qdf_tso_seg_elem_t *curr_seg = tso_info.tso_seg_list; + uint32_t num_segs = tso_info.num_segs; + + while (num_segs) { + dp_tx_tso_seg_history_add(soc, curr_seg, skb, sw_cookie, type); + curr_seg = curr_seg->next; + num_segs--; + } +} + +#else +static inline enum dp_tx_event_type dp_tx_get_event_type(uint32_t flags) +{ + return DP_TX_DESC_INVAL_EVT; +} + +static inline void +dp_tx_desc_history_add(struct dp_soc *soc, dma_addr_t paddr, + qdf_nbuf_t skb, uint32_t sw_cookie, + enum dp_tx_event_type type) +{ +} + +static inline void +dp_tx_tso_seg_history_add(struct dp_soc *soc, + struct qdf_tso_seg_elem_t *tso_seg, + qdf_nbuf_t skb, uint32_t sw_cookie, + enum dp_tx_event_type type) +{ +} + +static inline void +dp_tx_tso_history_add(struct dp_soc *soc, struct qdf_tso_info_t tso_info, + qdf_nbuf_t skb, uint32_t sw_cookie, + enum dp_tx_event_type type) +{ +} +#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */ + #if defined(FEATURE_TSO) /** * dp_tx_tso_unmap_segment() - Unmap TSO segment @@ -666,6 +784,8 @@ static QDF_STATUS dp_tx_prepare_tso(struct dp_vdev *vdev, return QDF_STATUS_E_INVAL; } + dp_tx_tso_history_add(soc, msdu_info->u.tso_info, + msdu, 0, DP_TX_DESC_MAP); tso_info->curr_seg = tso_info->tso_seg_list; @@ -1060,6 +1180,8 @@ static struct dp_tx_desc_s *dp_tx_prepare_desc(struct dp_vdev *vdev, DP_STATS_INC(vdev, tx_i.dropped.desc_na.num, 1); return NULL; } + dp_tx_tso_seg_history_add(soc, msdu_info->u.tso_info.curr_seg, + nbuf, tx_desc->id, DP_TX_DESC_COOKIE); dp_tx_outstanding_inc(pdev); @@ -1505,6 +1627,8 @@ dp_tx_hw_enqueue(struct dp_soc *soc, struct dp_vdev *vdev, tx_desc->pkt_offset; type = HAL_TX_BUF_TYPE_BUFFER; tx_desc->dma_addr = qdf_nbuf_mapped_paddr_get(tx_desc->nbuf); + dp_tx_desc_history_add(soc, tx_desc->dma_addr, tx_desc->nbuf, + tx_desc->id, DP_TX_DESC_MAP); } qdf_assert_always(tx_desc->dma_addr); @@ -2156,6 +2280,8 @@ dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf, if (status != QDF_STATUS_SUCCESS) { dp_err_rl("Tx_hw_enqueue Fail tx_desc %pK queue %d", tx_desc, tx_q->ring_id); + dp_tx_desc_history_add(soc, tx_desc->dma_addr, nbuf, + tx_desc->id, DP_TX_DESC_UNMAP); qdf_nbuf_unmap_nbytes_single(vdev->osdev, nbuf, QDF_DMA_TO_DEVICE, nbuf->len); @@ -2187,6 +2313,7 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc, struct dp_tx_desc_s *desc) { qdf_nbuf_t nbuf = desc->nbuf; + enum dp_tx_event_type type = dp_tx_get_event_type(desc->flags); /* nbuf already freed in vdev detach path */ if (!nbuf) @@ -2201,6 +2328,10 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc, /* TSO free */ if (hal_tx_ext_desc_get_tso_enable( desc->msdu_ext_desc->vaddr)) { + dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf, + desc->id, DP_TX_COMP_MSDU_EXT); + dp_tx_tso_seg_history_add(soc, desc->tso_desc, + desc->nbuf, desc->id, type); /* unmap eash TSO seg before free the nbuf */ dp_tx_tso_unmap_segment(soc, desc->tso_desc, desc->tso_num_desc); @@ -2209,6 +2340,7 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc, } } + dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf, desc->id, type); qdf_nbuf_unmap_nbytes_single(soc->osdev, nbuf, QDF_DMA_TO_DEVICE, nbuf->len); @@ -2305,6 +2437,10 @@ qdf_nbuf_t dp_tx_send_msdu_multiple(struct dp_vdev *vdev, qdf_nbuf_t nbuf, } if (msdu_info->frm_type == dp_tx_frm_tso) { + dp_tx_tso_seg_history_add( + soc, + msdu_info->u.tso_info.curr_seg, + nbuf, 0, DP_TX_DESC_UNMAP); dp_tx_tso_unmap_segment(soc, msdu_info->u.tso_info. curr_seg, @@ -4135,6 +4271,7 @@ dp_tx_comp_process_desc(struct dp_soc *soc, struct dp_peer *peer) { uint64_t time_latency = 0; + /* * m_copy/tx_capture modes are not supported for * scatter gather packets @@ -4170,6 +4307,7 @@ dp_tx_comp_process_desc(struct dp_soc *soc, } } + desc->flags |= DP_TX_DESC_FLAG_COMPLETED_TX; dp_tx_comp_free_buf(soc, desc); } @@ -4396,6 +4534,8 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc, * performance impact so avoided the wrapper call here */ next = desc->next; + dp_tx_desc_history_add(soc, desc->dma_addr, desc->nbuf, + desc->id, DP_TX_COMP_UNMAP); qdf_mem_unmap_nbytes_single(soc->osdev, desc->dma_addr, QDF_DMA_TO_DEVICE, @@ -4465,6 +4605,7 @@ void dp_tx_process_htt_completion(struct dp_tx_desc_s *tx_desc, uint8_t *status, if (qdf_unlikely(tx_desc->pdev->is_pdev_down)) { dp_info_rl("pdev in down state %d", tx_desc->id); + tx_desc->flags |= DP_TX_DESC_FLAG_TX_COMP_ERR; dp_tx_comp_free_buf(soc, tx_desc); dp_tx_desc_release(tx_desc, tx_desc->pool_id); return; @@ -4730,6 +4871,7 @@ more_data: if (qdf_unlikely(tx_desc->pdev->is_pdev_down)) { dp_info_rl("pdev in down state %d", tx_desc_id); + tx_desc->flags |= DP_TX_DESC_FLAG_TX_COMP_ERR; dp_tx_comp_free_buf(soc, tx_desc); dp_tx_desc_release(tx_desc, tx_desc->pool_id); goto next_desc; @@ -5029,6 +5171,7 @@ void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev, * in this TX desc. */ if (force_free) { + tx_desc->flags |= DP_TX_DESC_FLAG_FLUSH; dp_tx_comp_free_buf(soc, tx_desc); dp_tx_desc_release(tx_desc, i); } else { @@ -5092,6 +5235,7 @@ void dp_tx_desc_flush(struct dp_pdev *pdev, struct dp_vdev *vdev, if (dp_is_tx_desc_flush_match(pdev, vdev, tx_desc)) { if (force_free) { + tx_desc->flags |= DP_TX_DESC_FLAG_FLUSH; dp_tx_comp_free_buf(soc, tx_desc); dp_tx_desc_release(tx_desc, i); } else { diff --git a/dp/wifi3.0/dp_tx.h b/dp/wifi3.0/dp_tx.h index 021fbbb27220..80073bfc1845 100644 --- a/dp/wifi3.0/dp_tx.h +++ b/dp/wifi3.0/dp_tx.h @@ -38,6 +38,8 @@ #define DP_TX_DESC_FLAG_TDLS_FRAME 0x100 #define DP_TX_DESC_FLAG_ALLOCATED 0x200 #define DP_TX_DESC_FLAG_MESH_MODE 0x400 +#define DP_TX_DESC_FLAG_TX_COMP_ERR 0x1000 +#define DP_TX_DESC_FLAG_FLUSH 0x2000 #define DP_TX_EXT_DESC_FLAG_METADATA_VALID 0x1 diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 2dd2336da03b..636750af54fe 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -385,6 +385,8 @@ enum dp_ctxt_type { DP_RX_RING_HIST_TYPE, DP_RX_ERR_RING_HIST_TYPE, DP_RX_REINJECT_RING_HIST_TYPE, + DP_TX_TCL_HIST_TYPE, + DP_TX_COMP_HIST_TYPE, DP_FISA_RX_FT_TYPE, DP_RX_REFILL_RING_HIST_TYPE, DP_TX_HW_DESC_HIST_TYPE, @@ -1241,6 +1243,41 @@ struct dp_rx_refill_history { #endif +enum dp_tx_event_type { + DP_TX_DESC_INVAL_EVT = 0, + DP_TX_DESC_MAP, + DP_TX_DESC_COOKIE, + DP_TX_DESC_FLUSH, + DP_TX_DESC_UNMAP, + DP_TX_COMP_UNMAP, + DP_TX_COMP_UNMAP_ERR, + DP_TX_COMP_MSDU_EXT, +}; + +#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY +/* Size must be in 2 power, for bitwise index rotation */ +#define DP_TX_TCL_HISTORY_SIZE 0x4000 +#define DP_TX_COMP_HISTORY_SIZE 0x4000 + +struct dp_tx_desc_event { + qdf_nbuf_t skb; + dma_addr_t paddr; + uint32_t sw_cookie; + enum dp_tx_event_type type; + uint64_t ts; +}; + +struct dp_tx_tcl_history { + qdf_atomic_t index; + struct dp_tx_desc_event entry[DP_TX_TCL_HISTORY_SIZE]; +}; + +struct dp_tx_comp_history { + qdf_atomic_t index; + struct dp_tx_desc_event entry[DP_TX_COMP_HISTORY_SIZE]; +}; +#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */ + /* structure to record recent operation related variable */ struct dp_last_op_info { /* last link desc buf info through WBM release ring */ @@ -1627,6 +1664,11 @@ struct dp_soc { struct dp_rx_reinject_history *rx_reinject_ring_history; #endif +#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY + struct dp_tx_tcl_history *tx_tcl_history; + struct dp_tx_comp_history *tx_comp_history; +#endif + qdf_spinlock_t ast_lock; /*Timer for AST entry ageout maintainance */ qdf_timer_t ast_aging_timer;