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

[Xen-devel] [PATCH] VT-d: fix VF of RC integrated endpoint matched to wrong VT-d unit



The problem is a VF of RC integrated PF (e.g. PF's BDF is 00:02.0),
we would wrongly use 00:00.0 to search VT-d unit.

To search VT-d unit for a VF, the BDF of the PF is used. And If the
PF is an Extended Function, the BDF of one traditional function is
used. The following line (from acpi_find_matched_drhd_unit()):
    devfn = PCI_SLOT(pdev->info.physfn.devfn) ? 0 : pdev->info.physfn.devfn;
sets 'devfn' to 0 if PF's devfn > 8. Apparently, this line treats all
PFs as ARI-capable function and assumes the Root Port or Switch
Downstream Port immediately above the PF has ARIforwarding enabled.
However, according to SRIOV spec 3.7.3, ARI is not applicable to RC
integrated PF. For this case, we should use PF's BDF directly other
than using 0 as devfn.

This patch adds a new pdev type to indicate a function is RC
integrated. And check whether PF is a RC integrated endpoint when
searching VT-d unit.

Reported-by: Crawford, Eric R <Eric.R.Crawford@xxxxxxxxx>
Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
---
 xen/drivers/passthrough/pci.c          | 28 +++++++++++++++++++---------
 xen/drivers/passthrough/vtd/dmar.c     |  7 ++++++-
 xen/drivers/passthrough/vtd/intremap.c |  1 +
 xen/drivers/passthrough/vtd/iommu.c    |  2 ++
 xen/include/xen/pci.h                  |  1 +
 5 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 6e7126b..9842d76 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -345,6 +345,7 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 
bus, u8 devfn)
             break;
 
         case DEV_TYPE_PCIe_ENDPOINT:
+        case DEV_TYPE_RC_ENDPOINT:
             pos = pci_find_cap_offset(pseg->nr, bus, PCI_SLOT(devfn),
                                       PCI_FUNC(devfn), PCI_CAP_ID_EXP);
             BUG_ON(!pos);
