Skip to content

Commit

Permalink
xen/granttable: Introducing grant table V2 stucture
Browse files Browse the repository at this point in the history
This patch introduces new structures of grant table V2, grant table V2 is an
extension from V1. Grant table is shared between guest and Xen, and Xen is
responsible to do corresponding work for grant operations, such as: figure
out guest's grant table version, perform different actions based on
different grant table version, etc. Although full-page structure of V2
is different from V1, it play the same role as V1.

Acked-by: Ian Campbell <[email protected]>
Signed-off-by: Annie Li <[email protected]>
Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>
  • Loading branch information
annie-li authored and konradwilk committed Nov 22, 2011
1 parent 3b456ae commit 0f9f5a9
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 51 deletions.
7 changes: 3 additions & 4 deletions arch/x86/xen/grant-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,

int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
unsigned long max_nr_gframes,
struct grant_entry **__shared)
void **__shared)
{
int rc;
struct grant_entry *shared = *__shared;
void *shared = *__shared;

if (shared == NULL) {
struct vm_struct *area =
Expand All @@ -83,8 +83,7 @@ int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
return rc;
}

void arch_gnttab_unmap_shared(struct grant_entry *shared,
unsigned long nr_gframes)
void arch_gnttab_unmap_shared(void *shared, unsigned long nr_gframes)
{
apply_to_page_range(&init_mm, (unsigned long)shared,
PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL);
Expand Down
181 changes: 141 additions & 40 deletions drivers/xen/grant-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
/* External tools reserve first few grant table entries. */
#define NR_RESERVED_ENTRIES 8
#define GNTTAB_LIST_END 0xffffffff
#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry_v1))

static grant_ref_t **gnttab_list;
static unsigned int nr_grant_frames;
Expand All @@ -64,7 +64,63 @@ static DEFINE_SPINLOCK(gnttab_list_lock);
unsigned long xen_hvm_resume_frames;
EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);

static struct grant_entry *shared;
static union {
struct grant_entry_v1 *v1;
void *addr;
} gnttab_shared;

/*This is a structure of function pointers for grant table*/
struct gnttab_ops {
/*
* Mapping a list of frames for storing grant entries. First input
* parameter is used to storing grant table address when grant table
* being setup, second parameter is the number of frames to map grant
* table. Returning GNTST_okay means success and negative value means
* failure.
*/
int (*map_frames)(unsigned long *, unsigned int);
/*
* Release a list of frames which are mapped in map_frames for grant
* entry status.
*/
void (*unmap_frames)(void);
/*
* Introducing a valid entry into the grant table, granting the frame
* of this grant entry to domain for accessing, or transfering, or
* transitively accessing. First input parameter is reference of this
* introduced grant entry, second one is domid of granted domain, third
* one is the frame to be granted, and the last one is status of the
* grant entry to be updated.
*/
void (*update_entry)(grant_ref_t, domid_t, unsigned long, unsigned);
/*
* Stop granting a grant entry to domain for accessing. First input
* parameter is reference of a grant entry whose grant access will be
* stopped, second one is not in use now. If the grant entry is
* currently mapped for reading or writing, just return failure(==0)
* directly and don't tear down the grant access. Otherwise, stop grant
* access for this entry and return success(==1).
*/
int (*end_foreign_access_ref)(grant_ref_t, int);
/*
* Stop granting a grant entry to domain for transfer. If tranfer has
* not started, just reclaim the grant entry and return failure(==0).
* Otherwise, wait for the transfer to complete and then return the
* frame.
*/
unsigned long (*end_foreign_transfer_ref)(grant_ref_t);
/*
* Query the status of a grant entry. Input parameter is reference of
* queried grant entry, return value is the status of queried entry.
* Detailed status(writing/reading) can be gotten from the return value
* by bit operations.
*/
int (*query_foreign_access)(grant_ref_t);
};

static struct gnttab_ops *gnttab_interface;

static int grant_table_version;

static struct gnttab_free_callback *gnttab_free_callback_list;

Expand Down Expand Up @@ -142,23 +198,23 @@ static void put_free_entry(grant_ref_t ref)
spin_unlock_irqrestore(&gnttab_list_lock, flags);
}

static void update_grant_entry(grant_ref_t ref, domid_t domid,
unsigned long frame, unsigned flags)
/*
* Introducing a valid entry into the grant table:
* 1. Write ent->domid.
* 2. Write ent->frame:
* GTF_permit_access: Frame to which access is permitted.
* GTF_accept_transfer: Pseudo-phys frame slot being filled by new
* frame, or zero if none.
* 3. Write memory barrier (WMB).
* 4. Write ent->flags, inc. valid type.
*/
static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
unsigned long frame, unsigned flags)
{
/*
* Introducing a valid entry into the grant table:
* 1. Write ent->domid.
* 2. Write ent->frame:
* GTF_permit_access: Frame to which access is permitted.
* GTF_accept_transfer: Pseudo-phys frame slot being filled by new
* frame, or zero if none.
* 3. Write memory barrier (WMB).
* 4. Write ent->flags, inc. valid type.
*/
shared[ref].frame = frame;
shared[ref].domid = domid;
gnttab_shared.v1[ref].domid = domid;
gnttab_shared.v1[ref].frame = frame;
wmb();
shared[ref].flags = flags;
gnttab_shared.v1[ref].flags = flags;
}

