xref: /titanic_50/usr/src/uts/common/xen/os/gnttab.c (revision 6eb35ee750312cc65aa066dd0f625b9d54c6f86e)
1551bc2a6Smrj /*
2551bc2a6Smrj  * CDDL HEADER START
3551bc2a6Smrj  *
4551bc2a6Smrj  * The contents of this file are subject to the terms of the
5551bc2a6Smrj  * Common Development and Distribution License (the "License").
6551bc2a6Smrj  * You may not use this file except in compliance with the License.
7551bc2a6Smrj  *
8551bc2a6Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9551bc2a6Smrj  * or http://www.opensolaris.org/os/licensing.
10551bc2a6Smrj  * See the License for the specific language governing permissions
11551bc2a6Smrj  * and limitations under the License.
12551bc2a6Smrj  *
13551bc2a6Smrj  * When distributing Covered Code, include this CDDL HEADER in each
14551bc2a6Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15551bc2a6Smrj  * If applicable, add the following below this CDDL HEADER, with the
16551bc2a6Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
17551bc2a6Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
18551bc2a6Smrj  *
19551bc2a6Smrj  * CDDL HEADER END
20551bc2a6Smrj  */
21551bc2a6Smrj 
22551bc2a6Smrj /*
23a576ab5bSrab  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24551bc2a6Smrj  * Use is subject to license terms.
25551bc2a6Smrj  */
26551bc2a6Smrj 
27551bc2a6Smrj #pragma ident	"%Z%%M%	%I%	%E% SMI"
28551bc2a6Smrj 
29551bc2a6Smrj /*
30551bc2a6Smrj  * gnttab.c
31551bc2a6Smrj  *
32551bc2a6Smrj  * Granting foreign access to our memory reservation.
33551bc2a6Smrj  *
34a576ab5bSrab  * Copyright (c) 2005-2006, Christopher Clark
35551bc2a6Smrj  * Copyright (c) 2004-2005, K A Fraser
36551bc2a6Smrj  *
37a576ab5bSrab  * This program is free software; you can redistribute it and/or
38a576ab5bSrab  * modify it under the terms of the GNU General Public License version 2
39a576ab5bSrab  * as published by the Free Software Foundation; or, when distributed
40a576ab5bSrab  * separately from the Linux kernel or incorporated into other
41a576ab5bSrab  * software packages, subject to the following license:
42551bc2a6Smrj  *
43551bc2a6Smrj  * Permission is hereby granted, free of charge, to any person obtaining a copy
44551bc2a6Smrj  * of this source file (the "Software"), to deal in the Software without
45551bc2a6Smrj  * restriction, including without limitation the rights to use, copy, modify,
46551bc2a6Smrj  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
47551bc2a6Smrj  * and to permit persons to whom the Software is furnished to do so, subject to
48551bc2a6Smrj  * the following conditions:
49551bc2a6Smrj  *
50551bc2a6Smrj  * The above copyright notice and this permission notice shall be included in
51551bc2a6Smrj  * all copies or substantial portions of the Software.
52551bc2a6Smrj  *
53551bc2a6Smrj  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54551bc2a6Smrj  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55551bc2a6Smrj  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
56551bc2a6Smrj  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57551bc2a6Smrj  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
58551bc2a6Smrj  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
59551bc2a6Smrj  * IN THE SOFTWARE.
60551bc2a6Smrj  */
61551bc2a6Smrj 
62551bc2a6Smrj #include <sys/types.h>
63551bc2a6Smrj #include <sys/archsystm.h>
64551bc2a6Smrj #ifdef XPV_HVM_DRIVER
65551bc2a6Smrj #include <sys/xpv_support.h>
66551bc2a6Smrj #include <sys/mman.h>
67551bc2a6Smrj #include <vm/hat.h>
68551bc2a6Smrj #endif
69551bc2a6Smrj #include <sys/hypervisor.h>
70551bc2a6Smrj #include <sys/gnttab.h>
71551bc2a6Smrj #include <sys/sysmacros.h>
72551bc2a6Smrj #include <sys/machsystm.h>
73551bc2a6Smrj #include <sys/systm.h>
74551bc2a6Smrj #include <sys/mutex.h>
75551bc2a6Smrj #include <sys/atomic.h>
76551bc2a6Smrj #include <sys/spl.h>
77551bc2a6Smrj #include <sys/condvar.h>
78551bc2a6Smrj #include <sys/cpuvar.h>
79551bc2a6Smrj #include <sys/taskq.h>
80551bc2a6Smrj #include <sys/panic.h>
81551bc2a6Smrj #include <sys/cmn_err.h>
82551bc2a6Smrj #include <sys/promif.h>
83551bc2a6Smrj #include <sys/cpu.h>
84551bc2a6Smrj #include <sys/vmem.h>
85551bc2a6Smrj #include <vm/hat_i86.h>
86551bc2a6Smrj #include <sys/bootconf.h>
87551bc2a6Smrj #include <sys/bootsvcs.h>
88551bc2a6Smrj #ifndef XPV_HVM_DRIVER
89551bc2a6Smrj #include <sys/bootinfo.h>
90551bc2a6Smrj #include <sys/multiboot.h>
91551bc2a6Smrj #include <vm/kboot_mmu.h>
92551bc2a6Smrj #endif
93551bc2a6Smrj #include <sys/bootvfs.h>
94551bc2a6Smrj #include <sys/bootprops.h>
95551bc2a6Smrj #include <vm/seg_kmem.h>
96a576ab5bSrab #include <sys/mman.h>
97551bc2a6Smrj 
98a576ab5bSrab /* Globals */
99551bc2a6Smrj 
100a576ab5bSrab static grant_ref_t **gnttab_list;
101a576ab5bSrab static uint_t nr_grant_frames;
102551bc2a6Smrj static int gnttab_free_count;
103551bc2a6Smrj static grant_ref_t gnttab_free_head;
104551bc2a6Smrj static kmutex_t gnttab_list_lock;
105551bc2a6Smrj static grant_entry_t *shared;
106a576ab5bSrab static struct gnttab_free_callback *gnttab_free_callback_list;
107551bc2a6Smrj 
108a576ab5bSrab /* Macros */
109551bc2a6Smrj 
110a576ab5bSrab #define	GT_PGADDR(i) ((uintptr_t)shared + ((i) << MMU_PAGESHIFT))
111a576ab5bSrab #define	VALID_GRANT_REF(r) ((r) < (nr_grant_frames * GREFS_PER_GRANT_FRAME))
112a576ab5bSrab #define	RPP (PAGESIZE / sizeof (grant_ref_t))
113a576ab5bSrab #define	GNTTAB_ENTRY(entry) (gnttab_list[(entry) / RPP][(entry) % RPP])
114a576ab5bSrab #define	CMPXCHG(t, c, n) atomic_cas_16((t), (c), (n))
115a576ab5bSrab /* External tools reserve first few grant table entries. */
116a576ab5bSrab #define	NR_RESERVED_ENTRIES 8
117a576ab5bSrab #define	GNTTAB_LIST_END 0xffffffff
118a576ab5bSrab #define	GREFS_PER_GRANT_FRAME (PAGESIZE / sizeof (grant_entry_t))
119a576ab5bSrab 
120a576ab5bSrab /* Implementation */
121a576ab5bSrab 
122a576ab5bSrab static uint_t
max_nr_grant_frames(void)123a576ab5bSrab max_nr_grant_frames(void)
124551bc2a6Smrj {
125a576ab5bSrab 	struct gnttab_query_size query;
126a576ab5bSrab 	int rc;
127551bc2a6Smrj 
128a576ab5bSrab 	query.dom = DOMID_SELF;
129551bc2a6Smrj 
130a576ab5bSrab 	rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
131a576ab5bSrab 	if ((rc < 0) || (query.status != GNTST_okay))
132a576ab5bSrab 		return (4); /* Legacy max supported number of frames */
133a576ab5bSrab 
134a576ab5bSrab 	ASSERT(query.max_nr_frames);
135a576ab5bSrab 	return (query.max_nr_frames);
136a576ab5bSrab }
137551bc2a6Smrj 
138551bc2a6Smrj static void
do_free_callbacks(void)139551bc2a6Smrj do_free_callbacks(void)
140551bc2a6Smrj {
141551bc2a6Smrj 	struct gnttab_free_callback *callback, *next;
142551bc2a6Smrj 
143551bc2a6Smrj 	callback = gnttab_free_callback_list;
144551bc2a6Smrj 	gnttab_free_callback_list = NULL;
145551bc2a6Smrj 
146551bc2a6Smrj 	while (callback != NULL) {
147551bc2a6Smrj 		next = callback->next;
148551bc2a6Smrj 		if (gnttab_free_count >= callback->count) {
149551bc2a6Smrj 			callback->next = NULL;
150551bc2a6Smrj 			callback->fn(callback->arg);
151551bc2a6Smrj 		} else {
152551bc2a6Smrj 			callback->next = gnttab_free_callback_list;
153551bc2a6Smrj 			gnttab_free_callback_list = callback;
154551bc2a6Smrj 		}
155551bc2a6Smrj 		callback = next;
156551bc2a6Smrj 	}
157551bc2a6Smrj }
158551bc2a6Smrj 
159551bc2a6Smrj static void
check_free_callbacks(void)160551bc2a6Smrj check_free_callbacks(void)
161551bc2a6Smrj {
162551bc2a6Smrj 	if (gnttab_free_callback_list)
163551bc2a6Smrj 		do_free_callbacks();
164551bc2a6Smrj }
165551bc2a6Smrj 
166a576ab5bSrab static int
grow_gnttab_list(uint_t more_frames)167a576ab5bSrab grow_gnttab_list(uint_t more_frames)
168a576ab5bSrab {
169a576ab5bSrab 	uint_t new_nr_grant_frames, extra_entries, i;
1701213c83cSgarypen 	uint_t nr_glist_frames, new_nr_glist_frames;
171a576ab5bSrab 
172a576ab5bSrab 	ASSERT(MUTEX_HELD(&gnttab_list_lock));
173a576ab5bSrab 
174a576ab5bSrab 	new_nr_grant_frames = nr_grant_frames + more_frames;
175a576ab5bSrab 	extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
176a576ab5bSrab 
1771213c83cSgarypen 	nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1)
1781213c83cSgarypen 	    / RPP;
1791213c83cSgarypen 	new_nr_glist_frames = (new_nr_grant_frames * GREFS_PER_GRANT_FRAME
1801213c83cSgarypen 	    + RPP - 1) / RPP;
1811213c83cSgarypen 	for (i = nr_glist_frames; i < new_nr_glist_frames; i++)
182a576ab5bSrab 		gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP);
183a576ab5bSrab 
184a576ab5bSrab 	for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
185a576ab5bSrab 	    i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
186a576ab5bSrab 		GNTTAB_ENTRY(i) = i + 1;
187a576ab5bSrab 
188a576ab5bSrab 	GNTTAB_ENTRY(i) = gnttab_free_head;
189a576ab5bSrab 	gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
190a576ab5bSrab 	gnttab_free_count += extra_entries;
191a576ab5bSrab 
192a576ab5bSrab 	nr_grant_frames = new_nr_grant_frames;
193a576ab5bSrab 
194a576ab5bSrab 	check_free_callbacks();
195a576ab5bSrab 
196a576ab5bSrab 	return (0);
197a576ab5bSrab }
198a576ab5bSrab 
199a576ab5bSrab static int
gnttab_expand(uint_t req_entries)200a576ab5bSrab gnttab_expand(uint_t req_entries)
201a576ab5bSrab {
202a576ab5bSrab 	uint_t cur, extra;
203a576ab5bSrab 
204a576ab5bSrab 	ASSERT(MUTEX_HELD(&gnttab_list_lock));
205a576ab5bSrab 
206a576ab5bSrab 	cur = nr_grant_frames;
207a576ab5bSrab 	extra = ((req_entries + (GREFS_PER_GRANT_FRAME - 1)) /
208a576ab5bSrab 	    GREFS_PER_GRANT_FRAME);
209a576ab5bSrab 	if (cur + extra > max_nr_grant_frames())
210a576ab5bSrab 		return (-1);
211a576ab5bSrab 
212a576ab5bSrab 	return (grow_gnttab_list(extra));
213a576ab5bSrab }
214a576ab5bSrab 
215a576ab5bSrab static int
get_free_entries(int count)216a576ab5bSrab get_free_entries(int count)
217a576ab5bSrab {
218a576ab5bSrab 	int ref, rc;
219a576ab5bSrab 	grant_ref_t head;
220a576ab5bSrab 
221a576ab5bSrab 	mutex_enter(&gnttab_list_lock);
222a576ab5bSrab 	if (gnttab_free_count < count &&
223a576ab5bSrab 	    ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
224a576ab5bSrab 		mutex_exit(&gnttab_list_lock);
225a576ab5bSrab 		return (rc);
226a576ab5bSrab 	}
227a576ab5bSrab 	ref = head = gnttab_free_head;
228a576ab5bSrab 	gnttab_free_count -= count;
229a576ab5bSrab 	while (count-- > 1)
230a576ab5bSrab 		head = GNTTAB_ENTRY(head);
231a576ab5bSrab 	gnttab_free_head = GNTTAB_ENTRY(head);
232a576ab5bSrab 	GNTTAB_ENTRY(head) = GNTTAB_LIST_END;
233a576ab5bSrab 	mutex_exit(&gnttab_list_lock);
234a576ab5bSrab 	return (ref);
235a576ab5bSrab }
236a576ab5bSrab 
237551bc2a6Smrj static void
put_free_entry(grant_ref_t ref)238551bc2a6Smrj put_free_entry(grant_ref_t ref)
239551bc2a6Smrj {
240551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
241551bc2a6Smrj 
242551bc2a6Smrj 	mutex_enter(&gnttab_list_lock);
243a576ab5bSrab 	GNTTAB_ENTRY(ref) = gnttab_free_head;
244551bc2a6Smrj 	gnttab_free_head = ref;
245551bc2a6Smrj 	gnttab_free_count++;
246551bc2a6Smrj 	check_free_callbacks();
247551bc2a6Smrj 	mutex_exit(&gnttab_list_lock);
248551bc2a6Smrj }
249551bc2a6Smrj 
250551bc2a6Smrj /*
251551bc2a6Smrj  * Public grant-issuing interface functions
252551bc2a6Smrj  */
253551bc2a6Smrj 
254551bc2a6Smrj int
gnttab_grant_foreign_access(domid_t domid,gnttab_frame_t frame,int readonly)255551bc2a6Smrj gnttab_grant_foreign_access(domid_t domid, gnttab_frame_t frame, int readonly)
256551bc2a6Smrj {
257551bc2a6Smrj 	int ref;
258551bc2a6Smrj 
259a576ab5bSrab 	if ((ref = get_free_entries(1)) == -1)
260551bc2a6Smrj 		return (-1);
261551bc2a6Smrj 
262551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
263551bc2a6Smrj 
264551bc2a6Smrj 	shared[ref].frame = frame;
265551bc2a6Smrj 	shared[ref].domid = domid;
266551bc2a6Smrj 	membar_producer();
267551bc2a6Smrj 	shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
268551bc2a6Smrj 
269551bc2a6Smrj 	return (ref);
270551bc2a6Smrj }
271551bc2a6Smrj 
272551bc2a6Smrj void
gnttab_grant_foreign_access_ref(grant_ref_t ref,domid_t domid,gnttab_frame_t frame,int readonly)273551bc2a6Smrj gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
274551bc2a6Smrj 				gnttab_frame_t frame, int readonly)
275551bc2a6Smrj {
276551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
277551bc2a6Smrj 
278551bc2a6Smrj 	shared[ref].frame = frame;
279551bc2a6Smrj 	shared[ref].domid = domid;
280551bc2a6Smrj 	membar_producer();
281551bc2a6Smrj 	shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
282551bc2a6Smrj }
283551bc2a6Smrj 
284551bc2a6Smrj 
285551bc2a6Smrj int
gnttab_query_foreign_access(grant_ref_t ref)286551bc2a6Smrj gnttab_query_foreign_access(grant_ref_t ref)
287551bc2a6Smrj {
288551bc2a6Smrj 	uint16_t nflags;
289551bc2a6Smrj 
290551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
291551bc2a6Smrj 
292551bc2a6Smrj 	nflags = shared[ref].flags;
293551bc2a6Smrj 
294551bc2a6Smrj 	return (nflags & (GTF_reading|GTF_writing));
295551bc2a6Smrj }
296551bc2a6Smrj 
297551bc2a6Smrj /* ARGSUSED */
298551bc2a6Smrj int
gnttab_end_foreign_access_ref(grant_ref_t ref,int readonly)299551bc2a6Smrj gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
300551bc2a6Smrj {
301551bc2a6Smrj 	uint16_t flags, nflags;
302551bc2a6Smrj 
303551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
304551bc2a6Smrj 
305551bc2a6Smrj 	nflags = shared[ref].flags;
306551bc2a6Smrj 	do {
307551bc2a6Smrj 		if ((flags = nflags) & (GTF_reading|GTF_writing)) {
308551bc2a6Smrj 			cmn_err(CE_WARN, "g.e. still in use!");
309551bc2a6Smrj 			return (0);
310551bc2a6Smrj 		}
311a576ab5bSrab 	} while ((nflags = CMPXCHG(&shared[ref].flags, flags, 0)) != flags);
312551bc2a6Smrj 
313551bc2a6Smrj 	return (1);
314551bc2a6Smrj }
315551bc2a6Smrj 
316551bc2a6Smrj void
gnttab_end_foreign_access(grant_ref_t ref,int readonly,gnttab_frame_t page)317551bc2a6Smrj gnttab_end_foreign_access(grant_ref_t ref, int readonly, gnttab_frame_t page)
318551bc2a6Smrj {
319551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
320551bc2a6Smrj 
321551bc2a6Smrj 	if (gnttab_end_foreign_access_ref(ref, readonly)) {
322551bc2a6Smrj 		put_free_entry(ref);
323551bc2a6Smrj 		/*
324551bc2a6Smrj 		 * XXPV - we don't support freeing a page here
325551bc2a6Smrj 		 */
326551bc2a6Smrj 		if (page != 0) {
327551bc2a6Smrj 			cmn_err(CE_WARN,
328551bc2a6Smrj 	"gnttab_end_foreign_access_ref: using unsupported free_page interface");
329551bc2a6Smrj 			/* free_page(page); */
330551bc2a6Smrj 		}
331551bc2a6Smrj 	} else {
332551bc2a6Smrj 		/*
333551bc2a6Smrj 		 * XXX This needs to be fixed so that the ref and page are
334551bc2a6Smrj 		 * placed on a list to be freed up later.
335551bc2a6Smrj 		 */
336551bc2a6Smrj 		cmn_err(CE_WARN, "leaking g.e. and page still in use!");
337551bc2a6Smrj 	}
338551bc2a6Smrj }
339551bc2a6Smrj 
340551bc2a6Smrj int
gnttab_grant_foreign_transfer(domid_t domid,pfn_t pfn)341a576ab5bSrab gnttab_grant_foreign_transfer(domid_t domid, pfn_t pfn)
342551bc2a6Smrj {
343551bc2a6Smrj 	int ref;
344551bc2a6Smrj 
345a576ab5bSrab 	if ((ref = get_free_entries(1)) == -1)
346551bc2a6Smrj 		return (-1);
347551bc2a6Smrj 
348551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
349551bc2a6Smrj 
350a576ab5bSrab 	gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
351551bc2a6Smrj 
352551bc2a6Smrj 	return (ref);
353551bc2a6Smrj }
354551bc2a6Smrj 
355551bc2a6Smrj void
gnttab_grant_foreign_transfer_ref(grant_ref_t ref,domid_t domid,pfn_t pfn)356a576ab5bSrab gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, pfn_t pfn)
357551bc2a6Smrj {
358551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
359551bc2a6Smrj 
360a576ab5bSrab 	shared[ref].frame = pfn;
361551bc2a6Smrj 	shared[ref].domid = domid;
362551bc2a6Smrj 	membar_producer();
363551bc2a6Smrj 	shared[ref].flags = GTF_accept_transfer;
364551bc2a6Smrj }
365551bc2a6Smrj 
366551bc2a6Smrj gnttab_frame_t
gnttab_end_foreign_transfer_ref(grant_ref_t ref)367551bc2a6Smrj gnttab_end_foreign_transfer_ref(grant_ref_t ref)
368551bc2a6Smrj {
369551bc2a6Smrj 	gnttab_frame_t frame;
370551bc2a6Smrj 	uint16_t flags;
371551bc2a6Smrj 
372551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
373551bc2a6Smrj 
374551bc2a6Smrj 	/*
375551bc2a6Smrj 	 * If a transfer is not even yet started, try to reclaim the grant
376551bc2a6Smrj 	 * reference and return failure (== 0).
377551bc2a6Smrj 	 */
378551bc2a6Smrj 	while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
379a576ab5bSrab 		if (CMPXCHG(&shared[ref].flags, flags, 0) == flags)
380551bc2a6Smrj 			return (0);
381551bc2a6Smrj 		(void) HYPERVISOR_yield();
382551bc2a6Smrj 	}
383551bc2a6Smrj 
384551bc2a6Smrj 	/* If a transfer is in progress then wait until it is completed. */
385551bc2a6Smrj 	while (!(flags & GTF_transfer_completed)) {
386551bc2a6Smrj 		flags = shared[ref].flags;
387551bc2a6Smrj 		(void) HYPERVISOR_yield();
388551bc2a6Smrj 	}
389551bc2a6Smrj 
390551bc2a6Smrj 	/* Read the frame number /after/ reading completion status. */
391551bc2a6Smrj 	membar_consumer();
392551bc2a6Smrj 	frame = shared[ref].frame;
393551bc2a6Smrj 	ASSERT(frame != 0);
394551bc2a6Smrj 
395551bc2a6Smrj 	return (frame);
396551bc2a6Smrj }
397551bc2a6Smrj 
398551bc2a6Smrj gnttab_frame_t
gnttab_end_foreign_transfer(grant_ref_t ref)399551bc2a6Smrj gnttab_end_foreign_transfer(grant_ref_t ref)
400551bc2a6Smrj {
401551bc2a6Smrj 	gnttab_frame_t frame;
402551bc2a6Smrj 
403551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
404551bc2a6Smrj 
405551bc2a6Smrj 	frame = gnttab_end_foreign_transfer_ref(ref);
406551bc2a6Smrj 	put_free_entry(ref);
407551bc2a6Smrj 	return (frame);
408551bc2a6Smrj }
409551bc2a6Smrj 
410551bc2a6Smrj void
gnttab_free_grant_reference(grant_ref_t ref)411551bc2a6Smrj gnttab_free_grant_reference(grant_ref_t ref)
412551bc2a6Smrj {
413551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(ref));
414551bc2a6Smrj 
415551bc2a6Smrj 	put_free_entry(ref);
416551bc2a6Smrj }
417551bc2a6Smrj 
418551bc2a6Smrj void
gnttab_free_grant_references(grant_ref_t head)419551bc2a6Smrj gnttab_free_grant_references(grant_ref_t head)
420551bc2a6Smrj {
421551bc2a6Smrj 	grant_ref_t ref;
422551bc2a6Smrj 	int count = 1;
423551bc2a6Smrj 
424551bc2a6Smrj 	if (head == GNTTAB_LIST_END)
425551bc2a6Smrj 		return;
426551bc2a6Smrj 	mutex_enter(&gnttab_list_lock);
427551bc2a6Smrj 	ref = head;
428a576ab5bSrab 	while (GNTTAB_ENTRY(ref) != GNTTAB_LIST_END) {
429a576ab5bSrab 		ref = GNTTAB_ENTRY(ref);
430551bc2a6Smrj 		count++;
431551bc2a6Smrj 	}
432a576ab5bSrab 	GNTTAB_ENTRY(ref) = gnttab_free_head;
433551bc2a6Smrj 	gnttab_free_head = head;
434551bc2a6Smrj 	gnttab_free_count += count;
435551bc2a6Smrj 	check_free_callbacks();
436551bc2a6Smrj 	mutex_exit(&gnttab_list_lock);
437551bc2a6Smrj }
438551bc2a6Smrj 
439551bc2a6Smrj int
gnttab_alloc_grant_references(uint16_t count,grant_ref_t * head)440551bc2a6Smrj gnttab_alloc_grant_references(uint16_t count, grant_ref_t *head)
441551bc2a6Smrj {
442551bc2a6Smrj 	int h = get_free_entries(count);
443551bc2a6Smrj 
444551bc2a6Smrj 	if (h == -1)
445551bc2a6Smrj 		return (-1);
446551bc2a6Smrj 
447551bc2a6Smrj 	*head = h;
448551bc2a6Smrj 
449551bc2a6Smrj 	return (0);
450551bc2a6Smrj }
451551bc2a6Smrj 
452551bc2a6Smrj int
gnttab_empty_grant_references(const grant_ref_t * private_head)453a576ab5bSrab gnttab_empty_grant_references(const grant_ref_t *private_head)
454a576ab5bSrab {
455a576ab5bSrab 	return (*private_head == GNTTAB_LIST_END);
456a576ab5bSrab }
457a576ab5bSrab 
458a576ab5bSrab int
gnttab_claim_grant_reference(grant_ref_t * private_head)459551bc2a6Smrj gnttab_claim_grant_reference(grant_ref_t *private_head)
460551bc2a6Smrj {
461551bc2a6Smrj 	grant_ref_t g = *private_head;
462551bc2a6Smrj 
463551bc2a6Smrj 	if (g == GNTTAB_LIST_END)
464551bc2a6Smrj 		return (-1);
465a576ab5bSrab 	*private_head = GNTTAB_ENTRY(g);
466551bc2a6Smrj 	return (g);
467551bc2a6Smrj }
468551bc2a6Smrj 
469551bc2a6Smrj void
gnttab_release_grant_reference(grant_ref_t * private_head,grant_ref_t release)470551bc2a6Smrj gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
471551bc2a6Smrj {
472551bc2a6Smrj 	ASSERT(VALID_GRANT_REF(release));
473551bc2a6Smrj 
474a576ab5bSrab 	GNTTAB_ENTRY(release) = *private_head;
475551bc2a6Smrj 	*private_head = release;
476551bc2a6Smrj }
477551bc2a6Smrj 
478551bc2a6Smrj void
gnttab_request_free_callback(struct gnttab_free_callback * callback,void (* fn)(void *),void * arg,uint16_t count)479551bc2a6Smrj gnttab_request_free_callback(struct gnttab_free_callback *callback,
480551bc2a6Smrj 	void (*fn)(void *), void *arg, uint16_t count)
481551bc2a6Smrj {
482551bc2a6Smrj 	mutex_enter(&gnttab_list_lock);
483551bc2a6Smrj 	if (callback->next)
484551bc2a6Smrj 		goto out;
485551bc2a6Smrj 	callback->fn = fn;
486551bc2a6Smrj 	callback->arg = arg;
487551bc2a6Smrj 	callback->count = count;
488551bc2a6Smrj 	callback->next = gnttab_free_callback_list;
489551bc2a6Smrj 	gnttab_free_callback_list = callback;
490551bc2a6Smrj 	check_free_callbacks();
491551bc2a6Smrj out:
492551bc2a6Smrj 	mutex_exit(&gnttab_list_lock);
493551bc2a6Smrj }
494551bc2a6Smrj 
495a576ab5bSrab void
gnttab_cancel_free_callback(struct gnttab_free_callback * callback)496a576ab5bSrab gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
497a576ab5bSrab {
498a576ab5bSrab 	struct gnttab_free_callback **pcb;
499551bc2a6Smrj 
500a576ab5bSrab 	mutex_enter(&gnttab_list_lock);
501a576ab5bSrab 	for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
502a576ab5bSrab 		if (*pcb == callback) {
503a576ab5bSrab 			*pcb = callback->next;
504a576ab5bSrab 			break;
505a576ab5bSrab 		}
506a576ab5bSrab 	}
507a576ab5bSrab 	mutex_exit(&gnttab_list_lock);
508a576ab5bSrab }
509a576ab5bSrab 
510a576ab5bSrab static gnttab_frame_t *
gnttab_setup(gnttab_setup_table_t * pset)511a576ab5bSrab gnttab_setup(gnttab_setup_table_t *pset)
512a576ab5bSrab {
513a576ab5bSrab 	gnttab_frame_t *frames;
514a576ab5bSrab 
515a576ab5bSrab 	frames = kmem_alloc(pset->nr_frames * sizeof (gnttab_frame_t),
516a576ab5bSrab 	    KM_SLEEP);
517a576ab5bSrab 
518a576ab5bSrab 	/*LINTED: constant in conditional context*/
519a576ab5bSrab 	set_xen_guest_handle(pset->frame_list, frames);
520a576ab5bSrab 
521*6eb35ee7Srab #ifndef XPV_HVM_DRIVER
522a576ab5bSrab 	/*
523a576ab5bSrab 	 * Take pset->nr_frames pages of grant table space from
524a576ab5bSrab 	 * the hypervisor and map it
525a576ab5bSrab 	 */
526a576ab5bSrab 	if ((HYPERVISOR_grant_table_op(GNTTABOP_setup_table, pset, 1) != 0) ||
527a576ab5bSrab 	    (pset->status != 0)) {
528a576ab5bSrab 		cmn_err(CE_PANIC, "Grant Table setup failed");
529a576ab5bSrab 	}
530*6eb35ee7Srab #endif
531a576ab5bSrab 
532a576ab5bSrab 	return (frames);
533a576ab5bSrab }
534a576ab5bSrab 
535a576ab5bSrab #ifdef XPV_HVM_DRIVER
536551bc2a6Smrj static void
gnttab_map(void)537551bc2a6Smrj gnttab_map(void)
538551bc2a6Smrj {
539551bc2a6Smrj 	struct xen_add_to_physmap xatp;
540551bc2a6Smrj 	caddr_t va;
541551bc2a6Smrj 	pfn_t pfn;
542551bc2a6Smrj 	int i;
543551bc2a6Smrj 
544551bc2a6Smrj 	va = (caddr_t)shared;
545a576ab5bSrab 	for (i = 0; i < max_nr_grant_frames(); i++) {
546a576ab5bSrab 		if ((pfn = hat_getpfnum(kas.a_hat, va)) == PFN_INVALID)
547a576ab5bSrab 			cmn_err(CE_PANIC, "gnttab_map: Invalid pfn");
548551bc2a6Smrj 
549551bc2a6Smrj 		xatp.domid = DOMID_SELF;
550551bc2a6Smrj 		xatp.idx = i;
551551bc2a6Smrj 		xatp.space = XENMAPSPACE_grant_table;
552551bc2a6Smrj 		xatp.gpfn = pfn;
553551bc2a6Smrj 		hat_unload(kas.a_hat, va, MMU_PAGESIZE, HAT_UNLOAD);
554a576ab5bSrab 		/*
555a576ab5bSrab 		 * This call replaces the existing machine page backing
556a576ab5bSrab 		 * the given gpfn with the page from the allocated grant
557a576ab5bSrab 		 * table at index idx. The existing machine page is
558a576ab5bSrab 		 * returned to the free list.
559a576ab5bSrab 		 */
560551bc2a6Smrj 		if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp) != 0)
561551bc2a6Smrj 			panic("Couldn't map grant table");
562551bc2a6Smrj 		hat_devload(kas.a_hat, va, MMU_PAGESIZE, pfn,
5635b1df0b5Sjohnlev 		    PROT_READ | PROT_WRITE | HAT_STORECACHING_OK,
564551bc2a6Smrj 		    HAT_LOAD | HAT_LOAD_LOCK | HAT_LOAD_NOCONSIST);
565551bc2a6Smrj 		va += MMU_PAGESIZE;
566551bc2a6Smrj 	}
567551bc2a6Smrj }
568a576ab5bSrab #endif /* XPV_HVM_DRIVER */
569551bc2a6Smrj 
570551bc2a6Smrj void
gnttab_init(void)571551bc2a6Smrj gnttab_init(void)
572551bc2a6Smrj {
573a576ab5bSrab 	gnttab_setup_table_t set;
574551bc2a6Smrj 	int i;
5751213c83cSgarypen 	uint_t nr_init_grefs, max_nr_glist_frames, nr_glist_frames;
576a576ab5bSrab 	gnttab_frame_t *frames;
577551bc2a6Smrj 
578a576ab5bSrab 	/*
579a576ab5bSrab 	 * gnttab_init() should only be invoked once.
580a576ab5bSrab 	 */
581a576ab5bSrab 	mutex_enter(&gnttab_list_lock);
582a576ab5bSrab 	ASSERT(nr_grant_frames == 0);
583a576ab5bSrab 	nr_grant_frames = 1;
584a576ab5bSrab 	mutex_exit(&gnttab_list_lock);
585a576ab5bSrab 
586a576ab5bSrab 	max_nr_glist_frames = (max_nr_grant_frames() *
5871213c83cSgarypen 	    GREFS_PER_GRANT_FRAME / RPP);
588a576ab5bSrab 
589a576ab5bSrab 	set.dom = DOMID_SELF;
590a576ab5bSrab 	set.nr_frames = max_nr_grant_frames();
591a576ab5bSrab 	frames = gnttab_setup(&set);
592a576ab5bSrab 
593a576ab5bSrab #ifdef XPV_HVM_DRIVER
594a576ab5bSrab 	shared = (grant_entry_t *)xen_alloc_pages(set.nr_frames);
595551bc2a6Smrj 
596551bc2a6Smrj 	gnttab_map();
597551bc2a6Smrj #else /* XPV_HVM_DRIVER */
598a576ab5bSrab 	shared = vmem_xalloc(heap_arena, set.nr_frames * MMU_PAGESIZE,
599a576ab5bSrab 	    MMU_PAGESIZE, 0, 0, 0, 0, VM_SLEEP);
600a576ab5bSrab 	for (i = 0; i < set.nr_frames; i++) {
601a576ab5bSrab 		hat_devload(kas.a_hat, (caddr_t)GT_PGADDR(i), PAGESIZE,
6025b1df0b5Sjohnlev 		    xen_assign_pfn(frames[i]),
6035b1df0b5Sjohnlev 		    PROT_READ | PROT_WRITE | HAT_STORECACHING_OK,
604a576ab5bSrab 		    HAT_LOAD_LOCK);
605a576ab5bSrab 	}
606a576ab5bSrab #endif
607551bc2a6Smrj 
608a576ab5bSrab 	gnttab_list = kmem_alloc(max_nr_glist_frames * sizeof (grant_ref_t *),
609a576ab5bSrab 	    KM_SLEEP);
610551bc2a6Smrj 
6111213c83cSgarypen 	nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1)
6121213c83cSgarypen 	    / RPP;
6131213c83cSgarypen 	for (i = 0; i < nr_glist_frames; i++) {
614a576ab5bSrab 		gnttab_list[i] = kmem_alloc(PAGESIZE, KM_SLEEP);
615551bc2a6Smrj 	}
616551bc2a6Smrj 
617a576ab5bSrab 	kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t));
618551bc2a6Smrj 
619a576ab5bSrab 	nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
620551bc2a6Smrj 
621a576ab5bSrab 	for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
622a576ab5bSrab 		GNTTAB_ENTRY(i) = i + 1;
623a576ab5bSrab 
624a576ab5bSrab 	GNTTAB_ENTRY(nr_init_grefs - 1) = GNTTAB_LIST_END;
625a576ab5bSrab 	gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
626551bc2a6Smrj 	gnttab_free_head  = NR_RESERVED_ENTRIES;
627551bc2a6Smrj }
628551bc2a6Smrj 
629551bc2a6Smrj void
gnttab_resume(void)630551bc2a6Smrj gnttab_resume(void)
631551bc2a6Smrj {
632551bc2a6Smrj 	gnttab_setup_table_t set;
633551bc2a6Smrj 	int i;
634a576ab5bSrab 	gnttab_frame_t *frames;
635a576ab5bSrab 	uint_t available_frames = max_nr_grant_frames();
636551bc2a6Smrj 
637a576ab5bSrab 	if (available_frames < nr_grant_frames) {
638a576ab5bSrab 		cmn_err(CE_PANIC, "Hypervisor does not have enough grant "
639a576ab5bSrab 		    "frames: required(%u), available(%u)", nr_grant_frames,
640a576ab5bSrab 		    available_frames);
641551bc2a6Smrj 	}
642551bc2a6Smrj 
643a576ab5bSrab #ifdef XPV_HVM_DRIVER
644a576ab5bSrab 	gnttab_map();
645a576ab5bSrab #endif /* XPV_HVM_DRIVER */
646a576ab5bSrab 
647a576ab5bSrab 	set.dom = DOMID_SELF;
648a576ab5bSrab 	set.nr_frames = available_frames;
649a576ab5bSrab 	frames = gnttab_setup(&set);
650a576ab5bSrab 
651a576ab5bSrab 	for (i = 0; i < available_frames; i++) {
652551bc2a6Smrj 		(void) HYPERVISOR_update_va_mapping(GT_PGADDR(i),
653551bc2a6Smrj 		    FRAME_TO_MA(frames[i]) | PT_VALID | PT_WRITABLE,
654551bc2a6Smrj 		    UVMF_INVLPG | UVMF_ALL);
655551bc2a6Smrj 	}
656a576ab5bSrab 	kmem_free(frames, set.nr_frames * sizeof (gnttab_frame_t));
657551bc2a6Smrj }
658551bc2a6Smrj 
659551bc2a6Smrj void
gnttab_suspend(void)660551bc2a6Smrj gnttab_suspend(void)
661551bc2a6Smrj {
662551bc2a6Smrj 	int i;
663551bc2a6Smrj 
664551bc2a6Smrj 	/*
665551bc2a6Smrj 	 * clear grant table mappings before suspending
666551bc2a6Smrj 	 */
667a576ab5bSrab 	for (i = 0; i < max_nr_grant_frames(); i++) {
668551bc2a6Smrj 		(void) HYPERVISOR_update_va_mapping(GT_PGADDR(i),
669551bc2a6Smrj 		    0, UVMF_INVLPG);
670551bc2a6Smrj 	}
671551bc2a6Smrj }
672551bc2a6Smrj 
673551bc2a6Smrj /*
674551bc2a6Smrj  * Local variables:
675551bc2a6Smrj  *  c-file-style: "solaris"
676551bc2a6Smrj  *  indent-tabs-mode: t
677551bc2a6Smrj  *  c-indent-level: 8
678551bc2a6Smrj  *  c-basic-offset: 8
679551bc2a6Smrj  *  tab-width: 8
680551bc2a6Smrj  * End:
681551bc2a6Smrj  */
682