Received: by 2002:ac0:a5a7:0:0:0:0:0 with SMTP id m36-v6csp7100233imm; Tue, 24 Jul 2018 08:23:00 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcRnUn3SmZIbgm5IWPQaSefDF7CiPgSYyXXTZcDsxd0yQxCpGefVGZEKpqXdiHIxqmJUwTQ X-Received: by 2002:a65:6110:: with SMTP id z16-v6mr17157503pgu.412.1532445780473; Tue, 24 Jul 2018 08:23:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1532445780; cv=none; d=google.com; s=arc-20160816; b=GkxbyvQ0i7JXEUg3Ojrgje60yJMDwDSNtPptu8LudtxpVWdxgWlGBg32bcjFudA4Kd XN1RhF5AH395X5DdWZOmGve4tj36xDOEOyXurRoaGDy96MePUjdoxSvIK+zI9CAbL2pS u2TgmO+fOic8QdclfJM9KsxzJ9Eo2sQ7HT1xj98V312et0knsNM+YnBQuqf6tYu5p0xh N5Ss/Bc5JM2jqbBoVD9gM9WnCCiwKd+R8mqKxcXG6wQwbHu0Ft+pRHK9cyboSCTcjbxI r04NGylQNISUUNN1IxrLixoa04WbSdK6zWbPRjseLwrZn9Q9dkxc1rKFs59MIqrcICi1 2dDw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:references:cc:to:subject:from:arc-authentication-results; bh=2aQJgwTRe8KWmCzU9Jx1UQ4EL4KhOd1cJVgIL68f708=; b=UbSO8foKtqiFROeCcvNzW2Cg1GJQ6f5nGDCrZVcw+1+35il6mmpliGyCLdWklIGytV tAAg7Qyn9STQd7sMqTnk8lOudaUvjbVcebpGfyYa/2E1LfAuXvpeTbpFuHJgIezwLOV9 OPgn15B1lO2mBIbMkiV6/ye5AHObRu7yHALWMWAKTeUuYXK7ImY+SXNbRqg6jHhXLK8D tSooUlzvEc8d6HqRQNPoTTQ/0r3yv3flE08pRGUUghg3oW7K/S1MDupDPkfBaFdHLSP+ +X6YT0qberoX6G7stgDJOohBVa9Mosk1zyyiQ2dgFo4WIJJxISMKUMPWnjcYIRFpsWyD 90Jw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q23-v6si11754971pgq.483.2018.07.24.08.22.45; Tue, 24 Jul 2018 08:23:00 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2388374AbeGXQ22 (ORCPT + 99 others); Tue, 24 Jul 2018 12:28:28 -0400 Received: from foss.arm.com ([217.140.101.70]:53766 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726857AbeGXQ22 (ORCPT ); Tue, 24 Jul 2018 12:28:28 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4DAC780D; Tue, 24 Jul 2018 08:21:29 -0700 (PDT) Received: from [10.4.12.131] (e110467-lin.emea.arm.com [10.4.12.131]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 10EAA3F237; Tue, 24 Jul 2018 08:21:25 -0700 (PDT) From: Robin Murphy Subject: Re: [PATCH v13 1/4] iommu/arm-smmu: Add pm_runtime/sleep ops To: Vivek Gautam , joro@8bytes.org, robh+dt@kernel.org, rjw@rjwysocki.net, will.deacon@arm.com, iommu@lists.linux-foundation.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: alex.williamson@redhat.com, mark.rutland@arm.com, robdclark@gmail.com, linux-pm@vger.kernel.org, freedreno@lists.freedesktop.org, sboyd@kernel.org, tfiga@chromium.org, jcrouse@codeaurora.org, sricharan@codeaurora.org, m.szyprowski@samsung.com, lukas@wunner.de, architt@codeaurora.org, linux-arm-msm@vger.kernel.org References: <20180719101539.6104-1-vivek.gautam@codeaurora.org> <20180719101539.6104-2-vivek.gautam@codeaurora.org> Message-ID: Date: Tue, 24 Jul 2018 16:21:24 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.9.1 MIME-Version: 1.0 In-Reply-To: <20180719101539.6104-2-vivek.gautam@codeaurora.org> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-GB Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 19/07/18 11:15, Vivek Gautam wrote: > From: Sricharan R > > 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. > > Also, while we enable the runtime pm add a pm sleep suspend > callback that pushes devices to low power state by turning > the clocks off in a system sleep. > Also add corresponding clock enable path in resume callback. > > Signed-off-by: Sricharan R > Signed-off-by: Archit Taneja > [vivek: rework for clock and pm ops] > Signed-off-by: Vivek Gautam > Reviewed-by: Tomasz Figa > --- > > Changes since v12: > - Added pm sleep .suspend callback. This disables the clocks. > - Added corresponding change to enable clocks in .resume > pm sleep callback. > > drivers/iommu/arm-smmu.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 73 insertions(+), 2 deletions(-) > > diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c > index c73cfce1ccc0..9138a6fffe04 100644 > --- a/drivers/iommu/arm-smmu.c > +++ b/drivers/iommu/arm-smmu.c > @@ -48,6 +48,7 @@ > #include > #include > #include > +#include > #include > #include > > @@ -205,6 +206,8 @@ struct arm_smmu_device { > u32 num_global_irqs; > u32 num_context_irqs; > unsigned int *irqs; > + struct clk_bulk_data *clks; > + int num_clks; > > u32 cavium_id_base; /* Specific to Cavium */ > > @@ -1897,10 +1900,12 @@ 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; > + const char * const *clks; > + int num_clks; > }; > > #define ARM_SMMU_MATCH_DATA(name, ver, imp) \ > -static struct arm_smmu_match_data name = { .version = ver, .model = imp } > +static const 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); > @@ -1919,6 +1924,23 @@ static const struct of_device_id arm_smmu_of_match[] = { > }; > MODULE_DEVICE_TABLE(of, arm_smmu_of_match); > > +static void arm_smmu_fill_clk_data(struct arm_smmu_device *smmu, > + const char * const *clks) > +{ > + int i; > + > + if (smmu->num_clks < 1) > + return; > + > + smmu->clks = devm_kcalloc(smmu->dev, smmu->num_clks, > + sizeof(*smmu->clks), GFP_KERNEL); > + if (!smmu->clks) > + return; > + > + for (i = 0; i < smmu->num_clks; i++) > + smmu->clks[i].id = clks[i]; > +} > + > #ifdef CONFIG_ACPI > static int acpi_smmu_get_data(u32 model, struct arm_smmu_device *smmu) > { > @@ -2001,6 +2023,9 @@ 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->num_clks = data->num_clks; > + > + arm_smmu_fill_clk_data(smmu, data->clks); > > parse_driver_options(smmu); > > @@ -2099,6 +2124,14 @@ static int arm_smmu_device_probe(struct platform_device *pdev) > smmu->irqs[i] = irq; > } > > + err = devm_clk_bulk_get(smmu->dev, smmu->num_clks, smmu->clks); > + if (err) > + return err; > + > + err = clk_bulk_prepare(smmu->num_clks, smmu->clks); > + if (err) > + return err; > + > err = arm_smmu_device_cfg_probe(smmu); > if (err) > return err; > @@ -2181,6 +2214,9 @@ 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); > + > + clk_bulk_unprepare(smmu->num_clks, smmu->clks); > + > return 0; > } > > @@ -2189,15 +2225,50 @@ static void arm_smmu_device_shutdown(struct platform_device *pdev) > arm_smmu_device_remove(pdev); > } > > +static int __maybe_unused arm_smmu_runtime_resume(struct device *dev) > +{ > + struct arm_smmu_device *smmu = dev_get_drvdata(dev); > + > + return clk_bulk_enable(smmu->num_clks, smmu->clks); If there's a power domain being automatically switched by genpd then we need a reset here because we may have lost state entirely. Since I remembered the otherwise-useless GPU SMMU on Juno is in a separate power domain, I gave it a poking via sysfs with some debug stuff to dump sCR0 in these callbacks, and the problem is clear: ... [ 4.625551] arm-smmu 2b400000.iommu: genpd_runtime_suspend() [ 4.631163] arm-smmu 2b400000.iommu: arm_smmu_runtime_suspend: 0x00201936 [ 4.637897] arm-smmu 2b400000.iommu: suspend latency exceeded, 6733980 ns [ 21.566983] arm-smmu 2b400000.iommu: genpd_runtime_resume() [ 21.584796] arm-smmu 2b400000.iommu: arm_smmu_runtime_resume: 0x00220101 [ 21.591452] arm-smmu 2b400000.iommu: resume latency exceeded, 6658020 ns ... > +} > + > +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); > + > + return 0; > +} > + > static int __maybe_unused arm_smmu_pm_resume(struct device *dev) > { > struct arm_smmu_device *smmu = dev_get_drvdata(dev); > + int ret; > + > + if (!pm_runtime_suspended(dev)) { > + ret = arm_smmu_runtime_resume(dev); > + if (ret) > + return ret; > + } > > arm_smmu_device_reset(smmu); This looks a bit off too - if we wake from sleep when the SMMU was also runtime-suspended, it appears we might end up trying to restore the register state without clocks enabled. Surely we need to always enable clocks for the reset, then restore the previous suspended state? Although given my previous point, it's probably not worth doing anything at all here for that case. Robin. > return 0; > } > > -static SIMPLE_DEV_PM_OPS(arm_smmu_pm_ops, NULL, arm_smmu_pm_resume); > +static int __maybe_unused arm_smmu_pm_suspend(struct device *dev) > +{ > + if (!pm_runtime_suspended(dev)) > + return arm_smmu_runtime_suspend(dev); > + > + return 0; > +} > + > +static const struct dev_pm_ops arm_smmu_pm_ops = { > + SET_SYSTEM_SLEEP_PM_OPS(arm_smmu_pm_suspend, arm_smmu_pm_resume) > + SET_RUNTIME_PM_OPS(arm_smmu_runtime_suspend, > + arm_smmu_runtime_resume, NULL) > +}; > > static struct platform_driver arm_smmu_driver = { > .driver = { >