
Backport two commits to resolve issues with ath1kk causing it to fail driver registration on iommuless systems with DRAM outside of 32bit addressing such as a 4GiB imx8mm: commit 1bcd20981834 ("wifi: ath11k: Fix DMA buffer allocation to resolve SWIOTLB issues") commit eeadc6baf8b3 ("wifi: ath11k: Use dma_alloc_noncoherent for rx_tid buffer allocation") Signed-off-by: Tim Harvey <tharvey@gateworks.com> Link: https://github.com/openwrt/openwrt/pull/17751 Signed-off-by: Robert Marko <robimarko@gmail.com> (cherry picked from commit fa50e53aa92e4db9dfe091e7dd55c3fc2024ad13)
256 lines
8.4 KiB
Diff
256 lines
8.4 KiB
Diff
wifi: ath11k: Use dma_alloc_noncoherent for rx_tid buffer allocation
|
|
|
|
Currently, the driver allocates cacheable DMA buffers for the rx_tid
|
|
structure using kzalloc() and dma_map_single(). These buffers are
|
|
long-lived and can persist for the lifetime of the peer, which is not
|
|
advisable. Instead of using kzalloc() and dma_map_single() for allocating
|
|
cacheable DMA buffers, utilize the dma_alloc_noncoherent() helper for the
|
|
allocation of long-lived cacheable DMA buffers, such as the peer's rx_tid.
|
|
Since dma_alloc_noncoherent() returns unaligned physical and virtual
|
|
addresses, align them internally before use within the driver. This
|
|
ensures proper allocation of non-coherent memory through the kernel
|
|
helper.
|
|
|
|
Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
|
|
Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3
|
|
|
|
Signed-off-by: P Praneesh <quic_ppranees@quicinc.com>
|
|
--- a/drivers/net/wireless/ath/ath11k/dp.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp.h
|
|
@@ -1,7 +1,7 @@
|
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
- * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
+ * Copyright (c) 2021-2023, 2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#ifndef ATH11K_DP_H
|
|
@@ -20,7 +20,6 @@ struct ath11k_ext_irq_grp;
|
|
|
|
struct dp_rx_tid {
|
|
u8 tid;
|
|
- u32 *vaddr;
|
|
dma_addr_t paddr;
|
|
u32 size;
|
|
u32 ba_win_sz;
|
|
@@ -37,6 +36,9 @@ struct dp_rx_tid {
|
|
/* Timer info related to fragments */
|
|
struct timer_list frag_timer;
|
|
struct ath11k_base *ab;
|
|
+ u32 *vaddr_unaligned;
|
|
+ dma_addr_t paddr_unaligned;
|
|
+ u32 unaligned_size;
|
|
};
|
|
|
|
#define DP_REO_DESC_FREE_THRESHOLD 64
|
|
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
|
|
@@ -1,7 +1,7 @@
|
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
/*
|
|
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
|
- * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
+ * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/ieee80211.h>
|
|
@@ -675,11 +675,11 @@ void ath11k_dp_reo_cmd_list_cleanup(stru
|
|
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
|
list_del(&cmd->list);
|
|
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;
|
|
+ if (rx_tid->vaddr_unaligned) {
|
|
+ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
|
+ rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
}
|
|
kfree(cmd);
|
|
}
|
|
@@ -689,11 +689,11 @@ void ath11k_dp_reo_cmd_list_cleanup(stru
|
|
list_del(&cmd_cache->list);
|
|
dp->reo_cmd_cache_flush_count--;
|
|
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;
|
|
+ if (rx_tid->vaddr_unaligned) {
|
|
+ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
|
+ rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
}
|
|
kfree(cmd_cache);
|
|
}
|
|
@@ -708,11 +708,11 @@ 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);
|
|
- 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;
|
|
+ if (rx_tid->vaddr_unaligned) {
|
|
+ dma_free_noncoherent(dp->ab->dev, rx_tid->unaligned_size,
|
|
+ rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
}
|
|
}
|
|
|
|
@@ -749,10 +749,10 @@ static void ath11k_dp_reo_cache_flush(st
|
|
if (ret) {
|
|
ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
|
|
rx_tid->tid, ret);
|
|
- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
|
- DMA_BIDIRECTIONAL);
|
|
- kfree(rx_tid->vaddr);
|
|
- rx_tid->vaddr = NULL;
|
|
+ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
|
+ rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
}
|
|
}
|
|
|
|
@@ -802,10 +802,10 @@ static void ath11k_dp_rx_tid_del_func(st
|
|
|
|
return;
|
|
free_desc:
|
|
- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
|
- DMA_BIDIRECTIONAL);
|
|
- kfree(rx_tid->vaddr);
|
|
- rx_tid->vaddr = NULL;
|
|
+ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
|
+ rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
}
|
|
|
|
void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
|
@@ -831,14 +831,16 @@ void ath11k_peer_rx_tid_delete(struct at
|
|
if (ret != -ESHUTDOWN)
|
|
ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
|
|
tid, ret);
|
|
- dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
|
|
- DMA_BIDIRECTIONAL);
|
|
- kfree(rx_tid->vaddr);
|
|
- rx_tid->vaddr = NULL;
|
|
+ dma_free_noncoherent(ar->ab->dev, rx_tid->unaligned_size,
|
|
+ rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
}
|
|
|
|
rx_tid->paddr = 0;
|
|
+ rx_tid->paddr_unaligned = 0;
|
|
rx_tid->size = 0;
|
|
+ rx_tid->unaligned_size = 0;
|
|
}
|
|
|
|
static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
|
|
@@ -982,10 +984,9 @@ static void ath11k_dp_rx_tid_mem_free(st
|
|
if (!rx_tid->active)
|
|
goto unlock_exit;
|
|
|
|
- dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
|
- DMA_BIDIRECTIONAL);
|
|
- kfree(rx_tid->vaddr);
|
|
- rx_tid->vaddr = NULL;
|
|
+ dma_free_noncoherent(ab->dev, rx_tid->unaligned_size, rx_tid->vaddr_unaligned,
|
|
+ rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
|
+ rx_tid->vaddr_unaligned = NULL;
|
|
|
|
rx_tid->active = false;
|
|
|
|
@@ -1000,9 +1001,8 @@ int ath11k_peer_rx_tid_setup(struct ath1
|
|
struct ath11k_base *ab = ar->ab;
|
|
struct ath11k_peer *peer;
|
|
struct dp_rx_tid *rx_tid;
|
|
- u32 hw_desc_sz;
|
|
- u32 *addr_aligned;
|
|
- void *vaddr;
|
|
+ u32 hw_desc_sz, *vaddr;
|
|
+ void *vaddr_unaligned;
|
|
dma_addr_t paddr;
|
|
int ret;
|
|
|
|
@@ -1050,37 +1050,34 @@ int ath11k_peer_rx_tid_setup(struct ath1
|
|
else
|
|
hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
|
|
|
|
- vaddr = kzalloc(hw_desc_sz + HAL_LINK_DESC_ALIGN - 1, GFP_ATOMIC);
|
|
- if (!vaddr) {
|
|
+ rx_tid->unaligned_size = hw_desc_sz + HAL_LINK_DESC_ALIGN - 1;
|
|
+ vaddr_unaligned = dma_alloc_noncoherent(ab->dev, rx_tid->unaligned_size, &paddr,
|
|
+ DMA_BIDIRECTIONAL, GFP_ATOMIC);
|
|
+ if (!vaddr_unaligned) {
|
|
spin_unlock_bh(&ab->base_lock);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
|
|
-
|
|
- ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz,
|
|
- ssn, pn_type);
|
|
-
|
|
- paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
|
|
- DMA_BIDIRECTIONAL);
|
|
-
|
|
- ret = dma_mapping_error(ab->dev, paddr);
|
|
- if (ret) {
|
|
- spin_unlock_bh(&ab->base_lock);
|
|
- ath11k_warn(ab, "failed to setup dma map for peer %pM rx tid %d: %d\n",
|
|
- peer_mac, tid, ret);
|
|
- goto err_mem_free;
|
|
- }
|
|
-
|
|
- rx_tid->vaddr = vaddr;
|
|
- rx_tid->paddr = paddr;
|
|
+ rx_tid->vaddr_unaligned = vaddr_unaligned;
|
|
+ vaddr = PTR_ALIGN(vaddr_unaligned, HAL_LINK_DESC_ALIGN);
|
|
+ rx_tid->paddr_unaligned = paddr;
|
|
+ rx_tid->paddr = rx_tid->paddr_unaligned + ((unsigned long)vaddr -
|
|
+ (unsigned long)rx_tid->vaddr_unaligned);
|
|
+ ath11k_hal_reo_qdesc_setup(vaddr, tid, ba_win_sz, ssn, pn_type);
|
|
rx_tid->size = hw_desc_sz;
|
|
rx_tid->active = true;
|
|
|
|
+ /* After dma_alloc_noncoherent, vaddr is being modified for reo qdesc setup.
|
|
+ * Since these changes are not reflected in the device, driver now needs to
|
|
+ * explicitly call dma_sync_single_for_device.
|
|
+ */
|
|
+ dma_sync_single_for_device(ab->dev, rx_tid->paddr,
|
|
+ rx_tid->size,
|
|
+ DMA_TO_DEVICE);
|
|
spin_unlock_bh(&ab->base_lock);
|
|
|
|
- ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
|
|
- paddr, tid, 1, ba_win_sz);
|
|
+ ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, rx_tid->paddr,
|
|
+ tid, 1, ba_win_sz);
|
|
if (ret) {
|
|
ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n",
|
|
peer_mac, tid, ret);
|
|
@@ -1088,12 +1085,6 @@ int ath11k_peer_rx_tid_setup(struct ath1
|
|
}
|
|
|
|
return ret;
|
|
-
|
|
-err_mem_free:
|
|
- kfree(rx_tid->vaddr);
|
|
- rx_tid->vaddr = NULL;
|
|
-
|
|
- return ret;
|
|
}
|
|
|
|
int ath11k_dp_rx_ampdu_start(struct ath11k *ar,
|