diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2015-01-13 19:26:50 +0100 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2015-01-23 22:44:45 +0100 |
commit | d3d2ab43ddae5f958461ac0a9a2b484a68194df5 (patch) | |
tree | 60910830d853171b5511653903c53559b9ba768d /drivers/pci | |
parent | PCI: Add ACS quirk for Emulex NICs (diff) | |
download | linux-d3d2ab43ddae5f958461ac0a9a2b484a68194df5.tar.xz linux-d3d2ab43ddae5f958461ac0a9a2b484a68194df5.zip |
PCI: Add DMA alias quirk for Adaptec 3405
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>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/quirks.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 3fb378aa7c53..45bd8704c99d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -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 |