From patchwork Thu Oct 16 17:57:02 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vasily Khoruzhick X-Patchwork-Id: 5093111 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 67452C11AC for ; Thu, 16 Oct 2014 18:00:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0E84F201EC for ; Thu, 16 Oct 2014 18:00:23 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A07EF20127 for ; Thu, 16 Oct 2014 18:00:21 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XepJB-00070G-Nz; Thu, 16 Oct 2014 17:57:53 +0000 Received: from mail-ob0-x232.google.com ([2607:f8b0:4003:c01::232]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XepJ1-0006tB-J4; Thu, 16 Oct 2014 17:57:44 +0000 Received: by mail-ob0-f178.google.com with SMTP id wn1so3295411obc.37 for ; Thu, 16 Oct 2014 10:57:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type; bh=lex5iTjarXVCzIplrETFEwATQ5YVDqhpLO/HYo1wYMI=; b=gPGEUgvOIEwJn1/hgdPRt8aBD4Jg1f5PxeMohvfNEwdmZBJJpm39IiTc7C21aNt25h 9yB1Do2+kRRRKdx0S1vdbWo+4WjHwz20Og4+BDNbh2ZLfQNdgD/UTaBm8yeZoX73TxaX PjupNa5bLTeYQGUn+MUX9iBorUkZbhVKnZUtU6dlXyUXU3EiJ7Rzq+gDxtsPOnUQAA+V G9uDzUmK9sHcfYG+clDLzr+N6EdO1RD5lrvQW4xo6nWIxX0mTMmhxYpeubX3dQv3H/qC TuUHzRebbIwXYZevW8IP7UnY69JvA4L3y6hkSPEL2Qs3jSK7jjTTSkOP9S71b+w+nPVP nkSg== X-Received: by 10.202.194.67 with SMTP id s64mr2242327oif.22.1413482242443; Thu, 16 Oct 2014 10:57:22 -0700 (PDT) MIME-Version: 1.0 Received: by 10.76.97.105 with HTTP; Thu, 16 Oct 2014 10:57:02 -0700 (PDT) In-Reply-To: References: <1375889649-14638-1-git-send-email-zonque@gmail.com> <1375889649-14638-9-git-send-email-zonque@gmail.com> From: Vasily Khoruzhick Date: Thu, 16 Oct 2014 20:57:02 +0300 Message-ID: Subject: Re: [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use To: Daniel Mack X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20141016_105743_741054_BE9795B6 X-CRM114-Status: GOOD ( 24.66 ) X-Spam-Score: -0.1 (/) Cc: mark.rutland@arm.com, s.neumann@raumfeld.com, linux-mtd@lists.infradead.org, Haojian Zhuang , cxie4@marvell.com, Lars-Peter Clausen , Nicolas Pitre , Vinod Koul , =?UTF-8?B?TWFyZWsgVmHFoXV0?= , ezequiel.garcia@free-electrons.com, rmk+kernel@arm.linux.org.uk, devicetree@vger.kernel.org, samuel@sortiz.org, Arnd Bergmann , Mark Brown , mika.westerberg@linux.intel.com, arm-linux , Thomas Petazzoni , Eric Miao , Greg Kroah-Hartman , davem@davemloft.net, sachin.kamat@linaro.org, kernel@pengutronix.de, djbw@fb.com, Guennadi Liakhovetski X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=no 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 On Wed, Oct 15, 2014 at 9:32 PM, Vasily Khoruzhick wrote: > Hi Daniel, > > On Wed, Aug 7, 2013 at 6:33 PM, Daniel Mack wrote: >> Successfully testes on a PXA3xx board. > > I know it could be a bit late, but I tested your pxa-dma-3.15 branch > rebased against 3.17 on pxa270 device, > and unfortunatelly pxamci driver doesn't work well. > > It complains like this: > > [ 4.586118] mmc0: DMA error on rx channel > [ 4.586471] mmc0: status: 1 > [ 4.587340] mmcblk0: error -5 transferring data, sector 1586251, nr > 8, cmd response 0x900, card status 0xb00 > > status == 1, it's DMA_IN_PROGRESS, so I guess it's mmp_pdma bug, it > calls callback without calling dma_cookie_complete on appropriate > cookie? Any ideas how to fix it? Fixed it with attached patch. Original driver didn't set ENDMAEND flag for RX DMA, but after Daniel's conversion pxamci_dma_irq callback is called for both RX and TX. Now struggling with oops in pxa2xx_pcm driver. Regards Vasily > Regards, > Vasily > >> >> Signed-off-by: Daniel Mack >> --- >> drivers/mmc/host/pxamci.c | 188 +++++++++++++++++++++++++--------------------- >> 1 file changed, 102 insertions(+), 86 deletions(-) >> >> diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c >> index 2c5a91b..7aa97eb 100644 >> --- a/drivers/mmc/host/pxamci.c >> +++ b/drivers/mmc/host/pxamci.c >> @@ -22,7 +22,9 @@ >> #include >> #include >> #include >> +#include >> #include >> +#include >> #include >> #include >> #include >> @@ -37,7 +39,6 @@ >> #include >> >> #include >> -#include >> #include >> >> #include "pxamci.h" >> @@ -58,7 +59,6 @@ struct pxamci_host { >> struct clk *clk; >> unsigned long clkrate; >> int irq; >> - int dma; >> unsigned int clkrt; >> unsigned int cmdat; >> unsigned int imask; >> @@ -69,8 +69,10 @@ struct pxamci_host { >> struct mmc_command *cmd; >> struct mmc_data *data; >> >> + struct dma_chan *dma_chan_rx; >> + struct dma_chan *dma_chan_tx; >> + dma_cookie_t dma_cookie; >> dma_addr_t sg_dma; >> - struct pxa_dma_desc *sg_cpu; >> unsigned int dma_len; >> >> unsigned int dma_dir; >> @@ -173,14 +175,18 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) >> spin_unlock_irqrestore(&host->lock, flags); >> } >> >> +static void pxamci_dma_irq(void *param); >> + >> static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) >> { >> + struct dma_async_tx_descriptor *tx; >> + enum dma_data_direction direction; >> + struct dma_slave_config config; >> + struct dma_chan *chan; >> unsigned int nob = data->blocks; >> unsigned long long clks; >> unsigned int timeout; >> - bool dalgn = 0; >> - u32 dcmd; >> - int i; >> + int ret; >> >> host->data = data; >> >> @@ -195,54 +201,46 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) >> timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); >> writel((timeout + 255) / 256, host->base + MMC_RDTO); >> >> + memset(&config, 0, sizeof(config)); >> + config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; >> + config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; >> + config.src_addr = host->res->start + MMC_RXFIFO; >> + config.dst_addr = host->res->start + MMC_TXFIFO; >> + config.src_maxburst = 32; >> + config.dst_maxburst = 32; >> + >> if (data->flags & MMC_DATA_READ) { >> host->dma_dir = DMA_FROM_DEVICE; >> - dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; >> - DRCMR(host->dma_drcmrtx) = 0; >> - DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; >> + direction = DMA_DEV_TO_MEM; >> + chan = host->dma_chan_rx; >> } else { >> host->dma_dir = DMA_TO_DEVICE; >> - dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; >> - DRCMR(host->dma_drcmrrx) = 0; >> - DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; >> + direction = DMA_MEM_TO_DEV; >> + chan = host->dma_chan_tx; >> } >> >> - dcmd |= DCMD_BURST32 | DCMD_WIDTH1; >> + config.direction = direction; >> + >> + ret = dmaengine_slave_config(chan, &config); >> + if (ret < 0) { >> + dev_err(mmc_dev(host->mmc), "dma slave config failed\n"); >> + return; >> + } >> >> - host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, >> + host->dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len, >> host->dma_dir); >> >> - for (i = 0; i < host->dma_len; i++) { >> - unsigned int length = sg_dma_len(&data->sg[i]); >> - host->sg_cpu[i].dcmd = dcmd | length; >> - if (length & 31 && !(data->flags & MMC_DATA_READ)) >> - host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN; >> - /* Not aligned to 8-byte boundary? */ >> - if (sg_dma_address(&data->sg[i]) & 0x7) >> - dalgn = 1; >> - if (data->flags & MMC_DATA_READ) { >> - host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; >> - host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); >> - } else { >> - host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]); >> - host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; >> - } >> - host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * >> - sizeof(struct pxa_dma_desc); >> + tx = dmaengine_prep_slave_sg(chan, data->sg, host->dma_len, direction, >> + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); >> + if (!tx) { >> + dev_err(mmc_dev(host->mmc), "prep_slave_sg() failed\n"); >> + return; >> } >> - host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP; >> - wmb(); >> >> - /* >> - * The PXA27x DMA controller encounters overhead when working with >> - * unaligned (to 8-byte boundaries) data, so switch on byte alignment >> - * mode only if we have unaligned data. >> - */ >> - if (dalgn) >> - DALGN |= (1 << host->dma); >> - else >> - DALGN &= ~(1 << host->dma); >> - DDADR(host->dma) = host->sg_dma; >> + tx->callback = pxamci_dma_irq; >> + tx->callback_param = host; >> + >> + host->dma_cookie = dmaengine_submit(tx); >> >> /* >> * workaround for erratum #91: >> @@ -251,7 +249,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) >> * before starting DMA. >> */ >> if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ) >> - DCSR(host->dma) = DCSR_RUN; >> + dma_async_issue_pending(chan); >> } >> >> static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat) >> @@ -343,7 +341,7 @@ static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat) >> * enable DMA late >> */ >> if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE) >> - DCSR(host->dma) = DCSR_RUN; >> + dma_async_issue_pending(host->dma_chan_tx); >> } else { >> pxamci_finish_request(host, host->mrq); >> } >> @@ -358,9 +356,8 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) >> if (!data) >> return 0; >> >> - DCSR(host->dma) = 0; >> - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, >> - host->dma_dir); >> + dma_unmap_sg(host->dma_chan_rx->device->dev, >> + data->sg, data->sg_len, host->dma_dir); >> >> if (stat & STAT_READ_TIME_OUT) >> data->error = -ETIMEDOUT; >> @@ -552,17 +549,25 @@ static const struct mmc_host_ops pxamci_ops = { >> .enable_sdio_irq = pxamci_enable_sdio_irq, >> }; >> >> -static void pxamci_dma_irq(int dma, void *devid) >> +static void pxamci_dma_irq(void *param) >> { >> - struct pxamci_host *host = devid; >> - int dcsr = DCSR(dma); >> - DCSR(dma) = dcsr & ~DCSR_STOPIRQEN; >> + struct pxamci_host *host = param; >> + struct dma_tx_state state; >> + enum dma_status status; >> + struct dma_chan *chan; >> >> - if (dcsr & DCSR_ENDINTR) { >> + if (host->data->flags & MMC_DATA_READ) >> + chan = host->dma_chan_rx; >> + else >> + chan = host->dma_chan_tx; >> + >> + status = dmaengine_tx_status(chan, host->dma_cookie, &state); >> + >> + if (likely(status == DMA_SUCCESS)) { >> writel(BUF_PART_FULL, host->base + MMC_PRTBUF); >> } else { >> - pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", >> - mmc_hostname(host->mmc), dma, dcsr); >> + pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc), >> + host->data->flags & MMC_DATA_READ ? "rx" : "tx"); >> host->data->error = -EIO; >> pxamci_data_done(host, 0); >> } >> @@ -626,6 +631,7 @@ static int pxamci_probe(struct platform_device *pdev) >> struct pxamci_host *host = NULL; >> struct resource *r, *dmarx, *dmatx; >> int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; >> + dma_cap_mask_t mask; >> >> ret = pxamci_of_init(pdev); >> if (ret) >> @@ -671,7 +677,6 @@ static int pxamci_probe(struct platform_device *pdev) >> >> host = mmc_priv(mmc); >> host->mmc = mmc; >> - host->dma = -1; >> host->pdata = pdev->dev.platform_data; >> host->clkrt = CLKRT_OFF; >> >> @@ -702,12 +707,6 @@ static int pxamci_probe(struct platform_device *pdev) >> MMC_CAP_SD_HIGHSPEED; >> } >> >> - host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); >> - if (!host->sg_cpu) { >> - ret = -ENOMEM; >> - goto out; >> - } >> - >> spin_lock_init(&host->lock); >> host->res = r; >> host->irq = irq; >> @@ -728,32 +727,50 @@ static int pxamci_probe(struct platform_device *pdev) >> writel(64, host->base + MMC_RESTO); >> writel(host->imask, host->base + MMC_I_MASK); >> >> - host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW, >> - pxamci_dma_irq, host); >> - if (host->dma < 0) { >> - ret = -EBUSY; >> - goto out; >> - } >> - >> ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host); >> if (ret) >> goto out; >> >> platform_set_drvdata(pdev, mmc); >> >> - dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); >> - if (!dmarx) { >> - ret = -ENXIO; >> + if (!pdev->dev.of_node) { >> + dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); >> + if (!dmarx) { >> + ret = -ENXIO; >> + goto out; >> + } >> + host->dma_drcmrrx = dmarx->start; >> + >> + dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); >> + if (!dmatx) { >> + ret = -ENXIO; >> + goto out; >> + } >> + host->dma_drcmrtx = dmatx->start; >> + } >> + >> + dma_cap_zero(mask); >> + dma_cap_set(DMA_SLAVE, mask); >> + >> + host->dma_chan_rx = >> + dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn, >> + &host->dma_drcmrrx, >> + &pdev->dev, "rx"); >> + if (host->dma_chan_rx == NULL) { >> + dev_err(&pdev->dev, "unable to request rx dma channel\n"); >> + ret = -ENODEV; >> goto out; >> } >> - host->dma_drcmrrx = dmarx->start; >> >> - dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); >> - if (!dmatx) { >> - ret = -ENXIO; >> + host->dma_chan_tx = >> + dma_request_slave_channel_compat(mask, mmp_pdma_filter_fn, >> + &host->dma_drcmrtx, >> + &pdev->dev, "tx"); >> + if (host->dma_chan_tx == NULL) { >> + dev_err(&pdev->dev, "unable to request tx dma channel\n"); >> + ret = -ENODEV; >> goto out; >> } >> - host->dma_drcmrtx = dmatx->start; >> >> if (host->pdata) { >> gpio_cd = host->pdata->gpio_card_detect; >> @@ -814,12 +831,12 @@ err_gpio_ro: >> gpio_free(gpio_power); >> out: >> if (host) { >> - if (host->dma >= 0) >> - pxa_free_dma(host->dma); >> + if (host->dma_chan_rx) >> + dma_release_channel(host->dma_chan_rx); >> + if (host->dma_chan_tx) >> + dma_release_channel(host->dma_chan_tx); >> if (host->base) >> iounmap(host->base); >> - if (host->sg_cpu) >> - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); >> if (host->clk) >> clk_put(host->clk); >> } >> @@ -863,13 +880,12 @@ static int pxamci_remove(struct platform_device *pdev) >> END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, >> host->base + MMC_I_MASK); >> >> - DRCMR(host->dma_drcmrrx) = 0; >> - DRCMR(host->dma_drcmrtx) = 0; >> - >> free_irq(host->irq, host); >> - pxa_free_dma(host->dma); >> + dmaengine_terminate_all(host->dma_chan_rx); >> + dmaengine_terminate_all(host->dma_chan_tx); >> + dma_release_channel(host->dma_chan_rx); >> + dma_release_channel(host->dma_chan_tx); >> iounmap(host->base); >> - dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); >> >> clk_put(host->clk); >> >> -- >> 1.8.3.1 >> >> >> _______________________________________________ >> linux-arm-kernel mailing list >> linux-arm-kernel@lists.infradead.org >> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index eb725d3..b52e06e 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -237,8 +237,10 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) return; } - tx->callback = pxamci_dma_irq; - tx->callback_param = host; + if (!(data->flags & MMC_DATA_READ)) { + tx->callback = pxamci_dma_irq; + tx->callback_param = host; + } host->dma_cookie = dmaengine_submit(tx);