All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] wifi: ath12k: add page_pool support for rx data path
@ 2026-10-08 13:15 Lorenzo Bianconi
  2026-10-08 13:15 ` [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err() Lorenzo Bianconi
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2026-10-08 13:15 UTC (permalink / raw)
  To: Jeff Johnson, Vasanthakumar Thiagarajan, Ripan Deuri, P Praneesh,
	Kalle Valo, Baochen Qiang
  Cc: Jeff Johnson, linux-wireless, ath12k, Lorenzo Bianconi

Convert the Rx refill buffers to the page_pool API instead of allocating
an skb with dev_alloc_skb() and mapping it with dma_map_single().
Fix DMA direction for reinjeced packets.

---
Lorenzo Bianconi (3):
      wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err()
      wifi: ath12k: fix DMA direction for re-injected Rx buffers
      wifi: ath12k: rely on page_pool APIs for buffer allocation

 drivers/net/wireless/ath/ath12k/Kconfig        |   1 +
 drivers/net/wireless/ath/ath12k/core.h         |   1 +
 drivers/net/wireless/ath/ath12k/dp.c           |   5 +-
 drivers/net/wireless/ath/ath12k/dp.h           |   1 +
 drivers/net/wireless/ath/ath12k/dp_rx.c        | 101 +++++++++++++++++--------
 drivers/net/wireless/ath/ath12k/dp_rx.h        |  29 +++++++
 drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c |   5 +-
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c  |  67 ++++++++--------
 8 files changed, 138 insertions(+), 72 deletions(-)
---
base-commit: 17e4b9ea527b6c9491bed60f646bb2eff7d8db7b
change-id: 20261007-ath12k-pp-e8c62b54d756

Best regards,
-- 
Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err()
  2026-10-08 13:15 [PATCH 0/3] wifi: ath12k: add page_pool support for rx data path Lorenzo Bianconi
@ 2026-10-08 13:15 ` Lorenzo Bianconi
  2026-10-08 14:34   ` Jeff Johnson
  2026-10-08 13:15 ` [PATCH 2/3] wifi: ath12k: fix DMA direction for re-injected Rx buffers Lorenzo Bianconi
  2026-10-08 13:16 ` [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation Lorenzo Bianconi
  2 siblings, 1 reply; 8+ messages in thread
From: Lorenzo Bianconi @ 2026-10-08 13:15 UTC (permalink / raw)
  To: Jeff Johnson, Vasanthakumar Thiagarajan, Ripan Deuri, P Praneesh,
	Kalle Valo, Baochen Qiang
  Cc: Jeff Johnson, linux-wireless, ath12k, Lorenzo Bianconi

ath12k_wifi7_dp_rx_process_err() resolves the per-pdev datapath with
ath12k_dp_to_pdev_dp(dp, pdev_idx), using the local 'dp', while
'pdev_idx' is computed from the owning 'partner_dp'. As dp_pdevs[] is
indexed per ath12k_dp, this picks the wrong pdev when the REO exception
descriptor was sourced by a partner device in a multi-device group.

The error is currently masked by the drop condition that only processes
same-device fragments (partner_dp->device_id == dp->device_id), but it
is still incorrect and would misbehave as soon as that restriction is
relaxed.

Look the pdev datapath up from partner_dp, as already done in the other
Rx processing paths.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
Fixes: 9e0ee04f818f ("wifi: ath12k: Refactor data path pdev struct")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index a32c804403e8..633cb91b9e5d 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -1536,7 +1536,7 @@ int ath12k_wifi7_dp_rx_process_err(struct ath12k_dp *dp, struct napi_struct *nap
 
 		rcu_read_lock();
 
-		dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_idx);
+		dp_pdev = ath12k_dp_to_pdev_dp(partner_dp, pdev_idx);
 		if (!dp_pdev) {
 			rcu_read_unlock();
 			continue;

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] wifi: ath12k: fix DMA direction for re-injected Rx buffers
  2026-10-08 13:15 [PATCH 0/3] wifi: ath12k: add page_pool support for rx data path Lorenzo Bianconi
  2026-10-08 13:15 ` [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err() Lorenzo Bianconi
@ 2026-10-08 13:15 ` Lorenzo Bianconi
  2026-10-08 13:16 ` [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation Lorenzo Bianconi
  2 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2026-10-08 13:15 UTC (permalink / raw)
  To: Jeff Johnson, Vasanthakumar Thiagarajan, Ripan Deuri, P Praneesh,
	Kalle Valo, Baochen Qiang
  Cc: Jeff Johnson, linux-wireless, ath12k, Lorenzo Bianconi

Defragmented MPDUs that are re-injected into the REO are mapped with
DMA_TO_DEVICE, but all the Rx reap and teardown paths unmap them with
DMA_FROM_DEVICE. The DMA API requires the unmap direction to match the
map direction, so this violates the contract.

The mapping actually spans both directions, since the host has written
the buffer before the REO reads it and the buffer is read back by the
host afterwards, so DMA_BIDIRECTIONAL is the correct choice.

Add a 'reinjected' flag to struct ath12k_skb_rxcb and a common
ath12k_dp_unmap_rx_buf() helper that selects DMA_BIDIRECTIONAL for
re-injected buffers and DMA_FROM_DEVICE otherwise, then use it in all the
Rx reap and cleanup paths. Map and unmap the re-injected buffer with
DMA_BIDIRECTIONAL consistently.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
Fixes: 33322e3ef074 ("wifi: ath12k: change DMA direction while mapping reinjected packets")
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/core.h         |  1 +
 drivers/net/wireless/ath/ath12k/dp.c           |  5 +---
 drivers/net/wireless/ath/ath12k/dp_rx.h        | 11 ++++++++
 drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c |  5 +---
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c  | 37 +++++++++-----------------
 5 files changed, 26 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 99d71dab7c04..7a219249dc51 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -149,6 +149,7 @@ struct ath12k_skb_rxcb {
 	u8 tid;
 	u16 peer_id;
 	bool is_end_of_ppdu;
+	bool reinjected;
 };
 
 enum ath12k_hw_rev {
diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index 83f9edfabf69..dd3b0dcfa055 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1003,10 +1003,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 					continue;
 
 				if (!ATH12K_SKB_RXCB(skb)->unmapped)
-					dma_unmap_single(ab->dev,
-							 ATH12K_SKB_RXCB(skb)->paddr,
-							 skb->len + skb_tailroom(skb),
-							 DMA_FROM_DEVICE);
+					ath12k_dp_unmap_rx_buf(dp, skb);
 				dev_kfree_skb_any(skb);
 			}
 
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index 82700474548a..c3715c99054f 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -187,6 +187,17 @@ void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal,
 	hal->ops->extract_rx_desc_data(rx_info, rx_desc, ldesc);
 }
 
+static inline void ath12k_dp_unmap_rx_buf(struct ath12k_dp *dp,
+					  struct sk_buff *skb)
+{
+	struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(skb);
+	enum dma_data_direction dir;
+
+	dir = rxcb->reinjected ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
+	dma_unmap_single(dp->dev, rxcb->paddr, skb->len + skb_tailroom(skb),
+			 dir);
+}
+
 void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
 			    enum hal_encrypt_type enctype,
 			    bool decrypted,
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
index 1e29c13ad66d..e7d5dfa31361 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_mon.c
@@ -2722,10 +2722,7 @@ ath12k_wifi7_dp_rx_mon_mpdu_pop(struct ath12k *ar, int mac_id,
 				drop_mpdu = true;
 			}
 			if (!rxcb->unmapped) {
-				dma_unmap_single(ar->ab->dev, rxcb->paddr,
-						 msdu->len +
-						 skb_tailroom(msdu),
-						 DMA_FROM_DEVICE);
+				ath12k_dp_unmap_rx_buf(dp, msdu);
 				rxcb->unmapped = 1;
 			}
 			if (drop_mpdu) {
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index 633cb91b9e5d..9cd9c0bb07db 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -741,11 +741,7 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id,
 
 		list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]);
 
