diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 13:09:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 13:09:59 -0500 |
commit | 90160371b3a3e67ef78d68210a94dd30664a703d (patch) | |
tree | 2841ea811be129133cf9b83d9c3badd96e7ffab4 /drivers/xen/grant-table.c | |
parent | ae5cfc0546ca2698b9dcddf72accbd70e57590a0 (diff) | |
parent | 6c254de16a1d14c1ac931d3aa08dc88ac9fc582b (diff) |
Merge branch 'stable/for-linus-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
* 'stable/for-linus-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: (37 commits)
xen/pciback: Expand the warning message to include domain id.
xen/pciback: Fix "device has been assigned to X domain!" warning
xen/pciback: Move the PCI_DEV_FLAGS_ASSIGNED ops to the "[un|]bind"
xen/xenbus: don't reimplement kvasprintf via a fixed size buffer
xenbus: maximum buffer size is XENSTORE_PAYLOAD_MAX
xen/xenbus: Reject replies with payload > XENSTORE_PAYLOAD_MAX.
Xen: consolidate and simplify struct xenbus_driver instantiation
xen-gntalloc: introduce missing kfree
xen/xenbus: Fix compile error - missing header for xen_initial_domain()
xen/netback: Enable netback on HVM guests
xen/grant-table: Support mappings required by blkback
xenbus: Use grant-table wrapper functions
xenbus: Support HVM backends
xen/xenbus-frontend: Fix compile error with randconfig
xen/xenbus-frontend: Make error message more clear
xen/privcmd: Remove unused support for arch specific privcmp mmap
xen: Add xenbus_backend device
xen: Add xenbus device driver
xen: Add privcmd device driver
xen/gntalloc: fix reference counts on multi-page mappings
...
Diffstat (limited to 'drivers/xen/grant-table.c')
-rw-r--r-- | drivers/xen/grant-table.c | 518 |
1 files changed, 457 insertions, 61 deletions
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index bf1c094f4ebf..1cd94daa71db 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -44,16 +44,19 @@ | |||
44 | #include <xen/page.h> | 44 | #include <xen/page.h> |
45 | #include <xen/grant_table.h> | 45 | #include <xen/grant_table.h> |
46 | #include <xen/interface/memory.h> | 46 | #include <xen/interface/memory.h> |
47 | #include <xen/hvc-console.h> | ||
47 | #include <asm/xen/hypercall.h> | 48 | #include <asm/xen/hypercall.h> |
48 | 49 | ||
49 | #include <asm/pgtable.h> | 50 | #include <asm/pgtable.h> |
50 | #include <asm/sync_bitops.h> | 51 | #include <asm/sync_bitops.h> |
51 | 52 | ||
52 | |||
53 | /* External tools reserve first few grant table entries. */ | 53 | /* External tools reserve first few grant table entries. */ |
54 | #define NR_RESERVED_ENTRIES 8 | 54 | #define NR_RESERVED_ENTRIES 8 |
55 | #define GNTTAB_LIST_END 0xffffffff | 55 | #define GNTTAB_LIST_END 0xffffffff |
56 | #define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry)) | 56 | #define GREFS_PER_GRANT_FRAME \ |
57 | (grant_table_version == 1 ? \ | ||
58 | (PAGE_SIZE / sizeof(struct grant_entry_v1)) : \ | ||
59 | (PAGE_SIZE / sizeof(union grant_entry_v2))) | ||
57 | 60 | ||
58 | static grant_ref_t **gnttab_list; | 61 | static grant_ref_t **gnttab_list; |
59 | static unsigned int nr_grant_frames; | 62 | static unsigned int nr_grant_frames; |
@@ -64,13 +67,97 @@ static DEFINE_SPINLOCK(gnttab_list_lock); | |||
64 | unsigned long xen_hvm_resume_frames; | 67 | unsigned long xen_hvm_resume_frames; |
65 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); | 68 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); |
66 | 69 | ||
67 | static struct grant_entry *shared; | 70 | static union { |
71 | struct grant_entry_v1 *v1; | ||
72 | union grant_entry_v2 *v2; | ||
73 | void *addr; | ||
74 | } gnttab_shared; | ||
75 | |||
76 | /*This is a structure of function pointers for grant table*/ | ||
77 | struct gnttab_ops { | ||
78 | /* | ||
79 | * Mapping a list of frames for storing grant entries. Frames parameter | ||
80 | * is used to store grant table address when grant table being setup, | ||
81 | * nr_gframes is the number of frames to map grant table. Returning | ||
82 | * GNTST_okay means success and negative value means failure. | ||
83 | */ | ||
84 | int (*map_frames)(unsigned long *frames, unsigned int nr_gframes); | ||
85 | /* | ||
86 | * Release a list of frames which are mapped in map_frames for grant | ||
87 | * entry status. | ||
88 | */ | ||
89 | void (*unmap_frames)(void); | ||
90 | /* | ||
91 | * Introducing a valid entry into the grant table, granting the frame of | ||
92 | * this grant entry to domain for accessing or transfering. Ref | ||
93 | * parameter is reference of this introduced grant entry, domid is id of | ||
94 | * granted domain, frame is the page frame to be granted, and flags is | ||
95 | * status of the grant entry to be updated. | ||
96 | */ | ||
97 | void (*update_entry)(grant_ref_t ref, domid_t domid, | ||
98 | unsigned long frame, unsigned flags); | ||
99 | /* | ||
100 | * Stop granting a grant entry to domain for accessing. Ref parameter is | ||
101 | * reference of a grant entry whose grant access will be stopped, | ||
102 | * readonly is not in use in this function. If the grant entry is | ||
103 | * currently mapped for reading or writing, just return failure(==0) | ||
104 | * directly and don't tear down the grant access. Otherwise, stop grant | ||
105 | * access for this entry and return success(==1). | ||
106 | */ | ||
107 | int (*end_foreign_access_ref)(grant_ref_t ref, int readonly); | ||
108 | /* | ||
109 | * Stop granting a grant entry to domain for transfer. Ref parameter is | ||
110 | * reference of a grant entry whose grant transfer will be stopped. If | ||
111 | * tranfer has not started, just reclaim the grant entry and return | ||
112 | * failure(==0). Otherwise, wait for the transfer to complete and then | ||
113 | * return the frame. | ||
114 | */ | ||
115 | unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref); | ||
116 | /* | ||
117 | * Query the status of a grant entry. Ref parameter is reference of | ||
118 | * queried grant entry, return value is the status of queried entry. | ||
119 | * Detailed status(writing/reading) can be gotten from the return value | ||
120 | * by bit operations. | ||
121 | */ | ||
122 | int (*query_foreign_access)(grant_ref_t ref); | ||
123 | /* | ||
124 | * Grant a domain to access a range of bytes within the page referred by | ||
125 | * an available grant entry. Ref parameter is reference of a grant entry | ||
126 | * which will be sub-page accessed, domid is id of grantee domain, frame | ||
127 | * is frame address of subpage grant, flags is grant type and flag | ||
128 | * information, page_off is offset of the range of bytes, and length is | ||
129 | * length of bytes to be accessed. | ||
130 | */ | ||
131 | void (*update_subpage_entry)(grant_ref_t ref, domid_t domid, | ||
132 | unsigned long frame, int flags, | ||
133 | unsigned page_off, unsigned length); | ||
134 | /* | ||
135 | * Redirect an available grant entry on domain A to another grant | ||
136 | * reference of domain B, then allow domain C to use grant reference | ||
137 | * of domain B transitively. Ref parameter is an available grant entry | ||
138 | * reference on domain A, domid is id of domain C which accesses grant | ||
139 | * entry transitively, flags is grant type and flag information, | ||
140 | * trans_domid is id of domain B whose grant entry is finally accessed | ||
141 | * transitively, trans_gref is grant entry transitive reference of | ||
142 | * domain B. | ||
143 | */ | ||
144 | void (*update_trans_entry)(grant_ref_t ref, domid_t domid, int flags, | ||
145 | domid_t trans_domid, grant_ref_t trans_gref); | ||
146 | }; | ||
147 | |||
148 | static struct gnttab_ops *gnttab_interface; | ||
149 | |||
150 | /*This reflects status of grant entries, so act as a global value*/ | ||
151 | static grant_status_t *grstatus; | ||
152 | |||
153 | static int grant_table_version; | ||
68 | 154 | ||
69 | static struct gnttab_free_callback *gnttab_free_callback_list; | 155 | static struct gnttab_free_callback *gnttab_free_callback_list; |
70 | 156 | ||
71 | static int gnttab_expand(unsigned int req_entries); | 157 | static int gnttab_expand(unsigned int req_entries); |
72 | 158 | ||
73 | #define RPP (PAGE_SIZE / sizeof(grant_ref_t)) | 159 | #define RPP (PAGE_SIZE / sizeof(grant_ref_t)) |
160 | #define SPP (PAGE_SIZE / sizeof(grant_status_t)) | ||
74 | 161 | ||
75 | static inline grant_ref_t *__gnttab_entry(grant_ref_t entry) | 162 | static inline grant_ref_t *__gnttab_entry(grant_ref_t entry) |
76 | { | 163 | { |
@@ -142,23 +229,33 @@ static void put_free_entry(grant_ref_t ref) | |||
142 | spin_unlock_irqrestore(&gnttab_list_lock, flags); | 229 | spin_unlock_irqrestore(&gnttab_list_lock, flags); |
143 | } | 230 | } |
144 | 231 | ||
145 | static void update_grant_entry(grant_ref_t ref, domid_t domid, | 232 | /* |
146 | unsigned long frame, unsigned flags) | 233 | * Following applies to gnttab_update_entry_v1 and gnttab_update_entry_v2. |
234 | * Introducing a valid entry into the grant table: | ||
235 | * 1. Write ent->domid. | ||
236 | * 2. Write ent->frame: | ||
237 | * GTF_permit_access: Frame to which access is permitted. | ||
238 | * GTF_accept_transfer: Pseudo-phys frame slot being filled by new | ||
239 | * frame, or zero if none. | ||
240 | * 3. Write memory barrier (WMB). | ||
241 | * 4. Write ent->flags, inc. valid type. | ||
242 | */ | ||
243 | static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid, | ||
244 | unsigned long frame, unsigned flags) | ||
245 | { | ||
246 | gnttab_shared.v1[ref].domid = domid; | ||
247 | gnttab_shared.v1[ref].frame = frame; | ||
248 | wmb(); | ||
249 | gnttab_shared.v1[ref].flags = flags; | ||
250 | } | ||
251 | |||
252 | static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid, | ||
253 | unsigned long frame, unsigned flags) | ||
147 | { | 254 | { |
148 | /* | 255 | gnttab_shared.v2[ref].hdr.domid = domid; |
149 | * Introducing a valid entry into the grant table: | 256 | gnttab_shared.v2[ref].full_page.frame = frame; |
150 | * 1. Write ent->domid. | ||
151 | * 2. Write ent->frame: | ||
152 | * GTF_permit_access: Frame to which access is permitted. | ||
153 | * GTF_accept_transfer: Pseudo-phys frame slot being filled by new | ||
154 | * frame, or zero if none. | ||
155 | * 3. Write memory barrier (WMB). | ||
156 | * 4. Write ent->flags, inc. valid type. | ||
157 | */ | ||
158 | shared[ref].frame = frame; | ||
159 | shared[ref].domid = domid; | ||
160 | wmb(); | 257 | wmb(); |
161 | shared[ref].flags = flags; | 258 | gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags; |
162 | } | 259 | } |
163 | 260 | ||
164 | /* | 261 | /* |
@@ -167,7 +264,7 @@ static void update_grant_entry(grant_ref_t ref, domid_t domid, | |||
167 | void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, | 264 | void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, |
168 | unsigned long frame, int readonly) | 265 | unsigned long frame, int readonly) |
169 | { | 266 | { |
170 | update_grant_entry(ref, domid, frame, | 267 | gnttab_interface->update_entry(ref, domid, frame, |
171 | GTF_permit_access | (readonly ? GTF_readonly : 0)); | 268 | GTF_permit_access | (readonly ? GTF_readonly : 0)); |
172 | } | 269 | } |
173 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); | 270 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); |
@@ -187,31 +284,184 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, | |||
187 | } | 284 | } |
188 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); | 285 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); |
189 | 286 | ||
190 | int gnttab_query_foreign_access(grant_ref_t ref) | 287 | void gnttab_update_subpage_entry_v2(grant_ref_t ref, domid_t domid, |
288 | unsigned long frame, int flags, | ||
289 | unsigned page_off, | ||
290 | unsigned length) | ||
291 | { | ||
292 | gnttab_shared.v2[ref].sub_page.frame = frame; | ||
293 | gnttab_shared.v2[ref].sub_page.page_off = page_off; | ||
294 | gnttab_shared.v2[ref].sub_page.length = length; | ||
295 | gnttab_shared.v2[ref].hdr.domid = domid; | ||
296 | wmb(); | ||
297 | gnttab_shared.v2[ref].hdr.flags = | ||
298 | GTF_permit_access | GTF_sub_page | flags; | ||
299 | } | ||
300 | |||
301 | int gnttab_grant_foreign_access_subpage_ref(grant_ref_t ref, domid_t domid, | ||
302 | unsigned long frame, int flags, | ||
303 | unsigned page_off, | ||
304 | unsigned length) | ||
191 | { | 305 | { |
192 | u16 nflags; | 306 | if (flags & (GTF_accept_transfer | GTF_reading | |
307 | GTF_writing | GTF_transitive)) | ||
308 | return -EPERM; | ||
193 | 309 | ||
194 | nflags = shared[ref].flags; | 310 | if (gnttab_interface->update_subpage_entry == NULL) |
311 | return -ENOSYS; | ||
195 | 312 | ||
196 | return nflags & (GTF_reading|GTF_writing); | 313 | gnttab_interface->update_subpage_entry(ref, domid, frame, flags, |
314 | page_off, length); | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage_ref); | ||
319 | |||
320 | int gnttab_grant_foreign_access_subpage(domid_t domid, unsigned long frame, | ||
321 | int flags, unsigned page_off, | ||
322 | unsigned length) | ||
323 | { | ||
324 | int ref, rc; | ||
325 | |||
326 | ref = get_free_entries(1); | ||
327 | if (unlikely(ref < 0)) | ||
328 | return -ENOSPC; | ||
329 | |||
330 | rc = gnttab_grant_foreign_access_subpage_ref(ref, domid, frame, flags, | ||
331 | page_off, length); | ||
332 | if (rc < 0) { | ||
333 | put_free_entry(ref); | ||
334 | return rc; | ||
335 | } | ||
336 | |||
337 | return ref; | ||
338 | } | ||
339 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage); | ||
340 | |||
341 | bool gnttab_subpage_grants_available(void) | ||
342 | { | ||
343 | return gnttab_interface->update_subpage_entry != NULL; | ||
344 | } | ||
345 | EXPORT_SYMBOL_GPL(gnttab_subpage_grants_available); | ||
346 | |||
347 | void gnttab_update_trans_entry_v2(grant_ref_t ref, domid_t domid, | ||
348 | int flags, domid_t trans_domid, | ||
349 | grant_ref_t trans_gref) | ||
350 | { | ||
351 | gnttab_shared.v2[ref].transitive.trans_domid = trans_domid; | ||
352 | gnttab_shared.v2[ref].transitive.gref = trans_gref; | ||
353 | gnttab_shared.v2[ref].hdr.domid = domid; | ||
354 | wmb(); | ||
355 | gnttab_shared.v2[ref].hdr.flags = | ||
356 | GTF_permit_access | GTF_transitive | flags; | ||
357 | } | ||
358 | |||
359 | int gnttab_grant_foreign_access_trans_ref(grant_ref_t ref, domid_t domid, | ||
360 | int flags, domid_t trans_domid, | ||
361 | grant_ref_t trans_gref) | ||
362 | { | ||
363 | if (flags & (GTF_accept_transfer | GTF_reading | | ||
364 | GTF_writing | GTF_sub_page)) | ||
365 | return -EPERM; | ||
366 | |||
367 | if (gnttab_interface->update_trans_entry == NULL) | ||
368 | return -ENOSYS; | ||
369 | |||
370 | gnttab_interface->update_trans_entry(ref, domid, flags, trans_domid, | ||
371 | trans_gref); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans_ref); | ||
376 | |||
377 | int gnttab_grant_foreign_access_trans(domid_t domid, int flags, | ||
378 | domid_t trans_domid, | ||
379 | grant_ref_t trans_gref) | ||
380 | { | ||
381 | int ref, rc; | ||
382 | |||
383 | ref = get_free_entries(1); | ||
384 | if (unlikely(ref < 0)) | ||
385 | return -ENOSPC; | ||
386 | |||
387 | rc = gnttab_grant_foreign_access_trans_ref(ref, domid, flags, | ||
388 | trans_domid, trans_gref); | ||
389 | if (rc < 0) { | ||
390 | put_free_entry(ref); | ||
391 | return rc; | ||
392 | } | ||
393 | |||
394 | return ref; | ||
395 | } | ||
396 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans); | ||
397 | |||
398 | bool gnttab_trans_grants_available(void) | ||
399 | { | ||
400 | return gnttab_interface->update_trans_entry != NULL; | ||
401 | } | ||
402 | EXPORT_SYMBOL_GPL(gnttab_trans_grants_available); | ||
403 | |||
404 | static int gnttab_query_foreign_access_v1(grant_ref_t ref) | ||
405 | { | ||
406 | return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing); | ||
407 | } | ||
408 | |||
409 | static int gnttab_query_foreign_access_v2(grant_ref_t ref) | ||
410 | { | ||
411 | return grstatus[ref] & (GTF_reading|GTF_writing); | ||
412 | } | ||
413 | |||
414 | int gnttab_query_foreign_access(grant_ref_t ref) | ||
415 | { | ||
416 | return gnttab_interface->query_foreign_access(ref); | ||
197 | } | 417 | } |
198 | EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); | 418 | EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); |
199 | 419 | ||
200 | int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) | 420 | static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly) |
201 | { | 421 | { |
202 | u16 flags, nflags; | 422 | u16 flags, nflags; |
423 | u16 *pflags; | ||
203 | 424 | ||
204 | nflags = shared[ref].flags; | 425 | pflags = &gnttab_shared.v1[ref].flags; |
426 | nflags = *pflags; | ||
205 | do { | 427 | do { |
206 | flags = nflags; | 428 | flags = nflags; |
207 | if (flags & (GTF_reading|GTF_writing)) { | 429 | if (flags & (GTF_reading|GTF_writing)) { |
208 | printk(KERN_ALERT "WARNING: g.e. still in use!\n"); | 430 | printk(KERN_ALERT "WARNING: g.e. still in use!\n"); |
209 | return 0; | 431 | return 0; |
210 | } | 432 | } |
211 | } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags); | 433 | } while ((nflags = sync_cmpxchg(pflags, flags, 0)) != flags); |
434 | |||
435 | return 1; | ||
436 | } | ||
437 | |||
438 | static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly) | ||
439 | { | ||
440 | gnttab_shared.v2[ref].hdr.flags = 0; | ||
441 | mb(); | ||
442 | if (grstatus[ref] & (GTF_reading|GTF_writing)) { | ||
443 | return 0; | ||
444 | } else { | ||
445 | /* The read of grstatus needs to have acquire | ||
446 | semantics. On x86, reads already have | ||
447 | that, and we just need to protect against | ||
448 | compiler reorderings. On other | ||
449 | architectures we may need a full | ||
450 | barrier. */ | ||
451 | #ifdef CONFIG_X86 | ||
452 | barrier(); | ||
453 | #else | ||
454 | mb(); | ||
455 | #endif | ||
456 | } | ||
212 | 457 | ||
213 | return 1; | 458 | return 1; |
214 | } | 459 | } |
460 | |||
461 | int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) | ||
462 | { | ||
463 | return gnttab_interface->end_foreign_access_ref(ref, readonly); | ||
464 | } | ||
215 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); | 465 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); |
216 | 466 | ||
217 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, | 467 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, |
@@ -246,37 +496,76 @@ EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer); | |||
246 | void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, | 496 | void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, |
247 | unsigned long pfn) | 497 | unsigned long pfn) |
248 | { | 498 | { |
249 | update_grant_entry(ref, domid, pfn, GTF_accept_transfer); | 499 | gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer); |
250 | } | 500 | } |
251 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); | 501 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); |
252 | 502 | ||
253 | unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | 503 | static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref) |
254 | { | 504 | { |
255 | unsigned long frame; | 505 | unsigned long frame; |
256 | u16 flags; | 506 | u16 flags; |
507 | u16 *pflags; | ||
508 | |||
509 | pflags = &gnttab_shared.v1[ref].flags; | ||
257 | 510 | ||
258 | /* | 511 | /* |
259 | * If a transfer is not even yet started, try to reclaim the grant | 512 | * If a transfer is not even yet started, try to reclaim the grant |
260 | * reference and return failure (== 0). | 513 | * reference and return failure (== 0). |
261 | */ | 514 | */ |
262 | while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { | 515 | while (!((flags = *pflags) & GTF_transfer_committed)) { |
263 | if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags) | 516 | if (sync_cmpxchg(pflags, flags, 0) == flags) |
264 | return 0; | 517 | return 0; |
265 | cpu_relax(); | 518 | cpu_relax(); |
266 | } | 519 | } |
267 | 520 | ||
268 | /* If a transfer is in progress then wait until it is completed. */ | 521 | /* If a transfer is in progress then wait until it is completed. */ |
269 | while (!(flags & GTF_transfer_completed)) { | 522 | while (!(flags & GTF_transfer_completed)) { |
270 | flags = shared[ref].flags; | 523 | flags = *pflags; |
271 | cpu_relax(); | 524 | cpu_relax(); |
272 | } | 525 | } |
273 | 526 | ||
274 | rmb(); /* Read the frame number /after/ reading completion status. */ | 527 | rmb(); /* Read the frame number /after/ reading completion status. */ |
275 | frame = shared[ref].frame; | 528 | frame = gnttab_shared.v1[ref].frame; |
529 | BUG_ON(frame == 0); | ||
530 | |||
531 | return frame; | ||
532 | } | ||
533 | |||
534 | static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref) | ||
535 | { | ||
536 | unsigned long frame; | ||
537 | u16 flags; | ||
538 | u16 *pflags; | ||
539 | |||
540 | pflags = &gnttab_shared.v2[ref].hdr.flags; | ||
541 | |||
542 | /* | ||
543 | * If a transfer is not even yet started, try to reclaim the grant | ||
544 | * reference and return failure (== 0). | ||
545 | */ | ||
546 | while (!((flags = *pflags) & GTF_transfer_committed)) { | ||
547 | if (sync_cmpxchg(pflags, flags, 0) == flags) | ||
548 | return 0; | ||
549 | cpu_relax(); | ||
550 | } | ||
551 | |||
552 | /* If a transfer is in progress then wait until it is completed. */ | ||
553 | while (!(flags & GTF_transfer_completed)) { | ||
554 | flags = *pflags; | ||
555 | cpu_relax(); | ||
556 | } | ||
557 | |||
558 | rmb(); /* Read the frame number /after/ reading completion status. */ | ||
559 | frame = gnttab_shared.v2[ref].full_page.frame; | ||
276 | BUG_ON(frame == 0); | 560 | BUG_ON(frame == 0); |
277 | 561 | ||
278 | return frame; | 562 | return frame; |
279 | } | 563 | } |
564 | |||
565 | unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | ||
566 | { | ||
567 | return gnttab_interface->end_foreign_transfer_ref(ref); | ||
568 | } | ||
280 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); | 569 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); |
281 | 570 | ||
282 | unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) | 571 | unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) |
@@ -448,8 +737,8 @@ unsigned int gnttab_max_grant_frames(void) | |||
448 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); | 737 | EXPORT_SYMBOL_GPL(gnttab_max_grant_frames); |
449 | 738 | ||
450 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | 739 | int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, |
451 | struct gnttab_map_grant_ref *kmap_ops, | 740 | struct gnttab_map_grant_ref *kmap_ops, |
452 | struct page **pages, unsigned int count) | 741 | struct page **pages, unsigned int count) |
453 | { | 742 | { |
454 | int i, ret; | 743 | int i, ret; |
455 | pte_t *pte; | 744 | pte_t *pte; |
@@ -472,24 +761,10 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | |||
472 | (map_ops[i].host_addr & ~PAGE_MASK)); | 761 | (map_ops[i].host_addr & ~PAGE_MASK)); |
473 | mfn = pte_mfn(*pte); | 762 | mfn = pte_mfn(*pte); |
474 | } else { | 763 | } else { |
475 | /* If you really wanted to do this: | 764 | mfn = PFN_DOWN(map_ops[i].dev_bus_addr); |
476 | * mfn = PFN_DOWN(map_ops[i].dev_bus_addr); | ||
477 | * | ||
478 | * The reason we do not implement it is b/c on the | ||
479 | * unmap path (gnttab_unmap_refs) we have no means of | ||
480 | * checking whether the page is !GNTMAP_contains_pte. | ||
481 | * | ||
482 | * That is without some extra data-structure to carry | ||
483 | * the struct page, bool clear_pte, and list_head next | ||
484 | * tuples and deal with allocation/delallocation, etc. | ||
485 | * | ||
486 | * The users of this API set the GNTMAP_contains_pte | ||
487 | * flag so lets just return not supported until it | ||
488 | * becomes neccessary to implement. | ||
489 | */ | ||
490 | return -EOPNOTSUPP; | ||
491 | } | 765 | } |
492 | ret = m2p_add_override(mfn, pages[i], &kmap_ops[i]); | 766 | ret = m2p_add_override(mfn, pages[i], kmap_ops ? |
767 | &kmap_ops[i] : NULL); | ||
493 | if (ret) | 768 | if (ret) |
494 | return ret; | 769 | return ret; |
495 | } | 770 | } |
@@ -499,7 +774,7 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops, | |||
499 | EXPORT_SYMBOL_GPL(gnttab_map_refs); | 774 | EXPORT_SYMBOL_GPL(gnttab_map_refs); |
500 | 775 | ||
501 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | 776 | int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, |
502 | struct page **pages, unsigned int count) | 777 | struct page **pages, unsigned int count, bool clear_pte) |
503 | { | 778 | { |
504 | int i, ret; | 779 | int i, ret; |
505 | 780 | ||
@@ -511,7 +786,7 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | |||
511 | return ret; | 786 | return ret; |
512 | 787 | ||
513 | for (i = 0; i < count; i++) { | 788 | for (i = 0; i < count; i++) { |
514 | ret = m2p_remove_override(pages[i], true /* clear the PTE */); | 789 | ret = m2p_remove_override(pages[i], clear_pte); |
515 | if (ret) | 790 | if (ret) |
516 | return ret; | 791 | return ret; |
517 | } | 792 | } |
@@ -520,6 +795,77 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | |||
520 | } | 795 | } |
521 | EXPORT_SYMBOL_GPL(gnttab_unmap_refs); | 796 | EXPORT_SYMBOL_GPL(gnttab_unmap_refs); |
522 | 797 | ||
798 | static unsigned nr_status_frames(unsigned nr_grant_frames) | ||
799 | { | ||
800 | return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP; | ||
801 | } | ||
802 | |||
803 | static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes) | ||
804 | { | ||
805 | int rc; | ||
806 | |||
807 | rc = arch_gnttab_map_shared(frames, nr_gframes, | ||
808 | gnttab_max_grant_frames(), | ||
809 | &gnttab_shared.addr); | ||
810 | BUG_ON(rc); | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | static void gnttab_unmap_frames_v1(void) | ||
816 | { | ||
817 | arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames); | ||
818 | } | ||
819 | |||
820 | static int gnttab_map_frames_v2(unsigned long *frames, unsigned int nr_gframes) | ||
821 | { | ||
822 | uint64_t *sframes; | ||
823 | unsigned int nr_sframes; | ||
824 | struct gnttab_get_status_frames getframes; | ||
825 | int rc; | ||
826 | |||
827 | nr_sframes = nr_status_frames(nr_gframes); | ||
828 | |||
829 | /* No need for kzalloc as it is initialized in following hypercall | ||
830 | * GNTTABOP_get_status_frames. | ||
831 | */ | ||
832 | sframes = kmalloc(nr_sframes * sizeof(uint64_t), GFP_ATOMIC); | ||
833 | if (!sframes) | ||
834 | return -ENOMEM; | ||
835 | |||
836 | getframes.dom = DOMID_SELF; | ||
837 | getframes.nr_frames = nr_sframes; | ||
838 | set_xen_guest_handle(getframes.frame_list, sframes); | ||
839 | |||
840 | rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames, | ||
841 | &getframes, 1); | ||
842 | if (rc == -ENOSYS) { | ||
843 | kfree(sframes); | ||
844 | return -ENOSYS; | ||
845 | } | ||
846 | |||
847 | BUG_ON(rc || getframes.status); | ||
848 | |||
849 | rc = arch_gnttab_map_status(sframes, nr_sframes, | ||
850 | nr_status_frames(gnttab_max_grant_frames()), | ||
851 | &grstatus); | ||
852 | BUG_ON(rc); | ||
853 | kfree(sframes); | ||
854 | |||
855 | rc = arch_gnttab_map_shared(frames, nr_gframes, | ||
856 | gnttab_max_grant_frames(), | ||
857 | &gnttab_shared.addr); | ||
858 | BUG_ON(rc); | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static void gnttab_unmap_frames_v2(void) | ||
864 | { | ||
865 | arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames); | ||
866 | arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames)); | ||
867 | } | ||
868 | |||
523 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | 869 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) |
524 | { | 870 | { |
525 | struct gnttab_setup_table setup; | 871 | struct gnttab_setup_table setup; |
@@ -551,6 +897,9 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
551 | return rc; | 897 | return rc; |
552 | } | 898 | } |
553 | 899 | ||
900 | /* No need for kzalloc as it is initialized in following hypercall | ||
901 | * GNTTABOP_setup_table. | ||
902 | */ | ||
554 | frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); | 903 | frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); |
555 | if (!frames) | 904 | if (!frames) |
556 | return -ENOMEM; | 905 | return -ENOMEM; |
@@ -567,19 +916,65 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
567 | 916 | ||
568 | BUG_ON(rc || setup.status); | 917 | BUG_ON(rc || setup.status); |
569 | 918 | ||
570 | rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), | 919 | rc = gnttab_interface->map_frames(frames, nr_gframes); |
571 | &shared); | ||
572 | BUG_ON(rc); | ||
573 | 920 | ||
574 | kfree(frames); | 921 | kfree(frames); |
575 | 922 | ||
576 | return 0; | 923 | return rc; |
924 | } | ||
925 | |||
926 | static struct gnttab_ops gnttab_v1_ops = { | ||
927 | .map_frames = gnttab_map_frames_v1, | ||
928 | .unmap_frames = gnttab_unmap_frames_v1, | ||
929 | .update_entry = gnttab_update_entry_v1, | ||
930 | .end_foreign_access_ref = gnttab_end_foreign_access_ref_v1, | ||
931 | .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1, | ||
932 | .query_foreign_access = gnttab_query_foreign_access_v1, | ||
933 | }; | ||
934 | |||
935 | static struct gnttab_ops gnttab_v2_ops = { | ||
936 | .map_frames = gnttab_map_frames_v2, | ||
937 | .unmap_frames = gnttab_unmap_frames_v2, | ||
938 | .update_entry = gnttab_update_entry_v2, | ||
939 | .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2, | ||
940 | .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2, | ||
941 | .query_foreign_access = gnttab_query_foreign_access_v2, | ||
942 | .update_subpage_entry = gnttab_update_subpage_entry_v2, | ||
943 | .update_trans_entry = gnttab_update_trans_entry_v2, | ||
944 | }; | ||
945 | |||
946 | static void gnttab_request_version(void) | ||
947 | { | ||
948 | int rc; | ||
949 | struct gnttab_set_version gsv; | ||
950 | |||
951 | gsv.version = 2; | ||
952 | rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1); | ||
953 | if (rc == 0) { | ||
954 | grant_table_version = 2; | ||
955 | gnttab_interface = &gnttab_v2_ops; | ||
956 | } else if (grant_table_version == 2) { | ||
957 | /* | ||
958 | * If we've already used version 2 features, | ||
959 | * but then suddenly discover that they're not | ||
960 | * available (e.g. migrating to an older | ||
961 | * version of Xen), almost unbounded badness | ||
962 | * can happen. | ||
963 | */ | ||
964 | panic("we need grant tables version 2, but only version 1 is available"); | ||
965 | } else { | ||
966 | grant_table_version = 1; | ||
967 | gnttab_interface = &gnttab_v1_ops; | ||
968 | } | ||
969 | printk(KERN_INFO "Grant tables using version %d layout.\n", | ||
970 | grant_table_version); | ||
577 | } | 971 | } |
578 | 972 | ||
579 | int gnttab_resume(void) | 973 | int gnttab_resume(void) |
580 | { | 974 | { |
581 | unsigned int max_nr_gframes; | 975 | unsigned int max_nr_gframes; |
582 | 976 | ||
977 | gnttab_request_version(); | ||
583 | max_nr_gframes = gnttab_max_grant_frames(); | 978 | max_nr_gframes = gnttab_max_grant_frames(); |
584 | if (max_nr_gframes < nr_grant_frames) | 979 | if (max_nr_gframes < nr_grant_frames) |
585 | return -ENOSYS; | 980 | return -ENOSYS; |
@@ -587,9 +982,10 @@ int gnttab_resume(void) | |||
587 | if (xen_pv_domain()) | 982 | if (xen_pv_domain()) |
588 | return gnttab_map(0, nr_grant_frames - 1); | 983 | return gnttab_map(0, nr_grant_frames - 1); |
589 | 984 | ||
590 | if (!shared) { | 985 | if (gnttab_shared.addr == NULL) { |
591 | shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); | 986 | gnttab_shared.addr = ioremap(xen_hvm_resume_frames, |
592 | if (shared == NULL) { | 987 | PAGE_SIZE * max_nr_gframes); |
988 | if (gnttab_shared.addr == NULL) { | ||
593 | printk(KERN_WARNING | 989 | printk(KERN_WARNING |
594 | "Failed to ioremap gnttab share frames!"); | 990 | "Failed to ioremap gnttab share frames!"); |
595 | return -ENOMEM; | 991 | return -ENOMEM; |
@@ -603,7 +999,7 @@ int gnttab_resume(void) | |||
603 | 999 | ||
604 | int gnttab_suspend(void) | 1000 | int gnttab_suspend(void) |
605 | { | 1001 | { |
606 | arch_gnttab_unmap_shared(shared, nr_grant_frames); | 1002 | gnttab_interface->unmap_frames(); |
607 | return 0; | 1003 | return 0; |
608 | } | 1004 | } |
609 | 1005 | ||