xref: /freebsd/sys/compat/linuxkpi/common/src/linux_page.c (revision 1cdefd084d6e5aca88b1647d24fd3b02866865b6)
1*1cdefd08SHans Petter Selasky /*-
2*1cdefd08SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
3*1cdefd08SHans Petter Selasky  * Copyright (c) 2016 Matt Macy (mmacy@nextbsd.org)
4*1cdefd08SHans Petter Selasky  * Copyright (c) 2017 Mellanox Technologies, Ltd.
5*1cdefd08SHans Petter Selasky  * All rights reserved.
6*1cdefd08SHans Petter Selasky  *
7*1cdefd08SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
8*1cdefd08SHans Petter Selasky  * modification, are permitted provided that the following conditions
9*1cdefd08SHans Petter Selasky  * are met:
10*1cdefd08SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
11*1cdefd08SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
12*1cdefd08SHans Petter Selasky  *    disclaimer.
13*1cdefd08SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
14*1cdefd08SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
15*1cdefd08SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
16*1cdefd08SHans Petter Selasky  *
17*1cdefd08SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18*1cdefd08SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19*1cdefd08SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*1cdefd08SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21*1cdefd08SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22*1cdefd08SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23*1cdefd08SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24*1cdefd08SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25*1cdefd08SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26*1cdefd08SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*1cdefd08SHans Petter Selasky  */
28*1cdefd08SHans Petter Selasky 
29*1cdefd08SHans Petter Selasky #include <sys/cdefs.h>
30*1cdefd08SHans Petter Selasky __FBSDID("$FreeBSD$");
31*1cdefd08SHans Petter Selasky 
32*1cdefd08SHans Petter Selasky #include <sys/param.h>
33*1cdefd08SHans Petter Selasky #include <sys/systm.h>
34*1cdefd08SHans Petter Selasky #include <sys/malloc.h>
35*1cdefd08SHans Petter Selasky #include <sys/kernel.h>
36*1cdefd08SHans Petter Selasky #include <sys/sysctl.h>
37*1cdefd08SHans Petter Selasky #include <sys/lock.h>
38*1cdefd08SHans Petter Selasky #include <sys/mutex.h>
39*1cdefd08SHans Petter Selasky #include <sys/rwlock.h>
40*1cdefd08SHans Petter Selasky #include <sys/proc.h>
41*1cdefd08SHans Petter Selasky #include <sys/sched.h>
42*1cdefd08SHans Petter Selasky 
43*1cdefd08SHans Petter Selasky #include <machine/bus.h>
44*1cdefd08SHans Petter Selasky 
45*1cdefd08SHans Petter Selasky #include <linux/gfp.h>
46*1cdefd08SHans Petter Selasky 
47*1cdefd08SHans Petter Selasky #include <vm/vm.h>
48*1cdefd08SHans Petter Selasky #include <vm/vm_page.h>
49*1cdefd08SHans Petter Selasky #include <vm/vm_pageout.h>
50*1cdefd08SHans Petter Selasky 
51*1cdefd08SHans Petter Selasky void *
52*1cdefd08SHans Petter Selasky linux_page_address(struct page *page)
53*1cdefd08SHans Petter Selasky {
54*1cdefd08SHans Petter Selasky #ifdef __amd64__
55*1cdefd08SHans Petter Selasky 	return ((void *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page)));
56*1cdefd08SHans Petter Selasky #else
57*1cdefd08SHans Petter Selasky 	if (page->object != kmem_object && page->object != kernel_object)
58*1cdefd08SHans Petter Selasky 		return (NULL);
59*1cdefd08SHans Petter Selasky 	return ((void *)(uintptr_t)(VM_MIN_KERNEL_ADDRESS +
60*1cdefd08SHans Petter Selasky 	    IDX_TO_OFF(page->pindex)));
61*1cdefd08SHans Petter Selasky #endif
62*1cdefd08SHans Petter Selasky }
63*1cdefd08SHans Petter Selasky 
64*1cdefd08SHans Petter Selasky vm_page_t
65*1cdefd08SHans Petter Selasky linux_alloc_pages(gfp_t flags, unsigned int order)
66*1cdefd08SHans Petter Selasky {
67*1cdefd08SHans Petter Selasky #ifdef __amd64__
68*1cdefd08SHans Petter Selasky 	unsigned long npages = 1UL << order;
69*1cdefd08SHans Petter Selasky 	int req = (flags & M_ZERO) ? (VM_ALLOC_ZERO | VM_ALLOC_NOOBJ |
70*1cdefd08SHans Petter Selasky 	    VM_ALLOC_NORMAL) : (VM_ALLOC_NOOBJ | VM_ALLOC_NORMAL);
71*1cdefd08SHans Petter Selasky 	vm_page_t page;
72*1cdefd08SHans Petter Selasky 
73*1cdefd08SHans Petter Selasky 	if (order == 0 && (flags & GFP_DMA32) == 0) {
74*1cdefd08SHans Petter Selasky 		page = vm_page_alloc(NULL, 0, req);
75*1cdefd08SHans Petter Selasky 		if (page == NULL)
76*1cdefd08SHans Petter Selasky 			return (NULL);
77*1cdefd08SHans Petter Selasky 	} else {
78*1cdefd08SHans Petter Selasky 		vm_paddr_t pmax = (flags & GFP_DMA32) ?
79*1cdefd08SHans Petter Selasky 		    BUS_SPACE_MAXADDR_32BIT : BUS_SPACE_MAXADDR;
80*1cdefd08SHans Petter Selasky retry:
81*1cdefd08SHans Petter Selasky 		page = vm_page_alloc_contig(NULL, 0, req,
82*1cdefd08SHans Petter Selasky 		    npages, 0, pmax, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
83*1cdefd08SHans Petter Selasky 
84*1cdefd08SHans Petter Selasky 		if (page == NULL) {
85*1cdefd08SHans Petter Selasky 			if (flags & M_WAITOK) {
86*1cdefd08SHans Petter Selasky 				if (!vm_page_reclaim_contig(req,
87*1cdefd08SHans Petter Selasky 				    npages, 0, pmax, PAGE_SIZE, 0)) {
88*1cdefd08SHans Petter Selasky 					VM_WAIT;
89*1cdefd08SHans Petter Selasky 				}
90*1cdefd08SHans Petter Selasky 				flags &= ~M_WAITOK;
91*1cdefd08SHans Petter Selasky 				goto retry;
92*1cdefd08SHans Petter Selasky 			}
93*1cdefd08SHans Petter Selasky 			return (NULL);
94*1cdefd08SHans Petter Selasky 		}
95*1cdefd08SHans Petter Selasky 	}
96*1cdefd08SHans Petter Selasky 	if (flags & M_ZERO) {
97*1cdefd08SHans Petter Selasky 		unsigned long x;
98*1cdefd08SHans Petter Selasky 
99*1cdefd08SHans Petter Selasky 		for (x = 0; x != npages; x++) {
100*1cdefd08SHans Petter Selasky 			vm_page_t pgo = page + x;
101*1cdefd08SHans Petter Selasky 
102*1cdefd08SHans Petter Selasky 			if ((pgo->flags & PG_ZERO) == 0)
103*1cdefd08SHans Petter Selasky 				pmap_zero_page(pgo);
104*1cdefd08SHans Petter Selasky 		}
105*1cdefd08SHans Petter Selasky 	}
106*1cdefd08SHans Petter Selasky #else
107*1cdefd08SHans Petter Selasky 	vm_offset_t vaddr;
108*1cdefd08SHans Petter Selasky 	vm_page_t page;
109*1cdefd08SHans Petter Selasky 
110*1cdefd08SHans Petter Selasky 	vaddr = linux_alloc_kmem(flags, order);
111*1cdefd08SHans Petter Selasky 	if (vaddr == 0)
112*1cdefd08SHans Petter Selasky 		return (NULL);
113*1cdefd08SHans Petter Selasky 
114*1cdefd08SHans Petter Selasky 	page = PHYS_TO_VM_PAGE(vtophys((void *)vaddr));
115*1cdefd08SHans Petter Selasky 
116*1cdefd08SHans Petter Selasky 	KASSERT(vaddr == (vm_offset_t)page_address(page),
117*1cdefd08SHans Petter Selasky 	    ("Page address mismatch"));
118*1cdefd08SHans Petter Selasky #endif
119*1cdefd08SHans Petter Selasky 	return (page);
120*1cdefd08SHans Petter Selasky }
121*1cdefd08SHans Petter Selasky 
122*1cdefd08SHans Petter Selasky void
123*1cdefd08SHans Petter Selasky linux_free_pages(vm_page_t page, unsigned int order)
124*1cdefd08SHans Petter Selasky {
125*1cdefd08SHans Petter Selasky #ifdef __amd64__
126*1cdefd08SHans Petter Selasky 	unsigned long npages = 1UL << order;
127*1cdefd08SHans Petter Selasky 	unsigned long x;
128*1cdefd08SHans Petter Selasky 
129*1cdefd08SHans Petter Selasky 	for (x = 0; x != npages; x++) {
130*1cdefd08SHans Petter Selasky 		vm_page_t pgo = page + x;
131*1cdefd08SHans Petter Selasky 
132*1cdefd08SHans Petter Selasky 		vm_page_lock(pgo);
133*1cdefd08SHans Petter Selasky 		vm_page_free(pgo);
134*1cdefd08SHans Petter Selasky 		vm_page_unlock(pgo);
135*1cdefd08SHans Petter Selasky 	}
136*1cdefd08SHans Petter Selasky #else
137*1cdefd08SHans Petter Selasky 	vm_offset_t vaddr;
138*1cdefd08SHans Petter Selasky 
139*1cdefd08SHans Petter Selasky 	vaddr = (vm_offset_t)page_address(page);
140*1cdefd08SHans Petter Selasky 
141*1cdefd08SHans Petter Selasky 	linux_free_kmem(vaddr, order);
142*1cdefd08SHans Petter Selasky #endif
143*1cdefd08SHans Petter Selasky }
144*1cdefd08SHans Petter Selasky 
145*1cdefd08SHans Petter Selasky vm_offset_t
146*1cdefd08SHans Petter Selasky linux_alloc_kmem(gfp_t flags, unsigned int order)
147*1cdefd08SHans Petter Selasky {
148*1cdefd08SHans Petter Selasky 	size_t size = ((size_t)PAGE_SIZE) << order;
149*1cdefd08SHans Petter Selasky 	vm_offset_t addr;
150*1cdefd08SHans Petter Selasky 
151*1cdefd08SHans Petter Selasky 	if ((flags & GFP_DMA32) == 0) {
152*1cdefd08SHans Petter Selasky 		addr = kmem_malloc(kmem_arena, size, flags & GFP_NATIVE_MASK);
153*1cdefd08SHans Petter Selasky 	} else {
154*1cdefd08SHans Petter Selasky 		addr = kmem_alloc_contig(kmem_arena, size,
155*1cdefd08SHans Petter Selasky 		    flags & GFP_NATIVE_MASK, 0, BUS_SPACE_MAXADDR_32BIT,
156*1cdefd08SHans Petter Selasky 		    PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
157*1cdefd08SHans Petter Selasky 	}
158*1cdefd08SHans Petter Selasky 	return (addr);
159*1cdefd08SHans Petter Selasky }
160*1cdefd08SHans Petter Selasky 
161*1cdefd08SHans Petter Selasky void
162*1cdefd08SHans Petter Selasky linux_free_kmem(vm_offset_t addr, unsigned int order)
163*1cdefd08SHans Petter Selasky {
164*1cdefd08SHans Petter Selasky 	size_t size = ((size_t)PAGE_SIZE) << order;
165*1cdefd08SHans Petter Selasky 
166*1cdefd08SHans Petter Selasky 	kmem_free(kmem_arena, addr, size);
167*1cdefd08SHans Petter Selasky }
168