# 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
|