@@ -854,23 +855,24 @@ int pci_release_devices(struct domain *d)
 
 enum pdev_type pdev_type(u16 seg, u8 bus, u8 devfn)
 {
-    u16 class_device, creg;
-    u8 d = PCI_SLOT(devfn), f = PCI_FUNC(devfn);
+    uint8_t d = PCI_SLOT(devfn), f = PCI_FUNC(devfn);
     int pos = pci_find_cap_offset(seg, bus, d, f, PCI_CAP_ID_EXP);
+    int pcie_type = -1;
 
-    class_device = pci_conf_read16(seg, bus, d, f, PCI_CLASS_DEVICE);
-    switch ( class_device )
+    if ( pos )
+        pcie_type = MASK_EXTR(pci_conf_read16(seg, bus, d, f,
+                                  pos + PCI_EXP_FLAGS), PCI_EXP_FLAGS_TYPE);
+    switch ( pci_conf_read16(seg, bus, d, f, PCI_CLASS_DEVICE) )
     {
     case PCI_CLASS_BRIDGE_PCI:
-        if ( !pos )
-            return DEV_TYPE_LEGACY_PCI_BRIDGE;
-        creg = pci_conf_read16(seg, bus, d, f, pos + PCI_EXP_FLAGS);
-        switch ( (creg & PCI_EXP_FLAGS_TYPE) >> 4 )
+        switch ( pcie_type )
         {
         case PCI_EXP_TYPE_PCI_BRIDGE:
             return DEV_TYPE_PCIe2PCI_BRIDGE;
         case PCI_EXP_TYPE_PCIE_BRIDGE:
             return DEV_TYPE_PCI2PCIe_BRIDGE;
+        case -1:
+            return DEV_TYPE_LEGACY_PCI_BRIDGE;
         }
         return DEV_TYPE_PCIe_BRIDGE;
     case PCI_CLASS_BRIDGE_HOST:
@@ -880,7 +882,15 @@ enum pdev_type pdev_type(u16 seg, u8 bus, u8 devfn)
         return DEV_TYPE_PCI_UNKNOWN;
     }
 
-    return pos ? DEV_TYPE_PCIe_ENDPOINT : DEV_TYPE_PCI;
+    switch ( pcie_type )
+    {
+    case PCI_EXP_TYPE_RC_END:
+        return DEV_TYPE_RC_ENDPOINT;
+    case -1:
+        return DEV_TYPE_PCI;
+    }
+
+    return DEV_TYPE_PCIe_ENDPOINT;
 }
 
 /*
diff --git a/xen/drivers/passthrough/vtd/dmar.c 
b/xen/drivers/passthrough/vtd/dmar.c
index 82040dd..7c9d17b 100644
--- a/xen/drivers/passthrough/vtd/dmar.c
+++ b/xen/drivers/passthrough/vtd/dmar.c
@@ -219,7 +219,12 @@ struct acpi_drhd_unit *acpi_find_matched_drhd_unit(const 
struct pci_dev *pdev)
     else if ( pdev->info.is_virtfn )
     {
         bus = pdev->info.physfn.bus;
-        devfn = PCI_SLOT(pdev->info.physfn.devfn) ? 0 : 
pdev->info.physfn.devfn;
+        /* ARI is not appliable to Root Complex Integrated Endpoints */
+        if ( PCI_SLOT(pdev->info.physfn.devfn) &&
+             (pdev->type != DEV_TYPE_RC_ENDPOINT) )
+            devfn = 0;
+        else
+            devfn = pdev->info.physfn.devfn;
     }
     else
     {
diff --git a/xen/drivers/passthrough/vtd/intremap.c 
b/xen/drivers/passthrough/vtd/intremap.c
index 1e0317c..bae0d3b 100644
--- a/xen/drivers/passthrough/vtd/intremap.c
+++ b/xen/drivers/passthrough/vtd/intremap.c
@@ -486,6 +486,7 @@ static void set_msi_source_id(struct pci_dev *pdev, struct 
iremap_entry *ire)
         unsigned int sq;
 
     case DEV_TYPE_PCIe_ENDPOINT:
+    case DEV_TYPE_RC_ENDPOINT:
     case DEV_TYPE_PCIe_BRIDGE:
     case DEV_TYPE_PCIe2PCI_BRIDGE:
     case DEV_TYPE_PCI_HOST_BRIDGE:
diff --git a/xen/drivers/passthrough/vtd/iommu.c 
b/xen/drivers/passthrough/vtd/iommu.c
index 19328f6..73f3095 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -1493,6 +1493,7 @@ static int domain_context_mapping(struct domain *domain, 
u8 devfn,
         break;
 
     case DEV_TYPE_PCIe_ENDPOINT:
+    case DEV_TYPE_RC_ENDPOINT:
         if ( iommu_debug )
             printk(VTDPREFIX "d%d:PCIe: map %04x:%02x:%02x.%u\n",
                    domain->domain_id, seg, bus,
@@ -1644,6 +1645,7 @@ static int domain_context_unmap(struct domain *domain, u8 
devfn,
         goto out;
 
     case DEV_TYPE_PCIe_ENDPOINT:
+    case DEV_TYPE_RC_ENDPOINT:
         if ( iommu_debug )
             printk(VTDPREFIX "d%d:PCIe: unmap %04x:%02x:%02x.%u\n",
                    domain->domain_id, seg, bus,
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index 59b6e8a..4ec74b1 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -67,6 +67,7 @@ struct pci_dev {
     enum pdev_type {
         DEV_TYPE_PCI_UNKNOWN,
         DEV_TYPE_PCIe_ENDPOINT,
+        DEV_TYPE_RC_ENDPOINT,       // Root Complex Integrated Endpoint
         DEV_TYPE_PCIe_BRIDGE,       // PCIe root port, switch
         DEV_TYPE_PCIe2PCI_BRIDGE,   // PCIe-to-PCI/PCIx bridge
         DEV_TYPE_PCI2PCIe_BRIDGE,   // PCI/PCIx-to-PCIe bridge
-- 
1.8.3.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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