ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/gnttab.c @ 9551:f6a7f2657ff3

Disable xen bus and grant tables when supervisor_mode_kernel is enabled.
Neither of these features are useful/available in this mode since only a
single domain is supported.

Do not attempt to initialise xen bus when supervisor_mode_kernel is
enabled.

Do not BUG_ON() failure to setup grant tables, future versions
of supervisor_mode_kernel may return -ENOSYS here.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
author Ian.Campbell@xensource.com
date Fri Mar 31 11:04:42 2006 +0100 (2006-03-31)
parents bd108ccc38a0
children d0d3fef37685
line source
1 /******************************************************************************
2 * gnttab.c
3 *
4 * Granting foreign access to our memory reservation.
5 *
6 * Copyright (c) 2005, Christopher Clark
7 * Copyright (c) 2004-2005, K A Fraser
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation; or, when distributed
12 * separately from the Linux kernel or incorporated into other
13 * software packages, subject to the following license:
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a copy
16 * of this source file (the "Software"), to deal in the Software without
17 * restriction, including without limitation the rights to use, copy, modify,
18 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19 * and to permit persons to whom the Software is furnished to do so, subject to
20 * the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31 * IN THE SOFTWARE.
32 */
34 #include <linux/config.h>
35 #include <linux/module.h>
36 #include <linux/sched.h>
37 #include <linux/mm.h>
38 #include <linux/vmalloc.h>
39 #include <asm/pgtable.h>
40 #include <xen/interface/xen.h>
41 #include <asm/fixmap.h>
42 #include <asm/uaccess.h>
43 #include <xen/gnttab.h>
44 #include <asm/synch_bitops.h>
46 #if 1
47 #define ASSERT(_p) \
48 if (!(_p)) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
49 #_p , __LINE__, __FILE__); *(int*)0=0; }
50 #else
51 #define ASSERT(_p) ((void)0)
52 #endif
54 #define WPRINTK(fmt, args...) \
55 printk(KERN_WARNING "xen_grant: " fmt, ##args)
58 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
59 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
60 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
61 EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
62 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
63 EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
64 EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
65 EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
66 EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
67 EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
68 EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
69 EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
70 EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
71 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
72 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
74 /* External tools reserve first few grant table entries. */
75 #define NR_RESERVED_ENTRIES 8
77 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
78 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
80 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
81 static int gnttab_free_count;
82 static grant_ref_t gnttab_free_head;
83 static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED;
85 static grant_entry_t *shared = NULL;
87 static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
89 static int
90 get_free_entries(int count)
91 {
92 unsigned long flags;
93 int ref;
94 grant_ref_t head;
95 spin_lock_irqsave(&gnttab_list_lock, flags);
96 if (gnttab_free_count < count) {
97 spin_unlock_irqrestore(&gnttab_list_lock, flags);
98 return -1;
99 }
100 ref = head = gnttab_free_head;
101 gnttab_free_count -= count;
102 while (count-- > 1)
103 head = gnttab_list[head];
104 gnttab_free_head = gnttab_list[head];
105 gnttab_list[head] = GNTTAB_LIST_END;
106 spin_unlock_irqrestore(&gnttab_list_lock, flags);
107 return ref;
108 }
110 #define get_free_entry() get_free_entries(1)
112 static void
113 do_free_callbacks(void)
114 {
115 struct gnttab_free_callback *callback, *next;
117 callback = gnttab_free_callback_list;
118 gnttab_free_callback_list = NULL;
120 while (callback != NULL) {
121 next = callback->next;
122 if (gnttab_free_count >= callback->count) {
123 callback->next = NULL;
124 callback->fn(callback->arg);
125 } else {
126 callback->next = gnttab_free_callback_list;
127 gnttab_free_callback_list = callback;
128 }
129 callback = next;
130 }
131 }
133 static inline void
134 check_free_callbacks(void)
135 {
136 if (unlikely(gnttab_free_callback_list))
137 do_free_callbacks();
138 }
140 static void
141 put_free_entry(grant_ref_t ref)
142 {
143 unsigned long flags;
144 spin_lock_irqsave(&gnttab_list_lock, flags);
145 gnttab_list[ref] = gnttab_free_head;
146 gnttab_free_head = ref;
147 gnttab_free_count++;
148 check_free_callbacks();
149 spin_unlock_irqrestore(&gnttab_list_lock, flags);
150 }
152 /*
153 * Public grant-issuing interface functions
154 */
156 int
157 gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly)
158 {
159 int ref;
161 if (unlikely((ref = get_free_entry()) == -1))
162 return -ENOSPC;
164 shared[ref].frame = frame;
165 shared[ref].domid = domid;
166 wmb();
167 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
169 return ref;
170 }
172 void
173 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
174 unsigned long frame, int readonly)
175 {
176 shared[ref].frame = frame;
177 shared[ref].domid = domid;
178 wmb();
179 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
180 }
183 int
184 gnttab_query_foreign_access(grant_ref_t ref)
185 {
186 u16 nflags;
188 nflags = shared[ref].flags;
190 return (nflags & (GTF_reading|GTF_writing));
191 }
193 int
194 gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
195 {
196 u16 flags, nflags;
198 nflags = shared[ref].flags;
199 do {
200 if ((flags = nflags) & (GTF_reading|GTF_writing)) {
201 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
202 return 0;
203 }
204 } while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) !=
205 flags);
207 return 1;
208 }
210 void
211 gnttab_end_foreign_access(grant_ref_t ref, int readonly, unsigned long page)
212 {
213 if (gnttab_end_foreign_access_ref(ref, readonly)) {
214 put_free_entry(ref);
215 if (page != 0) {
216 free_page(page);
217 }
218 } else {
219 /* XXX This needs to be fixed so that the ref and page are
220 placed on a list to be freed up later. */
221 printk(KERN_WARNING
222 "WARNING: leaking g.e. and page still in use!\n");
223 }
224 }
226 int
227 gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
228 {
229 int ref;
231 if (unlikely((ref = get_free_entry()) == -1))
232 return -ENOSPC;
233 gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
235 return ref;
236 }
238 void
239 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
240 unsigned long pfn)
241 {
242 shared[ref].frame = pfn;
243 shared[ref].domid = domid;
244 wmb();
245 shared[ref].flags = GTF_accept_transfer;
246 }
248 unsigned long
249 gnttab_end_foreign_transfer_ref(grant_ref_t ref)
250 {
251 unsigned long frame;
252 u16 flags;
254 /*
255 * If a transfer is not even yet started, try to reclaim the grant
256 * reference and return failure (== 0).
257 */
258 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
259 if (synch_cmpxchg(&shared[ref].flags, flags, 0) == flags)
260 return 0;
261 cpu_relax();
262 }
264 /* If a transfer is in progress then wait until it is completed. */
265 while (!(flags & GTF_transfer_completed)) {
266 flags = shared[ref].flags;
267 cpu_relax();
268 }
270 /* Read the frame number /after/ reading completion status. */
271 rmb();
272 frame = shared[ref].frame;
273 BUG_ON(frame == 0);
275 return frame;
276 }
278 unsigned long
279 gnttab_end_foreign_transfer(grant_ref_t ref)
280 {
281 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
282 put_free_entry(ref);
283 return frame;
284 }
286 void
287 gnttab_free_grant_reference(grant_ref_t ref)
288 {
290 put_free_entry(ref);
291 }
293 void
294 gnttab_free_grant_references(grant_ref_t head)
295 {
296 grant_ref_t ref;
297 unsigned long flags;
298 int count = 1;
299 if (head == GNTTAB_LIST_END)
300 return;
301 spin_lock_irqsave(&gnttab_list_lock, flags);
302 ref = head;
303 while (gnttab_list[ref] != GNTTAB_LIST_END) {
304 ref = gnttab_list[ref];
305 count++;
306 }
307 gnttab_list[ref] = gnttab_free_head;
308 gnttab_free_head = head;
309 gnttab_free_count += count;
310 check_free_callbacks();
311 spin_unlock_irqrestore(&gnttab_list_lock, flags);
312 }
314 int
315 gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
316 {
317 int h = get_free_entries(count);
319 if (h == -1)
320 return -ENOSPC;
322 *head = h;
324 return 0;
325 }
327 int
328 gnttab_claim_grant_reference(grant_ref_t *private_head)
329 {
330 grant_ref_t g = *private_head;
331 if (unlikely(g == GNTTAB_LIST_END))
332 return -ENOSPC;
333 *private_head = gnttab_list[g];
334 return g;
335 }
337 void
338 gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
339 {
340 gnttab_list[release] = *private_head;
341 *private_head = release;
342 }
344 void
345 gnttab_request_free_callback(struct gnttab_free_callback *callback,
346 void (*fn)(void *), void *arg, u16 count)
347 {
348 unsigned long flags;
349 spin_lock_irqsave(&gnttab_list_lock, flags);
350 if (callback->next)
351 goto out;
352 callback->fn = fn;
353 callback->arg = arg;
354 callback->count = count;
355 callback->next = gnttab_free_callback_list;
356 gnttab_free_callback_list = callback;
357 check_free_callbacks();
358 out:
359 spin_unlock_irqrestore(&gnttab_list_lock, flags);
360 }
362 #ifndef __ia64__
363 static int map_pte_fn(pte_t *pte, struct page *pmd_page,
364 unsigned long addr, void *data)
365 {
366 unsigned long **frames = (unsigned long **)data;
368 set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
369 (*frames)++;
370 return 0;
371 }
373 static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
374 unsigned long addr, void *data)
375 {
377 set_pte_at(&init_mm, addr, pte, __pte(0));
378 return 0;
379 }
380 #endif
382 int
383 gnttab_resume(void)
384 {
385 gnttab_setup_table_t setup;
386 unsigned long frames[NR_GRANT_FRAMES];
387 int rc;
388 #ifndef __ia64__
389 void *pframes = frames;
390 struct vm_struct *area;
391 #endif
393 setup.dom = DOMID_SELF;
394 setup.nr_frames = NR_GRANT_FRAMES;
395 setup.frame_list = frames;
397 rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
398 if (rc < 0)
399 return rc;
401 BUG_ON(setup.status);
403 #ifndef __ia64__
404 if (shared == NULL) {
405 area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
406 BUG_ON(area == NULL);
407 shared = area->addr;
408 }
409 rc = apply_to_page_range(&init_mm, (unsigned long)shared,
410 PAGE_SIZE * NR_GRANT_FRAMES,
411 map_pte_fn, &pframes);
412 BUG_ON(rc);
413 #else
414 shared = __va(frames[0] << PAGE_SHIFT);
415 printk("grant table at %p\n", shared);
416 #endif
418 return 0;
419 }
421 int
422 gnttab_suspend(void)
423 {
425 #ifndef __ia64__
426 apply_to_page_range(&init_mm, (unsigned long)shared,
427 PAGE_SIZE * NR_GRANT_FRAMES,
428 unmap_pte_fn, NULL);
429 #endif
431 return 0;
432 }
434 static int __init
435 gnttab_init(void)
436 {
437 int i;
439 if (xen_init() < 0)
440 return -ENODEV;
442 if (gnttab_resume() < 0)
443 return -ENODEV;
445 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
446 gnttab_list[i] = i + 1;
447 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
448 gnttab_free_head = NR_RESERVED_ENTRIES;
450 printk("Grant table initialized\n");
451 return 0;
452 }
454 core_initcall(gnttab_init);
456 /*
457 * Local variables:
458 * c-file-style: "linux"
459 * indent-tabs-mode: t
460 * c-indent-level: 8
461 * c-basic-offset: 8
462 * tab-width: 8
463 * End:
464 */