* [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map()
@ 2026-06-25 9:42 Lorenzo Bianconi
2026-06-25 22:59 ` Harshitha Ramamurthy
2026-06-27 22:50 ` patchwork-bot+netdevbpf
0 siblings, 2 replies; 3+ messages in thread
From: Lorenzo Bianconi @ 2026-06-25 9:42 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: linux-arm-kernel, linux-mediatek, netdev, Lorenzo Bianconi
Map xmit skb fragments using skb_frag_dma_map() instead of
dma_map_single(skb_frag_address()). skb_frag_address() relies on
page_address() to obtain a kernel virtual address, which is not
guaranteed to work for all page types (e.g. highmem pages or
user-pinned pages from MSG_ZEROCOPY).
skb_frag_dma_map() maps the fragment directly via its struct page and
offset through dma_map_page(), avoiding the need for a kernel virtual
address entirely.
Introduce an enum airoha_dma_map_type to track how each queue entry was
mapped (single vs page), so that the matching unmap function is called
on completion and in error paths.
Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
drivers/net/ethernet/airoha/airoha_eth.c | 61 ++++++++++++++++++++------------
drivers/net/ethernet/airoha/airoha_eth.h | 7 ++++
2 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 932b3a3df2e5..1caf6766f2c0 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -944,6 +944,25 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
q->txq_stopped = false;
}
+static void airoha_unmap_xmit_buf(struct airoha_eth *eth,
+ struct airoha_queue_entry *e)
+{
+ switch (e->dma_type) {
+ case AIROHA_DMA_MAP_PAGE:
+ dma_unmap_page(eth->dev, e->dma_addr, e->dma_len,
+ DMA_TO_DEVICE);
+ break;
+ case AIROHA_DMA_MAP_SINGLE:
+ dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
+ DMA_TO_DEVICE);
+ break;
+ case AIROHA_DMA_UNMAPPED:
+ default:
+ break;
+ }
+ e->dma_type = AIROHA_DMA_UNMAPPED;
+}
+
static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
{
struct airoha_tx_irq_queue *irq_q;
@@ -1006,9 +1025,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
skb = e->skb;
e->skb = NULL;
- dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
- DMA_TO_DEVICE);
- e->dma_addr = 0;
+ airoha_unmap_xmit_buf(eth, e);
list_add_tail(&e->list, &q->tx_list);
WRITE_ONCE(desc->msg0, 0);
@@ -1177,12 +1194,10 @@ static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma)
struct airoha_qdma_desc *desc = &q->desc[j];
struct sk_buff *skb = e->skb;
- if (!e->dma_addr)
+ if (e->dma_type == AIROHA_DMA_UNMAPPED)
continue;
- dma_unmap_single(qdma->eth->dev, e->dma_addr,
- e->dma_len, DMA_TO_DEVICE);
- e->dma_addr = 0;
+ airoha_unmap_xmit_buf(qdma->eth, e);
list_add_tail(&e->list, &q->tx_list);
WRITE_ONCE(desc->ctrl, 0);
@@ -2193,8 +2208,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
struct netdev_queue *txq;
struct airoha_queue *q;
LIST_HEAD(tx_list);
+ dma_addr_t addr;
int i = 0, qid;
- void *data;
u16 index;
u8 fport;
@@ -2250,24 +2265,22 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- len = skb_headlen(skb);
- data = skb->data;
-
e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
list);
+ len = skb_headlen(skb);
+ addr = dma_map_single(netdev->dev.parent, skb->data, len,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
+ goto error_unlock;
+
+ e->dma_type = AIROHA_DMA_MAP_SINGLE;
index = e - q->entry;
while (true) {
struct airoha_qdma_desc *desc = &q->desc[index];
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- dma_addr_t addr;
u32 val;
- addr = dma_map_single(netdev->dev.parent, data, len,
- DMA_TO_DEVICE);
- if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
- goto error_unmap;
-
list_move_tail(&e->list, &tx_list);
e->skb = i == nr_frags - 1 ? skb : NULL;
e->dma_addr = addr;
@@ -2291,8 +2304,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
if (++i == nr_frags)
break;
- data = skb_frag_address(frag);
len = skb_frag_size(frag);
+ addr = skb_frag_dma_map(netdev->dev.parent, frag, 0, len,
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
+ goto error_unmap;
+
+ e->dma_type = AIROHA_DMA_MAP_PAGE;
}
q->queued += i;
@@ -2313,11 +2331,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
error_unmap:
- list_for_each_entry(e, &tx_list, list) {
- dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
- DMA_TO_DEVICE);
- e->dma_addr = 0;
- }
+ list_for_each_entry(e, &tx_list, list)
+ airoha_unmap_xmit_buf(dev->eth, e);
list_splice(&tx_list, &q->tx_list);
error_unlock:
spin_unlock_bh(&q->lock);
diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
index d7ff8c5200e2..2765244d937c 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.h
+++ b/drivers/net/ethernet/airoha/airoha_eth.h
@@ -170,12 +170,19 @@ enum trtcm_param {
#define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
#define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
+enum airoha_dma_map_type {
+ AIROHA_DMA_UNMAPPED,
+ AIROHA_DMA_MAP_SINGLE,
+ AIROHA_DMA_MAP_PAGE,
+};
+
struct airoha_queue_entry {
union {
void *buf;
struct {
struct list_head list;
struct sk_buff *skb;
+ enum airoha_dma_map_type dma_type;
};
};
dma_addr_t dma_addr;
---
base-commit: 232c4ca2343d1181cbfc061f9856d9591e397579
change-id: 20260625-airoha-eth-skb_frag_dma_map-bcccd5d6e4b1
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map()
2026-06-25 9:42 [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map() Lorenzo Bianconi
@ 2026-06-25 22:59 ` Harshitha Ramamurthy
2026-06-27 22:50 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: Harshitha Ramamurthy @ 2026-06-25 22:59 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev
On Thu, Jun 25, 2026 at 2:43 AM Lorenzo Bianconi <lorenzo@kernel.org> wrote:
>
> Map xmit skb fragments using skb_frag_dma_map() instead of
> dma_map_single(skb_frag_address()). skb_frag_address() relies on
> page_address() to obtain a kernel virtual address, which is not
> guaranteed to work for all page types (e.g. highmem pages or
> user-pinned pages from MSG_ZEROCOPY).
> skb_frag_dma_map() maps the fragment directly via its struct page and
> offset through dma_map_page(), avoiding the need for a kernel virtual
> address entirely.
> Introduce an enum airoha_dma_map_type to track how each queue entry was
> mapped (single vs page), so that the matching unmap function is called
> on completion and in error paths.
>
> Fixes: 23020f049327 ("net: airoha: Introduce ethernet support for EN7581 SoC")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Harshitha Ramamurthy <hramamurthy@google.com>
> ---
> drivers/net/ethernet/airoha/airoha_eth.c | 61 ++++++++++++++++++++------------
> drivers/net/ethernet/airoha/airoha_eth.h | 7 ++++
> 2 files changed, 45 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
> index 932b3a3df2e5..1caf6766f2c0 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.c
> +++ b/drivers/net/ethernet/airoha/airoha_eth.c
> @@ -944,6 +944,25 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q)
> q->txq_stopped = false;
> }
>
> +static void airoha_unmap_xmit_buf(struct airoha_eth *eth,
> + struct airoha_queue_entry *e)
> +{
> + switch (e->dma_type) {
> + case AIROHA_DMA_MAP_PAGE:
> + dma_unmap_page(eth->dev, e->dma_addr, e->dma_len,
> + DMA_TO_DEVICE);
> + break;
> + case AIROHA_DMA_MAP_SINGLE:
> + dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
> + DMA_TO_DEVICE);
> + break;
> + case AIROHA_DMA_UNMAPPED:
> + default:
> + break;
> + }
> + e->dma_type = AIROHA_DMA_UNMAPPED;
> +}
> +
> static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
> {
> struct airoha_tx_irq_queue *irq_q;
> @@ -1006,9 +1025,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget)
> skb = e->skb;
> e->skb = NULL;
>
> - dma_unmap_single(eth->dev, e->dma_addr, e->dma_len,
> - DMA_TO_DEVICE);
> - e->dma_addr = 0;
> + airoha_unmap_xmit_buf(eth, e);
> list_add_tail(&e->list, &q->tx_list);
>
> WRITE_ONCE(desc->msg0, 0);
> @@ -1177,12 +1194,10 @@ static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma)
> struct airoha_qdma_desc *desc = &q->desc[j];
> struct sk_buff *skb = e->skb;
>
> - if (!e->dma_addr)
> + if (e->dma_type == AIROHA_DMA_UNMAPPED)
> continue;
>
> - dma_unmap_single(qdma->eth->dev, e->dma_addr,
> - e->dma_len, DMA_TO_DEVICE);
> - e->dma_addr = 0;
> + airoha_unmap_xmit_buf(qdma->eth, e);
> list_add_tail(&e->list, &q->tx_list);
>
> WRITE_ONCE(desc->ctrl, 0);
> @@ -2193,8 +2208,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
> struct netdev_queue *txq;
> struct airoha_queue *q;
> LIST_HEAD(tx_list);
> + dma_addr_t addr;
> int i = 0, qid;
> - void *data;
> u16 index;
> u8 fport;
>
> @@ -2250,24 +2265,22 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
> return NETDEV_TX_BUSY;
> }
>
> - len = skb_headlen(skb);
> - data = skb->data;
> -
> e = list_first_entry(&q->tx_list, struct airoha_queue_entry,
> list);
> + len = skb_headlen(skb);
> + addr = dma_map_single(netdev->dev.parent, skb->data, len,
> + DMA_TO_DEVICE);
> + if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
> + goto error_unlock;
> +
> + e->dma_type = AIROHA_DMA_MAP_SINGLE;
> index = e - q->entry;
>
> while (true) {
> struct airoha_qdma_desc *desc = &q->desc[index];
> skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
> - dma_addr_t addr;
> u32 val;
>
> - addr = dma_map_single(netdev->dev.parent, data, len,
> - DMA_TO_DEVICE);
> - if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
> - goto error_unmap;
> -
> list_move_tail(&e->list, &tx_list);
> e->skb = i == nr_frags - 1 ? skb : NULL;
> e->dma_addr = addr;
> @@ -2291,8 +2304,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
> if (++i == nr_frags)
> break;
>
> - data = skb_frag_address(frag);
> len = skb_frag_size(frag);
> + addr = skb_frag_dma_map(netdev->dev.parent, frag, 0, len,
> + DMA_TO_DEVICE);
> + if (unlikely(dma_mapping_error(netdev->dev.parent, addr)))
> + goto error_unmap;
> +
> + e->dma_type = AIROHA_DMA_MAP_PAGE;
> }
> q->queued += i;
>
> @@ -2313,11 +2331,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,
> return NETDEV_TX_OK;
>
> error_unmap:
> - list_for_each_entry(e, &tx_list, list) {
> - dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len,
> - DMA_TO_DEVICE);
> - e->dma_addr = 0;
> - }
> + list_for_each_entry(e, &tx_list, list)
> + airoha_unmap_xmit_buf(dev->eth, e);
> list_splice(&tx_list, &q->tx_list);
> error_unlock:
> spin_unlock_bh(&q->lock);
> diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h
> index d7ff8c5200e2..2765244d937c 100644
> --- a/drivers/net/ethernet/airoha/airoha_eth.h
> +++ b/drivers/net/ethernet/airoha/airoha_eth.h
> @@ -170,12 +170,19 @@ enum trtcm_param {
> #define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6)
> #define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0)
>
> +enum airoha_dma_map_type {
> + AIROHA_DMA_UNMAPPED,
> + AIROHA_DMA_MAP_SINGLE,
> + AIROHA_DMA_MAP_PAGE,
> +};
> +
> struct airoha_queue_entry {
> union {
> void *buf;
> struct {
> struct list_head list;
> struct sk_buff *skb;
> + enum airoha_dma_map_type dma_type;
> };
> };
> dma_addr_t dma_addr;
>
> ---
> base-commit: 232c4ca2343d1181cbfc061f9856d9591e397579
> change-id: 20260625-airoha-eth-skb_frag_dma_map-bcccd5d6e4b1
>
> Best regards,
> --
> Lorenzo Bianconi <lorenzo@kernel.org>
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map()
2026-06-25 9:42 [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map() Lorenzo Bianconi
2026-06-25 22:59 ` Harshitha Ramamurthy
@ 2026-06-27 22:50 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-06-27 22:50 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, linux-arm-kernel,
linux-mediatek, netdev
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 25 Jun 2026 11:42:46 +0200 you wrote:
> Map xmit skb fragments using skb_frag_dma_map() instead of
> dma_map_single(skb_frag_address()). skb_frag_address() relies on
> page_address() to obtain a kernel virtual address, which is not
> guaranteed to work for all page types (e.g. highmem pages or
> user-pinned pages from MSG_ZEROCOPY).
> skb_frag_dma_map() maps the fragment directly via its struct page and
> offset through dma_map_page(), avoiding the need for a kernel virtual
> address entirely.
> Introduce an enum airoha_dma_map_type to track how each queue entry was
> mapped (single vs page), so that the matching unmap function is called
> on completion and in error paths.
>
> [...]
Here is the summary with links:
- [net] net: airoha: dma map xmit frags with skb_frag_dma_map()
https://git.kernel.org/netdev/net/c/32f1c2bbb26a
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-06-27 22:50 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-25 9:42 [PATCH net] net: airoha: dma map xmit frags with skb_frag_dma_map() Lorenzo Bianconi
2026-06-25 22:59 ` Harshitha Ramamurthy
2026-06-27 22:50 ` patchwork-bot+netdevbpf
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.