mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-24 21:02:35 +00:00
242 lines
8.2 KiB
Diff
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);
|
|
}
|
|
}
|
|
|