268 lines
8.9 KiB
Diff
268 lines
8.9 KiB
Diff
|
References: bnc#787169
|
||
|
|
||
|
# HG changeset patch
|
||
|
# User Jan Beulich <jbeulich@suse.com>
|
||
|
# Date 1357559364 -3600
|
||
|
# Node ID 62dd78a4e3fc9d190840549f13b4d613f2d19c41
|
||
|
# Parent 64b36dde26bc3c4fc80312cc9eeb0e511f0cf94b
|
||
|
IOMMU: adjust (re)assign operation parameters
|
||
|
|
||
|
... to use a (struct pci_dev *, devfn) pair.
|
||
|
|
||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||
|
Acked-by: "Zhang, Xiantao" <xiantao.zhang@intel.com>
|
||
|
|
||
|
--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
|
||
|
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
|
||
|
@@ -328,34 +328,31 @@ void amd_iommu_disable_domain_device(str
|
||
|
disable_ats_device(iommu->seg, bus, devfn);
|
||
|
}
|
||
|
|
||
|
-static int reassign_device( struct domain *source, struct domain *target,
|
||
|
- u16 seg, u8 bus, u8 devfn)
|
||
|
+static int reassign_device(struct domain *source, struct domain *target,
|
||
|
+ u8 devfn, struct pci_dev *pdev)
|
||
|
{
|
||
|
- struct pci_dev *pdev;
|
||
|
struct amd_iommu *iommu;
|
||
|
int bdf;
|
||
|
struct hvm_iommu *t = domain_hvm_iommu(target);
|
||
|
|
||
|
- ASSERT(spin_is_locked(&pcidevs_lock));
|
||
|
- pdev = pci_get_pdev_by_domain(source, seg, bus, devfn);
|
||
|
- if ( !pdev )
|
||
|
- return -ENODEV;
|
||
|
-
|
||
|
- bdf = PCI_BDF2(bus, devfn);
|
||
|
- iommu = find_iommu_for_device(seg, bdf);
|
||
|
+ bdf = PCI_BDF2(pdev->bus, pdev->devfn);
|
||
|
+ iommu = find_iommu_for_device(pdev->seg, bdf);
|
||
|
if ( !iommu )
|
||
|
{
|
||
|
AMD_IOMMU_DEBUG("Fail to find iommu."
|
||
|
" %04x:%02x:%x02.%x cannot be assigned to dom%d\n",
|
||
|
- seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
||
|
+ pdev->seg, pdev->bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
||
|
target->domain_id);
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
amd_iommu_disable_domain_device(source, iommu, bdf);
|
||
|
|
||
|
- list_move(&pdev->domain_list, &target->arch.pdev_list);
|
||
|
- pdev->domain = target;
|
||
|
+ if ( devfn == pdev->devfn )
|
||
|
+ {
|
||
|
+ list_move(&pdev->domain_list, &target->arch.pdev_list);
|
||
|
+ pdev->domain = target;
|
||
|
+ }
|
||
|
|
||
|
/* IO page tables might be destroyed after pci-detach the last device
|
||
|
* In this case, we have to re-allocate root table for next pci-attach.*/
|
||
|
@@ -364,17 +361,18 @@ static int reassign_device( struct domai
|
||
|
|
||
|
amd_iommu_setup_domain_device(target, iommu, bdf);
|
||
|
AMD_IOMMU_DEBUG("Re-assign %04x:%02x:%02x.%u from dom%d to dom%d\n",
|
||
|
- seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
||
|
+ pdev->seg, pdev->bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
||
|
source->domain_id, target->domain_id);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int amd_iommu_assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
|
||
|
+static int amd_iommu_assign_device(struct domain *d, u8 devfn,
|
||
|
+ struct pci_dev *pdev)
|
||
|
{
|
||
|
- struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(seg);
|
||
|
- int bdf = (bus << 8) | devfn;
|
||
|
- int req_id = get_dma_requestor_id(seg, bdf);
|
||
|
+ struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg);
|
||
|
+ int bdf = PCI_BDF2(pdev->bus, devfn);
|
||
|
+ int req_id = get_dma_requestor_id(pdev->seg, bdf);
|
||
|
|
||
|
if ( ivrs_mappings[req_id].unity_map_enable )
|
||
|
{
|
||
|
@@ -386,7 +384,7 @@ static int amd_iommu_assign_device(struc
|
||
|
ivrs_mappings[req_id].read_permission);
|
||
|
}
|
||
|
|
||
|
- return reassign_device(dom0, d, seg, bus, devfn);
|
||
|
+ return reassign_device(dom0, d, devfn, pdev);
|
||
|
}
|
||
|
|
||
|
static void deallocate_next_page_table(struct page_info* pg, int level)
|
||
|
@@ -451,12 +449,6 @@ static void amd_iommu_domain_destroy(str
|
||
|
amd_iommu_flush_all_pages(d);
|
||
|
}
|
||
|
|
||
|
-static int amd_iommu_return_device(
|
||
|
- struct domain *s, struct domain *t, u16 seg, u8 bus, u8 devfn)
|
||
|
-{
|
||
|
- return reassign_device(s, t, seg, bus, devfn);
|
||
|
-}
|
||
|
-
|
||
|
static int amd_iommu_add_device(struct pci_dev *pdev)
|
||
|
{
|
||
|
struct amd_iommu *iommu;
|
||
|
@@ -596,7 +588,7 @@ const struct iommu_ops amd_iommu_ops = {
|
||
|
.teardown = amd_iommu_domain_destroy,
|
||
|
.map_page = amd_iommu_map_page,
|
||
|
.unmap_page = amd_iommu_unmap_page,
|
||
|
- .reassign_device = amd_iommu_return_device,
|
||
|
+ .reassign_device = reassign_device,
|
||
|
.get_device_group_id = amd_iommu_group_id,
|
||
|
.update_ire_from_apic = amd_iommu_ioapic_update_ire,
|
||
|
.update_ire_from_msi = amd_iommu_msi_msg_update_ire,
|
||
|
--- a/xen/drivers/passthrough/iommu.c
|
||
|
+++ b/xen/drivers/passthrough/iommu.c
|
||
|
@@ -232,11 +232,16 @@ static int assign_device(struct domain *
|
||
|
return -EXDEV;
|
||
|
|
||
|
spin_lock(&pcidevs_lock);
|
||
|
- pdev = pci_get_pdev(seg, bus, devfn);
|
||
|
- if ( pdev )
|
||
|
- pdev->fault.count = 0;
|
||
|
+ pdev = pci_get_pdev_by_domain(dom0, seg, bus, devfn);
|
||
|
+ if ( !pdev )
|
||
|
+ {
|
||
|
+ rc = pci_get_pdev(seg, bus, devfn) ? -EBUSY : -ENODEV;
|
||
|
+ goto done;
|
||
|
+ }
|
||
|
+
|
||
|
+ pdev->fault.count = 0;
|
||
|
|
||
|
- if ( (rc = hd->platform_ops->assign_device(d, seg, bus, devfn)) )
|
||
|
+ if ( (rc = hd->platform_ops->assign_device(d, devfn, pdev)) )
|
||
|
goto done;
|
||
|
|
||
|
if ( has_arch_pdevs(d) && !need_iommu(d) )
|
||
|
@@ -367,18 +372,11 @@ int deassign_device(struct domain *d, u1
|
||
|
return -EINVAL;
|
||
|
|
||
|
ASSERT(spin_is_locked(&pcidevs_lock));
|
||
|
- pdev = pci_get_pdev(seg, bus, devfn);
|
||
|
+ pdev = pci_get_pdev_by_domain(d, seg, bus, devfn);
|
||
|
if ( !pdev )
|
||
|
return -ENODEV;
|
||
|
|
||
|
- if ( pdev->domain != d )
|
||
|
- {
|
||
|
- dprintk(XENLOG_ERR VTDPREFIX,
|
||
|
- "d%d: deassign a device not owned\n", d->domain_id);
|
||
|
- return -EINVAL;
|
||
|
- }
|
||
|
-
|
||
|
- ret = hd->platform_ops->reassign_device(d, dom0, seg, bus, devfn);
|
||
|
+ ret = hd->platform_ops->reassign_device(d, dom0, devfn, pdev);
|
||
|
if ( ret )
|
||
|
{
|
||
|
dprintk(XENLOG_ERR VTDPREFIX,
|
||
|
--- a/xen/drivers/passthrough/vtd/iommu.c
|
||
|
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
||
|
@@ -1689,17 +1689,10 @@ out:
|
||
|
static int reassign_device_ownership(
|
||
|
struct domain *source,
|
||
|
struct domain *target,
|
||
|
- u16 seg, u8 bus, u8 devfn)
|
||
|
+ u8 devfn, struct pci_dev *pdev)
|
||
|
{
|
||
|
- struct pci_dev *pdev;
|
||
|
int ret;
|
||
|
|
||
|
- ASSERT(spin_is_locked(&pcidevs_lock));
|
||
|
- pdev = pci_get_pdev_by_domain(source, seg, bus, devfn);
|
||
|
-
|
||
|
- if (!pdev)
|
||
|
- return -ENODEV;
|
||
|
-
|
||
|
/*
|
||
|
* Devices assigned to untrusted domains (here assumed to be any domU)
|
||
|
* can attempt to send arbitrary LAPIC/MSI messages. We are unprotected
|
||
|
@@ -1708,16 +1701,19 @@ static int reassign_device_ownership(
|
||
|
if ( (target != dom0) && !iommu_intremap )
|
||
|
untrusted_msi = 1;
|
||
|
|
||
|
- ret = domain_context_unmap(source, seg, bus, devfn);
|
||
|
+ ret = domain_context_unmap(source, pdev->seg, pdev->bus, devfn);
|
||
|
if ( ret )
|
||
|
return ret;
|
||
|
|
||
|
- ret = domain_context_mapping(target, seg, bus, devfn);
|
||
|
+ ret = domain_context_mapping(target, pdev->seg, pdev->bus, devfn);
|
||
|
if ( ret )
|
||
|
return ret;
|
||
|
|
||
|
- list_move(&pdev->domain_list, &target->arch.pdev_list);
|
||
|
- pdev->domain = target;
|
||
|
+ if ( devfn == pdev->devfn )
|
||
|
+ {
|
||
|
+ list_move(&pdev->domain_list, &target->arch.pdev_list);
|
||
|
+ pdev->domain = target;
|
||
|
+ }
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
@@ -2207,36 +2203,26 @@ int __init intel_vtd_setup(void)
|
||
|
}
|
||
|
|
||
|
static int intel_iommu_assign_device(
|
||
|
- struct domain *d, u16 seg, u8 bus, u8 devfn)
|
||
|
+ struct domain *d, u8 devfn, struct pci_dev *pdev)
|
||
|
{
|
||
|
struct acpi_rmrr_unit *rmrr;
|
||
|
int ret = 0, i;
|
||
|
- struct pci_dev *pdev;
|
||
|
- u16 bdf;
|
||
|
+ u16 bdf, seg;
|
||
|
+ u8 bus;
|
||
|
|
||
|
if ( list_empty(&acpi_drhd_units) )
|
||
|
return -ENODEV;
|
||
|
|
||
|
- ASSERT(spin_is_locked(&pcidevs_lock));
|
||
|
- pdev = pci_get_pdev(seg, bus, devfn);
|
||
|
- if (!pdev)
|
||
|
- return -ENODEV;
|
||
|
-
|
||
|
- if (pdev->domain != dom0)
|
||
|
- {
|
||
|
- dprintk(XENLOG_ERR VTDPREFIX,
|
||
|
- "IOMMU: assign a assigned device\n");
|
||
|
- return -EBUSY;
|
||
|
- }
|
||
|
-
|
||
|
- ret = reassign_device_ownership(dom0, d, seg, bus, devfn);
|
||
|
+ ret = reassign_device_ownership(dom0, d, devfn, pdev);
|
||
|
if ( ret )
|
||
|
goto done;
|
||
|
|
||
|
/* FIXME: Because USB RMRR conflicts with guest bios region,
|
||
|
* ignore USB RMRR temporarily.
|
||
|
*/
|
||
|
- if ( is_usb_device(seg, bus, devfn) )
|
||
|
+ seg = pdev->seg;
|
||
|
+ bus = pdev->bus;
|
||
|
+ if ( is_usb_device(seg, bus, pdev->devfn) )
|
||
|
{
|
||
|
ret = 0;
|
||
|
goto done;
|
||
|
--- a/xen/include/xen/iommu.h
|
||
|
+++ b/xen/include/xen/iommu.h
|
||
|
@@ -123,13 +123,13 @@ struct iommu_ops {
|
||
|
int (*add_device)(struct pci_dev *pdev);
|
||
|
int (*enable_device)(struct pci_dev *pdev);
|
||
|
int (*remove_device)(struct pci_dev *pdev);
|
||
|
- int (*assign_device)(struct domain *d, u16 seg, u8 bus, u8 devfn);
|
||
|
+ int (*assign_device)(struct domain *, u8 devfn, struct pci_dev *);
|
||
|
void (*teardown)(struct domain *d);
|
||
|
int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn,
|
||
|
unsigned int flags);
|
||
|
int (*unmap_page)(struct domain *d, unsigned long gfn);
|
||
|
int (*reassign_device)(struct domain *s, struct domain *t,
|
||
|
- u16 seg, u8 bus, u8 devfn);
|
||
|
+ u8 devfn, struct pci_dev *);
|
||
|
int (*get_device_group_id)(u16 seg, u8 bus, u8 devfn);
|
||
|
void (*update_ire_from_apic)(unsigned int apic, unsigned int reg, unsigned int value);
|
||
|
void (*update_ire_from_msi)(struct msi_desc *msi_desc, struct msi_msg *msg);
|