From patchwork Wed Nov 21 05:07:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cho KyongHo X-Patchwork-Id: 1778161 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id BC41A3FCAE for ; Wed, 21 Nov 2012 05:09:43 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tb2Wm-0004pT-VK; Wed, 21 Nov 2012 05:07:13 +0000 Received: from mailout3.samsung.com ([203.254.224.33]) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tb2Wc-0004lP-Pl for linux-arm-kernel@lists.infradead.org; Wed, 21 Nov 2012 05:07:05 +0000 Received: from epcpsbgm2.samsung.com (epcpsbgm2 [203.254.230.27]) by mailout3.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0MDT008JNNHH2BM0@mailout3.samsung.com> for linux-arm-kernel@lists.infradead.org; Wed, 21 Nov 2012 14:07:01 +0900 (KST) Received: from epcpsbgm2.samsung.com ( [203.254.230.49]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id A5.4A.12699.5716CA05; Wed, 21 Nov 2012 14:07:01 +0900 (KST) X-AuditID: cbfee61b-b7f616d00000319b-e3-50ac6175bbcd Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm2.samsung.com (EPCPMTA) with SMTP id 74.4A.12699.5716CA05; Wed, 21 Nov 2012 14:07:01 +0900 (KST) Received: from DOPULLIPCHO06 ([12.23.118.152]) by mmp2.samsung.com (Oracle Communications Messaging Server 7u4-24.01 (7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0MDT00NMPNJP1F90@mmp2.samsung.com> for linux-arm-kernel@lists.infradead.org; Wed, 21 Nov 2012 14:07:01 +0900 (KST) From: Cho KyongHo To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, iommu@lists.linux-foundation.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 09/12] iommu/exynos: add supoort for runtime pm and suspend/resume Date: Wed, 21 Nov 2012 14:07:01 +0900 Message-id: <003001cdc7a6$0a571470$1f053d50$%cho@samsung.com> MIME-version: 1.0 X-Mailer: Microsoft Office Outlook 12.0 Thread-index: Ac3Hpgo2U4ZZsjbJRZKw9ccPSVfuLQ== Content-language: ko DLP-Filter: Pass X-MTR: 20000000000000000@CPGS X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrPIsWRmVeSWpSXmKPExsVy+t8zQ93SxDUBBismmlpsenyN1YHRY/OS +gDGKC6blNSczLLUIn27BK6Mwyfvsxacca94+2srewPjR6suRk4OCQETiebJf1ghbDGJC/fW s3UxcnEICSxjlDjet5QFpuhHey87RGI6o8SzvT+hqpYzSTRPbWcGqWIT0JJYPfc4I0hCRKCX UeJC/1cmEIdZ4AejxOI3b8CqhAXCJS7uawNayMHBIqAqseCgIYjJK2Ar8eutBUgFr4CgxI/J 98A2MwPNXL/zOBOELS+xec1bZpByCQF1iUd/dUHCIgJ6Et3/LkOVi0jse/GOEcRmERCQ+Db5 EAtEuazEpgPMIMdICPSzS6z/d5IR4jFJiYMrbrBMYBSbhWTzLCSbZyHZPAvJigWMLKsYRVML kguKk9JzjfSKE3OLS/PS9ZLzczcxQmJFegfjqgaLQ4wCHIxKPLwS+1YHCLEmlhVX5h5ilOBg VhLhZZBfEyDEm5JYWZValB9fVJqTWnyI0Qfo8onMUqLJ+cA4ziuJNzQ2NjEzMTUxtzQ1N8Uh rCTO2+yREiAkkJ5YkpqdmlqQWgQzjomDU6qBsXDdLzXb+eLJbf9X7NFJjwtWnnryU17yUU55 /0m38py81s1cuCf35OM8Kc69F6f9ZFU9PP9z+Kvvl09vn3dxWX476/KUzS3PKtteHJfh0Vpf pJjToPcic/dDX1vZj2uzN4pZiV/4X2d8cNexe8U7bl//lh3Aw7ql6uQbKwb1l4dvht17LtaS JqnEUpyRaKjFXFScCAAPT4EJwgIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrHIsWRmVeSWpSXmKPExsVy+t9jQd3SxDUBButvG1hsenyN1YHRY/OS +gDGqAZGm4zUxJTUIoXUvOT8lMy8dFsl7+B453hTMwNDXUNLC3MlhbzE3FRbJRefAF23zByg qUoKZYk5pUChgMTiYiV9O0wTQkPcdC1gGiN0fUOC4HqMDNBAwjrGjMMn77MWnHGvePtrK3sD 40erLkZODgkBE4kf7b3sELaYxIV769m6GLk4hASmM0o82/sTylnOJNE8tZ0ZpIpNQEti9dzj jCAJEYFeRokL/V+ZQBxmgR+MEovfvAGrEhYIl7i4r421i5GDg0VAVWLBQUMQk1fAVuLXWwuQ Cl4BQYkfk++xgNjMQDPX7zzOBGHLS2xe85YZpFxCQF3i0V9dkLCIgJ5E97/LUOUiEvtevGOc wCgwC8mkWUgmzUIyaRaSlgWMLKsYRVMLkguKk9JzjfSKE3OLS/PS9ZLzczcxgiPxmfQOxlUN FocYBTgYlXh4JfatDhBiTSwrrsw9xCjBwawkwssgvyZAiDclsbIqtSg/vqg0J7X4EKMP0JsT maVEk/OBSSKvJN7Q2MTMyNLIzMLIxNwch7CSOG+zR0qAkEB6YklqdmpqQWoRzDgmDk6pBsb2 Ug7T0i6XJ8e81rIccc24FnJx93R3F9snX88edwj6KT2l63zu1+3LWnzvFm582nih2r+90n09 k//Po1N8NqfWel/e6WR6bl39hadXN7X06/W9zDjfFL83LGQWQ7q+/EH3H3vXH7QQsmRh0PrQ cFw8xc6PMf6bi71lzAqeYxVPL7TOPsI9ZYcSS3FGoqEWc1FxIgAO2+J/8QIAAA== X-CFilter-Loop: Reflected X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121121_000703_511808_1CBFE428 X-CRM114-Status: GOOD ( 16.89 ) X-Spam-Score: -7.5 (-------) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-7.5 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [203.254.224.33 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.1 HDRS_LCASE Odd capitalization of message header 0.0 T_MANY_HDRS_LCASE Odd capitalization of multiple message headers Cc: 'Kukjin Kim' , prathyush.k@samsung.com, 'Joerg Roedel' , sw0312.kim@samsung.com, 'Subash Patel' , 'Sanghyun Lee' , rahul.sharma@samsung.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org 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. Change-Id: Ic04c8f259d8b8af2846175dd7b98dbc4e463c96e Signed-off-by: KyongHo Cho --- 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 f7dff54..8d95505 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])) { @@ -893,6 +862,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); @@ -907,6 +877,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_suspend, sysmmu_runtime_resume, NULL) +}; + /* * Descriptions of Device Tree node for System MMU * @@ -944,6 +972,7 @@ static struct platform_driver exynos_sysmmu_driver __refdata = { .driver = { .owner = THIS_MODULE, .name = "exynos-sysmmu", + .pm = &__pm_ops, .of_match_table = of_match_ptr(sysmmu_of_match), } }; @@ -1005,13 +1034,9 @@ static void exynos_iommu_domain_destroy(struct iommu_domain *domain) spin_lock_irqsave(&priv->lock, flags); list_for_each_entry_safe(owner, n, &priv->clients, client) { - struct device *sysmmu; - while (!__exynos_sysmmu_disable(owner->dev)) + while (!exynos_sysmmu_disable(owner->dev)) ; /* until System MMU is actually disabled */ list_del_init(&owner->client); - - for_each_sysmmu(owner->dev, sysmmu) - pm_runtime_put(sysmmu); } spin_unlock_irqrestore(&priv->lock, flags); @@ -1034,7 +1059,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain, struct exynos_iommu_domain *priv = domain->priv; unsigned long flags; int ret; - struct device *sysmmu; if (WARN_ON(!list_empty(&owner->client))) { bool found = false; @@ -1059,20 +1083,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain, return 0; } - 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; - } - spin_lock_irqsave(&priv->lock, flags); ret = __exynos_sysmmu_enable(dev, __pa(priv->pgtable), domain); @@ -1087,15 +1097,12 @@ static int exynos_iommu_attach_device(struct iommu_domain *domain, spin_unlock_irqrestore(&priv->lock, flags); - if (ret < 0) { + if (ret < 0) dev_err(dev, "%s: Failed to attach IOMMU with pgtable %#lx\n", __func__, __pa(priv->pgtable)); - for_each_sysmmu(dev, sysmmu) - pm_runtime_put(sysmmu); - } else { + else dev_dbg(dev, "%s: Attached new IOMMU with pgtable 0x%lx\n", __func__, __pa(priv->pgtable)); - } return ret; } @@ -1111,7 +1118,7 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain, list_for_each_entry_safe(owner, n, &priv->clients, client) { if (owner == dev->archdata.iommu) { - if (__exynos_sysmmu_disable(dev)) + if (exynos_sysmmu_disable(dev)) list_del_init(&owner->client); else BUG(); @@ -1121,14 +1128,10 @@ static void exynos_iommu_detach_device(struct iommu_domain *domain, spin_unlock_irqrestore(&priv->lock, flags); - if (owner == dev->archdata.iommu) { - struct device *sysmmu; + if (owner == dev->archdata.iommu) dev_dbg(dev, "%s: Detached IOMMU with pgtable %#lx\n", __func__, __pa(priv->pgtable)); - for_each_sysmmu(dev, sysmmu) - pm_runtime_put(sysmmu); - - } else + else dev_dbg(dev, "%s: No IOMMU is attached\n", __func__); }