Skip to contentSkip to conversation

iommu/arm-smmu: Add runtime pm/sleep support

PATCH Superseded Sricharan R 6 participants 19 messages Mar 9, 2017 – Apr 10, 2017

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Took some reference from the exynos runtime patches [2]. Tested this with MDP, GPU, VENUS devices on apq8096-db820c board.

Previous version of the patchset [1].

[V3]
* Reworked the patches to keep the clocks init/enabling function seperately for each compatible.

* Added clocks bindings for MMU40x/500.

* Added a new compatible for qcom,smmu-v2 implementation and the clock bindings for the same.

* Rebased on top of 4.11-rc1

[V2]
* Split the patches little differently.

* Addressed comments.

* Removed the patch #4 [3] from previous post for arm-smmu context save restore. Planning to post this separately after reworking/addressing Robin's feedback.

* Reversed the sequence to disable clocks than enabling. This was required for those cases where the clocks are populated in a dependent order from DT.

[1] https://www.spinics.net/lists/linux-arm-msm/msg23870.html
[2] https://lkml.org/lkml/2016/10/20/70
[3] https://patchwork.kernel.org/patch/9389717/

Sricharan R (5):
iommu/arm-smmu: Add pm_runtime/sleep ops iommu/arm-smmu: Add support for MMU40x/500 clocks
drivers: arm-smmu: Add clock support for QCOM_SMMUV2 iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device iommu/arm-smmu: Add the device_link between masters and smmu

 .../devicetree/bindings/iommu/arm,smmu.txt         |  35 +++
 drivers/iommu/arm-smmu.c                           | 349 ++++++++++++++++++++-
 2 files changed, 373 insertions(+), 11 deletions(-)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
#1 lore raw

PATCH v3 1/5 iommu/arm-smmu: Add pm_runtime/sleep ops

The smmu needs to be functional only when the respective master's using it are active. The device_link feature helps to track such functional dependencies, so that the iommu gets powered when the master device enables itself using pm_runtime. So by adapting the smmu driver for runtime pm, above said dependency can be addressed.

This patch adds the pm runtime/sleep callbacks to the driver and also the functions to parse the smmu clocks from DT and enable them in resume/suspend.

---
 drivers/iommu/arm-smmu.c | 74 ++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 65 insertions(+), 9 deletions(-)
drivers/iommu/arm-smmu.c +65 -9
index abf6496..f7e11d3 100644
@@ -48,6 +48,7 @@
 #include <linux/of_iommu.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
@@ -340,6 +341,13 @@ struct arm_smmu_master_cfg {
 #define for_each_cfg_sme(fw, i, idx) \
 	for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
+struct arm_smmu_clks {
+	void *clks;
+	int (*init_clocks)(struct arm_smmu_device *smmu);
+	int (*enable_clocks)(struct arm_smmu_device *smmu);
+	void (*disable_clocks)(struct arm_smmu_device *smmu);
+};
+
 struct arm_smmu_device {
 	struct device			*dev;
 
@@ -387,7 +395,7 @@ struct arm_smmu_device {
 	u32				num_global_irqs;
 	u32				num_context_irqs;
 	unsigned int			*irqs;
-
+	struct arm_smmu_clks		smmu_clks;
 	u32				cavium_id_base; /* Specific to Cavium */
 
 	/* IOMMU core code handle */
@@ -1958,16 +1966,24 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
 struct arm_smmu_match_data {
 	enum arm_smmu_arch_version version;
 	enum arm_smmu_implementation model;
+	struct arm_smmu_clks smmu_clks;
 };
 
-#define ARM_SMMU_MATCH_DATA(name, ver, imp)	\
-static struct arm_smmu_match_data name = { .version = ver, .model = imp }
-
-ARM_SMMU_MATCH_DATA(smmu_generic_v1, ARM_SMMU_V1, GENERIC_SMMU);
-ARM_SMMU_MATCH_DATA(smmu_generic_v2, ARM_SMMU_V2, GENERIC_SMMU);
-ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU);
-ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500);
-ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2);
+#define ARM_SMMU_MATCH_DATA(name, ver, imp, init, enable, disable)	\
+static struct arm_smmu_match_data name = { .version = ver, .model = imp, \
+					   .smmu_clks.init_clocks = init, \
+					   .smmu_clks.enable_clocks = enable, \
+					   .smmu_clks.disable_clocks = disable }
+
+ARM_SMMU_MATCH_DATA(smmu_generic_v1, ARM_SMMU_V1, GENERIC_SMMU,
+		    NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(smmu_generic_v2, ARM_SMMU_V2, GENERIC_SMMU,
+		    NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU,
+		    NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2,
+		    NULL, NULL, NULL);
 
 static const struct of_device_id arm_smmu_of_match[] = {
 	{ .compatible = "arm,smmu-v1", .data = &smmu_generic_v1 },
@@ -2054,6 +2070,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
 	data = of_device_get_match_data(dev);
 	smmu->version = data->version;
 	smmu->model = data->model;
+	smmu->smmu_clks = data->smmu_clks;
 
 	parse_driver_options(smmu);
 
@@ -2135,6 +2152,13 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		smmu->irqs[i] = irq;
 	}
 
+	if (smmu->smmu_clks.init_clocks) {
+		err = smmu->smmu_clks.init_clocks(smmu);
+		if (err)
+			return err;
+	}
+
+	pm_runtime_enable(dev);
 	err = arm_smmu_device_cfg_probe(smmu);
 	if (err)
 		return err;
@@ -2211,10 +2235,42 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int arm_smmu_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+	int ret = 0;
+
+	if (smmu->smmu_clks.enable_clocks)
+		ret = smmu->smmu_clks.enable_clocks(smmu);
+
+	return ret;
+}
+
+static int arm_smmu_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct arm_smmu_device *smmu = platform_get_drvdata(pdev);
+
+	if (smmu->smmu_clks.disable_clocks)
+		smmu->smmu_clks.disable_clocks(smmu);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops arm_smmu_pm_ops = {
+	SET_RUNTIME_PM_OPS(arm_smmu_suspend, arm_smmu_resume, NULL)
+	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+				pm_runtime_force_resume)
+};
+
 static struct platform_driver arm_smmu_driver = {
 	.driver	= {
 		.name		= "arm-smmu",
 		.of_match_table	= of_match_ptr(arm_smmu_of_match),
+		.pm = &arm_smmu_pm_ops,
 	},
 	.probe	= arm_smmu_device_probe,
 	.remove	= arm_smmu_device_remove,
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
#2 lore raw

PATCH v3 2/5 iommu/arm-smmu: Add support for MMU40x/500 clocks

In reply to Sricharan R

The MMU400x/500 is the implementation of the SMMUv2 arch specification. It is split in to two blocks TBU, TCU. TBU caches the page table, instantiated for each master locally, clocked by the TBUn_clk. TCU manages the address translation with PTW and has the programming interface as well, clocked using the TCU_CLK. The TBU can also be sharing the same clock domain as TCU, in which case both are clocked using the TCU_CLK.

This defines the clock bindings for the same and adds the init, enable and disable functions for handling the clocks.

---
 .../devicetree/bindings/iommu/arm,smmu.txt         | 27 ++++++
 drivers/iommu/arm-smmu.c                           | 95 +++++++++++++++++++++-
 2 files changed, 121 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +27 -0
index 6cdf32d..b369c13 100644
@@ -60,6 +60,28 @@ conditions.
                   aliases of secure registers have to be used during
                   SMMU configuration.
 
+- clock-names:    Should be "tbu_clk" and "tcu_clk" and "cfg_clk" for
+                  "arm,mmu-400", "arm,mmu-401" and "arm,mmu-500"
+
+                  "tcu_clk" is required for smmu's register access using the
+                  programming interface and ptw for downstream bus access.
+
+                  "tbu_clk" is required for access to the TBU connected to the
+                  master locally. This clock is optional and not required when
+                  TBU is in the same clock domain as the TCU or when the TBU is
+                  clocked along with the master.
+
+                  "cfg_clk" is optional if required to access the TCU's programming
+                  interface, apart from the "tcu_clk".
+
+- clocks:         Phandles for respective clocks described by clock-names.
+
+- power-domains:  Phandles to SMMU's power domain specifier. This is
+                  required even if SMMU belongs to the master's power
+                  domain, as the SMMU will have to be enabled and
+                  accessed before master gets enabled and linked to its
+                  SMMU.
+
 ** Deprecated properties:
 
 - mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -84,6 +106,11 @@ conditions.
                              <0 36 4>,
                              <0 37 4>;
                 #iommu-cells = <1>;
+                clocks = <&gcc GCC_SMMU_CFG_CLK>,
+                         <&gcc GCC_APSS_TCU_CLK>,
+			 <&gcc GCC_MDP_TBU_CLK>;
+
+		clock-names = "cfg_clk", "tcu_clk", "tbu_clk";
         };
 
         /* device with two stream IDs, 0 and 7 */
