mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
15abf8d18b
Synchronize the ath11k backports with the current ath-next tree. This replaces the 160MHz with the upstreamed one, fixes 6GHz only WIPHY registration, allows SAR usage on WCN6750 and plenty of REO fixes. Signed-off-by: Robert Marko <robimarko@gmail.com>
145 lines
4.5 KiB
Diff
145 lines
4.5 KiB
Diff
From 93a91f40c25c3d0e61f8540a7accf105090f9995 Mon Sep 17 00:00:00 2001
|
|
From: Harshitha Prem <quic_hprem@quicinc.com>
|
|
Date: Mon, 17 Apr 2023 13:35:00 +0300
|
|
Subject: [PATCH] wifi: ath11k: fix double free of peer rx_tid during reo cmd
|
|
failure
|
|
|
|
Peer rx_tid is locally copied thrice during peer_rx_tid_cleanup to
|
|
send REO_CMD_UPDATE_RX_QUEUE followed by REO_CMD_FLUSH_CACHE to flush
|
|
all aged REO descriptors from HW cache.
|
|
|
|
When sending REO_CMD_FLUSH_CACHE fails, we do dma unmap of already
|
|
mapped rx_tid->vaddr and free it. This is not checked during
|
|
reo_cmd_list_cleanup() and dp_reo_cmd_free() before trying to free and
|
|
unmap again.
|
|
|
|
Fix this by setting rx_tid->vaddr NULL in rx tid delete and also
|
|
wherever freeing it to check in reo_cmd_list_cleanup() and
|
|
reo_cmd_free() before trying to free again.
|
|
|
|
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
|
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/20230403182420.23375-2-quic_hprem@quicinc.com
|
|
---
|
|
drivers/net/wireless/ath/ath11k/dp_rx.c | 43 ++++++++++++++++++-------
|
|
1 file changed, 31 insertions(+), 12 deletions(-)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
@@ -668,13 +668,18 @@ void ath11k_dp_reo_cmd_list_cleanup(stru
|
|
struct ath11k_dp *dp = &ab->dp;
|
|
struct dp_reo_cmd *cmd, *tmp;
|
|
struct dp_reo_cache_flush_elem *cmd_cache, *tmp_cache;
|
|
+ struct dp_rx_tid *rx_tid;
|
|
|
|
spin_lock_bh(&dp->reo_cmd_lock);
|
|
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
|
list_del(&cmd->list);
|
|
- dma_unmap_single(ab->dev, cmd->data.paddr,
|
|
- cmd->data.size, DMA_BIDIRECTIONAL);
|
|
- kfree(cmd->data.vaddr);
|
|
+ rx_tid = &cmd->data;
|
|
+ if (rx_tid->vaddr) {
|
|
+ dma_unmap_single(ab->dev, rx_tid->paddr,
|
|
+ rx_tid->size, DMA_BIDIRECTIONAL);
|
|
+ kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
+ }
|
|
kfree(cmd);
|
|
}
|
|
|
|
@@ -682,9 +687,13 @@ void ath11k_dp_reo_cmd_list_cleanup(stru
|
|
&dp->reo_cmd_cache_flush_list, list) {
|
|
list_del(&cmd_cache->list);
|
|
dp->reo_cmd_cache_flush_count--;
|
|
- dma_unmap_single(ab->dev, cmd_cache->data.paddr,
|
|
- cmd_cache->data.size, DMA_BIDIRECTIONAL);
|
|
- kfree(cmd_cache->data.vaddr);
|
|
+ rx_tid = &cmd_cache->data;
|
|
+ if (rx_tid->vaddr) {
|
|
+ dma_unmap_single(ab->dev, rx_tid->paddr,
|
|
+ rx_tid->size, DMA_BIDIRECTIONAL);
|
|
+ kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
+ }
|
|
kfree(cmd_cache);
|
|
}
|
|
spin_unlock_bh(&dp->reo_cmd_lock);
|
|
@@ -698,10 +707,12 @@ static void ath11k_dp_reo_cmd_free(struc
|
|
if (status != HAL_REO_CMD_SUCCESS)
|
|
ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
|
|
rx_tid->tid, status);
|
|
-
|
|
- dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
|
|
- DMA_BIDIRECTIONAL);
|
|
- kfree(rx_tid->vaddr);
|
|
+ if (rx_tid->vaddr) {
|
|
+ dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
|
|
+ DMA_BIDIRECTIONAL);
|
|
+ kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
+ }
|
|
}
|
|
|
|
static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
|
|
@@ -740,6 +751,7 @@ static void ath11k_dp_reo_cache_flush(st
|
|
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
|
DMA_BIDIRECTIONAL);
|
|
kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
}
|
|
}
|
|
|
|
@@ -792,6 +804,7 @@ free_desc:
|
|
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
|
DMA_BIDIRECTIONAL);
|
|
kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
}
|
|
|
|
void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
|
@@ -804,6 +817,8 @@ void ath11k_peer_rx_tid_delete(struct at
|
|
if (!rx_tid->active)
|
|
return;
|
|
|
|
+ rx_tid->active = false;
|
|
+
|
|
cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS;
|
|
cmd.addr_lo = lower_32_bits(rx_tid->paddr);
|
|
cmd.addr_hi = upper_32_bits(rx_tid->paddr);
|
|
@@ -818,9 +833,11 @@ void ath11k_peer_rx_tid_delete(struct at
|
|
dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
|
|
DMA_BIDIRECTIONAL);
|
|
kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
}
|
|
|
|
- rx_tid->active = false;
|
|
+ rx_tid->paddr = 0;
|
|
+ rx_tid->size = 0;
|
|
}
|
|
|
|
static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
|
|
@@ -967,6 +984,7 @@ static void ath11k_dp_rx_tid_mem_free(st
|
|
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
|
DMA_BIDIRECTIONAL);
|
|
kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
|
|
rx_tid->active = false;
|
|
|
|
@@ -1067,7 +1085,8 @@ int ath11k_peer_rx_tid_setup(struct ath1
|
|
return ret;
|
|
|
|
err_mem_free:
|
|
- kfree(vaddr);
|
|
+ kfree(rx_tid->vaddr);
|
|
+ rx_tid->vaddr = NULL;
|
|
|
|
return ret;
|
|
}
|