git: 55038a6306a5 - main - LinuxKPI: add simplified vesion of page_frag_cache
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 31 Dec 2022 02:47:56 UTC
The branch main has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=55038a6306a570c9f2df89f5ad076de0f7d98152
commit 55038a6306a570c9f2df89f5ad076de0f7d98152
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2022-12-03 00:33:34 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2022-12-31 02:45:44 +0000
LinuxKPI: add simplified vesion of page_frag_cache
For the moment and the currently only consumer (mt76) add a simplified
version of the page_frag_cache. We will only accept fragement sizes up
to 1 PAGE_SIZE (KASSERT) and we will always return a full page.
Should we add more consumers or small (or large) objects would become a
problem we can always add a more elaborate version.
Discussed with: markj
Reviewed by: markj (,hselasky commented as well)
MFC after: 3 days
Differential Revision: https://reviews.freebsd.org/D37595
---
sys/compat/linuxkpi/common/include/linux/gfp.h | 29 +++++++++++++++++
sys/compat/linuxkpi/common/src/linux_page.c | 45 ++++++++++++++++++++++++++
2 files changed, 74 insertions(+)
diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h
index 63b23b4b637e..a2930b44b0c4 100644
--- a/sys/compat/linuxkpi/common/include/linux/gfp.h
+++ b/sys/compat/linuxkpi/common/include/linux/gfp.h
@@ -81,6 +81,11 @@
CTASSERT((__GFP_DMA32 & GFP_NATIVE_MASK) == 0);
CTASSERT((__GFP_BITS_MASK & GFP_NATIVE_MASK) == GFP_NATIVE_MASK);
+struct page_frag_cache {
+ void *va;
+ int pagecnt_bias;
+};
+
/*
* Resolve a page into a virtual address:
*
@@ -95,6 +100,9 @@ extern void *linux_page_address(struct page *);
*/
extern vm_page_t linux_alloc_pages(gfp_t flags, unsigned int order);
extern void linux_free_pages(vm_page_t page, unsigned int order);
+void *linuxkpi_page_frag_alloc(struct page_frag_cache *, size_t, gfp_t);
+void linuxkpi_page_frag_free(void *);
+void linuxkpi__page_frag_cache_drain(struct page *, size_t);
static inline struct page *
alloc_page(gfp_t flags)
@@ -176,6 +184,27 @@ free_page(uintptr_t addr)
linux_free_kmem(addr, 0);
}
+static inline void *
+page_frag_alloc(struct page_frag_cache *pfc, size_t fragsz, gfp_t gfp)
+{
+
+ return (linuxkpi_page_frag_alloc(pfc, fragsz, gfp));
+}
+
+static inline void
+page_frag_free(void *addr)
+{
+
+ linuxkpi_page_frag_free(addr);
+}
+
+static inline void
+__page_frag_cache_drain(struct page *page, size_t count)
+{
+
+ linuxkpi__page_frag_cache_drain(page, count);
+}
+
static inline bool
gfpflags_allow_blocking(const gfp_t gfp_flags)
{
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
index 26b0ed649372..2bbe8f502cba 100644
--- a/sys/compat/linuxkpi/common/src/linux_page.c
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -429,3 +429,48 @@ lkpi_arch_phys_wc_del(int reg)
free(mrdesc, M_LKMTRR);
#endif
}
+
+/*
+ * This is a highly simplified version of the Linux page_frag_cache.
+ * We only support up-to 1 single page as fragment size and we will
+ * always return a full page. This may be wasteful on small objects
+ * but the only known consumer (mt76) is either asking for a half-page
+ * or a full page. If this was to become a problem we can implement
+ * a more elaborate version.
+ */
+void *
+linuxkpi_page_frag_alloc(struct page_frag_cache *pfc,
+ size_t fragsz, gfp_t gfp)
+{
+ vm_page_t pages;
+
+ if (fragsz == 0)
+ return (NULL);
+
+ KASSERT(fragsz <= PAGE_SIZE, ("%s: fragsz %zu > PAGE_SIZE not yet "
+ "supported", __func__, fragsz));
+
+ pages = alloc_pages(gfp, flsl(howmany(fragsz, PAGE_SIZE) - 1));
+ pfc->va = linux_page_address(pages);
+
+ /* Passed in as "count" to __page_frag_cache_drain(). Unused by us. */
+ pfc->pagecnt_bias = 0;
+
+ return (pfc->va);
+}
+
+void
+linuxkpi_page_frag_free(void *addr)
+{
+ vm_page_t page;
+
+ page = PHYS_TO_VM_PAGE(vtophys(addr));
+ linux_free_pages(page, 0);
+}
+
+void
+linuxkpi__page_frag_cache_drain(struct page *page, size_t count __unused)
+{
+
+ linux_free_pages(page, 0);
+}