drivers/iommu/arm-smmu.c +94 -1

113 lines not on this page · raw message

Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
maintainer
#3 lore raw

PATCH v3 2/5 iommu/arm-smmu: Add support for MMU40x/500 clocks

Quoted 25 lines · Sricharan R

The MMU400x/500 is the implementation of the SMMUv2 arch specification. It is split in to two blocks TBU, TCU. TBU caches the page table, instantiated for each master locally, clocked by the TBUn_clk. TCU manages the address translation with PTW and has the programming interface as well, clocked using the TCU_CLK. The TBU can also be sharing the same clock domain as TCU, in which case both are clocked using the TCU_CLK.

This defines the clock bindings for the same and adds the init, enable and disable functions for handling the clocks.

---
 .../devicetree/bindings/iommu/arm,smmu.txt         | 27 ++++++
 drivers/iommu/arm-smmu.c                           | 95 +++++++++++++++++++++-
 2 files changed, 121 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +0 -0
index 6cdf32d..b369c13 100644

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 63

Quoted 4 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +1 -0
@@ -60,6 +60,28 @@ conditions.
                   aliases of secure registers have to be used during
                   SMMU configuration.
 
+- clock-names:    Should be "tbu_clk" and "tcu_clk" and "cfg_clk" for

_clk is redundant

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 75

Quoted 12 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +12 -0
+                  "arm,mmu-400", "arm,mmu-401" and "arm,mmu-500"
+
+                  "tcu_clk" is required for smmu's register access using the
+                  programming interface and ptw for downstream bus access.
+
+                  "tbu_clk" is required for access to the TBU connected to the
+                  master locally. This clock is optional and not required when
+                  TBU is in the same clock domain as the TCU or when the TBU is
+                  clocked along with the master.
+
+                  "cfg_clk" is optional if required to access the TCU's programming
+                  interface, apart from the "tcu_clk".

Clocks generally shouldn't be optional. Either the h/w has a clock or it doesn't.

Quoted 147 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +14 -0
+
+- clocks:         Phandles for respective clocks described by clock-names.
+
+- power-domains:  Phandles to SMMU's power domain specifier. This is
+                  required even if SMMU belongs to the master's power
+                  domain, as the SMMU will have to be enabled and
+                  accessed before master gets enabled and linked to its
+                  SMMU.
+
 ** Deprecated properties:
 
 - mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -84,6 +106,11 @@ conditions.
                              <0 36 4>,
                              <0 37 4>;
                 #iommu-cells = <1>;
+                clocks = <&gcc GCC_SMMU_CFG_CLK>,
+                         <&gcc GCC_APSS_TCU_CLK>,
+			 <&gcc GCC_MDP_TBU_CLK>;
+
+		clock-names = "cfg_clk", "tcu_clk", "tbu_clk";
         };
 
         /* device with two stream IDs, 0 and 7 */
