* [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support
@ 2026-07-06 16:56 Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property Bibek Kumar Patro
` (5 more replies)
0 siblings, 6 replies; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro, Krzysztof Kozlowski
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.
Changes in v3:
- iommu/arm-smmu: Moved ICC voting from generic arm-smmu.c to
Qualcomm-specific arm-smmu-qcom.c via new runtime_resume and
runtime_suspend hooks in struct arm_smmu_impl, as suggested by
Konrad Dybcio.
- iommu/arm-smmu: Moved icc_path from arm_smmu_device to
qcom_smmu to keep Qualcomm-specific fields out of the generic
driver.
- iommu/arm-smmu: Restructured arm_smmu_icc_get() error path to
exit early on success as suggested by Dmitry Baryshkov.
- iommu/arm-smmu: Dropped if (smmu->icc_path) guards from
icc_enable/disable since icc_set_bw() handles NULL path safely.
- iommu/arm-smmu: Changed WARN_ON() to WARN_ON_ONCE() and
propagate error code to callers.
- iommu/arm-smmu: Changed ARM_SMMU_ICC_PEAK_BW_HIGH from 1000
to 1 kBps as a minimal keep-alive vote.
- Link to v2: https://lore.kernel.org/r/20260526-smmu_interconnect_addition-v2-0-2a6d8ca30d63@oss.qualcomm.com
Changes in v2:
- dt-bindings: Cleaned up 'interconnects' property description —
removed "Optional" prefix and driver implementation details as
flagged by Krzysztof Kozlowski.
- dt-bindings: Added allOf conditional using 'items' to restrict the
'interconnects' property to Adreno SMMU nodes only (qcom,adreno-smmu
with qcom,qcs615-smmu-500, qcom,qcs8300-smmu-500,
qcom,sa8775p-smmu-500 or qcom,sc7280-smmu-500 compatible), so
non-Adreno SMMU nodes on the same SoC cannot use this property.
- Added DTS patches for kodiak, lemans, monaco and talos to add
the GEM_NOC interconnect path for the adreno_smmu node on each
platform.
Link to v1:
https://lore.kernel.org/all/20260516-smmu_interconnect_addition-v1-0-f889d933f5c1@oss.qualcomm.com/
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
Bibek Kumar Patro (6):
dt-bindings: iommu: arm,smmu: Document interconnects property
iommu/arm-smmu: Add interconnect bandwidth voting support
arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU
arm64: dts: qcom: lemans: Add GEM_NOC interconnect for adreno SMMU
arm64: dts: qcom: monaco: Add GEM_NOC interconnect for adreno SMMU
arm64: dts: qcom: talos: Add GEM_NOC interconnect for adreno SMMU
.../devicetree/bindings/iommu/arm,smmu.yaml | 27 +++++++++++
arch/arm64/boot/dts/qcom/kodiak.dtsi | 2 +
arch/arm64/boot/dts/qcom/lemans.dtsi | 2 +
arch/arm64/boot/dts/qcom/monaco.dtsi | 2 +
arch/arm64/boot/dts/qcom/talos.dtsi | 2 +
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c | 55 +++++++++++++++++++++-
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h | 3 ++
drivers/iommu/arm/arm-smmu/arm-smmu.c | 27 ++++++++++-
drivers/iommu/arm/arm-smmu/arm-smmu.h | 2 +
9 files changed, 119 insertions(+), 3 deletions(-)
---
base-commit: 8e9685d3c41c35dd1b37df70d854137abcb2fbac
change-id: 20260516-smmu_interconnect_addition-d9567535e9d7
Best regards,
--
Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
@ 2026-07-06 16:56 ` Bibek Kumar Patro
2026-07-06 17:39 ` Dmitry Baryshkov
2026-07-06 16:56 ` [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
` (4 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro, Krzysztof Kozlowski
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.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
.../devicetree/bindings/iommu/arm,smmu.yaml | 27 ++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index a701dec2fa0a..fab8944d7b63 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -246,6 +246,13 @@ properties:
minItems: 1
maxItems: 3
+ interconnects:
+ maxItems: 1
+ description:
+ Interconnect path to the SMMU register space. Required on SoCs
+ where the SMMU registers are only accessible after a bandwidth
+ vote has been placed on the interconnect fabric.
+
nvidia,memory-controller:
description: |
A phandle to the memory controller on NVIDIA Tegra186 and later SoCs.
@@ -644,6 +651,26 @@ allOf:
clock-names: false
clocks: false
+ - if:
+ properties:
+ compatible:
+ items:
+ - enum:
+ - qcom,qcs615-smmu-500
+ - qcom,qcs8300-smmu-500
+ - qcom,sa8775p-smmu-500
+ - qcom,sc7280-smmu-500
+ - const: qcom,adreno-smmu
+ - const: qcom,smmu-500
+ - const: arm,mmu-500
+ then:
+ properties:
+ interconnects:
+ maxItems: 1
+ else:
+ properties:
+ interconnects: false
+
- if:
properties:
compatible:
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property Bibek Kumar Patro
@ 2026-07-06 16:56 ` Bibek Kumar Patro
2026-07-06 17:09 ` sashiko-bot
2026-07-06 17:40 ` Dmitry Baryshkov
2026-07-06 16:56 ` [PATCH v3 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU Bibek Kumar Patro
` (3 subsequent siblings)
5 siblings, 2 replies; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
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-qcom.c | 55 +++++++++++++++++++++++++++++-
drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h | 3 ++
drivers/iommu/arm/arm-smmu/arm-smmu.c | 27 +++++++++++++--
drivers/iommu/arm/arm-smmu/arm-smmu.h | 2 ++
4 files changed, 84 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
index e2c914fccd6f..5133d3ab023a 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
@@ -6,6 +6,7 @@
#include <linux/acpi.h>
#include <linux/adreno-smmu-priv.h>
#include <linux/delay.h>
+#include <linux/interconnect.h>
#include <linux/of_device.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/platform_device.h>
@@ -607,6 +608,45 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
return ret;
}
+static int qcom_adreno_smmu_icc_init(struct arm_smmu_device *smmu)
+{
+ struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
+ int err;
+
+ qsmmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
+ if (!IS_ERR(qsmmu->icc_path))
+ return 0;
+
+ err = PTR_ERR(qsmmu->icc_path);
+
+ if (err == -ENODEV) {
+ qsmmu->icc_path = NULL;
+ return 0;
+ }
+ return dev_err_probe(smmu->dev, err,
+ "failed to get interconnect path\n");
+}
+
+static int qcom_adreno_smmu_runtime_resume(struct arm_smmu_device *smmu)
+{
+ struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
+ int ret;
+
+ ret = icc_set_bw(qsmmu->icc_path, 0, 1);
+ WARN_ON_ONCE(ret);
+ return ret;
+}
+
+static int qcom_adreno_smmu_runtime_suspend(struct arm_smmu_device *smmu)
+{
+ struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
+ int ret;
+
+ ret = icc_set_bw(qsmmu->icc_path, 0, 0);
+ WARN_ON_ONCE(ret);
+ return ret;
+}
+
static const struct arm_smmu_impl qcom_smmu_v2_impl = {
.init_context = qcom_smmu_init_context,
.cfg_probe = qcom_smmu_cfg_probe,
@@ -648,6 +688,8 @@ static const struct arm_smmu_impl qcom_adreno_smmu_v2_impl = {
.alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
.write_sctlr = qcom_adreno_smmu_write_sctlr,
.tlb_sync = qcom_smmu_tlb_sync,
+ .runtime_resume = qcom_adreno_smmu_runtime_resume,
+ .runtime_suspend = qcom_adreno_smmu_runtime_suspend,
.context_fault_needs_threaded_irq = true,
};
@@ -658,6 +700,8 @@ static const struct arm_smmu_impl qcom_adreno_smmu_500_impl = {
.alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
.write_sctlr = qcom_adreno_smmu_write_sctlr,
.tlb_sync = qcom_smmu_tlb_sync,
+ .runtime_resume = qcom_adreno_smmu_runtime_resume,
+ .runtime_suspend = qcom_adreno_smmu_runtime_suspend,
.context_fault_needs_threaded_irq = true,
};
@@ -667,11 +711,14 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
const struct device_node *np = smmu->dev->of_node;
const struct arm_smmu_impl *impl;
struct qcom_smmu *qsmmu;
+ bool is_adreno_smmu;
+ int ret;
if (!data)
return ERR_PTR(-EINVAL);
- if (np && of_device_is_compatible(np, "qcom,adreno-smmu"))
+ is_adreno_smmu = np && of_device_is_compatible(np, "qcom,adreno-smmu");
+ if (is_adreno_smmu)
impl = data->adreno_impl;
else
impl = data->impl;
@@ -691,6 +738,12 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
qsmmu->smmu.impl = impl;
qsmmu->data = data;
+ if (is_adreno_smmu) {
+ ret = qcom_adreno_smmu_icc_init(&qsmmu->smmu);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+
return &qsmmu->smmu;
}
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
index 8addd453f5f1..6835b40339ce 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
@@ -6,12 +6,15 @@
#ifndef _ARM_SMMU_QCOM_H
#define _ARM_SMMU_QCOM_H
+#include <linux/interconnect.h>
+
struct qcom_smmu {
struct arm_smmu_device smmu;
const struct qcom_smmu_match_data *data;
bool bypass_quirk;
u8 bypass_cbndx;
u32 stall_enabled;
+ struct icc_path *icc_path;
};
enum qcom_smmu_impl_reg_offset {
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
index 0bd21d206eb3..a27804e15738 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
@@ -2189,6 +2189,14 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (err)
return err;
+ if (smmu->impl && smmu->impl->runtime_resume) {
+ err = smmu->impl->runtime_resume(smmu);
+ if (err) {
+ clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
+ return err;
+ }
+ }
+
err = arm_smmu_device_cfg_probe(smmu);
if (err)
return err;
@@ -2273,8 +2281,11 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
if (pm_runtime_enabled(smmu->dev))
pm_runtime_force_suspend(smmu->dev);
- else
+ else {
clk_bulk_disable(smmu->num_clks, smmu->clks);
+ if (smmu->impl && smmu->impl->runtime_suspend)
+ smmu->impl->runtime_suspend(smmu);
+ }
clk_bulk_unprepare(smmu->num_clks, smmu->clks);
}
@@ -2294,9 +2305,18 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
int ret;
+ if (smmu->impl && smmu->impl->runtime_resume) {
+ ret = smmu->impl->runtime_resume(smmu);
+ if (ret)
+ return ret;
+ }
+
ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
- if (ret)
+ if (ret) {
+ if (smmu->impl && smmu->impl->runtime_suspend)
+ smmu->impl->runtime_suspend(smmu);
return ret;
+ }
arm_smmu_device_reset(smmu);
@@ -2309,6 +2329,9 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
clk_bulk_disable(smmu->num_clks, smmu->clks);
+ if (smmu->impl && smmu->impl->runtime_suspend)
+ return smmu->impl->runtime_suspend(smmu);
+
return 0;
}
diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
index 26d2e33cd328..ed08f86cf99d 100644
--- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
+++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
@@ -455,6 +455,8 @@ struct arm_smmu_impl {
void (*write_s2cr)(struct arm_smmu_device *smmu, int idx);
void (*write_sctlr)(struct arm_smmu_device *smmu, int idx, u32 reg);
void (*probe_finalize)(struct arm_smmu_device *smmu, struct device *dev);
+ int (*runtime_resume)(struct arm_smmu_device *smmu);
+ int (*runtime_suspend)(struct arm_smmu_device *smmu);
};
#define INVALID_SMENDX -1
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
@ 2026-07-06 16:56 ` Bibek Kumar Patro
2026-07-06 17:42 ` Dmitry Baryshkov
2026-07-06 16:56 ` [PATCH v3 4/6] arm64: dts: qcom: lemans: " Bibek Kumar Patro
` (2 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
On Kodiak platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/kodiak.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
index 90e50c245c0c..721526f023dd 100644
--- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
+++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
@@ -3389,6 +3389,8 @@ adreno_smmu: iommu@3da0000 {
power-domains = <&gpucc GPU_CC_CX_GDSC>;
dma-coherent;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
gfx_0_tbu: tbu@3dd9000 {
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 4/6] arm64: dts: qcom: lemans: Add GEM_NOC interconnect for adreno SMMU
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
` (2 preceding siblings ...)
2026-07-06 16:56 ` [PATCH v3 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU Bibek Kumar Patro
@ 2026-07-06 16:56 ` Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 5/6] arm64: dts: qcom: monaco: " Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 6/6] arm64: dts: qcom: talos: " Bibek Kumar Patro
5 siblings, 0 replies; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
On Lemans platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/lemans.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
index a10322c5bc35..167c33d14375 100644
--- a/arch/arm64/boot/dts/qcom/lemans.dtsi
+++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
@@ -4809,6 +4809,8 @@ adreno_smmu: iommu@3da0000 {
<GIC_SPI 685 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH>;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
serdes0: phy@8901000 {
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 5/6] arm64: dts: qcom: monaco: Add GEM_NOC interconnect for adreno SMMU
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
` (3 preceding siblings ...)
2026-07-06 16:56 ` [PATCH v3 4/6] arm64: dts: qcom: lemans: " Bibek Kumar Patro
@ 2026-07-06 16:56 ` Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 6/6] arm64: dts: qcom: talos: " Bibek Kumar Patro
5 siblings, 0 replies; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
On Monaco platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/monaco.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/monaco.dtsi b/arch/arm64/boot/dts/qcom/monaco.dtsi
index 400c75437978..e3713c2b6236 100644
--- a/arch/arm64/boot/dts/qcom/monaco.dtsi
+++ b/arch/arm64/boot/dts/qcom/monaco.dtsi
@@ -5117,6 +5117,8 @@ adreno_smmu: iommu@3da0000 {
"gpu_cc_hub_aon_clk";
power-domains = <&gpucc GPU_CC_CX_GDSC>;
dma-coherent;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
pmu@9091000 {
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v3 6/6] arm64: dts: qcom: talos: Add GEM_NOC interconnect for adreno SMMU
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
` (4 preceding siblings ...)
2026-07-06 16:56 ` [PATCH v3 5/6] arm64: dts: qcom: monaco: " Bibek Kumar Patro
@ 2026-07-06 16:56 ` Bibek Kumar Patro
5 siblings, 0 replies; 11+ messages in thread
From: Bibek Kumar Patro @ 2026-07-06 16:56 UTC (permalink / raw)
To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark
Cc: linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm,
Bibek Kumar Patro
On Talos platforms, the Adreno SMMU requires a bandwidth vote on
the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
are accessible. Without this vote, the SMMU may become unreachable,
leading to intermittent probe failures and runtime issues.
Add the required interconnect to ensure reliable register access.
Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
---
arch/arm64/boot/dts/qcom/talos.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/qcom/talos.dtsi b/arch/arm64/boot/dts/qcom/talos.dtsi
index e506a16c9070..ec7f2c78ad18 100644
--- a/arch/arm64/boot/dts/qcom/talos.dtsi
+++ b/arch/arm64/boot/dts/qcom/talos.dtsi
@@ -2090,6 +2090,8 @@ adreno_smmu: iommu@50a0000 {
"iface";
power-domains = <&gpucc CX_GDSC>;
dma-coherent;
+ interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
+ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
};
stm@6002000 {
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support
2026-07-06 16:56 ` [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
@ 2026-07-06 17:09 ` sashiko-bot
2026-07-06 17:40 ` Dmitry Baryshkov
1 sibling, 0 replies; 11+ messages in thread
From: sashiko-bot @ 2026-07-06 17:09 UTC (permalink / raw)
To: Bibek Kumar Patro; +Cc: robh, devicetree, conor+dt
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] If `smmu->impl->runtime_suspend()` fails, `arm_smmu_runtime_suspend()` returns the error to the PM core after clocks have already been disabled, leaving the device logically active but physically unclocked.
- [Medium] Inconsistent power sequencing between probe and runtime PM regarding the enablement of clocks and the interconnect bandwidth vote.
Pre-existing issues:
- [High] The use of `devm_krealloc()` in `qcom_smmu_create()` leaves appended struct fields uninitialized, resulting in random hardware configuration.
- [High] Shared interrupt handlers access SMMU hardware without verifying PM runtime state, and runtime suspend lacks `synchronize_irq()`.
--
commit ca13a0dc53feec15c5946623eccfe70dcf798821
Author: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
iommu/arm-smmu: Add interconnect bandwidth voting support
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.
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> index e2c914fccd6fc..5133d3ab023a2 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
[ ... ]
> @@ -691,6 +738,12 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
> qsmmu->smmu.impl = impl;
> qsmmu->data = data;
>
> + if (is_adreno_smmu) {
> + ret = qcom_adreno_smmu_icc_init(&qsmmu->smmu);
> + if (ret)
> + return ERR_PTR(ret);
> + }
> +
> return &qsmmu->smmu;
> }
[Severity: High]
This is a pre-existing issue, but I noticed devm_krealloc() is used in
qcom_smmu_create() without passing __GFP_ZERO. Does this leave newly
appended fields in the struct (like qsmmu->stall_enabled) uninitialized?
When qcom_adreno_smmu_write_sctlr() later checks
if (qsmmu->stall_enabled & BIT(idx)), could it read uninitialized memory
and unpredictably enable stall-on-fault behavior?
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> index 0bd21d206eb3e..a27804e15738c 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
[ ... ]
> @@ -2189,6 +2189,14 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
> if (err)
> return err;
>
> + if (smmu->impl && smmu->impl->runtime_resume) {
> + err = smmu->impl->runtime_resume(smmu);
> + if (err) {
> + clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
> + return err;
> + }
> + }
> +
> err = arm_smmu_device_cfg_probe(smmu);
[Severity: Medium]
In arm_smmu_runtime_resume(), the interconnect bandwidth vote is
established before the clocks are enabled. However, in this probe
sequence, clk_bulk_prepare_enable() runs just before this runtime_resume
callback.
Could this sequence inversion cause hardware instability during probe if
clocks are enabled without the required active bandwidth vote?
[ ... ]
> @@ -2309,6 +2329,9 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
>
> clk_bulk_disable(smmu->num_clks, smmu->clks);
>
> + if (smmu->impl && smmu->impl->runtime_suspend)
> + return smmu->impl->runtime_suspend(smmu);
> +
> return 0;
> }
[Severity: High]
If smmu->impl->runtime_suspend() fails here (for example, if icc_set_bw
returns an error), the error is propagated to the PM core. The PM core
reacts to a failed suspend by leaving the device in the RPM_ACTIVE state.
Since the clocks were already disabled by clk_bulk_disable() right above
this, does this leave the device logically active but physically
unclocked? Could subsequent hardware accesses then trigger a synchronous
external abort?
[Severity: High]
This isn't a bug introduced by this patch, but since the driver requests
IRQF_SHARED for its fault interrupts, shouldn't synchronize_irq() be
called here during runtime suspend to wait for any in-flight shared IRQs?
Since the interrupt handlers (like arm_smmu_context_fault()) do not use
pm_runtime_get_if_active() to verify the device is powered before reading
hardware registers, could a shared interrupt firing while the SMMU is
fully suspended cause a crash when it accesses unclocked hardware?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260706-smmu_interconnect_addition-v3-0-afdca0125a65@oss.qualcomm.com?part=2
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property
2026-07-06 16:56 ` [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property Bibek Kumar Patro
@ 2026-07-06 17:39 ` Dmitry Baryshkov
0 siblings, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-07-06 17:39 UTC (permalink / raw)
To: Bibek Kumar Patro
Cc: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark, linux-arm-kernel, iommu, devicetree, linux-kernel,
linux-arm-msm, Krzysztof Kozlowski
On Mon, Jul 06, 2026 at 10:26:34PM +0530, Bibek Kumar Patro wrote:
> Some SoC implementations require a bandwidth vote on an interconnect
> path before the SMMU register space is accessible. Add the optional
Why is it limited only to those SoCs? Is it also applicable to other
Qualcomm SoCs?
> 'interconnects' property to the binding to allow platform DT nodes
> to describe this path.
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
> ---
> .../devicetree/bindings/iommu/arm,smmu.yaml | 27 ++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
> index a701dec2fa0a..fab8944d7b63 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
> @@ -246,6 +246,13 @@ properties:
> minItems: 1
> maxItems: 3
>
> + interconnects:
> + maxItems: 1
> + description:
> + Interconnect path to the SMMU register space. Required on SoCs
> + where the SMMU registers are only accessible after a bandwidth
> + vote has been placed on the interconnect fabric.
> +
> nvidia,memory-controller:
> description: |
> A phandle to the memory controller on NVIDIA Tegra186 and later SoCs.
> @@ -644,6 +651,26 @@ allOf:
> clock-names: false
> clocks: false
>
> + - if:
> + properties:
> + compatible:
> + items:
> + - enum:
> + - qcom,qcs615-smmu-500
> + - qcom,qcs8300-smmu-500
> + - qcom,sa8775p-smmu-500
> + - qcom,sc7280-smmu-500
> + - const: qcom,adreno-smmu
> + - const: qcom,smmu-500
> + - const: arm,mmu-500
Can we be more idiomatic here?
Something like:
if:
allOf:
- properties:
compatible:
contains:
enum:
- qcom,qcs615-smmu-500
- qcom,qcs8300-smmu-500
- qcom,sa8775p-smmu-500
- qcom,sc7280-smmu-500
- properties:
compatible:
contains:
const: qcom,adreno-smmu
In the end, we don't need to list the full list of compats. We need to
specify that it's Adreno SMMU on one of the listed platforms.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support
2026-07-06 16:56 ` [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-07-06 17:09 ` sashiko-bot
@ 2026-07-06 17:40 ` Dmitry Baryshkov
1 sibling, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-07-06 17:40 UTC (permalink / raw)
To: Bibek Kumar Patro
Cc: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark, linux-arm-kernel, iommu, devicetree, linux-kernel,
linux-arm-msm
On Mon, Jul 06, 2026 at 10:26:35PM +0530, Bibek Kumar Patro wrote:
> 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-qcom.c | 55 +++++++++++++++++++++++++++++-
> drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h | 3 ++
> drivers/iommu/arm/arm-smmu/arm-smmu.c | 27 +++++++++++++--
> drivers/iommu/arm/arm-smmu/arm-smmu.h | 2 ++
> 4 files changed, 84 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> index e2c914fccd6f..5133d3ab023a 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.c
> @@ -6,6 +6,7 @@
> #include <linux/acpi.h>
> #include <linux/adreno-smmu-priv.h>
> #include <linux/delay.h>
> +#include <linux/interconnect.h>
> #include <linux/of_device.h>
> #include <linux/firmware/qcom/qcom_scm.h>
> #include <linux/platform_device.h>
> @@ -607,6 +608,45 @@ static int qcom_sdm845_smmu500_reset(struct arm_smmu_device *smmu)
> return ret;
> }
>
> +static int qcom_adreno_smmu_icc_init(struct arm_smmu_device *smmu)
> +{
> + struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
> + int err;
> +
> + qsmmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
> + if (!IS_ERR(qsmmu->icc_path))
> + return 0;
> +
> + err = PTR_ERR(qsmmu->icc_path);
> +
> + if (err == -ENODEV) {
> + qsmmu->icc_path = NULL;
> + return 0;
> + }
> + return dev_err_probe(smmu->dev, err,
> + "failed to get interconnect path\n");
> +}
> +
> +static int qcom_adreno_smmu_runtime_resume(struct arm_smmu_device *smmu)
> +{
> + struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
> + int ret;
> +
> + ret = icc_set_bw(qsmmu->icc_path, 0, 1);
> + WARN_ON_ONCE(ret);
> + return ret;
> +}
> +
> +static int qcom_adreno_smmu_runtime_suspend(struct arm_smmu_device *smmu)
> +{
> + struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
> + int ret;
> +
> + ret = icc_set_bw(qsmmu->icc_path, 0, 0);
> + WARN_ON_ONCE(ret);
> + return ret;
> +}
> +
> static const struct arm_smmu_impl qcom_smmu_v2_impl = {
> .init_context = qcom_smmu_init_context,
> .cfg_probe = qcom_smmu_cfg_probe,
> @@ -648,6 +688,8 @@ static const struct arm_smmu_impl qcom_adreno_smmu_v2_impl = {
> .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
> .write_sctlr = qcom_adreno_smmu_write_sctlr,
> .tlb_sync = qcom_smmu_tlb_sync,
> + .runtime_resume = qcom_adreno_smmu_runtime_resume,
> + .runtime_suspend = qcom_adreno_smmu_runtime_suspend,
> .context_fault_needs_threaded_irq = true,
> };
>
> @@ -658,6 +700,8 @@ static const struct arm_smmu_impl qcom_adreno_smmu_500_impl = {
> .alloc_context_bank = qcom_adreno_smmu_alloc_context_bank,
> .write_sctlr = qcom_adreno_smmu_write_sctlr,
> .tlb_sync = qcom_smmu_tlb_sync,
> + .runtime_resume = qcom_adreno_smmu_runtime_resume,
> + .runtime_suspend = qcom_adreno_smmu_runtime_suspend,
> .context_fault_needs_threaded_irq = true,
> };
>
> @@ -667,11 +711,14 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
> const struct device_node *np = smmu->dev->of_node;
> const struct arm_smmu_impl *impl;
> struct qcom_smmu *qsmmu;
> + bool is_adreno_smmu;
> + int ret;
>
> if (!data)
> return ERR_PTR(-EINVAL);
>
> - if (np && of_device_is_compatible(np, "qcom,adreno-smmu"))
> + is_adreno_smmu = np && of_device_is_compatible(np, "qcom,adreno-smmu");
> + if (is_adreno_smmu)
> impl = data->adreno_impl;
> else
> impl = data->impl;
> @@ -691,6 +738,12 @@ static struct arm_smmu_device *qcom_smmu_create(struct arm_smmu_device *smmu,
> qsmmu->smmu.impl = impl;
> qsmmu->data = data;
>
> + if (is_adreno_smmu) {
> + ret = qcom_adreno_smmu_icc_init(&qsmmu->smmu);
> + if (ret)
> + return ERR_PTR(ret);
> + }
Move this to a runtime hook to be declared in *data.
> +
> return &qsmmu->smmu;
> }
>
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
> index 8addd453f5f1..6835b40339ce 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom.h
> @@ -6,12 +6,15 @@
> #ifndef _ARM_SMMU_QCOM_H
> #define _ARM_SMMU_QCOM_H
>
> +#include <linux/interconnect.h>
Not necessary here. Just forward-declare the struct.
> +
> struct qcom_smmu {
> struct arm_smmu_device smmu;
> const struct qcom_smmu_match_data *data;
> bool bypass_quirk;
> u8 bypass_cbndx;
> u32 stall_enabled;
> + struct icc_path *icc_path;
> };
>
> enum qcom_smmu_impl_reg_offset {
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> index 0bd21d206eb3..a27804e15738 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
> @@ -2189,6 +2189,14 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
> if (err)
> return err;
>
> + if (smmu->impl && smmu->impl->runtime_resume) {
> + err = smmu->impl->runtime_resume(smmu);
> + if (err) {
> + clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
> + return err;
> + }
> + }
> +
> err = arm_smmu_device_cfg_probe(smmu);
> if (err)
> return err;
> @@ -2273,8 +2281,11 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev)
>
> if (pm_runtime_enabled(smmu->dev))
> pm_runtime_force_suspend(smmu->dev);
> - else
> + else {
> clk_bulk_disable(smmu->num_clks, smmu->clks);
> + if (smmu->impl && smmu->impl->runtime_suspend)
> + smmu->impl->runtime_suspend(smmu);
> + }
>
> clk_bulk_unprepare(smmu->num_clks, smmu->clks);
> }
> @@ -2294,9 +2305,18 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
> struct arm_smmu_device *smmu = dev_get_drvdata(dev);
> int ret;
>
> + if (smmu->impl && smmu->impl->runtime_resume) {
> + ret = smmu->impl->runtime_resume(smmu);
> + if (ret)
> + return ret;
> + }
> +
> ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
> - if (ret)
> + if (ret) {
> + if (smmu->impl && smmu->impl->runtime_suspend)
> + smmu->impl->runtime_suspend(smmu);
> return ret;
> + }
>
> arm_smmu_device_reset(smmu);
>
> @@ -2309,6 +2329,9 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
>
> clk_bulk_disable(smmu->num_clks, smmu->clks);
>
> + if (smmu->impl && smmu->impl->runtime_suspend)
> + return smmu->impl->runtime_suspend(smmu);
> +
> return 0;
> }
>
> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.h b/drivers/iommu/arm/arm-smmu/arm-smmu.h
> index 26d2e33cd328..ed08f86cf99d 100644
> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.h
> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.h
> @@ -455,6 +455,8 @@ struct arm_smmu_impl {
> void (*write_s2cr)(struct arm_smmu_device *smmu, int idx);
> void (*write_sctlr)(struct arm_smmu_device *smmu, int idx, u32 reg);
> void (*probe_finalize)(struct arm_smmu_device *smmu, struct device *dev);
> + int (*runtime_resume)(struct arm_smmu_device *smmu);
> + int (*runtime_suspend)(struct arm_smmu_device *smmu);
> };
>
> #define INVALID_SMENDX -1
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v3 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU
2026-07-06 16:56 ` [PATCH v3 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU Bibek Kumar Patro
@ 2026-07-06 17:42 ` Dmitry Baryshkov
0 siblings, 0 replies; 11+ messages in thread
From: Dmitry Baryshkov @ 2026-07-06 17:42 UTC (permalink / raw)
To: Bibek Kumar Patro
Cc: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
Rob Clark, linux-arm-kernel, iommu, devicetree, linux-kernel,
linux-arm-msm
On Mon, Jul 06, 2026 at 10:26:36PM +0530, Bibek Kumar Patro wrote:
> On Kodiak platforms, the Adreno SMMU requires a bandwidth vote on
> the GEM_NOC path (MASTER_GPU_TCU -> SLAVE_EBI1) before its registers
> are accessible. Without this vote, the SMMU may become unreachable,
> leading to intermittent probe failures and runtime issues.
>
> Add the required interconnect to ensure reliable register access.
>
> Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
> ---
> arch/arm64/boot/dts/qcom/kodiak.dtsi | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/kodiak.dtsi b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> index 90e50c245c0c..721526f023dd 100644
> --- a/arch/arm64/boot/dts/qcom/kodiak.dtsi
> +++ b/arch/arm64/boot/dts/qcom/kodiak.dtsi
> @@ -3389,6 +3389,8 @@ adreno_smmu: iommu@3da0000 {
>
> power-domains = <&gpucc GPU_CC_CX_GDSC>;
> dma-coherent;
> + interconnects = <&gem_noc MASTER_GPU_TCU QCOM_ICC_TAG_ALWAYS
> + &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>;
Why is it ALWAYS? Would it be better to declare it as ACTIVE_ONLY and
then drop the extra suspend/resume play?
> };
>
> gfx_0_tbu: tbu@3dd9000 {
>
> --
> 2.34.1
>
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-07-06 17:42 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-06 16:56 [PATCH v3 0/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 1/6] dt-bindings: iommu: arm,smmu: Document interconnects property Bibek Kumar Patro
2026-07-06 17:39 ` Dmitry Baryshkov
2026-07-06 16:56 ` [PATCH v3 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support Bibek Kumar Patro
2026-07-06 17:09 ` sashiko-bot
2026-07-06 17:40 ` Dmitry Baryshkov
2026-07-06 16:56 ` [PATCH v3 3/6] arm64: dts: qcom: kodiak: Add GEM_NOC interconnect for adreno SMMU Bibek Kumar Patro
2026-07-06 17:42 ` Dmitry Baryshkov
2026-07-06 16:56 ` [PATCH v3 4/6] arm64: dts: qcom: lemans: " Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 5/6] arm64: dts: qcom: monaco: " Bibek Kumar Patro
2026-07-06 16:56 ` [PATCH v3 6/6] arm64: dts: qcom: talos: " Bibek Kumar Patro
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox