[PATCH] drivers/iommu: Protect STE base address in multi-core and multi-process concurrent scenarios
niliqiang
ni_liqiang at 126.com
Mon Nov 11 06:28:00 PST 2024
From: "ni.liqiang" <ni_liqiang at 126.com>
Background information
======================
During the testing of our self-developed FPGA test board based on
linux 5.10.134, we identified an issue when concurrently loading drivers
for different PCIe peripherals, specifically with BDF numbers 0001:81:00.0
and 0001:81:00.1, in a multi-core, multi-process setup.
During this process, the SMMU_STRTAB_BASE was allocated multiple times,
leading to errors in the STE content.
To address this, we referred to a relevant patch(https://lore.kernel.org/
linux-arm-kernel/20210401154718.307519-8-jean-philippe at linaro.org/)
from the Linux 5.13 kernel and introduced a mutex to ensure that
in the context of a single SMMU instance, the SMMU_STRTAB_BASE for devices
of the same type is only allocated once during concurrent operations.
Our testing confirmed that the issue of duplicate SMMU_STRTAB_BASE
allocation was resolved.
The issues
==========
I would like to know whether this is a known flaw in the Linux 5.10 kernel?
And is adding a mutex the correct and reasonable solution to this problem?
The call trace when two PCIe devices, each associated with a different
CPU, are accessed concurrently by two processes
======================================================================
> CPU: 3 PID: 433 Comm: systemd-udevd Tainted: G OE 5.10.134-iommu #26
> Call trace:
> dump_backtrace+0x0/0x208
> show_stack+0x1c/0x28
> dump_stack+0xd4/0x128
> arm_smmu_write_strtab_ent+0xa0/0x3a8
> arm_smmu_probe_device+0x1e0/0x670
> __iommu_probe_device+0x5c/0x2a0
> iommu_probe_device+0x2c/0x128
> iort_iommu_configure_id+0x17c/0x240
> acpi_dma_configure_id+0x8c/0xb8
> pci_dma_configure+0xa8/0xc8
> really_probe+0x74/0x420
> __driver_probe_device+0x114/0x188
> driver_probe_device+0x44/0x110
> __driver_attach+0xbc/0x1a0
> bus_for_each_dev+0x78/0xc8
> driver_attach+0x28/0x30
> bus_add_driver+0x1a4/0x248
> driver_register+0x68/0x118
> __pci_register_driver+0x48/0x50
> dh_pf_pci_init_module+0x88/0x1000 [zg_pf]
> do_one_initcall+0x50/0x268
> do_init_module+0x4c/0x228
> load_module+0x1998/0x1c70
> __do_sys_finit_module+0xbc/0x120
> __arm64_sys_finit_module+0x24/0x30
> el0_svc_common+0xb8/0x208
> do_el0_svc+0x88/0x90
> el0_svc+0x1c/0x28
> el0_sync_handler+0x88/0xb0
> el0_sync+0x148/0x180
> CPU: 2 PID: 423 Comm: systemd-udevd Tainted: G OE 5.10.134-iommu #26
> Call trace:
> zg_pf 0001:81:00.1: Adding to iommu group 8
> dump_backtrace+0x0/0x208
> show_stack+0x1c/0x28
> dump_stack+0xd4/0x128
> arm_smmu_write_strtab_ent+0xa0/0x3a8
> arm_smmu_probe_device+0x1e0/0x670
> __iommu_probe_device+0x5c/0x2a0
> iommu_probe_device+0x2c/0x128
> iort_iommu_configure_id+0x17c/0x240
> acpi_dma_configure_id+0x8c/0xb8
> pci_dma_configure+0xa8/0xc8
> really_probe+0x74/0x420
> __driver_probe_device+0x114/0x188
> driver_probe_device+0x44/0x110
> __driver_attach+0xbc/0x1a0
> bus_for_each_dev+0x78/0xc8
> driver_attach+0x28/0x30
> bus_add_driver+0x1a4/0x248
> driver_register+0x68/0x118
> __pci_register_driver+0x48/0x50
> init+0x44/0x1000 [zgm_pf]
> do_one_initcall+0x50/0x268
> do_init_module+0x4c/0x228
> load_module+0x1998/0x1c70
> __do_sys_finit_module+0xbc/0x120
> __arm64_sys_finit_module+0x24/0x30
> el0_svc_common+0xb8/0x208
> do_el0_svc+0x88/0x90
> el0_svc+0x1c/0x28
> el0_sync_handler+0x88/0xb0
> el0_sync+0x148/0x180
> zgm_pf 0001:81:00.0: Adding to iommu group 9
Signed-off-by: ni.liqiang <ni_liqiang at 126.com>
Reviewed-by: li.zhichao <li.zhichao at zte.com.cn>
Tested-by: ma.weichao <ma.weichao at zte.com.cn>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 4 ++++
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 2 ++
2 files changed, 6 insertions(+)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 9ac7b3729..b5b58e53d 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -2346,6 +2346,7 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
INIT_LIST_HEAD(&master->bonds);
dev_iommu_priv_set(dev, master);
+ mutex_lock(&smmu->streams_mutex);
/* Check the SIDs are in range of the SMMU and our stream table */
for (i = 0; i < master->num_sids; i++) {
u32 sid = master->sids[i];
@@ -2362,6 +2363,7 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
goto err_free_master;
}
}
+ mutex_unlock(&smmu->streams_mutex);
master->ssid_bits = min(smmu->ssid_bits, fwspec->num_pasid_bits);
@@ -2818,6 +2820,8 @@ static int arm_smmu_init_structures(struct arm_smmu_device *smmu)
{
int ret;
+ mutex_init(&smmu->streams_mutex);
+
ret = arm_smmu_init_queues(smmu);
if (ret)
return ret;
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 57e5d223c..867b867b5 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -636,6 +636,8 @@ struct arm_smmu_device {
/* IOMMU core code handle */
struct iommu_device iommu;
+
+ struct mutex streams_mutex;
};
/* SMMU private data for each master */
--
2.27.0
More information about the linux-arm-kernel
mailing list