drivers/iommu/arm-smmu.c +94 -1
index f7e11d3..720a1ef 100644
@@ -341,6 +341,12 @@ struct arm_smmu_master_cfg {
 #define for_each_cfg_sme(fw, i, idx) \
 	for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
+struct mmu500_clk {
+	struct clk *cfg_clk;
+	struct clk *tcu_clk;
+	struct clk *tbu_clk;
+};
+
 struct arm_smmu_clks {
 	void *clks;
 	int (*init_clocks)(struct arm_smmu_device *smmu);
@@ -455,6 +461,92 @@ static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 	return container_of(dom, struct arm_smmu_domain, domain);
 }
 
+static int mmu500_enable_clocks(struct arm_smmu_device *smmu)
+{
+	int ret = 0;
+	struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+	if (!sclks)
+		return 0;
+
+	ret = clk_prepare_enable(sclks->cfg_clk);
+	if (ret) {
+		dev_err(smmu->dev, "Couldn't enable cfg_clk");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(sclks->tcu_clk);
+	if (ret) {
+		dev_err(smmu->dev, "Couldn't enable tcu_clk");
+		clk_disable_unprepare(sclks->cfg_clk);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(sclks->tbu_clk);
+	if (ret) {
+		dev_err(smmu->dev, "Couln't enable tbu_clk");
+		clk_disable_unprepare(sclks->tcu_clk);
+		clk_disable_unprepare(sclks->cfg_clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mmu500_disable_clocks(struct arm_smmu_device *smmu)
+{
+	struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+	if (!sclks) {
+		clk_disable_unprepare(sclks->tbu_clk);
+		clk_disable_unprepare(sclks->tcu_clk);
+		clk_disable_unprepare(sclks->cfg_clk);
+	}
+}
+
+static int mmu500_init_clocks(struct arm_smmu_device *smmu)
+{
+	struct device *dev = smmu->dev;
+	struct mmu500_clk *sclks;
+	int err;
+
+	if (!of_find_property(dev->of_node, "clocks", NULL))
+		return 0;
+
+	sclks = devm_kzalloc(dev, sizeof(*sclks), GFP_KERNEL);
+	if (!sclks)
+		return -ENOMEM;
+
+	sclks->cfg_clk = devm_clk_get(dev, "cfg_clk");
+	if (IS_ERR(sclks->cfg_clk)) {
+		err = PTR_ERR(sclks->cfg_clk);
+		/* Ignore all, except -EPROBE_DEFER for optional clocks */
+		if (err == -EPROBE_DEFER)
+			return err;
+		else
+			sclks->cfg_clk = NULL;
+	}
+
+	sclks->tcu_clk = devm_clk_get(dev, "tcu_clk");
+	if (IS_ERR(sclks->tcu_clk)) {
+		dev_err(dev, "Couldn't get tcu_clk");
+		return PTR_ERR(sclks->tcu_clk);
+	}
+
+	sclks->tbu_clk = devm_clk_get(dev, "tbu_clk");
+	if (IS_ERR(sclks->tbu_clk)) {
+		err = PTR_ERR(sclks->tbu_clk);
+		/* Ignore all, ecept -EPROBE_DEFER for optional clocks */
+		if (err == -EPROBE_DEFER)
+			return err;
+		else
+			sclks->tbu_clk = NULL;
+	}
+
+	smmu->smmu_clks.clks = sclks;
+	return 0;
+}
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
 	int i = 0;
@@ -1981,7 +2073,8 @@ struct arm_smmu_match_data {
 		    NULL, NULL, NULL);
 ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU,
 		    NULL, NULL, NULL);
-ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, mmu500_init_clocks,
+		    mmu500_enable_clocks, mmu500_disable_clocks);
 ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2,
 		    NULL, NULL, NULL);
 
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
#4 lore raw

PATCH v3 2/5 iommu/arm-smmu: Add support for MMU40x/500 clocks

Hi Rob,

Quoted 29 lines · Rob Herring
Quoted 28 lines · Sricharan R

The MMU400x/500 is the implementation of the SMMUv2 arch specification. It is split in to two blocks TBU, TCU. TBU caches the page table, instantiated for each master locally, clocked by the TBUn_clk. TCU manages the address translation with PTW and has the programming interface as well, clocked using the TCU_CLK. The TBU can also be sharing the same clock domain as TCU, in which case both are clocked using the TCU_CLK.

This defines the clock bindings for the same and adds the init, enable and disable functions for handling the clocks.

---
 .../devicetree/bindings/iommu/arm,smmu.txt         | 27 ++++++
 drivers/iommu/arm-smmu.c                           | 95 +++++++++++++++++++++-
 2 files changed, 121 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +0 -0
index 6cdf32d..b369c13 100644
@@ -60,6 +60,28 @@ conditions.
                   aliases of secure registers have to be used during
                   SMMU configuration.
 
Quoted 3 lines

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 63

Quoted 1 line
Documentation/devicetree/bindings/iommu/arm,smmu.txt +1 -0
+- clock-names:    Should be "tbu_clk" and "tcu_clk" and "cfg_clk" for

_clk is redundant

ok, will remove it.

Quoted 17 lines

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 75

Quoted 13 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +12 -0
+                  "arm,mmu-400", "arm,mmu-401" and "arm,mmu-500"
+
+                  "tcu_clk" is required for smmu's register access using the
+                  programming interface and ptw for downstream bus access.
+
+                  "tbu_clk" is required for access to the TBU connected to the
+                  master locally. This clock is optional and not required when
+                  TBU is in the same clock domain as the TCU or when the TBU is
+                  clocked along with the master.
+
+                  "cfg_clk" is optional if required to access the TCU's programming
+                  interface, apart from the "tcu_clk".

Clocks generally shouldn't be optional. Either the h/w has a clock or it doesn't.

ok, will not define it as 'optional'. I will define it to be soc specific. Also will change the driver to ignore the clk not present, just to reuse/have common clock enable functions for MMU-500 for other socs as well. Only problem being unable to catch a case where a clk DT entry is not populated when it should have been.

Regards,
Sricharan

Quoted 147 lines
Quoted 147 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +14 -0
+
+- clocks:         Phandles for respective clocks described by clock-names.
+
+- power-domains:  Phandles to SMMU's power domain specifier. This is
+                  required even if SMMU belongs to the master's power
+                  domain, as the SMMU will have to be enabled and
+                  accessed before master gets enabled and linked to its
+                  SMMU.
+
 ** Deprecated properties:
 
 - mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -84,6 +106,11 @@ conditions.
                              <0 36 4>,
                              <0 37 4>;
                 #iommu-cells = <1>;
+                clocks = <&gcc GCC_SMMU_CFG_CLK>,
+                         <&gcc GCC_APSS_TCU_CLK>,
+			 <&gcc GCC_MDP_TBU_CLK>;
+
+		clock-names = "cfg_clk", "tcu_clk", "tbu_clk";
         };
 
         /* device with two stream IDs, 0 and 7 */
drivers/iommu/arm-smmu.c +94 -2
index f7e11d3..720a1ef 100644
@@ -341,6 +341,12 @@ struct arm_smmu_master_cfg {
 #define for_each_cfg_sme(fw, i, idx) \
 	for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
+struct mmu500_clk {
+	struct clk *cfg_clk;
+	struct clk *tcu_clk;
+	struct clk *tbu_clk;
+};
+
 struct arm_smmu_clks {
 	void *clks;
 	int (*init_clocks)(struct arm_smmu_device *smmu);
@@ -455,6 +461,92 @@ static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
 	return container_of(dom, struct arm_smmu_domain, domain);
 }
 
+static int mmu500_enable_clocks(struct arm_smmu_device *smmu)
+{
+	int ret = 0;
+	struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+	if (!sclks)
+		return 0;
+
+	ret = clk_prepare_enable(sclks->cfg_clk);
+	if (ret) {
+		dev_err(smmu->dev, "Couldn't enable cfg_clk");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(sclks->tcu_clk);
+	if (ret) {
+		dev_err(smmu->dev, "Couldn't enable tcu_clk");
+		clk_disable_unprepare(sclks->cfg_clk);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(sclks->tbu_clk);
+	if (ret) {
+		dev_err(smmu->dev, "Couln't enable tbu_clk");
+		clk_disable_unprepare(sclks->tcu_clk);
+		clk_disable_unprepare(sclks->cfg_clk);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void mmu500_disable_clocks(struct arm_smmu_device *smmu)
+{
+	struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+	if (!sclks) {
+		clk_disable_unprepare(sclks->tbu_clk);
+		clk_disable_unprepare(sclks->tcu_clk);
+		clk_disable_unprepare(sclks->cfg_clk);
+	}
+}
+
+static int mmu500_init_clocks(struct arm_smmu_device *smmu)
+{
+	struct device *dev = smmu->dev;
+	struct mmu500_clk *sclks;
+	int err;
+
+	if (!of_find_property(dev->of_node, "clocks", NULL))
+		return 0;
+
+	sclks = devm_kzalloc(dev, sizeof(*sclks), GFP_KERNEL);
+	if (!sclks)
+		return -ENOMEM;
+
+	sclks->cfg_clk = devm_clk_get(dev, "cfg_clk");
+	if (IS_ERR(sclks->cfg_clk)) {
+		err = PTR_ERR(sclks->cfg_clk);
+		/* Ignore all, except -EPROBE_DEFER for optional clocks */
+		if (err == -EPROBE_DEFER)
+			return err;
+		else
+			sclks->cfg_clk = NULL;
+	}
+
+	sclks->tcu_clk = devm_clk_get(dev, "tcu_clk");
+	if (IS_ERR(sclks->tcu_clk)) {
+		dev_err(dev, "Couldn't get tcu_clk");
+		return PTR_ERR(sclks->tcu_clk);
+	}
+
+	sclks->tbu_clk = devm_clk_get(dev, "tbu_clk");
+	if (IS_ERR(sclks->tbu_clk)) {
+		err = PTR_ERR(sclks->tbu_clk);
+		/* Ignore all, ecept -EPROBE_DEFER for optional clocks */
+		if (err == -EPROBE_DEFER)
+			return err;
+		else
+			sclks->tbu_clk = NULL;
+	}
+
+	smmu->smmu_clks.clks = sclks;
+	return 0;
+}
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
 	int i = 0;
@@ -1981,7 +2073,8 @@ struct arm_smmu_match_data {
 		    NULL, NULL, NULL);
 ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU,
 		    NULL, NULL, NULL);
-ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, mmu500_init_clocks,
+		    mmu500_enable_clocks, mmu500_disable_clocks);
 ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2,
 		    NULL, NULL, NULL);
 
--

QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

Signature · 2 lines
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a 
member of Code Aurora Forum, hosted by The Linux Foundation
#5 lore raw

PATCH v3 2/5 iommu/arm-smmu: Add support for MMU40x/500 clocks

In reply to Sricharan R
Quoted 25 lines · Sricharan R

The MMU400x/500 is the implementation of the SMMUv2 arch specification. It is split in to two blocks TBU, TCU. TBU caches the page table, instantiated for each master locally, clocked by the TBUn_clk. TCU manages the address translation with PTW and has the programming interface as well, clocked using the TCU_CLK. The TBU can also be sharing the same clock domain as TCU, in which case both are clocked using the TCU_CLK.

This defines the clock bindings for the same and adds the init, enable and disable functions for handling the clocks.

---
 .../devicetree/bindings/iommu/arm,smmu.txt         | 27 ++++++
 drivers/iommu/arm-smmu.c                           | 95 +++++++++++++++++++++-
 2 files changed, 121 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +0 -0
index 6cdf32d..b369c13 100644

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 64

Quoted 5 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +2 -0
@@ -60,6 +60,28 @@ conditions.
                   aliases of secure registers have to be used during
                   SMMU configuration.
 
+- clock-names:    Should be "tbu_clk" and "tcu_clk" and "cfg_clk" for
+                  "arm,mmu-400", "arm,mmu-401" and "arm,mmu-500"

I guess that should be: "Should be "tbu_clk" *or* "tcu_clk" and "cfg_clk" for..."

Also, possibly we should define our own compat strings for various SoC's that require these clks so we can properly describe when they are required? I guess that would address Rob H's comment.

BR,
-R

Quoted 161 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +24 -0
+                  "tcu_clk" is required for smmu's register access using the
+                  programming interface and ptw for downstream bus access.
+
+                  "tbu_clk" is required for access to the TBU connected to the
+                  master locally. This clock is optional and not required when
+                  TBU is in the same clock domain as the TCU or when the TBU is
+                  clocked along with the master.
+
+                  "cfg_clk" is optional if required to access the TCU's programming
+                  interface, apart from the "tcu_clk".
+
+- clocks:         Phandles for respective clocks described by clock-names.
+
+- power-domains:  Phandles to SMMU's power domain specifier. This is
+                  required even if SMMU belongs to the master's power
+                  domain, as the SMMU will have to be enabled and
+                  accessed before master gets enabled and linked to its
+                  SMMU.
+
 ** Deprecated properties:
 
 - mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -84,6 +106,11 @@ conditions.
                              <0 36 4>,
                              <0 37 4>;
                 #iommu-cells = <1>;
+                clocks = <&gcc GCC_SMMU_CFG_CLK>,
+                         <&gcc GCC_APSS_TCU_CLK>,
+                        <&gcc GCC_MDP_TBU_CLK>;
+
+               clock-names = "cfg_clk", "tcu_clk", "tbu_clk";
         };
 
         /* device with two stream IDs, 0 and 7 */
drivers/iommu/arm-smmu.c +94 -2
index f7e11d3..720a1ef 100644
@@ -341,6 +341,12 @@ struct arm_smmu_master_cfg {
 #define for_each_cfg_sme(fw, i, idx) \
        for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
+struct mmu500_clk {
+       struct clk *cfg_clk;
+       struct clk *tcu_clk;
+       struct clk *tbu_clk;
+};
+
 struct arm_smmu_clks {
        void *clks;
        int (*init_clocks)(struct arm_smmu_device *smmu);
@@ -455,6 +461,92 @@ static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
        return container_of(dom, struct arm_smmu_domain, domain);
 }
 
+static int mmu500_enable_clocks(struct arm_smmu_device *smmu)
+{
+       int ret = 0;
+       struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+       if (!sclks)
+               return 0;
+
+       ret = clk_prepare_enable(sclks->cfg_clk);
+       if (ret) {
+               dev_err(smmu->dev, "Couldn't enable cfg_clk");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sclks->tcu_clk);
+       if (ret) {
+               dev_err(smmu->dev, "Couldn't enable tcu_clk");
+               clk_disable_unprepare(sclks->cfg_clk);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sclks->tbu_clk);
+       if (ret) {
+               dev_err(smmu->dev, "Couln't enable tbu_clk");
+               clk_disable_unprepare(sclks->tcu_clk);
+               clk_disable_unprepare(sclks->cfg_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mmu500_disable_clocks(struct arm_smmu_device *smmu)
+{
+       struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+       if (!sclks) {
+               clk_disable_unprepare(sclks->tbu_clk);
+               clk_disable_unprepare(sclks->tcu_clk);
+               clk_disable_unprepare(sclks->cfg_clk);
+       }
+}
+
+static int mmu500_init_clocks(struct arm_smmu_device *smmu)
+{
+       struct device *dev = smmu->dev;
+       struct mmu500_clk *sclks;
+       int err;
+
+       if (!of_find_property(dev->of_node, "clocks", NULL))
+               return 0;
+
+       sclks = devm_kzalloc(dev, sizeof(*sclks), GFP_KERNEL);
+       if (!sclks)
+               return -ENOMEM;
+
+       sclks->cfg_clk = devm_clk_get(dev, "cfg_clk");
+       if (IS_ERR(sclks->cfg_clk)) {
+               err = PTR_ERR(sclks->cfg_clk);
+               /* Ignore all, except -EPROBE_DEFER for optional clocks */
+               if (err == -EPROBE_DEFER)
+                       return err;
+               else
+                       sclks->cfg_clk = NULL;
+       }
+
+       sclks->tcu_clk = devm_clk_get(dev, "tcu_clk");
+       if (IS_ERR(sclks->tcu_clk)) {
+               dev_err(dev, "Couldn't get tcu_clk");
+               return PTR_ERR(sclks->tcu_clk);
+       }
+
+       sclks->tbu_clk = devm_clk_get(dev, "tbu_clk");
+       if (IS_ERR(sclks->tbu_clk)) {
+               err = PTR_ERR(sclks->tbu_clk);
+               /* Ignore all, ecept -EPROBE_DEFER for optional clocks */
+               if (err == -EPROBE_DEFER)
+                       return err;
+               else
+                       sclks->tbu_clk = NULL;
+       }
+
+       smmu->smmu_clks.clks = sclks;
+       return 0;
+}
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
        int i = 0;
@@ -1981,7 +2073,8 @@ struct arm_smmu_match_data {
                    NULL, NULL, NULL);
 ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU,
                    NULL, NULL, NULL);
-ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, mmu500_init_clocks,
+                   mmu500_enable_clocks, mmu500_disable_clocks);
 ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2,
                    NULL, NULL, NULL);
 
--

QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

_______________________________________________
iommu mailing list
iommu at lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

#6 lore raw

PATCH v3 2/5 iommu/arm-smmu: Add support for MMU40x/500 clocks

Hi,

Quoted 35 lines · Rob Clark
Quoted 25 lines · Sricharan R

The MMU400x/500 is the implementation of the SMMUv2 arch specification. It is split in to two blocks TBU, TCU. TBU caches the page table, instantiated for each master locally, clocked by the TBUn_clk. TCU manages the address translation with PTW and has the programming interface as well, clocked using the TCU_CLK. The TBU can also be sharing the same clock domain as TCU, in which case both are clocked using the TCU_CLK.

This defines the clock bindings for the same and adds the init, enable and disable functions for handling the clocks.

---
 .../devicetree/bindings/iommu/arm,smmu.txt         | 27 ++++++
 drivers/iommu/arm-smmu.c                           | 95 +++++++++++++++++++++-
 2 files changed, 121 insertions(+), 1 deletion(-)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +0 -0
index 6cdf32d..b369c13 100644

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 64

Quoted 5 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +2 -0
@@ -60,6 +60,28 @@ conditions.
                   aliases of secure registers have to be used during
                   SMMU configuration.
 
+- clock-names:    Should be "tbu_clk" and "tcu_clk" and "cfg_clk" for
+                  "arm,mmu-400", "arm,mmu-401" and "arm,mmu-500"

I guess that should be: "Should be "tbu_clk" *or* "tcu_clk" and "cfg_clk" for..."

Quoted 4 lines

Also, possibly we should define our own compat strings for various SoC's that require these clks so we can properly describe when they are required? I guess that would address Rob H's comment.

Ok, calling "optional" does not look correct. But i was trying to define something which would be right for all implementations of MMU-500, but looks like that's not the right way. Making it soc specific would give a exact description, except for the number of compatibles and have to change the code to not consider any of tbu , tcu, cfg clk as mandatory for adding support for other compatibles later which are mostly similar. So i am trying to setup the clocks using functions specific for each compatible. Not sure, if at this point, some soc specific callback from the driver where these things can be initialized might be good.

Regards,
Sricharan

Regards,
Sricharan

Quoted 169 lines

BR,
-R

Quoted 157 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +24 -0
+                  "tcu_clk" is required for smmu's register access using the
+                  programming interface and ptw for downstream bus access.
+
+                  "tbu_clk" is required for access to the TBU connected to the
+                  master locally. This clock is optional and not required when
+                  TBU is in the same clock domain as the TCU or when the TBU is
+                  clocked along with the master.
+
+                  "cfg_clk" is optional if required to access the TCU's programming
+                  interface, apart from the "tcu_clk".
+
+- clocks:         Phandles for respective clocks described by clock-names.
+
+- power-domains:  Phandles to SMMU's power domain specifier. This is
+                  required even if SMMU belongs to the master's power
+                  domain, as the SMMU will have to be enabled and
+                  accessed before master gets enabled and linked to its
+                  SMMU.
+
 ** Deprecated properties:
 
 - mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -84,6 +106,11 @@ conditions.
                              <0 36 4>,
                              <0 37 4>;
                 #iommu-cells = <1>;
+                clocks = <&gcc GCC_SMMU_CFG_CLK>,
+                         <&gcc GCC_APSS_TCU_CLK>,
+                        <&gcc GCC_MDP_TBU_CLK>;
+
+               clock-names = "cfg_clk", "tcu_clk", "tbu_clk";
         };
 
         /* device with two stream IDs, 0 and 7 */
drivers/iommu/arm-smmu.c +94 -2
index f7e11d3..720a1ef 100644
@@ -341,6 +341,12 @@ struct arm_smmu_master_cfg {
 #define for_each_cfg_sme(fw, i, idx) \
        for (i = 0; idx = fwspec_smendx(fw, i), i < fw->num_ids; ++i)
 
+struct mmu500_clk {
+       struct clk *cfg_clk;
+       struct clk *tcu_clk;
+       struct clk *tbu_clk;
+};
+
 struct arm_smmu_clks {
        void *clks;
        int (*init_clocks)(struct arm_smmu_device *smmu);
@@ -455,6 +461,92 @@ static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
        return container_of(dom, struct arm_smmu_domain, domain);
 }
 
+static int mmu500_enable_clocks(struct arm_smmu_device *smmu)
+{
+       int ret = 0;
+       struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+       if (!sclks)
+               return 0;
+
+       ret = clk_prepare_enable(sclks->cfg_clk);
+       if (ret) {
+               dev_err(smmu->dev, "Couldn't enable cfg_clk");
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sclks->tcu_clk);
+       if (ret) {
+               dev_err(smmu->dev, "Couldn't enable tcu_clk");
+               clk_disable_unprepare(sclks->cfg_clk);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(sclks->tbu_clk);
+       if (ret) {
+               dev_err(smmu->dev, "Couln't enable tbu_clk");
+               clk_disable_unprepare(sclks->tcu_clk);
+               clk_disable_unprepare(sclks->cfg_clk);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void mmu500_disable_clocks(struct arm_smmu_device *smmu)
+{
+       struct mmu500_clk *sclks = smmu->smmu_clks.clks;
+
+       if (!sclks) {
+               clk_disable_unprepare(sclks->tbu_clk);
+               clk_disable_unprepare(sclks->tcu_clk);
+               clk_disable_unprepare(sclks->cfg_clk);
+       }
+}
+
+static int mmu500_init_clocks(struct arm_smmu_device *smmu)
+{
+       struct device *dev = smmu->dev;
+       struct mmu500_clk *sclks;
+       int err;
+
+       if (!of_find_property(dev->of_node, "clocks", NULL))
+               return 0;
+
+       sclks = devm_kzalloc(dev, sizeof(*sclks), GFP_KERNEL);
+       if (!sclks)
+               return -ENOMEM;
+
+       sclks->cfg_clk = devm_clk_get(dev, "cfg_clk");
+       if (IS_ERR(sclks->cfg_clk)) {
+               err = PTR_ERR(sclks->cfg_clk);
+               /* Ignore all, except -EPROBE_DEFER for optional clocks */
+               if (err == -EPROBE_DEFER)
+                       return err;
+               else
+                       sclks->cfg_clk = NULL;
+       }
+
+       sclks->tcu_clk = devm_clk_get(dev, "tcu_clk");
+       if (IS_ERR(sclks->tcu_clk)) {
+               dev_err(dev, "Couldn't get tcu_clk");
+               return PTR_ERR(sclks->tcu_clk);
+       }
+
+       sclks->tbu_clk = devm_clk_get(dev, "tbu_clk");
+       if (IS_ERR(sclks->tbu_clk)) {
+               err = PTR_ERR(sclks->tbu_clk);
+               /* Ignore all, ecept -EPROBE_DEFER for optional clocks */
+               if (err == -EPROBE_DEFER)
+                       return err;
+               else
+                       sclks->tbu_clk = NULL;
+       }
+
+       smmu->smmu_clks.clks = sclks;
+       return 0;
+}
+
 static void parse_driver_options(struct arm_smmu_device *smmu)
 {
        int i = 0;
@@ -1981,7 +2073,8 @@ struct arm_smmu_match_data {
                    NULL, NULL, NULL);
 ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU,
                    NULL, NULL, NULL);
-ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, NULL, NULL, NULL);
+ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500, mmu500_init_clocks,
+                   mmu500_enable_clocks, mmu500_disable_clocks);
 ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2,
                    NULL, NULL, NULL);
 
--

QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

Quoted 4 lines

_______________________________________________
iommu mailing list
iommu at lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 2 lines
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a 
member of Code Aurora Forum, hosted by The Linux Foundation
#7 lore raw

PATCH v3 3/5 drivers: arm-smmu: Add clock support for QCOM_SMMUV2

In reply to Sricharan R

The QCOM_SMMUV2 is an implementation of the arm,smmu-v2 architecture. The qcom,smmu is instantiated for each of the multimedia cores (for eg) Venus (video encoder/decoder), mdp (display) etc, and they are connected to the Multimedia Aggregator Interconnect (MMAGIC). So the access to any of the MMU's registers, as well as MMU's downstream bus access, requires the specified MMAGIC clocks to be enabled. So adding a new binding for the qcom,smmu-v2 and the required mmagic clock bindings for the same. Also adding the support for enabling the qcom,smmu-v2 clocks in the driver.

               -------------  ---------
               |   VENUS   |  | MDP   |
	       |	   |  |       |
	       -------------  --------
		     |           |
		     |           |
                  ------      ---------
                  |SMMU |     | SMMU  |
                  |	|     |       |
                  ------      --------
		    |            |
		    |            |
       -----------------------------------------
       |	MMAGIC INTERCONNECT (MMSS NOC) |
       |                                       |
       -----------------------------------------
                   |                 |
		   |           ----------------------------------
                 -----         | 	SYSTEM NOC		|
                 |DDR|	       |				|
                 -----         ---------------------------------
		   |		    |
                   |               ------
		   |<-------------| CPU|
				  ------
---
 .../devicetree/bindings/iommu/arm,smmu.txt         |   8 ++
 drivers/iommu/arm-smmu.c                           | 124 +++++++++++++++++++++
 2 files changed, 132 insertions(+)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +8 -0
index b369c13..88e02d6 100644
@@ -17,6 +17,7 @@ conditions.
                         "arm,mmu-401"
                         "arm,mmu-500"
                         "cavium,smmu-v2"
+			"qcom,smmu-v2"
 
                   depending on the particular implementation and/or the
                   version of the architecture implemented.
@@ -74,6 +75,13 @@ conditions.
                   "cfg_clk" is optional if required to access the TCU's programming
                   interface, apart from the "tcu_clk".
 
+		  Should have "mmagic_ahb_clk", "mmagic_cfg_ahb_clk",
+                              "smmu_core_ahb_clk", "smmu_core_axi_clk",
+                              "mmagic_core_axi_clk" for "qcom,smmu-v2"
+
+		  "mmagic_core_axi_clk" is required for smmu's access to the
+                   downstream bus and rest for the smmu's register group access.
+
 - clocks:         Phandles for respective clocks described by clock-names.
 
 - power-domains:  Phandles to SMMU's power domain specifier. This is
drivers/iommu/arm-smmu.c +124 -0

154 lines not on this page · raw message

Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
maintainer
#8 lore raw

PATCH v3 3/5 drivers: arm-smmu: Add clock support for QCOM_SMMUV2

Quoted 47 lines · Sricharan R

The QCOM_SMMUV2 is an implementation of the arm,smmu-v2 architecture. The qcom,smmu is instantiated for each of the multimedia cores (for eg) Venus (video encoder/decoder), mdp (display) etc, and they are connected to the Multimedia Aggregator Interconnect (MMAGIC). So the access to any of the MMU's registers, as well as MMU's downstream bus access, requires the specified MMAGIC clocks to be enabled. So adding a new binding for the qcom,smmu-v2 and the required mmagic clock bindings for the same. Also adding the support for enabling the qcom,smmu-v2 clocks in the driver.

               -------------  ---------
               |   VENUS   |  | MDP   |
	       |	   |  |       |
	       -------------  --------
		     |           |
		     |           |
                  ------      ---------
                  |SMMU |     | SMMU  |
                  |	|     |       |
                  ------      --------
		    |            |
		    |            |
       -----------------------------------------
       |	MMAGIC INTERCONNECT (MMSS NOC) |
       |                                       |
       -----------------------------------------
                   |                 |
		   |           ----------------------------------
                 -----         | 	SYSTEM NOC		|
                 |DDR|	       |				|
                 -----         ---------------------------------
		   |		    |
                   |               ------
		   |<-------------| CPU|
				  ------
---
 .../devicetree/bindings/iommu/arm,smmu.txt         |   8 ++
 drivers/iommu/arm-smmu.c                           | 124 +++++++++++++++++++++
 2 files changed, 132 insertions(+)
Documentation/devicetree/bindings/iommu/arm,smmu.txt +0 -0
index b369c13..88e02d6 100644

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 20

Quoted 4 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +1 -0
@@ -17,6 +17,7 @@ conditions.
                         "arm,mmu-401"
                         "arm,mmu-500"
                         "cavium,smmu-v2"
+			"qcom,smmu-v2"

I know Cavium did it, but I'd prefer to see SoC specific compatibles here.

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 80

Quoted 10 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +3 -0
                   depending on the particular implementation and/or the
                   version of the architecture implemented.
@@ -74,6 +75,13 @@ conditions.
                   "cfg_clk" is optional if required to access the TCU's programming
                   interface, apart from the "tcu_clk".
 
+		  Should have "mmagic_ahb_clk", "mmagic_cfg_ahb_clk",
+                              "smmu_core_ahb_clk", "smmu_core_axi_clk",
+                              "mmagic_core_axi_clk" for "qcom,smmu-v2"

This is instead of the above clocks?

Are these clocks all really part of the SMMU or are the mmagic clocks working around no proper driver for the mmagic?

Quoted 7 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +4 -0
+
+		  "mmagic_core_axi_clk" is required for smmu's access to the
+                   downstream bus and rest for the smmu's register group access.
+
 - clocks:         Phandles for respective clocks described by clock-names.
 
 - power-domains:  Phandles to SMMU's power domain specifier. This is
#9 lore raw

PATCH v3 3/5 drivers: arm-smmu: Add clock support for QCOM_SMMUV2

Hi Rob,

Quoted 43 lines · Rob Herring
Quoted 42 lines · Sricharan R

The QCOM_SMMUV2 is an implementation of the arm,smmu-v2 architecture. The qcom,smmu is instantiated for each of the multimedia cores (for eg) Venus (video encoder/decoder), mdp (display) etc, and they are connected to the Multimedia Aggregator Interconnect (MMAGIC). So the access to any of the MMU's registers, as well as MMU's downstream bus access, requires the specified MMAGIC clocks to be enabled. So adding a new binding for the qcom,smmu-v2 and the required mmagic clock bindings for the same. Also adding the support for enabling the qcom,smmu-v2 clocks in the driver.

               -------------  ---------
               |   VENUS   |  | MDP   |
	       |	   |  |       |
	       -------------  --------
		     |           |
		     |           |
                  ------      ---------
                  |SMMU |     | SMMU  |
                  |	|     |       |
                  ------      --------
		    |            |
		    |            |
       -----------------------------------------
       |	MMAGIC INTERCONNECT (MMSS NOC) |
       |                                       |
       -----------------------------------------
                   |                 |
		   |           ----------------------------------
                 -----         | 	SYSTEM NOC		|
                 |DDR|	       |				|
                 -----         ---------------------------------
		   |		    |
                   |               ------
		   |<-------------| CPU|
				  ------
---
 .../devicetree/bindings/iommu/arm,smmu.txt         |   8 ++
 drivers/iommu/arm-smmu.c                           | 124 +++++++++++++++++++++
 2 files changed, 132 insertions(+)
Quoted 12 lines

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 20

Quoted 9 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +1 -0
index b369c13..88e02d6 100644
@@ -17,6 +17,7 @@ conditions.
                         "arm,mmu-401"
                         "arm,mmu-500"
                         "cavium,smmu-v2"
+			"qcom,smmu-v2"

I know Cavium did it, but I'd prefer to see SoC specific compatibles here.

ok, will change it to be soc specific.

Quoted 8 lines
Quoted 8 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +0 -0
                   depending on the particular implementation and/or the
                   version of the architecture implemented.
@@ -74,6 +75,13 @@ conditions.
                   "cfg_clk" is optional if required to access the TCU's programming
                   interface, apart from the "tcu_clk".
 
Quoted 6 lines

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 80

Quoted 3 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +3 -0
+		  Should have "mmagic_ahb_clk", "mmagic_cfg_ahb_clk",
+                              "smmu_core_ahb_clk", "smmu_core_axi_clk",
+                              "mmagic_core_axi_clk" for "qcom,smmu-v2"

This is instead of the above clocks?

These clocks are for 'qcom,smmu-v2'. I should have put that first, then the clock names.

Quoted 3 lines

Are these clocks all really part of the SMMU or are the mmagic clocks working around no proper driver for the mmagic?

infact because of the absence of the mmagic driver to handle it. But i think, i will have to rework this, because handling mmagic clocks is going to pushed elsewhere, to the the gdscs(powerdomains). So adding the mmagic clocks should not be required here after that.

Regards,
Sricharan

Quoted 13 lines

Documentation/devicetree/bindings/iommu/arm,smmu.txt conditions. · line 87

Quoted 7 lines
Documentation/devicetree/bindings/iommu/arm,smmu.txt +4 -0
+
+		  "mmagic_core_axi_clk" is required for smmu's access to the
+                   downstream bus and rest for the smmu's register group access.
+
 - clocks:         Phandles for respective clocks described by clock-names.
 
 - power-domains:  Phandles to SMMU's power domain specifier. This is

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Signature · 2 lines
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a 
member of Code Aurora Forum, hosted by The Linux Foundation
#10 lore raw

PATCH v3 4/5 iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device

In reply to Sricharan R

The smmu device probe/remove and add/remove master device callbacks gets called when the smmu is not linked to its master, that is without the context of the master device. So calling runtime apis in those places separately.

---
 drivers/iommu/arm-smmu.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)
drivers/iommu/arm-smmu.c +45 -2
index f29e28bf..6370421 100644
@@ -1216,11 +1216,16 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
 	struct arm_smmu_device *smmu = smmu_domain->smmu;
 	struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
 	void __iomem *cb_base;
+	unsigned long ret;
 	int irq;
 
 	if (!smmu)
 		return;
 
+	ret = pm_runtime_get_sync(smmu->dev);
+	if (IS_ERR_VALUE(ret))
+		dev_warn(smmu->dev, "runtime resume failed");
+
 	/*
 	 * Disable the context bank and free the page tables before freeing
 	 * it.
@@ -1235,6 +1240,10 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
 
 	free_io_pgtable_ops(smmu_domain->pgtbl_ops);
 	__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
+
+	ret = pm_runtime_put_sync(smmu->dev);
+	if (IS_ERR_VALUE(ret))
+		dev_warn(smmu->dev, "runtime suspend failed");
 }
 
 static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
@@ -1663,6 +1672,7 @@ static int arm_smmu_add_device(struct device *dev)
 	struct arm_smmu_master_cfg *cfg;
 	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
 	int i, ret;
+	unsigned long err;
 
 	if (using_legacy_binding) {
 		ret = arm_smmu_register_legacy_master(dev, &smmu);
@@ -1703,12 +1713,20 @@ static int arm_smmu_add_device(struct device *dev)
 	while (i--)
 		cfg->smendx[i] = INVALID_SMENDX;
 
+	err = pm_runtime_get_sync(smmu->dev);
+	if (IS_ERR_VALUE(err))
+		goto out_free;
+
 	ret = arm_smmu_master_alloc_smes(dev);
 	if (ret)
 		goto out_free;
 
 	iommu_device_link(&smmu->iommu, dev);
 
+	err = pm_runtime_put_sync(smmu->dev);
+	if (IS_ERR_VALUE(err))
+		goto out_free;
+
 	return 0;
 
 out_free:
@@ -1723,7 +1741,7 @@ static void arm_smmu_remove_device(struct device *dev)
 	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
 	struct arm_smmu_master_cfg *cfg;
 	struct arm_smmu_device *smmu;
-
+	unsigned long ret;
 
 	if (!fwspec || fwspec->ops != &arm_smmu_ops)
 		return;
@@ -1731,8 +1749,23 @@ static void arm_smmu_remove_device(struct device *dev)
 	cfg  = fwspec->iommu_priv;
 	smmu = cfg->smmu;
 
+	/*
+	 * The device link between the master device and
+	 * smmu is already purged at this point.
+	 * So enable the power to smmu explicitly.
+	 */
+
+	ret = pm_runtime_get_sync(smmu->dev);
+	if (IS_ERR_VALUE(ret))
+		dev_warn(smmu->dev, "runtime resume failed");
+
 	iommu_device_unlink(&smmu->iommu, dev);
 	arm_smmu_master_free_smes(fwspec);
+
+	ret = pm_runtime_put_sync(smmu->dev);
+	if (IS_ERR_VALUE(ret))
+		dev_warn(smmu->dev, "runtime suspend failed");
+
 	iommu_group_remove_device(dev);
 	kfree(fwspec->iommu_priv);
 	iommu_fwspec_free(dev);
@@ -2316,6 +2349,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 	struct arm_smmu_device *smmu;
 	struct device *dev = &pdev->dev;
 	int num_irqs, i, err;
+	unsigned long ret;
 
 	smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
 	if (!smmu) {
@@ -2375,7 +2409,12 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 			return err;
 	}
 
+	platform_set_drvdata(pdev, smmu);
 	pm_runtime_enable(dev);
+	ret = pm_runtime_get_sync(dev);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
 	err = arm_smmu_device_cfg_probe(smmu);
 	if (err)
 		return err;
@@ -2417,9 +2456,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
 		return err;
 	}
 
-	platform_set_drvdata(pdev, smmu);
 	arm_smmu_device_reset(smmu);
 	arm_smmu_test_smr_masks(smmu);
+	ret = pm_runtime_put_sync(dev);
+	if (IS_ERR_VALUE(ret))
+		return err;
 
 	/* Oh, for a proper bus abstraction */
 	if (!iommu_present(&platform_bus_type))
@@ -2449,6 +2490,8 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
 
 	/* Turn the thing off */
 	writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+	pm_runtime_force_suspend(smmu->dev);
+
 	return 0;
 }
 
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
#11 lore raw

PATCH v3 5/5 iommu/arm-smmu: Add the device_link between masters and smmu

In reply to Sricharan R

Finally add the device link between the master device and smmu, so that the smmu gets runtime enabled/disabled only when the master needs it. This is done from add_device callback which gets called once when the master is added to the smmu.

---
 drivers/iommu/arm-smmu.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/iommu/arm-smmu.c +11 -0
index 6370421..b06f86c7 100644
@@ -1671,6 +1671,7 @@ static int arm_smmu_add_device(struct device *dev)
 	struct arm_smmu_device *smmu;
 	struct arm_smmu_master_cfg *cfg;
 	struct iommu_fwspec *fwspec = dev->iommu_fwspec;
+	struct device_link *link = NULL;
 	int i, ret;
 	unsigned long err;
 
@@ -1727,6 +1728,16 @@ static int arm_smmu_add_device(struct device *dev)
 	if (IS_ERR_VALUE(err))
 		goto out_free;
 
+	/*
+	 * Establish the link between smmu and master, so that the
+	 * smmu gets runtime enabled/disabled as per the master's
+	 * needs.
+	 */
+	link = device_link_add(dev, smmu->dev, DL_FLAG_PM_RUNTIME);
+	if (!link)
+		dev_warn(smmu->dev, "Unable to create device link between %s and %s\n",
+			 dev_name(smmu->dev), dev_name(dev));
+
 	return 0;
 
 out_free:
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
#12 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

In reply to Sricharan R
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

Thanks,

Will

Quoted 49 lines

Took some reference from the exynos runtime patches [2]. Tested this with MDP, GPU, VENUS devices on apq8096-db820c board.

Previous version of the patchset [1].

[V3]
* Reworked the patches to keep the clocks init/enabling function seperately for each compatible.

* Added clocks bindings for MMU40x/500.

* Added a new compatible for qcom,smmu-v2 implementation and the clock bindings for the same.

* Rebased on top of 4.11-rc1

[V2]
* Split the patches little differently.

* Addressed comments.

* Removed the patch #4 [3] from previous post for arm-smmu context save restore. Planning to post this separately after reworking/addressing Robin's feedback.

* Reversed the sequence to disable clocks than enabling. This was required for those cases where the clocks are populated in a dependent order from DT.

[1] https://www.spinics.net/lists/linux-arm-msm/msg23870.html
[2] https://lkml.org/lkml/2016/10/20/70
[3] https://patchwork.kernel.org/patch/9389717/

Sricharan R (5):
iommu/arm-smmu: Add pm_runtime/sleep ops iommu/arm-smmu: Add support for MMU40x/500 clocks
drivers: arm-smmu: Add clock support for QCOM_SMMUV2 iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device iommu/arm-smmu: Add the device_link between masters and smmu

 .../devicetree/bindings/iommu/arm,smmu.txt         |  35 +++
 drivers/iommu/arm-smmu.c                           | 349 ++++++++++++++++++++-
 2 files changed, 373 insertions(+), 11 deletions(-)
Signature · 1 line
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
#13 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

Quoted 7 lines · Will Deacon
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Quoted 6 lines

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

well, if you think about a phone/tablet with a command mode panel, pretty much all devices will be suspended most of the time ;-)

maybe it's a different case with servers.. unfortunately we have to share the same driver across both..

BR,
-R

Quoted 57 lines

Thanks,

Will

Quoted 42 lines

Took some reference from the exynos runtime patches [2]. Tested this with MDP, GPU, VENUS devices on apq8096-db820c board.

Previous version of the patchset [1].

[V3]
* Reworked the patches to keep the clocks init/enabling function seperately for each compatible.

* Added clocks bindings for MMU40x/500.

* Added a new compatible for qcom,smmu-v2 implementation and the clock bindings for the same.

* Rebased on top of 4.11-rc1

[V2]
* Split the patches little differently.

* Addressed comments.

* Removed the patch #4 [3] from previous post for arm-smmu context save restore. Planning to post this separately after reworking/addressing Robin's feedback.

* Reversed the sequence to disable clocks than enabling. This was required for those cases where the clocks are populated in a dependent order from DT.

[1] https://www.spinics.net/lists/linux-arm-msm/msg23870.html
[2] https://lkml.org/lkml/2016/10/20/70
[3] https://patchwork.kernel.org/patch/9389717/

Sricharan R (5):
iommu/arm-smmu: Add pm_runtime/sleep ops iommu/arm-smmu: Add support for MMU40x/500 clocks
drivers: arm-smmu: Add clock support for QCOM_SMMUV2 iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device iommu/arm-smmu: Add the device_link between masters and smmu

