diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 7168fa8982..fbc314d6fb 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -2242,6 +2242,24 @@ void dp_set_max_page_size(struct qdf_mem_multi_page_t *pages, } #endif /* MAX_ALLOC_PAGE_SIZE */ +/** + * dp_history_get_next_index() - get the next entry to record an entry + * in the history. + * @curr_idx: Current index where the last entry is written. + * @max_entries: Max number of entries in the history + * + * This function assumes that the max number os entries is a power of 2. + * + * Returns: The index where the next entry is to be written. + */ +static inline uint32_t dp_history_get_next_index(qdf_atomic_t *curr_idx, + uint32_t max_entries) +{ + uint32_t idx = qdf_atomic_inc_return(curr_idx); + + return idx & (max_entries - 1); +} + /** * dp_rx_skip_tlvs() - Skip TLVs len + L2 hdr_offset, save in nbuf->cb * @nbuf: nbuf cb to be updated diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 04324abc94..8b1d99a8ab 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3827,6 +3827,63 @@ static QDF_STATUS dp_htt_ppdu_stats_attach(struct dp_pdev *pdev) return QDF_STATUS_SUCCESS; } +#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY +/** + * dp_soc_rx_history_attach() - Attach the ring history record buffers + * @soc: DP soc structure + * + * This function allocates the memory for recording the rx ring, rx error + * ring and the reinject 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_rx_history_attach(struct dp_soc *soc) +{ + int i; + uint32_t rx_ring_hist_size; + uint32_t rx_err_ring_hist_size; + uint32_t rx_reinject_hist_size; + + rx_ring_hist_size = sizeof(*soc->rx_ring_history[i]); + rx_err_ring_hist_size = sizeof(*soc->rx_err_ring_history); + rx_reinject_hist_size = sizeof(*soc->rx_reinject_ring_history); + + for (i = 0; i < MAX_REO_DEST_RINGS; i++) { + soc->rx_ring_history[i] = qdf_mem_malloc(rx_ring_hist_size); + qdf_atomic_init(&soc->rx_ring_history[i]->index); + } + + soc->rx_err_ring_history = qdf_mem_malloc(rx_err_ring_hist_size); + qdf_atomic_init(&soc->rx_err_ring_history->index); + + soc->rx_reinject_ring_history = qdf_mem_malloc(rx_reinject_hist_size); + qdf_atomic_init(&soc->rx_reinject_ring_history->index); +} + +static void dp_soc_rx_history_detach(struct dp_soc *soc) +{ + int i; + + for (i = 0; i < MAX_REO_DEST_RINGS; i++) + qdf_mem_free(soc->rx_ring_history[i]); + + qdf_mem_free(soc->rx_err_ring_history); + qdf_mem_free(soc->rx_reinject_ring_history); +} + +#else +static inline void dp_soc_rx_history_attach(struct dp_soc *soc) +{ +} + +static inline void dp_soc_rx_history_detach(struct dp_soc *soc) +{ +} +#endif + /* * dp_pdev_attach_wifi3() - attach txrx pdev * @txrx_soc: Datapath SOC handle @@ -4327,6 +4384,7 @@ static void dp_soc_detach(struct cdp_soc_t *txrx_soc) dp_hw_link_desc_ring_free(soc); dp_hw_link_desc_pool_banks_free(soc, WLAN_INVALID_PDEV_ID); wlan_cfg_soc_detach(soc->wlan_cfg_ctx); + dp_soc_rx_history_detach(soc); qdf_mem_free(soc); } @@ -10922,6 +10980,7 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc, /* Reset wbm sg list and flags */ dp_rx_wbm_sg_list_reset(soc); + dp_soc_rx_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_rx.c b/dp/wifi3.0/dp_rx.c index 7a34259dd5..cd15fea0bf 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -1948,6 +1948,49 @@ bool dp_rx_is_raw_frame_dropped(qdf_nbuf_t nbuf) } #endif +#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY +/** + * dp_rx_ring_record_entry() - Record an entry into the rx ring history. + * @soc: Datapath soc structure + * @ring_num: REO ring number + * @ring_desc: REO ring descriptor + * + * Returns: None + */ +static inline void +dp_rx_ring_record_entry(struct dp_soc *soc, uint8_t ring_num, + hal_ring_desc_t ring_desc) +{ + struct dp_buf_info_record *record; + uint8_t rbm; + struct hal_buf_info hbi; + uint32_t idx; + + if (qdf_unlikely(!&soc->rx_ring_history[ring_num])) + return; + + hal_rx_reo_buf_paddr_get(ring_desc, &hbi); + rbm = hal_rx_ret_buf_manager_get(ring_desc); + + idx = dp_history_get_next_index(&soc->rx_ring_history[ring_num]->index, + DP_RX_HIST_MAX); + + /* No NULL check needed for record since its an array */ + record = &soc->rx_ring_history[ring_num]->entry[idx]; + + record->timestamp = qdf_get_log_timestamp(); + record->hbi.paddr = hbi.paddr; + record->hbi.sw_cookie = hbi.sw_cookie; + record->hbi.rbm = rbm; +} +#else +static inline void +dp_rx_ring_record_entry(struct dp_soc *soc, uint8_t ring_num, + hal_ring_desc_t ring_desc) +{ +} +#endif + /** * dp_rx_process() - Brain of the Rx processing functionality * Called from the bottom half (tasklet/NET_RX_SOFTIRQ) @@ -2071,6 +2114,7 @@ more_data: qdf_assert(0); } + dp_rx_ring_record_entry(soc, reo_ring_num, ring_desc); rx_buf_cookie = HAL_RX_REO_BUF_COOKIE_GET(ring_desc); status = dp_rx_cookie_check_and_invalidate(ring_desc); if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) { diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index 52476c78e6..9de7599f5b 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -1000,6 +1000,45 @@ dp_rx_defrag_nwifi_to_8023(struct dp_soc *soc, qdf_mem_free(rx_desc_info); } +#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY +/** + * dp_rx_reinject_ring_record_entry() - Record reinject ring history + * @soc: Datapath soc structure + * @paddr: paddr of the buffer reinjected to SW2REO ring + * @sw_cookie: SW cookie of the buffer reinjected to SW2REO ring + * @rbm: Return buffer manager of the buffer reinjected to SW2REO ring + * + * Returns: None + */ +static inline void +dp_rx_reinject_ring_record_entry(struct dp_soc *soc, uint64_t paddr, + uint32_t sw_cookie, uint8_t rbm) +{ + struct dp_buf_info_record *record; + uint32_t idx; + + if (qdf_unlikely(soc->rx_reinject_ring_history)) + return; + + idx = dp_history_get_next_index(&soc->rx_reinject_ring_history->index, + DP_RX_REINJECT_HIST_MAX); + + /* No NULL check needed for record since its an array */ + record = &soc->rx_reinject_ring_history->entry[idx]; + + record->timestamp = qdf_get_log_timestamp(); + record->hbi.paddr = paddr; + record->hbi.sw_cookie = sw_cookie; + record->hbi.rbm = rbm; +} +#else +static inline void +dp_rx_reinject_ring_record_entry(struct dp_soc *soc, uint64_t paddr, + uint32_t sw_cookie, uint8_t rbm) +{ +} +#endif + /* * dp_rx_defrag_reo_reinject(): Reinject the fragment chain back into REO * @peer: Pointer to the peer @@ -1136,6 +1175,7 @@ static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer, return QDF_STATUS_E_FAILURE; } + dp_rx_reinject_ring_record_entry(soc, paddr, cookie, DP_DEFRAG_RBM); paddr = (uint64_t)buf_info.paddr; /* buf addr */ hal_rxdma_buff_addr_info_set(ent_ring_desc, paddr, diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index e7c5603c80..5a6edc3d4e 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1436,6 +1436,45 @@ dp_rx_link_cookie_invalidate(hal_ring_desc_t ring_desc) } #endif +#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY +/** + * dp_rx_err_ring_record_entry() - Record rx err ring history + * @soc: Datapath soc structure + * @paddr: paddr of the buffer in RX err ring + * @sw_cookie: SW cookie of the buffer in RX err ring + * @rbm: Return buffer manager of the buffer in RX err ring + * + * Returns: None + */ +static inline void +dp_rx_err_ring_record_entry(struct dp_soc *soc, uint64_t paddr, + uint32_t sw_cookie, uint8_t rbm) +{ + struct dp_buf_info_record *record; + uint32_t idx; + + if (qdf_unlikely(soc->rx_err_ring_history)) + return; + + idx = dp_history_get_next_index(&soc->rx_err_ring_history->index, + DP_RX_ERR_HIST_MAX); + + /* No NULL check needed for record since its an array */ + record = &soc->rx_err_ring_history->entry[idx]; + + record->timestamp = qdf_get_log_timestamp(); + record->hbi.paddr = paddr; + record->hbi.sw_cookie = sw_cookie; + record->hbi.rbm = rbm; +} +#else +static inline void +dp_rx_err_ring_record_entry(struct dp_soc *soc, uint64_t paddr, + uint32_t sw_cookie, uint8_t rbm) +{ +} +#endif + uint32_t dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, hal_ring_handle_t hal_ring_hdl, uint32_t quota) @@ -1519,7 +1558,9 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, link_desc_va = dp_rx_cookie_2_link_desc_va(soc, &hbi); hal_rx_msdu_list_get(soc->hal_soc, link_desc_va, &msdu_list, &num_msdus); - + dp_rx_err_ring_record_entry(soc, msdu_list.paddr[0], + msdu_list.sw_cookie[0], + msdu_list.rbm[0]); if (qdf_unlikely((msdu_list.rbm[0] != DP_WBM2SW_RBM) && (msdu_list.rbm[0] != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST) && diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index d749b3cc41..8b418e35d1 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -975,6 +975,61 @@ struct rx_buff_pool { bool is_initialized; }; +/* + * The logic for get current index of these history is dependent on this + * value being power of 2. + */ +#define DP_RX_HIST_MAX 2048 +#define DP_RX_ERR_HIST_MAX 4096 +#define DP_RX_REINJECT_HIST_MAX 1024 + +QDF_COMPILE_TIME_ASSERT(rx_history_size, + (DP_RX_HIST_MAX & + (DP_RX_HIST_MAX - 1)) == 0); +QDF_COMPILE_TIME_ASSERT(rx_err_history_size, + (DP_RX_ERR_HIST_MAX & + (DP_RX_ERR_HIST_MAX - 1)) == 0); +QDF_COMPILE_TIME_ASSERT(rx_reinject_history_size, + (DP_RX_REINJECT_HIST_MAX & + (DP_RX_REINJECT_HIST_MAX - 1)) == 0); + +/** + * struct dp_buf_info_record - ring buffer info + * @hbi: HW ring buffer info + * @timestamp: timestamp when this entry was recorded + */ +struct dp_buf_info_record { + struct hal_buf_info hbi; + uint64_t timestamp; +}; + +/* struct dp_rx_history - rx ring hisotry + * @index: Index where the last entry is written + * @entry: history entries + */ +struct dp_rx_history { + qdf_atomic_t index; + struct dp_buf_info_record entry[DP_RX_HIST_MAX]; +}; + +/* struct dp_rx_err_history - rx err ring hisotry + * @index: Index where the last entry is written + * @entry: history entries + */ +struct dp_rx_err_history { + qdf_atomic_t index; + struct dp_buf_info_record entry[DP_RX_ERR_HIST_MAX]; +}; + +/* struct dp_rx_reinject_history - rx reinject ring hisotry + * @index: Index where the last entry is written + * @entry: history entries + */ +struct dp_rx_reinject_history { + qdf_atomic_t index; + struct dp_buf_info_record entry[DP_RX_REINJECT_HIST_MAX]; +}; + /* SOC level structure for data path */ struct dp_soc { /** @@ -1223,6 +1278,10 @@ struct dp_soc { TAILQ_HEAD(, dp_ast_entry) * bins; } ast_hash; + struct dp_rx_history *rx_ring_history[MAX_REO_DEST_RINGS]; + struct dp_rx_err_history *rx_err_ring_history; + struct dp_rx_reinject_history *rx_reinject_ring_history; + qdf_spinlock_t ast_lock; /*Timer for AST entry ageout maintainance */ qdf_timer_t ast_aging_timer;