diff options
Diffstat (limited to 'drivers/xen/grant-table.c')
-rw-r--r-- | drivers/xen/grant-table.c | 181 |
1 files changed, 141 insertions, 40 deletions
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index bf1c094f4ebf..18355a53763f 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c | |||
@@ -53,7 +53,7 @@ | |||
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 (PAGE_SIZE / sizeof(struct grant_entry_v1)) |
57 | 57 | ||
58 | static grant_ref_t **gnttab_list; | 58 | static grant_ref_t **gnttab_list; |
59 | static unsigned int nr_grant_frames; | 59 | static unsigned int nr_grant_frames; |
@@ -64,7 +64,63 @@ static DEFINE_SPINLOCK(gnttab_list_lock); | |||
64 | unsigned long xen_hvm_resume_frames; | 64 | unsigned long xen_hvm_resume_frames; |
65 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); | 65 | EXPORT_SYMBOL_GPL(xen_hvm_resume_frames); |
66 | 66 | ||
67 | static struct grant_entry *shared; | 67 | static union { |
68 | struct grant_entry_v1 *v1; | ||
69 | void *addr; | ||
70 | } gnttab_shared; | ||
71 | |||
72 | /*This is a structure of function pointers for grant table*/ | ||
73 | struct gnttab_ops { | ||
74 | /* | ||
75 | * Mapping a list of frames for storing grant entries. First input | ||
76 | * parameter is used to storing grant table address when grant table | ||
77 | * being setup, second parameter is the number of frames to map grant | ||
78 | * table. Returning GNTST_okay means success and negative value means | ||
79 | * failure. | ||
80 | */ | ||
81 | int (*map_frames)(unsigned long *, unsigned int); | ||
82 | /* | ||
83 | * Release a list of frames which are mapped in map_frames for grant | ||
84 | * entry status. | ||
85 | */ | ||
86 | void (*unmap_frames)(void); | ||
87 | /* | ||
88 | * Introducing a valid entry into the grant table, granting the frame | ||
89 | * of this grant entry to domain for accessing, or transfering, or | ||
90 | * transitively accessing. First input parameter is reference of this | ||
91 | * introduced grant entry, second one is domid of granted domain, third | ||
92 | * one is the frame to be granted, and the last one is status of the | ||
93 | * grant entry to be updated. | ||
94 | */ | ||
95 | void (*update_entry)(grant_ref_t, domid_t, unsigned long, unsigned); | ||
96 | /* | ||
97 | * Stop granting a grant entry to domain for accessing. First input | ||
98 | * parameter is reference of a grant entry whose grant access will be | ||
99 | * stopped, second one is not in use now. If the grant entry is | ||
100 | * currently mapped for reading or writing, just return failure(==0) | ||
101 | * directly and don't tear down the grant access. Otherwise, stop grant | ||
102 | * access for this entry and return success(==1). | ||
103 | */ | ||
104 | int (*end_foreign_access_ref)(grant_ref_t, int); | ||
105 | /* | ||
106 | * Stop granting a grant entry to domain for transfer. If tranfer has | ||
107 | * not started, just reclaim the grant entry and return failure(==0). | ||
108 | * Otherwise, wait for the transfer to complete and then return the | ||
109 | * frame. | ||
110 | */ | ||
111 | unsigned long (*end_foreign_transfer_ref)(grant_ref_t); | ||
112 | /* | ||
113 | * Query the status of a grant entry. Input parameter is reference of | ||
114 | * queried grant entry, return value is the status of queried entry. | ||
115 | * Detailed status(writing/reading) can be gotten from the return value | ||
116 | * by bit operations. | ||
117 | */ | ||
118 | int (*query_foreign_access)(grant_ref_t); | ||
119 | }; | ||
120 | |||
121 | static struct gnttab_ops *gnttab_interface; | ||
122 | |||
123 | static int grant_table_version; | ||
68 | 124 | ||
69 | static struct gnttab_free_callback *gnttab_free_callback_list; | 125 | static struct gnttab_free_callback *gnttab_free_callback_list; |
70 | 126 | ||
@@ -142,23 +198,23 @@ static void put_free_entry(grant_ref_t ref) | |||
142 | spin_unlock_irqrestore(&gnttab_list_lock, flags); | 198 | spin_unlock_irqrestore(&gnttab_list_lock, flags); |
143 | } | 199 | } |
144 | 200 | ||
145 | static void update_grant_entry(grant_ref_t ref, domid_t domid, | 201 | /* |
146 | unsigned long frame, unsigned flags) | 202 | * Introducing a valid entry into the grant table: |
203 | * 1. Write ent->domid. | ||
204 | * 2. Write ent->frame: | ||
205 | * GTF_permit_access: Frame to which access is permitted. | ||
206 | * GTF_accept_transfer: Pseudo-phys frame slot being filled by new | ||
207 | * frame, or zero if none. | ||
208 | * 3. Write memory barrier (WMB). | ||
209 | * 4. Write ent->flags, inc. valid type. | ||
210 | */ | ||
211 | static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid, | ||
212 | unsigned long frame, unsigned flags) | ||
147 | { | 213 | { |
148 | /* | 214 | gnttab_shared.v1[ref].domid = domid; |
149 | * Introducing a valid entry into the grant table: | 215 | gnttab_shared.v1[ref].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(); | 216 | wmb(); |
161 | shared[ref].flags = flags; | 217 | gnttab_shared.v1[ref].flags = flags; |
162 | } | 218 | } |
163 | 219 | ||
164 | /* | 220 | /* |
@@ -167,7 +223,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, | 223 | void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, |
168 | unsigned long frame, int readonly) | 224 | unsigned long frame, int readonly) |
169 | { | 225 | { |
170 | update_grant_entry(ref, domid, frame, | 226 | gnttab_interface->update_entry(ref, domid, frame, |
171 | GTF_permit_access | (readonly ? GTF_readonly : 0)); | 227 | GTF_permit_access | (readonly ? GTF_readonly : 0)); |
172 | } | 228 | } |
173 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); | 229 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref); |
@@ -187,31 +243,37 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame, | |||
187 | } | 243 | } |
188 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); | 244 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access); |
189 | 245 | ||
190 | int gnttab_query_foreign_access(grant_ref_t ref) | 246 | static int gnttab_query_foreign_access_v1(grant_ref_t ref) |
191 | { | 247 | { |
192 | u16 nflags; | 248 | return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing); |
193 | 249 | } | |
194 | nflags = shared[ref].flags; | ||
195 | 250 | ||
196 | return nflags & (GTF_reading|GTF_writing); | 251 | int gnttab_query_foreign_access(grant_ref_t ref) |
252 | { | ||
253 | return gnttab_interface->query_foreign_access(ref); | ||
197 | } | 254 | } |
198 | EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); | 255 | EXPORT_SYMBOL_GPL(gnttab_query_foreign_access); |
199 | 256 | ||
200 | int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) | 257 | static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly) |
201 | { | 258 | { |
202 | u16 flags, nflags; | 259 | u16 flags, nflags; |
203 | 260 | ||
204 | nflags = shared[ref].flags; | 261 | nflags = gnttab_shared.v1[ref].flags; |
205 | do { | 262 | do { |
206 | flags = nflags; | 263 | flags = nflags; |
207 | if (flags & (GTF_reading|GTF_writing)) { | 264 | if (flags & (GTF_reading|GTF_writing)) { |
208 | printk(KERN_ALERT "WARNING: g.e. still in use!\n"); | 265 | printk(KERN_ALERT "WARNING: g.e. still in use!\n"); |
209 | return 0; | 266 | return 0; |
210 | } | 267 | } |
211 | } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags); | 268 | } while ((nflags = sync_cmpxchg(&gnttab_shared.v1[ref].flags, flags, 0)) != flags); |
212 | 269 | ||
213 | return 1; | 270 | return 1; |
214 | } | 271 | } |
272 | |||
273 | int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) | ||
274 | { | ||
275 | return gnttab_interface->end_foreign_access_ref(ref, readonly); | ||
276 | } | ||
215 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); | 277 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref); |
216 | 278 | ||
217 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, | 279 | void gnttab_end_foreign_access(grant_ref_t ref, int readonly, |
@@ -246,11 +308,11 @@ EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer); | |||
246 | void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, | 308 | void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, |
247 | unsigned long pfn) | 309 | unsigned long pfn) |
248 | { | 310 | { |
249 | update_grant_entry(ref, domid, pfn, GTF_accept_transfer); | 311 | gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer); |
250 | } | 312 | } |
251 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); | 313 | EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref); |
252 | 314 | ||
253 | unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | 315 | static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref) |
254 | { | 316 | { |
255 | unsigned long frame; | 317 | unsigned long frame; |
256 | u16 flags; | 318 | u16 flags; |
@@ -259,24 +321,29 @@ unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | |||
259 | * If a transfer is not even yet started, try to reclaim the grant | 321 | * If a transfer is not even yet started, try to reclaim the grant |
260 | * reference and return failure (== 0). | 322 | * reference and return failure (== 0). |
261 | */ | 323 | */ |
262 | while (!((flags = shared[ref].flags) & GTF_transfer_committed)) { | 324 | while (!((flags = gnttab_shared.v1[ref].flags) & GTF_transfer_committed)) { |
263 | if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags) | 325 | if (sync_cmpxchg(&gnttab_shared.v1[ref].flags, flags, 0) == flags) |
264 | return 0; | 326 | return 0; |
265 | cpu_relax(); | 327 | cpu_relax(); |
266 | } | 328 | } |
267 | 329 | ||
268 | /* If a transfer is in progress then wait until it is completed. */ | 330 | /* If a transfer is in progress then wait until it is completed. */ |
269 | while (!(flags & GTF_transfer_completed)) { | 331 | while (!(flags & GTF_transfer_completed)) { |
270 | flags = shared[ref].flags; | 332 | flags = gnttab_shared.v1[ref].flags; |
271 | cpu_relax(); | 333 | cpu_relax(); |
272 | } | 334 | } |
273 | 335 | ||
274 | rmb(); /* Read the frame number /after/ reading completion status. */ | 336 | rmb(); /* Read the frame number /after/ reading completion status. */ |
275 | frame = shared[ref].frame; | 337 | frame = gnttab_shared.v1[ref].frame; |
276 | BUG_ON(frame == 0); | 338 | BUG_ON(frame == 0); |
277 | 339 | ||
278 | return frame; | 340 | return frame; |
279 | } | 341 | } |
342 | |||
343 | unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) | ||
344 | { | ||
345 | return gnttab_interface->end_foreign_transfer_ref(ref); | ||
346 | } | ||
280 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); | 347 | EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref); |
281 | 348 | ||
282 | unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) | 349 | unsigned long gnttab_end_foreign_transfer(grant_ref_t ref) |
@@ -520,6 +587,23 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops, | |||
520 | } | 587 | } |
521 | EXPORT_SYMBOL_GPL(gnttab_unmap_refs); | 588 | EXPORT_SYMBOL_GPL(gnttab_unmap_refs); |
522 | 589 | ||
590 | static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes) | ||
591 | { | ||
592 | int rc; | ||
593 | |||
594 | rc = arch_gnttab_map_shared(frames, nr_gframes, | ||
595 | gnttab_max_grant_frames(), | ||
596 | &gnttab_shared.addr); | ||
597 | BUG_ON(rc); | ||
598 | |||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | static void gnttab_unmap_frames_v1(void) | ||
603 | { | ||
604 | arch_gnttab_unmap_shared(gnttab_shared.addr, nr_grant_frames); | ||
605 | } | ||
606 | |||
523 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | 607 | static int gnttab_map(unsigned int start_idx, unsigned int end_idx) |
524 | { | 608 | { |
525 | struct gnttab_setup_table setup; | 609 | struct gnttab_setup_table setup; |
@@ -567,19 +651,35 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx) | |||
567 | 651 | ||
568 | BUG_ON(rc || setup.status); | 652 | BUG_ON(rc || setup.status); |
569 | 653 | ||
570 | rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(), | 654 | rc = gnttab_interface->map_frames(frames, nr_gframes); |
571 | &shared); | ||
572 | BUG_ON(rc); | ||
573 | 655 | ||
574 | kfree(frames); | 656 | kfree(frames); |
575 | 657 | ||
576 | return 0; | 658 | return rc; |
659 | } | ||
660 | |||
661 | static struct gnttab_ops gnttab_v1_ops = { | ||
662 | .map_frames = gnttab_map_frames_v1, | ||
663 | .unmap_frames = gnttab_unmap_frames_v1, | ||
664 | .update_entry = gnttab_update_entry_v1, | ||
665 | .end_foreign_access_ref = gnttab_end_foreign_access_ref_v1, | ||
666 | .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1, | ||
667 | .query_foreign_access = gnttab_query_foreign_access_v1, | ||
668 | }; | ||
669 | |||
670 | static void gnttab_request_version(void) | ||
671 | { | ||
672 | grant_table_version = 1; | ||
673 | gnttab_interface = &gnttab_v1_ops; | ||
674 | printk(KERN_INFO "Grant tables using version %d layout.\n", | ||
675 | grant_table_version); | ||
577 | } | 676 | } |
578 | 677 | ||
579 | int gnttab_resume(void) | 678 | int gnttab_resume(void) |
580 | { | 679 | { |
581 | unsigned int max_nr_gframes; | 680 | unsigned int max_nr_gframes; |
582 | 681 | ||
682 | gnttab_request_version(); | ||
583 | max_nr_gframes = gnttab_max_grant_frames(); | 683 | max_nr_gframes = gnttab_max_grant_frames(); |
584 | if (max_nr_gframes < nr_grant_frames) | 684 | if (max_nr_gframes < nr_grant_frames) |
585 | return -ENOSYS; | 685 | return -ENOSYS; |
@@ -587,9 +687,10 @@ int gnttab_resume(void) | |||
587 | if (xen_pv_domain()) | 687 | if (xen_pv_domain()) |
588 | return gnttab_map(0, nr_grant_frames - 1); | 688 | return gnttab_map(0, nr_grant_frames - 1); |
589 | 689 | ||
590 | if (!shared) { | 690 | if (gnttab_shared.addr == NULL) { |
591 | shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes); | 691 | gnttab_shared.addr = ioremap(xen_hvm_resume_frames, |
592 | if (shared == NULL) { | 692 | PAGE_SIZE * max_nr_gframes); |
693 | if (gnttab_shared.addr == NULL) { | ||
593 | printk(KERN_WARNING | 694 | printk(KERN_WARNING |
594 | "Failed to ioremap gnttab share frames!"); | 695 | "Failed to ioremap gnttab share frames!"); |
595 | return -ENOMEM; | 696 | return -ENOMEM; |
@@ -603,7 +704,7 @@ int gnttab_resume(void) | |||
603 | 704 | ||
604 | int gnttab_suspend(void) | 705 | int gnttab_suspend(void) |
605 | { | 706 | { |
606 | arch_gnttab_unmap_shared(shared, nr_grant_frames); | 707 | gnttab_interface->unmap_frames(); |
607 | return 0; | 708 | return 0; |
608 | } | 709 | } |
609 | 710 | ||