qcacmn: Release link descriptors on defrag errors
Link descriptors should be returned to WBM release ring if fragments are not reinjected due to defrag errors. Change-Id: Ia37db9f195f6848092918cf7cc221dc50e827ac5
This commit is contained in:

committed by
nshrivas

parent
eec199494e
commit
6fb46e2759
@@ -6389,6 +6389,8 @@ dp_print_soc_rx_stats(struct dp_soc *soc)
|
|||||||
DP_PRINT_STATS("HAL Ring Access Fail = %d",
|
DP_PRINT_STATS("HAL Ring Access Fail = %d",
|
||||||
soc->stats.rx.err.hal_ring_access_fail);
|
soc->stats.rx.err.hal_ring_access_fail);
|
||||||
DP_PRINT_STATS("RX frags: %d", soc->stats.rx.rx_frags);
|
DP_PRINT_STATS("RX frags: %d", soc->stats.rx.rx_frags);
|
||||||
|
DP_PRINT_STATS("RX frag wait: %d", soc->stats.rx.rx_frag_wait);
|
||||||
|
DP_PRINT_STATS("RX frag err: %d", soc->stats.rx.rx_frag_err);
|
||||||
DP_PRINT_STATS("RX HP out_of_sync: %d", soc->stats.rx.hp_oos);
|
DP_PRINT_STATS("RX HP out_of_sync: %d", soc->stats.rx.hp_oos);
|
||||||
|
|
||||||
for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) {
|
for (i = 0; i < HAL_RXDMA_ERR_MAX; i++) {
|
||||||
|
@@ -23,6 +23,7 @@
|
|||||||
#include "hal_api.h"
|
#include "hal_api.h"
|
||||||
#include "qdf_trace.h"
|
#include "qdf_trace.h"
|
||||||
#include "qdf_nbuf.h"
|
#include "qdf_nbuf.h"
|
||||||
|
#include "dp_internal.h"
|
||||||
#include "dp_rx_defrag.h"
|
#include "dp_rx_defrag.h"
|
||||||
#include <enet.h> /* LLC_SNAP_HDR_LEN */
|
#include <enet.h> /* LLC_SNAP_HDR_LEN */
|
||||||
#include "dp_rx_defrag.h"
|
#include "dp_rx_defrag.h"
|
||||||
@@ -182,6 +183,7 @@ void dp_rx_defrag_waitlist_flush(struct dp_soc *soc)
|
|||||||
|
|
||||||
TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder,
|
TAILQ_REMOVE(&soc->rx.defrag.waitlist, rx_reorder,
|
||||||
defrag_waitlist_elem);
|
defrag_waitlist_elem);
|
||||||
|
DP_STATS_DEC(soc, rx.rx_frag_wait, 1);
|
||||||
|
|
||||||
/* Move to temp list and clean-up later */
|
/* Move to temp list and clean-up later */
|
||||||
TAILQ_INSERT_TAIL(&temp_list, rx_reorder,
|
TAILQ_INSERT_TAIL(&temp_list, rx_reorder,
|
||||||
@@ -226,6 +228,7 @@ static void dp_rx_defrag_waitlist_add(struct dp_peer *peer, unsigned tid)
|
|||||||
qdf_spin_lock_bh(&psoc->rx.defrag.defrag_lock);
|
qdf_spin_lock_bh(&psoc->rx.defrag.defrag_lock);
|
||||||
TAILQ_INSERT_TAIL(&psoc->rx.defrag.waitlist, rx_reorder,
|
TAILQ_INSERT_TAIL(&psoc->rx.defrag.waitlist, rx_reorder,
|
||||||
defrag_waitlist_elem);
|
defrag_waitlist_elem);
|
||||||
|
DP_STATS_INC(psoc, rx.rx_frag_wait, 1);
|
||||||
qdf_spin_unlock_bh(&psoc->rx.defrag.defrag_lock);
|
qdf_spin_unlock_bh(&psoc->rx.defrag.defrag_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,9 +265,11 @@ void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid)
|
|||||||
rx_tid[rx_reorder->tid]);
|
rx_tid[rx_reorder->tid]);
|
||||||
|
|
||||||
/* Ensure it is TID for same peer */
|
/* Ensure it is TID for same peer */
|
||||||
if (peer_on_waitlist == peer && rx_reorder->tid == tid)
|
if (peer_on_waitlist == peer && rx_reorder->tid == tid) {
|
||||||
TAILQ_REMOVE(&soc->rx.defrag.waitlist,
|
TAILQ_REMOVE(&soc->rx.defrag.waitlist,
|
||||||
rx_reorder, defrag_waitlist_elem);
|
rx_reorder, defrag_waitlist_elem);
|
||||||
|
DP_STATS_DEC(soc, rx.rx_frag_wait, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
qdf_spin_unlock_bh(&soc->rx.defrag.defrag_lock);
|
qdf_spin_unlock_bh(&soc->rx.defrag.defrag_lock);
|
||||||
}
|
}
|
||||||
@@ -1384,7 +1389,7 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
|||||||
dp_rx_add_to_free_desc_list(head, tail, rx_desc);
|
dp_rx_add_to_free_desc_list(head, tail, rx_desc);
|
||||||
*rx_bfs = 1;
|
*rx_bfs = 1;
|
||||||
|
|
||||||
return QDF_STATUS_E_DEFRAG_ERROR;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdev = peer->vdev->pdev;
|
pdev = peer->vdev->pdev;
|
||||||
@@ -1458,11 +1463,9 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
|||||||
/* Drop stored fragments if out of sequence
|
/* Drop stored fragments if out of sequence
|
||||||
* fragment is received
|
* fragment is received
|
||||||
*/
|
*/
|
||||||
dp_rx_defrag_frames_free(rx_reorder_array_elem->head);
|
dp_rx_reorder_flush_frag(peer, tid);
|
||||||
|
|
||||||
rx_reorder_array_elem->head = NULL;
|
|
||||||
rx_reorder_array_elem->tail = NULL;
|
|
||||||
|
|
||||||
|
DP_STATS_INC(soc, rx.rx_frag_err, 1);
|
||||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
||||||
"%s mismatch, dropping earlier sequence ",
|
"%s mismatch, dropping earlier sequence ",
|
||||||
(rxseq == rx_tid->curr_seq_num)
|
(rxseq == rx_tid->curr_seq_num)
|
||||||
@@ -1474,7 +1477,6 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
|||||||
* new sequence number to be processed
|
* new sequence number to be processed
|
||||||
*/
|
*/
|
||||||
rx_tid->curr_seq_num = rxseq;
|
rx_tid->curr_seq_num = rxseq;
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Start of a new sequence */
|
/* Start of a new sequence */
|
||||||
@@ -1584,8 +1586,10 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc,
|
|||||||
return QDF_STATUS_SUCCESS;
|
return QDF_STATUS_SUCCESS;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
dp_peer_unref_del_find_by_id(peer);
|
if (peer)
|
||||||
|
dp_peer_unref_del_find_by_id(peer);
|
||||||
|
|
||||||
|
DP_STATS_INC(soc, rx.rx_frag_err, 1);
|
||||||
return QDF_STATUS_E_DEFRAG_ERROR;
|
return QDF_STATUS_E_DEFRAG_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1621,7 +1625,8 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
|
|||||||
uint32_t tid, msdu_len;
|
uint32_t tid, msdu_len;
|
||||||
int idx, rx_bfs = 0;
|
int idx, rx_bfs = 0;
|
||||||
struct dp_pdev *pdev;
|
struct dp_pdev *pdev;
|
||||||
QDF_STATUS status;
|
QDF_STATUS status = QDF_STATUS_SUCCESS;
|
||||||
|
struct dp_rx_desc *rx_desc = NULL;
|
||||||
|
|
||||||
qdf_assert(soc);
|
qdf_assert(soc);
|
||||||
qdf_assert(mpdu_desc_info);
|
qdf_assert(mpdu_desc_info);
|
||||||
@@ -1649,7 +1654,7 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
|
|||||||
&mpdu_desc_info->msdu_count);
|
&mpdu_desc_info->msdu_count);
|
||||||
|
|
||||||
/* Process all MSDUs in the current MPDU */
|
/* Process all MSDUs in the current MPDU */
|
||||||
for (idx = 0; (idx < mpdu_desc_info->msdu_count) && quota--; idx++) {
|
for (idx = 0; (idx < mpdu_desc_info->msdu_count); idx++) {
|
||||||
struct dp_rx_desc *rx_desc =
|
struct dp_rx_desc *rx_desc =
|
||||||
dp_rx_cookie_2_va_rxdma_buf(soc,
|
dp_rx_cookie_2_va_rxdma_buf(soc,
|
||||||
msdu_list.sw_cookie[idx]);
|
msdu_list.sw_cookie[idx]);
|
||||||
@@ -1698,6 +1703,29 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
return rx_bufs_used;
|
return rx_bufs_used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -592,6 +592,10 @@ struct dp_soc_stats {
|
|||||||
uint32_t err_ring_pkts;
|
uint32_t err_ring_pkts;
|
||||||
/* No of Fragments */
|
/* No of Fragments */
|
||||||
uint32_t rx_frags;
|
uint32_t rx_frags;
|
||||||
|
/* No of incomplete fragments in waitlist */
|
||||||
|
uint32_t rx_frag_wait;
|
||||||
|
/* Fragments dropped due to errors */
|
||||||
|
uint32_t rx_frag_err;
|
||||||
/* No of reinjected packets */
|
/* No of reinjected packets */
|
||||||
uint32_t reo_reinject;
|
uint32_t reo_reinject;
|
||||||
/* Head pointer Out of sync */
|
/* Head pointer Out of sync */
|
||||||
|
Reference in New Issue
Block a user