[PATCH v10 13/15] iommu/arm-smmu-v3: Enable pm_runtime and setup devlinks
Pranjal Shrivastava
praan at google.com
Tue Sep 8 10:17:09 PDT 2026
Enable PM runtime for SMMUs having a power-domain during smmu probe.
Add a devlink between the clients and SMMU device. The absence of a
power domain effectively disables runtime power management.
Additionally, handle runtime PM teardown in arm_smmu_disable_action()
and skip MMIO accesses during teardown and shutdown if the SMMU is
already runtime suspended, as translation is already disabled and the
hardware is in a low-power state.
Reviewed-by: Mostafa Saleh <smostafa at google.com>
Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Pranjal Shrivastava <praan at google.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 49 +++++++++++++++++++--
1 file changed, 46 insertions(+), 3 deletions(-)
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 1c5d891564e4..0a83d495d8d2 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -4511,8 +4511,28 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
if (ret)
goto err_disable_pasid;
+ /*
+ * If linking fails on an RPM-enabled SMMU, abort probe to prevent
+ * DMA transactions while the SMMU is autosuspended. Otherwise, warn
+ * and continue since the SMMU is always powered.
+ */
+ if (!device_link_add(dev, smmu->dev,
+ DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER)) {
+ if (pm_runtime_enabled(smmu->dev)) {
+ dev_err(smmu->dev, "failed to add devlink to %s\n",
+ dev_name(dev));
+ ret = -ENOMEM;
+ goto err_free_cd_tables;
+ }
+
+ dev_warn(smmu->dev, "failed to add devlink to %s\n", dev_name(dev));
+ }
+
return &smmu->iommu;
+err_free_cd_tables:
+ if (arm_smmu_cdtab_allocated(&master->cd_table))
+ arm_smmu_free_cd_tables(master);
err_disable_pasid:
arm_smmu_disable_pasid(master);
arm_smmu_remove_master(master);
@@ -5116,9 +5136,17 @@ static void arm_smmu_disable_action(void *data)
{
struct arm_smmu_device *smmu = data;
- if (smmu->impl_ops && smmu->impl_ops->device_disable)
- smmu->impl_ops->device_disable(smmu);
- arm_smmu_device_disable(smmu);
+ /* If the SMMU is already suspended, nothing to do */
+ if (!pm_runtime_suspended(smmu->dev)) {
+ if (smmu->impl_ops && smmu->impl_ops->device_disable)
+ smmu->impl_ops->device_disable(smmu);
+ arm_smmu_device_disable(smmu);
+ }
+
+ if (pm_runtime_enabled(smmu->dev)) {
+ pm_runtime_dont_use_autosuspend(smmu->dev);
+ pm_runtime_disable(smmu->dev);
+ }
}
static void arm_smmu_write_strtab(struct arm_smmu_device *smmu)
@@ -5931,6 +5959,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
return ret;
}
+ /*
+ * Safe to enable RPM here as client devices cannot be probed
+ * before this probe function successfully returns.
+ */
+ if (dev->pm_domain) {
+ pm_runtime_set_active(dev);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, RPM_AUTOSUSPEND_DELAY_MS);
+ pm_runtime_enable(dev);
+ }
+
return 0;
}
@@ -5946,6 +5985,10 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
{
struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+ /* If the SMMU is already suspended, nothing to do */
+ if (pm_runtime_suspended(&pdev->dev))
+ return;
+
arm_smmu_device_disable(smmu);
}
--
2.55.0.979.g7e5102b832-goog
More information about the linux-arm-kernel
mailing list