/*
Expand All @@ -167,7 +223,7 @@ static void update_grant_entry(grant_ref_t ref, domid_t domid,
void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
unsigned long frame, int readonly)
{
update_grant_entry(ref, domid, frame,
gnttab_interface->update_entry(ref, domid, frame,
GTF_permit_access | (readonly ? GTF_readonly : 0));
}
EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
Expand All @@ -187,31 +243,37 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
}
EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);

int gnttab_query_foreign_access(grant_ref_t ref)
static int gnttab_query_foreign_access_v1(grant_ref_t ref)
{
u16 nflags;

nflags = shared[ref].flags;
return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
}

return nflags & (GTF_reading|GTF_writing);
int gnttab_query_foreign_access(grant_ref_t ref)
{
return gnttab_interface->query_foreign_access(ref);
}
EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);

int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
{
u16 flags, nflags;

nflags = shared[ref].flags;
nflags = gnttab_shared.v1[ref].flags;
do {
flags = nflags;
if (flags & (GTF_reading|GTF_writing)) {
printk(KERN_ALERT "WARNING: g.e. still in use!\n");
return 0;
}
} while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
} while ((nflags = sync_cmpxchg(&gnttab_shared.v1[ref].flags, flags, 0)) != flags);

return 1;
}

int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
{
return gnttab_interface->end_foreign_access_ref(ref, readonly);
}
EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);

void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
Expand Down Expand Up @@ -246,11 +308,11 @@ EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
unsigned long pfn)
{
update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer);
}
EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);

unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
{
unsigned long frame;
u16 flags;
Expand All @@ -259,24 +321,29 @@ unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
* If a transfer is not even yet started, try to reclaim the grant
* reference and return failure (== 0).
*/
while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
while (!((flags = gnttab_shared.v1[ref].flags) & GTF_transfer_committed)) {
if (sync_cmpxchg(&gnttab_shared.v1[ref].flags, flags, 0) == flags)
return 0;
cpu_relax();
}

/* If a transfer is in progress then wait until it is completed. */
while (!(flags & GTF_transfer_completed)) {
flags = shared[ref].flags;
flags = gnttab_shared.v1[ref].flags;
cpu_relax();
}

rmb(); /* Read the frame number /after/ reading completion status. */
frame = shared[ref].frame;
frame = gnttab_shared.v1[ref].frame;
BUG_ON(frame == 0);

return frame;
}

unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
{
return gnttab_interface->end_foreign_transfer_ref(ref);
}
EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);

unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
Expand Down Expand Up @@ -520,6 +587,23 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
}
EXPORT_SYMBOL_GPL(gnttab_unmap_refs);

static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes)
{
int rc;

rc = arch_gnttab_map_shared(frames, nr_gframes,
gnttab_max_grant_frames(),
&gnttab_shared.addr);
BUG_ON(rc);

return 0;
}

static void gnttab_unmap_frames_v1(void)
{
arch_gnttab_unmap_shared(gnttab_shared.addr, nr_grant_frames);
}

static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
struct gnttab_setup_table setup;
Expand Down Expand Up @@ -567,29 +651,46 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)

BUG_ON(rc || setup.status);

rc = arch_gnttab_map_shared(frames, nr_gframes, gnttab_max_grant_frames(),
&shared);
BUG_ON(rc);
rc = gnttab_interface->map_frames(frames, nr_gframes);

kfree(frames);

return 0;
return rc;
}

static struct gnttab_ops gnttab_v1_ops = {
.map_frames = gnttab_map_frames_v1,
.unmap_frames = gnttab_unmap_frames_v1,
.update_entry = gnttab_update_entry_v1,
.end_foreign_access_ref = gnttab_end_foreign_access_ref_v1,
.end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1,
.query_foreign_access = gnttab_query_foreign_access_v1,
};

static void gnttab_request_version(void)
{
grant_table_version = 1;
gnttab_interface = &gnttab_v1_ops;
printk(KERN_INFO "Grant tables using version %d layout.\n",
grant_table_version);
}

int gnttab_resume(void)
{
unsigned int max_nr_gframes;

gnttab_request_version();
max_nr_gframes = gnttab_max_grant_frames();
if (max_nr_gframes < nr_grant_frames)
return -ENOSYS;

if (xen_pv_domain())
return gnttab_map(0, nr_grant_frames - 1);

if (!shared) {
shared = ioremap(xen_hvm_resume_frames, PAGE_SIZE * max_nr_gframes);
if (shared == NULL) {
if (gnttab_shared.addr == NULL) {
gnttab_shared.addr = ioremap(xen_hvm_resume_frames,
PAGE_SIZE * max_nr_gframes);
if (gnttab_shared.addr == NULL) {
printk(KERN_WARNING
"Failed to ioremap gnttab share frames!");
return -ENOMEM;
Expand All @@ -603,7 +704,7 @@ int gnttab_resume(void)

int gnttab_suspend(void)
{
arch_gnttab_unmap_shared(shared, nr_grant_frames);
gnttab_interface->unmap_frames();
return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions include/xen/grant_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, phys_addr_t addr,

int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
unsigned long max_nr_gframes,
struct grant_entry **__shared);
void arch_gnttab_unmap_shared(struct grant_entry *shared,
void **__shared);
void arch_gnttab_unmap_shared(void *shared,
unsigned long nr_gframes);

extern unsigned long xen_hvm_resume_frames;
Expand Down
Loading

0 comments on commit 0f9f5a9

Please sign in to comment.