diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 8fc1a5a798..e08a4d3a71 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -4109,6 +4109,9 @@ static void dp_soc_deinit(void *txrx_soc) htt_soc_detach(htt_soc); + /* Free wbm sg list and reset flags in down path */ + dp_rx_wbm_sg_list_deinit(soc); + wlan_minidump_remove(soc); } @@ -10556,6 +10559,9 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc, soc->osdev = qdf_osdev; soc->num_hw_dscp_tid_map = HAL_MAX_HW_DSCP_TID_MAPS; + /* Reset wbm sg list and flags */ + dp_rx_wbm_sg_list_reset(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) { @@ -10640,6 +10646,9 @@ void *dp_soc_init(struct dp_soc *soc, HTC_HANDLE htc_handle, dp_soc_cfg_init(soc); + /* Reset/Initialize wbm sg list and flags */ + dp_rx_wbm_sg_list_reset(soc); + /* Note: Any SRNG ring initialization should happen only after * Interrupt mode is set and followed by filling up the * interrupt mask. IT SHOULD ALWAYS BE IN THIS ORDER. diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index d89c0095d2..bc45889609 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -690,6 +690,19 @@ void dp_2k_jump_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr, qdf_nbuf_set_next((tail), NULL); \ } while (0) +#define DP_RX_MERGE_TWO_LIST(phead, ptail, chead, ctail) \ + do { \ + if (!(phead)) { \ + (phead) = (chead); \ + } else { \ + qdf_nbuf_set_next((ptail), (chead)); \ + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(phead) += \ + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(chead); \ + } \ + (ptail) = (ctail); \ + qdf_nbuf_set_next((ptail), NULL); \ + } while (0) + /*for qcn9000 emulation the pcie is complete phy and no address restrictions*/ #if !defined(BUILD_X86) || defined(QCA_WIFI_QCN9000) static inline int check_x86_paddr(struct dp_soc *dp_soc, qdf_nbuf_t *rx_netbuf, @@ -1238,7 +1251,37 @@ dp_rx_srng_access_end(struct dp_intr *int_ctx, struct dp_soc *soc, { dp_srng_access_end(int_ctx, soc, hal_ring_hdl); } - #endif +/* + * dp_rx_wbm_sg_list_reset() - Initialize sg list + * + * This api should be called at soc init and afterevery sg processing. + *@soc: DP SOC handle + */ +static inline void dp_rx_wbm_sg_list_reset(struct dp_soc *soc) +{ + if (soc) { + soc->wbm_sg_param.wbm_is_first_msdu_in_sg = false; + soc->wbm_sg_param.wbm_sg_nbuf_head = NULL; + soc->wbm_sg_param.wbm_sg_nbuf_tail = NULL; + soc->wbm_sg_param.wbm_sg_desc_msdu_len = 0; + } +} + +/* + * dp_rx_wbm_sg_list_deinit() - De-initialize sg list + * + * This api should be called in down path, to avoid any leak. + *@soc: DP SOC handle + */ +static inline void dp_rx_wbm_sg_list_deinit(struct dp_soc *soc) +{ + if (soc) { + if (soc->wbm_sg_param.wbm_sg_nbuf_head) + qdf_nbuf_list_free(soc->wbm_sg_param.wbm_sg_nbuf_head); + + dp_rx_wbm_sg_list_reset(soc); + } +} #endif /* _DP_RX_H */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 82e7bb25c0..424773c7c4 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1617,6 +1617,22 @@ static inline bool dp_handle_rxdma_decrypt_err(void) } #endif +static inline bool +dp_rx_is_sg_formation_required(struct hal_wbm_err_desc_info *info) +{ + /* + * Currently Null Queue and Unencrypted error handlers has support for + * SG. Other error handler do not deal with SG buffer. + */ + if (((info->wbm_err_src == HAL_RX_WBM_ERR_SRC_REO) && + (info->reo_err_code == HAL_REO_ERR_QUEUE_DESC_ADDR_0)) || + ((info->wbm_err_src == HAL_RX_WBM_ERR_SRC_RXDMA) && + (info->rxdma_err_code == HAL_RXDMA_ERR_UNENCRYPTED))) + return true; + + return false; +} + uint32_t dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, hal_ring_handle_t hal_ring_hdl, uint32_t quota) @@ -1642,8 +1658,7 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, uint8_t pool_id; uint8_t tid = 0; uint8_t msdu_continuation = 0; - bool first_msdu_in_sg = false; - uint32_t msdu_len = 0; + bool process_sg_buf = false; /* Debug -- Remove later */ qdf_assert(soc && hal_ring_hdl); @@ -1742,28 +1757,34 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, ring_desc, rx_desc); } - if (qdf_unlikely(soc->wbm_release_desc_rx_sg_support)) { + hal_rx_wbm_err_info_get(ring_desc, &wbm_err_info, hal_soc); + + if (qdf_unlikely(soc->wbm_release_desc_rx_sg_support && + dp_rx_is_sg_formation_required(&wbm_err_info))) { /* SG is detected from continuation bit */ msdu_continuation = hal_rx_wbm_err_msdu_continuation_get(hal_soc, ring_desc); - if (msdu_continuation && !first_msdu_in_sg) { + if (msdu_continuation && + !(soc->wbm_sg_param.wbm_is_first_msdu_in_sg)) { /* Update length from first buffer in SG */ - msdu_len = hal_rx_msdu_start_msdu_len_get( + soc->wbm_sg_param.wbm_sg_desc_msdu_len = + hal_rx_msdu_start_msdu_len_get( qdf_nbuf_data(rx_desc->nbuf)); - first_msdu_in_sg = true; - QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = msdu_len; + soc->wbm_sg_param.wbm_is_first_msdu_in_sg = true; } if (msdu_continuation) { /* MSDU continued packets */ qdf_nbuf_set_rx_chfrag_cont(rx_desc->nbuf, 1); - QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = msdu_len; + QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = + soc->wbm_sg_param.wbm_sg_desc_msdu_len; } else { /* This is the terminal packet in SG */ qdf_nbuf_set_rx_chfrag_start(rx_desc->nbuf, 1); qdf_nbuf_set_rx_chfrag_end(rx_desc->nbuf, 1); - QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = msdu_len; - first_msdu_in_sg = false; + QDF_NBUF_CB_RX_PKT_LEN(rx_desc->nbuf) = + soc->wbm_sg_param.wbm_sg_desc_msdu_len; + process_sg_buf = true; } } @@ -1774,14 +1795,27 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, * save the wbm desc info in nbuf TLV. We will need this * info when we do the actual nbuf processing */ - hal_rx_wbm_err_info_get(ring_desc, &wbm_err_info, hal_soc); wbm_err_info.pool_id = rx_desc->pool_id; hal_rx_wbm_err_info_set_in_tlv(qdf_nbuf_data(nbuf), &wbm_err_info); rx_bufs_reaped[rx_desc->pool_id]++; - DP_RX_LIST_APPEND(nbuf_head, nbuf_tail, rx_desc->nbuf); + if (qdf_nbuf_is_rx_chfrag_cont(nbuf) || process_sg_buf) { + DP_RX_LIST_APPEND(soc->wbm_sg_param.wbm_sg_nbuf_head, + soc->wbm_sg_param.wbm_sg_nbuf_tail, + nbuf); + if (process_sg_buf) { + DP_RX_MERGE_TWO_LIST(nbuf_head, nbuf_tail, + soc->wbm_sg_param.wbm_sg_nbuf_head, + soc->wbm_sg_param.wbm_sg_nbuf_tail); + dp_rx_wbm_sg_list_reset(soc); + process_sg_buf = false; + } + } else { + DP_RX_LIST_APPEND(nbuf_head, nbuf_tail, nbuf); + } + dp_rx_add_to_free_desc_list(&head[rx_desc->pool_id], &tail[rx_desc->pool_id], rx_desc); diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 5135c96b9a..a236c62093 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1326,6 +1326,16 @@ struct dp_soc { /* SG supported for msdu continued packets from wbm release ring */ bool wbm_release_desc_rx_sg_support; bool peer_map_attach_success; + + struct { + /* 1st msdu in sg for msdu continued packets in wbm rel ring */ + bool wbm_is_first_msdu_in_sg; + /* Wbm sg list head */ + qdf_nbuf_t wbm_sg_nbuf_head; + /* Wbm sg list tail */ + qdf_nbuf_t wbm_sg_nbuf_tail; + uint32_t wbm_sg_desc_msdu_len; + } wbm_sg_param; }; #ifdef IPA_OFFLOAD