[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] Add hypercall for adding and removing PCI devices



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1215190370 -3600
# Node ID 183ca809e1d7d2f2f8943bd323ecc85c3968ca09
# Parent  7f7d0e7aa01bbd51f4c2045fe6b99a3f0bcd963e
Add hypercall for adding and removing PCI devices

The add hypercall will add a new PCI device and register it.  The
remove hypercall will remove the pci_dev strucure for the device.  The
IOMMU hardware (if present) will be notifed as well.

Signed-off-by: Espen Skoglund <espen.skoglund@xxxxxxxxxxxxx>
Signed-off-by: Joshua LeVasseur <joshua.levasseur@xxxxxxxxxxxxx>
---
 xen/arch/x86/physdev.c                      |   26 ++++++++++++++
 xen/drivers/passthrough/amd/pci_amd_iommu.c |   12 ++++++
 xen/drivers/passthrough/iommu.c             |   26 ++++++++++++++
 xen/drivers/passthrough/pci.c               |   52 ++++++++++++++++++++++++++++
 xen/drivers/passthrough/vtd/iommu.c         |   39 +++++++++++++++------
 xen/include/public/physdev.h                |   11 +++++
 xen/include/xen/iommu.h                     |    6 ++-
 xen/include/xen/pci.h                       |    2 +
 8 files changed, 161 insertions(+), 13 deletions(-)

diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c    Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/arch/x86/physdev.c    Fri Jul 04 17:52:50 2008 +0100
@@ -500,6 +500,32 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
         break;
     }
 
+    case PHYSDEVOP_manage_pci_add: {
+        struct physdev_manage_pci manage_pci;
+        ret = -EPERM;
+        if ( !IS_PRIV(v->domain) )
+            break;
+        ret = -EFAULT;
+        if ( copy_from_guest(&manage_pci, arg, 1) != 0 )
+            break;
+
+        ret = pci_add_device(manage_pci.bus, manage_pci.devfn);
+        break;
+    }
+
+    case PHYSDEVOP_manage_pci_remove: {
+        struct physdev_manage_pci manage_pci;
+        ret = -EPERM;
+        if ( !IS_PRIV(v->domain) )
+            break;
+        ret = -EFAULT;
+        if ( copy_from_guest(&manage_pci, arg, 1) != 0 )
+            break;
+
+        ret = pci_remove_device(manage_pci.bus, manage_pci.devfn);
+        break;
+    }
+
     default:
         ret = -ENOSYS;
         break;
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/drivers/passthrough/amd/pci_amd_iommu.c
--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c       Fri Jul 04 17:52:24 
2008 +0100
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c       Fri Jul 04 17:52:50 
2008 +0100
@@ -628,6 +628,16 @@ static int amd_iommu_return_device(
     return reassign_device(s, t, bus, devfn);
 }
 
