From patchwork Fri Jan 16 02:24:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 5643871 Return-Path: X-Original-To: patchwork-dmaengine@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 1FDB5C058D for ; Fri, 16 Jan 2015 02:25:07 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id ACCCA2015E for ; Fri, 16 Jan 2015 02:25:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3559F20172 for ; Fri, 16 Jan 2015 02:25:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932271AbbAPCZD (ORCPT ); Thu, 15 Jan 2015 21:25:03 -0500 Received: from relmlor3.renesas.com ([210.160.252.173]:65222 "EHLO relmlie2.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1755621AbbAPCZB (ORCPT ); Thu, 15 Jan 2015 21:25:01 -0500 Received: from unknown (HELO relmlir1.idc.renesas.com) ([10.200.68.151]) by relmlie2.idc.renesas.com with ESMTP; 16 Jan 2015 11:25:00 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir1.idc.renesas.com (Postfix) with ESMTP id 501CB4581A; Fri, 16 Jan 2015 11:25:00 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 44FE62806E; Fri, 16 Jan 2015 11:25:00 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id 3A3532806D; Fri, 16 Jan 2015 11:25:00 +0900 (JST) Received: from relmlii1.idc.renesas.com [10.200.68.65] by relmlac2.idc.renesas.com with ESMTP id MAD31736; Fri, 16 Jan 2015 11:25:00 +0900 X-IronPort-AV: E=Sophos;i="5.09,407,1418050800"; d="scan'208";a="177764742" Received: from mail-hk1lp0124.outbound.protection.outlook.com (HELO APAC01-HK1-obe.outbound.protection.outlook.com) ([207.46.51.124]) by relmlii1.idc.renesas.com with ESMTP/TLS/AES256-SHA; 16 Jan 2015 11:24:58 +0900 Received: from remon.renesas.com (211.11.155.132) by SINPR06MB172.apcprd06.prod.outlook.com (10.242.57.21) with Microsoft SMTP Server (TLS) id 15.1.53.17; Fri, 16 Jan 2015 02:24:56 +0000 Message-ID: <87oapzxxzw.wl%kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH] dmaengine: shdma: use normal interface for passing slave id User-Agent: Wanderlust/2.14.0 Emacs/23.3 Mule/6.0 MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") To: Vinod Koul , Arnd Bergmann , Ulf Hansson CC: , Simon , Rob Herring , Linux-SH , Laurent In-Reply-To: <87ppafxy1f.wl%kuninori.morimoto.gx@renesas.com> References: <87ppafxy1f.wl%kuninori.morimoto.gx@renesas.com> Date: Fri, 16 Jan 2015 02:24:56 +0000 X-Originating-IP: [211.11.155.132] X-ClientProxiedBy: HKXPR02CA0066.apcprd02.prod.outlook.com (25.161.48.51) To SINPR06MB172.apcprd06.prod.outlook.com (10.242.57.21) Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=kuninori.morimoto.gx@renesas.com; X-DmarcAction-Test: None X-Microsoft-Antispam: UriScan:; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:(3005004);SRVR:SINPR06MB172; X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004); SRVR:SINPR06MB172; X-Forefront-PRVS: 04583CED1A X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6009001)(199003)(189002)(101416001)(23726002)(81156004)(97736003)(575784001)(86362001)(83506001)(229853001)(69596002)(19580405001)(42186005)(19580395003)(40100003)(106356001)(122386002)(46102003)(76176999)(54356999)(87976001)(50986999)(46406003)(105586002)(92566002)(62966003)(66066001)(53416004)(64706001)(77156002)(36756003)(2950100001)(50466002)(33646002)(77096005)(47776003)(68736005); DIR:OUT; SFP:1102; SCL:1; SRVR:SINPR06MB172; H:remon.renesas.com; FPR:; SPF:None; MLV:sfv; PTR:InfoNoRecords; A:1; MX:1; LANG:en; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:;SRVR:SINPR06MB172; X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 16 Jan 2015 02:24:56.4244 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SINPR06MB172 Sender: dmaengine-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: dmaengine@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Arnd Bergmann The shmobile platform is one of only two users of the slave_id field in dma_slave_config, which is incompatible with the way that the dmaengine API normally works. I've had a closer look at the existing code now and found that all slave drivers that pass a slave_id in dma_slave_config for SH do that right after passing the same ID into shdma_chan_filter, so we can just rely on that. However, the various shdma drivers currently do not remember the slave ID that was passed into the filter function when used in non-DT mode and only check the value to find a matching channel, unlike all other drivers. There might still be drivers that are not part of the kernel that rely on setting the slave_id to some other value, so to be on the safe side, this adds another 'real_slave_id' field to shdma_chan that remembers the ID and uses it when a driver passes a zero slave_id in dma_slave_config, like most drivers do. Eventually, the real_slave_id and slave_id fields should just get merged into one field, but that requires other changes. Signed-off-by: Arnd Bergmann Signed-off-by: Kuninori Morimoto --- drivers/dma/sh/shdma-base.c | 72 ++++++++++++++++++++++++++----------- drivers/mmc/host/sh_mmcif.c | 12 +++---- drivers/mmc/host/sh_mobile_sdhi.c | 2 -- drivers/mmc/host/tmio_mmc.h | 2 -- drivers/mmc/host/tmio_mmc_dma.c | 4 --- drivers/mtd/nand/sh_flctl.c | 2 -- drivers/spi/spi-rspi.c | 1 - drivers/spi/spi-sh-msiof.c | 1 - include/linux/shdma-base.h | 1 + 9 files changed, 58 insertions(+), 39 deletions(-) diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c index 8ee383d..1a8050a9 100644 --- a/drivers/dma/sh/shdma-base.c +++ b/drivers/dma/sh/shdma-base.c @@ -171,8 +171,7 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan) return NULL; } -static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, - dma_addr_t slave_addr) +static int shdma_setup_slave(struct shdma_chan *schan, dma_addr_t slave_addr) { struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device); const struct shdma_ops *ops = sdev->ops; @@ -183,25 +182,23 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id, ret = ops->set_slave(schan, match, slave_addr, true); if (ret < 0) return ret; - - slave_id = schan->slave_id; } else { - match = slave_id; + match = schan->real_slave_id; } - if (slave_id < 0 || slave_id >= slave_num) + if (schan->real_slave_id < 0 || schan->real_slave_id >= slave_num) return -EINVAL; - if (test_and_set_bit(slave_id, shdma_slave_used)) + if (test_and_set_bit(schan->real_slave_id, shdma_slave_used)) return -EBUSY; ret = ops->set_slave(schan, match, slave_addr, false); if (ret < 0) { - clear_bit(slave_id, shdma_slave_used); + clear_bit(schan->real_slave_id, shdma_slave_used); return ret; } - schan->slave_id = slave_id; + schan->slave_id = schan->real_slave_id; return 0; } @@ -221,10 +218,12 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan) */ if (slave) { /* Legacy mode: .private is set in filter */ - ret = shdma_setup_slave(schan, slave->slave_id, 0); + schan->real_slave_id = slave->slave_id; + ret = shdma_setup_slave(schan, 0); if (ret < 0) goto esetslave; } else { + /* Normal mode: real_slave_id was set by filter */ schan->slave_id = -EINVAL; } @@ -258,11 +257,14 @@ esetslave: /* * This is the standard shdma filter function to be used as a replacement to the - * "old" method, using the .private pointer. If for some reason you allocate a - * channel without slave data, use something like ERR_PTR(-EINVAL) as a filter + * "old" method, using the .private pointer. + * You always have to pass a valid slave id as the argument, old drivers that + * pass ERR_PTR(-EINVAL) as a filter parameter and set it up in dma_slave_config + * need to be updated so we can remove the slave_id field from dma_slave_config. * parameter. If this filter is used, the slave driver, after calling * dma_request_channel(), will also have to call dmaengine_slave_config() with - * .slave_id, .direction, and either .src_addr or .dst_addr set. + * .direction, and either .src_addr or .dst_addr set. + * * NOTE: this filter doesn't support multiple DMAC drivers with the DMA_SLAVE * capability! If this becomes a requirement, hardware glue drivers, using this * services would have to provide their own filters, which first would check @@ -276,7 +278,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) { struct shdma_chan *schan; struct shdma_dev *sdev; - int match = (long)arg; + int slave_id = (long)arg; int ret; /* Only support channels handled by this driver. */ @@ -284,16 +286,35 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg) shdma_alloc_chan_resources) return false; - if (match < 0) + schan = to_shdma_chan(chan); + sdev = to_shdma_dev(chan->device); + + /* + * For DT, the schan->slave_id field is generated by the + * set_slave function from the slave ID that is passed in + * from xlate. For the non-DT case, the slave ID is + * directly passed into the filter function by the driver + */ + if (schan->dev->of_node) { + ret = sdev->ops->set_slave(schan, slave_id, 0, true); + if (ret < 0) + return false; + + schan->real_slave_id = schan->slave_id; + return true; + } + + if (slave_id < 0) { /* No slave requested - arbitrary channel */ + dev_warn(sdev->dma_dev.dev, "invalid slave ID passed to dma_request_slave\n"); return true; + } - schan = to_shdma_chan(chan); - if (!schan->dev->of_node && match >= slave_num) + if (slave_id >= slave_num) return false; - sdev = to_shdma_dev(schan->dma_chan.device); - ret = sdev->ops->set_slave(schan, match, 0, true); + schan->real_slave_id = slave_id; + ret = sdev->ops->set_slave(schan, schan->real_slave_id, 0, true); if (ret < 0) return false; @@ -452,6 +473,8 @@ static void shdma_free_chan_resources(struct dma_chan *chan) chan->private = NULL; } + schan->real_slave_id = 0; + spin_lock_irq(&schan->chan_lock); list_splice_init(&schan->ld_free, &list); @@ -764,11 +787,20 @@ static int shdma_config(struct dma_chan *chan, */ if (!config) return -EINVAL; + + /* + * overriding the slave_id through dma_slave_config is deprecated, + * but possibly some out-of-tree drivers still do it. + */ + if (WARN_ON_ONCE(config->slave_id && + config->slave_id != schan->real_slave_id)) + schan->real_slave_id = config->slave_id; + /* * We could lock this, but you shouldn't be configuring the * channel, while using it... */ - return shdma_setup_slave(schan, config->slave_id, + return shdma_setup_slave(schan, config->direction == DMA_DEV_TO_MEM ? config->src_addr : config->dst_addr); } diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 7d9d6a3..5f1ba9c 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -388,7 +388,7 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host, { struct dma_slave_config cfg = { 0, }; struct dma_chan *chan; - unsigned int slave_id; + void *slave_data; struct resource *res; dma_cap_mask_t mask; int ret; @@ -397,13 +397,13 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host, dma_cap_set(DMA_SLAVE, mask); if (pdata) - slave_id = direction == DMA_MEM_TO_DEV - ? pdata->slave_id_tx : pdata->slave_id_rx; + slave_data = direction == DMA_MEM_TO_DEV + ? (void *)pdata->slave_id_tx : (void *)pdata->slave_id_rx; else - slave_id = 0; + slave_data = 0; chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, - (void *)(unsigned long)slave_id, &host->pd->dev, + slave_data, &host->pd->dev, direction == DMA_MEM_TO_DEV ? "tx" : "rx"); dev_dbg(&host->pd->dev, "%s: %s: got channel %p\n", __func__, @@ -414,8 +414,6 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host, res = platform_get_resource(host->pd, IORESOURCE_MEM, 0); - /* In the OF case the driver will get the slave ID from the DT */ - cfg.slave_id = slave_id; cfg.direction = direction; if (direction == DMA_DEV_TO_MEM) { diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 6906a90..11991f5 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -261,8 +261,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) */ dma_priv->chan_priv_tx = (void *)p->dma_slave_tx; dma_priv->chan_priv_rx = (void *)p->dma_slave_rx; - dma_priv->slave_id_tx = p->dma_slave_tx; - dma_priv->slave_id_rx = p->dma_slave_rx; } } dma_priv->filter = shdma_chan_filter; diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index fc3805e..1aea5c6 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -45,8 +45,6 @@ struct tmio_mmc_host; struct tmio_mmc_dma { void *chan_priv_tx; void *chan_priv_rx; - int slave_id_tx; - int slave_id_rx; enum dma_slave_buswidth dma_buswidth; bool (*filter)(struct dma_chan *chan, void *arg); void (*enable)(struct tmio_mmc_host *host, bool enable); diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 331bb61..8dbd785 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -286,8 +286,6 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_tx) return; - if (host->dma->chan_priv_tx) - cfg.slave_id = host->dma->slave_id_tx; cfg.direction = DMA_MEM_TO_DEV; cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift); cfg.dst_addr_width = host->dma->dma_buswidth; @@ -307,8 +305,6 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat if (!host->chan_rx) goto ereqrx; - if (host->dma->chan_priv_rx) - cfg.slave_id = host->dma->slave_id_rx; cfg.direction = DMA_DEV_TO_MEM; cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset; cfg.src_addr_width = host->dma->dma_buswidth; diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index a21c378..c3ce81c 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -159,7 +159,6 @@ static void flctl_setup_dma(struct sh_flctl *flctl) return; memset(&cfg, 0, sizeof(cfg)); - cfg.slave_id = pdata->slave_id_fifo0_tx; cfg.direction = DMA_MEM_TO_DEV; cfg.dst_addr = (dma_addr_t)FLDTFIFO(flctl); cfg.src_addr = 0; @@ -175,7 +174,6 @@ static void flctl_setup_dma(struct sh_flctl *flctl) if (!flctl->chan_fifo0_rx) goto err; - cfg.slave_id = pdata->slave_id_fifo0_rx; cfg.direction = DMA_DEV_TO_MEM; cfg.dst_addr = 0; cfg.src_addr = (dma_addr_t)FLDTFIFO(flctl); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 2071f78..6cbcdc0 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -918,7 +918,6 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev, } memset(&cfg, 0, sizeof(cfg)); - cfg.slave_id = id; cfg.direction = dir; if (dir == DMA_MEM_TO_DEV) { cfg.dst_addr = port_addr; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 239be7c..786ac9e 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -984,7 +984,6 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev, } memset(&cfg, 0, sizeof(cfg)); - cfg.slave_id = id; cfg.direction = dir; if (dir == DMA_MEM_TO_DEV) { cfg.dst_addr = port_addr; diff --git a/include/linux/shdma-base.h b/include/linux/shdma-base.h index abdf1f2..dd0ba50 100644 --- a/include/linux/shdma-base.h +++ b/include/linux/shdma-base.h @@ -69,6 +69,7 @@ struct shdma_chan { int id; /* Raw id of this channel */ int irq; /* Channel IRQ */ int slave_id; /* Client ID for slave DMA */ + int real_slave_id; /* argument passed to filter function */ int hw_req; /* DMA request line for slave DMA - same * as MID/RID, used with DT */ enum shdma_pm_state pm_state;