wlan-ap-Telecominfraproject/feeds/ipq95xx/mac80211/patches/qca/668-ath12k-fix-memory-leaks-during-multicast-tx.patch
John Crispin 144c5d00f4 ipq95xx/mac80211: update to ATH12.3-CS
Signed-off-by: John Crispin <john@phrozen.org>
2024-02-28 18:56:21 +01:00

242 lines
8.2 KiB
Diff

From 82a22abc253e4256be7e634912ec0f728465cb96 Mon Sep 17 00:00:00 2001
From: P Praneesh <quic_ppranees@quicinc.com>
Date: Wed, 28 Sep 2022 16:07:14 +0530
Subject: [PATCH] ath12k: fix memory leaks during multicast tx
SKBs which are allocated for MSDU extension descriptors are not freed up
properly while receiving tx completion for the corresponding SKB. This
causes memory leak while AP transmits multicast frames.
Fix it by releasing the memory used by extended SKB during tx completion.
Also, remove kfree usage for releasing SKB and replace it with the
dev_kfree_skb_any().
Fixes - 1e5aee4a23c63b : pkg-upgrade : "ath12k: add software encryption support for RAW mode"
Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
---
drivers/net/wireless/ath/ath12k/dp.c | 7 ++++
drivers/net/wireless/ath/ath12k/dp.h | 1 +
drivers/net/wireless/ath/ath12k/dp_tx.c | 52 ++++++++++++++++---------
3 files changed, 41 insertions(+), 19 deletions(-)
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1196,6 +1196,13 @@ static void ath12k_dp_cc_cleanup(struct
dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr,
skb->len, DMA_TO_DEVICE);
+
+ if (tx_desc_info->skb_ext_desc) {
+ dma_unmap_single(ab->dev, ATH12K_SKB_CB(skb)->paddr_ext_desc,
+ tx_desc_info->skb_ext_desc->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(tx_desc_info->skb_ext_desc);
+ }
+
dev_kfree_skb_any(skb);
}
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -281,6 +281,7 @@ struct ath12k_rx_desc_info {
struct ath12k_tx_desc_info {
struct list_head list;
struct sk_buff *skb;
+ struct sk_buff *skb_ext_desc;
u32 desc_id; /* Cookie */
u8 mac_id;
u8 pool_id;
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -72,6 +72,7 @@ static void ath12k_dp_tx_release_txbuf(s
{
spin_lock_bh(&dp->tx_desc_lock[ring_id]);
tx_desc->skb = NULL;
+ tx_desc->skb_ext_desc = NULL;
list_move_tail(&tx_desc->list, &dp->tx_desc_free_list[ring_id]);
spin_unlock_bh(&dp->tx_desc_lock[ring_id]);
}
@@ -286,7 +287,9 @@ tcl_ring_sel:
skb_ext_desc->len, DMA_TO_DEVICE);
ret = dma_mapping_error(ab->dev, ti.paddr);
if (ret) {
- kfree(skb_ext_desc);
+ atomic_inc(&ab->soc_stats.tx_err.misc_fail);
+ ath12k_warn(ab, "Failed to DMA map data Tx buffer\n");
+ dev_kfree_skb_any(skb_ext_desc);
goto fail_unmap_dma;
}
@@ -294,6 +297,7 @@ tcl_ring_sel:
ti.type = HAL_TCL_DESC_TYPE_EXT_DESC;
skb_cb->paddr_ext_desc = ti.paddr;
+ tx_desc->skb_ext_desc = skb_ext_desc;
}
hal_ring_id = tx_ring->tcl_data_ring.ring_id;
@@ -324,7 +328,7 @@ tcl_ring_sel:
ring_selector++;
}
- goto fail_unmap_dma;
+ goto fail_unmap_dma_ext_desc;
}
ath12k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc, &ti);
@@ -340,10 +344,15 @@ tcl_ring_sel:
return 0;
+fail_unmap_dma_ext_desc:
+ if (unlikely(msdu_ext_desc)) {
+ dma_unmap_single(ab->dev, ti.paddr,
+ skb_ext_desc->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb_ext_desc);
+ }
+
fail_unmap_dma:
- dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
- dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc,
- sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE);
+ dma_unmap_single(ab->dev, skb_cb->paddr, skb->len, DMA_TO_DEVICE);
fail_remove_tx_buf:
ath12k_dp_tx_release_txbuf(dp, tx_desc, ti.ring_id);
@@ -355,7 +364,8 @@ fail_remove_tx_buf:
static void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab,
struct sk_buff *msdu, u8 mac_id,
- struct dp_tx_ring *tx_ring)
+ struct dp_tx_ring *tx_ring,
+ struct sk_buff *skb_ext_desc)
{
struct ath12k *ar;
struct ath12k_skb_cb *skb_cb;
@@ -364,10 +374,12 @@ static void ath12k_dp_tx_free_txbuf(stru
dma_unmap_single_attrs(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
- if (unlikely(skb_cb->paddr_ext_desc))
+ if (unlikely(skb_ext_desc)) {
dma_unmap_single_attrs(ab->dev, skb_cb->paddr_ext_desc,
- sizeof(struct hal_tx_msdu_ext_desc),
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ skb_ext_desc->len,
+ DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ dev_kfree_skb_any(skb_ext_desc);
+ }
dev_kfree_skb_any(msdu);
@@ -380,7 +392,8 @@ static void
ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab,
struct sk_buff *msdu,
struct dp_tx_ring *tx_ring,
- struct ath12k_dp_htt_wbm_tx_status *ts)
+ struct ath12k_dp_htt_wbm_tx_status *ts,
+ struct sk_buff *skb_ext_desc)
{
struct ieee80211_tx_info *info;
struct ath12k_skb_cb *skb_cb;
@@ -397,9 +410,11 @@ ath12k_dp_tx_htt_tx_complete_buf(struct
wake_up(&ar->dp.tx_empty_waitq);
dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
- if (unlikely(skb_cb->paddr_ext_desc))
+ if (unlikely(skb_ext_desc)) {
dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc,
- sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE);
+ skb_ext_desc->len, DMA_TO_DEVICE);
+ dev_kfree_skb_any(skb_ext_desc);
+ }
flags = skb_cb->flags;
@@ -447,7 +462,8 @@ static void
ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab,
void *desc, u8 mac_id,
struct sk_buff *msdu,
- struct dp_tx_ring *tx_ring)
+ struct dp_tx_ring *tx_ring,
+ struct sk_buff *skb_ext_desc)
{
struct htt_tx_wbm_completion *status_desc;
struct ath12k_dp_htt_wbm_tx_status ts = {0};
@@ -465,11 +481,11 @@ ath12k_dp_tx_process_htt_tx_complete(str
ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
ts.ack_rssi = u32_get_bits(status_desc->info2,
HTT_TX_WBM_COMP_INFO2_ACK_RSSI);
- ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts);
+ ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts, skb_ext_desc);
break;
case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
- ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring);
+ ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring, skb_ext_desc);
break;
case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY:
/* This event is to be handled only when the driver decides to
@@ -637,7 +653,8 @@ static inline void ath12k_dp_tx_status_p
static void ath12k_dp_tx_complete_msdu(struct ath12k *ar,
struct sk_buff *msdu,
struct hal_wbm_release_ring *tx_status,
- enum hal_wbm_rel_src_module buf_rel_source)
+ enum hal_wbm_rel_src_module buf_rel_source,
+ struct sk_buff *skb_ext_desc)
{
struct ieee80211_tx_status status = { 0 };
@@ -663,10 +680,12 @@ static void ath12k_dp_tx_complete_msdu(s
dma_unmap_single_attrs(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
- if (unlikely(skb_cb->paddr_ext_desc))
+ if (unlikely(skb_cb->paddr_ext_desc)) {
dma_unmap_single_attrs(ab->dev, skb_cb->paddr_ext_desc,
- sizeof(struct hal_tx_msdu_ext_desc),
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ skb_ext_desc->len,
+ DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ dev_kfree_skb_any(skb_ext_desc);
+ }
flags = skb_cb->flags;
@@ -801,7 +820,7 @@ void ath12k_dp_tx_completion_handler(str
int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id;
struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id];
struct ath12k_tx_desc_info *tx_desc = NULL;
- struct sk_buff *msdu;
+ struct sk_buff *msdu, *skb_ext_desc;
struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id];
u32 *desc, desc_id;
u8 mac_id;
@@ -861,7 +880,7 @@ void ath12k_dp_tx_completion_handler(str
msdu = tx_desc->skb;
mac_id = tx_desc->mac_id;
-
+ skb_ext_desc = tx_desc->skb_ext_desc;
/* Release descriptor as soon as extracting necessary info
* to reduce contention
*/
@@ -872,7 +891,7 @@ void ath12k_dp_tx_completion_handler(str
ath12k_dp_tx_process_htt_tx_complete(ab,
(void *)tx_status,
mac_id, msdu,
- tx_ring);
+ tx_ring, skb_ext_desc);
continue;
}
@@ -881,7 +900,7 @@ void ath12k_dp_tx_completion_handler(str
if (atomic_dec_and_test(&ar->dp.num_tx_pending))
wake_up(&ar->dp.tx_empty_waitq);
- ath12k_dp_tx_complete_msdu(ar, msdu, tx_status, buf_rel_source);
+ ath12k_dp_tx_complete_msdu(ar, msdu, tx_status, buf_rel_source, skb_ext_desc);
}
}