Skip to content

Commit aea160c

Browse files
authored
iommu/arm-smmu: Add interconnect bandwidth voting support (#590)
iommu/arm-smmu: Add interconnect bandwidth voting support
2 parents daed243 + 685c987 commit aea160c

3 files changed

Lines changed: 63 additions & 1 deletion

File tree

Documentation/devicetree/bindings/iommu/arm,smmu.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ properties:
239239
minItems: 1
240240
maxItems: 3
241241

242+
interconnects:
243+
maxItems: 1
244+
description:
245+
Optional interconnect path to the SMMU register space. On some SoCs
246+
the SMMU registers are only accessible after a bandwidth vote has been
247+
placed on the interconnect fabric. When present the driver votes for
248+
bandwidth on this path before accessing any SMMU registers and releases
249+
the vote on runtime suspend.
250+
242251
nvidia,memory-controller:
243252
description: |
244253
A phandle to the memory controller on NVIDIA Tegra186 and later SoCs.

drivers/iommu/arm/arm-smmu/arm-smmu.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@
5353
#define MSI_IOVA_BASE 0x8000000
5454
#define MSI_IOVA_LENGTH 0x100000
5555

56+
/* Interconnect bandwidth vote values for the SMMU register access path */
57+
#define ARM_SMMU_ICC_AVG_BW 0
58+
#define ARM_SMMU_ICC_PEAK_BW_HIGH 1000
59+
#define ARM_SMMU_ICC_PEAK_BW_LOW 0
60+
5661
static int force_stage;
5762
module_param(force_stage, int, S_IRUGO);
5863
MODULE_PARM_DESC(force_stage,
@@ -86,6 +91,36 @@ static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
8691
}
8792
}
8893

94+
static int arm_smmu_icc_get(struct arm_smmu_device *smmu)
95+
{
96+
smmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
97+
if (IS_ERR(smmu->icc_path)) {
98+
int err = PTR_ERR(smmu->icc_path);
99+
100+
if (err == -ENODATA) {
101+
smmu->icc_path = NULL;
102+
return 0;
103+
}
104+
return dev_err_probe(smmu->dev, err,
105+
"failed to get interconnect path\n");
106+
}
107+
return 0;
108+
}
109+
110+
static void arm_smmu_icc_enable(struct arm_smmu_device *smmu)
111+
{
112+
if (smmu->icc_path)
113+
WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
114+
ARM_SMMU_ICC_PEAK_BW_HIGH));
115+
}
116+
117+
static void arm_smmu_icc_disable(struct arm_smmu_device *smmu)
118+
{
119+
if (smmu->icc_path)
120+
WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
121+
ARM_SMMU_ICC_PEAK_BW_LOW));
122+
}
123+
89124
static void arm_smmu_rpm_use_autosuspend(struct arm_smmu_device *smmu)
90125
{
91126
/*
@@ -2209,6 +2244,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
22092244
if (err)
22102245
return err;
22112246

2247+
/*
2248+
* Acquire and vote the interconnect path before accessing any SMMU
2249+
* registers (including ARM_SMMU_GR0_ID0 in arm_smmu_device_cfg_probe).
2250+
*/
2251+
err = arm_smmu_icc_get(smmu);
2252+
if (err) {
2253+
clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
2254+
return err;
2255+
}
2256+
arm_smmu_icc_enable(smmu);
2257+
22122258
err = arm_smmu_device_cfg_probe(smmu);
22132259
if (err)
22142260
return err;
@@ -2309,9 +2355,13 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
23092355
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
23102356
int ret;
23112357

2358+
arm_smmu_icc_enable(smmu);
2359+
23122360
ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
2313-
if (ret)
2361+
if (ret) {
2362+
arm_smmu_icc_disable(smmu);
23142363
return ret;
2364+
}
23152365

23162366
arm_smmu_device_reset(smmu);
23172367

@@ -2323,6 +2373,7 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
23232373
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
23242374

23252375
clk_bulk_disable(smmu->num_clks, smmu->clks);
2376+
arm_smmu_icc_disable(smmu);
23262377

23272378
return 0;
23282379
}

drivers/iommu/arm/arm-smmu/arm-smmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/bits.h>
1616
#include <linux/clk.h>
1717
#include <linux/device.h>
18+
#include <linux/interconnect.h>
1819
#include <linux/io-64-nonatomic-hi-lo.h>
1920
#include <linux/io-pgtable.h>
2021
#include <linux/iommu.h>
@@ -335,6 +336,7 @@ struct arm_smmu_device {
335336
int num_clks;
336337
unsigned int *irqs;
337338
struct clk_bulk_data *clks;
339+
struct icc_path *icc_path;
338340

339341
spinlock_t global_sync_lock;
340342

0 commit comments

Comments
 (0)