Skip to content

Commit 763fe0a

Browse files
Gavin Shanozbenh
Gavin Shan
authored andcommitted
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: <[email protected]> # 3.16+ Reported-by: Thadeu Lima de Souza Cascardo <[email protected]> Signed-off-by: Gavin Shan <[email protected]> Acked-by: Wei Yang <[email protected]> Signed-off-by: Benjamin Herrenschmidt <[email protected]>
1 parent 78e05b1 commit 763fe0a

File tree

2 files changed

+22
-18
lines changed

2 files changed

+22
-18
lines changed

arch/powerpc/kernel/iommu.c

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,37 +1120,41 @@ EXPORT_SYMBOL_GPL(iommu_release_ownership);
11201120
int iommu_add_device(struct device *dev)
11211121
{
11221122
struct iommu_table *tbl;
1123-
int ret = 0;
11241123

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));
11291136
return -EBUSY;
11301137
}
11311138

11321139
tbl = get_iommu_table_base(dev);
11331140
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));
11361143
return 0;
11371144
}
11381145

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));
11411149

11421150
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));
11451154
return -EINVAL;
11461155
}
11471156

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);
11541158
}
11551159
EXPORT_SYMBOL_GPL(iommu_add_device);
11561160

arch/powerpc/platforms/powernv/pci-ioda.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
857857

858858
pe = &phb->ioda.pe_array[pdn->pe_number];
859859
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);
861861
}
862862

863863
static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,

0 commit comments

Comments
 (0)