[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