mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 16:31:13 +00:00
930e702d72
Synchronize the ath11k backports with the current ath-next tree. This replaces the management TLV pending fix with the upstreamed one, fixes traffic flooding when AP and monitor modes are used at the same time, fixes QCN9074 always showing -95 dBm for station RSSI in dumps, fixes potential crash on boot if spectral scan is enabled due to writing to unitialized memory and adds 11d scan offloading for WCN6750 and WCN6855. Signed-off-by: Robert Marko <robimarko@gmail.com>
131 lines
4.2 KiB
Diff
131 lines
4.2 KiB
Diff
From 68e93ac5a31d4975b25f819b2dfe914c72abc3bb Mon Sep 17 00:00:00 2001
|
|
From: Harshitha Prem <quic_hprem@quicinc.com>
|
|
Date: Wed, 15 Mar 2023 12:24:43 +0200
|
|
Subject: [PATCH] wifi: ath11k: fix BUFFER_DONE read on monitor ring rx buffer
|
|
|
|
Perform dma_sync_single_for_cpu() on monitor ring rx buffer before
|
|
reading BUFFER_DONE tag and do dma_unmap_single() only after device
|
|
had set BUFFER_DONE tag to the buffer.
|
|
|
|
Also when BUFFER_DONE tag is not set, allow the buffer to get read
|
|
next time without freeing skb.
|
|
|
|
This helps to fix AP+Monitor VAP with flood traffic scenario to see
|
|
monitor ring rx buffer overrun missing BUFFER_DONE tag to be set.
|
|
|
|
Also remove redundant rx dma buf free performed on DP
|
|
rx_mon_status_refill_ring.
|
|
|
|
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
|
|
|
Signed-off-by: Sathishkumar Muruganandam <quic_murugana@quicinc.com>
|
|
Signed-off-by: Harshitha Prem <quic_hprem@quicinc.com>
|
|
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
|
|
Link: https://lore.kernel.org/r/20230309164434.32660-1-quic_hprem@quicinc.com
|
|
---
|
|
drivers/net/wireless/ath/ath11k/dp_rx.c | 57 ++++++++++---------------
|
|
1 file changed, 23 insertions(+), 34 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
@@ -435,7 +435,6 @@ fail_free_skb:
|
|
static int ath11k_dp_rxdma_buf_ring_free(struct ath11k *ar,
|
|
struct dp_rxdma_ring *rx_ring)
|
|
{
|
|
- struct ath11k_pdev_dp *dp = &ar->dp;
|
|
struct sk_buff *skb;
|
|
int buf_id;
|
|
|
|
@@ -453,28 +452,6 @@ static int ath11k_dp_rxdma_buf_ring_free
|
|
idr_destroy(&rx_ring->bufs_idr);
|
|
spin_unlock_bh(&rx_ring->idr_lock);
|
|
|
|
- /* if rxdma1_enable is false, mon_status_refill_ring
|
|
- * isn't setup, so don't clean.
|
|
- */
|
|
- if (!ar->ab->hw_params.rxdma1_enable)
|
|
- return 0;
|
|
-
|
|
- rx_ring = &dp->rx_mon_status_refill_ring[0];
|
|
-
|
|
- spin_lock_bh(&rx_ring->idr_lock);
|
|
- idr_for_each_entry(&rx_ring->bufs_idr, skb, buf_id) {
|
|
- idr_remove(&rx_ring->bufs_idr, buf_id);
|
|
- /* XXX: Understand where internal driver does this dma_unmap
|
|
- * of rxdma_buffer.
|
|
- */
|
|
- dma_unmap_single(ar->ab->dev, ATH11K_SKB_RXCB(skb)->paddr,
|
|
- skb->len + skb_tailroom(skb), DMA_BIDIRECTIONAL);
|
|
- dev_kfree_skb_any(skb);
|
|
- }
|
|
-
|
|
- idr_destroy(&rx_ring->bufs_idr);
|
|
- spin_unlock_bh(&rx_ring->idr_lock);
|
|
-
|
|
return 0;
|
|
}
|
|
|
|
@@ -3029,39 +3006,51 @@ static int ath11k_dp_rx_reap_mon_status_
|
|
|
|
spin_lock_bh(&rx_ring->idr_lock);
|
|
skb = idr_find(&rx_ring->bufs_idr, buf_id);
|
|
+ spin_unlock_bh(&rx_ring->idr_lock);
|
|
+
|
|
if (!skb) {
|
|
ath11k_warn(ab, "rx monitor status with invalid buf_id %d\n",
|
|
buf_id);
|
|
- spin_unlock_bh(&rx_ring->idr_lock);
|
|
pmon->buf_state = DP_MON_STATUS_REPLINISH;
|
|
goto move_next;
|
|
}
|
|
|
|
- idr_remove(&rx_ring->bufs_idr, buf_id);
|
|
- spin_unlock_bh(&rx_ring->idr_lock);
|
|
-
|
|
rxcb = ATH11K_SKB_RXCB(skb);
|
|
|
|
- dma_unmap_single(ab->dev, rxcb->paddr,
|
|
- skb->len + skb_tailroom(skb),
|
|
- DMA_FROM_DEVICE);
|
|
+ dma_sync_single_for_cpu(ab->dev, rxcb->paddr,
|
|
+ skb->len + skb_tailroom(skb),
|
|
+ DMA_FROM_DEVICE);
|
|
|
|
tlv = (struct hal_tlv_hdr *)skb->data;
|
|
if (FIELD_GET(HAL_TLV_HDR_TAG, tlv->tl) !=
|
|
HAL_RX_STATUS_BUFFER_DONE) {
|
|
- ath11k_warn(ab, "mon status DONE not set %lx\n",
|
|
+ ath11k_warn(ab, "mon status DONE not set %lx, buf_id %d\n",
|
|
FIELD_GET(HAL_TLV_HDR_TAG,
|
|
- tlv->tl));
|
|
- dev_kfree_skb_any(skb);
|
|
+ tlv->tl), buf_id);
|
|
+ /* If done status is missing, hold onto status
|
|
+ * ring until status is done for this status
|
|
+ * ring buffer.
|
|
+ * Keep HP in mon_status_ring unchanged,
|
|
+ * and break from here.
|
|
+ * Check status for same buffer for next time
|
|
+ */
|
|
pmon->buf_state = DP_MON_STATUS_NO_DMA;
|
|
- goto move_next;
|
|
+ break;
|
|
}
|
|
|
|
+ spin_lock_bh(&rx_ring->idr_lock);
|
|
+ idr_remove(&rx_ring->bufs_idr, buf_id);
|
|
+ spin_unlock_bh(&rx_ring->idr_lock);
|
|
if (ab->hw_params.full_monitor_mode) {
|
|
ath11k_dp_rx_mon_update_status_buf_state(pmon, tlv);
|
|
if (paddr == pmon->mon_status_paddr)
|
|
pmon->buf_state = DP_MON_STATUS_MATCH;
|
|
}
|
|
+
|
|
+ dma_unmap_single(ab->dev, rxcb->paddr,
|
|
+ skb->len + skb_tailroom(skb),
|
|
+ DMA_FROM_DEVICE);
|
|
+
|
|
__skb_queue_tail(skb_list, skb);
|
|
} else {
|
|
pmon->buf_state = DP_MON_STATUS_REPLINISH;
|