xref: /OK3568_Linux_fs/kernel/drivers/xen/grant-table.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /******************************************************************************
2*4882a593Smuzhiyun  * grant_table.c
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Granting foreign access to our memory reservation.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (c) 2005-2006, Christopher Clark
7*4882a593Smuzhiyun  * Copyright (c) 2004-2005, K A Fraser
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
10*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License version 2
11*4882a593Smuzhiyun  * as published by the Free Software Foundation; or, when distributed
12*4882a593Smuzhiyun  * separately from the Linux kernel or incorporated into other
13*4882a593Smuzhiyun  * software packages, subject to the following license:
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a copy
16*4882a593Smuzhiyun  * of this source file (the "Software"), to deal in the Software without
17*4882a593Smuzhiyun  * restriction, including without limitation the rights to use, copy, modify,
18*4882a593Smuzhiyun  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19*4882a593Smuzhiyun  * and to permit persons to whom the Software is furnished to do so, subject to
20*4882a593Smuzhiyun  * the following conditions:
21*4882a593Smuzhiyun  *
22*4882a593Smuzhiyun  * The above copyright notice and this permission notice shall be included in
23*4882a593Smuzhiyun  * all copies or substantial portions of the Software.
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28*4882a593Smuzhiyun  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29*4882a593Smuzhiyun  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30*4882a593Smuzhiyun  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31*4882a593Smuzhiyun  * IN THE SOFTWARE.
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun #include <linux/memblock.h>
37*4882a593Smuzhiyun #include <linux/sched.h>
38*4882a593Smuzhiyun #include <linux/mm.h>
39*4882a593Smuzhiyun #include <linux/slab.h>
40*4882a593Smuzhiyun #include <linux/vmalloc.h>
41*4882a593Smuzhiyun #include <linux/uaccess.h>
42*4882a593Smuzhiyun #include <linux/io.h>
43*4882a593Smuzhiyun #include <linux/delay.h>
44*4882a593Smuzhiyun #include <linux/hardirq.h>
45*4882a593Smuzhiyun #include <linux/workqueue.h>
46*4882a593Smuzhiyun #include <linux/ratelimit.h>
47*4882a593Smuzhiyun #include <linux/moduleparam.h>
48*4882a593Smuzhiyun #ifdef CONFIG_XEN_GRANT_DMA_ALLOC
49*4882a593Smuzhiyun #include <linux/dma-mapping.h>
50*4882a593Smuzhiyun #endif
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #include <xen/xen.h>
53*4882a593Smuzhiyun #include <xen/interface/xen.h>
54*4882a593Smuzhiyun #include <xen/page.h>
55*4882a593Smuzhiyun #include <xen/grant_table.h>
56*4882a593Smuzhiyun #include <xen/interface/memory.h>
57*4882a593Smuzhiyun #include <xen/hvc-console.h>
58*4882a593Smuzhiyun #include <xen/swiotlb-xen.h>
59*4882a593Smuzhiyun #include <xen/balloon.h>
60*4882a593Smuzhiyun #ifdef CONFIG_X86
61*4882a593Smuzhiyun #include <asm/xen/cpuid.h>
62*4882a593Smuzhiyun #endif
63*4882a593Smuzhiyun #include <xen/mem-reservation.h>
64*4882a593Smuzhiyun #include <asm/xen/hypercall.h>
65*4882a593Smuzhiyun #include <asm/xen/interface.h>
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #include <asm/sync_bitops.h>
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun /* External tools reserve first few grant table entries. */
70*4882a593Smuzhiyun #define NR_RESERVED_ENTRIES 8
71*4882a593Smuzhiyun #define GNTTAB_LIST_END 0xffffffff
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static grant_ref_t **gnttab_list;
74*4882a593Smuzhiyun static unsigned int nr_grant_frames;
75*4882a593Smuzhiyun static int gnttab_free_count;
76*4882a593Smuzhiyun static grant_ref_t gnttab_free_head;
77*4882a593Smuzhiyun static DEFINE_SPINLOCK(gnttab_list_lock);
78*4882a593Smuzhiyun struct grant_frames xen_auto_xlat_grant_frames;
79*4882a593Smuzhiyun static unsigned int xen_gnttab_version;
80*4882a593Smuzhiyun module_param_named(version, xen_gnttab_version, uint, 0);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun static union {
83*4882a593Smuzhiyun 	struct grant_entry_v1 *v1;
84*4882a593Smuzhiyun 	union grant_entry_v2 *v2;
85*4882a593Smuzhiyun 	void *addr;
86*4882a593Smuzhiyun } gnttab_shared;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /*This is a structure of function pointers for grant table*/
89*4882a593Smuzhiyun struct gnttab_ops {
90*4882a593Smuzhiyun 	/*
91*4882a593Smuzhiyun 	 * Version of the grant interface.
92*4882a593Smuzhiyun 	 */
93*4882a593Smuzhiyun 	unsigned int version;
94*4882a593Smuzhiyun 	/*
95*4882a593Smuzhiyun 	 * Grant refs per grant frame.
96*4882a593Smuzhiyun 	 */
97*4882a593Smuzhiyun 	unsigned int grefs_per_grant_frame;
98*4882a593Smuzhiyun 	/*
99*4882a593Smuzhiyun 	 * Mapping a list of frames for storing grant entries. Frames parameter
100*4882a593Smuzhiyun 	 * is used to store grant table address when grant table being setup,
101*4882a593Smuzhiyun 	 * nr_gframes is the number of frames to map grant table. Returning
102*4882a593Smuzhiyun 	 * GNTST_okay means success and negative value means failure.
103*4882a593Smuzhiyun 	 */
104*4882a593Smuzhiyun 	int (*map_frames)(xen_pfn_t *frames, unsigned int nr_gframes);
105*4882a593Smuzhiyun 	/*
106*4882a593Smuzhiyun 	 * Release a list of frames which are mapped in map_frames for grant
107*4882a593Smuzhiyun 	 * entry status.
108*4882a593Smuzhiyun 	 */
109*4882a593Smuzhiyun 	void (*unmap_frames)(void);
110*4882a593Smuzhiyun 	/*
111*4882a593Smuzhiyun 	 * Introducing a valid entry into the grant table, granting the frame of
112*4882a593Smuzhiyun 	 * this grant entry to domain for accessing or transfering. Ref
113*4882a593Smuzhiyun 	 * parameter is reference of this introduced grant entry, domid is id of
114*4882a593Smuzhiyun 	 * granted domain, frame is the page frame to be granted, and flags is
115*4882a593Smuzhiyun 	 * status of the grant entry to be updated.
116*4882a593Smuzhiyun 	 */
117*4882a593Smuzhiyun 	void (*update_entry)(grant_ref_t ref, domid_t domid,
118*4882a593Smuzhiyun 			     unsigned long frame, unsigned flags);
119*4882a593Smuzhiyun 	/*
120*4882a593Smuzhiyun 	 * Stop granting a grant entry to domain for accessing. Ref parameter is
121*4882a593Smuzhiyun 	 * reference of a grant entry whose grant access will be stopped,
122*4882a593Smuzhiyun 	 * readonly is not in use in this function. If the grant entry is
123*4882a593Smuzhiyun 	 * currently mapped for reading or writing, just return failure(==0)
124*4882a593Smuzhiyun 	 * directly and don't tear down the grant access. Otherwise, stop grant
125*4882a593Smuzhiyun 	 * access for this entry and return success(==1).
126*4882a593Smuzhiyun 	 */
127*4882a593Smuzhiyun 	int (*end_foreign_access_ref)(grant_ref_t ref, int readonly);
128*4882a593Smuzhiyun 	/*
129*4882a593Smuzhiyun 	 * Stop granting a grant entry to domain for transfer. Ref parameter is
130*4882a593Smuzhiyun 	 * reference of a grant entry whose grant transfer will be stopped. If
131*4882a593Smuzhiyun 	 * tranfer has not started, just reclaim the grant entry and return
132*4882a593Smuzhiyun 	 * failure(==0). Otherwise, wait for the transfer to complete and then
133*4882a593Smuzhiyun 	 * return the frame.
134*4882a593Smuzhiyun 	 */
135*4882a593Smuzhiyun 	unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
136*4882a593Smuzhiyun 	/*
137*4882a593Smuzhiyun 	 * Read the frame number related to a given grant reference.
138*4882a593Smuzhiyun 	 */
139*4882a593Smuzhiyun 	unsigned long (*read_frame)(grant_ref_t ref);
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun struct unmap_refs_callback_data {
143*4882a593Smuzhiyun 	struct completion completion;
144*4882a593Smuzhiyun 	int result;
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun static const struct gnttab_ops *gnttab_interface;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun /* This reflects status of grant entries, so act as a global value. */
150*4882a593Smuzhiyun static grant_status_t *grstatus;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun static struct gnttab_free_callback *gnttab_free_callback_list;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun static int gnttab_expand(unsigned int req_entries);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun #define RPP (PAGE_SIZE / sizeof(grant_ref_t))
157*4882a593Smuzhiyun #define SPP (PAGE_SIZE / sizeof(grant_status_t))
158*4882a593Smuzhiyun 
__gnttab_entry(grant_ref_t entry)159*4882a593Smuzhiyun static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	return &gnttab_list[(entry) / RPP][(entry) % RPP];
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun /* This can be used as an l-value */
164*4882a593Smuzhiyun #define gnttab_entry(entry) (*__gnttab_entry(entry))
165*4882a593Smuzhiyun 
get_free_entries(unsigned count)166*4882a593Smuzhiyun static int get_free_entries(unsigned count)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	unsigned long flags;
169*4882a593Smuzhiyun 	int ref, rc = 0;
170*4882a593Smuzhiyun 	grant_ref_t head;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	spin_lock_irqsave(&gnttab_list_lock, flags);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	if ((gnttab_free_count < count) &&
175*4882a593Smuzhiyun 	    ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
176*4882a593Smuzhiyun 		spin_unlock_irqrestore(&gnttab_list_lock, flags);
177*4882a593Smuzhiyun 		return rc;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	ref = head = gnttab_free_head;
181*4882a593Smuzhiyun 	gnttab_free_count -= count;
182*4882a593Smuzhiyun 	while (count-- > 1)
183*4882a593Smuzhiyun 		head = gnttab_entry(head);
184*4882a593Smuzhiyun 	gnttab_free_head = gnttab_entry(head);
185*4882a593Smuzhiyun 	gnttab_entry(head) = GNTTAB_LIST_END;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	spin_unlock_irqrestore(&gnttab_list_lock, flags);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return ref;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
do_free_callbacks(void)192*4882a593Smuzhiyun static void do_free_callbacks(void)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun 	struct gnttab_free_callback *callback, *next;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	callback = gnttab_free_callback_list;
197*4882a593Smuzhiyun 	gnttab_free_callback_list = NULL;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	while (callback != NULL) {
200*4882a593Smuzhiyun 		next = callback->next;
201*4882a593Smuzhiyun 		if (gnttab_free_count >= callback->count) {
202*4882a593Smuzhiyun 			callback->next = NULL;
203*4882a593Smuzhiyun 			callback->fn(callback->arg);
204*4882a593Smuzhiyun 		} else {
205*4882a593Smuzhiyun 			callback->next = gnttab_free_callback_list;
206*4882a593Smuzhiyun 			gnttab_free_callback_list = callback;
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 		callback = next;
209*4882a593Smuzhiyun 	}
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun 
check_free_callbacks(void)212*4882a593Smuzhiyun static inline void check_free_callbacks(void)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	if (unlikely(gnttab_free_callback_list))
215*4882a593Smuzhiyun 		do_free_callbacks();
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
put_free_entry(grant_ref_t ref)218*4882a593Smuzhiyun static void put_free_entry(grant_ref_t ref)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	unsigned long flags;
221*4882a593Smuzhiyun 	spin_lock_irqsave(&gnttab_list_lock, flags);
222*4882a593Smuzhiyun 	gnttab_entry(ref) = gnttab_free_head;
223*4882a593Smuzhiyun 	gnttab_free_head = ref;
224*4882a593Smuzhiyun 	gnttab_free_count++;
225*4882a593Smuzhiyun 	check_free_callbacks();
226*4882a593Smuzhiyun 	spin_unlock_irqrestore(&gnttab_list_lock, flags);
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun /*
230*4882a593Smuzhiyun  * Following applies to gnttab_update_entry_v1 and gnttab_update_entry_v2.
231*4882a593Smuzhiyun  * Introducing a valid entry into the grant table:
232*4882a593Smuzhiyun  *  1. Write ent->domid.
233*4882a593Smuzhiyun  *  2. Write ent->frame:
234*4882a593Smuzhiyun  *      GTF_permit_access:   Frame to which access is permitted.
235*4882a593Smuzhiyun  *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
236*4882a593Smuzhiyun  *                           frame, or zero if none.
237*4882a593Smuzhiyun  *  3. Write memory barrier (WMB).
238*4882a593Smuzhiyun  *  4. Write ent->flags, inc. valid type.
239*4882a593Smuzhiyun  */
gnttab_update_entry_v1(grant_ref_t ref,domid_t domid,unsigned long frame,unsigned flags)240*4882a593Smuzhiyun static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
241*4882a593Smuzhiyun 				   unsigned long frame, unsigned flags)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	gnttab_shared.v1[ref].domid = domid;
244*4882a593Smuzhiyun 	gnttab_shared.v1[ref].frame = frame;
245*4882a593Smuzhiyun 	wmb();
246*4882a593Smuzhiyun 	gnttab_shared.v1[ref].flags = flags;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
gnttab_update_entry_v2(grant_ref_t ref,domid_t domid,unsigned long frame,unsigned int flags)249*4882a593Smuzhiyun static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid,
250*4882a593Smuzhiyun 				   unsigned long frame, unsigned int flags)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	gnttab_shared.v2[ref].hdr.domid = domid;
253*4882a593Smuzhiyun 	gnttab_shared.v2[ref].full_page.frame = frame;
254*4882a593Smuzhiyun 	wmb();	/* Hypervisor concurrent accesses. */
255*4882a593Smuzhiyun 	gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun /*
259*4882a593Smuzhiyun  * Public grant-issuing interface functions
260*4882a593Smuzhiyun  */
gnttab_grant_foreign_access_ref(grant_ref_t ref,domid_t domid,unsigned long frame,int readonly)261*4882a593Smuzhiyun void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
262*4882a593Smuzhiyun 				     unsigned long frame, int readonly)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun 	gnttab_interface->update_entry(ref, domid, frame,
265*4882a593Smuzhiyun 			   GTF_permit_access | (readonly ? GTF_readonly : 0));
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
268*4882a593Smuzhiyun 
gnttab_grant_foreign_access(domid_t domid,unsigned long frame,int readonly)269*4882a593Smuzhiyun int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
270*4882a593Smuzhiyun 				int readonly)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	int ref;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	ref = get_free_entries(1);
275*4882a593Smuzhiyun 	if (unlikely(ref < 0))
276*4882a593Smuzhiyun 		return -ENOSPC;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	return ref;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
283*4882a593Smuzhiyun 
gnttab_end_foreign_access_ref_v1(grant_ref_t ref,int readonly)284*4882a593Smuzhiyun static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	u16 flags, nflags;
287*4882a593Smuzhiyun 	u16 *pflags;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	pflags = &gnttab_shared.v1[ref].flags;
290*4882a593Smuzhiyun 	nflags = *pflags;
291*4882a593Smuzhiyun 	do {
292*4882a593Smuzhiyun 		flags = nflags;
293*4882a593Smuzhiyun 		if (flags & (GTF_reading|GTF_writing))
294*4882a593Smuzhiyun 			return 0;
295*4882a593Smuzhiyun 	} while ((nflags = sync_cmpxchg(pflags, flags, 0)) != flags);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return 1;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
gnttab_end_foreign_access_ref_v2(grant_ref_t ref,int readonly)300*4882a593Smuzhiyun static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun 	gnttab_shared.v2[ref].hdr.flags = 0;
303*4882a593Smuzhiyun 	mb();	/* Concurrent access by hypervisor. */
304*4882a593Smuzhiyun 	if (grstatus[ref] & (GTF_reading|GTF_writing)) {
305*4882a593Smuzhiyun 		return 0;
306*4882a593Smuzhiyun 	} else {
307*4882a593Smuzhiyun 		/*
308*4882a593Smuzhiyun 		 * The read of grstatus needs to have acquire semantics.
309*4882a593Smuzhiyun 		 *  On x86, reads already have that, and we just need to
310*4882a593Smuzhiyun 		 * protect against compiler reorderings.
311*4882a593Smuzhiyun 		 * On other architectures we may need a full barrier.
312*4882a593Smuzhiyun 		 */
313*4882a593Smuzhiyun #ifdef CONFIG_X86
314*4882a593Smuzhiyun 		barrier();
315*4882a593Smuzhiyun #else
316*4882a593Smuzhiyun 		mb();
317*4882a593Smuzhiyun #endif
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	return 1;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
_gnttab_end_foreign_access_ref(grant_ref_t ref,int readonly)323*4882a593Smuzhiyun static inline int _gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	return gnttab_interface->end_foreign_access_ref(ref, readonly);
326*4882a593Smuzhiyun }
327*4882a593Smuzhiyun 
gnttab_end_foreign_access_ref(grant_ref_t ref,int readonly)328*4882a593Smuzhiyun int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	if (_gnttab_end_foreign_access_ref(ref, readonly))
331*4882a593Smuzhiyun 		return 1;
332*4882a593Smuzhiyun 	pr_warn("WARNING: g.e. %#x still in use!\n", ref);
333*4882a593Smuzhiyun 	return 0;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
336*4882a593Smuzhiyun 
gnttab_read_frame_v1(grant_ref_t ref)337*4882a593Smuzhiyun static unsigned long gnttab_read_frame_v1(grant_ref_t ref)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	return gnttab_shared.v1[ref].frame;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
gnttab_read_frame_v2(grant_ref_t ref)342*4882a593Smuzhiyun static unsigned long gnttab_read_frame_v2(grant_ref_t ref)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	return gnttab_shared.v2[ref].full_page.frame;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun struct deferred_entry {
348*4882a593Smuzhiyun 	struct list_head list;
349*4882a593Smuzhiyun 	grant_ref_t ref;
350*4882a593Smuzhiyun 	bool ro;
351*4882a593Smuzhiyun 	uint16_t warn_delay;
352*4882a593Smuzhiyun 	struct page *page;
353*4882a593Smuzhiyun };
354*4882a593Smuzhiyun static LIST_HEAD(deferred_list);
355*4882a593Smuzhiyun static void gnttab_handle_deferred(struct timer_list *);
356*4882a593Smuzhiyun static DEFINE_TIMER(deferred_timer, gnttab_handle_deferred);
357*4882a593Smuzhiyun 
gnttab_handle_deferred(struct timer_list * unused)358*4882a593Smuzhiyun static void gnttab_handle_deferred(struct timer_list *unused)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	unsigned int nr = 10;
361*4882a593Smuzhiyun 	struct deferred_entry *first = NULL;
362*4882a593Smuzhiyun 	unsigned long flags;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	spin_lock_irqsave(&gnttab_list_lock, flags);
365*4882a593Smuzhiyun 	while (nr--) {
366*4882a593Smuzhiyun 		struct deferred_entry *entry
367*4882a593Smuzhiyun 			= list_first_entry(&deferred_list,
368*4882a593Smuzhiyun 					   struct deferred_entry, list);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 		if (entry == first)
371*4882a593Smuzhiyun 			break;
372*4882a593Smuzhiyun 		list_del(&entry->list);
373*4882a593Smuzhiyun 		spin_unlock_irqrestore(&gnttab_list_lock, flags);
374*4882a593Smuzhiyun 		if (_gnttab_end_foreign_access_ref(entry->ref, entry->ro)) {
375*4882a593Smuzhiyun 			put_free_entry(entry->ref);
376*4882a593Smuzhiyun 			pr_debug("freeing g.e. %#x (pfn %#lx)\n",
377*4882a593Smuzhiyun 				 entry->ref, page_to_pfn(entry->page));
378*4882a593Smuzhiyun 			put_page(entry->page);
379*4882a593Smuzhiyun 			kfree(entry);
380*4882a593Smuzhiyun 			entry = NULL;
381*4882a593Smuzhiyun 		} else {
382*4882a593Smuzhiyun 			if (!--entry->warn_delay)
383*4882a593Smuzhiyun 				pr_info("g.e. %#x still pending\n", entry->ref);
384*4882a593Smuzhiyun 			if (!first)
385*4882a593Smuzhiyun 				first = entry;
386*4882a593Smuzhiyun 		}
387*4882a593Smuzhiyun 		spin_lock_irqsave(&gnttab_list_lock, flags);
388*4882a593Smuzhiyun 		if (entry)
389*4882a593Smuzhiyun 			list_add_tail(&entry->list, &deferred_list);
390*4882a593Smuzhiyun 		else if (list_empty(&deferred_list))
391*4882a593Smuzhiyun 			break;
392*4882a593Smuzhiyun 	}
393*4882a593Smuzhiyun 	if (!list_empty(&deferred_list) && !timer_pending(&deferred_timer)) {
394*4882a593Smuzhiyun 		deferred_timer.expires = jiffies + HZ;
395*4882a593Smuzhiyun 		add_timer(&deferred_timer);
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 	spin_unlock_irqrestore(&gnttab_list_lock, flags);
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
gnttab_add_deferred(grant_ref_t ref,bool readonly,struct page * page)400*4882a593Smuzhiyun static void gnttab_add_deferred(grant_ref_t ref, bool readonly,
401*4882a593Smuzhiyun 				struct page *page)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	struct deferred_entry *entry;
404*4882a593Smuzhiyun 	gfp_t gfp = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
405*4882a593Smuzhiyun 	const char *what = KERN_WARNING "leaking";
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	entry = kmalloc(sizeof(*entry), gfp);
408*4882a593Smuzhiyun 	if (!page) {
409*4882a593Smuzhiyun 		unsigned long gfn = gnttab_interface->read_frame(ref);
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 		page = pfn_to_page(gfn_to_pfn(gfn));
412*4882a593Smuzhiyun 		get_page(page);
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (entry) {
416*4882a593Smuzhiyun 		unsigned long flags;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		entry->ref = ref;
419*4882a593Smuzhiyun 		entry->ro = readonly;
420*4882a593Smuzhiyun 		entry->page = page;
421*4882a593Smuzhiyun 		entry->warn_delay = 60;
422*4882a593Smuzhiyun 		spin_lock_irqsave(&gnttab_list_lock, flags);
423*4882a593Smuzhiyun 		list_add_tail(&entry->list, &deferred_list);
424*4882a593Smuzhiyun 		if (!timer_pending(&deferred_timer)) {
425*4882a593Smuzhiyun 			deferred_timer.expires = jiffies + HZ;
426*4882a593Smuzhiyun 			add_timer(&deferred_timer);
427*4882a593Smuzhiyun 		}
428*4882a593Smuzhiyun 		spin_unlock_irqrestore(&gnttab_list_lock, flags);
429*4882a593Smuzhiyun 		what = KERN_DEBUG "deferring";
430*4882a593Smuzhiyun 	}
431*4882a593Smuzhiyun 	printk("%s g.e. %#x (pfn %#lx)\n",
432*4882a593Smuzhiyun 	       what, ref, page ? page_to_pfn(page) : -1);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
gnttab_try_end_foreign_access(grant_ref_t ref)435*4882a593Smuzhiyun int gnttab_try_end_foreign_access(grant_ref_t ref)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun 	int ret = _gnttab_end_foreign_access_ref(ref, 0);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	if (ret)
440*4882a593Smuzhiyun 		put_free_entry(ref);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	return ret;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_try_end_foreign_access);
445*4882a593Smuzhiyun 
gnttab_end_foreign_access(grant_ref_t ref,int readonly,unsigned long page)446*4882a593Smuzhiyun void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
447*4882a593Smuzhiyun 			       unsigned long page)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	if (gnttab_try_end_foreign_access(ref)) {
450*4882a593Smuzhiyun 		if (page != 0)
451*4882a593Smuzhiyun 			put_page(virt_to_page(page));
452*4882a593Smuzhiyun 	} else
453*4882a593Smuzhiyun 		gnttab_add_deferred(ref, readonly,
454*4882a593Smuzhiyun 				    page ? virt_to_page(page) : NULL);
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
457*4882a593Smuzhiyun 
gnttab_grant_foreign_transfer(domid_t domid,unsigned long pfn)458*4882a593Smuzhiyun int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun 	int ref;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	ref = get_free_entries(1);
463*4882a593Smuzhiyun 	if (unlikely(ref < 0))
464*4882a593Smuzhiyun 		return -ENOSPC;
465*4882a593Smuzhiyun 	gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	return ref;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
470*4882a593Smuzhiyun 
gnttab_grant_foreign_transfer_ref(grant_ref_t ref,domid_t domid,unsigned long pfn)471*4882a593Smuzhiyun void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
472*4882a593Smuzhiyun 				       unsigned long pfn)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun 	gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer);
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
477*4882a593Smuzhiyun 
gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)478*4882a593Smuzhiyun static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	unsigned long frame;
481*4882a593Smuzhiyun 	u16           flags;
482*4882a593Smuzhiyun 	u16          *pflags;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	pflags = &gnttab_shared.v1[ref].flags;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	/*
487*4882a593Smuzhiyun 	 * If a transfer is not even yet started, try to reclaim the grant
488*4882a593Smuzhiyun 	 * reference and return failure (== 0).
489*4882a593Smuzhiyun 	 */
490*4882a593Smuzhiyun 	while (!((flags = *pflags) & GTF_transfer_committed)) {
491*4882a593Smuzhiyun 		if (sync_cmpxchg(pflags, flags, 0) == flags)
492*4882a593Smuzhiyun 			return 0;
493*4882a593Smuzhiyun 		cpu_relax();
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/* If a transfer is in progress then wait until it is completed. */
497*4882a593Smuzhiyun 	while (!(flags & GTF_transfer_completed)) {
498*4882a593Smuzhiyun 		flags = *pflags;
499*4882a593Smuzhiyun 		cpu_relax();
500*4882a593Smuzhiyun 	}
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	rmb();	/* Read the frame number /after/ reading completion status. */
503*4882a593Smuzhiyun 	frame = gnttab_shared.v1[ref].frame;
504*4882a593Smuzhiyun 	BUG_ON(frame == 0);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	return frame;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun 
gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)509*4882a593Smuzhiyun static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	unsigned long frame;
512*4882a593Smuzhiyun 	u16           flags;
513*4882a593Smuzhiyun 	u16          *pflags;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	pflags = &gnttab_shared.v2[ref].hdr.flags;
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	/*
518*4882a593Smuzhiyun 	 * If a transfer is not even yet started, try to reclaim the grant
519*4882a593Smuzhiyun 	 * reference and return failure (== 0).
520*4882a593Smuzhiyun 	 */
521*4882a593Smuzhiyun 	while (!((flags = *pflags) & GTF_transfer_committed)) {
522*4882a593Smuzhiyun 		if (sync_cmpxchg(pflags, flags, 0) == flags)
523*4882a593Smuzhiyun 			return 0;
524*4882a593Smuzhiyun 		cpu_relax();
525*4882a593Smuzhiyun 	}
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	/* If a transfer is in progress then wait until it is completed. */
528*4882a593Smuzhiyun 	while (!(flags & GTF_transfer_completed)) {
529*4882a593Smuzhiyun 		flags = *pflags;
530*4882a593Smuzhiyun 		cpu_relax();
531*4882a593Smuzhiyun 	}
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	rmb();  /* Read the frame number /after/ reading completion status. */
534*4882a593Smuzhiyun 	frame = gnttab_shared.v2[ref].full_page.frame;
535*4882a593Smuzhiyun 	BUG_ON(frame == 0);
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	return frame;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun 
gnttab_end_foreign_transfer_ref(grant_ref_t ref)540*4882a593Smuzhiyun unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun 	return gnttab_interface->end_foreign_transfer_ref(ref);
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
545*4882a593Smuzhiyun 
gnttab_end_foreign_transfer(grant_ref_t ref)546*4882a593Smuzhiyun unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
549*4882a593Smuzhiyun 	put_free_entry(ref);
550*4882a593Smuzhiyun 	return frame;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
553*4882a593Smuzhiyun 
gnttab_free_grant_reference(grant_ref_t ref)554*4882a593Smuzhiyun void gnttab_free_grant_reference(grant_ref_t ref)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	put_free_entry(ref);
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
559*4882a593Smuzhiyun 
gnttab_free_grant_references(grant_ref_t head)560*4882a593Smuzhiyun void gnttab_free_grant_references(grant_ref_t head)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun 	grant_ref_t ref;
563*4882a593Smuzhiyun 	unsigned long flags;
564*4882a593Smuzhiyun 	int count = 1;
565*4882a593Smuzhiyun 	if (head == GNTTAB_LIST_END)
566*4882a593Smuzhiyun 		return;
567*4882a593Smuzhiyun 	spin_lock_irqsave(&gnttab_list_lock, flags);
568*4882a593Smuzhiyun 	ref = head;
569*4882a593Smuzhiyun 	while (gnttab_entry(ref) != GNTTAB_LIST_END) {
570*4882a593Smuzhiyun 		ref = gnttab_entry(ref);
571*4882a593Smuzhiyun 		count++;
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 	gnttab_entry(ref) = gnttab_free_head;
574*4882a593Smuzhiyun 	gnttab_free_head = head;
575*4882a593Smuzhiyun 	gnttab_free_count += count;
576*4882a593Smuzhiyun 	check_free_callbacks();
577*4882a593Smuzhiyun 	spin_unlock_irqrestore(&gnttab_list_lock, flags);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
580*4882a593Smuzhiyun 
gnttab_alloc_grant_references(u16 count,grant_ref_t * head)581*4882a593Smuzhiyun int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
582*4882a593Smuzhiyun {
583*4882a593Smuzhiyun 	int h = get_free_entries(count);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	if (h < 0)
586*4882a593Smuzhiyun 		return -ENOSPC;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	*head = h;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	return 0;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
593*4882a593Smuzhiyun 
gnttab_empty_grant_references(const grant_ref_t * private_head)594*4882a593Smuzhiyun int gnttab_empty_grant_references(const grant_ref_t *private_head)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	return (*private_head == GNTTAB_LIST_END);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
599*4882a593Smuzhiyun 
gnttab_claim_grant_reference(grant_ref_t * private_head)600*4882a593Smuzhiyun int gnttab_claim_grant_reference(grant_ref_t *private_head)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun 	grant_ref_t g = *private_head;
603*4882a593Smuzhiyun 	if (unlikely(g == GNTTAB_LIST_END))
604*4882a593Smuzhiyun 		return -ENOSPC;
605*4882a593Smuzhiyun 	*private_head = gnttab_entry(g);
606*4882a593Smuzhiyun 	return g;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
609*4882a593Smuzhiyun 
gnttab_release_grant_reference(grant_ref_t * private_head,grant_ref_t release)610*4882a593Smuzhiyun void gnttab_release_grant_reference(grant_ref_t *private_head,
611*4882a593Smuzhiyun 				    grant_ref_t release)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	gnttab_entry(release) = *private_head;
614*4882a593Smuzhiyun 	*private_head = release;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
617*4882a593Smuzhiyun 
gnttab_request_free_callback(struct gnttab_free_callback * callback,void (* fn)(void *),void * arg,u16 count)618*4882a593Smuzhiyun void gnttab_request_free_callback(struct gnttab_free_callback *callback,
619*4882a593Smuzhiyun 				  void (*fn)(void *), void *arg, u16 count)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	unsigned long flags;
622*4882a593Smuzhiyun 	struct gnttab_free_callback *cb;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	spin_lock_irqsave(&gnttab_list_lock, flags);
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	/* Check if the callback is already on the list */
627*4882a593Smuzhiyun 	cb = gnttab_free_callback_list;
628*4882a593Smuzhiyun 	while (cb) {
629*4882a593Smuzhiyun 		if (cb == callback)
630*4882a593Smuzhiyun 			goto out;
631*4882a593Smuzhiyun 		cb = cb->next;
632*4882a593Smuzhiyun 	}
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	callback->fn = fn;
635*4882a593Smuzhiyun 	callback->arg = arg;
636*4882a593Smuzhiyun 	callback->count = count;
637*4882a593Smuzhiyun 	callback->next = gnttab_free_callback_list;
638*4882a593Smuzhiyun 	gnttab_free_callback_list = callback;
639*4882a593Smuzhiyun 	check_free_callbacks();
640*4882a593Smuzhiyun out:
641*4882a593Smuzhiyun 	spin_unlock_irqrestore(&gnttab_list_lock, flags);
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
644*4882a593Smuzhiyun 
gnttab_cancel_free_callback(struct gnttab_free_callback * callback)645*4882a593Smuzhiyun void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
646*4882a593Smuzhiyun {
647*4882a593Smuzhiyun 	struct gnttab_free_callback **pcb;
648*4882a593Smuzhiyun 	unsigned long flags;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	spin_lock_irqsave(&gnttab_list_lock, flags);
651*4882a593Smuzhiyun 	for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
652*4882a593Smuzhiyun 		if (*pcb == callback) {
653*4882a593Smuzhiyun 			*pcb = callback->next;
654*4882a593Smuzhiyun 			break;
655*4882a593Smuzhiyun 		}
656*4882a593Smuzhiyun 	}
657*4882a593Smuzhiyun 	spin_unlock_irqrestore(&gnttab_list_lock, flags);
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
660*4882a593Smuzhiyun 
gnttab_frames(unsigned int frames,unsigned int align)661*4882a593Smuzhiyun static unsigned int gnttab_frames(unsigned int frames, unsigned int align)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun 	return (frames * gnttab_interface->grefs_per_grant_frame + align - 1) /
664*4882a593Smuzhiyun 	       align;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun 
grow_gnttab_list(unsigned int more_frames)667*4882a593Smuzhiyun static int grow_gnttab_list(unsigned int more_frames)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun 	unsigned int new_nr_grant_frames, extra_entries, i;
670*4882a593Smuzhiyun 	unsigned int nr_glist_frames, new_nr_glist_frames;
671*4882a593Smuzhiyun 	unsigned int grefs_per_frame;
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	grefs_per_frame = gnttab_interface->grefs_per_grant_frame;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 	new_nr_grant_frames = nr_grant_frames + more_frames;
676*4882a593Smuzhiyun 	extra_entries = more_frames * grefs_per_frame;
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	nr_glist_frames = gnttab_frames(nr_grant_frames, RPP);
679*4882a593Smuzhiyun 	new_nr_glist_frames = gnttab_frames(new_nr_grant_frames, RPP);
680*4882a593Smuzhiyun 	for (i = nr_glist_frames; i < new_nr_glist_frames; i++) {
681*4882a593Smuzhiyun 		gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
682*4882a593Smuzhiyun 		if (!gnttab_list[i])
683*4882a593Smuzhiyun 			goto grow_nomem;
684*4882a593Smuzhiyun 	}
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	for (i = grefs_per_frame * nr_grant_frames;
688*4882a593Smuzhiyun 	     i < grefs_per_frame * new_nr_grant_frames - 1; i++)
689*4882a593Smuzhiyun 		gnttab_entry(i) = i + 1;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	gnttab_entry(i) = gnttab_free_head;
692*4882a593Smuzhiyun 	gnttab_free_head = grefs_per_frame * nr_grant_frames;
693*4882a593Smuzhiyun 	gnttab_free_count += extra_entries;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	nr_grant_frames = new_nr_grant_frames;
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	check_free_callbacks();
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	return 0;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun grow_nomem:
702*4882a593Smuzhiyun 	while (i-- > nr_glist_frames)
703*4882a593Smuzhiyun 		free_page((unsigned long) gnttab_list[i]);
704*4882a593Smuzhiyun 	return -ENOMEM;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun 
__max_nr_grant_frames(void)707*4882a593Smuzhiyun static unsigned int __max_nr_grant_frames(void)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun 	struct gnttab_query_size query;
710*4882a593Smuzhiyun 	int rc;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	query.dom = DOMID_SELF;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
715*4882a593Smuzhiyun 	if ((rc < 0) || (query.status != GNTST_okay))
716*4882a593Smuzhiyun 		return 4; /* Legacy max supported number of frames */
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	return query.max_nr_frames;
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun 
gnttab_max_grant_frames(void)721*4882a593Smuzhiyun unsigned int gnttab_max_grant_frames(void)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun 	unsigned int xen_max = __max_nr_grant_frames();
724*4882a593Smuzhiyun 	static unsigned int boot_max_nr_grant_frames;
725*4882a593Smuzhiyun 
726*4882a593Smuzhiyun 	/* First time, initialize it properly. */
727*4882a593Smuzhiyun 	if (!boot_max_nr_grant_frames)
728*4882a593Smuzhiyun 		boot_max_nr_grant_frames = __max_nr_grant_frames();
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun 	if (xen_max > boot_max_nr_grant_frames)
731*4882a593Smuzhiyun 		return boot_max_nr_grant_frames;
732*4882a593Smuzhiyun 	return xen_max;
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
735*4882a593Smuzhiyun 
gnttab_setup_auto_xlat_frames(phys_addr_t addr)736*4882a593Smuzhiyun int gnttab_setup_auto_xlat_frames(phys_addr_t addr)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	xen_pfn_t *pfn;
739*4882a593Smuzhiyun 	unsigned int max_nr_gframes = __max_nr_grant_frames();
740*4882a593Smuzhiyun 	unsigned int i;
741*4882a593Smuzhiyun 	void *vaddr;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	if (xen_auto_xlat_grant_frames.count)
744*4882a593Smuzhiyun 		return -EINVAL;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	vaddr = xen_remap(addr, XEN_PAGE_SIZE * max_nr_gframes);
747*4882a593Smuzhiyun 	if (vaddr == NULL) {
748*4882a593Smuzhiyun 		pr_warn("Failed to ioremap gnttab share frames (addr=%pa)!\n",
749*4882a593Smuzhiyun 			&addr);
750*4882a593Smuzhiyun 		return -ENOMEM;
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun 	pfn = kcalloc(max_nr_gframes, sizeof(pfn[0]), GFP_KERNEL);
753*4882a593Smuzhiyun 	if (!pfn) {
754*4882a593Smuzhiyun 		xen_unmap(vaddr);
755*4882a593Smuzhiyun 		return -ENOMEM;
756*4882a593Smuzhiyun 	}
757*4882a593Smuzhiyun 	for (i = 0; i < max_nr_gframes; i++)
758*4882a593Smuzhiyun 		pfn[i] = XEN_PFN_DOWN(addr) + i;
759*4882a593Smuzhiyun 
760*4882a593Smuzhiyun 	xen_auto_xlat_grant_frames.vaddr = vaddr;
761*4882a593Smuzhiyun 	xen_auto_xlat_grant_frames.pfn = pfn;
762*4882a593Smuzhiyun 	xen_auto_xlat_grant_frames.count = max_nr_gframes;
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	return 0;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_setup_auto_xlat_frames);
767*4882a593Smuzhiyun 
gnttab_free_auto_xlat_frames(void)768*4882a593Smuzhiyun void gnttab_free_auto_xlat_frames(void)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun 	if (!xen_auto_xlat_grant_frames.count)
771*4882a593Smuzhiyun 		return;
772*4882a593Smuzhiyun 	kfree(xen_auto_xlat_grant_frames.pfn);
773*4882a593Smuzhiyun 	xen_unmap(xen_auto_xlat_grant_frames.vaddr);
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	xen_auto_xlat_grant_frames.pfn = NULL;
776*4882a593Smuzhiyun 	xen_auto_xlat_grant_frames.count = 0;
777*4882a593Smuzhiyun 	xen_auto_xlat_grant_frames.vaddr = NULL;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames);
780*4882a593Smuzhiyun 
gnttab_pages_set_private(int nr_pages,struct page ** pages)781*4882a593Smuzhiyun int gnttab_pages_set_private(int nr_pages, struct page **pages)
782*4882a593Smuzhiyun {
783*4882a593Smuzhiyun 	int i;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	for (i = 0; i < nr_pages; i++) {
786*4882a593Smuzhiyun #if BITS_PER_LONG < 64
787*4882a593Smuzhiyun 		struct xen_page_foreign *foreign;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 		foreign = kzalloc(sizeof(*foreign), GFP_KERNEL);
790*4882a593Smuzhiyun 		if (!foreign)
791*4882a593Smuzhiyun 			return -ENOMEM;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun 		set_page_private(pages[i], (unsigned long)foreign);
794*4882a593Smuzhiyun #endif
795*4882a593Smuzhiyun 		SetPagePrivate(pages[i]);
796*4882a593Smuzhiyun 	}
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	return 0;
799*4882a593Smuzhiyun }
800*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_pages_set_private);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun /**
803*4882a593Smuzhiyun  * gnttab_alloc_pages - alloc pages suitable for grant mapping into
804*4882a593Smuzhiyun  * @nr_pages: number of pages to alloc
805*4882a593Smuzhiyun  * @pages: returns the pages
806*4882a593Smuzhiyun  */
gnttab_alloc_pages(int nr_pages,struct page ** pages)807*4882a593Smuzhiyun int gnttab_alloc_pages(int nr_pages, struct page **pages)
808*4882a593Smuzhiyun {
809*4882a593Smuzhiyun 	int ret;
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	ret = xen_alloc_unpopulated_pages(nr_pages, pages);
812*4882a593Smuzhiyun 	if (ret < 0)
813*4882a593Smuzhiyun 		return ret;
814*4882a593Smuzhiyun 
815*4882a593Smuzhiyun 	ret = gnttab_pages_set_private(nr_pages, pages);
816*4882a593Smuzhiyun 	if (ret < 0)
817*4882a593Smuzhiyun 		gnttab_free_pages(nr_pages, pages);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	return ret;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_alloc_pages);
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun #ifdef CONFIG_XEN_UNPOPULATED_ALLOC
cache_init(struct gnttab_page_cache * cache)824*4882a593Smuzhiyun static inline void cache_init(struct gnttab_page_cache *cache)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun 	cache->pages = NULL;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun 
cache_empty(struct gnttab_page_cache * cache)829*4882a593Smuzhiyun static inline bool cache_empty(struct gnttab_page_cache *cache)
830*4882a593Smuzhiyun {
831*4882a593Smuzhiyun 	return !cache->pages;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun 
cache_deq(struct gnttab_page_cache * cache)834*4882a593Smuzhiyun static inline struct page *cache_deq(struct gnttab_page_cache *cache)
835*4882a593Smuzhiyun {
836*4882a593Smuzhiyun 	struct page *page;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	page = cache->pages;
839*4882a593Smuzhiyun 	cache->pages = page->zone_device_data;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 	return page;
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun 
cache_enq(struct gnttab_page_cache * cache,struct page * page)844*4882a593Smuzhiyun static inline void cache_enq(struct gnttab_page_cache *cache, struct page *page)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun 	page->zone_device_data = cache->pages;
847*4882a593Smuzhiyun 	cache->pages = page;
848*4882a593Smuzhiyun }
849*4882a593Smuzhiyun #else
cache_init(struct gnttab_page_cache * cache)850*4882a593Smuzhiyun static inline void cache_init(struct gnttab_page_cache *cache)
851*4882a593Smuzhiyun {
852*4882a593Smuzhiyun 	INIT_LIST_HEAD(&cache->pages);
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun 
cache_empty(struct gnttab_page_cache * cache)855*4882a593Smuzhiyun static inline bool cache_empty(struct gnttab_page_cache *cache)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun 	return list_empty(&cache->pages);
858*4882a593Smuzhiyun }
859*4882a593Smuzhiyun 
cache_deq(struct gnttab_page_cache * cache)860*4882a593Smuzhiyun static inline struct page *cache_deq(struct gnttab_page_cache *cache)
861*4882a593Smuzhiyun {
862*4882a593Smuzhiyun 	struct page *page;
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 	page = list_first_entry(&cache->pages, struct page, lru);
865*4882a593Smuzhiyun 	list_del(&page->lru);
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	return page;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
cache_enq(struct gnttab_page_cache * cache,struct page * page)870*4882a593Smuzhiyun static inline void cache_enq(struct gnttab_page_cache *cache, struct page *page)
871*4882a593Smuzhiyun {
872*4882a593Smuzhiyun 	list_add(&page->lru, &cache->pages);
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun #endif
875*4882a593Smuzhiyun 
gnttab_page_cache_init(struct gnttab_page_cache * cache)876*4882a593Smuzhiyun void gnttab_page_cache_init(struct gnttab_page_cache *cache)
877*4882a593Smuzhiyun {
878*4882a593Smuzhiyun 	spin_lock_init(&cache->lock);
879*4882a593Smuzhiyun 	cache_init(cache);
880*4882a593Smuzhiyun 	cache->num_pages = 0;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_page_cache_init);
883*4882a593Smuzhiyun 
gnttab_page_cache_get(struct gnttab_page_cache * cache,struct page ** page)884*4882a593Smuzhiyun int gnttab_page_cache_get(struct gnttab_page_cache *cache, struct page **page)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun 	unsigned long flags;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	spin_lock_irqsave(&cache->lock, flags);
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	if (cache_empty(cache)) {
891*4882a593Smuzhiyun 		spin_unlock_irqrestore(&cache->lock, flags);
892*4882a593Smuzhiyun 		return gnttab_alloc_pages(1, page);
893*4882a593Smuzhiyun 	}
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	page[0] = cache_deq(cache);
896*4882a593Smuzhiyun 	cache->num_pages--;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cache->lock, flags);
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_page_cache_get);
903*4882a593Smuzhiyun 
gnttab_page_cache_put(struct gnttab_page_cache * cache,struct page ** page,unsigned int num)904*4882a593Smuzhiyun void gnttab_page_cache_put(struct gnttab_page_cache *cache, struct page **page,
905*4882a593Smuzhiyun 			   unsigned int num)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun 	unsigned long flags;
908*4882a593Smuzhiyun 	unsigned int i;
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun 	spin_lock_irqsave(&cache->lock, flags);
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 	for (i = 0; i < num; i++)
913*4882a593Smuzhiyun 		cache_enq(cache, page[i]);
914*4882a593Smuzhiyun 	cache->num_pages += num;
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cache->lock, flags);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_page_cache_put);
919*4882a593Smuzhiyun 
gnttab_page_cache_shrink(struct gnttab_page_cache * cache,unsigned int num)920*4882a593Smuzhiyun void gnttab_page_cache_shrink(struct gnttab_page_cache *cache, unsigned int num)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun 	struct page *page[10];
923*4882a593Smuzhiyun 	unsigned int i = 0;
924*4882a593Smuzhiyun 	unsigned long flags;
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun 	spin_lock_irqsave(&cache->lock, flags);
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	while (cache->num_pages > num) {
929*4882a593Smuzhiyun 		page[i] = cache_deq(cache);
930*4882a593Smuzhiyun 		cache->num_pages--;
931*4882a593Smuzhiyun 		if (++i == ARRAY_SIZE(page)) {
932*4882a593Smuzhiyun 			spin_unlock_irqrestore(&cache->lock, flags);
933*4882a593Smuzhiyun 			gnttab_free_pages(i, page);
934*4882a593Smuzhiyun 			i = 0;
935*4882a593Smuzhiyun 			spin_lock_irqsave(&cache->lock, flags);
936*4882a593Smuzhiyun 		}
937*4882a593Smuzhiyun 	}
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	spin_unlock_irqrestore(&cache->lock, flags);
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	if (i != 0)
942*4882a593Smuzhiyun 		gnttab_free_pages(i, page);
943*4882a593Smuzhiyun }
944*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_page_cache_shrink);
945*4882a593Smuzhiyun 
gnttab_pages_clear_private(int nr_pages,struct page ** pages)946*4882a593Smuzhiyun void gnttab_pages_clear_private(int nr_pages, struct page **pages)
947*4882a593Smuzhiyun {
948*4882a593Smuzhiyun 	int i;
949*4882a593Smuzhiyun 
950*4882a593Smuzhiyun 	for (i = 0; i < nr_pages; i++) {
951*4882a593Smuzhiyun 		if (PagePrivate(pages[i])) {
952*4882a593Smuzhiyun #if BITS_PER_LONG < 64
953*4882a593Smuzhiyun 			kfree((void *)page_private(pages[i]));
954*4882a593Smuzhiyun #endif
955*4882a593Smuzhiyun 			ClearPagePrivate(pages[i]);
956*4882a593Smuzhiyun 		}
957*4882a593Smuzhiyun 	}
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_pages_clear_private);
960*4882a593Smuzhiyun 
961*4882a593Smuzhiyun /**
962*4882a593Smuzhiyun  * gnttab_free_pages - free pages allocated by gnttab_alloc_pages()
963*4882a593Smuzhiyun  * @nr_pages; number of pages to free
964*4882a593Smuzhiyun  * @pages: the pages
965*4882a593Smuzhiyun  */
gnttab_free_pages(int nr_pages,struct page ** pages)966*4882a593Smuzhiyun void gnttab_free_pages(int nr_pages, struct page **pages)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun 	gnttab_pages_clear_private(nr_pages, pages);
969*4882a593Smuzhiyun 	xen_free_unpopulated_pages(nr_pages, pages);
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_free_pages);
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun #ifdef CONFIG_XEN_GRANT_DMA_ALLOC
974*4882a593Smuzhiyun /**
975*4882a593Smuzhiyun  * gnttab_dma_alloc_pages - alloc DMAable pages suitable for grant mapping into
976*4882a593Smuzhiyun  * @args: arguments to the function
977*4882a593Smuzhiyun  */
gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args * args)978*4882a593Smuzhiyun int gnttab_dma_alloc_pages(struct gnttab_dma_alloc_args *args)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun 	unsigned long pfn, start_pfn;
981*4882a593Smuzhiyun 	size_t size;
982*4882a593Smuzhiyun 	int i, ret;
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	if (args->nr_pages < 0 || args->nr_pages > (INT_MAX >> PAGE_SHIFT))
985*4882a593Smuzhiyun 		return -ENOMEM;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	size = args->nr_pages << PAGE_SHIFT;
988*4882a593Smuzhiyun 	if (args->coherent)
989*4882a593Smuzhiyun 		args->vaddr = dma_alloc_coherent(args->dev, size,
990*4882a593Smuzhiyun 						 &args->dev_bus_addr,
991*4882a593Smuzhiyun 						 GFP_KERNEL | __GFP_NOWARN);
992*4882a593Smuzhiyun 	else
993*4882a593Smuzhiyun 		args->vaddr = dma_alloc_wc(args->dev, size,
994*4882a593Smuzhiyun 					   &args->dev_bus_addr,
995*4882a593Smuzhiyun 					   GFP_KERNEL | __GFP_NOWARN);
996*4882a593Smuzhiyun 	if (!args->vaddr) {
997*4882a593Smuzhiyun 		pr_debug("Failed to allocate DMA buffer of size %zu\n", size);
998*4882a593Smuzhiyun 		return -ENOMEM;
999*4882a593Smuzhiyun 	}
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	start_pfn = __phys_to_pfn(args->dev_bus_addr);
1002*4882a593Smuzhiyun 	for (pfn = start_pfn, i = 0; pfn < start_pfn + args->nr_pages;
1003*4882a593Smuzhiyun 			pfn++, i++) {
1004*4882a593Smuzhiyun 		struct page *page = pfn_to_page(pfn);
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 		args->pages[i] = page;
1007*4882a593Smuzhiyun 		args->frames[i] = xen_page_to_gfn(page);
1008*4882a593Smuzhiyun 		xenmem_reservation_scrub_page(page);
1009*4882a593Smuzhiyun 	}
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	xenmem_reservation_va_mapping_reset(args->nr_pages, args->pages);
1012*4882a593Smuzhiyun 
1013*4882a593Smuzhiyun 	ret = xenmem_reservation_decrease(args->nr_pages, args->frames);
1014*4882a593Smuzhiyun 	if (ret != args->nr_pages) {
1015*4882a593Smuzhiyun 		pr_debug("Failed to decrease reservation for DMA buffer\n");
1016*4882a593Smuzhiyun 		ret = -EFAULT;
1017*4882a593Smuzhiyun 		goto fail;
1018*4882a593Smuzhiyun 	}
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	ret = gnttab_pages_set_private(args->nr_pages, args->pages);
1021*4882a593Smuzhiyun 	if (ret < 0)
1022*4882a593Smuzhiyun 		goto fail;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	return 0;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun fail:
1027*4882a593Smuzhiyun 	gnttab_dma_free_pages(args);
1028*4882a593Smuzhiyun 	return ret;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_dma_alloc_pages);
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun /**
1033*4882a593Smuzhiyun  * gnttab_dma_free_pages - free DMAable pages
1034*4882a593Smuzhiyun  * @args: arguments to the function
1035*4882a593Smuzhiyun  */
gnttab_dma_free_pages(struct gnttab_dma_alloc_args * args)1036*4882a593Smuzhiyun int gnttab_dma_free_pages(struct gnttab_dma_alloc_args *args)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun 	size_t size;
1039*4882a593Smuzhiyun 	int i, ret;
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun 	gnttab_pages_clear_private(args->nr_pages, args->pages);
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	for (i = 0; i < args->nr_pages; i++)
1044*4882a593Smuzhiyun 		args->frames[i] = page_to_xen_pfn(args->pages[i]);
1045*4882a593Smuzhiyun 
1046*4882a593Smuzhiyun 	ret = xenmem_reservation_increase(args->nr_pages, args->frames);
1047*4882a593Smuzhiyun 	if (ret != args->nr_pages) {
1048*4882a593Smuzhiyun 		pr_debug("Failed to increase reservation for DMA buffer\n");
1049*4882a593Smuzhiyun 		ret = -EFAULT;
1050*4882a593Smuzhiyun 	} else {
1051*4882a593Smuzhiyun 		ret = 0;
1052*4882a593Smuzhiyun 	}
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	xenmem_reservation_va_mapping_update(args->nr_pages, args->pages,
1055*4882a593Smuzhiyun 					     args->frames);
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	size = args->nr_pages << PAGE_SHIFT;
1058*4882a593Smuzhiyun 	if (args->coherent)
1059*4882a593Smuzhiyun 		dma_free_coherent(args->dev, size,
1060*4882a593Smuzhiyun 				  args->vaddr, args->dev_bus_addr);
1061*4882a593Smuzhiyun 	else
1062*4882a593Smuzhiyun 		dma_free_wc(args->dev, size,
1063*4882a593Smuzhiyun 			    args->vaddr, args->dev_bus_addr);
1064*4882a593Smuzhiyun 	return ret;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_dma_free_pages);
1067*4882a593Smuzhiyun #endif
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun /* Handling of paged out grant targets (GNTST_eagain) */
1070*4882a593Smuzhiyun #define MAX_DELAY 256
1071*4882a593Smuzhiyun static inline void
gnttab_retry_eagain_gop(unsigned int cmd,void * gop,int16_t * status,const char * func)1072*4882a593Smuzhiyun gnttab_retry_eagain_gop(unsigned int cmd, void *gop, int16_t *status,
1073*4882a593Smuzhiyun 						const char *func)
1074*4882a593Smuzhiyun {
1075*4882a593Smuzhiyun 	unsigned delay = 1;
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	do {
1078*4882a593Smuzhiyun 		BUG_ON(HYPERVISOR_grant_table_op(cmd, gop, 1));
1079*4882a593Smuzhiyun 		if (*status == GNTST_eagain)
1080*4882a593Smuzhiyun 			msleep(delay++);
1081*4882a593Smuzhiyun 	} while ((*status == GNTST_eagain) && (delay < MAX_DELAY));
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	if (delay >= MAX_DELAY) {
1084*4882a593Smuzhiyun 		pr_err("%s: %s eagain grant\n", func, current->comm);
1085*4882a593Smuzhiyun 		*status = GNTST_bad_page;
1086*4882a593Smuzhiyun 	}
1087*4882a593Smuzhiyun }
1088*4882a593Smuzhiyun 
gnttab_batch_map(struct gnttab_map_grant_ref * batch,unsigned count)1089*4882a593Smuzhiyun void gnttab_batch_map(struct gnttab_map_grant_ref *batch, unsigned count)
1090*4882a593Smuzhiyun {
1091*4882a593Smuzhiyun 	struct gnttab_map_grant_ref *op;
1092*4882a593Smuzhiyun 
1093*4882a593Smuzhiyun 	if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, batch, count))
1094*4882a593Smuzhiyun 		BUG();
1095*4882a593Smuzhiyun 	for (op = batch; op < batch + count; op++)
1096*4882a593Smuzhiyun 		if (op->status == GNTST_eagain)
1097*4882a593Smuzhiyun 			gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, op,
1098*4882a593Smuzhiyun 						&op->status, __func__);
1099*4882a593Smuzhiyun }
1100*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_batch_map);
1101*4882a593Smuzhiyun 
gnttab_batch_copy(struct gnttab_copy * batch,unsigned count)1102*4882a593Smuzhiyun void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count)
1103*4882a593Smuzhiyun {
1104*4882a593Smuzhiyun 	struct gnttab_copy *op;
1105*4882a593Smuzhiyun 
1106*4882a593Smuzhiyun 	if (HYPERVISOR_grant_table_op(GNTTABOP_copy, batch, count))
1107*4882a593Smuzhiyun 		BUG();
1108*4882a593Smuzhiyun 	for (op = batch; op < batch + count; op++)
1109*4882a593Smuzhiyun 		if (op->status == GNTST_eagain)
1110*4882a593Smuzhiyun 			gnttab_retry_eagain_gop(GNTTABOP_copy, op,
1111*4882a593Smuzhiyun 						&op->status, __func__);
1112*4882a593Smuzhiyun }
1113*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_batch_copy);
1114*4882a593Smuzhiyun 
gnttab_foreach_grant_in_range(struct page * page,unsigned int offset,unsigned int len,xen_grant_fn_t fn,void * data)1115*4882a593Smuzhiyun void gnttab_foreach_grant_in_range(struct page *page,
1116*4882a593Smuzhiyun 				   unsigned int offset,
1117*4882a593Smuzhiyun 				   unsigned int len,
1118*4882a593Smuzhiyun 				   xen_grant_fn_t fn,
1119*4882a593Smuzhiyun 				   void *data)
1120*4882a593Smuzhiyun {
1121*4882a593Smuzhiyun 	unsigned int goffset;
1122*4882a593Smuzhiyun 	unsigned int glen;
1123*4882a593Smuzhiyun 	unsigned long xen_pfn;
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 	len = min_t(unsigned int, PAGE_SIZE - offset, len);
1126*4882a593Smuzhiyun 	goffset = xen_offset_in_page(offset);
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	xen_pfn = page_to_xen_pfn(page) + XEN_PFN_DOWN(offset);
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun 	while (len) {
1131*4882a593Smuzhiyun 		glen = min_t(unsigned int, XEN_PAGE_SIZE - goffset, len);
1132*4882a593Smuzhiyun 		fn(pfn_to_gfn(xen_pfn), goffset, glen, data);
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 		goffset = 0;
1135*4882a593Smuzhiyun 		xen_pfn++;
1136*4882a593Smuzhiyun 		len -= glen;
1137*4882a593Smuzhiyun 	}
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_foreach_grant_in_range);
1140*4882a593Smuzhiyun 
gnttab_foreach_grant(struct page ** pages,unsigned int nr_grefs,xen_grant_fn_t fn,void * data)1141*4882a593Smuzhiyun void gnttab_foreach_grant(struct page **pages,
1142*4882a593Smuzhiyun 			  unsigned int nr_grefs,
1143*4882a593Smuzhiyun 			  xen_grant_fn_t fn,
1144*4882a593Smuzhiyun 			  void *data)
1145*4882a593Smuzhiyun {
1146*4882a593Smuzhiyun 	unsigned int goffset = 0;
1147*4882a593Smuzhiyun 	unsigned long xen_pfn = 0;
1148*4882a593Smuzhiyun 	unsigned int i;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	for (i = 0; i < nr_grefs; i++) {
1151*4882a593Smuzhiyun 		if ((i % XEN_PFN_PER_PAGE) == 0) {
1152*4882a593Smuzhiyun 			xen_pfn = page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);
1153*4882a593Smuzhiyun 			goffset = 0;
1154*4882a593Smuzhiyun 		}
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 		fn(pfn_to_gfn(xen_pfn), goffset, XEN_PAGE_SIZE, data);
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 		goffset += XEN_PAGE_SIZE;
1159*4882a593Smuzhiyun 		xen_pfn++;
1160*4882a593Smuzhiyun 	}
1161*4882a593Smuzhiyun }
1162*4882a593Smuzhiyun 
gnttab_map_refs(struct gnttab_map_grant_ref * map_ops,struct gnttab_map_grant_ref * kmap_ops,struct page ** pages,unsigned int count)1163*4882a593Smuzhiyun int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
1164*4882a593Smuzhiyun 		    struct gnttab_map_grant_ref *kmap_ops,
1165*4882a593Smuzhiyun 		    struct page **pages, unsigned int count)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun 	int i, ret;
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun 	ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);
1170*4882a593Smuzhiyun 	if (ret)
1171*4882a593Smuzhiyun 		return ret;
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
1174*4882a593Smuzhiyun 		switch (map_ops[i].status) {
1175*4882a593Smuzhiyun 		case GNTST_okay:
1176*4882a593Smuzhiyun 		{
1177*4882a593Smuzhiyun 			struct xen_page_foreign *foreign;
1178*4882a593Smuzhiyun 
1179*4882a593Smuzhiyun 			SetPageForeign(pages[i]);
1180*4882a593Smuzhiyun 			foreign = xen_page_foreign(pages[i]);
1181*4882a593Smuzhiyun 			foreign->domid = map_ops[i].dom;
1182*4882a593Smuzhiyun 			foreign->gref = map_ops[i].ref;
1183*4882a593Smuzhiyun 			break;
1184*4882a593Smuzhiyun 		}
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 		case GNTST_no_device_space:
1187*4882a593Smuzhiyun 			pr_warn_ratelimited("maptrack limit reached, can't map all guest pages\n");
1188*4882a593Smuzhiyun 			break;
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 		case GNTST_eagain:
1191*4882a593Smuzhiyun 			/* Retry eagain maps */
1192*4882a593Smuzhiyun 			gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref,
1193*4882a593Smuzhiyun 						map_ops + i,
1194*4882a593Smuzhiyun 						&map_ops[i].status, __func__);
1195*4882a593Smuzhiyun 			/* Test status in next loop iteration. */
1196*4882a593Smuzhiyun 			i--;
1197*4882a593Smuzhiyun 			break;
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 		default:
1200*4882a593Smuzhiyun 			break;
1201*4882a593Smuzhiyun 		}
1202*4882a593Smuzhiyun 	}
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	return set_foreign_p2m_mapping(map_ops, kmap_ops, pages, count);
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_map_refs);
1207*4882a593Smuzhiyun 
gnttab_unmap_refs(struct gnttab_unmap_grant_ref * unmap_ops,struct gnttab_unmap_grant_ref * kunmap_ops,struct page ** pages,unsigned int count)1208*4882a593Smuzhiyun int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
1209*4882a593Smuzhiyun 		      struct gnttab_unmap_grant_ref *kunmap_ops,
1210*4882a593Smuzhiyun 		      struct page **pages, unsigned int count)
1211*4882a593Smuzhiyun {
1212*4882a593Smuzhiyun 	unsigned int i;
1213*4882a593Smuzhiyun 	int ret;
1214*4882a593Smuzhiyun 
1215*4882a593Smuzhiyun 	ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
1216*4882a593Smuzhiyun 	if (ret)
1217*4882a593Smuzhiyun 		return ret;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	for (i = 0; i < count; i++)
1220*4882a593Smuzhiyun 		ClearPageForeign(pages[i]);
1221*4882a593Smuzhiyun 
1222*4882a593Smuzhiyun 	return clear_foreign_p2m_mapping(unmap_ops, kunmap_ops, pages, count);
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun #define GNTTAB_UNMAP_REFS_DELAY 5
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun static void __gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item);
1229*4882a593Smuzhiyun 
gnttab_unmap_work(struct work_struct * work)1230*4882a593Smuzhiyun static void gnttab_unmap_work(struct work_struct *work)
1231*4882a593Smuzhiyun {
1232*4882a593Smuzhiyun 	struct gntab_unmap_queue_data
1233*4882a593Smuzhiyun 		*unmap_data = container_of(work,
1234*4882a593Smuzhiyun 					   struct gntab_unmap_queue_data,
1235*4882a593Smuzhiyun 					   gnttab_work.work);
1236*4882a593Smuzhiyun 	if (unmap_data->age != UINT_MAX)
1237*4882a593Smuzhiyun 		unmap_data->age++;
1238*4882a593Smuzhiyun 	__gnttab_unmap_refs_async(unmap_data);
1239*4882a593Smuzhiyun }
1240*4882a593Smuzhiyun 
__gnttab_unmap_refs_async(struct gntab_unmap_queue_data * item)1241*4882a593Smuzhiyun static void __gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
1242*4882a593Smuzhiyun {
1243*4882a593Smuzhiyun 	int ret;
1244*4882a593Smuzhiyun 	int pc;
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	for (pc = 0; pc < item->count; pc++) {
1247*4882a593Smuzhiyun 		if (page_count(item->pages[pc]) > 1) {
1248*4882a593Smuzhiyun 			unsigned long delay = GNTTAB_UNMAP_REFS_DELAY * (item->age + 1);
1249*4882a593Smuzhiyun 			schedule_delayed_work(&item->gnttab_work,
1250*4882a593Smuzhiyun 					      msecs_to_jiffies(delay));
1251*4882a593Smuzhiyun 			return;
1252*4882a593Smuzhiyun 		}
1253*4882a593Smuzhiyun 	}
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	ret = gnttab_unmap_refs(item->unmap_ops, item->kunmap_ops,
1256*4882a593Smuzhiyun 				item->pages, item->count);
1257*4882a593Smuzhiyun 	item->done(ret, item);
1258*4882a593Smuzhiyun }
1259*4882a593Smuzhiyun 
gnttab_unmap_refs_async(struct gntab_unmap_queue_data * item)1260*4882a593Smuzhiyun void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
1261*4882a593Smuzhiyun {
1262*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&item->gnttab_work, gnttab_unmap_work);
1263*4882a593Smuzhiyun 	item->age = 0;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	__gnttab_unmap_refs_async(item);
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_unmap_refs_async);
1268*4882a593Smuzhiyun 
unmap_refs_callback(int result,struct gntab_unmap_queue_data * data)1269*4882a593Smuzhiyun static void unmap_refs_callback(int result,
1270*4882a593Smuzhiyun 		struct gntab_unmap_queue_data *data)
1271*4882a593Smuzhiyun {
1272*4882a593Smuzhiyun 	struct unmap_refs_callback_data *d = data->data;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 	d->result = result;
1275*4882a593Smuzhiyun 	complete(&d->completion);
1276*4882a593Smuzhiyun }
1277*4882a593Smuzhiyun 
gnttab_unmap_refs_sync(struct gntab_unmap_queue_data * item)1278*4882a593Smuzhiyun int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item)
1279*4882a593Smuzhiyun {
1280*4882a593Smuzhiyun 	struct unmap_refs_callback_data data;
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	init_completion(&data.completion);
1283*4882a593Smuzhiyun 	item->data = &data;
1284*4882a593Smuzhiyun 	item->done = &unmap_refs_callback;
1285*4882a593Smuzhiyun 	gnttab_unmap_refs_async(item);
1286*4882a593Smuzhiyun 	wait_for_completion(&data.completion);
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun 	return data.result;
1289*4882a593Smuzhiyun }
1290*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_unmap_refs_sync);
1291*4882a593Smuzhiyun 
nr_status_frames(unsigned int nr_grant_frames)1292*4882a593Smuzhiyun static unsigned int nr_status_frames(unsigned int nr_grant_frames)
1293*4882a593Smuzhiyun {
1294*4882a593Smuzhiyun 	return gnttab_frames(nr_grant_frames, SPP);
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun 
gnttab_map_frames_v1(xen_pfn_t * frames,unsigned int nr_gframes)1297*4882a593Smuzhiyun static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun 	int rc;
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	rc = arch_gnttab_map_shared(frames, nr_gframes,
1302*4882a593Smuzhiyun 				    gnttab_max_grant_frames(),
1303*4882a593Smuzhiyun 				    &gnttab_shared.addr);
1304*4882a593Smuzhiyun 	BUG_ON(rc);
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	return 0;
1307*4882a593Smuzhiyun }
1308*4882a593Smuzhiyun 
gnttab_unmap_frames_v1(void)1309*4882a593Smuzhiyun static void gnttab_unmap_frames_v1(void)
1310*4882a593Smuzhiyun {
1311*4882a593Smuzhiyun 	arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun 
gnttab_map_frames_v2(xen_pfn_t * frames,unsigned int nr_gframes)1314*4882a593Smuzhiyun static int gnttab_map_frames_v2(xen_pfn_t *frames, unsigned int nr_gframes)
1315*4882a593Smuzhiyun {
1316*4882a593Smuzhiyun 	uint64_t *sframes;
1317*4882a593Smuzhiyun 	unsigned int nr_sframes;
1318*4882a593Smuzhiyun 	struct gnttab_get_status_frames getframes;
1319*4882a593Smuzhiyun 	int rc;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	nr_sframes = nr_status_frames(nr_gframes);
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	/* No need for kzalloc as it is initialized in following hypercall
1324*4882a593Smuzhiyun 	 * GNTTABOP_get_status_frames.
1325*4882a593Smuzhiyun 	 */
1326*4882a593Smuzhiyun 	sframes = kmalloc_array(nr_sframes, sizeof(uint64_t), GFP_ATOMIC);
1327*4882a593Smuzhiyun 	if (!sframes)
1328*4882a593Smuzhiyun 		return -ENOMEM;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun 	getframes.dom        = DOMID_SELF;
1331*4882a593Smuzhiyun 	getframes.nr_frames  = nr_sframes;
1332*4882a593Smuzhiyun 	set_xen_guest_handle(getframes.frame_list, sframes);
1333*4882a593Smuzhiyun 
1334*4882a593Smuzhiyun 	rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
1335*4882a593Smuzhiyun 				       &getframes, 1);
1336*4882a593Smuzhiyun 	if (rc == -ENOSYS) {
1337*4882a593Smuzhiyun 		kfree(sframes);
1338*4882a593Smuzhiyun 		return -ENOSYS;
1339*4882a593Smuzhiyun 	}
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun 	BUG_ON(rc || getframes.status);
1342*4882a593Smuzhiyun 
1343*4882a593Smuzhiyun 	rc = arch_gnttab_map_status(sframes, nr_sframes,
1344*4882a593Smuzhiyun 				    nr_status_frames(gnttab_max_grant_frames()),
1345*4882a593Smuzhiyun 				    &grstatus);
1346*4882a593Smuzhiyun 	BUG_ON(rc);
1347*4882a593Smuzhiyun 	kfree(sframes);
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	rc = arch_gnttab_map_shared(frames, nr_gframes,
1350*4882a593Smuzhiyun 				    gnttab_max_grant_frames(),
1351*4882a593Smuzhiyun 				    &gnttab_shared.addr);
1352*4882a593Smuzhiyun 	BUG_ON(rc);
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun 	return 0;
1355*4882a593Smuzhiyun }
1356*4882a593Smuzhiyun 
gnttab_unmap_frames_v2(void)1357*4882a593Smuzhiyun static void gnttab_unmap_frames_v2(void)
1358*4882a593Smuzhiyun {
1359*4882a593Smuzhiyun 	arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
1360*4882a593Smuzhiyun 	arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames));
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun 
gnttab_map(unsigned int start_idx,unsigned int end_idx)1363*4882a593Smuzhiyun static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
1364*4882a593Smuzhiyun {
1365*4882a593Smuzhiyun 	struct gnttab_setup_table setup;
1366*4882a593Smuzhiyun 	xen_pfn_t *frames;
1367*4882a593Smuzhiyun 	unsigned int nr_gframes = end_idx + 1;
1368*4882a593Smuzhiyun 	int rc;
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun 	if (xen_feature(XENFEAT_auto_translated_physmap)) {
1371*4882a593Smuzhiyun 		struct xen_add_to_physmap xatp;
1372*4882a593Smuzhiyun 		unsigned int i = end_idx;
1373*4882a593Smuzhiyun 		rc = 0;
1374*4882a593Smuzhiyun 		BUG_ON(xen_auto_xlat_grant_frames.count < nr_gframes);
1375*4882a593Smuzhiyun 		/*
1376*4882a593Smuzhiyun 		 * Loop backwards, so that the first hypercall has the largest
1377*4882a593Smuzhiyun 		 * index, ensuring that the table will grow only once.
1378*4882a593Smuzhiyun 		 */
1379*4882a593Smuzhiyun 		do {
1380*4882a593Smuzhiyun 			xatp.domid = DOMID_SELF;
1381*4882a593Smuzhiyun 			xatp.idx = i;
1382*4882a593Smuzhiyun 			xatp.space = XENMAPSPACE_grant_table;
1383*4882a593Smuzhiyun 			xatp.gpfn = xen_auto_xlat_grant_frames.pfn[i];
1384*4882a593Smuzhiyun 			rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
1385*4882a593Smuzhiyun 			if (rc != 0) {
1386*4882a593Smuzhiyun 				pr_warn("grant table add_to_physmap failed, err=%d\n",
1387*4882a593Smuzhiyun 					rc);
1388*4882a593Smuzhiyun 				break;
1389*4882a593Smuzhiyun 			}
1390*4882a593Smuzhiyun 		} while (i-- > start_idx);
1391*4882a593Smuzhiyun 
1392*4882a593Smuzhiyun 		return rc;
1393*4882a593Smuzhiyun 	}
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	/* No need for kzalloc as it is initialized in following hypercall
1396*4882a593Smuzhiyun 	 * GNTTABOP_setup_table.
1397*4882a593Smuzhiyun 	 */
1398*4882a593Smuzhiyun 	frames = kmalloc_array(nr_gframes, sizeof(unsigned long), GFP_ATOMIC);
1399*4882a593Smuzhiyun 	if (!frames)
1400*4882a593Smuzhiyun 		return -ENOMEM;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	setup.dom        = DOMID_SELF;
1403*4882a593Smuzhiyun 	setup.nr_frames  = nr_gframes;
1404*4882a593Smuzhiyun 	set_xen_guest_handle(setup.frame_list, frames);
1405*4882a593Smuzhiyun 
1406*4882a593Smuzhiyun 	rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
1407*4882a593Smuzhiyun 	if (rc == -ENOSYS) {
1408*4882a593Smuzhiyun 		kfree(frames);
1409*4882a593Smuzhiyun 		return -ENOSYS;
1410*4882a593Smuzhiyun 	}
1411*4882a593Smuzhiyun 
1412*4882a593Smuzhiyun 	BUG_ON(rc || setup.status);
1413*4882a593Smuzhiyun 
1414*4882a593Smuzhiyun 	rc = gnttab_interface->map_frames(frames, nr_gframes);
1415*4882a593Smuzhiyun 
1416*4882a593Smuzhiyun 	kfree(frames);
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun 	return rc;
1419*4882a593Smuzhiyun }
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun static const struct gnttab_ops gnttab_v1_ops = {
1422*4882a593Smuzhiyun 	.version			= 1,
1423*4882a593Smuzhiyun 	.grefs_per_grant_frame		= XEN_PAGE_SIZE /
1424*4882a593Smuzhiyun 					  sizeof(struct grant_entry_v1),
1425*4882a593Smuzhiyun 	.map_frames			= gnttab_map_frames_v1,
1426*4882a593Smuzhiyun 	.unmap_frames			= gnttab_unmap_frames_v1,
1427*4882a593Smuzhiyun 	.update_entry			= gnttab_update_entry_v1,
1428*4882a593Smuzhiyun 	.end_foreign_access_ref		= gnttab_end_foreign_access_ref_v1,
1429*4882a593Smuzhiyun 	.end_foreign_transfer_ref	= gnttab_end_foreign_transfer_ref_v1,
1430*4882a593Smuzhiyun 	.read_frame			= gnttab_read_frame_v1,
1431*4882a593Smuzhiyun };
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun static const struct gnttab_ops gnttab_v2_ops = {
1434*4882a593Smuzhiyun 	.version			= 2,
1435*4882a593Smuzhiyun 	.grefs_per_grant_frame		= XEN_PAGE_SIZE /
1436*4882a593Smuzhiyun 					  sizeof(union grant_entry_v2),
1437*4882a593Smuzhiyun 	.map_frames			= gnttab_map_frames_v2,
1438*4882a593Smuzhiyun 	.unmap_frames			= gnttab_unmap_frames_v2,
1439*4882a593Smuzhiyun 	.update_entry			= gnttab_update_entry_v2,
1440*4882a593Smuzhiyun 	.end_foreign_access_ref		= gnttab_end_foreign_access_ref_v2,
1441*4882a593Smuzhiyun 	.end_foreign_transfer_ref	= gnttab_end_foreign_transfer_ref_v2,
1442*4882a593Smuzhiyun 	.read_frame			= gnttab_read_frame_v2,
1443*4882a593Smuzhiyun };
1444*4882a593Smuzhiyun 
gnttab_need_v2(void)1445*4882a593Smuzhiyun static bool gnttab_need_v2(void)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun #ifdef CONFIG_X86
1448*4882a593Smuzhiyun 	uint32_t base, width;
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	if (xen_pv_domain()) {
1451*4882a593Smuzhiyun 		base = xen_cpuid_base();
1452*4882a593Smuzhiyun 		if (cpuid_eax(base) < 5)
1453*4882a593Smuzhiyun 			return false;	/* Information not available, use V1. */
1454*4882a593Smuzhiyun 		width = cpuid_ebx(base + 5) &
1455*4882a593Smuzhiyun 			XEN_CPUID_MACHINE_ADDRESS_WIDTH_MASK;
1456*4882a593Smuzhiyun 		return width > 32 + PAGE_SHIFT;
1457*4882a593Smuzhiyun 	}
1458*4882a593Smuzhiyun #endif
1459*4882a593Smuzhiyun 	return !!(max_possible_pfn >> 32);
1460*4882a593Smuzhiyun }
1461*4882a593Smuzhiyun 
gnttab_request_version(void)1462*4882a593Smuzhiyun static void gnttab_request_version(void)
1463*4882a593Smuzhiyun {
1464*4882a593Smuzhiyun 	long rc;
1465*4882a593Smuzhiyun 	struct gnttab_set_version gsv;
1466*4882a593Smuzhiyun 
1467*4882a593Smuzhiyun 	if (gnttab_need_v2())
1468*4882a593Smuzhiyun 		gsv.version = 2;
1469*4882a593Smuzhiyun 	else
1470*4882a593Smuzhiyun 		gsv.version = 1;
1471*4882a593Smuzhiyun 
1472*4882a593Smuzhiyun 	/* Boot parameter overrides automatic selection. */
1473*4882a593Smuzhiyun 	if (xen_gnttab_version >= 1 && xen_gnttab_version <= 2)
1474*4882a593Smuzhiyun 		gsv.version = xen_gnttab_version;
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun 	rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
1477*4882a593Smuzhiyun 	if (rc == 0 && gsv.version == 2)
1478*4882a593Smuzhiyun 		gnttab_interface = &gnttab_v2_ops;
1479*4882a593Smuzhiyun 	else
1480*4882a593Smuzhiyun 		gnttab_interface = &gnttab_v1_ops;
1481*4882a593Smuzhiyun 	pr_info("Grant tables using version %d layout\n",
1482*4882a593Smuzhiyun 		gnttab_interface->version);
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun 
gnttab_setup(void)1485*4882a593Smuzhiyun static int gnttab_setup(void)
1486*4882a593Smuzhiyun {
1487*4882a593Smuzhiyun 	unsigned int max_nr_gframes;
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	max_nr_gframes = gnttab_max_grant_frames();
1490*4882a593Smuzhiyun 	if (max_nr_gframes < nr_grant_frames)
1491*4882a593Smuzhiyun 		return -ENOSYS;
1492*4882a593Smuzhiyun 
1493*4882a593Smuzhiyun 	if (xen_feature(XENFEAT_auto_translated_physmap) && gnttab_shared.addr == NULL) {
1494*4882a593Smuzhiyun 		gnttab_shared.addr = xen_auto_xlat_grant_frames.vaddr;
1495*4882a593Smuzhiyun 		if (gnttab_shared.addr == NULL) {
1496*4882a593Smuzhiyun 			pr_warn("gnttab share frames is not mapped!\n");
1497*4882a593Smuzhiyun 			return -ENOMEM;
1498*4882a593Smuzhiyun 		}
1499*4882a593Smuzhiyun 	}
1500*4882a593Smuzhiyun 	return gnttab_map(0, nr_grant_frames - 1);
1501*4882a593Smuzhiyun }
1502*4882a593Smuzhiyun 
gnttab_resume(void)1503*4882a593Smuzhiyun int gnttab_resume(void)
1504*4882a593Smuzhiyun {
1505*4882a593Smuzhiyun 	gnttab_request_version();
1506*4882a593Smuzhiyun 	return gnttab_setup();
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun 
gnttab_suspend(void)1509*4882a593Smuzhiyun int gnttab_suspend(void)
1510*4882a593Smuzhiyun {
1511*4882a593Smuzhiyun 	if (!xen_feature(XENFEAT_auto_translated_physmap))
1512*4882a593Smuzhiyun 		gnttab_interface->unmap_frames();
1513*4882a593Smuzhiyun 	return 0;
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun 
gnttab_expand(unsigned int req_entries)1516*4882a593Smuzhiyun static int gnttab_expand(unsigned int req_entries)
1517*4882a593Smuzhiyun {
1518*4882a593Smuzhiyun 	int rc;
1519*4882a593Smuzhiyun 	unsigned int cur, extra;
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 	cur = nr_grant_frames;
1522*4882a593Smuzhiyun 	extra = ((req_entries + gnttab_interface->grefs_per_grant_frame - 1) /
1523*4882a593Smuzhiyun 		 gnttab_interface->grefs_per_grant_frame);
1524*4882a593Smuzhiyun 	if (cur + extra > gnttab_max_grant_frames()) {
1525*4882a593Smuzhiyun 		pr_warn_ratelimited("xen/grant-table: max_grant_frames reached"
1526*4882a593Smuzhiyun 				    " cur=%u extra=%u limit=%u"
1527*4882a593Smuzhiyun 				    " gnttab_free_count=%u req_entries=%u\n",
1528*4882a593Smuzhiyun 				    cur, extra, gnttab_max_grant_frames(),
1529*4882a593Smuzhiyun 				    gnttab_free_count, req_entries);
1530*4882a593Smuzhiyun 		return -ENOSPC;
1531*4882a593Smuzhiyun 	}
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 	rc = gnttab_map(cur, cur + extra - 1);
1534*4882a593Smuzhiyun 	if (rc == 0)
1535*4882a593Smuzhiyun 		rc = grow_gnttab_list(extra);
1536*4882a593Smuzhiyun 
1537*4882a593Smuzhiyun 	return rc;
1538*4882a593Smuzhiyun }
1539*4882a593Smuzhiyun 
gnttab_init(void)1540*4882a593Smuzhiyun int gnttab_init(void)
1541*4882a593Smuzhiyun {
1542*4882a593Smuzhiyun 	int i;
1543*4882a593Smuzhiyun 	unsigned long max_nr_grant_frames;
1544*4882a593Smuzhiyun 	unsigned int max_nr_glist_frames, nr_glist_frames;
1545*4882a593Smuzhiyun 	unsigned int nr_init_grefs;
1546*4882a593Smuzhiyun 	int ret;
1547*4882a593Smuzhiyun 
1548*4882a593Smuzhiyun 	gnttab_request_version();
1549*4882a593Smuzhiyun 	max_nr_grant_frames = gnttab_max_grant_frames();
1550*4882a593Smuzhiyun 	nr_grant_frames = 1;
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	/* Determine the maximum number of frames required for the
1553*4882a593Smuzhiyun 	 * grant reference free list on the current hypervisor.
1554*4882a593Smuzhiyun 	 */
1555*4882a593Smuzhiyun 	max_nr_glist_frames = (max_nr_grant_frames *
1556*4882a593Smuzhiyun 			       gnttab_interface->grefs_per_grant_frame / RPP);
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	gnttab_list = kmalloc_array(max_nr_glist_frames,
1559*4882a593Smuzhiyun 				    sizeof(grant_ref_t *),
1560*4882a593Smuzhiyun 				    GFP_KERNEL);
1561*4882a593Smuzhiyun 	if (gnttab_list == NULL)
1562*4882a593Smuzhiyun 		return -ENOMEM;
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun 	nr_glist_frames = gnttab_frames(nr_grant_frames, RPP);
1565*4882a593Smuzhiyun 	for (i = 0; i < nr_glist_frames; i++) {
1566*4882a593Smuzhiyun 		gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
1567*4882a593Smuzhiyun 		if (gnttab_list[i] == NULL) {
1568*4882a593Smuzhiyun 			ret = -ENOMEM;
1569*4882a593Smuzhiyun 			goto ini_nomem;
1570*4882a593Smuzhiyun 		}
1571*4882a593Smuzhiyun 	}
1572*4882a593Smuzhiyun 
1573*4882a593Smuzhiyun 	ret = arch_gnttab_init(max_nr_grant_frames,
1574*4882a593Smuzhiyun 			       nr_status_frames(max_nr_grant_frames));
1575*4882a593Smuzhiyun 	if (ret < 0)
1576*4882a593Smuzhiyun 		goto ini_nomem;
1577*4882a593Smuzhiyun 
1578*4882a593Smuzhiyun 	if (gnttab_setup() < 0) {
1579*4882a593Smuzhiyun 		ret = -ENODEV;
1580*4882a593Smuzhiyun 		goto ini_nomem;
1581*4882a593Smuzhiyun 	}
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	nr_init_grefs = nr_grant_frames *
1584*4882a593Smuzhiyun 			gnttab_interface->grefs_per_grant_frame;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
1587*4882a593Smuzhiyun 		gnttab_entry(i) = i + 1;
1588*4882a593Smuzhiyun 
1589*4882a593Smuzhiyun 	gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
1590*4882a593Smuzhiyun 	gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
1591*4882a593Smuzhiyun 	gnttab_free_head  = NR_RESERVED_ENTRIES;
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	printk("Grant table initialized\n");
1594*4882a593Smuzhiyun 	return 0;
1595*4882a593Smuzhiyun 
1596*4882a593Smuzhiyun  ini_nomem:
1597*4882a593Smuzhiyun 	for (i--; i >= 0; i--)
1598*4882a593Smuzhiyun 		free_page((unsigned long)gnttab_list[i]);
1599*4882a593Smuzhiyun 	kfree(gnttab_list);
1600*4882a593Smuzhiyun 	return ret;
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(gnttab_init);
1603*4882a593Smuzhiyun 
__gnttab_init(void)1604*4882a593Smuzhiyun static int __gnttab_init(void)
1605*4882a593Smuzhiyun {
1606*4882a593Smuzhiyun 	if (!xen_domain())
1607*4882a593Smuzhiyun 		return -ENODEV;
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	/* Delay grant-table initialization in the PV on HVM case */
1610*4882a593Smuzhiyun 	if (xen_hvm_domain() && !xen_pvh_domain())
1611*4882a593Smuzhiyun 		return 0;
1612*4882a593Smuzhiyun 
1613*4882a593Smuzhiyun 	return gnttab_init();
1614*4882a593Smuzhiyun }
1615*4882a593Smuzhiyun /* Starts after core_initcall so that xen_pvh_gnttab_setup can be called
1616*4882a593Smuzhiyun  * beforehand to initialize xen_auto_xlat_grant_frames. */
1617*4882a593Smuzhiyun core_initcall_sync(__gnttab_init);
1618