+static int amd_iommu_add_device(struct pci_dev *pdev)
+{
+    return 0;
+}
+
+static int amd_iommu_remove_device(struct pci_dev *pdev)
+{
+    return 0;
+}
+
 static int amd_iommu_group_id(u8 bus, u8 devfn)
 {
     int rt;
@@ -640,6 +650,8 @@ static int amd_iommu_group_id(u8 bus, u8
 
 struct iommu_ops amd_iommu_ops = {
     .init = amd_iommu_domain_init,
+    .add_device = amd_iommu_add_device,
+    .remove_device = amd_iommu_remove_device,
     .assign_device  = amd_iommu_assign_device,
     .teardown = amd_iommu_domain_destroy,
     .map_page = amd_iommu_map_page,
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/drivers/passthrough/iommu.c
--- a/xen/drivers/passthrough/iommu.c   Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/drivers/passthrough/iommu.c   Fri Jul 04 17:52:50 2008 +0100
@@ -55,6 +55,32 @@ int iommu_domain_init(struct domain *dom
     return hd->platform_ops->init(domain);
 }
 
+int iommu_add_device(struct pci_dev *pdev)
+{
+    struct hvm_iommu *hd;
+    if ( !pdev->domain )
+        return -EINVAL;
+
+    hd = domain_hvm_iommu(pdev->domain);
+    if ( !iommu_enabled || !hd->platform_ops )
+        return 0;
+
+    return hd->platform_ops->add_device(pdev);
+}
+
+int iommu_remove_device(struct pci_dev *pdev)
+{
+    struct hvm_iommu *hd;
+    if ( !pdev->domain )
+        return -EINVAL;
+
+    hd = domain_hvm_iommu(pdev->domain);
+    if ( !iommu_enabled || !hd->platform_ops )
+        return 0;
+
+    return hd->platform_ops->remove_device(pdev);
+}
+
 int assign_device(struct domain *d, u8 bus, u8 devfn)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(d);
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/drivers/passthrough/pci.c
--- a/xen/drivers/passthrough/pci.c     Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/drivers/passthrough/pci.c     Fri Jul 04 17:52:50 2008 +0100
@@ -19,6 +19,7 @@
 #include <xen/pci.h>
 #include <xen/list.h>
 #include <xen/prefetch.h>
+#include <xen/iommu.h>
 #include <xen/keyhandler.h>
 
 
@@ -93,6 +94,57 @@ struct pci_dev *pci_lock_domain_pdev(str
     return NULL;
 }
 
+int pci_add_device(u8 bus, u8 devfn)
+{
+    struct pci_dev *pdev;
+    int ret = -ENOMEM;
+
+    write_lock(&pcidevs_lock);
+    pdev = alloc_pdev(bus, devfn);
+    if ( !pdev )
+       goto out;
+
+    ret = 0;
+    spin_lock(&pdev->lock);
+    if ( !pdev->domain )
+    {
+       pdev->domain = dom0;
+       list_add(&pdev->domain_list, &dom0->arch.pdev_list);
+       ret = iommu_add_device(pdev);
+    }
+    spin_unlock(&pdev->lock);
+    printk(XENLOG_DEBUG "PCI add device %02x:%02x.%x\n", bus,
+          PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+out:
+    write_unlock(&pcidevs_lock);
+    return ret;
+}
+
+int pci_remove_device(u8 bus, u8 devfn)
+{
+    struct pci_dev *pdev;
+    int ret = -ENODEV;;
+
+    write_lock(&pcidevs_lock);
+    list_for_each_entry ( pdev, &alldevs_list, alldevs_list )
+        if ( pdev->bus == bus && pdev->devfn == devfn )
+       {
+           spin_lock(&pdev->lock);
+           ret = iommu_remove_device(pdev);
+           if ( pdev->domain )
+               list_del(&pdev->domain_list);
+           pci_cleanup_msi(pdev);
+           free_pdev(pdev);
+           printk(XENLOG_DEBUG "PCI remove device %02x:%02x.%x\n", bus,
+                  PCI_SLOT(devfn), PCI_FUNC(devfn));
+           break;
+       }
+
+    write_unlock(&pcidevs_lock);
+    return ret;
+}
+
 static void dump_pci_devices(unsigned char ch)
 {
     struct pci_dev *pdev;
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c       Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/drivers/passthrough/vtd/iommu.c       Fri Jul 04 17:52:50 2008 +0100
@@ -1223,13 +1223,15 @@ static int domain_context_mapping(struct
     switch ( type )
     {
     case DEV_TYPE_PCIe_BRIDGE:
-        break;
-
     case DEV_TYPE_PCI_BRIDGE:
         sec_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
                                  PCI_SECONDARY_BUS);
         sub_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
                                  PCI_SUBORDINATE_BUS);
+        /*dmar_scope_add_buses(&drhd->scope, sec_bus, sub_bus);*/
+
+        if ( type == DEV_TYPE_PCIe_BRIDGE )
+            break;
 
         for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ )
         {
@@ -1308,6 +1310,7 @@ static int domain_context_unmap(u8 bus, 
 static int domain_context_unmap(u8 bus, u8 devfn)
 {
     struct acpi_drhd_unit *drhd;
+    u16 sec_bus, sub_bus;
     int ret = 0;
     u32 type;
 
@@ -1319,10 +1322,14 @@ static int domain_context_unmap(u8 bus, 
     switch ( type )
     {
     case DEV_TYPE_PCIe_BRIDGE:
-        break;
-
     case DEV_TYPE_PCI_BRIDGE:
-        ret = domain_context_unmap_one(drhd->iommu, bus, devfn);
+        sec_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                 PCI_SECONDARY_BUS);
+        sub_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                 PCI_SUBORDINATE_BUS);
+        /*dmar_scope_remove_buses(&drhd->scope, sec_bus, sub_bus);*/
+        if ( DEV_TYPE_PCI_BRIDGE )
+            ret = domain_context_unmap_one(drhd->iommu, bus, devfn);
         break;
 
     case DEV_TYPE_PCIe_ENDPOINT:
@@ -1574,11 +1581,23 @@ static int iommu_prepare_rmrr_dev(struct
     return ret;
 }
 
+static int intel_iommu_add_device(struct pci_dev *pdev)
+{
+    if ( !pdev->domain )
+        return -EINVAL;
+    return domain_context_mapping(pdev->domain, pdev->bus, pdev->devfn);
+}
+
+static int intel_iommu_remove_device(struct pci_dev *pdev)
+{
+    return domain_context_unmap(pdev->bus, pdev->devfn);
+}
+
 static void setup_dom0_devices(struct domain *d)
 {
     struct hvm_iommu *hd;
     struct pci_dev *pdev;
-    int bus, dev, func, ret;
+    int bus, dev, func;
     u32 l;
 
     hd = domain_hvm_iommu(d);
@@ -1599,11 +1618,7 @@ static void setup_dom0_devices(struct do
                 pdev = alloc_pdev(bus, PCI_DEVFN(dev, func));
                 pdev->domain = d;
                 list_add(&pdev->domain_list, &d->arch.pdev_list);
-
-                ret = domain_context_mapping(d, pdev->bus, pdev->devfn);
-                if ( ret != 0 )
-                    gdprintk(XENLOG_ERR VTDPREFIX,
-                             "domain_context_mapping failed\n");
+                domain_context_mapping(d, pdev->bus, pdev->devfn);
             }
         }
     }
@@ -1866,6 +1881,8 @@ int iommu_resume(void)
 
 struct iommu_ops intel_iommu_ops = {
     .init = intel_iommu_domain_init,
+    .add_device = intel_iommu_add_device,
+    .remove_device = intel_iommu_remove_device,
     .assign_device  = intel_iommu_assign_device,
     .teardown = iommu_domain_teardown,
     .map_page = intel_iommu_map_page,
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/include/public/physdev.h
--- a/xen/include/public/physdev.h      Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/include/public/physdev.h      Fri Jul 04 17:52:50 2008 +0100
@@ -154,6 +154,17 @@ typedef struct physdev_unmap_pirq physde
 typedef struct physdev_unmap_pirq physdev_unmap_pirq_t;
 DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t);
 
+#define PHYSDEVOP_manage_pci_add         15
+#define PHYSDEVOP_manage_pci_remove      16
+struct physdev_manage_pci {
+    /* IN */
+    uint8_t bus;
+    uint8_t devfn;
+}; 
+
+typedef struct physdev_manage_pci physdev_manage_pci_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_t);
+
 /*
  * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
  * hypercall since 0x00030202.
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/include/xen/iommu.h
--- a/xen/include/xen/iommu.h   Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/include/xen/iommu.h   Fri Jul 04 17:52:50 2008 +0100
@@ -56,8 +56,8 @@ struct iommu {
     struct intel_iommu *intel;
 };
 
-int iommu_add_device(u8 bus, u8 devfn);
-void iommu_remove_device(u8 bus, u8 devfn);
+int iommu_add_device(struct pci_dev *pdev);
+int iommu_remove_device(struct pci_dev *pdev);
 int iommu_domain_init(struct domain *d);
 void iommu_domain_destroy(struct domain *d);
 int device_assigned(u8 bus, u8 devfn);
@@ -94,6 +94,8 @@ int domain_set_irq_dpci(struct domain *d
 
 struct iommu_ops {
     int (*init)(struct domain *d);
+    int (*add_device)(struct pci_dev *pdev);
+    int (*remove_device)(struct pci_dev *pdev);
     int (*assign_device)(struct domain *d, u8 bus, u8 devfn);
     void (*teardown)(struct domain *d);
     int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn);
diff -r 7f7d0e7aa01b -r 183ca809e1d7 xen/include/xen/pci.h
--- a/xen/include/xen/pci.h     Fri Jul 04 17:52:24 2008 +0100
+++ b/xen/include/xen/pci.h     Fri Jul 04 17:52:50 2008 +0100
@@ -56,6 +56,8 @@ struct pci_dev *pci_lock_pdev(int bus, i
 struct pci_dev *pci_lock_pdev(int bus, int devfn);
 struct pci_dev *pci_lock_domain_pdev(struct domain *d, int bus, int devfn);
 
+int pci_add_device(u8 bus, u8 devfn);
+int pci_remove_device(u8 bus, u8 devfn);
 
 uint8_t pci_conf_read8(
     unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.