]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: free skb during idr cleanup callback
authorKarthik M <quic_karm@quicinc.com>
Tue, 23 Sep 2025 22:03:16 +0000 (15:03 -0700)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Mon, 6 Oct 2025 16:48:55 +0000 (09:48 -0700)
ath12k just like ath11k [1] did not handle skb cleanup during idr
cleanup callback. Both ath12k_mac_vif_txmgmt_idr_remove() and
ath12k_mac_tx_mgmt_pending_free() performed idr cleanup and DMA
unmapping for skb but only ath12k_mac_tx_mgmt_pending_free() freed
skb. As a result, during vdev deletion a memory leak occurs.

Refactor all clean up steps into a new function. New function
ath12k_mac_tx_mgmt_free() creates a centralized area where idr
cleanup, DMA unmapping for skb and freeing skb is performed. Utilize
skb pointer given by idr_remove(), instead of passed as a function
argument because IDR will be protected by locking. This will prevent
concurrent modification of the same IDR.

Now ath12k_mac_tx_mgmt_pending_free() and
ath12k_mac_vif_txmgmt_idr_remove() call ath12k_mac_tx_mgmt_free().

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1

Link: https://lore.kernel.org/r/1637832614-13831-1-git-send-email-quic_srirrama@quicinc.com
Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
Signed-off-by: Karthik M <quic_karm@quicinc.com>
Signed-off-by: Muna Sinada <muna.sinada@oss.qualcomm.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20250923220316.1595758-1-muna.sinada@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/mac.c

index 3a3965b79942d2ae0ce57965dc1951fb53993af3..2fad2df1d6ce50ca6ff68f7e4ba5075abc8b56f9 100644 (file)
@@ -8304,23 +8304,32 @@ static void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb)
                wake_up(&ar->txmgmt_empty_waitq);
 }
 
-int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+static void ath12k_mac_tx_mgmt_free(struct ath12k *ar, int buf_id)
 {
-       struct sk_buff *msdu = skb;
+       struct sk_buff *msdu;
        struct ieee80211_tx_info *info;
-       struct ath12k *ar = ctx;
-       struct ath12k_base *ab = ar->ab;
 
        spin_lock_bh(&ar->txmgmt_idr_lock);
-       idr_remove(&ar->txmgmt_idr, buf_id);
+       msdu = idr_remove(&ar->txmgmt_idr, buf_id);
        spin_unlock_bh(&ar->txmgmt_idr_lock);
-       dma_unmap_single(ab->dev, ATH12K_SKB_CB(msdu)->paddr, msdu->len,
+
+       if (!msdu)
+               return;
+
+       dma_unmap_single(ar->ab->dev, ATH12K_SKB_CB(msdu)->paddr, msdu->len,
                         DMA_TO_DEVICE);
 
        info = IEEE80211_SKB_CB(msdu);
        memset(&info->status, 0, sizeof(info->status));
 
-       ath12k_mgmt_over_wmi_tx_drop(ar, skb);
+       ath12k_mgmt_over_wmi_tx_drop(ar, msdu);
+}
+
+int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
+{
+       struct ath12k *ar = ctx;
+
+       ath12k_mac_tx_mgmt_free(ar, buf_id);
 
        return 0;
 }
@@ -8329,17 +8338,10 @@ static int ath12k_mac_vif_txmgmt_idr_remove(int buf_id, void *skb, void *ctx)
 {
        struct ieee80211_vif *vif = ctx;
        struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
-       struct sk_buff *msdu = skb;
        struct ath12k *ar = skb_cb->ar;
-       struct ath12k_base *ab = ar->ab;
 
-       if (skb_cb->vif == vif) {
-               spin_lock_bh(&ar->txmgmt_idr_lock);
-               idr_remove(&ar->txmgmt_idr, buf_id);
-               spin_unlock_bh(&ar->txmgmt_idr_lock);
-               dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len,
-                                DMA_TO_DEVICE);
-       }
+       if (skb_cb->vif == vif)
+               ath12k_mac_tx_mgmt_free(ar, buf_id);
 
        return 0;
 }