Skip to content

Commit b8f712c

Browse files
nicolincvijay-suman
authored andcommitted
iommu/arm-smmu-v3: Fix iommu_device_probe bug due to duplicated stream ids
[ Upstream commit b00d24997a11c10d3e420614f0873b83ce358a34 ] ASPEED VGA card has two built-in devices: 0008:06:00.0 PCI bridge: ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge (rev 06) 0008:07:00.0 VGA compatible controller: ASPEED Technology, Inc. ASPEED Graphics Family (rev 52) Its toplogy looks like this: +-[0008:00]---00.0-[01-09]--+-00.0-[02-09]--+-00.0-[03]----00.0 Sandisk Corp Device 5017 | +-01.0-[04]-- | +-02.0-[05]----00.0 NVIDIA Corporation Device | +-03.0-[06-07]----00.0-[07]----00.0 ASPEED Technology, Inc. ASPEED Graphics Family | +-04.0-[08]----00.0 Renesas Technology Corp. uPD720201 USB 3.0 Host Controller | \-05.0-[09]----00.0 Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller \-00.1 PMC-Sierra Inc. Device 4028 The IORT logic populaties two identical IDs into the fwspec->ids array via DMA aliasing in iort_pci_iommu_init() called by pci_for_each_dma_alias(). Though the SMMU driver had been able to handle this situation since commit 563b5cb ("iommu/arm-smmu-v3: Cope with duplicated Stream IDs"), that got broken by the later commit cdf315f ("iommu/arm-smmu-v3: Maintain a SID->device structure"), which ended up with allocating separate streams with the same stuffing. On a kernel prior to v6.15-rc1, there has been an overlooked warning: pci 0008:07:00.0: vgaarb: setting as boot VGA device pci 0008:07:00.0: vgaarb: bridge control possible pci 0008:07:00.0: vgaarb: VGA device added: decodes=io+mem,owns=none,locks=none pcieport 0008:06:00.0: Adding to iommu group 14 ast 0008:07:00.0: stream 67328 already in tree <===== WARNING ast 0008:07:00.0: enabling device (0002 -> 0003) ast 0008:07:00.0: Using default configuration ast 0008:07:00.0: AST 2600 detected ast 0008:07:00.0: [drm] Using analog VGA ast 0008:07:00.0: [drm] dram MCLK=396 Mhz type=1 bus_width=16 [drm] Initialized ast 0.1.0 for 0008:07:00.0 on minor 0 ast 0008:07:00.0: [drm] fb0: astdrmfb frame buffer device With v6.15-rc, since the commit bcb81ac6ae3c ("iommu: Get DT/ACPI parsing into the proper probe path"), the error returned with the warning is moved to the SMMU device probe flow: arm_smmu_probe_device+0x15c/0x4c0 __iommu_probe_device+0x150/0x4f8 probe_iommu_group+0x44/0x80 bus_for_each_dev+0x7c/0x100 bus_iommu_probe+0x48/0x1a8 iommu_device_register+0xb8/0x178 arm_smmu_device_probe+0x1350/0x1db0 which then fails the entire SMMU driver probe: pci 0008:06:00.0: Adding to iommu group 21 pci 0008:07:00.0: stream 67328 already in tree arm-smmu-v3 arm-smmu-v3.9.auto: Failed to register iommu arm-smmu-v3 arm-smmu-v3.9.auto: probe with driver arm-smmu-v3 failed with error -22 Since SMMU driver had been already expecting a potential duplicated Stream ID in arm_smmu_install_ste_for_dev(), change the arm_smmu_insert_master() routine to ignore a duplicated ID from the fwspec->sids array as well. Note: this has been failing the iommu_device_probe() since 2021, although a recent iommu commit in v6.15-rc1 that moves iommu_device_probe() started to fail the SMMU driver probe. Since nobody has cared about DMA Alias support, leave that as it was but fix the fundamental iommu_device_probe() breakage. Fixes: cdf315f ("iommu/arm-smmu-v3: Maintain a SID->device structure") Cc: [email protected] Suggested-by: Jason Gunthorpe <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Signed-off-by: Nicolin Chen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]> Signed-off-by: Sasha Levin <[email protected]> (cherry picked from commit 655e607898f8cdfdb29fd2a6e618d11de99ec17a) Signed-off-by: Vijayendra Suman <[email protected]>
1 parent 496c37b commit b8f712c

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2675,6 +2675,7 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
26752675
mutex_lock(&smmu->streams_mutex);
26762676
for (i = 0; i < fwspec->num_ids; i++) {
26772677
struct arm_smmu_stream *new_stream = &master->streams[i];
2678+
struct rb_node *existing;
26782679
u32 sid = fwspec->ids[i];
26792680

26802681
new_stream->id = sid;
@@ -2696,10 +2697,20 @@ static int arm_smmu_insert_master(struct arm_smmu_device *smmu,
26962697
}
26972698

26982699
/* Insert into SID tree */
2699-
if (rb_find_add(&new_stream->node, &smmu->streams,
2700-
arm_smmu_streams_cmp_node)) {
2701-
dev_warn(master->dev, "stream %u already in tree\n",
2702-
sid);
2700+
existing = rb_find_add(&new_stream->node, &smmu->streams,
2701+
arm_smmu_streams_cmp_node);
2702+
if (existing) {
2703+
struct arm_smmu_master *existing_master =
2704+
rb_entry(existing, struct arm_smmu_stream, node)
2705+
->master;
2706+
2707+
/* Bridged PCI devices may end up with duplicated IDs */
2708+
if (existing_master == master)
2709+
continue;
2710+
2711+
dev_warn(master->dev,
2712+
"stream %u already in tree from dev %s\n", sid,
2713+
dev_name(existing_master->dev));
27032714
ret = -EINVAL;
27042715
break;
27052716
}

0 commit comments

Comments
 (0)