difficult to deal with, and I'm not sure what we can do with them other
than warn when we might hit problems and prevent them from being moved
to a VM domain. The patch below does that, though I fear we may be
tweaking what devices we white-list for a while. Comments? Thanks,
Alex
commit db9778445a5347a817263db60bfb432f235411ba
Author: Alex Williamson <alex.williamson@hp.com>
Date: Wed Oct 28 14:10:56 2009 -0600
intel-iommu: warn/prevent operations on devices with RMRRs
RMRRs throw a wrench in our ability to change VT-d domain mapping since
they may be used for side-band platform purposes and we cannot switch
domain mappings seamlessly. RMRRs for USB devices are typical, but
anything else is likely suspect. Provide a warning when such devices
are removed from an identity map and prevent them from being assigned
to a VM.
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
@@ -49,6 +49,7 @@
#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
+#define IS_USB_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_SERIAL_USB)
#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
#define IOAPIC_RANGE_START (0xfee00000)
@@ -2517,6 +2518,25 @@ static int iommu_dummy(struct pci_dev *pdev)
return pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO;
}
+static int device_has_rmrr(struct pci_dev *pdev)
+{
+ struct dmar_rmrr_unit *rmrr;
+ int i;
+
+ /*
+ * USB devices do typically have RMRRs for DOS
+ * compatibility, but can typically be ignored.
+ */
+ if (IS_USB_DEVICE(pdev))
+ return 0;
+
+ for_each_rmrr_units(rmrr)
+ for (i = 0; i < rmrr->devices_cnt; i++)
+ if (pdev == rmrr->devices[i])
+ return 1;
+ return 0;
+}
+
/* Check if the pdev needs to go through non-identity map and unmap process.*/
static int iommu_no_mapping(struct device *dev)
{
@@ -2546,6 +2566,13 @@ static int iommu_no_mapping(struct device *dev)
domain_remove_one_dev_info(si_domain, pdev);
printk(KERN_INFO "%s uses non-identity mapping\n",
pci_name(pdev));
+
+ if (device_has_rmrr(pdev))
+ printk(KERN_WARNING
+ "IOMMU: Warning RMRRs for %s not mapped\n",
+ pci_name(pdev));
+
+
return 0;
}
} else {
@@ -3544,6 +3571,13 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
int addr_width;
u64 end;
+ if (device_has_rmrr(pdev)) {
+ printk(KERN_WARNING
+ "IOMMU: Device %s requires RMRRs, cannot be attached\n",
+ pci_name(pdev));
+ return -EBUSY;
+ }
+
/* normally pdev is not mapped */
if (unlikely(domain_context_mapped(pdev))) {
struct dmar_domain *old_domain;