OSDN Git Service

PCI: Add DMA alias quirk for Adaptec 3405
authorAlex Williamson <alex.williamson@redhat.com>
Tue, 13 Jan 2015 18:26:50 +0000 (11:26 -0700)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 23 Jan 2015 21:44:45 +0000 (15:44 -0600)
The Adaptec 3405 is actually an Intel 80333 I/O processor where the exposed
device at 0e.0 is actually the address translation unit of the I/O
processor and a hidden, private device at 01.0 masters the DMA for the
device.  Create a fixed alias between the exposed and hidden devfn so we
can enable the IOMMU.

Scenarios like this are potentially likely for any device incorporating
this I/O processor, so this little bit of abstraction with the fixed alias
table should make future additions trivial.

Without this fix, booting a system with the Intel IOMMU enabled and an
Adaptec 3405 at 02:0e.0 results in a flood of errors like this:

  dmar: DRHD: handling fault status reg 3
  dmar: DMAR:[DMA Write] Request device [02:01.0] fault addr ffbff000
  DMAR:[fault reason 02] Present bit in context entry is clear

[bhelgaas: changelog, comment]
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Adaptec OEM Raid Solutions <aacraid@adaptec.com>
drivers/pci/quirks.c

index 3fb378a..45bd870 100644 (file)
@@ -3563,6 +3563,44 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON,
                         quirk_dma_func1_alias);
 
 /*
+ * Some devices DMA with the wrong devfn, not just the wrong function.
+ * quirk_fixed_dma_alias() uses this table to create fixed aliases, where
+ * the alias is "fixed" and independent of the device devfn.
+ *
+ * For example, the Adaptec 3405 is a PCIe card with an Intel 80333 I/O
+ * processor.  To software, this appears as a PCIe-to-PCI/X bridge with a
+ * single device on the secondary bus.  In reality, the single exposed
+ * device at 0e.0 is the Address Translation Unit (ATU) of the controller
+ * that provides a bridge to the internal bus of the I/O processor.  The
+ * controller supports private devices, which can be hidden from PCI config
+ * space.  In the case of the Adaptec 3405, a private device at 01.0
+ * appears to be the DMA engine, which therefore needs to become a DMA
+ * alias for the device.
+ */
+static const struct pci_device_id fixed_dma_alias_tbl[] = {
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
+                        PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */
+         .driver_data = PCI_DEVFN(1, 0) },
+       { 0 }
+};
+
+static void quirk_fixed_dma_alias(struct pci_dev *dev)
+{
+       const struct pci_device_id *id;
+
+       id = pci_match_id(fixed_dma_alias_tbl, dev);
+       if (id) {
+               dev->dma_alias_devfn = id->driver_data;
+               dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
+               dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n",
+                        PCI_SLOT(dev->dma_alias_devfn),
+                        PCI_FUNC(dev->dma_alias_devfn));
+       }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);
+
+/*
  * A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in
  * using the wrong DMA alias for the device.  Some of these devices can be
  * used as either forward or reverse bridges, so we need to test whether the