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

[Xen-changelog] [xen-unstable] Xen: use proper device ID to search VT-d unit for ARI and SR-IOV device



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1237458011 0
# Node ID f02a528d2e568b0a8899981677a013da749b7a28
# Parent  e2ada9d65bcafca6cbea903b0a89ae8e60ee5cec
Xen: use proper device ID to search VT-d unit for ARI and SR-IOV device

PCIe Alternative Routing-ID Interpretation (ARI) ECN defines the Extended
Function -- a function whose function number is greater than 7 within an
ARI Device. Intel VT-d spec 1.2 section 8.3.2 specifies that the Extended
Function is under the scope of the same remapping unit as the traditional
function. The hypervisor needs to know if a function is Extended
Function so it can find proper DMAR for it.

And section 8.3.3 specifies that the SR-IOV Virtual Function is under the
scope of the same remapping unit as the Physical Function. The hypervisor
also needs to know if a function is the Virtual Function and which
Physical Function it's associated with for same reason.

Signed-off-by: Yu Zhao <yu.zhao@xxxxxxxxx>
---
 xen/arch/ia64/xen/hypercall.c          |   22 +++++++++++++++++
 xen/arch/x86/physdev.c                 |   26 ++++++++++++++++++++
 xen/drivers/passthrough/pci.c          |   41 +++++++++++++++++++++++++++++++++
 xen/drivers/passthrough/vtd/dmar.c     |   16 +++++++++++-
 xen/drivers/passthrough/vtd/dmar.h     |    2 -
 xen/drivers/passthrough/vtd/intremap.c |    4 +--
 xen/drivers/passthrough/vtd/iommu.c    |   18 +++++++++-----
 xen/include/public/physdev.h           |   16 ++++++++++++
 xen/include/xen/pci.h                  |   11 ++++++++
 9 files changed, 145 insertions(+), 11 deletions(-)

diff -r e2ada9d65bca -r f02a528d2e56 xen/arch/ia64/xen/hypercall.c
--- a/xen/arch/ia64/xen/hypercall.c     Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/arch/ia64/xen/hypercall.c     Thu Mar 19 10:20:11 2009 +0000
@@ -674,6 +674,28 @@ long do_physdev_op(int cmd, XEN_GUEST_HA
             break;
     }
 
+    case PHYSDEVOP_manage_pci_add_ext: {
+        struct physdev_manage_pci_ext manage_pci_ext;
+        struct pci_dev_info pdev_info;
+
+        ret = -EPERM;
+        if ( !IS_PRIV(current->domain) )
+            break;
+
+        ret = -EFAULT;
+        if ( copy_from_guest(&manage_pci_ext, arg, 1) != 0 )
+            break;
+
+        pdev_info.is_extfn = manage_pci_ext.is_extfn;
+        pdev_info.is_virtfn = manage_pci_ext.is_virtfn;
+        pdev_info.physfn.bus = manage_pci_ext.physfn.bus;
+        pdev_info.physfn.devfn = manage_pci_ext.physfn.devfn;
+        ret = pci_add_device_ext(manage_pci_ext.bus,
+                                 manage_pci_ext.devfn,
+                                 &pdev_info);
+            break;
+    }
+
     default:
         ret = -ENOSYS;
         printk("not implemented do_physdev_op: %d\n", cmd);
diff -r e2ada9d65bca -r f02a528d2e56 xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c    Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/arch/x86/physdev.c    Thu Mar 19 10:20:11 2009 +0000
@@ -421,6 +421,32 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
         break;
     }
 
+    case PHYSDEVOP_manage_pci_add_ext: {
+        struct physdev_manage_pci_ext manage_pci_ext;
+        struct pci_dev_info pdev_info;
+
+        ret = -EPERM;
+        if ( !IS_PRIV(current->domain) )
+            break;
+
+        ret = -EFAULT;
+        if ( copy_from_guest(&manage_pci_ext, arg, 1) != 0 )
+            break;
+
+        ret = -EINVAL;
+        if ( (manage_pci_ext.is_extfn > 1) || (manage_pci_ext.is_virtfn > 1) )
+            break;
+
+        pdev_info.is_extfn = manage_pci_ext.is_extfn;
+        pdev_info.is_virtfn = manage_pci_ext.is_virtfn;
+        pdev_info.physfn.bus = manage_pci_ext.physfn.bus;
+        pdev_info.physfn.devfn = manage_pci_ext.physfn.devfn;
+        ret = pci_add_device_ext(manage_pci_ext.bus,
+                                 manage_pci_ext.devfn,
+                                 &pdev_info);
+        break;
+    }
+
     case PHYSDEVOP_restore_msi: {
         struct physdev_restore_msi restore_msi;
         struct pci_dev *pdev;
diff -r e2ada9d65bca -r f02a528d2e56 xen/drivers/passthrough/pci.c
--- a/xen/drivers/passthrough/pci.c     Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/drivers/passthrough/pci.c     Thu Mar 19 10:20:11 2009 +0000
@@ -143,6 +143,47 @@ int pci_remove_device(u8 bus, u8 devfn)
     return ret;
 }
 
