Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Documentation/devicetree/bindings/iommu/arm,smmu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,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.
Expand Down Expand Up @@ -600,6 +607,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:
Expand Down
57 changes: 55 additions & 2 deletions drivers/iommu/arm/arm-smmu/arm-smmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
#define MSI_IOVA_BASE 0x8000000
#define MSI_IOVA_LENGTH 0x100000

/* Interconnect bandwidth vote values for the SMMU register access path */
#define ARM_SMMU_ICC_AVG_BW 0
#define ARM_SMMU_ICC_PEAK_BW_HIGH 1000
#define ARM_SMMU_ICC_PEAK_BW_LOW 0

static int force_stage;
module_param(force_stage, int, S_IRUGO);
MODULE_PARM_DESC(force_stage,
Expand Down Expand Up @@ -86,6 +91,36 @@ static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
}
}

static int arm_smmu_icc_get(struct arm_smmu_device *smmu)
{
smmu->icc_path = devm_of_icc_get(smmu->dev, NULL);
if (IS_ERR(smmu->icc_path)) {
int err = PTR_ERR(smmu->icc_path);

if (err == -ENODEV) {
smmu->icc_path = NULL;
return 0;
}
return dev_err_probe(smmu->dev, err,
"failed to get interconnect path\n");
}
return 0;
}

static void arm_smmu_icc_enable(struct arm_smmu_device *smmu)
{
if (smmu->icc_path)
WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
ARM_SMMU_ICC_PEAK_BW_HIGH));
}

static void arm_smmu_icc_disable(struct arm_smmu_device *smmu)
{
if (smmu->icc_path)
WARN_ON(icc_set_bw(smmu->icc_path, ARM_SMMU_ICC_AVG_BW,
ARM_SMMU_ICC_PEAK_BW_LOW));
}

static void arm_smmu_rpm_use_autosuspend(struct arm_smmu_device *smmu)
{
/*
Expand Down Expand Up @@ -2212,6 +2247,17 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
if (err)
return err;

/*
* Acquire and vote the interconnect path before accessing any SMMU
* registers (including ARM_SMMU_GR0_ID0 in arm_smmu_device_cfg_probe).
*/
err = arm_smmu_icc_get(smmu);
if (err) {
clk_bulk_disable_unprepare(smmu->num_clks, smmu->clks);
return err;
}
arm_smmu_icc_enable(smmu);

err = arm_smmu_device_cfg_probe(smmu);
if (err)
return err;
Expand Down Expand Up @@ -2291,8 +2337,10 @@ 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);
arm_smmu_icc_disable(smmu);
}

clk_bulk_unprepare(smmu->num_clks, smmu->clks);
}
Expand All @@ -2312,9 +2360,13 @@ static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
struct arm_smmu_device *smmu = dev_get_drvdata(dev);
int ret;

arm_smmu_icc_enable(smmu);

ret = clk_bulk_enable(smmu->num_clks, smmu->clks);
if (ret)
if (ret) {
arm_smmu_icc_disable(smmu);
return ret;
}

arm_smmu_device_reset(smmu);

Expand All @@ -2326,6 +2378,7 @@ static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
struct arm_smmu_device *smmu = dev_get_drvdata(dev);

clk_bulk_disable(smmu->num_clks, smmu->clks);
arm_smmu_icc_disable(smmu);

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/iommu/arm/arm-smmu/arm-smmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/io-64-nonatomic-hi-lo.h>
#include <linux/io-pgtable.h>
#include <linux/iommu.h>
Expand Down Expand Up @@ -335,6 +336,7 @@ struct arm_smmu_device {
int num_clks;
unsigned int *irqs;
struct clk_bulk_data *clks;
struct icc_path *icc_path;

spinlock_t global_sync_lock;

Expand Down