From aceafadc2e2f453e1deafe836d0bf2245739ec56 Mon Sep 17 00:00:00 2001 From: Mainak Sen Date: Fri, 6 Mar 2020 19:16:27 +0530 Subject: [PATCH] qcacmn: WBM msdu continuation for SG in QCN9000 In QCN9000, wbm release ring has msdu continuation bit support for invld peer MPDUs. Host needs to form SG buffer for packets with msdu continuation bit set Change-Id: Ica03c78068d32d2c8dc609b9a50298b91dd48c0a --- dp/wifi3.0/dp_main.c | 1 + dp/wifi3.0/dp_rx_err.c | 102 ++++++++++++++++++++++++++++++--- dp/wifi3.0/dp_types.h | 2 + hal/wifi3.0/hal_api.h | 18 ++++++ hal/wifi3.0/hal_internal.h | 1 + hal/wifi3.0/hal_rx.h | 18 +++++- hal/wifi3.0/qca6750/hal_6750.c | 1 + hal/wifi3.0/qcn9000/hal_9000.c | 19 ++++++ 8 files changed, 152 insertions(+), 10 deletions(-) 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[] = {