diff --git a/dp/wifi3.0/be/dp_be_rx.c b/dp/wifi3.0/be/dp_be_rx.c index 5243f1936e..9e3deec1b8 100644 --- a/dp/wifi3.0/be/dp_be_rx.c +++ b/dp/wifi3.0/be/dp_be_rx.c @@ -72,6 +72,7 @@ dp_rx_update_flow_info(qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr) #ifdef DP_RX_MSDU_DONE_FAIL_HISTORY static inline void dp_rx_msdu_done_fail_event_record(struct dp_soc *soc, + struct dp_rx_desc *rx_desc, qdf_nbuf_t nbuf) { struct dp_msdu_done_fail_entry *entry; @@ -84,10 +85,16 @@ dp_rx_msdu_done_fail_event_record(struct dp_soc *soc, DP_MSDU_DONE_FAIL_HIST_MAX); entry = &soc->msdu_done_fail_hist->entry[idx]; entry->paddr = qdf_nbuf_get_frag_paddr(nbuf, 0); + + if (rx_desc) + entry->sw_cookie = rx_desc->cookie; + else + entry->sw_cookie = 0xDEAD; } #else static inline void dp_rx_msdu_done_fail_event_record(struct dp_soc *soc, + struct dp_rx_desc *rx_desc, qdf_nbuf_t nbuf) { } @@ -192,6 +199,84 @@ dp_rx_wds_learn(struct dp_soc *soc, } #endif +#ifdef DP_RX_PEEK_MSDU_DONE_WAR +static inline int dp_rx_war_peek_msdu_done(struct dp_soc *soc, + struct dp_rx_desc *rx_desc) +{ + uint8_t *rx_tlv_hdr; + + qdf_nbuf_sync_for_cpu(soc->osdev, rx_desc->nbuf, QDF_DMA_FROM_DEVICE); + rx_tlv_hdr = qdf_nbuf_data(rx_desc->nbuf); + + return hal_rx_tlv_msdu_done_get_be(rx_tlv_hdr); +} + +/** + * dp_rx_delink_n_rel_rx_desc() - unmap & free the nbuf in the rx_desc + * @soc: DP SoC handle + * @rx_desc: rx_desc handle of the nbuf to be unmapped & freed + * @reo_ring_num: REO_RING_NUM corresponding to the REO for which the + * bottom half is being serviced. + * + * Return: None + */ +static inline void +dp_rx_delink_n_rel_rx_desc(struct dp_soc *soc, struct dp_rx_desc *rx_desc, + uint8_t reo_ring_num) +{ + if (!rx_desc) + return; + + dp_rx_nbuf_unmap(soc, rx_desc, reo_ring_num); + dp_rx_nbuf_free(rx_desc->nbuf); + /* + * RX_DESC flags: + * in_use = 0 will be set when this rx_desc is added to local freelist + * unmapped = 1 will be set by dp_rx_nbuf_unmap + * in_err_state = 0 will be set during replenish + * has_reuse_nbuf need not be touched. + * msdu_done_fail = 0 should be set here ..!! + */ + rx_desc->msdu_done_fail = 0; +} + +static inline struct dp_rx_desc * +dp_rx_war_store_msdu_done_fail_desc(struct dp_soc *soc, + struct dp_rx_desc *rx_desc, + uint8_t reo_ring_num) +{ + struct dp_rx_msdu_done_fail_desc_list *msdu_done_fail_desc_list = + &soc->msdu_done_fail_desc_list; + struct dp_rx_desc *old_rx_desc; + uint32_t idx; + + idx = dp_get_next_index(&msdu_done_fail_desc_list->index, + DP_MSDU_DONE_FAIL_DESCS_MAX); + + old_rx_desc = msdu_done_fail_desc_list->msdu_done_fail_descs[idx]; + dp_rx_delink_n_rel_rx_desc(soc, old_rx_desc, reo_ring_num); + + msdu_done_fail_desc_list->msdu_done_fail_descs[idx] = rx_desc; + + return old_rx_desc; +} + +#else +static inline int dp_rx_war_peek_msdu_done(struct dp_soc *soc, + struct dp_rx_desc *rx_desc) +{ + return 1; +} + +static inline struct dp_rx_desc * +dp_rx_war_store_msdu_done_fail_desc(struct dp_soc *soc, + struct dp_rx_desc *rx_desc, + uint8_t reo_ring_num) +{ + return NULL; +} +#endif + uint32_t dp_rx_process_be(struct dp_intr *int_ctx, hal_ring_handle_t hal_ring_hdl, uint8_t reo_ring_num, uint32_t quota) @@ -446,6 +531,29 @@ more_data: } is_prev_msdu_last = false; } + } else if (qdf_unlikely(!dp_rx_war_peek_msdu_done(soc, + rx_desc))) { + struct dp_rx_desc *old_rx_desc = + dp_rx_war_store_msdu_done_fail_desc( + soc, rx_desc, + reo_ring_num); + if (qdf_likely(old_rx_desc)) { + rx_bufs_reaped[rx_desc->chip_id][rx_desc->pool_id]++; + dp_rx_add_to_free_desc_list + (&head[rx_desc->chip_id][rx_desc->pool_id], + &tail[rx_desc->chip_id][rx_desc->pool_id], + old_rx_desc); + quota -= 1; + num_pending -= 1; + num_rx_bufs_reaped++; + } + rx_desc->msdu_done_fail = 1; + DP_STATS_INC(soc, rx.err.msdu_done_fail, 1); + dp_err("MSDU DONE failure %d", + soc->stats.rx.err.msdu_done_fail); + dp_rx_msdu_done_fail_event_record(soc, rx_desc, + rx_desc->nbuf); + continue; } if (!is_prev_msdu_last && @@ -641,7 +749,7 @@ done: soc->stats.rx.err.msdu_done_fail); hal_rx_dump_pkt_tlvs(hal_soc, rx_tlv_hdr, QDF_TRACE_LEVEL_INFO); - dp_rx_msdu_done_fail_event_record(soc, nbuf); + dp_rx_msdu_done_fail_event_record(soc, NULL, nbuf); tid_stats->fail_cnt[MSDU_DONE_FAILURE]++; dp_rx_nbuf_free(nbuf); qdf_assert(0); diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 09d008b0d1..322689193d 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -4499,6 +4499,25 @@ void dp_set_max_page_size(struct qdf_mem_multi_page_t *pages, } #endif /* MAX_ALLOC_PAGE_SIZE */ +/** + * dp_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. + * + * Return: The index where the next entry is to be written. + */ + +static inline uint32_t dp_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_history_get_next_index() - get the next entry to record an entry * in the history. @@ -4512,9 +4531,7 @@ void dp_set_max_page_size(struct qdf_mem_multi_page_t *pages, 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); + return dp_get_next_index(curr_idx, max_entries); } /** diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 703904ffdf..04a2e7eaae 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3493,6 +3493,19 @@ static inline void dp_soc_msdu_done_fail_history_detach(struct dp_soc *soc) } #endif +#ifdef DP_RX_PEEK_MSDU_DONE_WAR +static void dp_soc_msdu_done_fail_desc_list_attach(struct dp_soc *soc) +{ + qdf_atomic_init(&soc->msdu_done_fail_desc_list.index); + qdf_atomic_set(&soc->msdu_done_fail_desc_list.index, + DP_MSDU_DONE_FAIL_DESCS_MAX - 1); +} +#else +static void dp_soc_msdu_done_fail_desc_list_attach(struct dp_soc *soc) +{ +} +#endif + #ifdef WLAN_SUPPORT_RX_FLOW_TAG QDF_STATUS dp_rx_fst_attach_wrapper(struct dp_soc *soc, struct dp_pdev *pdev) @@ -13675,6 +13688,7 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc, dp_soc_rx_history_attach(soc); dp_soc_mon_status_ring_history_attach(soc); dp_soc_tx_history_attach(soc); + dp_soc_msdu_done_fail_desc_list_attach(soc); dp_soc_msdu_done_fail_history_attach(soc); wlan_set_srng_cfg(&soc->wlan_srng_cfg); soc->wlan_cfg_ctx = wlan_cfg_soc_attach(soc->ctrl_psoc); diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 565a23dd1c..7e9a548902 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -138,6 +138,8 @@ struct dp_rx_desc_dbg_info { * @in_err_state: Nbuf sanity failed for this descriptor. * @has_reuse_nbuf: the nbuf associated with this desc is also saved in * reuse_nbuf field + * @msdu_done_fail: this particular rx_desc was dequeued from REO with + * msdu_done bit not set in data buffer. */ struct dp_rx_desc { qdf_nbuf_t nbuf; @@ -158,7 +160,8 @@ struct dp_rx_desc { uint8_t in_use:1, unmapped:1, in_err_state:1, - has_reuse_nbuf:1; + has_reuse_nbuf:1, + msdu_done_fail:1; }; #ifndef QCA_HOST_MODE_WIFI_DISABLED diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 5d5233dc4c..e85eda1ebe 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -2645,10 +2645,11 @@ struct test_qaddr_del { #ifdef DP_RX_MSDU_DONE_FAIL_HISTORY -#define DP_MSDU_DONE_FAIL_HIST_MAX 32 +#define DP_MSDU_DONE_FAIL_HIST_MAX 128 struct dp_msdu_done_fail_entry { qdf_dma_addr_t paddr; + uint32_t sw_cookie; }; struct dp_msdu_done_fail_history { @@ -2657,6 +2658,15 @@ struct dp_msdu_done_fail_history { }; #endif +#ifdef DP_RX_PEEK_MSDU_DONE_WAR +#define DP_MSDU_DONE_FAIL_DESCS_MAX 64 + +struct dp_rx_msdu_done_fail_desc_list { + qdf_atomic_t index; + struct dp_rx_desc *msdu_done_fail_descs[DP_MSDU_DONE_FAIL_DESCS_MAX]; +}; +#endif + /* SOC level structure for data path */ struct dp_soc { /** @@ -3229,6 +3239,9 @@ struct dp_soc { #ifdef DP_RX_MSDU_DONE_FAIL_HISTORY struct dp_msdu_done_fail_history *msdu_done_fail_hist; #endif +#ifdef DP_RX_PEEK_MSDU_DONE_WAR + struct dp_rx_msdu_done_fail_desc_list msdu_done_fail_desc_list; +#endif }; #ifdef IPA_OFFLOAD