Quoted 7 lines
 .../devicetree/bindings/iommu/arm,smmu.txt         |  35 +++
 drivers/iommu/arm-smmu.c                           | 349 ++++++++++++++++++++-
 2 files changed, 373 insertions(+), 11 deletions(-)

--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

_______________________________________________
iommu mailing list
iommu at lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

#14 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

Quoted 12 lines · Rob Clark
Quoted 11 lines · Will Deacon
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

Quoted 5 lines
Quoted 2 lines

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

well, if you think about a phone/tablet with a command mode panel, pretty much all devices will be suspended most of the time ;-)

Well, that's really what I was asking about. I assumed that periodic modem/radio transactions would keep the SMMU clocked, so would like to get a rough idea of the power savings achieved with this coarse-grained approach.

Will

#15 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

Hi Will,

Quoted 16 lines · Will Deacon
Quoted 15 lines · Rob Clark
Quoted 13 lines · Will Deacon
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

Quoted 7 lines
Quoted 2 lines

well, if you think about a phone/tablet with a command mode panel, pretty much all devices will be suspended most of the time ;-)

Well, that's really what I was asking about. I assumed that periodic modem/radio transactions would keep the SMMU clocked, so would like to get a rough idea of the power savings achieved with this coarse-grained approach.

One main reason for introducing this was to enable power for the iommus separately in those places where the iommu gets accessed without the context of the master, pm runtime was done to use the device links feature and also those iommus had their power-domains to be enabled (during the iommu probe, faults) (downstream was modelling those power-domains as 'regulators' which was not correct) and have to be clocked as well.