+int pci_add_device_ext(u8 bus, u8 devfn, struct pci_dev_info *info)
+{
+    int ret;
+    char *pdev_type;
+    struct pci_dev *pdev;
+
+    if (info->is_extfn)
+        pdev_type = "Extended Function";
+    else if (info->is_virtfn)
+        pdev_type = "Virtual Function";
+    else
+       return -EINVAL;;
+
+
+    ret = -ENOMEM;
+    spin_lock(&pcidevs_lock);
+    pdev = alloc_pdev(bus, devfn);
+    if ( !pdev )
+        goto out;
+
+    pdev->info = *info;
+
+    ret = 0;
+    if ( !pdev->domain )
+    {
+        pdev->domain = dom0;
+        ret = iommu_add_device(pdev);
+        if ( ret )
+            goto out;
+
+        list_add(&pdev->domain_list, &dom0->arch.pdev_list);
+    }
+
+out:
+    spin_unlock(&pcidevs_lock);
+    printk(XENLOG_DEBUG "PCI add %s %02x:%02x.%x\n", pdev_type,
+           bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+    return ret;
+}
+
 static void pci_clean_dpci_irqs(struct domain *d)
 {
     struct hvm_irq_dpci *hvm_irq_dpci = NULL;
diff -r e2ada9d65bca -r f02a528d2e56 xen/drivers/passthrough/vtd/dmar.c
--- a/xen/drivers/passthrough/vtd/dmar.c        Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/drivers/passthrough/vtd/dmar.c        Thu Mar 19 10:20:11 2009 +0000
@@ -152,11 +152,23 @@ static int __init acpi_register_atsr_uni
     return 0;
 }
 
-struct acpi_drhd_unit * acpi_find_matched_drhd_unit(u8 bus, u8 devfn)
-{
+struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *pdev)
+{
+    u8 bus, devfn;
     struct acpi_drhd_unit *drhd;
     struct acpi_drhd_unit *found = NULL, *include_all = NULL;
     int i;
+
+    if (pdev->info.is_extfn) {
+        bus = pdev->bus;
+        devfn = 0;
+    } else if (pdev->info.is_virtfn) {
+        bus = pdev->info.physfn.bus;
+        devfn = PCI_SLOT(pdev->info.physfn.devfn) ? 0 : 
pdev->info.physfn.devfn;
+    } else {
+        bus = pdev->bus;
+        devfn = pdev->devfn;
+    }
 
     list_for_each_entry ( drhd, &acpi_drhd_units, list )
     {
diff -r e2ada9d65bca -r f02a528d2e56 xen/drivers/passthrough/vtd/dmar.h
--- a/xen/drivers/passthrough/vtd/dmar.h        Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/drivers/passthrough/vtd/dmar.h        Thu Mar 19 10:20:11 2009 +0000
@@ -79,7 +79,7 @@ struct acpi_atsr_unit {
         for (idx = 0; (bdf = rmrr->scope.devices[idx]) && \
                  idx < rmrr->scope.devices_cnt; idx++)
 
-struct acpi_drhd_unit * acpi_find_matched_drhd_unit(u8 bus, u8 devfn);
+struct acpi_drhd_unit * acpi_find_matched_drhd_unit(struct pci_dev *pdev);
 struct acpi_atsr_unit * acpi_find_matched_atsr_unit(u8 bus, u8 devfn);
 void dmar_scope_add_buses(struct dmar_scope *scope, u16 sec, u16 sub);
 void dmar_scope_remove_buses(struct dmar_scope *scope, u16 sec, u16 sub);
diff -r e2ada9d65bca -r f02a528d2e56 xen/drivers/passthrough/vtd/intremap.c
--- a/xen/drivers/passthrough/vtd/intremap.c    Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/drivers/passthrough/vtd/intremap.c    Thu Mar 19 10:20:11 2009 +0000
@@ -450,7 +450,7 @@ void msi_msg_read_remap_rte(
     struct iommu *iommu = NULL;
     struct ir_ctrl *ir_ctrl;
 
-    drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
+    drhd = acpi_find_matched_drhd_unit(pdev);
     iommu = drhd->iommu;
 
     ir_ctrl = iommu_ir_ctrl(iommu);
@@ -468,7 +468,7 @@ void msi_msg_write_remap_rte(
     struct iommu *iommu = NULL;
     struct ir_ctrl *ir_ctrl;
 
-    drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
+    drhd = acpi_find_matched_drhd_unit(pdev);
     iommu = drhd->iommu;
 
     ir_ctrl = iommu_ir_ctrl(iommu);
diff -r e2ada9d65bca -r f02a528d2e56 xen/drivers/passthrough/vtd/iommu.c
--- a/xen/drivers/passthrough/vtd/iommu.c       Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/drivers/passthrough/vtd/iommu.c       Thu Mar 19 10:20:11 2009 +0000
@@ -1193,8 +1193,11 @@ static int domain_context_mapping(struct
     u16 sec_bus, sub_bus;
     u32 type;
     u8 secbus, secdevfn;
-
-    drhd = acpi_find_matched_drhd_unit(bus, devfn);
+    struct pci_dev *pdev = pci_get_pdev(bus, devfn);
+
+    BUG_ON(!pdev);
+
+    drhd = acpi_find_matched_drhd_unit(pdev);
     if ( !drhd )
         return -ENODEV;
 
@@ -1319,8 +1322,11 @@ static int domain_context_unmap(struct d
     int ret = 0;
     u32 type;
     u8 secbus, secdevfn;
-
-    drhd = acpi_find_matched_drhd_unit(bus, devfn);
+    struct pci_dev *pdev = pci_get_pdev(bus, devfn);
+
+    BUG_ON(!pdev);
+
+    drhd = acpi_find_matched_drhd_unit(pdev);
     if ( !drhd )
         return -ENODEV;
 
@@ -1392,7 +1398,7 @@ static int reassign_device_ownership(
     if (!pdev)
         return -ENODEV;
 
-    drhd = acpi_find_matched_drhd_unit(bus, devfn);
+    drhd = acpi_find_matched_drhd_unit(pdev);
     pdev_iommu = drhd->iommu;
     domain_context_unmap(source, bus, devfn);
 
@@ -1405,7 +1411,7 @@ static int reassign_device_ownership(
 
     for_each_pdev ( source, pdev )
     {
-        drhd = acpi_find_matched_drhd_unit(pdev->bus, pdev->devfn);
+        drhd = acpi_find_matched_drhd_unit(pdev);
         if ( drhd->iommu == pdev_iommu )
         {
             found = 1;
diff -r e2ada9d65bca -r f02a528d2e56 xen/include/public/physdev.h
--- a/xen/include/public/physdev.h      Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/include/public/physdev.h      Thu Mar 19 10:20:11 2009 +0000
@@ -183,6 +183,22 @@ typedef struct physdev_manage_pci physde
 typedef struct physdev_manage_pci physdev_manage_pci_t;
 DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_t);
 
+#define PHYSDEVOP_manage_pci_add_ext    20
+struct physdev_manage_pci_ext {
+    /* IN */
+    uint8_t bus;
+    uint8_t devfn;
+    unsigned is_extfn;
+    unsigned is_virtfn;
+    struct {
+        uint8_t bus;
+        uint8_t devfn;
+    } physfn;
+};
+
+typedef struct physdev_manage_pci_ext physdev_manage_pci_ext_t;
+DEFINE_XEN_GUEST_HANDLE(physdev_manage_pci_ext_t);
+
 #define PHYSDEVOP_restore_msi            19
 struct physdev_restore_msi {
     /* IN */
diff -r e2ada9d65bca -r f02a528d2e56 xen/include/xen/pci.h
--- a/xen/include/xen/pci.h     Thu Mar 19 10:10:59 2009 +0000
+++ b/xen/include/xen/pci.h     Thu Mar 19 10:20:11 2009 +0000
@@ -31,6 +31,15 @@
 
 #define MAX_MSIX_TABLE_ENTRIES  2048
 #define MAX_MSIX_TABLE_PAGES    8
+struct pci_dev_info {
+    unsigned is_extfn;
+    unsigned is_virtfn;
+    struct {
+        u8 bus;
+        u8 devfn;
+    } physfn;
+};
+
 struct pci_dev {
     struct list_head alldevs_list;
     struct list_head domain_list;
@@ -43,6 +52,7 @@ struct pci_dev {
     struct domain *domain;
     const u8 bus;
     const u8 devfn;
+    struct pci_dev_info info;
 };
 
 #define for_each_pdev(domain, pdev) \
@@ -64,6 +74,7 @@ void pci_release_devices(struct domain *
 void pci_release_devices(struct domain *d);
 int pci_add_device(u8 bus, u8 devfn);
 int pci_remove_device(u8 bus, u8 devfn);
+int pci_add_device_ext(u8 bus, u8 devfn, struct pci_dev_info *info);
 struct pci_dev *pci_get_pdev(int bus, int devfn);
 struct pci_dev *pci_get_pdev_by_domain(struct domain *d, int bus, int devfn);
 

_______________________________________________
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®.