The PCI devices handled by intel-iommu may have a DMA requester on
another bus, such as VMD subdevices needing to use the VMD endpoint.

The real DMA device is now used for the DMA mapping, but one case was
missed earlier, when allocating memory through (e.g.) intel_map_page().
Confusion ensues if the iommu domain type for the subdevice does not match
the iommu domain type for the real DMA device.

For example, take the case of the subdevice handled by intel_map_page()
in a IOMMU_DOMAIN_DMA, with the real DMA device in a
IOMMU_DOMAIN_IDENTITY:

1. intel_map_page() checks if an IOMMU mapping is needed by calling
   iommu_need_mapping() on the subdevice. Result: mapping is needed.
2. __intel_map_single() is called to create the mapping:
  - __intel_map_single() calls find_domain(). This function now returns
    the IDENTITY domain corresponding to the real DMA device.
  - __intel_map_single() then calls domain_get_iommu() on this "real"
    domain. A failure is hit and the entire operation is aborted, because
    this codepath is not intended to handle IDENTITY mappings:
        if (WARN_ON(domain->domain.type != IOMMU_DOMAIN_DMA))
             return NULL;

Fix this by using the real DMA device when checking if a mapping is
needed. The above case will then directly fall back on
dma_direct_map_page().

Fixes: 2b0140c69637 ("iommu/vt-d: Use pci_real_dma_dev() for mapping")
Signed-off-by: Daniel Drake <dr...@endlessm.com>
---

Notes:
    This problem was detected with a non-upstream patch
    "PCI: Add Intel remapped NVMe device support"
    (https://marc.info/?l=linux-ide&m=156015271021615&w=2)
    
    This patch creates PCI devices in the same way as VMD, and hence
    I believe VMD would hit this class of problem for any cases where
    iommu domain type may mismatch between subdevice and real device,
    which we have run into here.
    
    However this hasn't actually been tested on VMD (don't have the hardware)
    so if I've missed anything and/or it's not a real issue then feel free to
    drop this patch.

 drivers/iommu/intel-iommu.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 9dc37672bf89..713810f8350c 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3587,6 +3587,9 @@ static bool iommu_need_mapping(struct device *dev)
        if (iommu_dummy(dev))
                return false;
 
+       if (dev_is_pci(dev))
+               dev = &pci_real_dma_dev(to_pci_dev(dev))->dev;
+
        ret = identity_mapping(dev);
        if (ret) {
                u64 dma_mask = *dev->dma_mask;
-- 
2.20.1

_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to