* Re: [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use
@ 2014-10-15 18:32 ` Vasily Khoruzhick
0 siblings, 0 replies; 13+ messages in thread
From: Vasily Khoruzhick @ 2014-10-15 18:32 UTC (permalink / raw)
To: Daniel Mack
Cc: Haojian Zhuang, Eric Miao, arm-linux, mark.rutland-5wv7dgnIgG8,
s.neumann-5g8ninUHluJWk0Htik3J/w,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
cxie4-eYqpPyKDWXRBDgjK7y7TUQ, Lars-Peter Clausen,
nico-QSEj5FYQhm4dnm+yROfE0A, Vinod Koul, Marek Vašut,
ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ,
devicetree-u79uwXL29TY76Z2rM5mHXA, samuel-jcdQHdrhKHMdnm+yROfE0A,
Arnd Bergmann, Mark Brown, mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
Greg Kroah-Hartman, g.liakhovetski-Mmb7MZpHnFY,
sachin.kamat-QSEj5FYQhm4dnm+yROfE0A,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ, djbw-b10kYP2dOMg,
davem-fT/PcQaiUtIeIZ0/mPfg9Q
Hi Daniel,
On Wed, Aug 7, 2013 at 6:33 PM, Daniel Mack <zonque-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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?
Regards,
Vasily
>
> Signed-off-by: Daniel Mack <zonque-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> 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 <linux/platform_device.h>
> #include <linux/delay.h>
> #include <linux/interrupt.h>
> +#include <linux/dmaengine.h>
> #include <linux/dma-mapping.h>
> +#include <linux/dma/mmp-pdma.h>
> #include <linux/clk.h>
> #include <linux/err.h>
> #include <linux/mmc/host.h>
> @@ -37,7 +39,6 @@
> #include <asm/sizes.h>
>
> #include <mach/hardware.h>
> -#include <mach/dma.h>
> #include <linux/platform_data/mmc-pxamci.h>
>
> #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-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use
@ 2014-10-15 18:32 ` Vasily Khoruzhick
0 siblings, 0 replies; 13+ messages in thread
From: Vasily Khoruzhick @ 2014-10-15 18:32 UTC (permalink / raw)
To: linux-arm-kernel
Hi Daniel,
On Wed, Aug 7, 2013 at 6:33 PM, Daniel Mack <zonque@gmail.com> 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?
Regards,
Vasily
>
> Signed-off-by: Daniel Mack <zonque@gmail.com>
> ---
> 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 <linux/platform_device.h>
> #include <linux/delay.h>
> #include <linux/interrupt.h>
> +#include <linux/dmaengine.h>
> #include <linux/dma-mapping.h>
> +#include <linux/dma/mmp-pdma.h>
> #include <linux/clk.h>
> #include <linux/err.h>
> #include <linux/mmc/host.h>
> @@ -37,7 +39,6 @@
> #include <asm/sizes.h>
>
> #include <mach/hardware.h>
> -#include <mach/dma.h>
> #include <linux/platform_data/mmc-pxamci.h>
>
> #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 at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use
2014-10-15 18:32 ` Vasily Khoruzhick
(?)
@ 2014-10-16 17:57 ` Vasily Khoruzhick
-1 siblings, 0 replies; 13+ messages in thread
From: Vasily Khoruzhick @ 2014-10-16 17:57 UTC (permalink / raw)
To: Daniel Mack
Cc: mark.rutland, s.neumann, linux-mtd, Haojian Zhuang, cxie4,
Lars-Peter Clausen, Nicolas Pitre, Vinod Koul, Marek Vašut,
ezequiel.garcia, rmk+kernel, devicetree, samuel, Arnd Bergmann,
Mark Brown, mika.westerberg, arm-linux, Thomas Petazzoni,
Eric Miao, Greg Kroah-Hartman, davem, sachin.kamat, kernel, djbw,
Guennadi Liakhovetski
[-- Attachment #1: Type: text/plain, Size: 15379 bytes --]
On Wed, Oct 15, 2014 at 9:32 PM, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> Hi Daniel,
>
> On Wed, Aug 7, 2013 at 6:33 PM, Daniel Mack <zonque@gmail.com> 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 <zonque@gmail.com>
>> ---
>> 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 <linux/platform_device.h>
>> #include <linux/delay.h>
>> #include <linux/interrupt.h>
>> +#include <linux/dmaengine.h>
>> #include <linux/dma-mapping.h>
>> +#include <linux/dma/mmp-pdma.h>
>> #include <linux/clk.h>
>> #include <linux/err.h>
>> #include <linux/mmc/host.h>
>> @@ -37,7 +39,6 @@
>> #include <asm/sizes.h>
>>
>> #include <mach/hardware.h>
>> -#include <mach/dma.h>
>> #include <linux/platform_data/mmc-pxamci.h>
>>
>> #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
[-- Attachment #2: pxamci-mmp-pdma-fix.patch --]
[-- Type: text/x-patch, Size: 495 bytes --]
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);
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use
@ 2014-10-16 17:57 ` Vasily Khoruzhick
0 siblings, 0 replies; 13+ messages in thread
From: Vasily Khoruzhick @ 2014-10-16 17:57 UTC (permalink / raw)
To: Daniel Mack
Cc: Haojian Zhuang, Eric Miao, arm-linux, mark.rutland-5wv7dgnIgG8,
s.neumann-5g8ninUHluJWk0Htik3J/w,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
cxie4-eYqpPyKDWXRBDgjK7y7TUQ, Lars-Peter Clausen, Nicolas Pitre,
Vinod Koul, Marek Vašut,
ezequiel.garcia-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
rmk+kernel-lFZ/pmaqli7XmaaqVzeoHQ,
devicetree-u79uwXL29TY76Z2rM5mHXA, samuel-jcdQHdrhKHMdnm+yROfE0A,
Arnd Bergmann, Mark Brown, mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
Thomas Petazzoni, Greg Kroah-Hartman, Guennadi Liakhovetski,
sachin.kamat-QSEj5FYQhm4dnm+yROfE0A,
kernel-bIcnvbaLZ9MEGnE8C9+IrQ, djbw-b10kYP2dOMg,
davem-fT/PcQaiUtIeIZ0/mPfg9Q
[-- Attachment #1: Type: text/plain, Size: 15499 bytes --]
On Wed, Oct 15, 2014 at 9:32 PM, Vasily Khoruzhick <anarsoul-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Hi Daniel,
>
> On Wed, Aug 7, 2013 at 6:33 PM, Daniel Mack <zonque-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 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 <zonque-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> ---
>> 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 <linux/platform_device.h>
>> #include <linux/delay.h>
>> #include <linux/interrupt.h>
>> +#include <linux/dmaengine.h>
>> #include <linux/dma-mapping.h>
>> +#include <linux/dma/mmp-pdma.h>
>> #include <linux/clk.h>
>> #include <linux/err.h>
>> #include <linux/mmc/host.h>
>> @@ -37,7 +39,6 @@
>> #include <asm/sizes.h>
>>
>> #include <mach/hardware.h>
>> -#include <mach/dma.h>
>> #include <linux/platform_data/mmc-pxamci.h>
>>
>> #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-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
[-- Attachment #2: pxamci-mmp-pdma-fix.patch --]
[-- Type: text/x-patch, Size: 495 bytes --]
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);
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use
@ 2014-10-16 17:57 ` Vasily Khoruzhick
0 siblings, 0 replies; 13+ messages in thread
From: Vasily Khoruzhick @ 2014-10-16 17:57 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Oct 15, 2014 at 9:32 PM, Vasily Khoruzhick <anarsoul@gmail.com> wrote:
> Hi Daniel,
>
> On Wed, Aug 7, 2013 at 6:33 PM, Daniel Mack <zonque@gmail.com> 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 <zonque@gmail.com>
>> ---
>> 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 <linux/platform_device.h>
>> #include <linux/delay.h>
>> #include <linux/interrupt.h>
>> +#include <linux/dmaengine.h>
>> #include <linux/dma-mapping.h>
>> +#include <linux/dma/mmp-pdma.h>
>> #include <linux/clk.h>
>> #include <linux/err.h>
>> #include <linux/mmc/host.h>
>> @@ -37,7 +39,6 @@
>> #include <asm/sizes.h>
>>
>> #include <mach/hardware.h>
>> -#include <mach/dma.h>
>> #include <linux/platform_data/mmc-pxamci.h>
>>
>> #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 at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: pxamci-mmp-pdma-fix.patch
Type: text/x-patch
Size: 495 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20141016/8d400f7e/attachment-0001.bin>
^ permalink raw reply [flat|nested] 13+ messages in thread