Commit 763fe0addb8fe15ccea67c0aebddc06f4bb25439

Authored by Gavin Shan
Committed by Benjamin Herrenschmidt
1 parent 78e05b1421

powerpc/powernv: Fix IOMMU group lost

When we take full hotplug to recover from EEH errors, PCI buses
could be involved. For the case, the child devices of involved
PCI buses can't be attached to IOMMU group properly, which is
caused by commit 3f28c5a ("powerpc/powernv: Reduce multi-hit of
iommu_add_device()").

When adding the PCI devices of the newly created PCI buses to
the system, the IOMMU group is expected to be added in (C).
(A) fails to bind the IOMMU group because bus->is_added is
false. (B) fails because the device doesn't have binding IOMMU
table yet. bus->is_added is set to true at end of (C) and
pdev->is_added is set to true at (D).

   pcibios_add_pci_devices()
      pci_scan_bridge()
         pci_scan_child_bus()
            pci_scan_slot()
               pci_scan_single_device()
                  pci_scan_device()
                  pci_device_add()
                     pcibios_add_device()           A: Ignore
                     device_add()                   B: Ignore
                  pcibios_fixup_bus()
                     pcibios_setup_bus_devices()
                        pcibios_setup_device()      C: Hit
      pcibios_finish_adding_to_bus()
         pci_bus_add_devices()
            pci_bus_add_device()                    D: Add device

If the parent PCI bus isn't involved in hotplug, the IOMMU
group is expected to be bound in (B). (A) should fail as the
sysfs entries aren't populated.

The patch fixes the issue by reverting commit 3f28c5a and remove
WARN_ON() in iommu_add_device() to allow calling the function
even the specified device already has associated IOMMU group.

Cc: <stable@vger.kernel.org>  # 3.16+
Reported-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Acked-by: Wei Yang <weiyang@linux.vnet.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Showing 2 changed files with 22 additions and 18 deletions Side-by-side Diff

arch/powerpc/kernel/iommu.c
... ... @@ -1120,37 +1120,41 @@
1120 1120 int iommu_add_device(struct device *dev)
1121 1121 {
1122 1122 struct iommu_table *tbl;
1123   - int ret = 0;
1124 1123  
1125   - if (WARN_ON(dev->iommu_group)) {
1126   - pr_warn("iommu_tce: device %s is already in iommu group %d, skipping\n",
1127   - dev_name(dev),
1128   - iommu_group_id(dev->iommu_group));
  1124 + /*
  1125 + * The sysfs entries should be populated before
  1126 + * binding IOMMU group. If sysfs entries isn't
  1127 + * ready, we simply bail.
  1128 + */
  1129 + if (!device_is_registered(dev))
  1130 + return -ENOENT;
  1131 +
  1132 + if (dev->iommu_group) {
  1133 + pr_debug("%s: Skipping device %s with iommu group %d\n",
  1134 + __func__, dev_name(dev),
  1135 + iommu_group_id(dev->iommu_group));
1129 1136 return -EBUSY;
1130 1137 }
1131 1138  
1132 1139 tbl = get_iommu_table_base(dev);
1133 1140 if (!tbl || !tbl->it_group) {
1134   - pr_debug("iommu_tce: skipping device %s with no tbl\n",
1135   - dev_name(dev));
  1141 + pr_debug("%s: Skipping device %s with no tbl\n",
  1142 + __func__, dev_name(dev));
1136 1143 return 0;
1137 1144 }
1138 1145  
1139   - pr_debug("iommu_tce: adding %s to iommu group %d\n",
1140   - dev_name(dev), iommu_group_id(tbl->it_group));
  1146 + pr_debug("%s: Adding %s to iommu group %d\n",
  1147 + __func__, dev_name(dev),
  1148 + iommu_group_id(tbl->it_group));
1141 1149  
1142 1150 if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) {
1143   - pr_err("iommu_tce: unsupported iommu page size.");
1144   - pr_err("%s has not been added\n", dev_name(dev));
  1151 + pr_err("%s: Invalid IOMMU page size %lx (%lx) on %s\n",
  1152 + __func__, IOMMU_PAGE_SIZE(tbl),
  1153 + PAGE_SIZE, dev_name(dev));
1145 1154 return -EINVAL;
1146 1155 }
1147 1156  
1148   - ret = iommu_group_add_device(tbl->it_group, dev);
1149   - if (ret < 0)
1150   - pr_err("iommu_tce: %s has not been added, ret=%d\n",
1151   - dev_name(dev), ret);
1152   -
1153   - return ret;
  1157 + return iommu_group_add_device(tbl->it_group, dev);
1154 1158 }
1155 1159 EXPORT_SYMBOL_GPL(iommu_add_device);
1156 1160  
arch/powerpc/platforms/powernv/pci-ioda.c
... ... @@ -857,7 +857,7 @@
857 857  
858 858 pe = &phb->ioda.pe_array[pdn->pe_number];
859 859 WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops);
860   - set_iommu_table_base(&pdev->dev, &pe->tce32_table);
  860 + set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
861 861 }
862 862  
863 863 static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,