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