I was in the process of trying to measure the power difference that this would achieve. One concern here is, this series depends on the device link between master and iommu.
So essentially the masters have to be pm runtime adapted fully to use this. For my testing i was using couple of them (mdp, gpu), by just enabling pm runtime for them, not full pm runtime though. But i will come-up with the numbers by instrumenting little more. The downstream code explicitly turns on the iommu clocks/regulators in the standalone path (called without master context and after that, lets the master to control the iommu clocks ( the iommu clocks are populated in master DT data as well), so ensures iommu is clocked only when really needed by the master. So number measured from downstream should also give the power numbers in another way.

Regards,
Sricharan

Signature · 2 lines
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a 
member of Code Aurora Forum, hosted by The Linux Foundation
#16 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

In reply to Will Deacon
Quoted 16 lines · Will Deacon
Quoted 15 lines · Rob Clark
Quoted 13 lines · Will Deacon
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

Quoted 6 lines
Quoted 2 lines

well, if you think about a phone/tablet with a command mode panel, pretty much all devices will be suspended most of the time ;-)

Well, that's really what I was asking about. I assumed that periodic modem/radio transactions would keep the SMMU clocked, so would like to get a rough idea of the power savings achieved with this coarse-grained approach.

Sometimes we distribute SMMUs to each IP block in the system and let each one of those live in their own clock + power domain. In these cases, the SMMU can be powered down along with the only IP block that uses it. Furthermore, sometimes we put the IP block and the SMMU inside the same power domain to really tie the two together, so we definitely have cases where all devices (device?) upstream of the SMMU are suspended. And in the case of multimedia, it could be very often that something like the camera app isn't open and thus the SMMU dedicated for the camera can be powered down.

Other times we have two SMMUs in the system where one is dedicated to GPU and the other is "everything else". Even in these cases, we can suspend the GPU one when the GPU is inactive because it's the only consumer. The other SMMU might not be as fine grained, but I think we still power it down quite often because the consumers are mostly multimedia devices that aren't active when the display is off.

Signature · 2 lines
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#17 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

Quoted 35 lines · Stephen Boyd
Quoted 16 lines · Will Deacon
Quoted 15 lines · Rob Clark
Quoted 13 lines · Will Deacon
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

Quoted 6 lines
Quoted 2 lines

well, if you think about a phone/tablet with a command mode panel, pretty much all devices will be suspended most of the time ;-)

Well, that's really what I was asking about. I assumed that periodic modem/radio transactions would keep the SMMU clocked, so would like to get a rough idea of the power savings achieved with this coarse-grained approach.

Sometimes we distribute SMMUs to each IP block in the system and let each one of those live in their own clock + power domain. In these cases, the SMMU can be powered down along with the only IP block that uses it. Furthermore, sometimes we put the IP block and the SMMU inside the same power domain to really tie the two together, so we definitely have cases where all devices (device?) upstream of the SMMU are suspended. And in the case of multimedia, it could be very often that something like the camera app isn't open and thus the SMMU dedicated for the camera can be powered down.

