From patchwork Thu Dec 22 12:11:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 88854 Delivered-To: patch@linaro.org Received: by 10.140.20.101 with SMTP id 92csp2770827qgi; Thu, 22 Dec 2016 04:12:06 -0800 (PST) X-Received: by 10.98.112.3 with SMTP id l3mr1773536pfc.87.1482408726769; Thu, 22 Dec 2016 04:12:06 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m136si30534774pga.237.2016.12.22.04.12.06; Thu, 22 Dec 2016 04:12:06 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-pm-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-pm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-pm-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S938829AbcLVMME (ORCPT + 13 others); Thu, 22 Dec 2016 07:12:04 -0500 Received: from mailout2.samsung.com ([203.254.224.25]:45461 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S938786AbcLVMMB (ORCPT ); Thu, 22 Dec 2016 07:12:01 -0500 Received: from epcas1p3.samsung.com (unknown [182.195.41.47]) by mailout2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0OIL00PPV5VZ84B0@mailout2.samsung.com>; Thu, 22 Dec 2016 21:11:59 +0900 (KST) Received: from epsmges1p8.samsung.com (unknown [182.195.42.60]) by epcas1p2.samsung.com (KnoxPortal) with ESMTP id 20161222121159epcas1p234b863cb680d1b23780e554d5b452ac8~SkuBVWDDg1834818348epcas1p2G; Thu, 22 Dec 2016 12:11:59 +0000 (GMT) Received: from epcas1p2.samsung.com ( [182.195.41.46]) by epsmges1p8.samsung.com (Symantec Messaging Gateway) with SMTP id A6.93.19842.F03CB585; Thu, 22 Dec 2016 21:11:59 +0900 (KST) Received: from epcpsbgm1new.samsung.com (u26.gpu120.samsung.co.kr [203.254.230.26]) by epcas1p2.samsung.com (KnoxPortal) with ESMTP id 20161222121159epcas1p2e64486c51ae3b824f35ffb082d04f178~SkuBE-gks1629716297epcas1p2u; Thu, 22 Dec 2016 12:11:59 +0000 (GMT) X-AuditID: b6c32a3c-f79646d000004d82-cd-585bc30fc3de Received: from epmmp2 ( [203.254.227.17]) by epcpsbgm1new.samsung.com (EPCPMTA) with SMTP id 69.A8.28252.F03CB585; Thu, 22 Dec 2016 21:11:59 +0900 (KST) Received: from AMDC2765.digital.local ([106.116.147.25]) by mmp2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0OIL007QI5VFOVA0@mmp2.samsung.com>; Thu, 22 Dec 2016 21:11:59 +0900 (KST) From: Marek Szyprowski To: linux-samsung-soc@vger.kernel.org, dmaengine@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org Cc: Marek Szyprowski , Krzysztof Kozlowski , Bartlomiej Zolnierkiewicz , Vinod Koul , Ulf Hansson , "Rafael J. Wysocki" , Inki Dae Subject: [PATCH 3/3] dmaengine: pl330: Don't require irq-safe runtime PM Date: Thu, 22 Dec 2016 13:11:29 +0100 Message-id: <1482408689-21971-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.1 In-reply-to: <1482408689-21971-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrOIsWRmVeSWpSXmKPExsWy7bCmni7/4egIgx935C02zljParF66l9W i0n3J7BYnD+/gd1i0+NrrBafe48wWsw4v4/JYu2Ru+wWZ05fYrU4vjbc4mXffhYHbo/Fe14y eWxa1cnmcefaHjaPzUvqPbZcbWfx6NuyitHj8ya5APYoLpuU1JzMstQifbsErowLR7YyFayO rJiyT7qB8btnFyMnh4SAiUTr1Q+MELaYxIV769m6GLk4hAR2MErsObKYBcJpZ5JYM/8gO0zH mhk9zBCJOYwSD/ZNYoRwfjFKTNq7CmwWm4ChRNfbLrBZIgJNjBJv5y8Hq2IWWMoksbn9Jdgs YQEPictrF7KA2CwCqhLvt15hA7F5geIzj3WxQuyTkzh5bDKQzcHBKeApsei7EsgcCYF57BKb bj1nAolLCMhKbDrADFHuIjG/fSkThC0s8er4FqizpSVW/bsFFe9nlGhq1YawZzBKnHvLC2Fb Sxw+fhFsLbMAn8S7rz2sEON5JTrahCBKPCTWHW6HWuUosfPvPBZ4SMyavJ9lAqPMAkaGVYxi qQXFuempxYYFFnrFibnFpXnpesn5uZsYwdGvZbOD8dI5n0OMAhyMSjy8DlOiIoRYE8uKK3MP MUpwMCuJ8OYeiI4Q4k1JrKxKLcqPLyrNSS0+xCjNwaIkzrus0TpCSCA9sSQ1OzW1ILUIJsvE wSnVwBjwbOobveWbqwVqK869c03UEf6kkm+38USY4f1jKcc26Ram1G/iZl3049xEzu0mwcsL ooKWsZz9/LfP1SXK+3fCm0OdVyb6nDzO7s0icjHu6qrqOr6s1pdZzndtv97W4tu/4ELBdpay S5f1+DveVX1+tuvRjT/OfZ5xJ6PfN1sL6hffrz7w6pQSS3FGoqEWc1FxIgCCPAIq+gIAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupgkeLIzCtJLcpLzFFi42I5/e+xoC7/4egIg+0N/BYbZ6xntVg99S+r xaT7E1gszp/fwG6x6fE1VovPvUcYLWac38dksfbIXXaLM6cvsVocXxtu8bJvP4sDt8fiPS+Z PDat6mTzuHNtD5vH5iX1HluutrN49G1ZxejxeZNcAHuUm01GamJKapFCal5yfkpmXrqtUmiI m66FkkJeYm6qrVKErm9IkJJCWWJOKZBnZIAGHJwD3IOV9O0S3DIuHNnKVLA6smLKPukGxu+e XYycHBICJhJrZvQwQ9hiEhfurWfrYuTiEBKYxSjRcf4GO4Tzi1FiwurNbCBVbAKGEl1vu8Bs EYEmRomDvzxAipgFljNJbJl+gR0kISzgIXF57UIWEJtFQFXi/dYrYA28QPGZx7pYIdbJSZw8 NhnI5uDgFPCUWPRdCSQsBFSydOccxgmMvAsYGVYxSqQWJBcUJ6XnGuallusVJ+YWl+al6yXn 525iBMfCM6kdjAd3uR9iFOBgVOLh/fEqKkKINbGsuDL3EKMEB7OSCG/ugegIId6UxMqq1KL8 +KLSnNTiQ4ymQHdNZJYSTc4HxmleSbyhibmJubGBhbmlpYmRkjhv4+xn4UIC6YklqdmpqQWp RTB9TBycUg2MRWc1VjAcNd/8hufMZqPVExS605e+NbJguLZ5+5tDF2o8RFPrhcMe5TY+Oy/P 9t70ypkPRlwX3+ziKD0d/m2fZ8h585T8P3p3dWSjfaZlxX14m3V1ak3Glo33Hud2LRU43WYt Yh0i/P6bTM1vD9GZJ63388o4e87Ueppa6Hz06vHnxaaPq3sSlFiKMxINtZiLihMBN/EvoZsC AAA= X-MTR: 20000000000000000@CPGS X-CMS-MailID: 20161222121159epcas1p2e64486c51ae3b824f35ffb082d04f178 X-Msg-Generator: CA X-Sender-IP: 203.254.230.26 X-Local-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRs=?= =?UTF-8?B?7IK87ISx7KCE7J6QG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Global-Sender: =?UTF-8?B?TWFyZWsgU3p5cHJvd3NraRtTUlBPTC1LZXJuZWwgKFRQKRtT?= =?UTF-8?B?YW1zdW5nIEVsZWN0cm9uaWNzG1NlbmlvciBTb2Z0d2FyZSBFbmdpbmVlcg==?= X-Sender-Code: =?UTF-8?B?QzEwG0VIURtDMTBDRDAyQ0QwMjczOTI=?= CMS-TYPE: 101P X-HopCount: 7 X-CMS-RootMailID: 20161222121159epcas1p2e64486c51ae3b824f35ffb082d04f178 X-RootMTR: 20161222121159epcas1p2e64486c51ae3b824f35ffb082d04f178 References: <1482408689-21971-1-git-send-email-m.szyprowski@samsung.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org This patch replaces irq-safe runtime pm with non-irq-safe version. Till now non-irq-safe runtime PM implementation was only possible by calling pm_runtime_get/put functions from alloc/free_chan_resources. All other DMA engine API functions cannot be called from a context, which allows sleeping. Such implementation in practice resulted in keeping PL330 DMA controller device active almost all the time, because most of the slave device drivers (DMA engine clients) acquired DMA channel in their probe() function and released it during driver removal. This patch provides a new approach. The main assumption for it is an observation that there can be only one slave device using each DMA channel. Using recently introduced device dependencies (links) infrastructure one can ensure proper runtime PM state of PL330 DMA controller. In this approach in pl330_alloc_chan_resources() function a new dependency is being created between PL330 DMA controller device (as supplier) and given slave device (as consumer). This way PL330 DMA controller device runtime active counter is increased when the slave device is resumed and decreased the same time when given slave device is put to suspend. This way it has been ensured to keep PL330 DMA controller runtime active if there is an active used of any of its DMA channels. Slave device pointer is initially stored in per-channel data in of_dma_xlate callback. This is similar to what has been already implemented in Exynos IOMMU driver in commit 2f5f44f205cc958b ("iommu/exynos: Use device dependency links to control runtime pm"). If one requests memory-to-memory chanel, runtime active counter is increased unconditionally. This might be a drawback of this approach, but PL330 is not really used for memory-to-memory operations due to poor performance in such operations compared to CPU. Introducing non-irq-safe runtime power management finally allows to turn audio power domain off on Exynos5 SoCs. Removal of irq-safe runtime pm is based on the revert of the following commits: 1. "dmaengine: pl330: fix runtime pm support" commit 2. "dmaengine: pl330: Fix hang on dmaengine_terminate_all on certain boards" commit 81cc6edc08705ac0146fe6ac14a0982a31ce6f3d 3. "ARM: 8202/1: dmaengine: pl330: Add runtime Power Management support v12" commit ae43b3289186480f81c78bb63d788a85a3631f47 Signed-off-by: Marek Szyprowski --- drivers/dma/pl330.c | 133 +++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 63 deletions(-) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 3c80e71..2cffbb4 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -268,9 +268,6 @@ enum pl330_byteswap { #define NR_DEFAULT_DESC 16 -/* Delay for runtime PM autosuspend, ms */ -#define PL330_AUTOSUSPEND_DELAY 20 - /* Populated by the PL330 core driver for DMA API driver's info */ struct pl330_config { u32 periph_id; @@ -449,7 +446,8 @@ struct dma_pl330_chan { bool cyclic; /* for runtime pm tracking */ - bool active; + struct device *slave; + struct device_link *slave_link; }; struct pl330_dmac { @@ -2015,7 +2013,6 @@ static void pl330_tasklet(unsigned long data) struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data; struct dma_pl330_desc *desc, *_dt; unsigned long flags; - bool power_down = false; spin_lock_irqsave(&pch->lock, flags); @@ -2030,18 +2027,10 @@ static void pl330_tasklet(unsigned long data) /* Try to submit a req imm. next to the last completed cookie */ fill_queue(pch); - if (list_empty(&pch->work_list)) { - spin_lock(&pch->thread->dmac->lock); - _stop(pch->thread); - spin_unlock(&pch->thread->dmac->lock); - power_down = true; - pch->active = false; - } else { - /* Make sure the PL330 Channel thread is active */ - spin_lock(&pch->thread->dmac->lock); - _start(pch->thread); - spin_unlock(&pch->thread->dmac->lock); - } + /* Make sure the PL330 Channel thread is active */ + spin_lock(&pch->thread->dmac->lock); + _start(pch->thread); + spin_unlock(&pch->thread->dmac->lock); while (!list_empty(&pch->completed_list)) { struct dmaengine_desc_callback cb; @@ -2054,13 +2043,6 @@ static void pl330_tasklet(unsigned long data) if (pch->cyclic) { desc->status = PREP; list_move_tail(&desc->node, &pch->work_list); - if (power_down) { - pch->active = true; - spin_lock(&pch->thread->dmac->lock); - _start(pch->thread); - spin_unlock(&pch->thread->dmac->lock); - power_down = false; - } } else { desc->status = FREE; list_move_tail(&desc->node, &pch->dmac->desc_pool); @@ -2075,12 +2057,6 @@ static void pl330_tasklet(unsigned long data) } } spin_unlock_irqrestore(&pch->lock, flags); - - /* If work list empty, power down */ - if (power_down) { - pm_runtime_mark_last_busy(pch->dmac->ddma.dev); - pm_runtime_put_autosuspend(pch->dmac->ddma.dev); - } } bool pl330_filter(struct dma_chan *chan, void *param) @@ -2113,14 +2089,63 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec, if (chan_id >= pl330->num_peripherals) return NULL; + if (!pl330->peripherals[chan_id].slave) + pl330->peripherals[chan_id].slave = slave; + else if (pl330->peripherals[chan_id].slave != slave) { + dev_err(pl330->ddma.dev, + "Can't use same channel with multiple slave devices!\n"); + return NULL; + } + return dma_get_slave_channel(&pl330->peripherals[chan_id].chan); } +static int pl330_add_slave_link(struct pl330_dmac *pl330, + struct dma_pl330_chan *pch) +{ + struct device_link *link; + int i; + + if (pch->slave_link) + return 0; + + link = device_link_add(pch->slave, pl330->ddma.dev, + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + if (!link) + return -ENODEV; + + for (i = 0; i < pl330->num_peripherals; i++) + if (pl330->peripherals[i].slave == pch->slave) + pl330->peripherals[i].slave_link = link; + return 0; +} + +static void pl330_del_slave_link(struct pl330_dmac *pl330, + struct dma_pl330_chan *pch) +{ + struct device_link *link = pch->slave_link; + int i, count = 0; + + for (i = 0; i < pl330->num_peripherals; i++) + if (pl330->peripherals[i].slave == pch->slave && + pl330->peripherals[i].thread) + count++; + + if (count > 0) + return; + + device_link_del(link); + for (i = 0; i < pl330->num_peripherals; i++) + if (pl330->peripherals[i].slave == pch->slave) + pch->slave_link = NULL; +} + static int pl330_alloc_chan_resources(struct dma_chan *chan) { struct dma_pl330_chan *pch = to_pchan(chan); struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; + int ret = 0; spin_lock_irqsave(&pch->lock, flags); @@ -2137,6 +2162,14 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) spin_unlock_irqrestore(&pch->lock, flags); + if (pch->slave) + ret = pl330_add_slave_link(pl330, pch); + else + ret = pm_runtime_get_sync(pl330->ddma.dev); + + if (ret < 0) + return ret; + return 1; } @@ -2171,9 +2204,7 @@ static int pl330_terminate_all(struct dma_chan *chan) unsigned long flags; struct pl330_dmac *pl330 = pch->dmac; LIST_HEAD(list); - bool power_down = false; - pm_runtime_get_sync(pl330->ddma.dev); spin_lock_irqsave(&pch->lock, flags); spin_lock(&pl330->lock); _stop(pch->thread); @@ -2182,8 +2213,6 @@ static int pl330_terminate_all(struct dma_chan *chan) pch->thread->req[0].desc = NULL; pch->thread->req[1].desc = NULL; pch->thread->req_running = -1; - power_down = pch->active; - pch->active = false; /* Mark all desc done */ list_for_each_entry(desc, &pch->submitted_list, node) { @@ -2200,10 +2229,6 @@ static int pl330_terminate_all(struct dma_chan *chan) list_splice_tail_init(&pch->work_list, &pl330->desc_pool); list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); spin_unlock_irqrestore(&pch->lock, flags); - pm_runtime_mark_last_busy(pl330->ddma.dev); - if (power_down) - pm_runtime_put_autosuspend(pl330->ddma.dev); - pm_runtime_put_autosuspend(pl330->ddma.dev); return 0; } @@ -2221,7 +2246,6 @@ static int pl330_pause(struct dma_chan *chan) struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; - pm_runtime_get_sync(pl330->ddma.dev); spin_lock_irqsave(&pch->lock, flags); spin_lock(&pl330->lock); @@ -2229,8 +2253,6 @@ static int pl330_pause(struct dma_chan *chan) spin_unlock(&pl330->lock); spin_unlock_irqrestore(&pch->lock, flags); - pm_runtime_mark_last_busy(pl330->ddma.dev); - pm_runtime_put_autosuspend(pl330->ddma.dev); return 0; } @@ -2238,11 +2260,11 @@ static int pl330_pause(struct dma_chan *chan) static void pl330_free_chan_resources(struct dma_chan *chan) { struct dma_pl330_chan *pch = to_pchan(chan); + struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; tasklet_kill(&pch->task); - pm_runtime_get_sync(pch->dmac->ddma.dev); spin_lock_irqsave(&pch->lock, flags); pl330_release_channel(pch->thread); @@ -2252,19 +2274,20 @@ static void pl330_free_chan_resources(struct dma_chan *chan) list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); spin_unlock_irqrestore(&pch->lock, flags); - pm_runtime_mark_last_busy(pch->dmac->ddma.dev); - pm_runtime_put_autosuspend(pch->dmac->ddma.dev); + + if (pch->slave) + pl330_del_slave_link(pl330, pch); + else + pm_runtime_put(pl330->ddma.dev); } static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, struct dma_pl330_desc *desc) { struct pl330_thread *thrd = pch->thread; - struct pl330_dmac *pl330 = pch->dmac; void __iomem *regs = thrd->dmac->base; u32 val, addr; - pm_runtime_get_sync(pl330->ddma.dev); val = addr = 0; if (desc->rqcfg.src_inc) { val = readl(regs + SA(thrd->id)); @@ -2273,8 +2296,6 @@ static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, val = readl(regs + DA(thrd->id)); addr = desc->px.dst_addr; } - pm_runtime_mark_last_busy(pch->dmac->ddma.dev); - pm_runtime_put_autosuspend(pl330->ddma.dev); /* If DMAMOV hasn't finished yet, SAR/DAR can be zero */ if (!val) @@ -2360,16 +2381,6 @@ static void pl330_issue_pending(struct dma_chan *chan) unsigned long flags; spin_lock_irqsave(&pch->lock, flags); - if (list_empty(&pch->work_list)) { - /* - * Warn on nothing pending. Empty submitted_list may - * break our pm_runtime usage counter as it is - * updated on work_list emptiness status. - */ - WARN_ON(list_empty(&pch->submitted_list)); - pch->active = true; - pm_runtime_get_sync(pch->dmac->ddma.dev); - } list_splice_tail_init(&pch->submitted_list, &pch->work_list); spin_unlock_irqrestore(&pch->lock, flags); @@ -2987,11 +2998,7 @@ static int __maybe_unused pl330_resume(struct device *dev) pcfg->data_buf_dep, pcfg->data_bus_width / 8, pcfg->num_chan, pcfg->num_peri, pcfg->num_events); - pm_runtime_irq_safe(&adev->dev); - pm_runtime_use_autosuspend(&adev->dev); - pm_runtime_set_autosuspend_delay(&adev->dev, PL330_AUTOSUSPEND_DELAY); - pm_runtime_mark_last_busy(&adev->dev); - pm_runtime_put_autosuspend(&adev->dev); + pm_runtime_put(&adev->dev); return 0; probe_err3: