Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Jul 2026 19:35:06 +0000
From:      Bjoern A. Zeeb <bz@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: e591a7662143 - main - LinuxKPI: page pool updates and add to the build
Message-ID:  <6a63be6a.26c00.20d04f@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=e591a76621430d6d29f2580e2dec8991e450ed5e

commit e591a76621430d6d29f2580e2dec8991e450ed5e
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-07-18 11:54:42 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-07-24 19:33:57 +0000

    LinuxKPI: page pool updates and add to the build
    
    Split implementation out from the header files.
    
    This "page pool" is the very minimalistic version we need in order to
    support packets on mt76.
    We allocate the page pool in order to have the meta data available of
    which we only make limited use.
    This implementation does no pooling, it does no page fragments for now,
    it always hands out a full page and frees it upon return.
    
    It is written in a way that it can be in the tree before the 'struct page'
    work it depends on has landed in order to reduce friction for people who
    want to try mt7921 (or others later) upfront.  We use the same #ifdef
    as in the struct page work for that reason so one knob will turn everything
    on or off.
    
    Once the struct page work has landed and settled we can start filling this
    with more complexity.
    
    In the unlikely event that in the mean time any other consumer would start
    showing up they will have to be aware that the current code as-is
    essentially is a NOP without the 'struct page' work.  A WARN_ONCE() will
    notify them.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
---
 .../common/include/net/page_pool/helpers.h         |  58 ++++----
 .../linuxkpi/common/include/net/page_pool/types.h  |  19 ++-
 .../linuxkpi/common/src/linuxkpi_page_pool.c       | 156 +++++++++++++++++++++
 sys/conf/files                                     |   2 +
 sys/modules/linuxkpi/Makefile                      |   1 +
 5 files changed, 207 insertions(+), 29 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/net/page_pool/helpers.h b/sys/compat/linuxkpi/common/include/net/page_pool/helpers.h
index 3469c39c7757..032e171fea3e 100644
--- a/sys/compat/linuxkpi/common/include/net/page_pool/helpers.h
+++ b/sys/compat/linuxkpi/common/include/net/page_pool/helpers.h
@@ -1,5 +1,9 @@
-/*-
+/*
  * Copyright (c) 2023-2025 Bjoern A. Zeeb
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -12,58 +16,57 @@
 #include <linux/dma-mapping.h>
 #include <net/page_pool/types.h>
 
+struct page_pool *linuxkpi_page_pool_create(const struct page_pool_params *);
+void linuxkpi_page_pool_destroy(struct page_pool *);
+
+struct page *linuxkpi_page_pool_dev_alloc_frag(struct page_pool *,
+    uint32_t *, size_t);
+void linuxkpi_page_pool_put_full_page(struct page_pool *, struct page *, bool);
+dma_addr_t linuxkpi_page_pool_get_dma_addr(const struct page *);
+
+
 static inline struct page_pool *
 page_pool_create(const struct page_pool_params *ppparams)
 {
-
-	pr_debug("%s: TODO\n", __func__);
-	return (NULL);
+	return (linuxkpi_page_pool_create(ppparams));
 }
 
 static inline void
-page_pool_destroy(struct page_pool *ppool)
+page_pool_destroy(struct page_pool *pp)
 {
-
-	pr_debug("%s: TODO\n", __func__);
+	linuxkpi_page_pool_destroy(pp);
 }
 
+
 static inline struct page *
-page_pool_dev_alloc_frag(struct page_pool *ppool, uint32_t *offset,
+page_pool_dev_alloc_frag(struct page_pool *pp, uint32_t *offset,
     size_t size)
 {
-
-	pr_debug("%s: TODO\n", __func__);
-	return (NULL);
+	return (linuxkpi_page_pool_dev_alloc_frag(pp, offset, size));
 }
 
-static inline dma_addr_t
-page_pool_get_dma_addr(struct page *page)
+static inline void
+page_pool_put_full_page(struct page_pool *pp, struct page *page,
+    bool allow_direct)
 {
-
-	pr_debug("%s: TODO\n", __func__);
-	return (0);
+	linuxkpi_page_pool_put_full_page(pp, page, allow_direct);
 }
 
-static inline enum dma_data_direction
-page_pool_get_dma_dir(const struct page_pool *ppool)
+static inline dma_addr_t
+page_pool_get_dma_addr(const struct page *page)
 {
-
-	pr_debug("%s: TODO\n", __func__);
-	return (DMA_BIDIRECTIONAL);
+	return (linuxkpi_page_pool_get_dma_addr(page));
 }
 
-static inline void
-page_pool_put_full_page(struct page_pool *ppool, struct page *page,
-    bool allow_direct)
+static inline enum dma_data_direction
+page_pool_get_dma_dir(const struct page_pool *pp)
 {
-
-	pr_debug("%s: TODO\n", __func__);
+	return (pp->params.dma_dir);
 }
 
 static inline int
 page_pool_ethtool_stats_get_count(void)
 {
-
 	pr_debug("%s: TODO\n", __func__);
 	return (0);
 }
@@ -71,7 +74,6 @@ page_pool_ethtool_stats_get_count(void)
 static inline uint8_t *
 page_pool_ethtool_stats_get_strings(uint8_t *x)
 {
-
 	pr_debug("%s: TODO\n", __func__);
 	return (x);
 }
diff --git a/sys/compat/linuxkpi/common/include/net/page_pool/types.h b/sys/compat/linuxkpi/common/include/net/page_pool/types.h
index 6747be50b9b2..e35fd32d3e02 100644
--- a/sys/compat/linuxkpi/common/include/net/page_pool/types.h
+++ b/sys/compat/linuxkpi/common/include/net/page_pool/types.h
@@ -1,5 +1,9 @@
-/*-
+/*
  * Copyright (c) 2023-2025 Bjoern A. Zeeb
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -27,10 +31,23 @@ struct page_pool_params {
 };
 
 struct page_pool {
+	struct page_pool_params		params;
 };
 
 #define	PP_FLAG_DMA_MAP		BIT(0)
 #define	PP_FLAG_DMA_SYNC_DEV	BIT(1)
 #define	PP_FLAG_PAGE_FRAG	BIT(2)
+#define	PP_FLAGS_ALL		(PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV | \
+    PP_FLAG_PAGE_FRAG)
+
+struct page *linuxkpi_page_pool_alloc_frag(struct page_pool *, uint32_t *,
+    size_t, gfp_t);
+
+static inline struct page *
+page_pool_alloc_frag(struct page_pool *pp, uint32_t *offset,
+    size_t size, gfp_t gfp)
+{
+	return (linuxkpi_page_pool_alloc_frag(pp, offset, size, gfp));
+}
 
 #endif	/* _LINUXKPI_NET_PAGE_POOL_TYPES_H */
diff --git a/sys/compat/linuxkpi/common/src/linuxkpi_page_pool.c b/sys/compat/linuxkpi/common/src/linuxkpi_page_pool.c
new file mode 100644
index 000000000000..93e649faafd7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linuxkpi_page_pool.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <net/page_pool/helpers.h>
+
+struct page_pool *
+linuxkpi_page_pool_create(const struct page_pool_params *ppparams)
+{
+	struct page_pool *pp;
+	int error;
+
+#ifndef PAGE_IS_LKPI_PAGE
+	WARN_ONCE(1, "\n!!! LinuxKPI page pool not supported yet!!!\n\n");
+#endif
+
+	pp = kzalloc_node(sizeof(*pp), GFP_KERNEL, ppparams->nid);
+	if (pp == NULL)
+		return (ERR_PTR(-ENOMEM));
+
+	pp->params = *ppparams;
+
+	if ((pp->params.flags & PP_FLAG_DMA_MAP) != 0) {
+		if (pp->params.dma_dir != DMA_FROM_DEVICE &&
+		    pp->params.dma_dir != DMA_BIDIRECTIONAL) {
+			pr_warn_once("%s: invalid dma_dir %#04x\n",
+			    __func__, pp->params.dma_dir);
+			error = -EINVAL;
+			goto free_pp;
+		}
+	}
+
+	if ((pp->params.flags & PP_FLAG_DMA_SYNC_DEV) != 0) {
+		if ((pp->params.flags & PP_FLAG_DMA_MAP) == 0) {
+			pr_warn_once("%s: DMA_SYNC_DEV but no DMA_MAP\n",
+			    __func__);
+			error = -EINVAL;
+			goto free_pp;
+		}
+
+		if (pp->params.max_len == 0) {
+			pr_warn_once("%s: max_len unset\n", __func__);
+			error = -EINVAL;
+			goto free_pp;
+		}
+	}
+
+	return (pp);
+
+free_pp:
+	kfree(pp);
+	return (ERR_PTR(error));
+}
+
+void
+linuxkpi_page_pool_destroy(struct page_pool *pp)
+{
+	kfree(pp);
+}
+
+/* ---------------------------------------------------------------------------- */
+
+struct page *
+linuxkpi_page_pool_alloc_frag(struct page_pool *pp, uint32_t *offset,
+    size_t size, gfp_t gfp)
+{
+#ifdef PAGE_IS_LKPI_PAGE
+	struct page *p;
+	dma_addr_t dma;
+
+	if (size > PAGE_SIZE) {
+		pr_warn_once("%s: size %zu > PAGE_SIZE\n", __func__, size);
+		return (NULL);
+	}
+
+	/*
+	 * We do not try to be smart on the first cut until 'struct page' work
+	 * is sorted and settled.  Everyone gets a page for now.
+	 * XXX in the future deal with page fragments, pool limits, etc.
+	 */
+	p = alloc_page(gfp);
+	if (p == NULL)
+		return (NULL);
+
+	if (offset != NULL)
+		*offset = 0;
+
+	if ((pp->params.flags & PP_FLAG_DMA_MAP) != 0) {
+		dma = dma_map_page_attrs(pp->params.dev, p, 0, PAGE_SIZE,
+		    pp->params.dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+		if (dma_mapping_error(pp->params.dev, dma)) {
+			put_page(p);
+			return (NULL);
+		}
+
+		/* We store the dma address in struct page as well. */
+		p->dma_addr = dma;
+	}
+
+	if ((pp->params.flags & PP_FLAG_DMA_SYNC_DEV) != 0)
+		dma_sync_single_for_device(pp->params.dev, dma, PAGE_SIZE,
+		    pp->params.dma_dir);
+
+	/*
+	 * We may not yet need to track the page pool on the page in order
+	 * to know where to return it but prepare at least for that.
+	 */
+	p->pp = pp;
+
+	return (p);
+#else
+	return (NULL);
+#endif /* PAGE_IS_LKPI_PAGE */
+}
+
+struct page *
+linuxkpi_page_pool_dev_alloc_frag(struct page_pool *pp, uint32_t *offset,
+    size_t size)
+{
+	gfp_t gfp;
+
+	gfp = (GFP_ATOMIC | __GFP_NOWARN);
+	return (page_pool_alloc_frag(pp, offset, size, gfp));
+}
+
+void
+linuxkpi_page_pool_put_full_page(struct page_pool *pp, struct page *page,
+    bool allow_direct)
+{
+	/* We just free the full page we handed out for now. */
+#ifdef PAGE_IS_LKPI_PAGE
+	page->pp = NULL;
+	page->dma_addr = 0;
+#endif
+	put_page(page);
+}
+
+dma_addr_t
+linuxkpi_page_pool_get_dma_addr(const struct page *page)
+{
+
+	KASSERT(page != NULL, ("%s: page %p\n", __func__, page));
+
+#ifdef PAGE_IS_LKPI_PAGE
+	return (page->dma_addr);
+#else
+	return (0);
+#endif
+}
diff --git a/sys/conf/files b/sys/conf/files
index fcce58183b9b..567e024259b0 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4724,6 +4724,8 @@ compat/linuxkpi/common/src/linux_netdev.c	optional compat_linuxkpi \
 	compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_page.c		optional compat_linuxkpi \
 	compile-with "${LINUXKPI_C}"
+compat/linuxkpi/common/src/linuxkpi_page_pool.c	optional compat_linuxkpi \
+	compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_pci.c		optional compat_linuxkpi pci \
 	compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_tasklet.c	optional compat_linuxkpi \
diff --git a/sys/modules/linuxkpi/Makefile b/sys/modules/linuxkpi/Makefile
index 2090fe76d857..da8d003e1d22 100644
--- a/sys/modules/linuxkpi/Makefile
+++ b/sys/modules/linuxkpi/Makefile
@@ -21,6 +21,7 @@ SRCS=	linux_compat.c \
 	linux_lock.c \
 	linux_netdev.c \
 	linux_page.c \
+	linuxkpi_page_pool.c \
 	linux_pci.c \
 	linux_radix.c \
 	linux_rcu.c \


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a63be6a.26c00.20d04f>