<br><div class="gmail_extra"><br><br><div class="gmail_quote">On Tue, Nov 20, 2012 at 1:00 PM, Cho KyongHo <span dir="ltr"><<a href="mailto:pullip.cho@samsung.com" target="_blank">pullip.cho@samsung.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">This change enables the client device drivers not to care about<br>

the state of System MMU since the internal state of System MMU<br>
is controlled by the runtime PM and suspend/resume callback functions.<br>
<br>
Signed-off-by: KyongHo Cho <<a href="mailto:pullip.cho@samsung.com">pullip.cho@samsung.com</a>><br>
---<br>
 drivers/iommu/exynos-iommu.c | 175 ++++++++++++++++++++++---------------------<br>
 1 file changed, 89 insertions(+), 86 deletions(-)<br>
<br>
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c<br>
index 8f9239c..169f56e 100644<br>
--- a/drivers/iommu/exynos-iommu.c<br>
+++ b/drivers/iommu/exynos-iommu.c<br>
@@ -208,6 +208,7 @@ struct sysmmu_drvdata {<br>
        struct iommu_domain *domain;<br>
        sysmmu_fault_handler_t fault_handler;<br>
        unsigned long pgtable;<br>
+       bool runtime_active;<br>
        void __iomem *sfrbases[0];<br>
 };<br>
<br>
@@ -477,7 +478,8 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *drvdata)<br>
                drvdata->pgtable = 0;<br>
                drvdata->domain = NULL;<br>
<br>
-               __sysmmu_disable_nocount(drvdata);<br>
+               if (drvdata->runtime_active)<br>
+                       __sysmmu_disable_nocount(drvdata);<br>
<br>
                dev_dbg(drvdata->sysmmu, "Disabled\n");<br>
        } else  {<br>
@@ -490,30 +492,6 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *drvdata)<br>
        return disabled;<br>
 }<br>
<br>
-static bool __exynos_sysmmu_disable(struct device *dev)<br>
-{<br>
-       unsigned long flags;<br>
-       bool disabled = true;<br>
-       struct exynos_iommu_owner *owner = dev->archdata.iommu;<br>
-       struct device *sysmmu;<br>
-<br>
-       BUG_ON(!has_sysmmu(dev));<br>
-<br>
-       spin_lock_irqsave(&owner->lock, flags);<br>
-<br>
-       /* Every call to __sysmmu_disable() must return same result */<br>
-       for_each_sysmmu(dev, sysmmu) {<br>
-               struct sysmmu_drvdata *drvdata = dev_get_drvdata(sysmmu);<br>
-               disabled = __sysmmu_disable(drvdata);<br>
-               if (disabled)<br>
-                       drvdata->master = NULL;<br>
-       }<br>
-<br>
-       spin_unlock_irqrestore(&owner->lock, flags);<br>
-<br>
-       return disabled;<br>
-}<br>
-<br>
 static void __sysmmu_enable_nocount(struct sysmmu_drvdata *drvdata)<br>
 {<br>
        int i;<br>
@@ -554,7 +532,8 @@ static int __sysmmu_enable(struct sysmmu_drvdata *drvdata,<br>
                drvdata->pgtable = pgtable;<br>
                drvdata->domain = domain;<br>
<br>
-               __sysmmu_enable_nocount(drvdata);<br>
+               if (drvdata->runtime_active)<br>
+                       __sysmmu_enable_nocount(drvdata);<br>
<br>
                dev_dbg(drvdata->sysmmu, "Enabled\n");<br>
        } else {<br>
@@ -610,42 +589,31 @@ static int __exynos_sysmmu_enable(struct device *dev, unsigned long pgtable,<br>
<br>
 int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable)<br>
 {<br>
-       int ret;<br>
-       struct device *sysmmu;<br>
-<br>
        BUG_ON(!memblock_is_memory(pgtable));<br>
<br>
-       for_each_sysmmu(dev, sysmmu) {<br>
-               ret = pm_runtime_get_sync(sysmmu);<br>
-               if (ret < 0)<br>
-                       break;<br>
-       }<br>
-<br>
-       if (ret < 0) {<br>
-               struct device *start;<br>
-               for_each_sysmmu_until(dev, start, sysmmu)<br>
-                       pm_runtime_put(start);<br>
-<br>
-               return ret;<br>
-       }<br>
-<br>
-       ret = __exynos_sysmmu_enable(dev, pgtable, NULL);<br>
-       if (ret < 0)<br>
-               for_each_sysmmu(dev, sysmmu)<br>
-                       pm_runtime_put(sysmmu);<br>
-<br>
-       return ret;<br>
+       return __exynos_sysmmu_enable(dev, pgtable, NULL);<br>
 }<br>
<br>
 bool exynos_sysmmu_disable(struct device *dev)<br>
 {<br>
-       bool disabled;<br>
+       unsigned long flags;<br>
+       bool disabled = true;<br>
+       struct exynos_iommu_owner *owner = dev->archdata.iommu;<br>
        struct device *sysmmu;<br>
<br>
-       disabled = __exynos_sysmmu_disable(dev);<br>
+       BUG_ON(!has_sysmmu(dev));<br>
<br>
-       for_each_sysmmu(dev, sysmmu)<br>
-               pm_runtime_put(sysmmu);<br>
+       spin_lock_irqsave(&owner->lock, flags);<br>
+<br>
+       /* Every call to __sysmmu_disable() must return same result */<br>
+       for_each_sysmmu(dev, sysmmu) {<br>
+               struct sysmmu_drvdata *drvdata = dev_get_drvdata(sysmmu);<br>
+               disabled = __sysmmu_disable(drvdata);<br>
+               if (disabled)<br>
+                       drvdata->master = NULL;<br>
+       }<br>
+<br>
+       spin_unlock_irqrestore(&owner->lock, flags);<br>
<br>
        return disabled;<br>
 }<br>
@@ -661,7 +629,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)<br>
                data = dev_get_drvdata(sysmmu);<br>
<br>
                spin_lock_irqsave(&data->lock, flags);<br>
-               if (is_sysmmu_active(data)) {<br>
+               if (is_sysmmu_active(data) &&<br>
+                               data->runtime_active) {<br>
                        int i;<br>
                        for (i = 0; i < data->nsfrs; i++) {<br>
                                if (sysmmu_block(data->sfrbases[i])) {<br>
@@ -899,6 +868,7 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev)<br>
<br>
        ret = __sysmmu_setup(dev, data);<br>
        if (!ret) {<br>
+               data->runtime_active = !pm_runtime_enabled(dev);<br>
                data->sysmmu = dev;<br>
                spin_lock_init(&data->lock);<br>
<br>
@@ -911,6 +881,64 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev)<br>
        return ret;<br>
 }<br>
<br>
+#ifdef CONFIG_PM_SLEEP<br>
+static int sysmmu_suspend(struct device *dev)<br>
+{<br>
+       struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);<br>
+       unsigned long flags;<br>
+       spin_lock_irqsave(&drvdata->lock, flags);<br>
+       if (is_sysmmu_active(drvdata) &&<br>
+               (!pm_runtime_enabled(dev) || drvdata->runtime_active))<br>
+               __sysmmu_disable_nocount(drvdata);<br>
+       spin_unlock_irqrestore(&drvdata->lock, flags);<br>
+       return 0;<br>
+}<br>
+<br>
+static int sysmmu_resume(struct device *dev)<br>
+{<br>
+       struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);<br>
+       unsigned long flags;<br>
+       spin_lock_irqsave(&drvdata->lock, flags);<br>
+       if (is_sysmmu_active(drvdata) &&<br>
+               (!pm_runtime_enabled(dev) || drvdata->runtime_active)) {<br>
+               __sysmmu_enable_nocount(drvdata);<br>
+       }<br>
+       spin_unlock_irqrestore(&drvdata->lock, flags);<br>
+       return 0;<br>
+}<br>
+#endif<br>
+<br>
+#ifdef CONFIG_PM_RUNTIME<br>
+static int sysmmu_runtime_suspend(struct device *dev)<br>
+{<br>
+       struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);<br>
+       unsigned long flags;<br>
+       spin_lock_irqsave(&drvdata->lock, flags);<br>
+       if (is_sysmmu_active(drvdata))<br>
+               __sysmmu_disable_nocount(drvdata);<br>
+       drvdata->runtime_active = false;<br>
+       spin_unlock_irqrestore(&drvdata->lock, flags);<br>
+       return 0;<br>
+}<br>
+<br>
+static int sysmmu_runtime_resume(struct device *dev)<br>
+{<br>
+       struct sysmmu_drvdata *drvdata = dev_get_drvdata(dev);<br>
+       unsigned long flags;<br>
+       spin_lock_irqsave(&drvdata->lock, flags);<br>
+       drvdata->runtime_active = true;<br>
+       if (is_sysmmu_active(drvdata))<br>
+               __sysmmu_enable_nocount(drvdata);<br>
+       spin_unlock_irqrestore(&drvdata->lock, flags);<br>
+       return 0;<br>
+}<br>
+#endif<br>
+<br>
+static const struct dev_pm_ops __pm_ops = {<br>
+       SET_SYSTEM_SLEEP_PM_OPS(sysmmu_suspend, sysmmu_resume)<br>
+       SET_RUNTIME_PM_OPS(sysmmu_runtime_resume, sysmmu_runtime_suspend, NULL)<br></blockquote><div><br></div><div><div>The runtime PM ops are not set correctly. The suspend_fn should be first, followed</div><div>by resume_fn as per SET_RUNTIME_PM_OPS.</div>
<div><br></div><div>Thanks,</div><div>Prathyush</div></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

+};<br>
+<br>
 /*<br>
  * Descriptions of Device Tree node for System MMU<br>
  *<br>
@@ -948,6 +976,7 @@ static struct platform_driver exynos_sysmmu_driver __refdata = {<br>
        .driver         = {<br>
                .owner          = THIS_MODULE,<br>
                .name           = "exynos-sysmmu",<br>
+               .pm             = &__pm_ops,<br>
                .of_match_table = of_match_ptr(sysmmu_of_match),<br>
        }<br>
 };<br>
@@ -1009,13 +1038,9 @@ static void exynos_iommu_domain_destroy(struct iommu_domain *domain)<br>
        spin_lock_irqsave(&priv->lock, flags);<br>
<br>
        list_for_each_entry_safe(owner, n, &priv->clients, client) {<br>
-               struct device *sysmmu;<br>
-               while (!__exynos_sysmmu_disable(owner->dev))<br>
+               while (!exynos_sysmmu_disable(owner->dev))<br>
                        ; /* until System MMU is actually disabled */<br>
                list_del_init(&owner->client);<br>
-<br>
-               for_each_sysmmu(owner->dev, sysmmu)<br>
-                       pm_runtime_put(sysmmu);<br>
        }<br>
<br>
        spin_unlock_irqrestore(&priv->lock, flags);<br>
@@ -1038,7 +1063,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain,<br>
        struct exynos_iommu_domain *priv = domain->priv;<br>
        unsigned long flags;<br>
        int ret;<br>
-       struct device *sysmmu;<br>
<br>
        if (WARN_ON(!list_empty(&owner->client))) {<br>
                bool found = false;<br>
@@ -1063,20 +1087,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain,<br>
                return 0;<br>
        }<br>
<br>
-       for_each_sysmmu(dev, sysmmu) {<br>
-               ret = pm_runtime_get_sync(sysmmu);<br>
-               if (ret < 0)<br>
-                       break;<br>
-       }<br>
-<br>
-       if (ret < 0) {<br>
-               struct device *start;<br>
-               for_each_sysmmu_until(dev, start, sysmmu)<br>
-                       pm_runtime_put(start);<br>
-<br>
-               return ret;<br>
-       }<br>
-<br>
        spin_lock_irqsave(&priv->lock, flags);<br>
<br>
        ret = __exynos_sysmmu_enable(dev, __pa(priv->pgtable), domain);<br>
@@ -1091,15 +1101,12 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain,<br>
<br>
        spin_unlock_irqrestore(&priv->lock, flags);<br>
<br>
-       if (ret < 0) {<br>
+       if (ret < 0)<br>
                dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n",<br>
                                __func__, __pa(priv->pgtable));<br>
-               for_each_sysmmu(dev, sysmmu)<br>
-                       pm_runtime_put(sysmmu);<br>
-       } else {<br>
+       else<br>
                dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n",<br>
                                        __func__, __pa(priv->pgtable));<br>
-       }<br>
<br>
        return ret;<br>
 }<br>
@@ -1115,7 +1122,7 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain,<br>
<br>
        list_for_each_entry_safe(owner, n, &priv->clients, client) {<br>
                if (owner == dev->archdata.iommu) {<br>
-                       if (__exynos_sysmmu_disable(dev))<br>
+                       if (exynos_sysmmu_disable(dev))<br>
                                list_del_init(&owner->client);<br>
                        else<br>
                                BUG();<br>
@@ -1125,14 +1132,10 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain,<br>
<br>
        spin_unlock_irqrestore(&priv->lock, flags);<br>
<br>
-       if (owner == dev->archdata.iommu) {<br>
-               struct device *sysmmu;<br>
+       if (owner == dev->archdata.iommu)<br>
                dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n",<br>
                                        __func__, __pa(priv->pgtable));<br>
-               for_each_sysmmu(dev, sysmmu)<br>
-                       pm_runtime_put(sysmmu);<br>
-<br>
-       } else<br>
+       else<br>
                dev_dbg(dev, "%s: No IOMMU is attached\n", __func__);<br>
 }<br>
<span class=""><font color="#888888"><br>
--<br>
1.8.0<br>
<br>
<br>
_______________________________________________<br>
iommu mailing list<br>
<a href="mailto:iommu@lists.linux-foundation.org">iommu@lists.linux-foundation.org</a><br>
<a href="https://lists.linuxfoundation.org/mailman/listinfo/iommu" target="_blank">https://lists.linuxfoundation.org/mailman/listinfo/iommu</a><br>
</font></span></blockquote></div><br></div>