-		rxcb = ATH12K_SKB_RXCB(msdu);
-		dma_unmap_single(partner_dp->dev, rxcb->paddr,
-				 msdu->len + skb_tailroom(msdu),
-				 DMA_FROM_DEVICE);
-
+		ath12k_dp_unmap_rx_buf(partner_dp, msdu);
 		num_buffs_reaped[device_id]++;
 		dp->device_stats.reo_rx[ring_id][dp->device_id]++;
 
@@ -761,6 +757,7 @@ int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int ring_id,
 		msdu_info = &desc->rx_msdu_info;
 		mpdu_info = &desc->rx_mpdu_info;
 
+		rxcb = ATH12K_SKB_RXCB(msdu);
 		rxcb->is_first_msdu = !!(le32_to_cpu(msdu_info->info0) &
 					 RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU);
 		rxcb->is_last_msdu = !!(le32_to_cpu(msdu_info->info0) &
@@ -858,6 +855,7 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 						    struct ath12k_dp_rx_tid *rx_tid,
 						    struct sk_buff *defrag_skb)
 {
+	struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(defrag_skb);
 	struct ath12k_base *ab = dp->ab;
 	struct ath12k_hal *hal = dp->hal;
 	struct hal_rx_desc *rx_desc = (struct hal_rx_desc *)defrag_skb->data;
@@ -906,10 +904,13 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 
 	buf_paddr = dma_map_single(dp->dev, defrag_skb->data,
 				   defrag_skb->len + skb_tailroom(defrag_skb),
-				   DMA_TO_DEVICE);
+				   DMA_BIDIRECTIONAL);
 	if (dma_mapping_error(dp->dev, buf_paddr))
 		return -ENOMEM;
 
+	rxcb->reinjected = true;
+	rxcb->paddr = buf_paddr;
+
 	spin_lock_bh(&dp->rx_desc_lock);
 	desc_info = list_first_entry_or_null(&dp->rx_desc_free_list,
 					     struct ath12k_rx_desc_info,
@@ -927,8 +928,6 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 	list_del(&desc_info->list);
 	spin_unlock_bh(&dp->rx_desc_lock);
 
-	ATH12K_SKB_RXCB(defrag_skb)->paddr = buf_paddr;
-
 	ath12k_wifi7_hal_rx_buf_addr_info_set(&msdu0->buf_addr_info, buf_paddr,
 					      desc_info->cookie,
 					      HAL_RX_BUF_RBM_SW3_BM);
@@ -996,7 +995,7 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 	spin_unlock_bh(&dp->rx_desc_lock);
 err_unmap_dma:
 	dma_unmap_single(dp->dev, buf_paddr, defrag_skb->len + skb_tailroom(defrag_skb),
-			 DMA_TO_DEVICE);
+			 DMA_BIDIRECTIONAL);
 	return ret;
 }
 
@@ -1298,7 +1297,6 @@ ath12k_wifi7_dp_process_rx_err_buf(struct ath12k_pdev_dp *dp_pdev,
 	struct ath12k_dp *dp = dp_pdev->dp;
 	struct ath12k_hal *hal = dp->hal;
 	struct sk_buff *msdu;
-	struct ath12k_skb_rxcb *rxcb;
 	struct hal_rx_desc_data rx_info;
 	struct hal_rx_desc *rx_desc;
 	u16 msdu_len;
@@ -1328,11 +1326,7 @@ ath12k_wifi7_dp_process_rx_err_buf(struct ath12k_pdev_dp *dp_pdev,
 	desc_info->skb = NULL;
 
 	list_add_tail(&desc_info->list, used_list);
-
-	rxcb = ATH12K_SKB_RXCB(msdu);
-	dma_unmap_single(dp->dev, rxcb->paddr,
-			 msdu->len + skb_tailroom(msdu),
-			 DMA_FROM_DEVICE);
+	ath12k_dp_unmap_rx_buf(dp, msdu);
 
 	if (drop) {
 		dev_kfree_skb_any(msdu);
@@ -1379,7 +1373,6 @@ static int ath12k_dp_h_msdu_buffer_type(struct ath12k_dp *dp,
 					struct hal_reo_dest_ring *desc)
 {
 	struct ath12k_rx_desc_info *desc_info;
-	struct ath12k_skb_rxcb *rxcb;
 	struct sk_buff *msdu;
 	u64 desc_va;
 
@@ -1410,9 +1403,7 @@ static int ath12k_dp_h_msdu_buffer_type(struct ath12k_dp *dp,
 	msdu = desc_info->skb;
 	desc_info->skb = NULL;
 	list_add_tail(&desc_info->list, list);
-	rxcb = ATH12K_SKB_RXCB(msdu);
-	dma_unmap_single(dp->dev, rxcb->paddr, msdu->len + skb_tailroom(msdu),
-			 DMA_FROM_DEVICE);
+	ath12k_dp_unmap_rx_buf(dp, msdu);
 	dev_kfree_skb_any(msdu);
 
 	return 0;
@@ -1998,12 +1989,7 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp,
 		}
 
 		list_add_tail(&desc_info->list, &rx_desc_used_list[device_id]);
-
-		rxcb = ATH12K_SKB_RXCB(msdu);
-		dma_unmap_single(partner_dp->dev, rxcb->paddr,
-				 msdu->len + skb_tailroom(msdu),
-				 DMA_FROM_DEVICE);
-
+		ath12k_dp_unmap_rx_buf(partner_dp, msdu);
 		num_buffs_reaped[device_id]++;
 		total_num_buffs_reaped++;
 
@@ -2017,6 +2003,7 @@ int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp,
 		}
 
 		msdu_data = (struct hal_rx_desc *)msdu->data;
+		rxcb = ATH12K_SKB_RXCB(msdu);
 		rxcb->err_rel_src = err_info.err_rel_src;
 		rxcb->err_code = err_info.err_code;
 		rxcb->is_first_msdu = err_info.first_msdu;

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation
  2026-10-08 13:15 [PATCH 0/3] wifi: ath12k: add page_pool support for rx data path Lorenzo Bianconi
  2026-10-08 13:15 ` [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err() Lorenzo Bianconi
  2026-10-08 13:15 ` [PATCH 2/3] wifi: ath12k: fix DMA direction for re-injected Rx buffers Lorenzo Bianconi
@ 2026-10-08 13:16 ` Lorenzo Bianconi
  2026-10-09 10:24   ` Baochen Qiang
  2 siblings, 1 reply; 8+ messages in thread
From: Lorenzo Bianconi @ 2026-10-08 13:16 UTC (permalink / raw)
  To: Jeff Johnson, Vasanthakumar Thiagarajan, Ripan Deuri, P Praneesh,
	Kalle Valo, Baochen Qiang
  Cc: Jeff Johnson, linux-wireless, ath12k, Lorenzo Bianconi

Convert the Rx refill buffers to the page_pool API instead of allocating
an skb with dev_alloc_skb() and mapping it with dma_map_single(). The pool
handles the DMA mapping and buffer recycling.

Add a page_pool to struct dp_rxdma_ring, created in
ath12k_dp_rxdma_ring_buf_setup() and destroyed in
ath12k_dp_rxdma_ring_buf_cleanup().

Update ath12k_dp_unmap_rx_buf() to sync page_pool buffers for the CPU
instead of unmapping them, and guard the teardown paths
(ath12k_dp_cc_cleanup(), ath12k_dp_h_msdu_buffer_type()) against
page_pool buffers. In the re-inject path, sync an already mapped
page_pool buffer for the device instead of mapping it again, and fill the
descriptor with the DMA address stored in the rxcb.

The monitor, CE and TX paths are left unchanged.

This is just preliminary support: the goal is to use a single page to map
two separated fragments of 2048B.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/Kconfig       |   1 +
 drivers/net/wireless/ath/ath12k/dp.h          |   1 +
 drivers/net/wireless/ath/ath12k/dp_rx.c       | 101 ++++++++++++++++++--------
 drivers/net/wireless/ath/ath12k/dp_rx.h       |  32 ++++++--
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c |  34 ++++++---
 5 files changed, 121 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/Kconfig b/drivers/net/wireless/ath/ath12k/Kconfig
index 0d5d1c55bfc1..13985daffaee 100644
--- a/drivers/net/wireless/ath/ath12k/Kconfig
+++ b/drivers/net/wireless/ath/ath12k/Kconfig
@@ -7,6 +7,7 @@ config ATH12K
 	select QRTR
 	select QRTR_MHI
 	select PCI_PWRCTRL_PWRSEQ if HAVE_PWRCTRL
+	select PAGE_POOL
 	help
 	  Enable support for Qualcomm Technologies Wi-Fi 7 (IEEE
 	  802.11be) family of chipsets, for example WCN7850 and
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index c53eac20b989..599ce3c45c7a 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -59,6 +59,7 @@ struct dp_rxdma_mon_ring {
 
 struct dp_rxdma_ring {
 	struct dp_srng refill_buf_ring;
+	struct page_pool *page_pool;
 	int bufs_max;
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index cfaf26ae2720..de9ea84323df 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -68,6 +68,31 @@ static void ath12k_dp_rx_enqueue_free(struct ath12k_dp *dp,
 	spin_unlock_bh(&dp->rx_desc_lock);
 }
 
+static struct sk_buff *ath12k_dp_rx_build_skb(struct ath12k_dp *dp,
+					      struct dp_rxdma_ring *rx_ring)
+{
+	struct sk_buff *skb;
+	struct page *page;
+
+	if (!rx_ring->page_pool)
+		return NULL;
+
+	page = page_pool_dev_alloc_pages(rx_ring->page_pool);
+	if (!page)
+		return NULL;
+
+	skb = build_skb(page_address(page), PAGE_SIZE);
+	if (!skb) {
+		page_pool_put_full_page(rx_ring->page_pool, page, false);
+		return NULL;
+	}
+
+	ATH12K_SKB_RXCB(skb)->paddr = page_pool_get_dma_addr(page);
+	skb_mark_for_recycle(skb);
+
+	return skb;
+}
+
 /* Returns number of Rx buffers replenished */
 int ath12k_dp_rx_bufs_replenish(struct ath12k_dp *dp,
 				struct dp_rxdma_ring *rx_ring,
@@ -81,7 +106,6 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_dp *dp,
 	int num_free;
 	int num_remain;
 	u32 cookie;
-	dma_addr_t paddr;
 	struct ath12k_rx_desc_info *rx_desc;
 	enum hal_rx_buf_return_buf_manager mgr = dp->hal->hal_params->rx_buf_rbm;
 
@@ -114,51 +138,33 @@ int ath12k_dp_rx_bufs_replenish(struct ath12k_dp *dp,
 	}
 
 	while (num_remain > 0) {
-		skb = dev_alloc_skb(DP_RX_BUFFER_SIZE +
-				    DP_RX_BUFFER_ALIGN_SIZE);
+		skb = ath12k_dp_rx_build_skb(dp, rx_ring);
 		if (!skb)
 			break;
 
-		if (!IS_ALIGNED((unsigned long)skb->data,
-				DP_RX_BUFFER_ALIGN_SIZE)) {
-			skb_pull(skb,
-				 PTR_ALIGN(skb->data, DP_RX_BUFFER_ALIGN_SIZE) -
-				 skb->data);
-		}
-
-		paddr = dma_map_single(dp->dev, skb->data,
-				       skb->len + skb_tailroom(skb),
-				       DMA_FROM_DEVICE);
-		if (dma_mapping_error(dp->dev, paddr))
-			goto fail_free_skb;
-
 		rx_desc = list_first_entry_or_null(used_list,
 						   struct ath12k_rx_desc_info,
 						   list);
 		if (!rx_desc)
-			goto fail_dma_unmap;
-
-		rx_desc->skb = skb;
-		cookie = rx_desc->cookie;
+			goto fail_free_skb;
 
 		desc = ath12k_hal_srng_src_get_next_entry(ab, srng);
 		if (!desc)
-			goto fail_dma_unmap;
+			goto fail_free_skb;
 
-		list_del(&rx_desc->list);
-		ATH12K_SKB_RXCB(skb)->paddr = paddr;
+		rx_desc->skb = skb;
+		cookie = rx_desc->cookie;
 
+		list_del(&rx_desc->list);
 		num_remain--;
 
-		ath12k_hal_rx_buf_addr_info_set(dp->hal, desc, paddr, cookie,
-						mgr);
+		ath12k_hal_rx_buf_addr_info_set(dp->hal, desc,
+						ATH12K_SKB_RXCB(skb)->paddr,
+						cookie, mgr);
 	}
 
 	goto out;
 
-fail_dma_unmap:
-	dma_unmap_single(dp->dev, paddr, skb->len + skb_tailroom(skb),
-			 DMA_FROM_DEVICE);
 fail_free_skb:
 	dev_kfree_skb_any(skb);
 out:
@@ -196,12 +202,21 @@ static int ath12k_dp_rxdma_mon_buf_ring_free(struct ath12k_base *ab,
 	return 0;
 }
 
+static void ath12k_dp_rxdma_ring_buf_cleanup(struct dp_rxdma_ring *rx_ring)
+{
+	if (rx_ring->page_pool) {
+		page_pool_destroy(rx_ring->page_pool);
+		rx_ring->page_pool = NULL;
+	}
+}
+
 static int ath12k_dp_rxdma_buf_free(struct ath12k_base *ab)
 {
 	struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
 	int i;
 
 	ath12k_dp_rxdma_mon_buf_ring_free(ab, &dp->rxdma_mon_buf_ring);
+	ath12k_dp_rxdma_ring_buf_cleanup(&dp->rx_refill_buf_ring);
 
 	if (ab->hw_params->rxdma1_enable)
 		return 0;
@@ -236,11 +251,28 @@ static int ath12k_dp_rxdma_mon_ring_buf_setup(struct ath12k_base *ab,
 static int ath12k_dp_rxdma_ring_buf_setup(struct ath12k_base *ab,
 					  struct dp_rxdma_ring *rx_ring)
 {
+	struct page_pool_params pp_params = {
+		.order = 0,
+		.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
+		.nid = NUMA_NO_NODE,
+		.dma_dir = DMA_BIDIRECTIONAL,
+		.max_len = PAGE_SIZE,
+		.dev = ab->dev,
+		.offset = 0,
+	};
 	LIST_HEAD(list);
 
 	rx_ring->bufs_max = rx_ring->refill_buf_ring.size /
 			ath12k_hal_srng_get_entrysize(ab, HAL_RXDMA_BUF);
 
+	rx_ring->page_pool = page_pool_create(&pp_params);
+	if (IS_ERR(rx_ring->page_pool)) {
+		int err = PTR_ERR(rx_ring->page_pool);
+
+		rx_ring->page_pool = NULL;
+		return err;
+	}
+
 	ath12k_dp_rx_bufs_replenish(ath12k_ab_to_dp(ab), rx_ring, &list, 0);
 
 	return 0;
@@ -263,10 +295,13 @@ static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab)
 		ret = ath12k_dp_rxdma_mon_ring_buf_setup(ab,
 							 &dp->rxdma_mon_buf_ring,
 							 HAL_RXDMA_MONITOR_BUF);
-		if (ret)
+		if (ret) {
 			ath12k_warn(ab,
 				    "failed to setup HAL_RXDMA_MONITOR_BUF\n");
-		return ret;
+			goto error;
+		}
+
+		return 0;
 	}
 
 	for (i = 0; i < ab->hw_params->num_rxdma_per_pdev; i++) {
@@ -276,11 +311,15 @@ static int ath12k_dp_rxdma_buf_setup(struct ath12k_base *ab)
 		if (ret) {
 			ath12k_warn(ab,
 				    "failed to setup HAL_RXDMA_MONITOR_STATUS\n");
-			return ret;
+			goto error;
 		}
 	}
 
 	return 0;
+error:
+	ath12k_dp_rxdma_ring_buf_cleanup(&dp->rx_refill_buf_ring);
+
+	return ret;
 }
 
 static void ath12k_dp_rx_pdev_srng_free(struct ath12k *ar)
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h
index c3715c99054f..a1113f8b7399 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.h
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.h
@@ -6,6 +6,7 @@
 #ifndef ATH12K_DP_RX_H
 #define ATH12K_DP_RX_H
 
+#include <net/page_pool/helpers.h>
 #include "core.h"
 #include "debug.h"
 
@@ -187,15 +188,32 @@ void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal,
 	hal->ops->extract_rx_desc_data(rx_info, rx_desc, ldesc);
 }
 
-static inline void ath12k_dp_unmap_rx_buf(struct ath12k_dp *dp,
-					  struct sk_buff *skb)
+static inline bool ath12k_skb_from_page_pool(struct sk_buff *skb)
 {
-	struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(skb);
-	enum dma_data_direction dir;
+	if (!skb->head_frag || !skb->pp_recycle)
+		return false;
 
-	dir = rxcb->reinjected ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
-	dma_unmap_single(dp->dev, rxcb->paddr, skb->len + skb_tailroom(skb),
-			 dir);
+	return page_pool_page_is_pp(virt_to_head_page(skb->head));
+}
+
+static inline void ath12k_dp_unmap_rx_buf(struct ath12k_dp *dp, struct sk_buff *skb)
+{
+	if (likely(ath12k_skb_from_page_pool(skb))) {
+		struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
+		struct page *page = virt_to_head_page(skb->data);
+		int offset = (void *)skb->data - page_address(page);
+
+		page_pool_dma_sync_for_cpu(rx_ring->page_pool, page,
+					   offset,
+					   skb->len + skb_tailroom(skb));
+	} else {
+		struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(skb);
+		enum dma_data_direction dir;
+
+		dir = rxcb->reinjected ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE;
+		dma_unmap_single(dp->dev, rxcb->paddr,
+				 skb->len + skb_tailroom(skb), dir);
+	}
 }
 
 void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
index 9cd9c0bb07db..d1703c736d49 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
@@ -902,14 +902,26 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 	/* change msdu len in hal rx desc */
 	ath12k_dp_rxdesc_set_msdu_len(hal, rx_desc, defrag_skb->len - hal_rx_desc_sz);
 
-	buf_paddr = dma_map_single(dp->dev, defrag_skb->data,
-				   defrag_skb->len + skb_tailroom(defrag_skb),
-				   DMA_BIDIRECTIONAL);
-	if (dma_mapping_error(dp->dev, buf_paddr))
-		return -ENOMEM;
+	if (ath12k_skb_from_page_pool(defrag_skb)) {
+		struct dp_rxdma_ring *rx_ring;
+
+		rx_ring = &dp->rx_refill_buf_ring;
+		dma_sync_single_for_device(dp->dev,
+					   ATH12K_SKB_RXCB(defrag_skb)->paddr,
+					   defrag_skb->len +
+					   skb_tailroom(defrag_skb),
+					   rx_ring->page_pool->p.dma_dir);
+	} else {
+		buf_paddr = dma_map_single(dp->dev, defrag_skb->data,
+					   defrag_skb->len +
+					   skb_tailroom(defrag_skb),
+					   DMA_BIDIRECTIONAL);
+		if (dma_mapping_error(dp->dev, buf_paddr))
+			return -ENOMEM;
 
+		rxcb->paddr = buf_paddr;
+	}
 	rxcb->reinjected = true;
-	rxcb->paddr = buf_paddr;
 
 	spin_lock_bh(&dp->rx_desc_lock);
 	desc_info = list_first_entry_or_null(&dp->rx_desc_free_list,
@@ -928,8 +940,8 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 	list_del(&desc_info->list);
 	spin_unlock_bh(&dp->rx_desc_lock);
 
-	ath12k_wifi7_hal_rx_buf_addr_info_set(&msdu0->buf_addr_info, buf_paddr,
-					      desc_info->cookie,
+	ath12k_wifi7_hal_rx_buf_addr_info_set(&msdu0->buf_addr_info,
+					      rxcb->paddr, desc_info->cookie,
 					      HAL_RX_BUF_RBM_SW3_BM);
 
 	/* Fill mpdu details into reo entrance ring */
@@ -994,8 +1006,10 @@ static int ath12k_wifi7_dp_rx_h_defrag_reo_reinject(struct ath12k_dp *dp,
 	list_add_tail(&desc_info->list, &dp->rx_desc_free_list);
 	spin_unlock_bh(&dp->rx_desc_lock);
 err_unmap_dma:
-	dma_unmap_single(dp->dev, buf_paddr, defrag_skb->len + skb_tailroom(defrag_skb),
-			 DMA_BIDIRECTIONAL);
+	if (!ath12k_skb_from_page_pool(defrag_skb))
+		dma_unmap_single(dp->dev, ATH12K_SKB_RXCB(defrag_skb)->paddr,
+				 defrag_skb->len + skb_tailroom(defrag_skb),
+				 DMA_BIDIRECTIONAL);
 	return ret;
 }
 

-- 
2.56.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err()
  2026-10-08 13:15 ` [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err() Lorenzo Bianconi
@ 2026-10-08 14:34   ` Jeff Johnson
  2026-10-08 15:05     ` Lorenzo Bianconi
  0 siblings, 1 reply; 8+ messages in thread
From: Jeff Johnson @ 2026-10-08 14:34 UTC (permalink / raw)
  To: Lorenzo Bianconi, Jeff Johnson, Vasanthakumar Thiagarajan,
	Baochen Qiang
  Cc: linux-wireless, ath12k

On 10/8/2026 6:15 AM, Lorenzo Bianconi wrote:
> ath12k_wifi7_dp_rx_process_err() resolves the per-pdev datapath with
> ath12k_dp_to_pdev_dp(dp, pdev_idx), using the local 'dp', while
> 'pdev_idx' is computed from the owning 'partner_dp'. As dp_pdevs[] is
> indexed per ath12k_dp, this picks the wrong pdev when the REO exception
> descriptor was sourced by a partner device in a multi-device group.
> 
> The error is currently masked by the drop condition that only processes
> same-device fragments (partner_dp->device_id == dp->device_id), but it
> is still incorrect and would misbehave as soon as that restriction is
> relaxed.
> 
> Look the pdev datapath up from partner_dp, as already done in the other
> Rx processing paths.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3

Tested-on is not an official upstream tag but is an ath-specific tag. There
should be a blank line separating this tag from the official tags.

No need to repost for this, I can fix it in my tree.

> Fixes: 9e0ee04f818f ("wifi: ath12k: Refactor data path pdev struct")

If this issue is masked then IMO we don't need to backport to LTS kernels and
hence should drop the fixes tag or add Cc: <stable+noautosel@kernel.org>

> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
> ---
>  drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
> index a32c804403e8..633cb91b9e5d 100644
> --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
> +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
> @@ -1536,7 +1536,7 @@ int ath12k_wifi7_dp_rx_process_err(struct ath12k_dp *dp, struct napi_struct *nap
>  
>  		rcu_read_lock();
>  
> -		dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_idx);
> +		dp_pdev = ath12k_dp_to_pdev_dp(partner_dp, pdev_idx);
>  		if (!dp_pdev) {
>  			rcu_read_unlock();
>  			continue;
> 



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err()
  2026-10-08 14:34   ` Jeff Johnson
@ 2026-10-08 15:05     ` Lorenzo Bianconi
  0 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2026-10-08 15:05 UTC (permalink / raw)
  To: Jeff Johnson
  Cc: Jeff Johnson, Vasanthakumar Thiagarajan, Baochen Qiang,
	linux-wireless, ath12k

[-- Attachment #1: Type: text/plain, Size: 2193 bytes --]

> On 10/8/2026 6:15 AM, Lorenzo Bianconi wrote:
> > ath12k_wifi7_dp_rx_process_err() resolves the per-pdev datapath with
> > ath12k_dp_to_pdev_dp(dp, pdev_idx), using the local 'dp', while
> > 'pdev_idx' is computed from the owning 'partner_dp'. As dp_pdevs[] is
> > indexed per ath12k_dp, this picks the wrong pdev when the REO exception
> > descriptor was sourced by a partner device in a multi-device group.
> > 
> > The error is currently masked by the drop condition that only processes
> > same-device fragments (partner_dp->device_id == dp->device_id), but it
> > is still incorrect and would misbehave as soon as that restriction is
> > relaxed.
> > 
> > Look the pdev datapath up from partner_dp, as already done in the other
> > Rx processing paths.
> > 
> > Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3
> 
> Tested-on is not an official upstream tag but is an ath-specific tag. There
> should be a blank line separating this tag from the official tags.
> 
> No need to repost for this, I can fix it in my tree.

ack, thx.

> 
> > Fixes: 9e0ee04f818f ("wifi: ath12k: Refactor data path pdev struct")
> 
> If this issue is masked then IMO we don't need to backport to LTS kernels and
> hence should drop the fixes tag or add Cc: <stable+noautosel@kernel.org>

ack.

Regards,
Lorenzo

> 
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
> > ---
> >  drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
> > index a32c804403e8..633cb91b9e5d 100644
> > --- a/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
> > +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c
> > @@ -1536,7 +1536,7 @@ int ath12k_wifi7_dp_rx_process_err(struct ath12k_dp *dp, struct napi_struct *nap
> >  
> >  		rcu_read_lock();
> >  
> > -		dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_idx);
> > +		dp_pdev = ath12k_dp_to_pdev_dp(partner_dp, pdev_idx);
> >  		if (!dp_pdev) {
> >  			rcu_read_unlock();
> >  			continue;
> > 
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation
  2026-10-08 13:16 ` [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation Lorenzo Bianconi
@ 2026-10-09 10:24   ` Baochen Qiang
  2026-10-09 16:35     ` Lorenzo Bianconi
  0 siblings, 1 reply; 8+ messages in thread
From: Baochen Qiang @ 2026-10-09 10:24 UTC (permalink / raw)
  To: Lorenzo Bianconi, Jeff Johnson, Vasanthakumar Thiagarajan,
	Ripan Deuri, P Praneesh, Kalle Valo
  Cc: Jeff Johnson, linux-wireless, ath12k



On 10/8/2026 9:16 PM, Lorenzo Bianconi wrote:
> Convert the Rx refill buffers to the page_pool API instead of allocating
> an skb with dev_alloc_skb() and mapping it with dma_map_single(). The pool
> handles the DMA mapping and buffer recycling.
> 
> Add a page_pool to struct dp_rxdma_ring, created in
> ath12k_dp_rxdma_ring_buf_setup() and destroyed in
> ath12k_dp_rxdma_ring_buf_cleanup().
> 
> Update ath12k_dp_unmap_rx_buf() to sync page_pool buffers for the CPU
> instead of unmapping them, and guard the teardown paths
> (ath12k_dp_cc_cleanup(), ath12k_dp_h_msdu_buffer_type()) against
> page_pool buffers. In the re-inject path, sync an already mapped
> page_pool buffer for the device instead of mapping it again, and fill the
> descriptor with the DMA address stored in the rxcb.
> 
> The monitor, CE and TX paths are left unchanged.
> 
> This is just preliminary support: the goal is to use a single page to map
> two separated fragments of 2048B.

why? please always justify your motivation in detail when the change is not trival.

Besides, instead of preliminary patches, why not just send the full support in a single
series?


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation
  2026-10-09 10:24   ` Baochen Qiang
@ 2026-10-09 16:35     ` Lorenzo Bianconi
  0 siblings, 0 replies; 8+ messages in thread
From: Lorenzo Bianconi @ 2026-10-09 16:35 UTC (permalink / raw)
  To: Baochen Qiang
  Cc: Jeff Johnson, Vasanthakumar Thiagarajan, Ripan Deuri, P Praneesh,
	Kalle Valo, Jeff Johnson, linux-wireless, ath12k

[-- Attachment #1: Type: text/plain, Size: 1705 bytes --]

> 
> 
> On 10/8/2026 9:16 PM, Lorenzo Bianconi wrote:
> > Convert the Rx refill buffers to the page_pool API instead of allocating
> > an skb with dev_alloc_skb() and mapping it with dma_map_single(). The pool
> > handles the DMA mapping and buffer recycling.
> > 
> > Add a page_pool to struct dp_rxdma_ring, created in
> > ath12k_dp_rxdma_ring_buf_setup() and destroyed in
> > ath12k_dp_rxdma_ring_buf_cleanup().
> > 
> > Update ath12k_dp_unmap_rx_buf() to sync page_pool buffers for the CPU
> > instead of unmapping them, and guard the teardown paths
> > (ath12k_dp_cc_cleanup(), ath12k_dp_h_msdu_buffer_type()) against
> > page_pool buffers. In the re-inject path, sync an already mapped
> > page_pool buffer for the device instead of mapping it again, and fill the
> > descriptor with the DMA address stored in the rxcb.
> > 
> > The monitor, CE and TX paths are left unchanged.
> > 
> > This is just preliminary support: the goal is to use a single page to map
> > two separated fragments of 2048B.
> 
> why? please always justify your motivation in detail when the change is not trival.

my main goal here would be to avoid running dev_alloc_skb()/dma_{map,unmap}() on every
rx packets but rely on page_pool APIs in order to recycles and keep pages DMA
mapped. I guess this way we will have even a smaller memory footprint.

> 
> Besides, instead of preliminary patches, why not just send the full support in a single
> series?
> 

I would like to implement it incrementally (you can find the code here [0]) but
I am fine to squash patches in the next iteration.

Regards,
Lorenzo

[0] https://github.com/LorenzoBianconi/wireless-next/tree/b4/ath12k-pp-dev

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-10-09 16:35 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-08 13:15 [PATCH 0/3] wifi: ath12k: add page_pool support for rx data path Lorenzo Bianconi
2026-10-08 13:15 ` [PATCH 1/3] wifi: ath12k: fix datapath lookup in ath12k_wifi7_dp_rx_process_err() Lorenzo Bianconi
2026-10-08 14:34   ` Jeff Johnson
2026-10-08 15:05     ` Lorenzo Bianconi
2026-10-08 13:15 ` [PATCH 2/3] wifi: ath12k: fix DMA direction for re-injected Rx buffers Lorenzo Bianconi
2026-10-08 13:16 ` [PATCH 3/3] wifi: ath12k: rely on page_pool APIs for buffer allocation Lorenzo Bianconi
2026-10-09 10:24   ` Baochen Qiang
2026-10-09 16:35     ` Lorenzo Bianconi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.