powerpc/powernv: Fix IOMMU table for VFIO dev
authorGavin Shan <gwshan@linux.vnet.ibm.com>
Tue, 15 Jul 2014 07:00:55 +0000 (17:00 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 5 Aug 2014 05:41:12 +0000 (15:41 +1000)
On PHB3, PCI devices can bypass IOMMU for DMA access. If we pass
through one PCI device, whose hose driver ever enable the bypass
mode, pdev->dev.archdata.dma_data.iommu_table_base isn't IOMMU
table. However, EEH needs access the IOMMU table when the device
is owned by guest.

The patch fixes pdev->dev.archdata.dma_data.iommu_table when
passing through the device to guest in pnv_pci_ioda2_set_bypass().

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/platforms/powernv/pci-ioda.c

index 866692b851f29557fc94da64a7f4921fc83f00e0..035db476be0e02137128d285d01e1390fed9355a 100644 (file)
@@ -495,14 +495,22 @@ static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
        return 0;
 }
 
-static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
+static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
+                                  struct pci_bus *bus,
+                                  bool add_to_iommu_group)
 {
        struct pci_dev *dev;
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
-               set_iommu_table_base_and_group(&dev->dev, &pe->tce32_table);
+               if (add_to_iommu_group)
+                       set_iommu_table_base_and_group(&dev->dev,
+                                                      &pe->tce32_table);
+               else
+                       set_iommu_table_base(&dev->dev, &pe->tce32_table);
+
                if (dev->subordinate)
-                       pnv_ioda_setup_bus_dma(pe, dev->subordinate);
+                       pnv_ioda_setup_bus_dma(pe, dev->subordinate,
+                                              add_to_iommu_group);
        }
 }
 
@@ -680,7 +688,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
        if (pe->pdev)
                set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
        else
-               pnv_ioda_setup_bus_dma(pe, pe->pbus);
+               pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
 
        return;
  fail:
@@ -716,11 +724,15 @@ static void pnv_pci_ioda2_set_bypass(struct iommu_table *tbl, bool enable)
                                                     0);
 
                /*
-                * We might want to reset the DMA ops of all devices on
-                * this PE. However in theory, that shouldn't be necessary
-                * as this is used for VFIO/KVM pass-through and the device
-                * hasn't yet been returned to its kernel driver
+                * EEH needs the mapping between IOMMU table and group
+                * of those VFIO/KVM pass-through devices. We can postpone
+                * resetting DMA ops until the DMA mask is configured in
+                * host side.
                 */
+               if (pe->pdev)
+                       set_iommu_table_base(&pe->pdev->dev, tbl);
+               else
+                       pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
        }
        if (rc)
                pe_err(pe, "OPAL error %lld configuring bypass window\n", rc);
@@ -809,7 +821,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
        if (pe->pdev)
                set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
        else
-               pnv_ioda_setup_bus_dma(pe, pe->pbus);
+               pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
 
        /* Also create a bypass window */
        pnv_pci_ioda2_setup_bypass_pe(phb, pe);