[PATCH v2 09/12] iommu/exynos: add supoort for runtime pm and suspend/resume
KyongHo Cho
pullip.cho at samsung.com
Tue Nov 20 04:05:55 EST 2012
On Tue, Nov 20, 2012 at 5:03 PM, Prathyush K <prathyush at chromium.org> wrote:
> On Tue, Nov 20, 2012 at 1:00 PM, Cho KyongHo <pullip.cho at samsung.com>
wrote:
>>
>> This change enables the client device drivers not to care about
>> the state of System MMU since the internal state of System MMU
>> is controlled by the runtime PM and suspend/resume callback functions.
>>
>> Signed-off-by: KyongHo Cho <pullip.cho at samsung.com>
>> ---
>> drivers/iommu/exynos-iommu.c | 175
>> ++++++++++++++++++++++---------------------
>> 1 file changed, 89 insertions(+), 86 deletions(-)
>>
>> diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
>> index 8f9239c..169f56e 100644
>> --- a/drivers/iommu/exynos-iommu.c
>> +++ b/drivers/iommu/exynos-iommu.c
>> @@ -208,6 +208,7 @@ struct sysmmu_drvdata {
>> struct iommu_domain *domain;
>> sysmmu_fault_handler_t fault_handler;
>> unsigned long pgtable;
>> + bool runtime_active;
>> void __iomem *sfrbases[0];
>> };
>>
>> @@ -477,7 +478,8 @@ static bool __sysmmu_disable(struct sysmmu_drvdata
>> *drvdata)
>> drvdata->pgtable = 0;
>> drvdata->domain = NULL;
>>
>> - __sysmmu_disable_nocount(drvdata);
>> + if (drvdata->runtime_active)
>> + __sysmmu_disable_nocount(drvdata);
>>
>> dev_dbg(drvdata->sysmmu, "Disabled\n");
>> } else {
>> @@ -490,30 +492,6 @@ static bool __sysmmu_disable(struct sysmmu_drvdata
>> *drvdata)
>> return disabled;
>> }
>>
>> -static bool __exynos_sysmmu_disable(struct device *dev)
>> -{
>> - unsigned long flags;
>> - bool disabled = true;
>> - struct exynos_iommu_owner *owner = dev->archdata.iommu;
>> - struct device *sysmmu;
>> -
>> - BUG_ON(!has_sysmmu(dev));
>> -
>> - spin_lock_irqsave(&owner->lock, flags);
>> -
>> - /* Every call to __sysmmu_disable() must return same result */
>> - for_each_sysmmu(dev, sysmmu) {
>> - struct sysmmu_drvdata *drvdata = dev_get_drvdata(sysmmu);
>> - disabled = __sysmmu_disable(drvdata);
>> - if (disabled)
>> - drvdata->master = NULL;
>> - }
>> -
>> - spin_unlock_irqrestore(&owner->lock, flags);
>> -
>> - return disabled;
>> -}
>> -
>> static void __sysmmu_enable_nocount(struct sysmmu_drvdata *drvdata)
>> {
>> int i;
>> @@ -554,7 +532,8 @@ static int __sysmmu_enable(struct sysmmu_drvdata
>> *drvdata,
>> drvdata->pgtable = pgtable;
>> drvdata->domain = domain;
>>
>> - __sysmmu_enable_nocount(drvdata);
>> + if (drvdata->runtime_active)
>> + __sysmmu_enable_nocount(drvdata);
>>
>> dev_dbg(drvdata->sysmmu, "Enabled\n");
>> } else {
>> @@ -610,42 +589,31 @@ static int __exynos_sysmmu_enable(struct device
>> *dev, unsigned long pgtable,
>>
>> int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable)
>> {
>> - int ret;
>> - struct device *sysmmu;
>> -
>> BUG_ON(!memblock_is_memory(pgtable));
>>
>> - for_each_sysmmu(dev, sysmmu) {
>> - ret = pm_runtime_get_sync(sysmmu);
>> - if (ret < 0)
>> - break;
>> - }
>> -
>> - if (ret < 0) {
>> - struct device *start;
>> - for_each_sysmmu_until(dev, start, sysmmu)
>> - pm_runtime_put(start);
>> -
>> - return ret;
>> - }
>> -
>> - ret = __exynos_sysmmu_enable(dev, pgtable, NULL);
>> - if (ret < 0)
>> - for_each_sysmmu(dev, sysmmu)
>> - pm_runtime_put(sysmmu);
>> -
>> - return ret;
>> + return __exynos_sysmmu_enable(dev, pgtable, NULL);
>> }
>>
>> bool exynos_sysmmu_disable(struct device *dev)
>> {
>> - bool disabled;
>> + unsigned long flags;
>> + bool disabled = true;
>> + struct exynos_iommu_owner *owner = dev->archdata.iommu;
>> struct device *sysmmu;
>>
>> - disabled = __exynos_sysmmu_disable(dev);
>> + BUG_ON(!has_sysmmu(dev));
>>
>> - for_each_sysmmu(dev, sysmmu)
>> - pm_runtime_put(sysmmu);
>> + spin_lock_irqsave(&owner->lock, flags);
>> +
>> + /* Every call to __sysmmu_disable() must return same result */
>> + for_each_sysmmu(dev, sysmmu) {
>> + struct sysmmu_drvdata *drvdata = dev_get_drvdata(sysmmu);
>> + disabled = __sysmmu_disable(drvdata);
>> + if (disabled)
>> + drvdata->master = NULL;
>> + }
>> +
>> + spin_unlock_irqrestore(&owner->lock, flags);
>>
>> return disabled;
>> }
>> @@ -661,7 +629,8 @@ static void sysmmu_tlb_invalidate_entry(struct device
>> *dev, unsigned long iova)
>> data = dev_get_drvdata(sysmmu);
>>
>> spin_lock_irqsave(&data->lock, flags);
>> - if (is_sysmmu_active(data)) {
>> + if (is_sysmmu_active(data) &&
>> + data->runtime_active) {
>> int i;
>> for (i = 0; i < data->nsfrs; i++) {
>> if (sysmmu_block(data->sfrbases[i])) {
>> @@ -899,6 +868,7 @@ static int __init exynos_sysmmu_probe(struct
>> platform_device *pdev)
>>
>> ret = __sysmmu_setup(dev, data);
>> if (!ret) {
>> + data->runtime_active = !pm_runtime_enabled(dev);
>> data->sysmmu = dev;
>> spin_lock_init(&data->lock);
>>
>> @@ -911,6 +881,64 @@ static int __init exynos_sysmmu_probe(struct
>> platform_device *pdev)
>> return ret;
>> }
>>
>> +#ifdef CONFIG_PM_SLEEP
>> +static int sysmmu_suspend(struct device *dev)
>> +{
>> + struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);
>> + unsigned long flags;
>> + spin_lock_irqsave(&drvdata->lock, flags);
>> + if (is_sysmmu_active(drvdata) &&
>> + (!pm_runtime_enabled(dev) || drvdata->runtime_active))
>> + __sysmmu_disable_nocount(drvdata);
>> + spin_unlock_irqrestore(&drvdata->lock, flags);
>> + return 0;
>> +}
>> +
>> +static int sysmmu_resume(struct device *dev)
>> +{
>> + struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);
>> + unsigned long flags;
>> + spin_lock_irqsave(&drvdata->lock, flags);
>> + if (is_sysmmu_active(drvdata) &&
>> + (!pm_runtime_enabled(dev) || drvdata->runtime_active)) {
>> + __sysmmu_enable_nocount(drvdata);
>> + }
>> + spin_unlock_irqrestore(&drvdata->lock, flags);
>> + return 0;
>> +}
>> +#endif
>> +
>> +#ifdef CONFIG_PM_RUNTIME
>> +static int sysmmu_runtime_suspend(struct device *dev)
>> +{
>> + struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);
>> + unsigned long flags;
>> + spin_lock_irqsave(&drvdata->lock, flags);
>> + if (is_sysmmu_active(drvdata))
>> + __sysmmu_disable_nocount(drvdata);
>> + drvdata->runtime_active = false;
>> + spin_unlock_irqrestore(&drvdata->lock, flags);
>> + return 0;
>> +}
>> +
>> +static int sysmmu_runtime_resume(struct device *dev)
>> +{
>> + struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);
>> + unsigned long flags;
>> + spin_lock_irqsave(&drvdata->lock, flags);
>> + drvdata->runtime_active = true;
>> + if (is_sysmmu_active(drvdata))
>> + __sysmmu_enable_nocount(drvdata);
>> + spin_unlock_irqrestore(&drvdata->lock, flags);
>> + return 0;
>> +}
>> +#endif
>> +
>> +static const struct dev_pm_ops __pm_ops = {
>> + SET_SYSTEM_SLEEP_PM_OPS(sysmmu_suspend, sysmmu_resume)
>> + SET_RUNTIME_PM_OPS(sysmmu_runtime_resume, sysmmu_runtime_suspend,
>> NULL)
>
>
> The runtime PM ops are not set correctly. The suspend_fn should be first,
> followed
> by resume_fn as per SET_RUNTIME_PM_OPS.
>
> Thanks,
> Prathyush
>
Thank you.
I missed that. It will be fixed in the next version of this patch.
Cho KyongHo.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20121120/34a82256/attachment-0001.html>
More information about the linux-arm-kernel
mailing list