[PATCH v8 6/9] iommu/arm-smmu-v3-kdump: Implement is_attach_deferred()
From: Nicolin Chen <hidden>
Date: 2026-07-11 00:53:35
Also in:
linux-iommu, lkml
Subsystem:
arm smmu drivers, iommu subsystem, the rest · Maintainers:
Will Deacon, Joerg Roedel, Linus Torvalds
Though the kdump kernel adopts the crashed kernel's stream table, the iommu core will still try to attach each probed device to a default domain, which overwrites the adopted STE and breaks in-flight DMA from that device. Implement an is_attach_deferred() callback to prevent this. For each device that has STE.V=1 and STE.Cfg!=Abort in the adopted table, defer the default domain attachment, until the device driver explicitly requests it. Also, move arm_smmu_get_step_for_sid() to the header for the kdump function to use. Reviewed-by: Kevin Tian <kevin.tian@intel.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Pranjal Shrivastava <praan@google.com> Signed-off-by: Nicolin Chen <redacted> --- drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 22 ++++++++++++++++ .../iommu/arm/arm-smmu-v3/arm-smmu-v3-kdump.c | 19 ++++++++++++++ drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 25 ++++++++----------- 3 files changed, 51 insertions(+), 15 deletions(-)
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 e567be11f2d56..7c5a25b90a8fb 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h@@ -1208,6 +1208,21 @@ void arm_smmu_attach_commit(struct arm_smmu_attach_state *state); void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master, const struct arm_smmu_ste *target); +static inline struct arm_smmu_ste * +arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) +{ + struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; + + if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { + /* Two-level walk */ + return &cfg->l2.l2ptrs[arm_smmu_strtab_l1_idx(sid)] + ->stes[arm_smmu_strtab_l2_idx(sid)]; + } else { + /* Simple linear lookup */ + return &cfg->linear.table[sid]; + } +} + int arm_smmu_cmdq_issue_cmdlist(struct arm_smmu_device *smmu, struct arm_smmu_cmdq *cmdq, struct arm_smmu_cmd *cmds, int n,
@@ -1245,6 +1260,7 @@ int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu); 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); #else /* CONFIG_CRASH_DUMP */ static inline int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu) {
@@ -1258,6 +1274,12 @@ arm_smmu_kdump_adopt_deferred_l2_strtab(struct arm_smmu_device *smmu, u32 sid, { return -EOPNOTSUPP; } + +static inline bool +arm_smmu_kdump_is_attach_deferred(struct arm_smmu_master *master) +{ + return false; +} #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 4d010df430587..3efb4e7ff94b6 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@@ -531,3 +531,22 @@ int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu) smmu->options &= ~ARM_SMMU_OPT_KDUMP_ADOPT; return ret; } + +bool arm_smmu_kdump_is_attach_deferred(struct arm_smmu_master *master) +{ + struct arm_smmu_device *smmu = master->smmu; + int i; + + for (i = 0; i < master->num_streams; i++) { + struct arm_smmu_ste *ste = + arm_smmu_get_step_for_sid(smmu, master->streams[i].id); + u64 ent0 = le64_to_cpu(ste->data[0]); + + /* Defer only when there might be in-flight DMAs */ + if ((ent0 & STRTAB_STE_0_V) && + FIELD_GET(STRTAB_STE_0_CFG, ent0) != STRTAB_STE_0_CFG_ABORT) + return true; + } + + return false; +}
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 3f4b281c35fed..97c024c133f41 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c@@ -2898,21 +2898,6 @@ static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain, return 0; } -static struct arm_smmu_ste * -arm_smmu_get_step_for_sid(struct arm_smmu_device *smmu, u32 sid) -{ - struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; - - if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB) { - /* Two-level walk */ - return &cfg->l2.l2ptrs[arm_smmu_strtab_l1_idx(sid)] - ->stes[arm_smmu_strtab_l2_idx(sid)]; - } else { - /* Simple linear lookup */ - return &cfg->linear.table[sid]; - } -} - void arm_smmu_install_ste_for_dev(struct arm_smmu_master *master, const struct arm_smmu_ste *target) {
@@ -4318,6 +4303,15 @@ static int arm_smmu_def_domain_type(struct device *dev) return 0; } +static bool arm_smmu_is_attach_deferred(struct device *dev) +{ + struct arm_smmu_master *master = dev_iommu_priv_get(dev); + + if (master->smmu->options & ARM_SMMU_OPT_KDUMP_ADOPT) + return arm_smmu_kdump_is_attach_deferred(master); + return false; +} + static const struct iommu_ops arm_smmu_ops = { .identity_domain = &arm_smmu_identity_domain, .blocked_domain = &arm_smmu_blocked_domain,
@@ -4326,6 +4320,7 @@ static const struct iommu_ops arm_smmu_ops = { .hw_info = arm_smmu_hw_info, .domain_alloc_sva = arm_smmu_sva_domain_alloc, .domain_alloc_paging_flags = arm_smmu_domain_alloc_paging_flags, + .is_attach_deferred = arm_smmu_is_attach_deferred, .probe_device = arm_smmu_probe_device, .release_device = arm_smmu_release_device, .device_group = arm_smmu_device_group,
--
2.43.0