Integrating IOMMU groups more closely into the driver core allows us to more easily work around DMA quirks. The Ricoh multifunction controller is a favorite example of devices that are currently incompatible with IOMMU isolation as all the functions use the requestor ID of function 0 for DMA. Passing this device into pci_dma_quirk returns the PCI device to use for DMA. The IOMMU driver can then construct an IOMMU group including both devices. Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx> --- drivers/pci/quirks.c | 22 ++++++++++++++++++++++ include/linux/pci.h | 2 ++ 2 files changed, 24 insertions(+), 0 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4bf7102..6f9f7f9 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3109,3 +3109,25 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe) return -ENOTTY; } + +struct pci_dev *pci_dma_quirk(struct pci_dev *dev) +{ + struct pci_dev *dma_dev = dev; + + /* + * https://bugzilla.redhat.com/show_bug.cgi?id=605888 + * + * Some Ricoh devices use the function 0 source ID for DMA on + * other functions of a multifunction device. The DMA devices + * is therefore function 0, which will have implications of the + * iommu grouping of these devices. + */ + if (dev->vendor == PCI_VENDOR_ID_RICOH && + (dev->device == 0xe822 || dev->device == 0xe230 || + dev->device == 0xe832 || dev->device == 0xe476)) { + dma_dev = pci_get_slot(dev->bus, + PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); + } + + return dma_dev; +} diff --git a/include/linux/pci.h b/include/linux/pci.h index e444f5b..9910b5c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1479,9 +1479,11 @@ enum pci_fixup_pass { #ifdef CONFIG_PCI_QUIRKS void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); +struct pci_dev *pci_dma_quirk(struct pci_dev *dev); #else static inline void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {} +struct pci_dev *pci_dma_quirk(struct pci_dev *dev) { return dev } #endif void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html