Quoted 7 lines

Other times we have two SMMUs in the system where one is dedicated to GPU and the other is "everything else". Even in these cases, we can suspend the GPU one when the GPU is inactive because it's the only consumer. The other SMMU might not be as fine grained, but I think we still power it down quite often because the consumers are mostly multimedia devices that aren't active when the display is off.

And just to confuse things even further: with per-instance pagetables we have an interest in forcing the SMMU clocks *on* because we don't know when the GPU might try to hit the registers to switch a pagetable and if somebody in the pipeline is actively trying to do power management at the same time hilarity will ensue.

The alternative to pm_runtime is the downstream driver that probes the SMMU clocks from DT and frobs them itself. I think we can agree that is far less reasonable.

Jordan

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
#18 lore raw

v3 cover iommu/arm-smmu: Add runtime pm/sleep support

Hi Jordon,

Quoted 44 lines · Jordan Crouse
Quoted 35 lines · Stephen Boyd
Quoted 16 lines · Will Deacon
Quoted 15 lines · Rob Clark
Quoted 13 lines · Will Deacon
Quoted 5 lines · Sricharan R

This series provides the support for turning on the arm-smmu's clocks/power domains using runtime pm. This is done using the recently introduced device links patches, which lets the symmu's runtime to follow the master's runtime pm, so the smmu remains powered only when the masters use it.

Do you have any numbers for the power savings you achieve with this? How often do we actually manage to stop the SMMU clocks on an SoC with a handful of masters?

In other words, is this too coarse-grained to be useful, or is it common that all the devices upstream of the SMMU are suspended?

Quoted 6 lines
Quoted 2 lines

well, if you think about a phone/tablet with a command mode panel, pretty much all devices will be suspended most of the time ;-)

Well, that's really what I was asking about. I assumed that periodic modem/radio transactions would keep the SMMU clocked, so would like to get a rough idea of the power savings achieved with this coarse-grained approach.

Sometimes we distribute SMMUs to each IP block in the system and let each one of those live in their own clock + power domain. In these cases, the SMMU can be powered down along with the only IP block that uses it. Furthermore, sometimes we put the IP block and the SMMU inside the same power domain to really tie the two together, so we definitely have cases where all devices (device?) upstream of the SMMU are suspended. And in the case of multimedia, it could be very often that something like the camera app isn't open and thus the SMMU dedicated for the camera can be powered down.

Quoted 7 lines

Other times we have two SMMUs in the system where one is dedicated to GPU and the other is "everything else". Even in these cases, we can suspend the GPU one when the GPU is inactive because it's the only consumer. The other SMMU might not be as fine grained, but I think we still power it down quite often because the consumers are mostly multimedia devices that aren't active when the display is off.

Quoted 6 lines

And just to confuse things even further: with per-instance pagetables we have an interest in forcing the SMMU clocks *on* because we don't know when the GPU might try to hit the registers to switch a pagetable and if somebody in the pipeline is actively trying to do power management at the same time hilarity will ensue.

Ok, with per-process pagetables which gpu handles by itself, is the gpu driver not going to keep its own clocks pm_runtime active before handing it over to the firmware ? which would in this case take care of having the iommu clocks also enabled because of the device links in the behind.

Quoted 3 lines

The alternative to pm_runtime is the downstream driver that probes the SMMU clocks from DT and frobs them itself. I think we can agree that is far less reasonable.

The idea here was to keep the iommu clocks only represented inside the IOMMU DT and handled by that driver. This works fine with the video decoder which is already fully pm_runtime enabled and works fine with basic gpu testing. Do you see any issues in testing this with the per-process pagetables ?

Regards,
Sricharan

Signature · 1 line
"QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation