summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-driver-pciback26
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/arm/xen/grant-table.c6
-rw-r--r--arch/x86/xen/enlighten.c13
-rw-r--r--arch/x86/xen/grant-table.c106
-rw-r--r--drivers/xen/grant-table.c314
-rw-r--r--drivers/xen/xen-pciback/passthrough.c14
-rw-r--r--drivers/xen/xen-pciback/pci_stub.c42
-rw-r--r--drivers/xen/xen-pciback/pciback.h7
-rw-r--r--drivers/xen/xen-pciback/vpci.c14
-rw-r--r--drivers/xen/xen-pciback/xenbus.c4
-rw-r--r--include/linux/device.h5
-rw-r--r--include/xen/grant_table.h29
14 files changed, 166 insertions, 425 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-pciback b/Documentation/ABI/testing/sysfs-driver-pciback
new file mode 100644
index 000000000000..8440aa721951
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-pciback
@@ -0,0 +1,26 @@
+What: /sys/bus/pci/drivers/pciback/quirks
+Date: Oct 2011
+KernelVersion: 3.1
+Contact: xen-devel@lists.xenproject.org
+Description:
+ If the permissive attribute is set, then writing a string in
+ the format of DDDD:BB:DD.F-REG:SIZE:MASK will allow the guest
+ to write and read from the PCI device. That is Domain:Bus:
+ Device.Function-Register:Size:Mask (Domain is optional).
+ For example:
+ #echo 00:19.0-E0:2:FF > /sys/bus/pci/drivers/pciback/quirks
+ will allow the guest to read and write to the configuration
+ register 0x0E.
+
+What: /sys/bus/pci/drivers/pciback/irq_handlers
+Date: Oct 2011
+KernelVersion: 3.1
+Contact: xen-devel@lists.xenproject.org
+Description:
+ A list of all of the PCI devices owned by Xen PCI back and
+ whether Xen PCI backend will acknowledge the interrupts received
+ and the amount of interrupts received. Xen PCI back acknowledges
+ said interrupts only when they are level, shared with another
+ guest, whether it will acknowledge interrupts, and enabled by
+ the guest.
+
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 04de29c341b9..bdbecac35b52 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3747,6 +3747,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Disables the ticketlock slowpath using Xen PV
optimizations.
+ xen_nopv [X86]
+ Disables the PV optimizations forcing the HVM guest to
+ run as generic HVM guest with no PV drivers.
+
xirc2ps_cs= [NET,PCMCIA]
Format:
<irq>,<irq_mask>,<io>,<full_duplex>,<do_sound>,<lockup_hack>[,<irq2>[,<irq3>[,<irq4>]]]
diff --git a/MAINTAINERS b/MAINTAINERS
index 7582e75a776e..15fdd27b4fc3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10077,6 +10077,13 @@ S: Supported
F: arch/x86/pci/*xen*
F: drivers/pci/*xen*
+XEN BLOCK SUBSYSTEM
+M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
+S: Supported
+F: drivers/block/xen-blkback/*
+F: drivers/block/xen*
+
XEN SWIOTLB SUBSYSTEM
M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
diff --git a/arch/arm/xen/grant-table.c b/arch/arm/xen/grant-table.c
index 859a9bb002d5..e43791829ace 100644
--- a/arch/arm/xen/grant-table.c
+++ b/arch/arm/xen/grant-table.c
@@ -45,9 +45,7 @@ void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
return;
}
-int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
- unsigned long max_nr_gframes,
- grant_status_t **__shared)
+int arch_gnttab_init(unsigned long nr_shared)
{
- return -ENOSYS;
+ return 0;
}
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index ffb101e45731..eb822391b84c 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1826,8 +1826,19 @@ static void __init xen_hvm_guest_init(void)
xen_hvm_init_mmu_ops();
}
+static bool xen_nopv = false;
+static __init int xen_parse_nopv(char *arg)
+{
+ xen_nopv = true;
+ return 0;
+}
+early_param("xen_nopv", xen_parse_nopv);
+
static uint32_t __init xen_hvm_platform(void)
{
+ if (xen_nopv)
+ return 0;
+
if (xen_pv_domain())
return 0;
@@ -1836,6 +1847,8 @@ static uint32_t __init xen_hvm_platform(void)
bool xen_hvm_need_lapic(void)
{
+ if (xen_nopv)
+ return false;
if (xen_pv_domain())
return false;
if (!xen_hvm_domain())
diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c
index c98583588580..c0413046483a 100644
--- a/arch/x86/xen/grant-table.c
+++ b/arch/x86/xen/grant-table.c
@@ -36,99 +36,83 @@
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <xen/interface/xen.h>
#include <xen/page.h>
#include <xen/grant_table.h>
+#include <xen/xen.h>
#include <asm/pgtable.h>
-static int map_pte_fn(pte_t *pte, struct page *pmd_page,
- unsigned long addr, void *data)
+static struct gnttab_vm_area {
+ struct vm_struct *area;
+ pte_t **ptes;
+} gnttab_shared_vm_area;
+
+int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
+ unsigned long max_nr_gframes,
+ void **__shared)
{
- unsigned long **frames = (unsigned long **)data;
+ void *shared = *__shared;
+ unsigned long addr;
+ unsigned long i;
- set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
- (*frames)++;
- return 0;
-}
+ if (shared == NULL)
+ *__shared = shared = gnttab_shared_vm_area.area->addr;
-/*
- * This function is used to map shared frames to store grant status. It is
- * different from map_pte_fn above, the frames type here is uint64_t.
- */
-static int map_pte_fn_status(pte_t *pte, struct page *pmd_page,
- unsigned long addr, void *data)
-{
- uint64_t **frames = (uint64_t **)data;
+ addr = (unsigned long)shared;
+
+ for (i = 0; i < nr_gframes; i++) {
+ set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i],
+ mfn_pte(frames[i], PAGE_KERNEL));
+ addr += PAGE_SIZE;
+ }
- set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
- (*frames)++;
return 0;
}
-static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
- unsigned long addr, void *data)
+void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
{
+ unsigned long addr;
+ unsigned long i;
- set_pte_at(&init_mm, addr, pte, __pte(0));
- return 0;
+ addr = (unsigned long)shared;
+
+ for (i = 0; i < nr_gframes; i++) {
+ set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i],
+ __pte(0));
+ addr += PAGE_SIZE;
+ }
}
-int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
- unsigned long max_nr_gframes,
- void **__shared)
+static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames)
{
- int rc;
- void *shared = *__shared;
+ area->ptes = kmalloc(sizeof(pte_t *) * nr_frames, GFP_KERNEL);
+ if (area->ptes == NULL)
+ return -ENOMEM;
- if (shared == NULL) {
- struct vm_struct *area =
- alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
- BUG_ON(area == NULL);
- shared = area->addr;
- *__shared = shared;
+ area->area = alloc_vm_area(PAGE_SIZE * nr_frames, area->ptes);
+ if (area->area == NULL) {
+ kfree(area->ptes);
+ return -ENOMEM;
}
- rc = apply_to_page_range(&init_mm, (unsigned long)shared,
- PAGE_SIZE * nr_gframes,
- map_pte_fn, &frames);
- return rc;
+ return 0;
}
-int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
- unsigned long max_nr_gframes,
- grant_status_t **__shared)
+int arch_gnttab_init(unsigned long nr_shared)
{
- int rc;
- grant_status_t *shared = *__shared;
-
- if (shared == NULL) {
- /* No need to pass in PTE as we are going to do it
- * in apply_to_page_range anyhow. */
- struct vm_struct *area =
- alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
- BUG_ON(area == NULL);
- shared = area->addr;
- *__shared = shared;
- }
+ if (!xen_pv_domain())
+ return 0;
- rc = apply_to_page_range(&init_mm, (unsigned long)shared,
- PAGE_SIZE * nr_gframes,
- map_pte_fn_status, &frames);
- return rc;
+ return arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared);
}
-void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
-{
- apply_to_page_range(&init_mm, (unsigned long)shared,
- PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL);
-}
#ifdef CONFIG_XEN_PVH
#include <xen/balloon.h>
#include <xen/events.h>
-#include <xen/xen.h>
#include <linux/slab.h>
static int __init xlated_setup_gnttab_pages(void)
{
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 5d4de88fe5b8..c254ae036f18 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -69,7 +69,6 @@ struct grant_frames xen_auto_xlat_grant_frames;
static union {
struct grant_entry_v1 *v1;
- union grant_entry_v2 *v2;
void *addr;
} gnttab_shared;
@@ -120,36 +119,10 @@ struct gnttab_ops {
* by bit operations.
*/
int (*query_foreign_access)(grant_ref_t ref);
- /*
- * Grant a domain to access a range of bytes within the page referred by
- * an available grant entry. Ref parameter is reference of a grant entry
- * which will be sub-page accessed, domid is id of grantee domain, frame
- * is frame address of subpage grant, flags is grant type and flag
- * information, page_off is offset of the range of bytes, and length is
- * length of bytes to be accessed.
- */
- void (*update_subpage_entry)(grant_ref_t ref, domid_t domid,
- unsigned long frame, int flags,
- unsigned page_off, unsigned length);
- /*
- * Redirect an available grant entry on domain A to another grant
- * reference of domain B, then allow domain C to use grant reference
- * of domain B transitively. Ref parameter is an available grant entry
- * reference on domain A, domid is id of domain C which accesses grant
- * entry transitively, flags is grant type and flag information,
- * trans_domid is id of domain B whose grant entry is finally accessed
- * transitively, trans_gref is grant entry transitive reference of
- * domain B.
- */
- void (*update_trans_entry)(grant_ref_t ref, domid_t domid, int flags,
- domid_t trans_domid, grant_ref_t trans_gref);
};
static struct gnttab_ops *gnttab_interface;
-/*This reflects status of grant entries, so act as a global value*/
-static grant_status_t *grstatus;
-
static int grant_table_version;
static int grefs_per_grant_frame;
@@ -231,7 +204,7 @@ static void put_free_entry(grant_ref_t ref)
}
/*
- * Following applies to gnttab_update_entry_v1 and gnttab_update_entry_v2.
+ * Following applies to gnttab_update_entry_v1.
* Introducing a valid entry into the grant table:
* 1. Write ent->domid.
* 2. Write ent->frame:
@@ -250,15 +223,6 @@ static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
gnttab_shared.v1[ref].flags = flags;
}
-static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid,
- unsigned long frame, unsigned flags)
-{
- gnttab_shared.v2[ref].hdr.domid = domid;
- gnttab_shared.v2[ref].full_page.frame = frame;
- wmb();
- gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags;
-}
-
/*
* Public grant-issuing interface functions
*/
@@ -285,132 +249,11 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
}
EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
-static void gnttab_update_subpage_entry_v2(grant_ref_t ref, domid_t domid,
- unsigned long frame, int flags,
- unsigned page_off, unsigned length)
-{
- gnttab_shared.v2[ref].sub_page.frame = frame;
- gnttab_shared.v2[ref].sub_page.page_off = page_off;
- gnttab_shared.v2[ref].sub_page.length = length;
- gnttab_shared.v2[ref].hdr.domid = domid;
- wmb();
- gnttab_shared.v2[ref].hdr.flags =
- GTF_permit_access | GTF_sub_page | flags;
-}
-
-int gnttab_grant_foreign_access_subpage_ref(grant_ref_t ref, domid_t domid,
- unsigned long frame, int flags,
- unsigned page_off,
- unsigned length)
-{
- if (flags & (GTF_accept_transfer | GTF_reading |
- GTF_writing | GTF_transitive))
- return -EPERM;
-
- if (gnttab_interface->update_subpage_entry == NULL)
- return -ENOSYS;
-
- gnttab_interface->update_subpage_entry(ref, domid, frame, flags,
- page_off, length);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage_ref);
-
-int gnttab_grant_foreign_access_subpage(domid_t domid, unsigned long frame,
- int flags, unsigned page_off,
- unsigned length)
-{
- int ref, rc;
-
- ref = get_free_entries(1);
- if (unlikely(ref < 0))
- return -ENOSPC;
-
- rc = gnttab_grant_foreign_access_subpage_ref(ref, domid, frame, flags,
- page_off, length);
- if (rc < 0) {
- put_free_entry(ref);
- return rc;
- }
-
- return ref;
-}
-EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage);
-
-bool gnttab_subpage_grants_available(void)
-{
- return gnttab_interface->update_subpage_entry != NULL;
-}
-EXPORT_SYMBOL_GPL(gnttab_subpage_grants_available);
-
-static void gnttab_update_trans_entry_v2(grant_ref_t ref, domid_t domid,
- int flags, domid_t trans_domid,
- grant_ref_t trans_gref)
-{
- gnttab_shared.v2[ref].transitive.trans_domid = trans_domid;
- gnttab_shared.v2[ref].transitive.gref = trans_gref;
- gnttab_shared.v2[ref].hdr.domid = domid;
- wmb();
- gnttab_shared.v2[ref].hdr.flags =
- GTF_permit_access | GTF_transitive | flags;
-}
-
-int gnttab_grant_foreign_access_trans_ref(grant_ref_t ref, domid_t domid,
- int flags, domid_t trans_domid,
- grant_ref_t trans_gref)
-{
- if (flags & (GTF_accept_transfer | GTF_reading |
- GTF_writing | GTF_sub_page))
- return -EPERM;
-
- if (gnttab_interface->update_trans_entry == NULL)
- return -ENOSYS;
-
- gnttab_interface->update_trans_entry(ref, domid, flags, trans_domid,
- trans_gref);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans_ref);
-
-int gnttab_grant_foreign_access_trans(domid_t domid, int flags,
- domid_t trans_domid,
- grant_ref_t trans_gref)
-{
- int ref, rc;
-
- ref = get_free_entries(1);
- if (unlikely(ref < 0))
- return -ENOSPC;
-
- rc = gnttab_grant_foreign_access_trans_ref(ref, domid, flags,
- trans_domid, trans_gref);
- if (rc < 0) {
- put_free_entry(ref);
- return rc;
- }
-
- return ref;
-}
-EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans);
-
-bool gnttab_trans_grants_available(void)
-{
- return gnttab_interface->update_trans_entry != NULL;
-}
-EXPORT_SYMBOL_GPL(gnttab_trans_grants_available);
-
static int gnttab_query_foreign_access_v1(grant_ref_t ref)
{
return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
}
-static int gnttab_query_foreign_access_v2(grant_ref_t ref)
-{
- return grstatus[ref] & (GTF_reading|GTF_writing);
-}
-
int gnttab_query_foreign_access(grant_ref_t ref)
{
return gnttab_interface->query_foreign_access(ref);
@@ -433,29 +276,6 @@ static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
return 1;
}
-static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly)
-{
- gnttab_shared.v2[ref].hdr.flags = 0;
- mb();
- if (grstatus[ref] & (GTF_reading|GTF_writing)) {
- return 0;
- } else {
- /* The read of grstatus needs to have acquire
- semantics. On x86, reads already have
- that, and we just need to protect against
- compiler reorderings. On other
- architectures we may need a full
- barrier. */
-#ifdef CONFIG_X86
- barrier();
-#else
- mb();
-#endif
- }
-
- return 1;
-}
-
static inline int _gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
{
return gnttab_interface->end_foreign_access_ref(ref, readonly);
@@ -616,37 +436,6 @@ static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
return frame;
}
-static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)
-{
- unsigned long frame;
- u16 flags;
- u16 *pflags;
-
- pflags = &gnttab_shared.v2[ref].hdr.flags;
-
- /*
- * If a transfer is not even yet started, try to reclaim the grant
- * reference and return failure (== 0).
- */
- while (!((flags = *pflags) & GTF_transfer_committed)) {
- if (sync_cmpxchg(pflags, 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 = *pflags;
- cpu_relax();
- }
-
- rmb(); /* Read the frame number /after/ reading completion status. */
- frame = gnttab_shared.v2[ref].full_page.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);
@@ -962,12 +751,6 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
}
EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
-static unsigned nr_status_frames(unsigned nr_grant_frames)
-{
- BUG_ON(grefs_per_grant_frame == 0);
- return (nr_grant_frames * grefs_per_grant_frame + SPP - 1) / SPP;
-}
-
static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes)
{
int rc;
@@ -985,55 +768,6 @@ static void gnttab_unmap_frames_v1(void)
arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
}
-static int gnttab_map_frames_v2(xen_pfn_t *frames, unsigned int nr_gframes)
-{
- uint64_t *sframes;
- unsigned int nr_sframes;
- struct gnttab_get_status_frames getframes;
- int rc;
-
- nr_sframes = nr_status_frames(nr_gframes);
-
- /* No need for kzalloc as it is initialized in following hypercall
- * GNTTABOP_get_status_frames.
- */
- sframes = kmalloc(nr_sframes * sizeof(uint64_t), GFP_ATOMIC);
- if (!sframes)
- return -ENOMEM;
-
- getframes.dom = DOMID_SELF;
- getframes.nr_frames = nr_sframes;
- set_xen_guest_handle(getframes.frame_list, sframes);
-
- rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
- &getframes, 1);
- if (rc == -ENOSYS) {
- kfree(sframes);
- return -ENOSYS;
- }
-
- BUG_ON(rc || getframes.status);
-
- rc = arch_gnttab_map_status(sframes, nr_sframes,
- nr_status_frames(gnttab_max_grant_frames()),
- &grstatus);
- BUG_ON(rc);
- kfree(sframes);
-
- 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_v2(void)
-{
- arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
- arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames));
-}
-
static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
{
struct gnttab_setup_table setup;
@@ -1101,43 +835,13 @@ static struct gnttab_ops gnttab_v1_ops = {
.query_foreign_access = gnttab_query_foreign_access_v1,
};
-static struct gnttab_ops gnttab_v2_ops = {
- .map_frames = gnttab_map_frames_v2,
- .unmap_frames = gnttab_unmap_frames_v2,
- .update_entry = gnttab_update_entry_v2,
- .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2,
- .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2,
- .query_foreign_access = gnttab_query_foreign_access_v2,
- .update_subpage_entry = gnttab_update_subpage_entry_v2,
- .update_trans_entry = gnttab_update_trans_entry_v2,
-};
-
static void gnttab_request_version(void)
{
- int rc;
- struct gnttab_set_version gsv;
+ /* Only version 1 is used, which will always be available. */
+ grant_table_version = 1;
+ grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1);
+ gnttab_interface = &gnttab_v1_ops;
- gsv.version = 1;
-
- rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
- if (rc == 0 && gsv.version == 2) {
- grant_table_version = 2;
- grefs_per_grant_frame = PAGE_SIZE / sizeof(union grant_entry_v2);
- gnttab_interface = &gnttab_v2_ops;
- } else if (grant_table_version == 2) {
- /*
- * If we've already used version 2 features,
- * but then suddenly discover that they're not
- * available (e.g. migrating to an older
- * version of Xen), almost unbounded badness
- * can happen.
- */
- panic("we need grant tables version 2, but only version 1 is available");
- } else {
- grant_table_version = 1;
- grefs_per_grant_frame = PAGE_SIZE / sizeof(struct grant_entry_v1);
- gnttab_interface = &gnttab_v1_ops;
- }
pr_info("Grant tables using version %d layout\n", grant_table_version);
}
@@ -1195,18 +899,20 @@ static int gnttab_expand(unsigned int req_entries)
int gnttab_init(void)
{
int i;
+ unsigned long max_nr_grant_frames;
unsigned int max_nr_glist_frames, nr_glist_frames;
unsigned int nr_init_grefs;
int ret;
gnttab_request_version();
+ max_nr_grant_frames = gnttab_max_grant_frames();
nr_grant_frames = 1;
/* Determine the maximum number of frames required for the
* grant reference free list on the current hypervisor.
*/
BUG_ON(grefs_per_grant_frame == 0);
- max_nr_glist_frames = (gnttab_max_grant_frames() *
+ max_nr_glist_frames = (max_nr_grant_frames *
grefs_per_grant_frame / RPP);
gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
@@ -1223,6 +929,10 @@ int gnttab_init(void)
}
}
+ ret = arch_gnttab_init(max_nr_grant_frames);
+ if (ret < 0)
+ goto ini_nomem;
+
if (gnttab_setup() < 0) {
ret = -ENODEV;
goto ini_nomem;
diff --git a/drivers/xen/xen-pciback/passthrough.c b/drivers/xen/xen-pciback/passthrough.c
index 828dddc360df..f16a30e2a110 100644
--- a/drivers/xen/xen-pciback/passthrough.c
+++ b/drivers/xen/xen-pciback/passthrough.c
@@ -69,7 +69,7 @@ static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
}
static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
- struct pci_dev *dev)
+ struct pci_dev *dev, bool lock)
{
struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
struct pci_dev_entry *dev_entry, *t;
@@ -87,8 +87,13 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
mutex_unlock(&dev_data->lock);
- if (found_dev)
+ if (found_dev) {
+ if (lock)
+ device_lock(&found_dev->dev);
pcistub_put_pci_dev(found_dev);
+ if (lock)
+ device_unlock(&found_dev->dev);
+ }
}
static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
@@ -156,8 +161,11 @@ static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
struct pci_dev_entry *dev_entry, *t;
list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
+ struct pci_dev *dev = dev_entry->dev;
list_del(&dev_entry->list);
- pcistub_put_pci_dev(dev_entry->dev);
+ device_lock(&dev->dev);
+ pcistub_put_pci_dev(dev);
+ device_unlock(&dev->dev);
kfree(dev_entry);
}
diff --git a/drivers/xen/xen-pciback/pci_stub.c b/drivers/xen/xen-pciback/pci_stub.c
index d57a173685f3..1ddd22feb2c0 100644
--- a/drivers/xen/xen-pciback/pci_stub.c
+++ b/drivers/xen/xen-pciback/pci_stub.c
@@ -250,6 +250,8 @@ struct pci_dev *pcistub_get_pci_dev(struct xen_pcibk_device *pdev,
* - 'echo BDF > unbind' with a guest still using it. See pcistub_remove
*
* As such we have to be careful.
+ *
+ * To make this easier, the caller has to hold the device lock.
*/
void pcistub_put_pci_dev(struct pci_dev *dev)
{
@@ -276,11 +278,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev)
/* Cleanup our device
* (so it's ready for the next domain)
*/
-
- /* This is OK - we are running from workqueue context
- * and want to inhibit the user from fiddling with 'reset'
- */
- pci_reset_function(dev);
+ device_lock_assert(&dev->dev);
+ __pci_reset_function_locked(dev);
pci_restore_state(dev);
/* This disables the device. */
@@ -554,12 +553,14 @@ static void pcistub_remove(struct pci_dev *dev)
spin_unlock_irqrestore(&pcistub_devices_lock, flags);
if (found_psdev) {
- dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
- found_psdev->pdev);
+ dev_dbg(&dev->dev, "found device to remove %s\n",
+ found_psdev->pdev ? "- in-use" : "");
if (found_psdev->pdev) {
- pr_warn("****** removing device %s while still in-use! ******\n",
- pci_name(found_psdev->dev));
+ int domid = xen_find_device_domain_owner(dev);
+
+ pr_warn("****** removing device %s while still in-use by domain %d! ******\n",
+ pci_name(found_psdev->dev), domid);
pr_warn("****** driver domain may still access this device's i/o resources!\n");
pr_warn("****** shutdown driver domain before binding device\n");
pr_warn("****** to other drivers or domains\n");
@@ -567,7 +568,8 @@ static void pcistub_remove(struct pci_dev *dev)
/* N.B. This ends up calling pcistub_put_pci_dev which ends up
* doing the FLR. */
xen_pcibk_release_pci_dev(found_psdev->pdev,
- found_psdev->dev);
+ found_psdev->dev,
+ false /* caller holds the lock. */);
}
spin_lock_irqsave(&pcistub_devices_lock, flags);
@@ -629,10 +631,12 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev,
{
pci_ers_result_t res = result;
struct xen_pcie_aer_op *aer_op;
+ struct xen_pcibk_device *pdev = psdev->pdev;
+ struct xen_pci_sharedinfo *sh_info = pdev->sh_info;
int ret;
/*with PV AER drivers*/
- aer_op = &(psdev->pdev->sh_info->aer_op);
+ aer_op = &(sh_info->aer_op);
aer_op->cmd = aer_cmd ;
/*useful for error_detected callback*/
aer_op->err = state;
@@ -653,36 +657,36 @@ static pci_ers_result_t common_process(struct pcistub_device *psdev,
* this flag to judge whether we need to check pci-front give aer
* service ack signal
*/
- set_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
+ set_bit(_PCIB_op_pending, (unsigned long *)&pdev->flags);
/*It is possible that a pcifront conf_read_write ops request invokes
* the callback which cause the spurious execution of wake_up.
* Yet it is harmless and better than a spinlock here
*/
set_bit(_XEN_PCIB_active,
- (unsigned long *)&psdev->pdev->sh_info->flags);
+ (unsigned long *)&sh_info->flags);
wmb();
- notify_remote_via_irq(psdev->pdev->evtchn_irq);
+ notify_remote_via_irq(pdev->evtchn_irq);
ret = wait_event_timeout(xen_pcibk_aer_wait_queue,
!(test_bit(_XEN_PCIB_active, (unsigned long *)
- &psdev->pdev->sh_info->flags)), 300*HZ);
+ &sh_info->flags)), 300*HZ);
if (!ret) {
if (test_bit(_XEN_PCIB_active,
- (unsigned long *)&psdev->pdev->sh_info->flags)) {
+ (unsigned long *)&sh_info->flags)) {
dev_err(&psdev->dev->dev,
"pcifront aer process not responding!\n");
clear_bit(_XEN_PCIB_active,
- (unsigned long *)&psdev->pdev->sh_info->flags);
+ (unsigned long *)&sh_info->flags);
aer_op->err = PCI_ERS_RESULT_NONE;
return res;
}
}
- clear_bit(_PCIB_op_pending, (unsigned long *)&psdev->pdev->flags);
+ clear_bit(_PCIB_op_pending, (unsigned long *)&pdev->flags);
if (test_bit(_XEN_PCIF_active,
- (unsigned long *)&psdev->pdev->sh_info->flags)) {
+ (unsigned long *)&sh_info->flags)) {
dev_dbg(&psdev->dev->dev,
"schedule pci_conf service in " DRV_NAME "\n");
xen_pcibk_test_and_schedule_op(psdev->pdev);
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h
index f72af87640e0..58e38d586f52 100644
--- a/drivers/xen/xen-pciback/pciback.h
+++ b/drivers/xen/xen-pciback/pciback.h
@@ -99,7 +99,8 @@ struct xen_pcibk_backend {
unsigned int *domain, unsigned int *bus,
unsigned int *devfn);
int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb);
- void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev);
+ void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev,
+ bool lock);
int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev,
int devid, publish_pci_dev_cb publish_cb);
struct pci_dev *(*get)(struct xen_pcibk_device *pdev,
@@ -122,10 +123,10 @@ static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev,
}
static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
- struct pci_dev *dev)
+ struct pci_dev *dev, bool lock)
{
if (xen_pcibk_backend && xen_pcibk_backend->release)
- return xen_pcibk_backend->release(pdev, dev);
+ return xen_pcibk_backend->release(pdev, dev, lock);
}
static inline struct pci_dev *
diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c
index 51afff96c515..c99f8bb1c56c 100644
--- a/drivers/xen/xen-pciback/vpci.c
+++ b/drivers/xen/xen-pciback/vpci.c
@@ -145,7 +145,7 @@ out:
}
static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
- struct pci_dev *dev)
+ struct pci_dev *dev, bool lock)
{
int slot;
struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
@@ -169,8 +169,13 @@ static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev,
out:
mutex_unlock(&vpci_dev->lock);
- if (found_dev)
+ if (found_dev) {
+ if (lock)
+ device_lock(&found_dev->dev);
pcistub_put_pci_dev(found_dev);
+ if (lock)
+ device_unlock(&found_dev->dev);
+ }
}
static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev)
@@ -208,8 +213,11 @@ static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev)
struct pci_dev_entry *e, *tmp;
list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
list) {
+ struct pci_dev *dev = e->dev;
list_del(&e->list);
- pcistub_put_pci_dev(e->dev);
+ device_lock(&dev->dev);
+ pcistub_put_pci_dev(dev);
+ device_unlock(&dev->dev);
kfree(e);
}
}
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
index 4a7e6e0a5f4c..53e2dda43446 100644
--- a/drivers/xen/xen-pciback/xenbus.c
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -246,7 +246,7 @@ static int xen_pcibk_export_device(struct xen_pcibk_device *pdev,
if (err)
goto out;
- dev_dbg(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
+ dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id);
if (xen_register_device_domain_owner(dev,
pdev->xdev->otherend_id) != 0) {
dev_err(&dev->dev, "Stealing ownership from dom%d.\n",
@@ -290,7 +290,7 @@ static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev,
/* N.B. This ends up calling pcistub_put_pci_dev which ends up
* doing the FLR. */
- xen_pcibk_release_pci_dev(pdev, dev);
+ xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */);
out:
return err;
diff --git a/include/linux/device.h b/include/linux/device.h
index 75f5bcb8930b..cf20850a1c6a 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -908,6 +908,11 @@ static inline void device_unlock(struct device *dev)
mutex_unlock(&dev->mutex);
}
+static inline void device_lock_assert(struct device *dev)
+{
+ lockdep_assert_held(&dev->mutex);
+}
+
void driver_init(void);
/*
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index a5af2a26d94f..3387465b9caa 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -64,24 +64,6 @@ int gnttab_resume(void);
int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
int readonly);
-int gnttab_grant_foreign_access_subpage(domid_t domid, unsigned long frame,
- int flags, unsigned page_off,
- unsigned length);
-int gnttab_grant_foreign_access_trans(domid_t domid, int flags,
- domid_t trans_domid,
- grant_ref_t trans_gref);
-
-/*
- * Are sub-page grants available on this version of Xen? Returns true if they
- * are, and false if they're not.
- */
-bool gnttab_subpage_grants_available(void);
-
-/*
- * Are transitive grants available on this version of Xen? Returns true if they
- * are, and false if they're not.
- */
-bool gnttab_trans_grants_available(void);
/*
* End access through the given grant reference, iff the grant entry is no
@@ -128,13 +110,6 @@ void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
unsigned long frame, int readonly);
-int gnttab_grant_foreign_access_subpage_ref(grant_ref_t ref, domid_t domid,
- unsigned long frame, int flags,
- unsigned page_off,
- unsigned length);
-int gnttab_grant_foreign_access_trans_ref(grant_ref_t ref, domid_t domid,
- int flags, domid_t trans_domid,
- grant_ref_t trans_gref);
void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
unsigned long pfn);
@@ -170,12 +145,10 @@ gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, phys_addr_t addr,
unmap->dev_bus_addr = 0;
}
+int arch_gnttab_init(unsigned long nr_shared);
int arch_gnttab_map_shared(xen_pfn_t *frames, unsigned long nr_gframes,
unsigned long max_nr_gframes,
void **__shared);
-int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
- unsigned long max_nr_gframes,
- grant_status_t **__shared);
void arch_gnttab_unmap(void *shared, unsigned long nr_gframes);
struct grant_frames {