[PATCH v8 9/9] iommu/arm-smmu-v3: Detect ARM_SMMU_OPT_KDUMP_ADOPT in probe()
From: Nicolin Chen
Date: Fri Jul 10 2026 - 20:55:16 EST
arm_smmu_device_hw_probe() runs before arm_smmu_init_structures(), so it's
natural to decide whether the kdump kernel must adopt the crashed kernel's
stream table.
Given that memremap is used to adopt the old stream table, set this option
only on a coherent SMMU.
And make sure SMMU isn't in Service Failure Mode.
Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>
Reviewed-by: Jason Gunthorpe <jgg@xxxxxxxxxx>
Reviewed-by: Pranjal Shrivastava <praan@xxxxxxxxxx>
Signed-off-by: Nicolin Chen <nicolinc@xxxxxxxxxx>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 5 ++++
.../iommu/arm/arm-smmu-v3/arm-smmu-v3-kdump.c | 27 +++++++++++++++++++
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 4 +++
3 files changed, 36 insertions(+)
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 7c5a25b90a8fb..6fe0dcc2cf400 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -1261,6 +1261,7 @@ int arm_smmu_kdump_adopt_deferred_l2_strtab(struct arm_smmu_device *smmu,
u32 sid, phys_addr_t base, u32 span,
struct arm_smmu_strtab_l2 **l2table);
bool arm_smmu_kdump_is_attach_deferred(struct arm_smmu_master *master);
+void arm_smmu_device_kdump_probe(struct arm_smmu_device *smmu);
#else /* CONFIG_CRASH_DUMP */
static inline int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu)
{
@@ -1280,6 +1281,10 @@ arm_smmu_kdump_is_attach_deferred(struct arm_smmu_master *master)
{
return false;
}
+
+static inline void arm_smmu_device_kdump_probe(struct arm_smmu_device *smmu)
+{
+}
#endif /* CONFIG_CRASH_DUMP */
struct arm_vsmmu {
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kdump.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kdump.c
index 3efb4e7ff94b6..487b38d995a9f 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kdump.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-kdump.c
@@ -550,3 +550,30 @@ bool arm_smmu_kdump_is_attach_deferred(struct arm_smmu_master *master)
return false;
}
+
+void arm_smmu_device_kdump_probe(struct arm_smmu_device *smmu)
+{
+ u32 gerror, gerrorn, active;
+
+ /* No adoption if SMMU is disabled (i.e., there is no in-flight DMA) */
+ if (!(readl_relaxed(smmu->base + ARM_SMMU_CR0) & CR0_SMMUEN))
+ return;
+
+ /* For now, only support a coherent SMMU that works with MEMREMAP_WB */
+ if (!(smmu->features & ARM_SMMU_FEAT_COHERENCY)) {
+ dev_warn(smmu->dev,
+ "non-coherent SMMU unsupported; reset to block all DMAs\n");
+ return;
+ }
+
+ gerror = readl_relaxed(smmu->base + ARM_SMMU_GERROR);
+ gerrorn = readl_relaxed(smmu->base + ARM_SMMU_GERRORN);
+ active = gerror ^ gerrorn;
+ if (active & GERROR_SFM_ERR) {
+ dev_warn(smmu->dev,
+ "SMMU in Service Failure Mode, must reset\n");
+ return;
+ }
+
+ smmu->options |= ARM_SMMU_OPT_KDUMP_ADOPT;
+}
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 325376cd72ba8..95bc7eec2fa57 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -5257,6 +5257,10 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
dev_info(smmu->dev, "oas %lu-bit (features 0x%08x)\n",
smmu->oas, smmu->features);
+
+ if (is_kdump_kernel())
+ arm_smmu_device_kdump_probe(smmu);
+
return 0;
}
--
2.43.0