ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/core/gnttab.c @ 9222:c5286130a96e

Map grant table pages in vmalloc kernel address space instead of fixmap.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Fri Mar 10 13:27:24 2006 +0000 (2006-03-10)
parents e9daf5307296
children a07e25890329
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 file may be distributed separately from the Linux kernel, or
10 * incorporated into other software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
31 #include <linux/config.h>
32 #include <linux/module.h>
33 #include <linux/sched.h>
34 #include <linux/mm.h>
35 #include <linux/vmalloc.h>
36 #include <asm/pgtable.h>
37 #include <xen/interface/xen.h>
38 #include <asm/fixmap.h>
39 #include <asm/uaccess.h>
40 #include <xen/gnttab.h>
41 #include <asm/synch_bitops.h>
43 #if 1
44 #define ASSERT(_p) \
45 if (!(_p)) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
46 #_p , __LINE__, __FILE__); *(int*)0=0; }
47 #else
48 #define ASSERT(_p) ((void)0)
49 #endif
51 #define WPRINTK(fmt, args...) \
52 printk(KERN_WARNING "xen_grant: " fmt, ##args)
55 EXPORT_SYMBOL(gnttab_grant_foreign_access);
56 EXPORT_SYMBOL(gnttab_end_foreign_access_ref);
57 EXPORT_SYMBOL(gnttab_end_foreign_access);
58 EXPORT_SYMBOL(gnttab_query_foreign_access);
59 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
60 EXPORT_SYMBOL(gnttab_end_foreign_transfer_ref);
61 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
62 EXPORT_SYMBOL(gnttab_alloc_grant_references);
63 EXPORT_SYMBOL(gnttab_free_grant_references);
64 EXPORT_SYMBOL(gnttab_free_grant_reference);
65 EXPORT_SYMBOL(gnttab_claim_grant_reference);
66 EXPORT_SYMBOL(gnttab_release_grant_reference);
67 EXPORT_SYMBOL(gnttab_request_free_callback);
68 EXPORT_SYMBOL(gnttab_grant_foreign_access_ref);
69 EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref);
71 /* External tools reserve first few grant table entries. */
72 #define NR_RESERVED_ENTRIES 8
74 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
75 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
77 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
78 static int gnttab_free_count;
79 static grant_ref_t gnttab_free_head;
80 static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED;
82 static grant_entry_t *shared = NULL;
84 static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
86 static int
87 get_free_entries(int count)
88 {
89 unsigned long flags;
90 int ref;
91 grant_ref_t head;
92 spin_lock_irqsave(&gnttab_list_lock, flags);
93 if (gnttab_free_count < count) {
94 spin_unlock_irqrestore(&gnttab_list_lock, flags);
95 return -1;
96 }
97 ref = head = gnttab_free_head;
98 gnttab_free_count -= count;
99 while (count-- > 1)
100 head = gnttab_list[head];
101 gnttab_free_head = gnttab_list[head];
102 gnttab_list[head] = GNTTAB_LIST_END;
103 spin_unlock_irqrestore(&gnttab_list_lock, flags);
104 return ref;
105 }
107 #define get_free_entry() get_free_entries(1)
109 static void
110 do_free_callbacks(void)
111 {
112 struct gnttab_free_callback *callback, *next;
114 callback = gnttab_free_callback_list;
115 gnttab_free_callback_list = NULL;
117 while (callback != NULL) {
118 next = callback->next;
119 if (gnttab_free_count >= callback->count) {
120 callback->next = NULL;
121 callback->fn(callback->arg);
122 } else {
123 callback->next = gnttab_free_callback_list;
124 gnttab_free_callback_list = callback;
125 }
126 callback = next;
127 }
128 }
130 static inline void
131 check_free_callbacks(void)
132 {
133 if (unlikely(gnttab_free_callback_list))
134 do_free_callbacks();
135 }
137 static void
138 put_free_entry(grant_ref_t ref)
139 {
140 unsigned long flags;
141 spin_lock_irqsave(&gnttab_list_lock, flags);
142 gnttab_list[ref] = gnttab_free_head;
143 gnttab_free_head = ref;
144 gnttab_free_count++;
145 check_free_callbacks();
146 spin_unlock_irqrestore(&gnttab_list_lock, flags);
147 }
149 /*
150 * Public grant-issuing interface functions
151 */
153 int
154 gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly)
155 {
156 int ref;
158 if (unlikely((ref = get_free_entry()) == -1))
159 return -ENOSPC;
161 shared[ref].frame = frame;
162 shared[ref].domid = domid;
163 wmb();
164 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
166 return ref;
167 }
169 void
170 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
171 unsigned long frame, int readonly)
172 {
173 shared[ref].frame = frame;
174 shared[ref].domid = domid;
175 wmb();
176 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
177 }
180 int
181 gnttab_query_foreign_access(grant_ref_t ref)
182 {
183 u16 nflags;
185 nflags = shared[ref].flags;
187 return (nflags & (GTF_reading|GTF_writing));
188 }
190 int
191 gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
192 {
193 u16 flags, nflags;
195 nflags = shared[ref].flags;
196 do {
197 if ((flags = nflags) & (GTF_reading|GTF_writing)) {
198 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
199 return 0;
200 }
201 } while ((nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) !=
202 flags);
204 return 1;
205 }
207 void
208 gnttab_end_foreign_access(grant_ref_t ref, int readonly, unsigned long page)
209 {
210 if (gnttab_end_foreign_access_ref(ref, readonly)) {
211 put_free_entry(ref);
212 if (page != 0) {
213 free_page(page);
214 }
215 } else {
216 /* XXX This needs to be fixed so that the ref and page are
217 placed on a list to be freed up later. */
218 printk(KERN_WARNING
219 "WARNING: leaking g.e. and page still in use!\n");
220 }
221 }
223 int
224 gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
225 {
226 int ref;
228 if (unlikely((ref = get_free_entry()) == -1))
229 return -ENOSPC;
230 gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
232 return ref;
233 }
235 void
236 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
237 unsigned long pfn)
238 {
239 shared[ref].frame = pfn;
240 shared[ref].domid = domid;
241 wmb();
242 shared[ref].flags = GTF_accept_transfer;
243 }
245 unsigned long
246 gnttab_end_foreign_transfer_ref(grant_ref_t ref)
247 {
248 unsigned long frame;
249 u16 flags;
251 /*
252 * If a transfer is not even yet started, try to reclaim the grant
253 * reference and return failure (== 0).
254 */
255 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
256 if (synch_cmpxchg(&shared[ref].flags, flags, 0) == flags)
257 return 0;
258 cpu_relax();
259 }
261 /* If a transfer is in progress then wait until it is completed. */
262 while (!(flags & GTF_transfer_completed)) {
263 flags = shared[ref].flags;
264 cpu_relax();
265 }
267 /* Read the frame number /after/ reading completion status. */
268 rmb();
269 frame = shared[ref].frame;
270 BUG_ON(frame == 0);
272 return frame;
273 }
275 unsigned long
276 gnttab_end_foreign_transfer(grant_ref_t ref)
277 {
278 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
279 put_free_entry(ref);
280 return frame;
281 }
283 void
284 gnttab_free_grant_reference(grant_ref_t ref)
285 {
287 put_free_entry(ref);
288 }
290 void
291 gnttab_free_grant_references(grant_ref_t head)
292 {
293 grant_ref_t ref;
294 unsigned long flags;
295 int count = 1;
296 if (head == GNTTAB_LIST_END)
297 return;
298 spin_lock_irqsave(&gnttab_list_lock, flags);
299 ref = head;
300 while (gnttab_list[ref] != GNTTAB_LIST_END) {
301 ref = gnttab_list[ref];
302 count++;
303 }
304 gnttab_list[ref] = gnttab_free_head;
305 gnttab_free_head = head;
306 gnttab_free_count += count;
307 check_free_callbacks();
308 spin_unlock_irqrestore(&gnttab_list_lock, flags);
309 }
311 int
312 gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
313 {
314 int h = get_free_entries(count);
316 if (h == -1)
317 return -ENOSPC;
319 *head = h;
321 return 0;
322 }
324 int
325 gnttab_claim_grant_reference(grant_ref_t *private_head)
326 {
327 grant_ref_t g = *private_head;
328 if (unlikely(g == GNTTAB_LIST_END))
329 return -ENOSPC;
330 *private_head = gnttab_list[g];
331 return g;
332 }
334 void
335 gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
336 {
337 gnttab_list[release] = *private_head;
338 *private_head = release;
339 }
341 void
342 gnttab_request_free_callback(struct gnttab_free_callback *callback,
343 void (*fn)(void *), void *arg, u16 count)
344 {
345 unsigned long flags;
346 spin_lock_irqsave(&gnttab_list_lock, flags);
347 if (callback->next)
348 goto out;
349 callback->fn = fn;
350 callback->arg = arg;
351 callback->count = count;
352 callback->next = gnttab_free_callback_list;
353 gnttab_free_callback_list = callback;
354 check_free_callbacks();
355 out:
356 spin_unlock_irqrestore(&gnttab_list_lock, flags);
357 }
359 #ifndef __ia64__
360 static int map_pte_fn(pte_t *pte, struct page *pte_page,
361 unsigned long addr, void *data)
362 {
363 unsigned long **frames = (unsigned long **)data;
365 set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
366 (*frames)++;
367 return 0;
368 }
370 static int unmap_pte_fn(pte_t *pte, struct page *pte_page,
371 unsigned long addr, void *data)
372 {
374 set_pte_at(&init_mm, addr, pte, __pte(0));
375 return 0;
376 }
377 #endif
379 int
380 gnttab_resume(void)
381 {
382 gnttab_setup_table_t setup;
383 unsigned long frames[NR_GRANT_FRAMES];
384 #ifndef __ia64__
385 void *pframes = frames;
386 struct vm_struct *area;
387 #endif
389 setup.dom = DOMID_SELF;
390 setup.nr_frames = NR_GRANT_FRAMES;
391 setup.frame_list = frames;
393 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1));
394 BUG_ON(setup.status != 0);
396 #ifndef __ia64__
397 if (shared == NULL) {
398 area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
399 BUG_ON(area == NULL);
400 shared = area->addr;
401 }
402 BUG_ON(generic_page_range(&init_mm, (unsigned long)shared,
403 PAGE_SIZE * NR_GRANT_FRAMES,
404 map_pte_fn, &pframes));
405 #else
406 shared = __va(frames[0] << PAGE_SHIFT);
407 printk("grant table at %p\n", shared);
408 #endif
410 return 0;
411 }
413 int
414 gnttab_suspend(void)
415 {
417 #ifndef __ia64__
418 generic_page_range(&init_mm, (unsigned long)shared,
419 PAGE_SIZE * NR_GRANT_FRAMES,
420 unmap_pte_fn, NULL);
421 #endif
423 return 0;
424 }
426 static int __init
427 gnttab_init(void)
428 {
429 int i;
431 if (xen_init() < 0)
432 return -ENODEV;
434 BUG_ON(gnttab_resume());
436 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
437 gnttab_list[i] = i + 1;
438 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
439 gnttab_free_head = NR_RESERVED_ENTRIES;
441 printk("Grant table initialized\n");
442 return 0;
443 }
445 core_initcall(gnttab_init);
447 /*
448 * Local variables:
449 * c-file-style: "linux"
450 * indent-tabs-mode: t
451 * c-indent-level: 8
452 * c-basic-offset: 8
453 * tab-width: 8
454 * End:
455 */