wifi: ath11k: Use dma_alloc_noncoherent for rx_tid buffer allocation
[ Upstream commit eeadc6baf8b3dcd32787cc84f0473dc2a2850370 ] 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> Tested-by: Tim Harvey <tharvey@gateworks.com> Link: https://patch.msgid.link/20250119164219.647059-3-quic_ppranees@quicinc.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e1fffcd1d7
commit
115360031b
@@ -1,7 +1,7 @@
|
|||||||
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
* 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
|
#ifndef ATH11K_DP_H
|
||||||
@@ -20,7 +20,6 @@ struct ath11k_ext_irq_grp;
|
|||||||
|
|
||||||
struct dp_rx_tid {
|
struct dp_rx_tid {
|
||||||
u8 tid;
|
u8 tid;
|
||||||
u32 *vaddr;
|
|
||||||
dma_addr_t paddr;
|
dma_addr_t paddr;
|
||||||
u32 size;
|
u32 size;
|
||||||
u32 ba_win_sz;
|
u32 ba_win_sz;
|
||||||
@@ -37,6 +36,9 @@ struct dp_rx_tid {
|
|||||||
/* Timer info related to fragments */
|
/* Timer info related to fragments */
|
||||||
struct timer_list frag_timer;
|
struct timer_list frag_timer;
|
||||||
struct ath11k_base *ab;
|
struct ath11k_base *ab;
|
||||||
|
u32 *vaddr_unaligned;
|
||||||
|
dma_addr_t paddr_unaligned;
|
||||||
|
u32 unaligned_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DP_REO_DESC_FREE_THRESHOLD 64
|
#define DP_REO_DESC_FREE_THRESHOLD 64
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
// SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
|
* 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>
|
#include <linux/ieee80211.h>
|
||||||
@@ -675,11 +675,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
|
|||||||
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) {
|
||||||
list_del(&cmd->list);
|
list_del(&cmd->list);
|
||||||
rx_tid = &cmd->data;
|
rx_tid = &cmd->data;
|
||||||
if (rx_tid->vaddr) {
|
if (rx_tid->vaddr_unaligned) {
|
||||||
dma_unmap_single(ab->dev, rx_tid->paddr,
|
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||||
rx_tid->size, DMA_BIDIRECTIONAL);
|
rx_tid->vaddr_unaligned,
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
rx_tid->vaddr = NULL;
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
}
|
}
|
||||||
kfree(cmd);
|
kfree(cmd);
|
||||||
}
|
}
|
||||||
@@ -689,11 +689,11 @@ void ath11k_dp_reo_cmd_list_cleanup(struct ath11k_base *ab)
|
|||||||
list_del(&cmd_cache->list);
|
list_del(&cmd_cache->list);
|
||||||
dp->reo_cmd_cache_flush_count--;
|
dp->reo_cmd_cache_flush_count--;
|
||||||
rx_tid = &cmd_cache->data;
|
rx_tid = &cmd_cache->data;
|
||||||
if (rx_tid->vaddr) {
|
if (rx_tid->vaddr_unaligned) {
|
||||||
dma_unmap_single(ab->dev, rx_tid->paddr,
|
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||||
rx_tid->size, DMA_BIDIRECTIONAL);
|
rx_tid->vaddr_unaligned,
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
rx_tid->vaddr = NULL;
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
}
|
}
|
||||||
kfree(cmd_cache);
|
kfree(cmd_cache);
|
||||||
}
|
}
|
||||||
@@ -708,11 +708,11 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx,
|
|||||||
if (status != HAL_REO_CMD_SUCCESS)
|
if (status != HAL_REO_CMD_SUCCESS)
|
||||||
ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
|
ath11k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n",
|
||||||
rx_tid->tid, status);
|
rx_tid->tid, status);
|
||||||
if (rx_tid->vaddr) {
|
if (rx_tid->vaddr_unaligned) {
|
||||||
dma_unmap_single(dp->ab->dev, rx_tid->paddr, rx_tid->size,
|
dma_free_noncoherent(dp->ab->dev, rx_tid->unaligned_size,
|
||||||
DMA_BIDIRECTIONAL);
|
rx_tid->vaddr_unaligned,
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
rx_tid->vaddr = NULL;
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,10 +749,10 @@ static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab,
|
|||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
|
ath11k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n",
|
||||||
rx_tid->tid, ret);
|
rx_tid->tid, ret);
|
||||||
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||||
DMA_BIDIRECTIONAL);
|
rx_tid->vaddr_unaligned,
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
rx_tid->vaddr = NULL;
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,10 +802,10 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
free_desc:
|
free_desc:
|
||||||
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size,
|
||||||
DMA_BIDIRECTIONAL);
|
rx_tid->vaddr_unaligned,
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
rx_tid->vaddr = NULL;
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
||||||
@@ -831,14 +831,16 @@ void ath11k_peer_rx_tid_delete(struct ath11k *ar,
|
|||||||
if (ret != -ESHUTDOWN)
|
if (ret != -ESHUTDOWN)
|
||||||
ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
|
ath11k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n",
|
||||||
tid, ret);
|
tid, ret);
|
||||||
dma_unmap_single(ar->ab->dev, rx_tid->paddr, rx_tid->size,
|
dma_free_noncoherent(ar->ab->dev, rx_tid->unaligned_size,
|
||||||
DMA_BIDIRECTIONAL);
|
rx_tid->vaddr_unaligned,
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
rx_tid->vaddr = NULL;
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rx_tid->paddr = 0;
|
rx_tid->paddr = 0;
|
||||||
|
rx_tid->paddr_unaligned = 0;
|
||||||
rx_tid->size = 0;
|
rx_tid->size = 0;
|
||||||
|
rx_tid->unaligned_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
|
static int ath11k_dp_rx_link_desc_return(struct ath11k_base *ab,
|
||||||
@@ -982,10 +984,9 @@ static void ath11k_dp_rx_tid_mem_free(struct ath11k_base *ab,
|
|||||||
if (!rx_tid->active)
|
if (!rx_tid->active)
|
||||||
goto unlock_exit;
|
goto unlock_exit;
|
||||||
|
|
||||||
dma_unmap_single(ab->dev, rx_tid->paddr, rx_tid->size,
|
dma_free_noncoherent(ab->dev, rx_tid->unaligned_size, rx_tid->vaddr_unaligned,
|
||||||
DMA_BIDIRECTIONAL);
|
rx_tid->paddr_unaligned, DMA_BIDIRECTIONAL);
|
||||||
kfree(rx_tid->vaddr);
|
rx_tid->vaddr_unaligned = NULL;
|
||||||
rx_tid->vaddr = NULL;
|
|
||||||
|
|
||||||
rx_tid->active = false;
|
rx_tid->active = false;
|
||||||
|
|
||||||
@@ -1000,9 +1001,8 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
|
|||||||
struct ath11k_base *ab = ar->ab;
|
struct ath11k_base *ab = ar->ab;
|
||||||
struct ath11k_peer *peer;
|
struct ath11k_peer *peer;
|
||||||
struct dp_rx_tid *rx_tid;
|
struct dp_rx_tid *rx_tid;
|
||||||
u32 hw_desc_sz;
|
u32 hw_desc_sz, *vaddr;
|
||||||
u32 *addr_aligned;
|
void *vaddr_unaligned;
|
||||||
void *vaddr;
|
|
||||||
dma_addr_t paddr;
|
dma_addr_t paddr;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1050,49 +1050,40 @@ int ath11k_peer_rx_tid_setup(struct ath11k *ar, const u8 *peer_mac, int vdev_id,
|
|||||||
else
|
else
|
||||||
hw_desc_sz = ath11k_hal_reo_qdesc_size(DP_BA_WIN_SZ_MAX, tid);
|
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);
|
rx_tid->unaligned_size = hw_desc_sz + HAL_LINK_DESC_ALIGN - 1;
|
||||||
if (!vaddr) {
|
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);
|
spin_unlock_bh(&ab->base_lock);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr_aligned = PTR_ALIGN(vaddr, HAL_LINK_DESC_ALIGN);
|
rx_tid->vaddr_unaligned = vaddr_unaligned;
|
||||||
|
vaddr = PTR_ALIGN(vaddr_unaligned, HAL_LINK_DESC_ALIGN);
|
||||||
ath11k_hal_reo_qdesc_setup(addr_aligned, tid, ba_win_sz,
|
rx_tid->paddr_unaligned = paddr;
|
||||||
ssn, pn_type);
|
rx_tid->paddr = rx_tid->paddr_unaligned + ((unsigned long)vaddr -
|
||||||
|
(unsigned long)rx_tid->vaddr_unaligned);
|
||||||
paddr = dma_map_single(ab->dev, addr_aligned, hw_desc_sz,
|
ath11k_hal_reo_qdesc_setup(vaddr, tid, ba_win_sz, ssn, pn_type);
|
||||||
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->size = hw_desc_sz;
|
rx_tid->size = hw_desc_sz;
|
||||||
rx_tid->active = true;
|
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);
|
spin_unlock_bh(&ab->base_lock);
|
||||||
|
|
||||||
ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac,
|
ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, rx_tid->paddr,
|
||||||
paddr, tid, 1, ba_win_sz);
|
tid, 1, ba_win_sz);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n",
|
ath11k_warn(ar->ab, "failed to setup rx reorder queue for peer %pM tid %d: %d\n",
|
||||||
peer_mac, tid, ret);
|
peer_mac, tid, ret);
|
||||||
ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
|
ath11k_dp_rx_tid_mem_free(ab, peer_mac, vdev_id, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
err_mem_free:
|
|
||||||
kfree(rx_tid->vaddr);
|
|
||||||
rx_tid->vaddr = NULL;
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user