From 7dad533e6c43c863c9f289baef645cd7e6202c51 Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Tue, 21 Apr 2020 22:23:01 +0530 Subject: [PATCH] qcacmn: Handle scattered msdu in OOR error scenario In OOR error handling scenario, msdu is spread across two nbufs. Due to this, there is a mismatch between msdu count fetched from MPDU desc detatils and count fetched from rx link descriptor. Fix is to create frag list for the case where msdu is spread across multiple nbufs. Change-Id: I1d600a0988b373e68aad6ef815fb2d775763b7cb CRs-Fixed: 2665963 --- dp/wifi3.0/dp_rx.c | 43 ++++++++++++++++++++++++---------- dp/wifi3.0/dp_rx.h | 7 ++++-- dp/wifi3.0/dp_rx_err.c | 53 +++++++++++++++++++++++++++++++----------- dp/wifi3.0/dp_types.h | 2 ++ 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index f531538eac..ad309fb00f 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -1792,11 +1792,29 @@ void dp_rx_skip_tlvs(qdf_nbuf_t nbuf, uint32_t l3_padding) QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(nbuf) = l3_padding; qdf_nbuf_pull_head(nbuf, l3_padding + RX_PKT_TLVS_LEN); } + +/** + * dp_rx_set_hdr_pad() - set l3 padding in nbuf cb + * @nbuf: pkt skb pointer + * @l3_padding: l3 padding + * + * Return: None + */ +static inline +void dp_rx_set_hdr_pad(qdf_nbuf_t nbuf, uint32_t l3_padding) +{ + QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(nbuf) = l3_padding; +} #else void dp_rx_skip_tlvs(qdf_nbuf_t nbuf, uint32_t l3_padding) { qdf_nbuf_pull_head(nbuf, l3_padding + RX_PKT_TLVS_LEN); } + +static inline +void dp_rx_set_hdr_pad(qdf_nbuf_t nbuf, uint32_t l3_padding) +{ +} #endif @@ -2911,26 +2929,27 @@ dp_rx_nbuf_prepare(struct dp_soc *soc, struct dp_pdev *pdev) #ifdef DP_RX_SPECIAL_FRAME_NEED bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer, - qdf_nbuf_t nbuf, uint32_t frame_mask) + qdf_nbuf_t nbuf, uint32_t frame_mask, + uint8_t *rx_tlv_hdr) { uint32_t l2_hdr_offset = 0; uint16_t msdu_len = 0; - uint32_t pkt_len = 0; - uint8_t *rx_tlv_hdr; + uint32_t skip_len; - if (qdf_unlikely(qdf_nbuf_is_frag(nbuf))) - return false; - - rx_tlv_hdr = qdf_nbuf_data(nbuf); l2_hdr_offset = hal_rx_msdu_end_l3_hdr_padding_get(soc->hal_soc, rx_tlv_hdr); - msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf); - pkt_len = msdu_len + l2_hdr_offset + RX_PKT_TLVS_LEN; - QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf) = 1; + if (qdf_unlikely(qdf_nbuf_is_frag(nbuf))) { + skip_len = l2_hdr_offset; + } else { + msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf); + skip_len = l2_hdr_offset + RX_PKT_TLVS_LEN; + qdf_nbuf_set_pktlen(nbuf, msdu_len + skip_len); + } - qdf_nbuf_set_pktlen(nbuf, pkt_len); - dp_rx_skip_tlvs(nbuf, l2_hdr_offset); + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf) = 1; + dp_rx_set_hdr_pad(nbuf, l2_hdr_offset); + qdf_nbuf_pull_head(nbuf, skip_len); if (dp_rx_is_special_frame(nbuf, frame_mask)) { dp_rx_deliver_to_stack(soc, peer->vdev, peer, diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index 6dbf094608..c617cd95f4 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -172,6 +172,7 @@ bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask) * @peer: pointer to DP peer * @nbuf: pointer to the skb of RX frame * @frame_mask: the mask for speical frame needed + * @rx_tlv_hdr: start of rx tlv header * * note: Msdu_len must have been stored in QDF_NBUF_CB_RX_PKT_LEN(nbuf) and * single nbuf is expected. @@ -179,7 +180,8 @@ bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask) * return: true - nbuf has been delivered to stack, false - not. */ bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer, - qdf_nbuf_t nbuf, uint32_t frame_mask); + qdf_nbuf_t nbuf, uint32_t frame_mask, + uint8_t *rx_tlv_hdr); #else static inline bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask) @@ -189,7 +191,8 @@ bool dp_rx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask) static inline bool dp_rx_deliver_special_frame(struct dp_soc *soc, struct dp_peer *peer, - qdf_nbuf_t nbuf, uint32_t frame_mask) + qdf_nbuf_t nbuf, uint32_t frame_mask, + uint8_t *rx_tlv_hdr) { return false; } diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 424790102a..82e7bb25c0 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -390,6 +390,7 @@ dp_rx_pn_error_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc, * @soc: core txrx main context * @nbuf: pointer to msdu skb * @peer_id: dp peer ID + * @rx_tlv_hdr: start of rx tlv header * * This function process the msdu delivered from REO2TCL * ring with error type OOR @@ -399,7 +400,8 @@ dp_rx_pn_error_handle(struct dp_soc *soc, hal_ring_desc_t ring_desc, static void dp_rx_oor_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, - uint16_t peer_id) + uint16_t peer_id, + uint8_t *rx_tlv_hdr) { uint32_t frame_mask = FRAME_MASK_IPV4_ARP | FRAME_MASK_IPV4_DHCP | FRAME_MASK_IPV4_EAPOL | FRAME_MASK_IPV6_DHCP; @@ -411,7 +413,8 @@ dp_rx_oor_handle(struct dp_soc *soc, goto free_nbuf; } - if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask)) { + if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask, + rx_tlv_hdr)) { DP_STATS_INC(soc, rx.err.reo_err_oor_to_stack, 1); dp_peer_unref_del_find_by_id(peer); return; @@ -449,7 +452,8 @@ dp_rx_reo_err_entry_process(struct dp_soc *soc, uint32_t rx_bufs_used = 0; struct dp_pdev *pdev; int i; - uint8_t *rx_tlv_hdr; + uint8_t *rx_tlv_hdr_first; + uint8_t *rx_tlv_hdr_last; uint32_t tid = DP_MAX_TIDS; uint16_t peer_id; struct dp_rx_desc *rx_desc; @@ -461,6 +465,9 @@ dp_rx_reo_err_entry_process(struct dp_soc *soc, struct buffer_addr_info next_link_desc_addr_info = { 0 }; /* First field in REO Dst ring Desc is buffer_addr_info */ void *buf_addr_info = ring_desc; + qdf_nbuf_t head_nbuf = NULL; + qdf_nbuf_t tail_nbuf = NULL; + uint16_t msdu_processed = 0; peer_id = DP_PEER_METADATA_PEER_ID_GET( mpdu_desc_info->peer_meta_data); @@ -482,8 +489,25 @@ more_msdu_link_desc: qdf_nbuf_unmap_single(soc->osdev, nbuf, QDF_DMA_FROM_DEVICE); - rx_tlv_hdr = qdf_nbuf_data(nbuf); QDF_NBUF_CB_RX_PKT_LEN(nbuf) = msdu_list.msdu_info[i].msdu_len; + rx_bufs_used++; + dp_rx_add_to_free_desc_list(&pdev->free_list_head, + &pdev->free_list_tail, rx_desc); + + DP_RX_LIST_APPEND(head_nbuf, tail_nbuf, nbuf); + + if (qdf_unlikely(msdu_list.msdu_info[i].msdu_flags & + HAL_MSDU_F_MSDU_CONTINUATION)) + continue; + + rx_tlv_hdr_first = qdf_nbuf_data(head_nbuf); + rx_tlv_hdr_last = qdf_nbuf_data(tail_nbuf); + + if (qdf_unlikely(head_nbuf != tail_nbuf)) { + nbuf = dp_rx_sg_create(head_nbuf); + qdf_nbuf_set_is_frag(nbuf, 1); + DP_STATS_INC(soc, rx.err.reo_err_oor_sg_count, 1); + } switch (err_code) { case HAL_REO_ERR_REGULAR_FRAME_2K_JUMP: @@ -492,28 +516,28 @@ more_msdu_link_desc: * and use it for following msdu. */ if (hal_rx_msdu_end_first_msdu_get(soc->hal_soc, - rx_tlv_hdr)) + rx_tlv_hdr_last)) tid = hal_rx_mpdu_start_tid_get(soc->hal_soc, - rx_tlv_hdr); + rx_tlv_hdr_first); - dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr, + dp_2k_jump_handle(soc, nbuf, rx_tlv_hdr_last, peer_id, tid); break; case HAL_REO_ERR_REGULAR_FRAME_OOR: - dp_rx_oor_handle(soc, nbuf, peer_id); + dp_rx_oor_handle(soc, nbuf, peer_id, rx_tlv_hdr_last); break; default: dp_err_rl("Non-support error code %d", err_code); qdf_nbuf_free(nbuf); } - dp_rx_add_to_free_desc_list(&pdev->free_list_head, - &pdev->free_list_tail, rx_desc); - rx_bufs_used++; + msdu_processed++; + head_nbuf = NULL; + tail_nbuf = NULL; } - if (rx_bufs_used < mpdu_desc_info->msdu_count) { + if (msdu_processed < mpdu_desc_info->msdu_count) { hal_rx_get_next_msdu_link_desc_buf_addr_info( link_desc_va, &next_link_desc_addr_info); @@ -539,7 +563,7 @@ more_msdu_link_desc: dp_rx_link_desc_return_by_addr(soc, buf_addr_info, HAL_BM_ACTION_PUT_IN_IDLE_LIST); - QDF_BUG(rx_bufs_used == mpdu_desc_info->msdu_count); + QDF_BUG(msdu_processed == mpdu_desc_info->msdu_count); return rx_bufs_used; } @@ -755,7 +779,8 @@ dp_2k_jump_handle(struct dp_soc *soc, } nbuf_deliver: - if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask)) { + if (dp_rx_deliver_special_frame(soc, peer, nbuf, frame_mask, + rx_tlv_hdr)) { DP_STATS_INC(soc, rx.err.rx_2k_jump_to_stack, 1); dp_peer_unref_del_find_by_id(peer); return; diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index eb2d256d05..0b3c13ab75 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -832,6 +832,8 @@ struct dp_soc_stats { uint32_t reo_err_oor_drop; /* REO OOR msdu indicated to stack count */ uint32_t reo_err_oor_to_stack; + /* REO OOR scattered msdu count */ + uint32_t reo_err_oor_sg_count; } err; /* packet count per core - per ring */