| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- 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 <[email protected]>
- --- 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,
|