From 917f3e143a045cbbf23328cec292b7070b95a45a Mon Sep 17 00:00:00 2001 From: Jiankang Chen Date: Tue, 12 Nov 2019 10:02:10 +0800 Subject: [PATCH] driver/iommu/smmu-v3: Support smmu suspend/resume. ascend inclusion category: feature bugzilla: 14369 CVE: NA ------------------- Smmu need to reconfiguration when the device resumed. So must support smmu suspend/resume. Signed-off-by: Jiankang Chen Signed-off-by: Fang Lijun Signed-off-by: Chen Jun Reviewed-by: Hanjun Guo Signed-off-by: Yang Yingliang --- drivers/iommu/arm-smmu-v3.c | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index c2eff42f2bc1..4a0e5684731d 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -647,6 +647,10 @@ struct arm_smmu_device { struct mutex streams_mutex; struct iopf_queue *iopf_queue; + +#define ARM_SUMMU_STATE_BYPASS (1 << 0) +#define ARM_SUMMU_STATE_SUSPEND (1 << 1) + unsigned int state; }; struct arm_smmu_stream { @@ -3374,6 +3378,9 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) return ret; } + if (smmu->state & ARM_SUMMU_STATE_SUSPEND) + goto irq_requested; + irq = smmu->combined_irq; if (irq) { /* @@ -3393,6 +3400,7 @@ static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) if (smmu->features & ARM_SMMU_FEAT_PRI) irqen_flags |= IRQ_CTRL_PRIQ_IRQEN; +irq_requested: /* Enable interrupt generation on the SMMU */ ret = arm_smmu_write_reg_sync(smmu, irqen_flags, ARM_SMMU_IRQ_CTRL, ARM_SMMU_IRQ_CTRLACK); @@ -3939,6 +3947,9 @@ static int arm_smmu_device_probe(struct platform_device *pdev) /* Set bypass mode according to firmware probing result */ bypass = !!ret; + if (bypass) + smmu->state = smmu->state | ARM_SUMMU_STATE_BYPASS; + /* Base address */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (resource_size(res) + 1 < arm_smmu_resource_size(smmu)) { @@ -4054,10 +4065,47 @@ static const struct of_device_id arm_smmu_of_match[] = { }; MODULE_DEVICE_TABLE(of, arm_smmu_of_match); +#ifdef CONFIG_PM_SLEEP + +static int arm_smmu_suspend(struct device *dev) +{ + struct arm_smmu_device *smmu = dev_get_drvdata(dev); + + dev_info(smmu->dev, "smmu device is suspend\n"); + smmu->state = smmu->state | ARM_SUMMU_STATE_SUSPEND; + + return 0; +} + +static int arm_smmu_resume(struct device *dev) +{ + struct arm_smmu_device *smmu = dev_get_drvdata(dev); + + dev_info(smmu->dev, "smmu device is resumed\n"); + arm_smmu_device_reset(smmu, smmu->state & ARM_SUMMU_STATE_BYPASS); + smmu->state = smmu->state & ~ARM_SUMMU_STATE_SUSPEND; + + return 0; +} + +static const struct dev_pm_ops arm_smmu_pm_ops = { + .suspend = arm_smmu_suspend, + .resume = arm_smmu_resume, +}; + +#define ARM_SMMU_PM_OPS (&arm_smmu_pm_ops) + +#else + +#define ARM_SMMU_PM_OPS NULL + +#endif + static struct platform_driver arm_smmu_driver = { .driver = { .name = "arm-smmu-v3", .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, -- GitLab