Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/2] iommu/arm-smmu: Add interconnect bandwidth voting support
@ 2026-05-16 12:34 Bibek Kumar Patro
  2026-05-16 12:34 ` [PATCH 1/2] dt-bindings: iommu: arm,smmu: Document optional interconnects property Bibek Kumar Patro
  2026-05-16 12:34 ` [PATCH 2/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
  0 siblings, 2 replies; 4+ messages in thread
From: Bibek Kumar Patro @ 2026-05-16 12:34 UTC (permalink / raw)
  To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-arm-kernel, iommu, devicetree, linux-kernel,
	Bibek Kumar Patro

On some Qualcomm SoCs the SMMU register space is gated behind an
interconnect fabric that requires an active bandwidth vote before
registers can be accessed. In the common case this vote is held
implicitly by other clients (e.g. the GMU device holds a GEM_NOC
vote whenever the GPU is active), so the SMMU works without any
explicit vote from the driver.

However, during certain power transitions — specifically sleep/wakeup
sequences — the interconnect vote can be dropped before the SMMU is
powered down. If the SMMU is then accessed (e.g. during runtime
resume) while the vote is absent, register reads fail intermittently.
The precise ordering makes this difficult to reproduce consistently.

This series adds support for an optional interconnect path in the
arm-smmu driver. When an 'interconnects' property is present in the
SMMU device node, the driver acquires the path and votes for bandwidth
before any register access, releasing the vote on runtime suspend and
on error paths. Platforms that do not describe an interconnect path
are unaffected.

[PATCH 1/2] documents the optional 'interconnects' properties in the
arm,smmu DT binding.

[PATCH 2/2] implements the ICC path acquisition and bandwidth voting in
the arm-smmu driver.

Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
Bibek Kumar Patro (2):
      dt-bindings: iommu: arm,smmu: Document optional interconnects property
      iommu/arm-smmu: Add interconnect bandwidth voting support

 .../devicetree/bindings/iommu/arm,smmu.yaml        |  9 ++++
 drivers/iommu/arm/arm-smmu/arm-smmu.c              | 53 +++++++++++++++++++++-
 drivers/iommu/arm/arm-smmu/arm-smmu.h              |  2 +
 3 files changed, 63 insertions(+), 1 deletion(-)
---
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
change-id: 20260516-smmu_interconnect_addition-d9567535e9d7

Best regards,
-- 
Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] dt-bindings: iommu: arm,smmu: Document optional interconnects property
  2026-05-16 12:34 [PATCH 0/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
@ 2026-05-16 12:34 ` Bibek Kumar Patro
  2026-05-16 12:34 ` [PATCH 2/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
  1 sibling, 0 replies; 4+ messages in thread
From: Bibek Kumar Patro @ 2026-05-16 12:34 UTC (permalink / raw)
  To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-arm-kernel, iommu, devicetree, linux-kernel,
	Bibek Kumar Patro

Some SoC implementations require a bandwidth vote on an interconnect
path before the SMMU register space is accessible. Add the optional
'interconnects' property to the binding to allow platform DT nodes
to describe this path.

The arm-smmu driver uses these properties to vote for bandwidth before
accessing any SMMU registers and releases the vote on runtime suspend.

Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index 06fb5c8e7547cb7a92823adc2772b94f747376a6..5cbf944f2d3e178b3723d4dbaa19ee0d33446979 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -243,6 +243,15 @@ properties:
     minItems: 1
     maxItems: 3
 
+  interconnects:
+    maxItems: 1
+    description:
+      Optional interconnect path to the SMMU register space. On some SoCs
+      the SMMU registers are only accessible after a bandwidth vote has been
+      placed on the interconnect fabric. When present the driver votes for
+      bandwidth on this path before accessing any SMMU registers and releases
+      the vote on runtime suspend.
+
   nvidia,memory-controller:
     description: |
       A phandle to the memory controller on NVIDIA Tegra186 and later SoCs.

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] iommu/arm-smmu: Add interconnect bandwidth voting support
  2026-05-16 12:34 [PATCH 0/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
  2026-05-16 12:34 ` [PATCH 1/2] dt-bindings: iommu: arm,smmu: Document optional interconnects property Bibek Kumar Patro
@ 2026-05-16 12:34 ` Bibek Kumar Patro
  2026-05-16 13:02   ` sashiko-bot
  1 sibling, 1 reply; 4+ messages in thread
From: Bibek Kumar Patro @ 2026-05-16 12:34 UTC (permalink / raw)
  To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-arm-kernel, iommu, devicetree, linux-kernel,
	Bibek Kumar Patro

On some SoCs the SMMU registers require an active interconnect
bandwidth vote to be accessible. While other clients typically
satisfy this requirement implicitly, certain corner cases (e.g.
during sleep/wakeup transitions) can leave the SMMU without a
vote, causing intermittent register access failures.

Add support for an optional interconnect path to the arm-smmu
driver and vote for bandwidth while the SMMU is active. The path
is acquired from DT if present and ignored otherwise.

The bandwidth vote is enabled before accessing SMMU registers
during probe and runtime resume, and released during runtime
suspend and on error paths.

Generally, from an architectural perspective, GEM_NOC and DDR are
expected to have an active vote whenever the adreno_smmu block is
powered on. In most common use cases, this requirement is implicitly
satisfied because other GPU-related clients (for example, the GMU
device) already hold a GEM_NOC vote when adreno_smmu is enabled.

However, there are certain corner cases, such as during sleep/wakeup
transitions, where the GEM_NOC vote can be removed before adreno_smmu
is powered down. If adreno_smmu is then accessed while the interconnect
vote is missing, it can lead to the observed failures. Because of the
precise ordering involved, this scenario is difficult to reproduce
consistently.
(also GDSC is involved in adreno usecases can have an independent vote)

Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
 drivers/iommu/arm/arm-smmu/arm-smmu.c | 53 ++++++++++++++++++++++++++++++++++-
 drivers/iommu/arm/arm-smmu/arm-smmu.h |  2 ++
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 0bd21d206eb3e75c3b9fb1364cdc92e82c5aa499..aedf5edf8f9b2b75f80a61af66727b52a5b3ad49 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -53,6 +53,11 @@
 #define MSI_IOVA_BASE			0x8000000
 #define MSI_IOVA_LENGTH			0x100000
 
+/* Interconnect bandwidth vote values for the SMMU register access path */
+#define ARM_SMMU_ICC_AVG_BW		0
+#define ARM_SMMU_ICC_PEAK_BW_HIGH	1000
+#define ARM_SMMU_ICC_PEAK_BW_LOW	0
+
 static int force_stage;
 module_param(force_stage, int, S_IRUGO);
 MODULE_PARM_DESC(force_stage,
@@ -86,6 +91,36 @@ static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
 	}
 }
 
+static int arm_smmu_icc_get(struct arm_smmu_device *smmu)
+{
+	smmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
+	if (IS_ERR(smmu->icc_path)) {
+		int err = PTR_ERR(smmu->icc_path);
+
+		if (err == -ENODATA) {
+			smmu->icc_path = NULL;
+			return 0;
+		}
+		return dev_err_probe(smmu->dev, err,
+				     "failed to get interconnect path\n");
+	}
+	return 0;
+}
+
+static void arm_smmu_icc_enable(struct arm_smmu_device *smmu)
+{
+	if (smmu->icc_path)
+		WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
+				   ARM_SMMU_ICC_PEAK_BW_HIGH));
+}
+
+static void arm_smmu_icc_disable(struct arm_smmu_device *smmu)
+{
+	if (smmu->icc_path)
+		WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
+				   ARM_SMMU_ICC_PEAK_BW_LOW));
+}
+
 static void arm_smmu_rpm_use_autosuspend(struct arm_smmu_device *smmu)
 {
 	/*
@@ -2189,6 +2224,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	if (err)
 		return err;
 
+	/*
+	 * Acquire and vote the interconnect path before accessing any SMMU
+	 * registers (including ARM_SMMU_GR0_ID0 in arm_smmu_device_cfg_probe).
+	 */
+	err = arm_smmu_icc_get(smmu);
+	if (err) {
+		clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
+		return err;
+	}
+	arm_smmu_icc_enable(smmu);
+
 	err = arm_smmu_device_cfg_probe(smmu);
 	if (err)
 		return err;
@@ -2294,9 +2340,13 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
 	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
 	int ret;
 
+	arm_smmu_icc_enable(smmu);
+
 	ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
-	if (ret)
+	if (ret) {
+		arm_smmu_icc_disable(smmu);
 		return ret;
+	}
 
 	arm_smmu_device_reset(smmu);
 
@@ -2308,6 +2358,7 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
 	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
 
 	clk_bulk_disable(smmu->num_clks, smmu->clks);
+	arm_smmu_icc_disable(smmu);
 
 	return 0;
 }
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 26d2e33cd328b8278888585fc07a31485d9397e2..c00606a416b2f4bb44a35e5d67f6ef801df68e1c 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -15,6 +15,7 @@
 #include <linux/bits.h>
 #include <linux/clk.h>
 #include <linux/device.h>
+#include <linux/interconnect.h>
 #include <linux/io-64-nonatomic-hi-lo.h>
 #include <linux/io-pgtable.h>
 #include <linux/iommu.h>
@@ -335,6 +336,7 @@ struct arm_smmu_device {
 	int				num_clks;
 	unsigned int			*irqs;
 	struct clk_bulk_data		*clks;
+	struct icc_path			*icc_path;
 
 	spinlock_t			global_sync_lock;
 

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 2/2] iommu/arm-smmu: Add interconnect bandwidth voting support
  2026-05-16 12:34 ` [PATCH 2/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
@ 2026-05-16 13:02   ` sashiko-bot
  0 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-05-16 13:02 UTC (permalink / raw)
  To: Bibek Kumar Patro; +Cc: conor+dt, robh, krzk+dt, devicetree

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Dead code `-ENODATA` check in `arm_smmu_icc_get()` causes probe failure on platforms without interconnects.
- [High] Shared IRQ handlers access SMMU hardware registers while the device might be runtime suspended.
- [Medium] Interconnect bandwidth vote is not released during system shutdown if Runtime PM is disabled.
--

commit efe802bf0c93309aa584a5eb41c34c9788a6e837
Author: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>

iommu/arm-smmu: Add interconnect bandwidth voting support

This commit adds support for an optional interconnect path to the arm-smmu
driver. It votes for bandwidth while the SMMU is active to prevent register
access failures during transitions. The bandwidth vote is enabled during
probe and runtime resume, and released during runtime suspend and errors.

> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> index 0bd21d206eb3e..aedf5edf8f9b2 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
[ ... ]
> @@ -86,6 +91,36 @@ static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
>  	}
>  }
>  
> +static int arm_smmu_icc_get(struct arm_smmu_device *smmu)
> +{
> +	smmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
> +	if (IS_ERR(smmu->icc_path)) {
> +		int err = PTR_ERR(smmu->icc_path);
> +
> +		if (err == -ENODATA) {

Is this -ENODATA check correct for handling missing interconnects?

Looking at devm_of_icc_get(), it relies on of_icc_get(), which returns
-ENOENT when the interconnects DT property is missing, or -ENODEV on ACPI
platforms where dev->of_node is NULL. It appears it never returns -ENODATA.

Will this cause the driver to unconditionally call dev_err_probe() and fail
to probe on all ACPI platforms and DT platforms that do not define
interconnect properties?

> +			smmu->icc_path = NULL;
> +			return 0;
> +		}
> +		return dev_err_probe(smmu->dev, err,
> +				     "failed to get interconnect path\n");
> +	}
> +	return 0;
> +}
> +
> +static void arm_smmu_icc_enable(struct arm_smmu_device *smmu)
> +{
> +	if (smmu->icc_path)
> +		WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
> +				   ARM_SMMU_ICC_PEAK_BW_HIGH));
> +}
> +
> +static void arm_smmu_icc_disable(struct arm_smmu_device *smmu)
> +{
> +	if (smmu->icc_path)
> +		WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
> +				   ARM_SMMU_ICC_PEAK_BW_LOW));
> +}

Should arm_smmu_icc_disable() also be called during system shutdown?

In arm_smmu_device_shutdown(), if pm_runtime_enabled(smmu->dev) is false,
the driver manually disables the SMMU clocks via clk_bulk_disable().
However, a corresponding call to drop the interconnect vote doesn't appear
to be added to that branch.

Could this leave the bandwidth vote permanently held at
ARM_SMMU_ICC_PEAK_BW_HIGH during system halt or kexec?

[ ... ]
> @@ -2308,6 +2358,7 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
>  	struct arm_smmu_device *smmu = dev_get_drvdata(dev);
>  
>  	clk_bulk_disable(smmu->num_clks, smmu->clks);
> +	arm_smmu_icc_disable(smmu);
>  
>  	return 0;
>  }

With the clocks disabled and the interconnect vote dropped here, is there a
risk of a bus hang if a shared IRQ fires while the device is suspended?

The driver registers its global_fault and context_fault handlers as
IRQF_SHARED. If another device on the same IRQ line triggers an interrupt
while the SMMU is in RPM_SUSPENDED, the handler might attempt to read
hardware registers (such as calling arm_smmu_gr0_read()) while the SMMU is
powered down without an active clock or interconnect vote.

Should the interrupt handlers use pm_runtime_get_if_active() before
accessing registers, and should this suspend callback use synchronize_irq()?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260516-smmu_interconnect_addition-v1-0-f889d933f5c1@oss.qualcomm.com?part=2

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-05-16 13:02 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-16 12:34 [PATCH 0/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-05-16 12:34 ` [PATCH 1/2] dt-bindings: iommu: arm,smmu: Document optional interconnects property Bibek Kumar Patro
2026-05-16 12:34 ` [PATCH 2/2] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-05-16 13:02   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox