60fee70571
OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=55b9cda496deba4d219bfb38823f905d
139 lines
4.7 KiB
Diff
139 lines
4.7 KiB
Diff
References: bnc#573413
|
|
|
|
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1274253726 -3600
|
|
# Node ID f67ae6f9d4107f091d062fc1501a96f873671d10
|
|
# Parent eb4ecc037b7a53647f0ac89c7067d11ea622ab00
|
|
VT-d: Fix ATS enabling for device assignment
|
|
|
|
Currently, Xen only enables ATS in Xen booting. When an ATS capable
|
|
device is assigned to guest, ATS is actually not enabled because FLR
|
|
before assignment causes it to be disabled. Thus ATS cannot be used in
|
|
guest. This patch enables ATS in domain_context_mapping. This ensures
|
|
ATS is enabled in assignment because FLR is earlier than
|
|
domain_context_mapping call. Therefore ATS can be used in guest. This
|
|
patch also implements disable_ats_device to disable ATS when the
|
|
device is deassigned from a domain.
|
|
|
|
Signed-off-by: Weidong Han <weidong.han@intel.com>
|
|
|
|
--- a/xen/drivers/passthrough/vtd/ia64/ats.c
|
|
+++ b/xen/drivers/passthrough/vtd/ia64/ats.c
|
|
@@ -47,6 +47,11 @@ int enable_ats_device(int seg, int bus,
|
|
return 0;
|
|
}
|
|
|
|
+int disable_ats_device(int seg, int bus, int devfn)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int dev_invalidate_iotlb(struct iommu *iommu, u16 did,
|
|
u64 addr, unsigned int size_order, u64 type)
|
|
{
|
|
--- a/xen/drivers/passthrough/vtd/iommu.c
|
|
+++ b/xen/drivers/passthrough/vtd/iommu.c
|
|
@@ -1324,6 +1324,9 @@ static int domain_context_mapping(struct
|
|
dprintk(VTDPREFIX, "d%d:PCIe: map bdf = %x:%x.%x\n",
|
|
domain->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
|
ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn);
|
|
+ if ( !ret && ats_device(0, bus, devfn) )
|
|
+ enable_ats_device(0, bus, devfn);
|
|
+
|
|
break;
|
|
|
|
case DEV_TYPE_PCI:
|
|
@@ -1453,6 +1456,9 @@ static int domain_context_unmap(struct d
|
|
dprintk(VTDPREFIX, "d%d:PCIe: unmap bdf = %x:%x.%x\n",
|
|
domain->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
|
ret = domain_context_unmap_one(domain, iommu, bus, devfn);
|
|
+ if ( !ret && ats_device(0, bus, devfn) )
|
|
+ disable_ats_device(0, bus, devfn);
|
|
+
|
|
break;
|
|
|
|
case DEV_TYPE_PCI:
|
|
@@ -1771,8 +1777,6 @@ static void setup_dom0_devices(struct do
|
|
list_add(&pdev->domain_list, &d->arch.pdev_list);
|
|
domain_context_mapping(d, pdev->bus, pdev->devfn);
|
|
pci_enable_acs(pdev);
|
|
- if ( ats_device(0, pdev->bus, pdev->devfn) )
|
|
- enable_ats_device(0, pdev->bus, pdev->devfn);
|
|
}
|
|
}
|
|
spin_unlock(&pcidevs_lock);
|
|
--- a/xen/drivers/passthrough/vtd/x86/ats.c
|
|
+++ b/xen/drivers/passthrough/vtd/x86/ats.c
|
|
@@ -92,6 +92,9 @@ int ats_device(int seg, int bus, int dev
|
|
|
|
pdev = pci_get_pdev(bus, devfn);
|
|
drhd = acpi_find_matched_drhd_unit(pdev);
|
|
+ if ( !drhd )
|
|
+ return 0;
|
|
+
|
|
if ( !ecap_queued_inval(drhd->iommu->ecap) ||
|
|
!ecap_dev_iotlb(drhd->iommu->ecap) )
|
|
return 0;
|
|
@@ -144,6 +147,9 @@ int enable_ats_device(int seg, int bus,
|
|
|
|
value = pci_conf_read16(bus, PCI_SLOT(devfn),
|
|
PCI_FUNC(devfn), pos + ATS_REG_CTL);
|
|
+ if ( value & ATS_ENABLE )
|
|
+ return 0;
|
|
+
|
|
value |= ATS_ENABLE;
|
|
pci_conf_write16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
|
pos + ATS_REG_CTL, value);
|
|
@@ -153,10 +159,50 @@ int enable_ats_device(int seg, int bus,
|
|
pdev->devfn = devfn;
|
|
pdev->ats_queue_depth = queue_depth;
|
|
list_add(&(pdev->list), &ats_devices);
|
|
+ if ( iommu_verbose )
|
|
+ dprintk(XENLOG_INFO VTDPREFIX, "%x:%x.%x: ATS is enabled\n",
|
|
+ bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
|
|
|
return pos;
|
|
}
|
|
|
|
+int disable_ats_device(int seg, int bus, int devfn)
|
|
+{
|
|
+ struct list_head *pdev_list, *tmp;
|
|
+ struct pci_ats_dev *pdev;
|
|
+ u32 value;
|
|
+ int pos;
|
|
+
|
|
+ pos = pci_find_ext_capability(seg, bus, devfn, PCI_EXT_CAP_ID_ATS);
|
|
+ if ( !pos )
|
|
+ return 0;
|
|
+
|
|
+ /* BUGBUG: add back seg when multi-seg platform support is enabled */
|
|
+ value = pci_conf_read16(bus, PCI_SLOT(devfn),
|
|
+ PCI_FUNC(devfn), pos + ATS_REG_CTL);
|
|
+ value &= ~ATS_ENABLE;
|
|
+ pci_conf_write16(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
|
|
+ pos + ATS_REG_CTL, value);
|
|
+
|
|
+ list_for_each_safe( pdev_list, tmp, &ats_devices )
|
|
+ {
|
|
+ pdev = list_entry(pdev_list, struct pci_ats_dev, list);
|
|
+ if ( pdev->bus == bus && pdev->devfn == devfn )
|
|
+ {
|
|
+ list_del(&pdev->list);
|
|
+ xfree(pdev);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ( iommu_verbose )
|
|
+ dprintk(XENLOG_INFO VTDPREFIX, "%x:%x.%x: ATS is disabled\n",
|
|
+ bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
static int device_in_domain(struct iommu *iommu, struct pci_ats_dev *pdev, u16 did)
|
|
{
|
|
struct root_entry *root_entry = NULL;
|