xref: /freebsd/sys/compat/linuxkpi/common/src/linuxkpi_page_pool.c (revision e591a76621430d6d29f2580e2dec8991e450ed5e)
1*e591a766SBjoern A. Zeeb /*
2*e591a766SBjoern A. Zeeb  * Copyright (c) 2025-2026 The FreeBSD Foundation
3*e591a766SBjoern A. Zeeb  *
4*e591a766SBjoern A. Zeeb  * This software was developed by Björn Zeeb under sponsorship from
5*e591a766SBjoern A. Zeeb  * the FreeBSD Foundation.
6*e591a766SBjoern A. Zeeb  *
7*e591a766SBjoern A. Zeeb  * SPDX-License-Identifier: BSD-2-Clause
8*e591a766SBjoern A. Zeeb  */
9*e591a766SBjoern A. Zeeb 
10*e591a766SBjoern A. Zeeb #include <linux/types.h>
11*e591a766SBjoern A. Zeeb #include <linux/dma-mapping.h>
12*e591a766SBjoern A. Zeeb #include <net/page_pool/helpers.h>
13*e591a766SBjoern A. Zeeb 
14*e591a766SBjoern A. Zeeb struct page_pool *
linuxkpi_page_pool_create(const struct page_pool_params * ppparams)15*e591a766SBjoern A. Zeeb linuxkpi_page_pool_create(const struct page_pool_params *ppparams)
16*e591a766SBjoern A. Zeeb {
17*e591a766SBjoern A. Zeeb 	struct page_pool *pp;
18*e591a766SBjoern A. Zeeb 	int error;
19*e591a766SBjoern A. Zeeb 
20*e591a766SBjoern A. Zeeb #ifndef PAGE_IS_LKPI_PAGE
21*e591a766SBjoern A. Zeeb 	WARN_ONCE(1, "\n!!! LinuxKPI page pool not supported yet!!!\n\n");
22*e591a766SBjoern A. Zeeb #endif
23*e591a766SBjoern A. Zeeb 
24*e591a766SBjoern A. Zeeb 	pp = kzalloc_node(sizeof(*pp), GFP_KERNEL, ppparams->nid);
25*e591a766SBjoern A. Zeeb 	if (pp == NULL)
26*e591a766SBjoern A. Zeeb 		return (ERR_PTR(-ENOMEM));
27*e591a766SBjoern A. Zeeb 
28*e591a766SBjoern A. Zeeb 	pp->params = *ppparams;
29*e591a766SBjoern A. Zeeb 
30*e591a766SBjoern A. Zeeb 	if ((pp->params.flags & PP_FLAG_DMA_MAP) != 0) {
31*e591a766SBjoern A. Zeeb 		if (pp->params.dma_dir != DMA_FROM_DEVICE &&
32*e591a766SBjoern A. Zeeb 		    pp->params.dma_dir != DMA_BIDIRECTIONAL) {
33*e591a766SBjoern A. Zeeb 			pr_warn_once("%s: invalid dma_dir %#04x\n",
34*e591a766SBjoern A. Zeeb 			    __func__, pp->params.dma_dir);
35*e591a766SBjoern A. Zeeb 			error = -EINVAL;
36*e591a766SBjoern A. Zeeb 			goto free_pp;
37*e591a766SBjoern A. Zeeb 		}
38*e591a766SBjoern A. Zeeb 	}
39*e591a766SBjoern A. Zeeb 
40*e591a766SBjoern A. Zeeb 	if ((pp->params.flags & PP_FLAG_DMA_SYNC_DEV) != 0) {
41*e591a766SBjoern A. Zeeb 		if ((pp->params.flags & PP_FLAG_DMA_MAP) == 0) {
42*e591a766SBjoern A. Zeeb 			pr_warn_once("%s: DMA_SYNC_DEV but no DMA_MAP\n",
43*e591a766SBjoern A. Zeeb 			    __func__);
44*e591a766SBjoern A. Zeeb 			error = -EINVAL;
45*e591a766SBjoern A. Zeeb 			goto free_pp;
46*e591a766SBjoern A. Zeeb 		}
47*e591a766SBjoern A. Zeeb 
48*e591a766SBjoern A. Zeeb 		if (pp->params.max_len == 0) {
49*e591a766SBjoern A. Zeeb 			pr_warn_once("%s: max_len unset\n", __func__);
50*e591a766SBjoern A. Zeeb 			error = -EINVAL;
51*e591a766SBjoern A. Zeeb 			goto free_pp;
52*e591a766SBjoern A. Zeeb 		}
53*e591a766SBjoern A. Zeeb 	}
54*e591a766SBjoern A. Zeeb 
55*e591a766SBjoern A. Zeeb 	return (pp);
56*e591a766SBjoern A. Zeeb 
57*e591a766SBjoern A. Zeeb free_pp:
58*e591a766SBjoern A. Zeeb 	kfree(pp);
59*e591a766SBjoern A. Zeeb 	return (ERR_PTR(error));
60*e591a766SBjoern A. Zeeb }
61*e591a766SBjoern A. Zeeb 
62*e591a766SBjoern A. Zeeb void
linuxkpi_page_pool_destroy(struct page_pool * pp)63*e591a766SBjoern A. Zeeb linuxkpi_page_pool_destroy(struct page_pool *pp)
64*e591a766SBjoern A. Zeeb {
65*e591a766SBjoern A. Zeeb 	kfree(pp);
66*e591a766SBjoern A. Zeeb }
67*e591a766SBjoern A. Zeeb 
68*e591a766SBjoern A. Zeeb /* ---------------------------------------------------------------------------- */
69*e591a766SBjoern A. Zeeb 
70*e591a766SBjoern A. Zeeb struct page *
linuxkpi_page_pool_alloc_frag(struct page_pool * pp,uint32_t * offset,size_t size,gfp_t gfp)71*e591a766SBjoern A. Zeeb linuxkpi_page_pool_alloc_frag(struct page_pool *pp, uint32_t *offset,
72*e591a766SBjoern A. Zeeb     size_t size, gfp_t gfp)
73*e591a766SBjoern A. Zeeb {
74*e591a766SBjoern A. Zeeb #ifdef PAGE_IS_LKPI_PAGE
75*e591a766SBjoern A. Zeeb 	struct page *p;
76*e591a766SBjoern A. Zeeb 	dma_addr_t dma;
77*e591a766SBjoern A. Zeeb 
78*e591a766SBjoern A. Zeeb 	if (size > PAGE_SIZE) {
79*e591a766SBjoern A. Zeeb 		pr_warn_once("%s: size %zu > PAGE_SIZE\n", __func__, size);
80*e591a766SBjoern A. Zeeb 		return (NULL);
81*e591a766SBjoern A. Zeeb 	}
82*e591a766SBjoern A. Zeeb 
83*e591a766SBjoern A. Zeeb 	/*
84*e591a766SBjoern A. Zeeb 	 * We do not try to be smart on the first cut until 'struct page' work
85*e591a766SBjoern A. Zeeb 	 * is sorted and settled.  Everyone gets a page for now.
86*e591a766SBjoern A. Zeeb 	 * XXX in the future deal with page fragments, pool limits, etc.
87*e591a766SBjoern A. Zeeb 	 */
88*e591a766SBjoern A. Zeeb 	p = alloc_page(gfp);
89*e591a766SBjoern A. Zeeb 	if (p == NULL)
90*e591a766SBjoern A. Zeeb 		return (NULL);
91*e591a766SBjoern A. Zeeb 
92*e591a766SBjoern A. Zeeb 	if (offset != NULL)
93*e591a766SBjoern A. Zeeb 		*offset = 0;
94*e591a766SBjoern A. Zeeb 
95*e591a766SBjoern A. Zeeb 	if ((pp->params.flags & PP_FLAG_DMA_MAP) != 0) {
96*e591a766SBjoern A. Zeeb 		dma = dma_map_page_attrs(pp->params.dev, p, 0, PAGE_SIZE,
97*e591a766SBjoern A. Zeeb 		    pp->params.dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
98*e591a766SBjoern A. Zeeb 		if (dma_mapping_error(pp->params.dev, dma)) {
99*e591a766SBjoern A. Zeeb 			put_page(p);
100*e591a766SBjoern A. Zeeb 			return (NULL);
101*e591a766SBjoern A. Zeeb 		}
102*e591a766SBjoern A. Zeeb 
103*e591a766SBjoern A. Zeeb 		/* We store the dma address in struct page as well. */
104*e591a766SBjoern A. Zeeb 		p->dma_addr = dma;
105*e591a766SBjoern A. Zeeb 	}
106*e591a766SBjoern A. Zeeb 
107*e591a766SBjoern A. Zeeb 	if ((pp->params.flags & PP_FLAG_DMA_SYNC_DEV) != 0)
108*e591a766SBjoern A. Zeeb 		dma_sync_single_for_device(pp->params.dev, dma, PAGE_SIZE,
109*e591a766SBjoern A. Zeeb 		    pp->params.dma_dir);
110*e591a766SBjoern A. Zeeb 
111*e591a766SBjoern A. Zeeb 	/*
112*e591a766SBjoern A. Zeeb 	 * We may not yet need to track the page pool on the page in order
113*e591a766SBjoern A. Zeeb 	 * to know where to return it but prepare at least for that.
114*e591a766SBjoern A. Zeeb 	 */
115*e591a766SBjoern A. Zeeb 	p->pp = pp;
116*e591a766SBjoern A. Zeeb 
117*e591a766SBjoern A. Zeeb 	return (p);
118*e591a766SBjoern A. Zeeb #else
119*e591a766SBjoern A. Zeeb 	return (NULL);
120*e591a766SBjoern A. Zeeb #endif /* PAGE_IS_LKPI_PAGE */
121*e591a766SBjoern A. Zeeb }
122*e591a766SBjoern A. Zeeb 
123*e591a766SBjoern A. Zeeb struct page *
linuxkpi_page_pool_dev_alloc_frag(struct page_pool * pp,uint32_t * offset,size_t size)124*e591a766SBjoern A. Zeeb linuxkpi_page_pool_dev_alloc_frag(struct page_pool *pp, uint32_t *offset,
125*e591a766SBjoern A. Zeeb     size_t size)
126*e591a766SBjoern A. Zeeb {
127*e591a766SBjoern A. Zeeb 	gfp_t gfp;
128*e591a766SBjoern A. Zeeb 
129*e591a766SBjoern A. Zeeb 	gfp = (GFP_ATOMIC | __GFP_NOWARN);
130*e591a766SBjoern A. Zeeb 	return (page_pool_alloc_frag(pp, offset, size, gfp));
131*e591a766SBjoern A. Zeeb }
132*e591a766SBjoern A. Zeeb 
133*e591a766SBjoern A. Zeeb void
linuxkpi_page_pool_put_full_page(struct page_pool * pp,struct page * page,bool allow_direct)134*e591a766SBjoern A. Zeeb linuxkpi_page_pool_put_full_page(struct page_pool *pp, struct page *page,
135*e591a766SBjoern A. Zeeb     bool allow_direct)
136*e591a766SBjoern A. Zeeb {
137*e591a766SBjoern A. Zeeb 	/* We just free the full page we handed out for now. */
138*e591a766SBjoern A. Zeeb #ifdef PAGE_IS_LKPI_PAGE
139*e591a766SBjoern A. Zeeb 	page->pp = NULL;
140*e591a766SBjoern A. Zeeb 	page->dma_addr = 0;
141*e591a766SBjoern A. Zeeb #endif
142*e591a766SBjoern A. Zeeb 	put_page(page);
143*e591a766SBjoern A. Zeeb }
144*e591a766SBjoern A. Zeeb 
145*e591a766SBjoern A. Zeeb dma_addr_t
linuxkpi_page_pool_get_dma_addr(const struct page * page)146*e591a766SBjoern A. Zeeb linuxkpi_page_pool_get_dma_addr(const struct page *page)
147*e591a766SBjoern A. Zeeb {
148*e591a766SBjoern A. Zeeb 
149*e591a766SBjoern A. Zeeb 	KASSERT(page != NULL, ("%s: page %p\n", __func__, page));
150*e591a766SBjoern A. Zeeb 
151*e591a766SBjoern A. Zeeb #ifdef PAGE_IS_LKPI_PAGE
152*e591a766SBjoern A. Zeeb 	return (page->dma_addr);
153*e591a766SBjoern A. Zeeb #else
154*e591a766SBjoern A. Zeeb 	return (0);
155*e591a766SBjoern A. Zeeb #endif
156*e591a766SBjoern A. Zeeb }
157