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
This commit is contained in:
parent
4b0af11437
commit
55038a6306
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user