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:
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:
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);
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;
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);
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;