diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index 1fdf68df2a..ca0d592f10 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -95,9 +95,10 @@ static void dp_rx_return_head_frag_desc(struct dp_peer *peer, union dp_rx_desc_list_elem_t *head = NULL; union dp_rx_desc_list_elem_t *tail = NULL; + pdev = peer->vdev->pdev; + soc = pdev->soc; + if (peer->rx_tid[tid].head_frag_desc) { - pdev = peer->vdev->pdev; - soc = pdev->soc; dp_rxdma_srng = &pdev->rx_refill_buf_ring; rx_desc_pool = &soc->rx_desc_buf[pdev->pdev_id]; @@ -106,6 +107,15 @@ static void dp_rx_return_head_frag_desc(struct dp_peer *peer, dp_rx_buffers_replenish(soc, 0, dp_rxdma_srng, rx_desc_pool, 1, &head, &tail); } + + if (peer->rx_tid[tid].dst_ring_desc) { + if (dp_rx_link_desc_return(soc, + peer->rx_tid[tid].dst_ring_desc, + HAL_BM_ACTION_PUT_IN_IDLE_LIST) != + QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to return link desc", __func__); + } } /* @@ -120,8 +130,6 @@ static void dp_rx_return_head_frag_desc(struct dp_peer *peer, void dp_rx_reorder_flush_frag(struct dp_peer *peer, unsigned int tid) { - struct dp_soc *soc; - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH, FL("Flushing TID %d"), tid); @@ -131,18 +139,6 @@ void dp_rx_reorder_flush_frag(struct dp_peer *peer, return; } - soc = peer->vdev->pdev->soc; - - if (peer->rx_tid[tid].dst_ring_desc) { - if (dp_rx_link_desc_return(soc, - peer->rx_tid[tid].dst_ring_desc, - HAL_BM_ACTION_PUT_IN_IDLE_LIST) != - QDF_STATUS_SUCCESS) - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Failed to return link desc", - __func__); - } - dp_rx_return_head_frag_desc(peer, tid); dp_rx_defrag_cleanup(peer, tid); } @@ -1405,11 +1401,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "Unknown peer, dropping the fragment"); - qdf_nbuf_free(frag); - dp_rx_add_to_free_desc_list(head, tail, rx_desc); - *rx_bfs = 1; - - goto end; + goto discard_frag; } pdev = peer->vdev->pdev; @@ -1422,12 +1414,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, if (!mpdu_sequence_control_valid) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "Invalid MPDU seq control field, dropping MPDU"); - qdf_nbuf_free(frag); - dp_rx_add_to_free_desc_list(head, tail, rx_desc); - *rx_bfs = 1; qdf_assert(0); - goto end; + goto discard_frag; } mpdu_frame_control_valid = @@ -1437,12 +1426,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, if (!mpdu_frame_control_valid) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "Invalid frame control field, dropping MPDU"); - qdf_nbuf_free(frag); - dp_rx_add_to_free_desc_list(head, tail, rx_desc); - *rx_bfs = 1; qdf_assert(0); - goto end; + goto discard_frag; } /* Current mpdu sequence */ @@ -1476,12 +1462,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, */ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "Rcvd unfragmented pkt on REO Err srng, dropping"); - qdf_nbuf_free(frag); - dp_rx_add_to_free_desc_list(head, tail, rx_desc); - *rx_bfs = 1; qdf_assert(0); - goto end; + goto discard_frag; } /* Check if the fragment is for the same sequence or a different one */ @@ -1529,25 +1512,26 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, if ((fragno == 0) && (status == QDF_STATUS_SUCCESS) && (rx_reorder_array_elem->head == frag)) { + qdf_assert_always(ring_desc); status = dp_rx_defrag_save_info_from_ring_desc(ring_desc, rx_desc, peer, tid); if (status != QDF_STATUS_SUCCESS) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, "%s: Unable to store ring desc !", __func__); - goto end; + goto discard_frag; } } else { dp_rx_add_to_free_desc_list(head, tail, rx_desc); *rx_bfs = 1; /* Return the non-head link desc */ - if (dp_rx_link_desc_return(soc, ring_desc, - HAL_BM_ACTION_PUT_IN_IDLE_LIST) != - QDF_STATUS_SUCCESS) + if (ring_desc && + dp_rx_link_desc_return(soc, ring_desc, + HAL_BM_ACTION_PUT_IN_IDLE_LIST) != + QDF_STATUS_SUCCESS) QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Failed to return link desc", - __func__); + "%s: Failed to return link desc", __func__); } @@ -1613,6 +1597,16 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, return QDF_STATUS_SUCCESS; +discard_frag: + qdf_nbuf_free(frag); + dp_rx_add_to_free_desc_list(head, tail, rx_desc); + if (dp_rx_link_desc_return(soc, ring_desc, + HAL_BM_ACTION_PUT_IN_IDLE_LIST) != + QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to return link desc", __func__); + *rx_bfs = 1; + end: if (peer) dp_peer_unref_del_find_by_id(peer); @@ -1641,30 +1635,21 @@ end: * Return: uint32_t: No. of elements processed */ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, - struct hal_rx_mpdu_desc_info *mpdu_desc_info, - uint8_t *mac_id, - uint32_t quota) + struct hal_rx_mpdu_desc_info *mpdu_desc_info, + struct dp_rx_desc *rx_desc, + uint8_t *mac_id, + uint32_t quota) { uint32_t rx_bufs_used = 0; - void *link_desc_va; - struct hal_buf_info buf_info; - struct hal_rx_msdu_list msdu_list; /* per MPDU list of MSDUs */ qdf_nbuf_t msdu = NULL; uint32_t tid, msdu_len; - int idx, rx_bfs = 0; + int rx_bfs = 0; struct dp_pdev *pdev; QDF_STATUS status = QDF_STATUS_SUCCESS; - struct dp_rx_desc *rx_desc = NULL; qdf_assert(soc); qdf_assert(mpdu_desc_info); - - /* Fragment from a valid peer */ - hal_rx_reo_buf_paddr_get(ring_desc, &buf_info); - - link_desc_va = dp_rx_cookie_2_link_desc_va(soc, &buf_info); - - qdf_assert(link_desc_va); + qdf_assert(rx_desc); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, "Number of MSDUs to process, num_msdus: %d", @@ -1677,82 +1662,39 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, return rx_bufs_used; } - /* Get msdu_list for the given MPDU */ - hal_rx_msdu_list_get(soc->hal_soc, link_desc_va, &msdu_list, - &mpdu_desc_info->msdu_count); + /* all buffers in MSDU link belong to same pdev */ + pdev = soc->pdev_list[rx_desc->pool_id]; + *mac_id = rx_desc->pool_id; - /* Process all MSDUs in the current MPDU */ - for (idx = 0; (idx < mpdu_desc_info->msdu_count); idx++) { - struct dp_rx_desc *rx_desc = - dp_rx_cookie_2_va_rxdma_buf(soc, - msdu_list.sw_cookie[idx]); + msdu = rx_desc->nbuf; - qdf_assert_always(rx_desc); + qdf_nbuf_unmap_single(soc->osdev, msdu, QDF_DMA_BIDIRECTIONAL); - /* all buffers in MSDU link belong to same pdev */ - pdev = soc->pdev_list[rx_desc->pool_id]; - *mac_id = rx_desc->pool_id; + rx_desc->rx_buf_start = qdf_nbuf_data(msdu); - msdu = rx_desc->nbuf; + msdu_len = hal_rx_msdu_start_msdu_len_get(rx_desc->rx_buf_start); - qdf_nbuf_unmap_single(soc->osdev, msdu, - QDF_DMA_BIDIRECTIONAL); + qdf_nbuf_set_pktlen(msdu, (msdu_len + RX_PKT_TLVS_LEN)); + qdf_nbuf_append_ext_list(msdu, NULL, 0); - rx_desc->rx_buf_start = qdf_nbuf_data(msdu); + tid = hal_rx_mpdu_start_tid_get(soc->hal_soc, rx_desc->rx_buf_start); - msdu_len = hal_rx_msdu_start_msdu_len_get( - rx_desc->rx_buf_start); + /* Process fragment-by-fragment */ + status = dp_rx_defrag_store_fragment(soc, ring_desc, + &pdev->free_list_head, + &pdev->free_list_tail, + mpdu_desc_info, + tid, rx_desc, &rx_bfs); - qdf_nbuf_set_pktlen(msdu, (msdu_len + RX_PKT_TLVS_LEN)); - qdf_nbuf_append_ext_list(msdu, NULL, 0); + if (rx_bfs) + rx_bufs_used++; - tid = hal_rx_mpdu_start_tid_get(soc->hal_soc, - rx_desc->rx_buf_start); - - /* Process fragment-by-fragment */ - status = dp_rx_defrag_store_fragment(soc, ring_desc, - &pdev->free_list_head, - &pdev->free_list_tail, - mpdu_desc_info, - tid, rx_desc, &rx_bfs); - - if (rx_bfs) - rx_bufs_used++; - - if (!QDF_IS_STATUS_SUCCESS(status)) { - QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "Rx Defrag err seq#:0x%x msdu_count:%d flags:%d", - mpdu_desc_info->mpdu_seq, - mpdu_desc_info->msdu_count, - mpdu_desc_info->mpdu_flags); - - /* No point in processing rest of the fragments */ - break; - } - } - - if (!QDF_IS_STATUS_SUCCESS(status)) { - /* drop any remaining buffers in current descriptor */ - idx++; - for (; (idx < mpdu_desc_info->msdu_count); idx++) { - rx_desc = - dp_rx_cookie_2_va_rxdma_buf(soc, - msdu_list.sw_cookie[idx]); - qdf_assert(rx_desc); - msdu = rx_desc->nbuf; - qdf_nbuf_unmap_single(soc->osdev, msdu, - QDF_DMA_BIDIRECTIONAL); - qdf_nbuf_free(msdu); - dp_rx_add_to_free_desc_list(&pdev->free_list_head, - &pdev->free_list_tail, - rx_desc); - rx_bufs_used++; - } - if (dp_rx_link_desc_return(soc, ring_desc, - HAL_BM_ACTION_PUT_IN_IDLE_LIST) != - QDF_STATUS_SUCCESS) - dp_err("Failed to return link desc"); - } + if (!QDF_IS_STATUS_SUCCESS(status)) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Rx Defrag err seq#:0x%x msdu_count:%d flags:%d", + mpdu_desc_info->mpdu_seq, + mpdu_desc_info->msdu_count, + mpdu_desc_info->mpdu_flags); return rx_bufs_used; } @@ -1771,6 +1713,11 @@ QDF_STATUS dp_rx_defrag_add_last_frag(struct dp_soc *soc, if (rx_reorder_array_elem->head && rxseq != rx_tid->curr_seq_num) { + /* Drop stored fragments if out of sequence + * fragment is received + */ + dp_rx_reorder_flush_frag(peer, tid); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, "%s: No list found for TID %d Seq# %d", __func__, tid, rxseq); @@ -1833,8 +1780,7 @@ QDF_STATUS dp_rx_defrag_add_last_frag(struct dp_soc *soc, __func__); } else { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: Frag seq reinjection failed", - __func__); + "%s: Frag seq reinjection failed", __func__); dp_rx_return_head_frag_desc(peer, tid); } diff --git a/dp/wifi3.0/dp_rx_defrag.h b/dp/wifi3.0/dp_rx_defrag.h index 15ef478255..404446ec95 100644 --- a/dp/wifi3.0/dp_rx_defrag.h +++ b/dp/wifi3.0/dp_rx_defrag.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the @@ -57,6 +57,7 @@ struct dp_rx_defrag_cipher { uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, struct hal_rx_mpdu_desc_info *mpdu_desc_info, + struct dp_rx_desc *rx_desc, uint8_t *mac_id, uint32_t quota); diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 481bd31011..6a38f74e0d 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1084,6 +1084,7 @@ dp_rx_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) void *link_desc_va; struct hal_rx_msdu_list msdu_list; /* MSDU's per MPDU */ uint16_t num_msdus; + struct dp_rx_desc *rx_desc = NULL; /* Debug -- Remove later */ qdf_assert(soc && hal_ring); @@ -1138,6 +1139,12 @@ dp_rx_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) hal_rx_msdu_list_get(soc->hal_soc, link_desc_va, &msdu_list, &num_msdus); + rx_desc = dp_rx_cookie_2_va_rxdma_buf(soc, + msdu_list.sw_cookie[0]); + qdf_assert_always(rx_desc); + + mac_id = rx_desc->pool_id; + if (qdf_unlikely((msdu_list.rbm[0] != DP_WBM2SW_RBM) && (msdu_list.rbm[0] != HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST))) { @@ -1157,10 +1164,22 @@ dp_rx_err_process(struct dp_soc *soc, void *hal_ring, uint32_t quota) hal_rx_mpdu_desc_info_get(ring_desc, &mpdu_desc_info); if (mpdu_desc_info.mpdu_flags & HAL_MPDU_F_FRAGMENT) { - /* TODO */ + /* + * We only handle one msdu per link desc for fragmented + * case. We drop the msdus and release the link desc + * back if there are more than one msdu in link desc. + */ + if (qdf_unlikely(num_msdus > 1)) { + count = dp_rx_msdus_drop(soc, ring_desc, + &mpdu_desc_info, + &mac_id, quota); + rx_bufs_reaped[mac_id] += count; + continue; + } + count = dp_rx_frag_handle(soc, ring_desc, &mpdu_desc_info, - &mac_id, quota); + rx_desc, &mac_id, quota); rx_bufs_reaped[mac_id] += count; DP_STATS_INC(soc, rx.rx_frags, 1);