diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 24bfedaf85..436d2b1c5f 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -11178,6 +11178,7 @@ void *dp_soc_init(struct dp_soc *soc, HTC_HANDLE htc_handle, soc->per_tid_basize_max_tid = 8; soc->num_hw_dscp_tid_map = HAL_MAX_HW_DSCP_TID_V2_MAPS; soc->lmac_polled_mode = 1; + soc->wbm_release_desc_rx_sg_support = 1; break; case TARGET_TYPE_QCA5018: wlan_cfg_set_reo_dst_ring_size(soc->wlan_cfg_ctx, diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 12fe2ce179..ffab7261af 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -813,11 +813,19 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, DP_STATS_INC_PKT(soc, rx.err.rx_invalid_peer, 1, qdf_nbuf_len(nbuf)); - mpdu_done = dp_rx_chain_msdus(soc, nbuf, rx_tlv_hdr, pool_id); - /* Trigger invalid peer handler wrapper */ - dp_rx_process_invalid_peer_wrapper(soc, - pdev->invalid_peer_head_msdu, - mpdu_done, pool_id); + /* QCN9000 has the support enabled */ + if (qdf_unlikely(soc->wbm_release_desc_rx_sg_support)) { + mpdu_done = true; + /* Trigger invalid peer handler wrapper */ + dp_rx_process_invalid_peer_wrapper(soc, + nbuf, mpdu_done, pool_id); + } else { + mpdu_done = dp_rx_chain_msdus(soc, nbuf, rx_tlv_hdr, pool_id); + /* Trigger invalid peer handler wrapper */ + dp_rx_process_invalid_peer_wrapper(soc, + pdev->invalid_peer_head_msdu, + mpdu_done, pool_id); + } if (mpdu_done) { pdev->invalid_peer_head_msdu = NULL; @@ -1442,6 +1450,11 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, struct hal_wbm_err_desc_info wbm_err_info = { 0 }; uint8_t pool_id; uint8_t tid = 0; + uint8_t msdu_continuation = 0; + bool first_msdu_in_sg = false; + bool is_raw_mode = false; + uint32_t msdu_len = 0; + /* Debug -- Remove later */ qdf_assert(soc && hal_ring_hdl); @@ -1463,9 +1476,30 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, goto done; } - while (qdf_likely(quota-- && (ring_desc = - hal_srng_dst_get_next(hal_soc, - hal_ring_hdl)))) { + while (qdf_likely(quota)) { + ring_desc = hal_srng_dst_get_next(hal_soc, hal_ring_hdl); + + if (qdf_unlikely(!ring_desc)) { + /* Check hw hp in case of SG support */ + if (qdf_unlikely(soc->wbm_release_desc_rx_sg_support)) { + /* + * Update the cached hp from hw hp + * This is required for partially created + * SG packets while quote is still left + */ + hal_srng_sync_cachedhp(hal_soc, hal_ring_hdl); + ring_desc = hal_srng_dst_get_next(hal_soc, hal_ring_hdl); + if (!ring_desc) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("No Rx Hw Desc for intermediate sg -- %pK"), + hal_ring_hdl); + break; + } + } else { + /* Come out of the loop in Non SG support cases */ + break; + } + } /* XXX */ buf_type = HAL_RX_WBM_BUF_TYPE_GET(ring_desc); @@ -1519,6 +1553,31 @@ 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)) { + /* 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) { + /* Update length from first buffer in SG */ + 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; + } + + 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; + } 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; + } + } + nbuf = rx_desc->nbuf; qdf_nbuf_unmap_single(soc->osdev, nbuf, QDF_DMA_FROM_DEVICE); @@ -1537,6 +1596,14 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, dp_rx_add_to_free_desc_list(&head[rx_desc->pool_id], &tail[rx_desc->pool_id], rx_desc); + + /* + * if continuation bit is set then we have MSDU spread + * across multiple buffers, let us not decrement quota + * till we reap all buffers of that MSDU. + */ + if (qdf_likely(!msdu_continuation)) + quota -= 1; } done: dp_srng_access_end(int_ctx, soc, hal_ring_hdl); @@ -1581,9 +1648,26 @@ done: next = nbuf->next; + /* + * Form the SG for msdu continued buffers + * QCN9000 has this support + */ + if (qdf_nbuf_is_rx_chfrag_cont(nbuf)) { + nbuf = dp_rx_sg_create(nbuf); + next = nbuf->next; + is_raw_mode = HAL_IS_DECAP_FORMAT_RAW(soc->hal_soc, qdf_nbuf_data(nbuf)); + if (!is_raw_mode) { + /* Free the pacckets in case of 802.3 SG */ + qdf_nbuf_free(nbuf); + dp_info_rl("scattered 802.3 msdu dropped"); + nbuf = next; + continue; + } + } + if (wbm_err_info.wbm_err_src == HAL_RX_WBM_ERR_SRC_REO) { if (wbm_err_info.reo_psh_rsn - == HAL_RX_WBM_REO_PSH_RSN_ERROR) { + == HAL_RX_WBM_REO_PSH_RSN_ERROR) { DP_STATS_INC(soc, rx.err.reo_error diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 44d1d047ae..d92f6741ac 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1255,6 +1255,8 @@ struct dp_soc { /* Full monitor mode support */ bool full_mon_mode; + /* SG supported for msdu continued packets from wbm release ring */ + bool wbm_release_desc_rx_sg_support; }; #ifdef IPA_OFFLOAD diff --git a/hal/wifi3.0/hal_api.h b/hal/wifi3.0/hal_api.h index 17901fda4a..57d253d65c 100644 --- a/hal/wifi3.0/hal_api.h +++ b/hal/wifi3.0/hal_api.h @@ -1157,6 +1157,24 @@ hal_srng_dst_num_valid_locked(hal_soc_handle_t hal_soc, return num_valid; } +/** + * hal_srng_sync_cachedhp - sync cachehp pointer from hw hp + * + * @hal_soc: Opaque HAL SOC handle + * @hal_ring_hdl: Destination ring pointer + * + */ +static inline +void hal_srng_sync_cachedhp(void *hal_soc, + hal_ring_handle_t hal_ring_hdl) +{ + struct hal_srng *srng = (struct hal_srng *)hal_ring_hdl; + uint32_t hp; + + hp = *(volatile uint32_t *)(srng->u.dst_ring.hp_addr); + srng->u.dst_ring.cached_hp = hp; +} + /** * hal_srng_src_reap_next - Reap next entry from a source ring and move reap * pointer. This can be used to release any buffers associated with completed diff --git a/hal/wifi3.0/hal_internal.h b/hal/wifi3.0/hal_internal.h index d17369ff6a..213a41c9c9 100644 --- a/hal/wifi3.0/hal_internal.h +++ b/hal/wifi3.0/hal_internal.h @@ -590,6 +590,7 @@ struct hal_hw_txrx_ops { uint8_t (*hal_rx_mpdu_start_tlv_tag_valid)(void *rx_tlv_hdr); void (*hal_rx_sw_mon_desc_info_get)(hal_ring_desc_t rxdma_dst_ring_desc, hal_rx_mon_desc_info_t mon_desc_info); + uint8_t (*hal_rx_wbm_err_msdu_continuation_get)(void *ring_desc); }; /** diff --git a/hal/wifi3.0/hal_rx.h b/hal/wifi3.0/hal_rx.h index 32791fafd4..dd97a75fc3 100644 --- a/hal/wifi3.0/hal_rx.h +++ b/hal/wifi3.0/hal_rx.h @@ -69,7 +69,8 @@ struct hal_wbm_err_desc_info { reserved_1:2; uint8_t wbm_err_src:3, pool_id:2, - reserved_2:3; + msdu_continued:1, + reserved_2:2; }; /** @@ -2964,6 +2965,21 @@ static inline void hal_rx_wbm_err_info_get_from_tlv(uint8_t *buf, sizeof(struct hal_wbm_err_desc_info)); } +/** + * hal_rx_wbm_err_msdu_continuation_get(): Get wbm msdu continuation + * bit from wbm release ring descriptor + * @wbm_desc: wbm ring descriptor + * Return: uint8_t + */ +static inline +uint8_t hal_rx_wbm_err_msdu_continuation_get(hal_soc_handle_t hal_soc_hdl, + void *wbm_desc) +{ + struct hal_soc *hal_soc = (struct hal_soc *)hal_soc_hdl; + + return hal_soc->ops->hal_rx_wbm_err_msdu_continuation_get(wbm_desc); +} + #define HAL_RX_MSDU_START_NSS_GET(_rx_msdu_start) \ (_HAL_MS((*_OFFSET_TO_WORD_PTR((_rx_msdu_start), \ RX_MSDU_START_5_NSS_OFFSET)), \ diff --git a/hal/wifi3.0/qca6750/hal_6750.c b/hal/wifi3.0/qca6750/hal_6750.c index 16371c30ff..51706d8905 100644 --- a/hal/wifi3.0/qca6750/hal_6750.c +++ b/hal/wifi3.0/qca6750/hal_6750.c @@ -1422,6 +1422,7 @@ struct hal_hw_txrx_ops qca6750_hal_hw_txrx_ops = { NULL, NULL, NULL, + NULL, }; struct hal_hw_srng_config hw_srng_table_6750[] = { diff --git a/hal/wifi3.0/qcn9000/hal_9000.c b/hal/wifi3.0/qcn9000/hal_9000.c index 795bb6d156..6c70db09bc 100644 --- a/hal/wifi3.0/qcn9000/hal_9000.c +++ b/hal/wifi3.0/qcn9000/hal_9000.c @@ -268,6 +268,24 @@ uint8_t hal_rx_mpdu_start_tlv_tag_valid_9000(void *rx_tlv_hdr) return tlv_tag == WIFIRX_MPDU_START_E ? true : false; } +/** + * hal_rx_wbm_err_msdu_continuation_get_9000 () - API to check if WBM + * msdu continuation bit is set + * + *@wbm_desc: wbm release ring descriptor + * + * Return: true if msdu continuation bit is set. + */ +uint8_t hal_rx_wbm_err_msdu_continuation_get_9000(void *wbm_desc) +{ + uint32_t comp_desc = + *(uint32_t *)(((uint8_t *)wbm_desc) + + WBM_RELEASE_RING_3_MSDU_CONTINUATION_OFFSET); + + return (comp_desc & WBM_RELEASE_RING_3_MSDU_CONTINUATION_MASK) >> + WBM_RELEASE_RING_3_MSDU_CONTINUATION_LSB; +} + /** * hal_rx_proc_phyrx_other_receive_info_tlv_9000(): API to get tlv info * @@ -1548,6 +1566,7 @@ struct hal_hw_txrx_ops qcn9000_hal_hw_txrx_ops = { NULL, hal_rx_mpdu_start_tlv_tag_valid_9000, hal_rx_sw_mon_desc_info_get_9000, + hal_rx_wbm_err_msdu_continuation_get_9000, }; struct hal_hw_srng_config hw_srng_table_9000[] = {