diff --git a/dp/wifi3.0/dp_rx_defrag.c b/dp/wifi3.0/dp_rx_defrag.c index 0f35d9cd59..437fd74830 100644 --- a/dp/wifi3.0/dp_rx_defrag.c +++ b/dp/wifi3.0/dp_rx_defrag.c @@ -83,6 +83,29 @@ static void dp_rx_clear_saved_desc_info(struct dp_peer *peer, unsigned tid) peer->rx_tid[tid].dst_ring_desc = NULL; } +static void dp_rx_return_head_frag_desc(struct dp_peer *peer, + unsigned int tid) +{ + struct dp_soc *soc; + struct dp_pdev *pdev; + struct dp_srng *dp_rxdma_srng; + struct rx_desc_pool *rx_desc_pool; + union dp_rx_desc_list_elem_t *head = NULL; + union dp_rx_desc_list_elem_t *tail = NULL; + + 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[0]; + + dp_rx_add_to_free_desc_list(&head, &tail, + peer->rx_tid[tid].head_frag_desc); + dp_rx_buffers_replenish(soc, 0, dp_rxdma_srng, rx_desc_pool, + 1, &head, &tail, HAL_RX_BUF_RBM_SW3_BM); + } +} + /* * dp_rx_reorder_flush_frag(): Flush the frag list * @peer: Pointer to the peer data structure @@ -96,11 +119,6 @@ void dp_rx_reorder_flush_frag(struct dp_peer *peer, unsigned int tid) { struct dp_soc *soc; - struct dp_srng *dp_rxdma_srng; - struct rx_desc_pool *rx_desc_pool; - struct dp_pdev *pdev; - union dp_rx_desc_list_elem_t *head = NULL; - union dp_rx_desc_list_elem_t *tail = NULL; QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, FL("Flushing TID %d"), tid); @@ -111,8 +129,7 @@ void dp_rx_reorder_flush_frag(struct dp_peer *peer, return; } - pdev = peer->vdev->pdev; - soc = pdev->soc; + soc = peer->vdev->pdev->soc; if (peer->rx_tid[tid].dst_ring_desc) { if (dp_rx_link_desc_return(soc, @@ -124,16 +141,7 @@ void dp_rx_reorder_flush_frag(struct dp_peer *peer, __func__); } - if (peer->rx_tid[tid].head_frag_desc) { - dp_rxdma_srng = &pdev->rx_refill_buf_ring; - rx_desc_pool = &soc->rx_desc_buf[0]; - - dp_rx_add_to_free_desc_list(&head, &tail, - peer->rx_tid[tid].head_frag_desc); - dp_rx_buffers_replenish(soc, 0, dp_rxdma_srng, rx_desc_pool, - 1, &head, &tail); - } - + dp_rx_return_head_frag_desc(peer, tid); dp_rx_defrag_cleanup(peer, tid); } @@ -1531,10 +1539,11 @@ static QDF_STATUS dp_rx_defrag_store_fragment(struct dp_soc *soc, rx_reorder_array_elem->tail = NULL; QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, "Fragmented sequence successfully reinjected"); - } - else + } else { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, "Fragmented sequence reinjection failed"); + dp_rx_return_head_frag_desc(peer, tid); + } dp_rx_defrag_cleanup(peer, tid); return QDF_STATUS_SUCCESS; @@ -1646,3 +1655,86 @@ uint32_t dp_rx_frag_handle(struct dp_soc *soc, void *ring_desc, return rx_bufs_used; } + +QDF_STATUS dp_rx_defrag_add_last_frag(struct dp_soc *soc, + struct dp_peer *peer, uint16_t tid, + uint16_t rxseq, qdf_nbuf_t nbuf) +{ + struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; + struct dp_rx_reorder_array_elem *rx_reorder_array_elem; + uint8_t all_frag_present; + QDF_STATUS status; + + rx_reorder_array_elem = peer->rx_tid[tid].array; + + if (rx_reorder_array_elem->head && + rxseq != rx_tid->curr_seq_num) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: No list found for TID %d Seq# %d\n", + __func__, tid, rxseq); + qdf_nbuf_free(nbuf); + goto fail; + } + + status = dp_rx_defrag_fraglist_insert(peer, tid, + &rx_reorder_array_elem->head, + &rx_reorder_array_elem->tail, nbuf, + &all_frag_present); + + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s Fragment insert failed\n", __func__); + + goto fail; + } + + if (soc->rx.flags.defrag_timeout_check) + dp_rx_defrag_waitlist_remove(peer, tid); + + if (!all_frag_present) { + uint32_t now_ms = + qdf_system_ticks_to_msecs(qdf_system_ticks()); + + peer->rx_tid[tid].defrag_timeout_ms = + now_ms + soc->rx.defrag.timeout_ms; + + dp_rx_defrag_waitlist_add(peer, tid); + + return QDF_STATUS_SUCCESS; + } + + status = dp_rx_defrag(peer, tid, rx_reorder_array_elem->head, + rx_reorder_array_elem->tail); + + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s Fragment processing failed\n", __func__); + + dp_rx_return_head_frag_desc(peer, tid); + dp_rx_defrag_cleanup(peer, tid); + + goto fail; + } + + /* Re-inject the fragments back to REO for further processing */ + status = dp_rx_defrag_reo_reinject(peer, tid, + rx_reorder_array_elem->head); + if (QDF_IS_STATUS_SUCCESS(status)) { + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s: Frag seq successfully reinjected\n", + __func__); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Frag seq reinjection failed\n", + __func__); + dp_rx_return_head_frag_desc(peer, tid); + } + + dp_rx_defrag_cleanup(peer, tid); + return QDF_STATUS_SUCCESS; + +fail: + return QDF_STATUS_E_DEFRAG_ERROR; +} diff --git a/dp/wifi3.0/dp_rx_defrag.h b/dp/wifi3.0/dp_rx_defrag.h index 5ff3c0b7de..2e141908cc 100644 --- a/dp/wifi3.0/dp_rx_defrag.h +++ b/dp/wifi3.0/dp_rx_defrag.h @@ -144,4 +144,8 @@ void dp_rx_reorder_flush_frag(struct dp_peer *peer, unsigned int tid); void dp_rx_defrag_waitlist_remove(struct dp_peer *peer, unsigned tid); void dp_rx_defrag_cleanup(struct dp_peer *peer, unsigned tid); + +QDF_STATUS dp_rx_defrag_add_last_frag(struct dp_soc *soc, + struct dp_peer *peer, uint16_t tid, + uint16_t rxseq, qdf_nbuf_t nbuf); #endif /* _DP_RX_DEFRAG_H */ diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index e4c49f0fff..29399b13c5 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -794,7 +794,9 @@ dp_rx_process_mic_error(struct dp_soc *soc, struct ieee80211_frame *wh; uint8_t *rx_pkt_hdr; struct dp_peer *peer; - uint16_t peer_id; + uint16_t peer_id, rx_seq, fragno; + unsigned int tid; + QDF_STATUS status; if (!hal_rx_msdu_end_first_msdu_get(rx_tlv_hdr)) return; @@ -824,6 +826,24 @@ dp_rx_process_mic_error(struct dp_soc *soc, goto fail; } + tid = hal_rx_mpdu_start_tid_get(qdf_nbuf_data(nbuf)); + rx_seq = (((*(uint16_t *)wh->i_seq) & + IEEE80211_SEQ_SEQ_MASK) >> + IEEE80211_SEQ_SEQ_SHIFT); + + fragno = dp_rx_frag_get_mpdu_frag_number(qdf_nbuf_data(nbuf)); + + /* Can get only last fragment */ + if (fragno) { + status = dp_rx_defrag_add_last_frag(soc, peer, + tid, rx_seq, nbuf); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Frag pkt seq# %d frag# %d consumed status %d !\n", + __func__, rx_seq, fragno, status); + return; + } + tops = pdev->soc->cdp_soc.ol_ops; if (tops->rx_mic_error) tops->rx_mic_error(pdev->osif_pdev, vdev->vdev_id, wh);