blob: 573e7fe9b14739c50e805ba18370e858d2937901 [file] [log] [blame]
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001/******************************************************************************
2 * grant_table.c
3 *
4 * Granting foreign access to our memory reservation.
5 *
6 * Copyright (c) 2005-2006, 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 */
33
Joe Perches283c0972013-06-28 03:21:41 -070034#define pr_fmt(fmt) "xen:" KBUILD_MODNAME ": " fmt
35
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070036#include <linux/sched.h>
37#include <linux/mm.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090038#include <linux/slab.h>
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070039#include <linux/vmalloc.h>
40#include <linux/uaccess.h>
Stefano Stabellini183d03c2010-05-17 17:08:21 +010041#include <linux/io.h>
Andres Lagar-Cavillac5718982012-09-14 14:26:59 +000042#include <linux/delay.h>
Stefano Stabellinif62805f2012-04-24 11:55:43 +010043#include <linux/hardirq.h>
Jennifer Herbert3f9f1c62014-12-09 18:28:37 +000044#include <linux/workqueue.h>
Wengang Wang29d11cfd2017-07-18 09:40:35 +020045#include <linux/ratelimit.h>
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070046
Jeremy Fitzhardinge1ccbf532009-10-06 15:11:14 -070047#include <xen/xen.h>
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070048#include <xen/interface/xen.h>
49#include <xen/page.h>
50#include <xen/grant_table.h>
Stefano Stabellini183d03c2010-05-17 17:08:21 +010051#include <xen/interface/memory.h>
Annie Li85ff6ac2011-11-22 09:59:21 +080052#include <xen/hvc-console.h>
Stefano Stabellini3d24bbd2013-10-25 10:41:44 +000053#include <xen/swiotlb-xen.h>
David Vrabelff4b1562015-01-08 18:06:01 +000054#include <xen/balloon.h>
Jeremy Fitzhardingeecbf29c2008-12-16 12:37:07 -080055#include <asm/xen/hypercall.h>
Stefano Stabellini4d9310e2012-08-06 15:27:09 +010056#include <asm/xen/interface.h>
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070057
58#include <asm/pgtable.h>
59#include <asm/sync_bitops.h>
60
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070061/* External tools reserve first few grant table entries. */
62#define NR_RESERVED_ENTRIES 8
63#define GNTTAB_LIST_END 0xffffffff
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070064
65static grant_ref_t **gnttab_list;
66static unsigned int nr_grant_frames;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070067static int gnttab_free_count;
68static grant_ref_t gnttab_free_head;
69static DEFINE_SPINLOCK(gnttab_list_lock);
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -050070struct grant_frames xen_auto_xlat_grant_frames;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -070071
Annie Li0f9f5a92011-11-22 09:58:06 +080072static union {
73 struct grant_entry_v1 *v1;
Juergen Grossb988b8f2017-11-02 10:19:17 +010074 union grant_entry_v2 *v2;
Annie Li0f9f5a92011-11-22 09:58:06 +080075 void *addr;
76} gnttab_shared;
77
78/*This is a structure of function pointers for grant table*/
79struct gnttab_ops {
80 /*
Juergen Gross83c69322017-11-02 10:19:19 +010081 * Version of the grant interface.
82 */
83 unsigned int version;
84 /*
85 * Grant refs per grant frame.
86 */
87 unsigned int grefs_per_grant_frame;
88 /*
Annie Li9dbc71d2011-12-12 18:13:57 +080089 * Mapping a list of frames for storing grant entries. Frames parameter
90 * is used to store grant table address when grant table being setup,
91 * nr_gframes is the number of frames to map grant table. Returning
92 * GNTST_okay means success and negative value means failure.
Annie Li0f9f5a92011-11-22 09:58:06 +080093 */
Ian Campbellef32f892012-10-17 09:39:14 +010094 int (*map_frames)(xen_pfn_t *frames, unsigned int nr_gframes);
Annie Li0f9f5a92011-11-22 09:58:06 +080095 /*
96 * Release a list of frames which are mapped in map_frames for grant
97 * entry status.
98 */
99 void (*unmap_frames)(void);
100 /*
Annie Li9dbc71d2011-12-12 18:13:57 +0800101 * Introducing a valid entry into the grant table, granting the frame of
102 * this grant entry to domain for accessing or transfering. Ref
103 * parameter is reference of this introduced grant entry, domid is id of
104 * granted domain, frame is the page frame to be granted, and flags is
105 * status of the grant entry to be updated.
Annie Li0f9f5a92011-11-22 09:58:06 +0800106 */
Annie Li9dbc71d2011-12-12 18:13:57 +0800107 void (*update_entry)(grant_ref_t ref, domid_t domid,
108 unsigned long frame, unsigned flags);
Annie Li0f9f5a92011-11-22 09:58:06 +0800109 /*
Annie Li9dbc71d2011-12-12 18:13:57 +0800110 * Stop granting a grant entry to domain for accessing. Ref parameter is
111 * reference of a grant entry whose grant access will be stopped,
112 * readonly is not in use in this function. If the grant entry is
Annie Li0f9f5a92011-11-22 09:58:06 +0800113 * currently mapped for reading or writing, just return failure(==0)
114 * directly and don't tear down the grant access. Otherwise, stop grant
115 * access for this entry and return success(==1).
116 */
Annie Li9dbc71d2011-12-12 18:13:57 +0800117 int (*end_foreign_access_ref)(grant_ref_t ref, int readonly);
Annie Li0f9f5a92011-11-22 09:58:06 +0800118 /*
Annie Li9dbc71d2011-12-12 18:13:57 +0800119 * Stop granting a grant entry to domain for transfer. Ref parameter is
120 * reference of a grant entry whose grant transfer will be stopped. If
121 * tranfer has not started, just reclaim the grant entry and return
122 * failure(==0). Otherwise, wait for the transfer to complete and then
123 * return the frame.
Annie Li0f9f5a92011-11-22 09:58:06 +0800124 */
Annie Li9dbc71d2011-12-12 18:13:57 +0800125 unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
Annie Li0f9f5a92011-11-22 09:58:06 +0800126 /*
Annie Li9dbc71d2011-12-12 18:13:57 +0800127 * Query the status of a grant entry. Ref parameter is reference of
Annie Li0f9f5a92011-11-22 09:58:06 +0800128 * queried grant entry, return value is the status of queried entry.
129 * Detailed status(writing/reading) can be gotten from the return value
130 * by bit operations.
131 */
Annie Li9dbc71d2011-12-12 18:13:57 +0800132 int (*query_foreign_access)(grant_ref_t ref);
Annie Li0f9f5a92011-11-22 09:58:06 +0800133};
134
Bob Liub44166c2015-04-03 14:42:59 +0800135struct unmap_refs_callback_data {
136 struct completion completion;
137 int result;
138};
139
Julia Lawall86fc2132015-11-28 15:28:40 +0100140static const struct gnttab_ops *gnttab_interface;
Annie Li0f9f5a92011-11-22 09:58:06 +0800141
Juergen Grossb988b8f2017-11-02 10:19:17 +0100142/* This reflects status of grant entries, so act as a global value. */
143static grant_status_t *grstatus;
144
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700145static struct gnttab_free_callback *gnttab_free_callback_list;
146
147static int gnttab_expand(unsigned int req_entries);
148
149#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
Juergen Grossb988b8f2017-11-02 10:19:17 +0100150#define SPP (PAGE_SIZE / sizeof(grant_status_t))
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700151
152static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
153{
154 return &gnttab_list[(entry) / RPP][(entry) % RPP];
155}
156/* This can be used as an l-value */
157#define gnttab_entry(entry) (*__gnttab_entry(entry))
158
159static int get_free_entries(unsigned count)
160{
161 unsigned long flags;
Konrad Rzeszutek Wilk272800d2011-07-22 14:00:06 -0400162 int ref, rc = 0;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700163 grant_ref_t head;
164
165 spin_lock_irqsave(&gnttab_list_lock, flags);
166
167 if ((gnttab_free_count < count) &&
168 ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
169 spin_unlock_irqrestore(&gnttab_list_lock, flags);
170 return rc;
171 }
172
173 ref = head = gnttab_free_head;
174 gnttab_free_count -= count;
175 while (count-- > 1)
176 head = gnttab_entry(head);
177 gnttab_free_head = gnttab_entry(head);
178 gnttab_entry(head) = GNTTAB_LIST_END;
179
180 spin_unlock_irqrestore(&gnttab_list_lock, flags);
181
182 return ref;
183}
184
185static void do_free_callbacks(void)
186{
187 struct gnttab_free_callback *callback, *next;
188
189 callback = gnttab_free_callback_list;
190 gnttab_free_callback_list = NULL;
191
192 while (callback != NULL) {
193 next = callback->next;
194 if (gnttab_free_count >= callback->count) {
195 callback->next = NULL;
196 callback->fn(callback->arg);
197 } else {
198 callback->next = gnttab_free_callback_list;
199 gnttab_free_callback_list = callback;
200 }
201 callback = next;
202 }
203}
204
205static inline void check_free_callbacks(void)
206{
207 if (unlikely(gnttab_free_callback_list))
208 do_free_callbacks();
209}
210
211static void put_free_entry(grant_ref_t ref)
212{
213 unsigned long flags;
214 spin_lock_irqsave(&gnttab_list_lock, flags);
215 gnttab_entry(ref) = gnttab_free_head;
216 gnttab_free_head = ref;
217 gnttab_free_count++;
218 check_free_callbacks();
219 spin_unlock_irqrestore(&gnttab_list_lock, flags);
220}
221
Annie Li0f9f5a92011-11-22 09:58:06 +0800222/*
Juergen Grossb988b8f2017-11-02 10:19:17 +0100223 * Following applies to gnttab_update_entry_v1 and gnttab_update_entry_v2.
Annie Li0f9f5a92011-11-22 09:58:06 +0800224 * Introducing a valid entry into the grant table:
225 * 1. Write ent->domid.
226 * 2. Write ent->frame:
227 * GTF_permit_access: Frame to which access is permitted.
228 * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
229 * frame, or zero if none.
230 * 3. Write memory barrier (WMB).
231 * 4. Write ent->flags, inc. valid type.
232 */
233static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
234 unsigned long frame, unsigned flags)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700235{
Annie Li0f9f5a92011-11-22 09:58:06 +0800236 gnttab_shared.v1[ref].domid = domid;
237 gnttab_shared.v1[ref].frame = frame;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700238 wmb();
Annie Li0f9f5a92011-11-22 09:58:06 +0800239 gnttab_shared.v1[ref].flags = flags;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700240}
241
Juergen Grossb988b8f2017-11-02 10:19:17 +0100242static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid,
243 unsigned long frame, unsigned int flags)
244{
245 gnttab_shared.v2[ref].hdr.domid = domid;
246 gnttab_shared.v2[ref].full_page.frame = frame;
247 wmb(); /* Hypervisor concurrent accesses. */
248 gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags;
249}
250
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700251/*
252 * Public grant-issuing interface functions
253 */
254void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
255 unsigned long frame, int readonly)
256{
Annie Li0f9f5a92011-11-22 09:58:06 +0800257 gnttab_interface->update_entry(ref, domid, frame,
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700258 GTF_permit_access | (readonly ? GTF_readonly : 0));
259}
260EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
261
262int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
263 int readonly)
264{
265 int ref;
266
267 ref = get_free_entries(1);
268 if (unlikely(ref < 0))
269 return -ENOSPC;
270
271 gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
272
273 return ref;
274}
275EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
276
Annie Li0f9f5a92011-11-22 09:58:06 +0800277static int gnttab_query_foreign_access_v1(grant_ref_t ref)
278{
279 return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
280}
281
Juergen Grossb988b8f2017-11-02 10:19:17 +0100282static int gnttab_query_foreign_access_v2(grant_ref_t ref)
283{
284 return grstatus[ref] & (GTF_reading|GTF_writing);
285}
286
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700287int gnttab_query_foreign_access(grant_ref_t ref)
288{
Annie Li0f9f5a92011-11-22 09:58:06 +0800289 return gnttab_interface->query_foreign_access(ref);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700290}
291EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
292
Annie Li0f9f5a92011-11-22 09:58:06 +0800293static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700294{
295 u16 flags, nflags;
Annie Lib1e495b2011-11-22 09:58:47 +0800296 u16 *pflags;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700297
Annie Lib1e495b2011-11-22 09:58:47 +0800298 pflags = &gnttab_shared.v1[ref].flags;
299 nflags = *pflags;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700300 do {
301 flags = nflags;
Jan Beulich569ca5b2012-04-05 16:10:07 +0100302 if (flags & (GTF_reading|GTF_writing))
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700303 return 0;
Annie Lib1e495b2011-11-22 09:58:47 +0800304 } while ((nflags = sync_cmpxchg(pflags, flags, 0)) != flags);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700305
306 return 1;
307}
Annie Li0f9f5a92011-11-22 09:58:06 +0800308
Juergen Grossb988b8f2017-11-02 10:19:17 +0100309static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly)
310{
311 gnttab_shared.v2[ref].hdr.flags = 0;
312 mb(); /* Concurrent access by hypervisor. */
313 if (grstatus[ref] & (GTF_reading|GTF_writing)) {
314 return 0;
315 } else {
316 /*
317 * The read of grstatus needs to have acquire semantics.
318 * On x86, reads already have that, and we just need to
319 * protect against compiler reorderings.
320 * On other architectures we may need a full barrier.
321 */
322#ifdef CONFIG_X86
323 barrier();
324#else
325 mb();
326#endif
327 }
328
329 return 1;
330}
331
Jan Beulich569ca5b2012-04-05 16:10:07 +0100332static inline int _gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
Annie Li0f9f5a92011-11-22 09:58:06 +0800333{
334 return gnttab_interface->end_foreign_access_ref(ref, readonly);
335}
Jan Beulich569ca5b2012-04-05 16:10:07 +0100336
337int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
338{
339 if (_gnttab_end_foreign_access_ref(ref, readonly))
340 return 1;
341 pr_warn("WARNING: g.e. %#x still in use!\n", ref);
342 return 0;
343}
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700344EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
345
Jan Beulich569ca5b2012-04-05 16:10:07 +0100346struct deferred_entry {
347 struct list_head list;
348 grant_ref_t ref;
349 bool ro;
350 uint16_t warn_delay;
351 struct page *page;
352};
353static LIST_HEAD(deferred_list);
354static void gnttab_handle_deferred(unsigned long);
355static DEFINE_TIMER(deferred_timer, gnttab_handle_deferred, 0, 0);
356
357static void gnttab_handle_deferred(unsigned long unused)
358{
359 unsigned int nr = 10;
360 struct deferred_entry *first = NULL;
361 unsigned long flags;
362
363 spin_lock_irqsave(&gnttab_list_lock, flags);
364 while (nr--) {
365 struct deferred_entry *entry
366 = list_first_entry(&deferred_list,
367 struct deferred_entry, list);
368
369 if (entry == first)
370 break;
371 list_del(&entry->list);
372 spin_unlock_irqrestore(&gnttab_list_lock, flags);
373 if (_gnttab_end_foreign_access_ref(entry->ref, entry->ro)) {
374 put_free_entry(entry->ref);
375 if (entry->page) {
376 pr_debug("freeing g.e. %#x (pfn %#lx)\n",
377 entry->ref, page_to_pfn(entry->page));
378 __free_page(entry->page);
379 } else
380 pr_info("freeing g.e. %#x\n", entry->ref);
381 kfree(entry);
382 entry = NULL;
383 } else {
384 if (!--entry->warn_delay)
Joe Perches283c0972013-06-28 03:21:41 -0700385 pr_info("g.e. %#x still pending\n", entry->ref);
Jan Beulich569ca5b2012-04-05 16:10:07 +0100386 if (!first)
387 first = entry;
388 }
389 spin_lock_irqsave(&gnttab_list_lock, flags);
390 if (entry)
391 list_add_tail(&entry->list, &deferred_list);
392 else if (list_empty(&deferred_list))
393 break;
394 }
395 if (!list_empty(&deferred_list) && !timer_pending(&deferred_timer)) {
396 deferred_timer.expires = jiffies + HZ;
397 add_timer(&deferred_timer);
398 }
399 spin_unlock_irqrestore(&gnttab_list_lock, flags);
400}
401
402static void gnttab_add_deferred(grant_ref_t ref, bool readonly,
403 struct page *page)
404{
405 struct deferred_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
406 const char *what = KERN_WARNING "leaking";
407
408 if (entry) {
409 unsigned long flags;
410
411 entry->ref = ref;
412 entry->ro = readonly;
413 entry->page = page;
414 entry->warn_delay = 60;
415 spin_lock_irqsave(&gnttab_list_lock, flags);
416 list_add_tail(&entry->list, &deferred_list);
417 if (!timer_pending(&deferred_timer)) {
418 deferred_timer.expires = jiffies + HZ;
419 add_timer(&deferred_timer);
420 }
421 spin_unlock_irqrestore(&gnttab_list_lock, flags);
422 what = KERN_DEBUG "deferring";
423 }
424 printk("%s g.e. %#x (pfn %#lx)\n",
425 what, ref, page ? page_to_pfn(page) : -1);
426}
427
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700428void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
429 unsigned long page)
430{
431 if (gnttab_end_foreign_access_ref(ref, readonly)) {
432 put_free_entry(ref);
433 if (page != 0)
434 free_page(page);
Jan Beulich569ca5b2012-04-05 16:10:07 +0100435 } else
436 gnttab_add_deferred(ref, readonly,
437 page ? virt_to_page(page) : NULL);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700438}
439EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
440
441int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
442{
443 int ref;
444
445 ref = get_free_entries(1);
446 if (unlikely(ref < 0))
447 return -ENOSPC;
448 gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
449
450 return ref;
451}
452EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
453
454void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
455 unsigned long pfn)
456{
Annie Li0f9f5a92011-11-22 09:58:06 +0800457 gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700458}
459EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
460
Annie Li0f9f5a92011-11-22 09:58:06 +0800461static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700462{
463 unsigned long frame;
464 u16 flags;
Annie Lib1e495b2011-11-22 09:58:47 +0800465 u16 *pflags;
466
467 pflags = &gnttab_shared.v1[ref].flags;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700468
469 /*
470 * If a transfer is not even yet started, try to reclaim the grant
471 * reference and return failure (== 0).
472 */
Annie Lib1e495b2011-11-22 09:58:47 +0800473 while (!((flags = *pflags) & GTF_transfer_committed)) {
474 if (sync_cmpxchg(pflags, flags, 0) == flags)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700475 return 0;
476 cpu_relax();
477 }
478
479 /* If a transfer is in progress then wait until it is completed. */
480 while (!(flags & GTF_transfer_completed)) {
Annie Lib1e495b2011-11-22 09:58:47 +0800481 flags = *pflags;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700482 cpu_relax();
483 }
484
485 rmb(); /* Read the frame number /after/ reading completion status. */
Annie Li0f9f5a92011-11-22 09:58:06 +0800486 frame = gnttab_shared.v1[ref].frame;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700487 BUG_ON(frame == 0);
488
489 return frame;
490}
Annie Li0f9f5a92011-11-22 09:58:06 +0800491
Juergen Grossb988b8f2017-11-02 10:19:17 +0100492static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)
493{
494 unsigned long frame;
495 u16 flags;
496 u16 *pflags;
497
498 pflags = &gnttab_shared.v2[ref].hdr.flags;
499
500 /*
501 * If a transfer is not even yet started, try to reclaim the grant
502 * reference and return failure (== 0).
503 */
504 while (!((flags = *pflags) & GTF_transfer_committed)) {
505 if (sync_cmpxchg(pflags, flags, 0) == flags)
506 return 0;
507 cpu_relax();
508 }
509
510 /* If a transfer is in progress then wait until it is completed. */
511 while (!(flags & GTF_transfer_completed)) {
512 flags = *pflags;
513 cpu_relax();
514 }
515
516 rmb(); /* Read the frame number /after/ reading completion status. */
517 frame = gnttab_shared.v2[ref].full_page.frame;
518 BUG_ON(frame == 0);
519
520 return frame;
521}
522
Annie Li0f9f5a92011-11-22 09:58:06 +0800523unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
524{
525 return gnttab_interface->end_foreign_transfer_ref(ref);
526}
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700527EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
528
529unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
530{
531 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
532 put_free_entry(ref);
533 return frame;
534}
535EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
536
537void gnttab_free_grant_reference(grant_ref_t ref)
538{
539 put_free_entry(ref);
540}
541EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
542
543void gnttab_free_grant_references(grant_ref_t head)
544{
545 grant_ref_t ref;
546 unsigned long flags;
547 int count = 1;
548 if (head == GNTTAB_LIST_END)
549 return;
550 spin_lock_irqsave(&gnttab_list_lock, flags);
551 ref = head;
552 while (gnttab_entry(ref) != GNTTAB_LIST_END) {
553 ref = gnttab_entry(ref);
554 count++;
555 }
556 gnttab_entry(ref) = gnttab_free_head;
557 gnttab_free_head = head;
558 gnttab_free_count += count;
559 check_free_callbacks();
560 spin_unlock_irqrestore(&gnttab_list_lock, flags);
561}
562EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
563
564int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
565{
566 int h = get_free_entries(count);
567
568 if (h < 0)
569 return -ENOSPC;
570
571 *head = h;
572
573 return 0;
574}
575EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
576
577int gnttab_empty_grant_references(const grant_ref_t *private_head)
578{
579 return (*private_head == GNTTAB_LIST_END);
580}
581EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
582
583int gnttab_claim_grant_reference(grant_ref_t *private_head)
584{
585 grant_ref_t g = *private_head;
586 if (unlikely(g == GNTTAB_LIST_END))
587 return -ENOSPC;
588 *private_head = gnttab_entry(g);
589 return g;
590}
591EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
592
593void gnttab_release_grant_reference(grant_ref_t *private_head,
594 grant_ref_t release)
595{
596 gnttab_entry(release) = *private_head;
597 *private_head = release;
598}
599EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
600
601void gnttab_request_free_callback(struct gnttab_free_callback *callback,
602 void (*fn)(void *), void *arg, u16 count)
603{
604 unsigned long flags;
Roger Pau Monne5f338d92013-07-31 17:00:42 +0200605 struct gnttab_free_callback *cb;
606
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700607 spin_lock_irqsave(&gnttab_list_lock, flags);
Roger Pau Monne5f338d92013-07-31 17:00:42 +0200608
609 /* Check if the callback is already on the list */
610 cb = gnttab_free_callback_list;
611 while (cb) {
612 if (cb == callback)
613 goto out;
614 cb = cb->next;
615 }
616
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700617 callback->fn = fn;
618 callback->arg = arg;
619 callback->count = count;
620 callback->next = gnttab_free_callback_list;
621 gnttab_free_callback_list = callback;
622 check_free_callbacks();
623out:
624 spin_unlock_irqrestore(&gnttab_list_lock, flags);
625}
626EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
627
628void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
629{
630 struct gnttab_free_callback **pcb;
631 unsigned long flags;
632
633 spin_lock_irqsave(&gnttab_list_lock, flags);
634 for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
635 if (*pcb == callback) {
636 *pcb = callback->next;
637 break;
638 }
639 }
640 spin_unlock_irqrestore(&gnttab_list_lock, flags);
641}
642EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
643
Juergen Gross83c69322017-11-02 10:19:19 +0100644static unsigned int gnttab_frames(unsigned int frames, unsigned int align)
645{
646 return (frames * gnttab_interface->grefs_per_grant_frame + align - 1) /
647 align;
648}
649
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700650static int grow_gnttab_list(unsigned int more_frames)
651{
652 unsigned int new_nr_grant_frames, extra_entries, i;
Michael Abd-El-Malekbbc60c12008-04-04 02:33:48 -0700653 unsigned int nr_glist_frames, new_nr_glist_frames;
Juergen Gross83c69322017-11-02 10:19:19 +0100654 unsigned int grefs_per_frame;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700655
Juergen Gross83c69322017-11-02 10:19:19 +0100656 BUG_ON(gnttab_interface == NULL);
657 grefs_per_frame = gnttab_interface->grefs_per_grant_frame;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700658
Matt Wilsond0b4d642013-01-15 13:21:27 +0000659 new_nr_grant_frames = nr_grant_frames + more_frames;
Juergen Gross83c69322017-11-02 10:19:19 +0100660 extra_entries = more_frames * grefs_per_frame;
Matt Wilsond0b4d642013-01-15 13:21:27 +0000661
Juergen Gross83c69322017-11-02 10:19:19 +0100662 nr_glist_frames = gnttab_frames(nr_grant_frames, RPP);
663 new_nr_glist_frames = gnttab_frames(new_nr_grant_frames, RPP);
Michael Abd-El-Malekbbc60c12008-04-04 02:33:48 -0700664 for (i = nr_glist_frames; i < new_nr_glist_frames; i++) {
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700665 gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
666 if (!gnttab_list[i])
667 goto grow_nomem;
668 }
669
670
Juergen Gross83c69322017-11-02 10:19:19 +0100671 for (i = grefs_per_frame * nr_grant_frames;
672 i < grefs_per_frame * new_nr_grant_frames - 1; i++)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700673 gnttab_entry(i) = i + 1;
674
675 gnttab_entry(i) = gnttab_free_head;
Juergen Gross83c69322017-11-02 10:19:19 +0100676 gnttab_free_head = grefs_per_frame * nr_grant_frames;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700677 gnttab_free_count += extra_entries;
678
679 nr_grant_frames = new_nr_grant_frames;
680
681 check_free_callbacks();
682
683 return 0;
684
685grow_nomem:
Chen Gang46e36262014-08-26 23:38:44 +0800686 while (i-- > nr_glist_frames)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700687 free_page((unsigned long) gnttab_list[i]);
688 return -ENOMEM;
689}
690
691static unsigned int __max_nr_grant_frames(void)
692{
693 struct gnttab_query_size query;
694 int rc;
695
696 query.dom = DOMID_SELF;
697
698 rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
699 if ((rc < 0) || (query.status != GNTST_okay))
700 return 4; /* Legacy max supported number of frames */
701
702 return query.max_nr_frames;
703}
704
Stefano Stabellini183d03c2010-05-17 17:08:21 +0100705unsigned int gnttab_max_grant_frames(void)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700706{
707 unsigned int xen_max = __max_nr_grant_frames();
Konrad Rzeszutek Wilk7f256022013-12-31 15:55:39 -0500708 static unsigned int boot_max_nr_grant_frames;
709
710 /* First time, initialize it properly. */
711 if (!boot_max_nr_grant_frames)
712 boot_max_nr_grant_frames = __max_nr_grant_frames();
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700713
714 if (xen_max > boot_max_nr_grant_frames)
715 return boot_max_nr_grant_frames;
716 return xen_max;
717}
Stefano Stabellini183d03c2010-05-17 17:08:21 +0100718EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -0700719
Julien Grall47c54202014-01-30 12:56:34 +0000720int gnttab_setup_auto_xlat_frames(phys_addr_t addr)
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -0500721{
722 xen_pfn_t *pfn;
723 unsigned int max_nr_gframes = __max_nr_grant_frames();
724 unsigned int i;
725 void *vaddr;
726
727 if (xen_auto_xlat_grant_frames.count)
728 return -EINVAL;
729
Julien Grall5ed54512015-05-05 16:37:49 +0100730 vaddr = xen_remap(addr, XEN_PAGE_SIZE * max_nr_gframes);
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -0500731 if (vaddr == NULL) {
Julien Grall47c54202014-01-30 12:56:34 +0000732 pr_warn("Failed to ioremap gnttab share frames (addr=%pa)!\n",
733 &addr);
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -0500734 return -ENOMEM;
735 }
736 pfn = kcalloc(max_nr_gframes, sizeof(pfn[0]), GFP_KERNEL);
737 if (!pfn) {
738 xen_unmap(vaddr);
739 return -ENOMEM;
740 }
741 for (i = 0; i < max_nr_gframes; i++)
Julien Grall5ed54512015-05-05 16:37:49 +0100742 pfn[i] = XEN_PFN_DOWN(addr) + i;
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -0500743
744 xen_auto_xlat_grant_frames.vaddr = vaddr;
745 xen_auto_xlat_grant_frames.pfn = pfn;
746 xen_auto_xlat_grant_frames.count = max_nr_gframes;
747
748 return 0;
749}
750EXPORT_SYMBOL_GPL(gnttab_setup_auto_xlat_frames);
751
752void gnttab_free_auto_xlat_frames(void)
753{
754 if (!xen_auto_xlat_grant_frames.count)
755 return;
756 kfree(xen_auto_xlat_grant_frames.pfn);
757 xen_unmap(xen_auto_xlat_grant_frames.vaddr);
758
759 xen_auto_xlat_grant_frames.pfn = NULL;
760 xen_auto_xlat_grant_frames.count = 0;
761 xen_auto_xlat_grant_frames.vaddr = NULL;
762}
763EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames);
764
David Vrabelff4b1562015-01-08 18:06:01 +0000765/**
766 * gnttab_alloc_pages - alloc pages suitable for grant mapping into
767 * @nr_pages: number of pages to alloc
768 * @pages: returns the pages
769 */
770int gnttab_alloc_pages(int nr_pages, struct page **pages)
771{
Jennifer Herbert8da76332014-12-24 14:17:06 +0000772 int i;
David Vrabelff4b1562015-01-08 18:06:01 +0000773 int ret;
774
David Vrabel81b286e2015-06-25 13:12:46 +0100775 ret = alloc_xenballooned_pages(nr_pages, pages);
David Vrabelff4b1562015-01-08 18:06:01 +0000776 if (ret < 0)
777 return ret;
778
Jennifer Herbert8da76332014-12-24 14:17:06 +0000779 for (i = 0; i < nr_pages; i++) {
780#if BITS_PER_LONG < 64
781 struct xen_page_foreign *foreign;
782
783 foreign = kzalloc(sizeof(*foreign), GFP_KERNEL);
784 if (!foreign) {
785 gnttab_free_pages(nr_pages, pages);
786 return -ENOMEM;
787 }
788 set_page_private(pages[i], (unsigned long)foreign);
789#endif
790 SetPagePrivate(pages[i]);
791 }
792
David Vrabelff4b1562015-01-08 18:06:01 +0000793 return 0;
794}
795EXPORT_SYMBOL(gnttab_alloc_pages);
796
797/**
798 * gnttab_free_pages - free pages allocated by gnttab_alloc_pages()
799 * @nr_pages; number of pages to free
800 * @pages: the pages
801 */
802void gnttab_free_pages(int nr_pages, struct page **pages)
803{
Jennifer Herbert8da76332014-12-24 14:17:06 +0000804 int i;
805
806 for (i = 0; i < nr_pages; i++) {
807 if (PagePrivate(pages[i])) {
808#if BITS_PER_LONG < 64
809 kfree((void *)page_private(pages[i]));
810#endif
811 ClearPagePrivate(pages[i]);
812 }
813 }
David Vrabelff4b1562015-01-08 18:06:01 +0000814 free_xenballooned_pages(nr_pages, pages);
815}
816EXPORT_SYMBOL(gnttab_free_pages);
817
Andres Lagar-Cavillac5718982012-09-14 14:26:59 +0000818/* Handling of paged out grant targets (GNTST_eagain) */
819#define MAX_DELAY 256
820static inline void
821gnttab_retry_eagain_gop(unsigned int cmd, void *gop, int16_t *status,
822 const char *func)
823{
824 unsigned delay = 1;
825
826 do {
827 BUG_ON(HYPERVISOR_grant_table_op(cmd, gop, 1));
828 if (*status == GNTST_eagain)
829 msleep(delay++);
830 } while ((*status == GNTST_eagain) && (delay < MAX_DELAY));
831
832 if (delay >= MAX_DELAY) {
Joe Perches283c0972013-06-28 03:21:41 -0700833 pr_err("%s: %s eagain grant\n", func, current->comm);
Andres Lagar-Cavillac5718982012-09-14 14:26:59 +0000834 *status = GNTST_bad_page;
835 }
836}
837
838void gnttab_batch_map(struct gnttab_map_grant_ref *batch, unsigned count)
839{
840 struct gnttab_map_grant_ref *op;
841
842 if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, batch, count))
843 BUG();
844 for (op = batch; op < batch + count; op++)
845 if (op->status == GNTST_eagain)
846 gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, op,
847 &op->status, __func__);
848}
849EXPORT_SYMBOL_GPL(gnttab_batch_map);
850
851void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count)
852{
853 struct gnttab_copy *op;
854
855 if (HYPERVISOR_grant_table_op(GNTTABOP_copy, batch, count))
856 BUG();
857 for (op = batch; op < batch + count; op++)
858 if (op->status == GNTST_eagain)
859 gnttab_retry_eagain_gop(GNTTABOP_copy, op,
860 &op->status, __func__);
861}
862EXPORT_SYMBOL_GPL(gnttab_batch_copy);
863
Julien Grall008c3202015-06-19 17:49:03 +0100864void gnttab_foreach_grant_in_range(struct page *page,
865 unsigned int offset,
866 unsigned int len,
867 xen_grant_fn_t fn,
868 void *data)
869{
870 unsigned int goffset;
871 unsigned int glen;
872 unsigned long xen_pfn;
873
874 len = min_t(unsigned int, PAGE_SIZE - offset, len);
875 goffset = xen_offset_in_page(offset);
876
877 xen_pfn = page_to_xen_pfn(page) + XEN_PFN_DOWN(offset);
878
879 while (len) {
880 glen = min_t(unsigned int, XEN_PAGE_SIZE - goffset, len);
881 fn(pfn_to_gfn(xen_pfn), goffset, glen, data);
882
883 goffset = 0;
884 xen_pfn++;
885 len -= glen;
886 }
887}
888EXPORT_SYMBOL_GPL(gnttab_foreach_grant_in_range);
889
Julien Grallf73314b2015-10-13 17:50:12 +0100890void gnttab_foreach_grant(struct page **pages,
891 unsigned int nr_grefs,
892 xen_grant_fn_t fn,
893 void *data)
894{
895 unsigned int goffset = 0;
896 unsigned long xen_pfn = 0;
897 unsigned int i;
898
899 for (i = 0; i < nr_grefs; i++) {
900 if ((i % XEN_PFN_PER_PAGE) == 0) {
901 xen_pfn = page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);
902 goffset = 0;
903 }
904
905 fn(pfn_to_gfn(xen_pfn), goffset, XEN_PAGE_SIZE, data);
906
907 goffset += XEN_PAGE_SIZE;
908 xen_pfn++;
909 }
910}
911
Konrad Rzeszutek Wilke85fc982014-02-03 06:43:59 -0500912int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
Annie Lic1237992011-11-22 09:59:56 +0800913 struct gnttab_map_grant_ref *kmap_ops,
Konrad Rzeszutek Wilke85fc982014-02-03 06:43:59 -0500914 struct page **pages, unsigned int count)
Stefano Stabellini289b7772010-12-10 14:54:44 +0000915{
916 int i, ret;
Stefano Stabellini289b7772010-12-10 14:54:44 +0000917
918 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);
Jeremy Fitzhardinge87f1d402010-12-13 14:42:30 +0000919 if (ret)
920 return ret;
Stefano Stabellini289b7772010-12-10 14:54:44 +0000921
Jennifer Herbert8da76332014-12-24 14:17:06 +0000922 for (i = 0; i < count; i++) {
923 /* Retry eagain maps */
Andres Lagar-Cavillac5718982012-09-14 14:26:59 +0000924 if (map_ops[i].status == GNTST_eagain)
925 gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, map_ops + i,
926 &map_ops[i].status, __func__);
927
Jennifer Herbert8da76332014-12-24 14:17:06 +0000928 if (map_ops[i].status == GNTST_okay) {
929 struct xen_page_foreign *foreign;
930
931 SetPageForeign(pages[i]);
932 foreign = xen_page_foreign(pages[i]);
933 foreign->domid = map_ops[i].dom;
934 foreign->gref = map_ops[i].ref;
935 }
936 }
937
Zoltan Kiss1429d462014-02-27 15:55:30 +0000938 return set_foreign_p2m_mapping(map_ops, kmap_ops, pages, count);
Stefano Stabellini289b7772010-12-10 14:54:44 +0000939}
940EXPORT_SYMBOL_GPL(gnttab_map_refs);
941
Konrad Rzeszutek Wilke85fc982014-02-03 06:43:59 -0500942int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
David Vrabel853d0282015-01-05 14:13:41 +0000943 struct gnttab_unmap_grant_ref *kunmap_ops,
Konrad Rzeszutek Wilke85fc982014-02-03 06:43:59 -0500944 struct page **pages, unsigned int count)
Stefano Stabellini289b7772010-12-10 14:54:44 +0000945{
Jennifer Herbert8da76332014-12-24 14:17:06 +0000946 unsigned int i;
Zoltan Kiss1429d462014-02-27 15:55:30 +0000947 int ret;
Stefano Stabellini289b7772010-12-10 14:54:44 +0000948
949 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
Jeremy Fitzhardinge87f1d402010-12-13 14:42:30 +0000950 if (ret)
951 return ret;
952
Jennifer Herbert8da76332014-12-24 14:17:06 +0000953 for (i = 0; i < count; i++)
954 ClearPageForeign(pages[i]);
955
David Vrabel853d0282015-01-05 14:13:41 +0000956 return clear_foreign_p2m_mapping(unmap_ops, kunmap_ops, pages, count);
Stefano Stabellini289b7772010-12-10 14:54:44 +0000957}
958EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
959
Jennifer Herbert3f9f1c62014-12-09 18:28:37 +0000960#define GNTTAB_UNMAP_REFS_DELAY 5
961
962static void __gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item);
963
964static void gnttab_unmap_work(struct work_struct *work)
965{
966 struct gntab_unmap_queue_data
967 *unmap_data = container_of(work,
968 struct gntab_unmap_queue_data,
969 gnttab_work.work);
970 if (unmap_data->age != UINT_MAX)
971 unmap_data->age++;
972 __gnttab_unmap_refs_async(unmap_data);
973}
974
975static void __gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
976{
977 int ret;
978 int pc;
979
980 for (pc = 0; pc < item->count; pc++) {
981 if (page_count(item->pages[pc]) > 1) {
982 unsigned long delay = GNTTAB_UNMAP_REFS_DELAY * (item->age + 1);
983 schedule_delayed_work(&item->gnttab_work,
984 msecs_to_jiffies(delay));
985 return;
986 }
987 }
988
989 ret = gnttab_unmap_refs(item->unmap_ops, item->kunmap_ops,
990 item->pages, item->count);
991 item->done(ret, item);
992}
993
994void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
995{
996 INIT_DELAYED_WORK(&item->gnttab_work, gnttab_unmap_work);
997 item->age = 0;
998
999 __gnttab_unmap_refs_async(item);
1000}
1001EXPORT_SYMBOL_GPL(gnttab_unmap_refs_async);
1002
Bob Liub44166c2015-04-03 14:42:59 +08001003static void unmap_refs_callback(int result,
1004 struct gntab_unmap_queue_data *data)
1005{
1006 struct unmap_refs_callback_data *d = data->data;
1007
1008 d->result = result;
1009 complete(&d->completion);
1010}
1011
1012int gnttab_unmap_refs_sync(struct gntab_unmap_queue_data *item)
1013{
1014 struct unmap_refs_callback_data data;
1015
1016 init_completion(&data.completion);
1017 item->data = &data;
1018 item->done = &unmap_refs_callback;
1019 gnttab_unmap_refs_async(item);
1020 wait_for_completion(&data.completion);
1021
1022 return data.result;
1023}
1024EXPORT_SYMBOL_GPL(gnttab_unmap_refs_sync);
1025
Juergen Grossb988b8f2017-11-02 10:19:17 +01001026static unsigned int nr_status_frames(unsigned int nr_grant_frames)
1027{
Juergen Gross83c69322017-11-02 10:19:19 +01001028 BUG_ON(gnttab_interface == NULL);
1029 return gnttab_frames(nr_grant_frames, SPP);
Juergen Grossb988b8f2017-11-02 10:19:17 +01001030}
1031
Ian Campbellef32f892012-10-17 09:39:14 +01001032static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes)
Annie Li0f9f5a92011-11-22 09:58:06 +08001033{
1034 int rc;
1035
1036 rc = arch_gnttab_map_shared(frames, nr_gframes,
1037 gnttab_max_grant_frames(),
1038 &gnttab_shared.addr);
1039 BUG_ON(rc);
1040
1041 return 0;
1042}
1043
1044static void gnttab_unmap_frames_v1(void)
1045{
Annie Li85ff6ac2011-11-22 09:59:21 +08001046 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
1047}
1048
Juergen Grossb988b8f2017-11-02 10:19:17 +01001049static int gnttab_map_frames_v2(xen_pfn_t *frames, unsigned int nr_gframes)
1050{
1051 uint64_t *sframes;
1052 unsigned int nr_sframes;
1053 struct gnttab_get_status_frames getframes;
1054 int rc;
1055
1056 nr_sframes = nr_status_frames(nr_gframes);
1057
1058 /* No need for kzalloc as it is initialized in following hypercall
1059 * GNTTABOP_get_status_frames.
1060 */
1061 sframes = kmalloc_array(nr_sframes, sizeof(uint64_t), GFP_ATOMIC);
1062 if (!sframes)
1063 return -ENOMEM;
1064
1065 getframes.dom = DOMID_SELF;
1066 getframes.nr_frames = nr_sframes;
1067 set_xen_guest_handle(getframes.frame_list, sframes);
1068
1069 rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
1070 &getframes, 1);
1071 if (rc == -ENOSYS) {
1072 kfree(sframes);
1073 return -ENOSYS;
1074 }
1075
1076 BUG_ON(rc || getframes.status);
1077
1078 rc = arch_gnttab_map_status(sframes, nr_sframes,
1079 nr_status_frames(gnttab_max_grant_frames()),
1080 &grstatus);
1081 BUG_ON(rc);
1082 kfree(sframes);
1083
1084 rc = arch_gnttab_map_shared(frames, nr_gframes,
1085 gnttab_max_grant_frames(),
1086 &gnttab_shared.addr);
1087 BUG_ON(rc);
1088
1089 return 0;
1090}
1091
1092static void gnttab_unmap_frames_v2(void)
1093{
1094 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
1095 arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames));
1096}
1097
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001098static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
1099{
1100 struct gnttab_setup_table setup;
Ian Campbellef32f892012-10-17 09:39:14 +01001101 xen_pfn_t *frames;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001102 unsigned int nr_gframes = end_idx + 1;
1103 int rc;
1104
Konrad Rzeszutek Wilk6926f6d2014-01-03 10:20:18 -05001105 if (xen_feature(XENFEAT_auto_translated_physmap)) {
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001106 struct xen_add_to_physmap xatp;
1107 unsigned int i = end_idx;
1108 rc = 0;
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -05001109 BUG_ON(xen_auto_xlat_grant_frames.count < nr_gframes);
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001110 /*
1111 * Loop backwards, so that the first hypercall has the largest
1112 * index, ensuring that the table will grow only once.
1113 */
1114 do {
1115 xatp.domid = DOMID_SELF;
1116 xatp.idx = i;
1117 xatp.space = XENMAPSPACE_grant_table;
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -05001118 xatp.gpfn = xen_auto_xlat_grant_frames.pfn[i];
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001119 rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
1120 if (rc != 0) {
Joe Perches283c0972013-06-28 03:21:41 -07001121 pr_warn("grant table add_to_physmap failed, err=%d\n",
1122 rc);
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001123 break;
1124 }
1125 } while (i-- > start_idx);
1126
1127 return rc;
1128 }
1129
Annie Li85ff6ac2011-11-22 09:59:21 +08001130 /* No need for kzalloc as it is initialized in following hypercall
1131 * GNTTABOP_setup_table.
1132 */
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001133 frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
1134 if (!frames)
1135 return -ENOMEM;
1136
1137 setup.dom = DOMID_SELF;
1138 setup.nr_frames = nr_gframes;
Isaku Yamahata87e27cf2008-04-02 10:53:52 -07001139 set_xen_guest_handle(setup.frame_list, frames);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001140
1141 rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
1142 if (rc == -ENOSYS) {
1143 kfree(frames);
1144 return -ENOSYS;
1145 }
1146
1147 BUG_ON(rc || setup.status);
1148
Annie Li0f9f5a92011-11-22 09:58:06 +08001149 rc = gnttab_interface->map_frames(frames, nr_gframes);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001150
1151 kfree(frames);
1152
Annie Li0f9f5a92011-11-22 09:58:06 +08001153 return rc;
1154}
1155
Julia Lawall86fc2132015-11-28 15:28:40 +01001156static const struct gnttab_ops gnttab_v1_ops = {
Juergen Gross83c69322017-11-02 10:19:19 +01001157 .version = 1,
1158 .grefs_per_grant_frame = XEN_PAGE_SIZE /
1159 sizeof(struct grant_entry_v1),
Annie Li0f9f5a92011-11-22 09:58:06 +08001160 .map_frames = gnttab_map_frames_v1,
1161 .unmap_frames = gnttab_unmap_frames_v1,
1162 .update_entry = gnttab_update_entry_v1,
1163 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v1,
1164 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1,
1165 .query_foreign_access = gnttab_query_foreign_access_v1,
1166};
1167
Juergen Grossb988b8f2017-11-02 10:19:17 +01001168static const struct gnttab_ops gnttab_v2_ops = {
Juergen Gross83c69322017-11-02 10:19:19 +01001169 .version = 2,
1170 .grefs_per_grant_frame = XEN_PAGE_SIZE /
1171 sizeof(union grant_entry_v2),
Juergen Grossb988b8f2017-11-02 10:19:17 +01001172 .map_frames = gnttab_map_frames_v2,
1173 .unmap_frames = gnttab_unmap_frames_v2,
1174 .update_entry = gnttab_update_entry_v2,
1175 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2,
1176 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2,
1177 .query_foreign_access = gnttab_query_foreign_access_v2,
Juergen Grossb988b8f2017-11-02 10:19:17 +01001178};
1179
Annie Li0f9f5a92011-11-22 09:58:06 +08001180static void gnttab_request_version(void)
1181{
Juergen Grossb988b8f2017-11-02 10:19:17 +01001182 int rc;
1183 struct gnttab_set_version gsv;
Annie Li85ff6ac2011-11-22 09:59:21 +08001184
Juergen Grossb988b8f2017-11-02 10:19:17 +01001185 gsv.version = 1;
1186
1187 rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
Juergen Gross83c69322017-11-02 10:19:19 +01001188 if (rc == 0 && gsv.version == 2)
Juergen Grossb988b8f2017-11-02 10:19:17 +01001189 gnttab_interface = &gnttab_v2_ops;
Juergen Gross83c69322017-11-02 10:19:19 +01001190 else
Juergen Grossb988b8f2017-11-02 10:19:17 +01001191 gnttab_interface = &gnttab_v1_ops;
Juergen Gross83c69322017-11-02 10:19:19 +01001192 pr_info("Grant tables using version %d layout\n",
1193 gnttab_interface->version);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001194}
1195
Matt Wilsond0b4d642013-01-15 13:21:27 +00001196static int gnttab_setup(void)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001197{
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001198 unsigned int max_nr_gframes;
1199
1200 max_nr_gframes = gnttab_max_grant_frames();
1201 if (max_nr_gframes < nr_grant_frames)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001202 return -ENOSYS;
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001203
Konrad Rzeszutek Wilk45684752013-12-31 16:33:31 -05001204 if (xen_feature(XENFEAT_auto_translated_physmap) && gnttab_shared.addr == NULL) {
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -05001205 gnttab_shared.addr = xen_auto_xlat_grant_frames.vaddr;
Annie Li0f9f5a92011-11-22 09:58:06 +08001206 if (gnttab_shared.addr == NULL) {
Konrad Rzeszutek Wilkefaf30a2014-01-06 10:40:36 -05001207 pr_warn("gnttab share frames (addr=0x%08lx) is not mapped!\n",
1208 (unsigned long)xen_auto_xlat_grant_frames.vaddr);
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001209 return -ENOMEM;
1210 }
1211 }
Konrad Rzeszutek Wilk45684752013-12-31 16:33:31 -05001212 return gnttab_map(0, nr_grant_frames - 1);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001213}
1214
Matt Wilsond0b4d642013-01-15 13:21:27 +00001215int gnttab_resume(void)
1216{
1217 gnttab_request_version();
1218 return gnttab_setup();
1219}
1220
Jeremy Fitzhardinge0e913982008-05-26 23:31:27 +01001221int gnttab_suspend(void)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001222{
David Vrabel13cd36a2014-06-16 11:12:03 +01001223 if (!xen_feature(XENFEAT_auto_translated_physmap))
1224 gnttab_interface->unmap_frames();
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001225 return 0;
1226}
1227
1228static int gnttab_expand(unsigned int req_entries)
1229{
1230 int rc;
1231 unsigned int cur, extra;
1232
Juergen Gross83c69322017-11-02 10:19:19 +01001233 BUG_ON(gnttab_interface == NULL);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001234 cur = nr_grant_frames;
Juergen Gross83c69322017-11-02 10:19:19 +01001235 extra = ((req_entries + gnttab_interface->grefs_per_grant_frame - 1) /
1236 gnttab_interface->grefs_per_grant_frame);
Wengang Wang29d11cfd2017-07-18 09:40:35 +02001237 if (cur + extra > gnttab_max_grant_frames()) {
1238 pr_warn_ratelimited("xen/grant-table: max_grant_frames reached"
1239 " cur=%u extra=%u limit=%u"
1240 " gnttab_free_count=%u req_entries=%u\n",
1241 cur, extra, gnttab_max_grant_frames(),
1242 gnttab_free_count, req_entries);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001243 return -ENOSPC;
Wengang Wang29d11cfd2017-07-18 09:40:35 +02001244 }
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001245
1246 rc = gnttab_map(cur, cur + extra - 1);
1247 if (rc == 0)
1248 rc = grow_gnttab_list(extra);
1249
1250 return rc;
1251}
1252
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001253int gnttab_init(void)
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001254{
1255 int i;
David Vrabel162e3712014-07-11 16:42:34 +01001256 unsigned long max_nr_grant_frames;
Michael Abd-El-Malekbbc60c12008-04-04 02:33:48 -07001257 unsigned int max_nr_glist_frames, nr_glist_frames;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001258 unsigned int nr_init_grefs;
Julia Lawall6b5e7d92012-04-15 11:27:12 +02001259 int ret;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001260
Matt Wilsond0b4d642013-01-15 13:21:27 +00001261 gnttab_request_version();
David Vrabel162e3712014-07-11 16:42:34 +01001262 max_nr_grant_frames = gnttab_max_grant_frames();
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001263 nr_grant_frames = 1;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001264
1265 /* Determine the maximum number of frames required for the
1266 * grant reference free list on the current hypervisor.
1267 */
Juergen Gross83c69322017-11-02 10:19:19 +01001268 BUG_ON(gnttab_interface == NULL);
David Vrabel162e3712014-07-11 16:42:34 +01001269 max_nr_glist_frames = (max_nr_grant_frames *
Juergen Gross83c69322017-11-02 10:19:19 +01001270 gnttab_interface->grefs_per_grant_frame / RPP);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001271
1272 gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
1273 GFP_KERNEL);
1274 if (gnttab_list == NULL)
1275 return -ENOMEM;
1276
Juergen Gross83c69322017-11-02 10:19:19 +01001277 nr_glist_frames = gnttab_frames(nr_grant_frames, RPP);
Michael Abd-El-Malekbbc60c12008-04-04 02:33:48 -07001278 for (i = 0; i < nr_glist_frames; i++) {
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001279 gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
Julia Lawall6b5e7d92012-04-15 11:27:12 +02001280 if (gnttab_list[i] == NULL) {
1281 ret = -ENOMEM;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001282 goto ini_nomem;
Julia Lawall6b5e7d92012-04-15 11:27:12 +02001283 }
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001284 }
1285
Juergen Grossb988b8f2017-11-02 10:19:17 +01001286 ret = arch_gnttab_init(max_nr_grant_frames,
1287 nr_status_frames(max_nr_grant_frames));
David Vrabel162e3712014-07-11 16:42:34 +01001288 if (ret < 0)
1289 goto ini_nomem;
1290
Matt Wilsond0b4d642013-01-15 13:21:27 +00001291 if (gnttab_setup() < 0) {
Julia Lawall6b5e7d92012-04-15 11:27:12 +02001292 ret = -ENODEV;
1293 goto ini_nomem;
1294 }
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001295
Juergen Gross83c69322017-11-02 10:19:19 +01001296 nr_init_grefs = nr_grant_frames *
1297 gnttab_interface->grefs_per_grant_frame;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001298
1299 for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
1300 gnttab_entry(i) = i + 1;
1301
1302 gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
1303 gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
1304 gnttab_free_head = NR_RESERVED_ENTRIES;
1305
1306 printk("Grant table initialized\n");
1307 return 0;
1308
1309 ini_nomem:
1310 for (i--; i >= 0; i--)
1311 free_page((unsigned long)gnttab_list[i]);
1312 kfree(gnttab_list);
Julia Lawall6b5e7d92012-04-15 11:27:12 +02001313 return ret;
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001314}
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001315EXPORT_SYMBOL_GPL(gnttab_init);
Jeremy Fitzhardingead9a8612007-07-17 18:37:06 -07001316
Greg Kroah-Hartman345a5252012-12-21 13:00:00 -08001317static int __gnttab_init(void)
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001318{
Boris Ostrovsky8613d782017-02-06 10:56:15 -05001319 if (!xen_domain())
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001320 return -ENODEV;
1321
Boris Ostrovsky8613d782017-02-06 10:56:15 -05001322 /* Delay grant-table initialization in the PV on HVM case */
1323 if (xen_hvm_domain() && !xen_pvh_domain())
1324 return 0;
1325
Stefano Stabellini183d03c2010-05-17 17:08:21 +01001326 return gnttab_init();
1327}
Konrad Rzeszutek Wilk6926f6d2014-01-03 10:20:18 -05001328/* Starts after core_initcall so that xen_pvh_gnttab_setup can be called
1329 * beforehand to initialize xen_auto_xlat_grant_frames. */
1330core_initcall_sync(__gnttab_init);