xref: /illumos-gate/usr/src/uts/common/xen/os/gnttab.c (revision 551bc2a6)
1843e1988Sjohnlev /*
2843e1988Sjohnlev  * CDDL HEADER START
3843e1988Sjohnlev  *
4843e1988Sjohnlev  * The contents of this file are subject to the terms of the
5843e1988Sjohnlev  * Common Development and Distribution License (the "License").
6843e1988Sjohnlev  * You may not use this file except in compliance with the License.
7843e1988Sjohnlev  *
8843e1988Sjohnlev  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9843e1988Sjohnlev  * or http://www.opensolaris.org/os/licensing.
10843e1988Sjohnlev  * See the License for the specific language governing permissions
11843e1988Sjohnlev  * and limitations under the License.
12843e1988Sjohnlev  *
13843e1988Sjohnlev  * When distributing Covered Code, include this CDDL HEADER in each
14843e1988Sjohnlev  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15843e1988Sjohnlev  * If applicable, add the following below this CDDL HEADER, with the
16843e1988Sjohnlev  * fields enclosed by brackets "[]" replaced with your own identifying
17843e1988Sjohnlev  * information: Portions Copyright [yyyy] [name of copyright owner]
18843e1988Sjohnlev  *
19843e1988Sjohnlev  * CDDL HEADER END
20843e1988Sjohnlev  */
21843e1988Sjohnlev 
22843e1988Sjohnlev /*
23843e1988Sjohnlev  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24843e1988Sjohnlev  * Use is subject to license terms.
25843e1988Sjohnlev  */
26843e1988Sjohnlev 
27843e1988Sjohnlev #pragma ident	"%Z%%M%	%I%	%E% SMI"
28843e1988Sjohnlev 
29843e1988Sjohnlev /*
30843e1988Sjohnlev  * gnttab.c
31843e1988Sjohnlev  *
32843e1988Sjohnlev  * Granting foreign access to our memory reservation.
33843e1988Sjohnlev  *
34843e1988Sjohnlev  * Copyright (c) 2005, Christopher Clark
35843e1988Sjohnlev  * Copyright (c) 2004-2005, K A Fraser
36843e1988Sjohnlev  *
37843e1988Sjohnlev  * This file may be distributed separately from the Linux kernel, or
38843e1988Sjohnlev  * incorporated into other software packages, subject to the following license:
39843e1988Sjohnlev  *
40843e1988Sjohnlev  * Permission is hereby granted, free of charge, to any person obtaining a copy
41843e1988Sjohnlev  * of this source file (the "Software"), to deal in the Software without
42843e1988Sjohnlev  * restriction, including without limitation the rights to use, copy, modify,
43843e1988Sjohnlev  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
44843e1988Sjohnlev  * and to permit persons to whom the Software is furnished to do so, subject to
45843e1988Sjohnlev  * the following conditions:
46843e1988Sjohnlev  *
47843e1988Sjohnlev  * The above copyright notice and this permission notice shall be included in
48843e1988Sjohnlev  * all copies or substantial portions of the Software.
49843e1988Sjohnlev  *
50843e1988Sjohnlev  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51843e1988Sjohnlev  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52843e1988Sjohnlev  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53843e1988Sjohnlev  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54843e1988Sjohnlev  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
55843e1988Sjohnlev  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
56843e1988Sjohnlev  * IN THE SOFTWARE.
57843e1988Sjohnlev  */
58843e1988Sjohnlev 
59843e1988Sjohnlev #include <sys/types.h>
60843e1988Sjohnlev #include <sys/archsystm.h>
61*551bc2a6Smrj #ifdef XPV_HVM_DRIVER
62*551bc2a6Smrj #include <sys/xpv_support.h>
63*551bc2a6Smrj #include <sys/mman.h>
64*551bc2a6Smrj #include <vm/hat.h>
65*551bc2a6Smrj #endif
66843e1988Sjohnlev #include <sys/hypervisor.h>
67843e1988Sjohnlev #include <sys/gnttab.h>
68843e1988Sjohnlev #include <sys/sysmacros.h>
69843e1988Sjohnlev #include <sys/machsystm.h>
70843e1988Sjohnlev #include <sys/systm.h>
71843e1988Sjohnlev #include <sys/mutex.h>
72843e1988Sjohnlev #include <sys/atomic.h>
73843e1988Sjohnlev #include <sys/spl.h>
74843e1988Sjohnlev #include <sys/condvar.h>
75843e1988Sjohnlev #include <sys/cpuvar.h>
76843e1988Sjohnlev #include <sys/taskq.h>
77843e1988Sjohnlev #include <sys/panic.h>
78843e1988Sjohnlev #include <sys/cmn_err.h>
79843e1988Sjohnlev #include <sys/promif.h>
80843e1988Sjohnlev #include <sys/cpu.h>
81843e1988Sjohnlev #include <sys/vmem.h>
82843e1988Sjohnlev #include <vm/hat_i86.h>
83843e1988Sjohnlev #include <sys/bootconf.h>
84843e1988Sjohnlev #include <sys/bootsvcs.h>
85*551bc2a6Smrj #ifndef XPV_HVM_DRIVER
86843e1988Sjohnlev #include <sys/bootinfo.h>
87843e1988Sjohnlev #include <sys/multiboot.h>
88*551bc2a6Smrj #include <vm/kboot_mmu.h>
89*551bc2a6Smrj #endif
90843e1988Sjohnlev #include <sys/bootvfs.h>
91843e1988Sjohnlev #include <sys/bootprops.h>
92843e1988Sjohnlev #include <vm/seg_kmem.h>
93843e1988Sjohnlev 
94843e1988Sjohnlev #define	cmpxchg(t, c, n) atomic_cas_16((t), (c), (n))
95843e1988Sjohnlev 
96843e1988Sjohnlev /* External tools reserve first few grant table entries. */
97843e1988Sjohnlev #define	NR_RESERVED_ENTRIES 8
98843e1988Sjohnlev 
99843e1988Sjohnlev #define	NR_GRANT_ENTRIES (NR_GRANT_FRAMES * \
100843e1988Sjohnlev 	    MMU_PAGESIZE / sizeof (grant_entry_t))
101843e1988Sjohnlev #define	GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
102843e1988Sjohnlev #define	VALID_GRANT_REF(r) ((r) < NR_GRANT_ENTRIES)
103843e1988Sjohnlev 
104843e1988Sjohnlev static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
105843e1988Sjohnlev static int gnttab_free_count;
106843e1988Sjohnlev static grant_ref_t gnttab_free_head;
107843e1988Sjohnlev static kmutex_t gnttab_list_lock;
108843e1988Sjohnlev 
109843e1988Sjohnlev static grant_entry_t *shared;
110843e1988Sjohnlev #define	GT_PGADDR(i) ((uintptr_t)shared + ((i) << PAGESHIFT))
111843e1988Sjohnlev 
112843e1988Sjohnlev static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
113843e1988Sjohnlev 
114843e1988Sjohnlev static int
115843e1988Sjohnlev get_free_entries(int count)
116843e1988Sjohnlev {
117843e1988Sjohnlev 	int ref;
118843e1988Sjohnlev 	grant_ref_t head;
119843e1988Sjohnlev 
120843e1988Sjohnlev 	mutex_enter(&gnttab_list_lock);
121843e1988Sjohnlev 	if (gnttab_free_count < count) {
122843e1988Sjohnlev 		mutex_exit(&gnttab_list_lock);
123843e1988Sjohnlev 		return (-1);
124843e1988Sjohnlev 	}
125843e1988Sjohnlev 	ref = head = gnttab_free_head;
126843e1988Sjohnlev 	gnttab_free_count -= count;
127843e1988Sjohnlev 	while (count-- > 1)
128843e1988Sjohnlev 		head = gnttab_list[head];
129843e1988Sjohnlev 	gnttab_free_head = gnttab_list[head];
130843e1988Sjohnlev 	gnttab_list[head] = GNTTAB_LIST_END;
131843e1988Sjohnlev 	mutex_exit(&gnttab_list_lock);
132843e1988Sjohnlev 	return (ref);
133843e1988Sjohnlev }
134843e1988Sjohnlev 
135843e1988Sjohnlev #define	get_free_entry() get_free_entries(1)
136843e1988Sjohnlev 
137843e1988Sjohnlev static void
138843e1988Sjohnlev do_free_callbacks(void)
139843e1988Sjohnlev {
140843e1988Sjohnlev 	struct gnttab_free_callback *callback, *next;
141843e1988Sjohnlev 
142843e1988Sjohnlev 	callback = gnttab_free_callback_list;
143843e1988Sjohnlev 	gnttab_free_callback_list = NULL;
144843e1988Sjohnlev 
145843e1988Sjohnlev 	while (callback != NULL) {
146843e1988Sjohnlev 		next = callback->next;
147843e1988Sjohnlev 		if (gnttab_free_count >= callback->count) {
148843e1988Sjohnlev 			callback->next = NULL;
149843e1988Sjohnlev 			callback->fn(callback->arg);
150843e1988Sjohnlev 		} else {
151843e1988Sjohnlev 			callback->next = gnttab_free_callback_list;
152843e1988Sjohnlev 			gnttab_free_callback_list = callback;
153843e1988Sjohnlev 		}
154843e1988Sjohnlev 		callback = next;
155843e1988Sjohnlev 	}
156843e1988Sjohnlev }
157843e1988Sjohnlev 
158843e1988Sjohnlev static void
159843e1988Sjohnlev check_free_callbacks(void)
160843e1988Sjohnlev {
161843e1988Sjohnlev 	if (gnttab_free_callback_list)
162843e1988Sjohnlev 		do_free_callbacks();
163843e1988Sjohnlev }
164843e1988Sjohnlev 
165843e1988Sjohnlev static void
166843e1988Sjohnlev put_free_entry(grant_ref_t ref)
167843e1988Sjohnlev {
168843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
169843e1988Sjohnlev 
170843e1988Sjohnlev 	mutex_enter(&gnttab_list_lock);
171843e1988Sjohnlev 	gnttab_list[ref] = gnttab_free_head;
172843e1988Sjohnlev 	gnttab_free_head = ref;
173843e1988Sjohnlev 	gnttab_free_count++;
174843e1988Sjohnlev 	check_free_callbacks();
175843e1988Sjohnlev 	mutex_exit(&gnttab_list_lock);
176843e1988Sjohnlev }
177843e1988Sjohnlev 
178843e1988Sjohnlev /*
179843e1988Sjohnlev  * Public grant-issuing interface functions
180843e1988Sjohnlev  */
181843e1988Sjohnlev 
182843e1988Sjohnlev int
183843e1988Sjohnlev gnttab_grant_foreign_access(domid_t domid, gnttab_frame_t frame, int readonly)
184843e1988Sjohnlev {
185843e1988Sjohnlev 	int ref;
186843e1988Sjohnlev 
187843e1988Sjohnlev 	if ((ref = get_free_entry()) == -1)
188843e1988Sjohnlev 		return (-1);
189843e1988Sjohnlev 
190843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
191843e1988Sjohnlev 
192843e1988Sjohnlev 	shared[ref].frame = frame;
193843e1988Sjohnlev 	shared[ref].domid = domid;
194843e1988Sjohnlev 	membar_producer();
195843e1988Sjohnlev 	shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
196843e1988Sjohnlev 
197843e1988Sjohnlev 	return (ref);
198843e1988Sjohnlev }
199843e1988Sjohnlev 
200843e1988Sjohnlev void
201843e1988Sjohnlev gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
202843e1988Sjohnlev 				gnttab_frame_t frame, int readonly)
203843e1988Sjohnlev {
204843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
205843e1988Sjohnlev 
206843e1988Sjohnlev 	shared[ref].frame = frame;
207843e1988Sjohnlev 	shared[ref].domid = domid;
208843e1988Sjohnlev 	membar_producer();
209843e1988Sjohnlev 	shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
210843e1988Sjohnlev }
211843e1988Sjohnlev 
212843e1988Sjohnlev 
213843e1988Sjohnlev int
214843e1988Sjohnlev gnttab_query_foreign_access(grant_ref_t ref)
215843e1988Sjohnlev {
216843e1988Sjohnlev 	uint16_t nflags;
217843e1988Sjohnlev 
218843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
219843e1988Sjohnlev 
220843e1988Sjohnlev 	nflags = shared[ref].flags;
221843e1988Sjohnlev 
222843e1988Sjohnlev 	return (nflags & (GTF_reading|GTF_writing));
223843e1988Sjohnlev }
224843e1988Sjohnlev 
225843e1988Sjohnlev /* ARGSUSED */
226843e1988Sjohnlev int
227843e1988Sjohnlev gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
228843e1988Sjohnlev {
229843e1988Sjohnlev 	uint16_t flags, nflags;
230843e1988Sjohnlev 
231843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
232843e1988Sjohnlev 
233843e1988Sjohnlev 	nflags = shared[ref].flags;
234843e1988Sjohnlev 	do {
235843e1988Sjohnlev 		if ((flags = nflags) & (GTF_reading|GTF_writing)) {
236843e1988Sjohnlev 			cmn_err(CE_WARN, "g.e. still in use!");
237843e1988Sjohnlev 			return (0);
238843e1988Sjohnlev 		}
239843e1988Sjohnlev 	} while ((nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags);
240843e1988Sjohnlev 
241843e1988Sjohnlev 	return (1);
242843e1988Sjohnlev }
243843e1988Sjohnlev 
244843e1988Sjohnlev void
245843e1988Sjohnlev gnttab_end_foreign_access(grant_ref_t ref, int readonly, gnttab_frame_t page)
246843e1988Sjohnlev {
247843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
248843e1988Sjohnlev 
249843e1988Sjohnlev 	if (gnttab_end_foreign_access_ref(ref, readonly)) {
250843e1988Sjohnlev 		put_free_entry(ref);
251843e1988Sjohnlev 		/*
252843e1988Sjohnlev 		 * XXPV - we don't support freeing a page here
253843e1988Sjohnlev 		 */
254843e1988Sjohnlev 		if (page != 0) {
255843e1988Sjohnlev 			cmn_err(CE_WARN,
256843e1988Sjohnlev 	"gnttab_end_foreign_access_ref: using unsupported free_page interface");
257843e1988Sjohnlev 			/* free_page(page); */
258843e1988Sjohnlev 		}
259843e1988Sjohnlev 	} else {
260843e1988Sjohnlev 		/*
261843e1988Sjohnlev 		 * XXX This needs to be fixed so that the ref and page are
262843e1988Sjohnlev 		 * placed on a list to be freed up later.
263843e1988Sjohnlev 		 */
264843e1988Sjohnlev 		cmn_err(CE_WARN, "leaking g.e. and page still in use!");
265843e1988Sjohnlev 	}
266843e1988Sjohnlev }
267843e1988Sjohnlev 
268843e1988Sjohnlev int
269843e1988Sjohnlev gnttab_grant_foreign_transfer(domid_t domid)
270843e1988Sjohnlev {
271843e1988Sjohnlev 	int ref;
272843e1988Sjohnlev 
273843e1988Sjohnlev 	if ((ref = get_free_entry()) == -1)
274843e1988Sjohnlev 		return (-1);
275843e1988Sjohnlev 
276843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
277843e1988Sjohnlev 
278843e1988Sjohnlev 	shared[ref].frame = 0;
279843e1988Sjohnlev 	shared[ref].domid = domid;
280843e1988Sjohnlev 	membar_producer();
281843e1988Sjohnlev 	shared[ref].flags = GTF_accept_transfer;
282843e1988Sjohnlev 
283843e1988Sjohnlev 	return (ref);
284843e1988Sjohnlev }
285843e1988Sjohnlev 
286843e1988Sjohnlev void
287843e1988Sjohnlev gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid)
288843e1988Sjohnlev {
289843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
290843e1988Sjohnlev 
291843e1988Sjohnlev 	shared[ref].frame = 0;
292843e1988Sjohnlev 	shared[ref].domid = domid;
293843e1988Sjohnlev 	membar_producer();
294843e1988Sjohnlev 	shared[ref].flags = GTF_accept_transfer;
295843e1988Sjohnlev }
296843e1988Sjohnlev 
297843e1988Sjohnlev gnttab_frame_t
298843e1988Sjohnlev gnttab_end_foreign_transfer_ref(grant_ref_t ref)
299843e1988Sjohnlev {
300843e1988Sjohnlev 	gnttab_frame_t frame;
301843e1988Sjohnlev 	uint16_t flags;
302843e1988Sjohnlev 
303843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
304843e1988Sjohnlev 
305843e1988Sjohnlev 	/*
306843e1988Sjohnlev 	 * If a transfer is not even yet started, try to reclaim the grant
307843e1988Sjohnlev 	 * reference and return failure (== 0).
308843e1988Sjohnlev 	 */
309843e1988Sjohnlev 	while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
310843e1988Sjohnlev 		if (cmpxchg(&shared[ref].flags, flags, 0) == flags)
311843e1988Sjohnlev 			return (0);
312843e1988Sjohnlev 		(void) HYPERVISOR_yield();
313843e1988Sjohnlev 	}
314843e1988Sjohnlev 
315843e1988Sjohnlev 	/* If a transfer is in progress then wait until it is completed. */
316843e1988Sjohnlev 	while (!(flags & GTF_transfer_completed)) {
317843e1988Sjohnlev 		flags = shared[ref].flags;
318843e1988Sjohnlev 		(void) HYPERVISOR_yield();
319843e1988Sjohnlev 	}
320843e1988Sjohnlev 
321843e1988Sjohnlev 	/* Read the frame number /after/ reading completion status. */
322843e1988Sjohnlev 	membar_consumer();
323843e1988Sjohnlev 	frame = shared[ref].frame;
324843e1988Sjohnlev 	ASSERT(frame != 0);
325843e1988Sjohnlev 
326843e1988Sjohnlev 	return (frame);
327843e1988Sjohnlev }
328843e1988Sjohnlev 
329843e1988Sjohnlev gnttab_frame_t
330843e1988Sjohnlev gnttab_end_foreign_transfer(grant_ref_t ref)
331843e1988Sjohnlev {
332843e1988Sjohnlev 	gnttab_frame_t frame;
333843e1988Sjohnlev 
334843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
335843e1988Sjohnlev 
336843e1988Sjohnlev 	frame = gnttab_end_foreign_transfer_ref(ref);
337843e1988Sjohnlev 	put_free_entry(ref);
338843e1988Sjohnlev 	return (frame);
339843e1988Sjohnlev }
340843e1988Sjohnlev 
341843e1988Sjohnlev void
342843e1988Sjohnlev gnttab_free_grant_reference(grant_ref_t ref)
343843e1988Sjohnlev {
344843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(ref));
345843e1988Sjohnlev 
346843e1988Sjohnlev 	put_free_entry(ref);
347843e1988Sjohnlev }
348843e1988Sjohnlev 
349843e1988Sjohnlev void
350843e1988Sjohnlev gnttab_free_grant_references(grant_ref_t head)
351843e1988Sjohnlev {
352843e1988Sjohnlev 	grant_ref_t ref;
353843e1988Sjohnlev 	int count = 1;
354843e1988Sjohnlev 
355843e1988Sjohnlev 	if (head == GNTTAB_LIST_END)
356843e1988Sjohnlev 		return;
357843e1988Sjohnlev 	mutex_enter(&gnttab_list_lock);
358843e1988Sjohnlev 	ref = head;
359843e1988Sjohnlev 	while (gnttab_list[ref] != GNTTAB_LIST_END) {
360843e1988Sjohnlev 		ref = gnttab_list[ref];
361843e1988Sjohnlev 		count++;
362843e1988Sjohnlev 	}
363843e1988Sjohnlev 	gnttab_list[ref] = gnttab_free_head;
364843e1988Sjohnlev 	gnttab_free_head = head;
365843e1988Sjohnlev 	gnttab_free_count += count;
366843e1988Sjohnlev 	check_free_callbacks();
367843e1988Sjohnlev 	mutex_exit(&gnttab_list_lock);
368843e1988Sjohnlev }
369843e1988Sjohnlev 
370843e1988Sjohnlev int
371843e1988Sjohnlev gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head)
372843e1988Sjohnlev {
373843e1988Sjohnlev 	int h = get_free_entries(count);
374843e1988Sjohnlev 
375843e1988Sjohnlev 	if (h == -1)
376843e1988Sjohnlev 		return (-1);
377843e1988Sjohnlev 
378843e1988Sjohnlev 	*head = h;
379843e1988Sjohnlev 
380843e1988Sjohnlev 	return (0);
381843e1988Sjohnlev }
382843e1988Sjohnlev 
383843e1988Sjohnlev int
384843e1988Sjohnlev gnttab_claim_grant_reference(grant_ref_t *private_head)
385843e1988Sjohnlev {
386843e1988Sjohnlev 	grant_ref_t g = *private_head;
387843e1988Sjohnlev 
388843e1988Sjohnlev 	if (g == GNTTAB_LIST_END)
389843e1988Sjohnlev 		return (-1);
390843e1988Sjohnlev 	*private_head = gnttab_list[g];
391843e1988Sjohnlev 	return (g);
392843e1988Sjohnlev }
393843e1988Sjohnlev 
394843e1988Sjohnlev void
395843e1988Sjohnlev gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
396843e1988Sjohnlev {
397843e1988Sjohnlev 	ASSERT(VALID_GRANT_REF(release));
398843e1988Sjohnlev 
399843e1988Sjohnlev 	gnttab_list[release] = *private_head;
400843e1988Sjohnlev 	*private_head = release;
401843e1988Sjohnlev }
402843e1988Sjohnlev 
403843e1988Sjohnlev void
404843e1988Sjohnlev gnttab_request_free_callback(struct gnttab_free_callback *callback,
405843e1988Sjohnlev 	void (*fn)(void *), void *arg, uint16_t count)
406843e1988Sjohnlev {
407843e1988Sjohnlev 	mutex_enter(&gnttab_list_lock);
408843e1988Sjohnlev 	if (callback->next)
409843e1988Sjohnlev 		goto out;
410843e1988Sjohnlev 	callback->fn = fn;
411843e1988Sjohnlev 	callback->arg = arg;
412843e1988Sjohnlev 	callback->count = count;
413843e1988Sjohnlev 	callback->next = gnttab_free_callback_list;
414843e1988Sjohnlev 	gnttab_free_callback_list = callback;
415843e1988Sjohnlev 	check_free_callbacks();
416843e1988Sjohnlev out:
417843e1988Sjohnlev 	mutex_exit(&gnttab_list_lock);
418843e1988Sjohnlev }
419843e1988Sjohnlev 
420*551bc2a6Smrj #ifdef XPV_HVM_DRIVER
421*551bc2a6Smrj 
422*551bc2a6Smrj static void
423*551bc2a6Smrj gnttab_map(void)
424*551bc2a6Smrj {
425*551bc2a6Smrj 	struct xen_add_to_physmap xatp;
426*551bc2a6Smrj 	caddr_t va;
427*551bc2a6Smrj 	pfn_t pfn;
428*551bc2a6Smrj 	int i;
429*551bc2a6Smrj 
430*551bc2a6Smrj 	va = (caddr_t)shared;
431*551bc2a6Smrj 	for (i = 0; i < NR_GRANT_FRAMES; i++) {
432*551bc2a6Smrj 		pfn = hat_getpfnum(kas.a_hat, va);
433*551bc2a6Smrj 
434*551bc2a6Smrj 		xatp.domid = DOMID_SELF;
435*551bc2a6Smrj 		xatp.idx = i;
436*551bc2a6Smrj 		xatp.space = XENMAPSPACE_grant_table;
437*551bc2a6Smrj 		xatp.gpfn = pfn;
438*551bc2a6Smrj 		hat_unload(kas.a_hat, va, MMU_PAGESIZE, HAT_UNLOAD);
439*551bc2a6Smrj 		if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
440*551bc2a6Smrj 			panic("Couldn't map grant table");
441*551bc2a6Smrj 
442*551bc2a6Smrj 		hat_devload(kas.a_hat, va, MMU_PAGESIZE, pfn,
443*551bc2a6Smrj 		    PROT_READ | PROT_WRITE,
444*551bc2a6Smrj 		    HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
445*551bc2a6Smrj 
446*551bc2a6Smrj 		va += MMU_PAGESIZE;
447*551bc2a6Smrj 	}
448*551bc2a6Smrj }
449*551bc2a6Smrj 
450*551bc2a6Smrj void
451*551bc2a6Smrj gnttab_init(void)
452*551bc2a6Smrj {
453*551bc2a6Smrj 	int i;
454*551bc2a6Smrj 
455*551bc2a6Smrj 	shared = (grant_entry_t *)xen_alloc_pages(NR_GRANT_FRAMES);
456*551bc2a6Smrj 
457*551bc2a6Smrj 	gnttab_map();
458*551bc2a6Smrj 
459*551bc2a6Smrj 	for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
460*551bc2a6Smrj 		gnttab_list[i] = i + 1;
461*551bc2a6Smrj 	gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
462*551bc2a6Smrj 	gnttab_free_head  = NR_RESERVED_ENTRIES;
463*551bc2a6Smrj 
464*551bc2a6Smrj 	mutex_init(&gnttab_list_lock, NULL, MUTEX_DEFAULT, NULL);
465*551bc2a6Smrj }
466*551bc2a6Smrj 
467*551bc2a6Smrj void
468*551bc2a6Smrj gnttab_resume(void)
469*551bc2a6Smrj {
470*551bc2a6Smrj 	gnttab_map();
471*551bc2a6Smrj }
472*551bc2a6Smrj 
473*551bc2a6Smrj #else /* XPV_HVM_DRIVER */
474*551bc2a6Smrj 
475843e1988Sjohnlev void
476843e1988Sjohnlev gnttab_init(void)
477843e1988Sjohnlev {
478843e1988Sjohnlev 	gnttab_setup_table_t set;
479843e1988Sjohnlev 	gnttab_frame_t frames[NR_GRANT_FRAMES];
480843e1988Sjohnlev 	int i;
481843e1988Sjohnlev 
482843e1988Sjohnlev 	set.dom = DOMID_SELF;
483843e1988Sjohnlev 	set.nr_frames = NR_GRANT_FRAMES;
484843e1988Sjohnlev 	/*LINTED: constant in conditional context*/
485843e1988Sjohnlev 	set_xen_guest_handle(set.frame_list, frames);
486843e1988Sjohnlev 
487843e1988Sjohnlev 	/*
488843e1988Sjohnlev 	 * Take 4 pages of grant table space from the hypervisor and map it
489843e1988Sjohnlev 	 */
490843e1988Sjohnlev 	if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &set, 1) != 0) ||
491843e1988Sjohnlev 	    (set.status != 0)) {
492843e1988Sjohnlev 		cmn_err(CE_PANIC, "Grant Table setup failed");
493843e1988Sjohnlev 	}
494843e1988Sjohnlev 
495843e1988Sjohnlev 	shared = vmem_xalloc(heap_arena, NR_GRANT_FRAMES * MMU_PAGESIZE,
496843e1988Sjohnlev 	    MMU_PAGESIZE, 0, 0, 0, 0, VM_SLEEP);
497843e1988Sjohnlev 
498843e1988Sjohnlev 	for (i = 0; i < NR_GRANT_FRAMES; i++)
499843e1988Sjohnlev 		kbm_map_ma(FRAME_TO_MA(frames[i]), GT_PGADDR(i), 0);
500843e1988Sjohnlev 
501843e1988Sjohnlev 	for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
502843e1988Sjohnlev 		gnttab_list[i] = i + 1;
503843e1988Sjohnlev 	gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
504843e1988Sjohnlev 	gnttab_free_head  = NR_RESERVED_ENTRIES;
505843e1988Sjohnlev 
506843e1988Sjohnlev 	mutex_init(&gnttab_list_lock, NULL, MUTEX_DEFAULT, NULL);
507843e1988Sjohnlev }
508843e1988Sjohnlev 
509843e1988Sjohnlev void
510843e1988Sjohnlev gnttab_resume(void)
511843e1988Sjohnlev {
512843e1988Sjohnlev 	gnttab_setup_table_t set;
513843e1988Sjohnlev 	gnttab_frame_t frames[NR_GRANT_FRAMES];
514843e1988Sjohnlev 	int i;
515843e1988Sjohnlev 
516843e1988Sjohnlev 	set.dom = DOMID_SELF;
517843e1988Sjohnlev 	set.nr_frames = NR_GRANT_FRAMES;
518843e1988Sjohnlev 	/*LINTED: constant in conditional context*/
519843e1988Sjohnlev 	set_xen_guest_handle(set.frame_list, frames);
520843e1988Sjohnlev 
521843e1988Sjohnlev 	/*
522843e1988Sjohnlev 	 * Take NR_GRANT_FRAMES pages of grant table space from the
523843e1988Sjohnlev 	 * hypervisor and map it
524843e1988Sjohnlev 	 */
525843e1988Sjohnlev 	if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &set, 1) != 0) ||
526843e1988Sjohnlev 	    (set.status != 0)) {
527843e1988Sjohnlev 		cmn_err(CE_PANIC, "Grant Table setup failed");
528843e1988Sjohnlev 	}
529843e1988Sjohnlev 
530843e1988Sjohnlev 	for (i = 0; i < NR_GRANT_FRAMES; i++) {
531843e1988Sjohnlev 		(void) HYPERVISOR_update_va_mapping(GT_PGADDR(i),
532843e1988Sjohnlev 		    FRAME_TO_MA(frames[i]) | PT_VALID | PT_WRITABLE,
533843e1988Sjohnlev 		    UVMF_INVLPG | UVMF_ALL);
534843e1988Sjohnlev 	}
535843e1988Sjohnlev }
536843e1988Sjohnlev 
537*551bc2a6Smrj #endif /* XPV_HVM_DRIVER */
538*551bc2a6Smrj 
539843e1988Sjohnlev void
540843e1988Sjohnlev gnttab_suspend(void)
541843e1988Sjohnlev {
542843e1988Sjohnlev 	int i;
543843e1988Sjohnlev 
544843e1988Sjohnlev 	/*
545843e1988Sjohnlev 	 * clear grant table mappings before suspending
546843e1988Sjohnlev 	 */
547843e1988Sjohnlev 	for (i = 0; i < NR_GRANT_FRAMES; i++) {
548843e1988Sjohnlev 		(void) HYPERVISOR_update_va_mapping(GT_PGADDR(i),
549843e1988Sjohnlev 		    0, UVMF_INVLPG);
550843e1988Sjohnlev 	}
551843e1988Sjohnlev }
552843e1988Sjohnlev 
553843e1988Sjohnlev /*
554843e1988Sjohnlev  * Local variables:
555843e1988Sjohnlev  *  c-file-style: "solaris"
556843e1988Sjohnlev  *  indent-tabs-mode: t
557843e1988Sjohnlev  *  c-indent-level: 8
558843e1988Sjohnlev  *  c-basic-offset: 8
559843e1988Sjohnlev  *  tab-width: 8
560843e1988Sjohnlev  * End:
561843e1988Sjohnlev  */
562