* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use @ 2013-12-10 9:24 Sergei Ianovich 0 siblings, 0 replies; 8+ messages in thread From: Sergei Ianovich @ 2013-12-10 9:24 UTC (permalink / raw) To: linux-arm-kernel Tested this patch rebased onto v3.13-rc2 In-kernel DMA driver was not modified. Below is the full diff against Daniel's version based on v3.11-rc5 My changes are at the line 572 to fix build failure and at the lines 630 and 780 to receive DMA channels from device tree. The device works in general, but it is slower than with the old DMA and it reports sporadic failures like that --->8--- [ 2848.451688] mmc0: DMA error on rx channel, status 1 [ 2848.458326] mmcblk0: error -5 transferring data, sector 7037462, nr 2, cmd response 0x900, card status 0x0 [ 2848.469245] end_request: I/O error, dev mmcblk0, sector 7037462 [ 2883.228720] mmc0: DMA error on rx channel, status 1 [ 2883.263844] mmcblk0: error -5 transferring data, sector 7163928, nr 8, cmd response 0x900, card status 0xb00 [ 2883.274240] mmcblk0: retrying using single block read --->8--- diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 7aa97eb..e5bafd2 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -85,7 +85,7 @@ struct pxamci_host { static inline void pxamci_init_ocr(struct pxamci_host *host) { #ifdef CONFIG_REGULATOR - host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc"); if (IS_ERR(host->vcc)) host->vcc = NULL; @@ -555,6 +555,12 @@ static void pxamci_dma_irq(void *param) struct dma_tx_state state; enum dma_status status; struct dma_chan *chan; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (!host->data) + goto out_unlock; if (host->data->flags & MMC_DATA_READ) chan = host->dma_chan_rx; @@ -563,14 +569,17 @@ static void pxamci_dma_irq(void *param) status = dmaengine_tx_status(chan, host->dma_cookie, &state); - if (likely(status == DMA_SUCCESS)) { + if (likely(status == DMA_COMPLETE)) { writel(BUF_PART_FULL, host->base + MMC_PRTBUF); } else { - pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc), - host->data->flags & MMC_DATA_READ ? "rx" : "tx"); + pr_err("%s: DMA error on %s channel, status %i\n", mmc_hostname(host->mmc), + host->data->flags & MMC_DATA_READ ? "rx" : "tx", status); host->data->error = -EIO; pxamci_data_done(host, 0); } + +out_unlock: + spin_unlock_irqrestore(&host->lock, flags); } static irqreturn_t pxamci_detect_irq(int irq, void *devid) @@ -618,11 +627,46 @@ static int pxamci_of_init(struct platform_device *pdev) return 0; } + +static int pxamci_of_init_dma(struct platform_device *pdev, + struct pxamci_host *host) +{ + struct device_node *np = pdev->dev.of_node; + u32 tmp; + int i; + int ret; + + i = of_property_match_string(np, "dma-names", "rx"); + if (i < 0) + return i; + + ret = of_property_read_u32_index(np, "dmas", 2 * i + 1, &tmp); + if (ret < 0) + return ret; + host->dma_drcmrrx = tmp; + + i = of_property_match_string(np, "dma-names", "tx"); + if (i < 0) + return i; + + ret = of_property_read_u32_index(np, "dmas", 2 * i + 1, &tmp); + if (ret < 0) + return ret; + host->dma_drcmrtx = tmp; + + return 0; +} #else static int pxamci_of_init(struct platform_device *pdev) { return 0; } + +static int pxamci_of_init_dma(struct platform_device *pdev, + struct pxamci_host *host) +{ + return -ENODATA; +} #endif static int pxamci_probe(struct platform_device *pdev) @@ -733,7 +777,7 @@ static int pxamci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); - if (!pdev->dev.of_node) { + if (pxamci_of_init_dma(pdev, host) < 0) { dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmarx) { ret = -ENXIO; @@ -896,35 +940,6 @@ static int pxamci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int pxamci_suspend(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int pxamci_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} - -static const struct dev_pm_ops pxamci_pm_ops = { - .suspend = pxamci_suspend, - .resume = pxamci_resume, -}; -#endif - static struct platform_driver pxamci_driver = { .probe = pxamci_probe, .remove = pxamci_remove, @@ -932,9 +947,6 @@ static struct platform_driver pxamci_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(pxa_mmc_dt_ids), -#ifdef CONFIG_PM - .pm = &pxamci_pm_ops, -#endif }, }; ^ permalink raw reply related [flat|nested] 8+ messages in thread
[parent not found: <1375889649-14638-9-git-send-email-zonque>]
* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use [not found] <1375889649-14638-9-git-send-email-zonque> @ 2013-12-10 9:27 ` Sergei Ianovich 2013-12-10 10:25 ` Sergei Ianovich 0 siblings, 1 reply; 8+ messages in thread From: Sergei Ianovich @ 2013-12-10 9:27 UTC (permalink / raw) To: linux-arm-kernel Tested this patch rebased onto v3.13-rc2 In-kernel DMA driver was not modified. Below is the full diff against Daniel's version based on v3.11-rc5 My changes are at the line 572 to fix build failure and at the lines 630 and 780 to receive DMA channels from device tree. The device works in general, but it is slower than with the old DMA and it reports sporadic failures like that --->8--- [ 2848.451688] mmc0: DMA error on rx channel, status 1 [ 2848.458326] mmcblk0: error -5 transferring data, sector 7037462, nr 2, cmd response 0x900, card status 0x0 [ 2848.469245] end_request: I/O error, dev mmcblk0, sector 7037462 [ 2883.228720] mmc0: DMA error on rx channel, status 1 [ 2883.263844] mmcblk0: error -5 transferring data, sector 7163928, nr 8, cmd response 0x900, card status 0xb00 [ 2883.274240] mmcblk0: retrying using single block read --->8--- diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 7aa97eb..e5bafd2 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -85,7 +85,7 @@ struct pxamci_host { static inline void pxamci_init_ocr(struct pxamci_host *host) { #ifdef CONFIG_REGULATOR - host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + host->vcc = regulator_get_optional(mmc_dev(host->mmc), "vmmc"); if (IS_ERR(host->vcc)) host->vcc = NULL; @@ -555,6 +555,12 @@ static void pxamci_dma_irq(void *param) struct dma_tx_state state; enum dma_status status; struct dma_chan *chan; + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + + if (!host->data) + goto out_unlock; if (host->data->flags & MMC_DATA_READ) chan = host->dma_chan_rx; @@ -563,14 +569,17 @@ static void pxamci_dma_irq(void *param) status = dmaengine_tx_status(chan, host->dma_cookie, &state); - if (likely(status == DMA_SUCCESS)) { + if (likely(status == DMA_COMPLETE)) { writel(BUF_PART_FULL, host->base + MMC_PRTBUF); } else { - pr_err("%s: DMA error on %s channel\n", mmc_hostname(host->mmc), - host->data->flags & MMC_DATA_READ ? "rx" : "tx"); + pr_err("%s: DMA error on %s channel, status %i\n", mmc_hostname(host->mmc), + host->data->flags & MMC_DATA_READ ? "rx" : "tx", status); host->data->error = -EIO; pxamci_data_done(host, 0); } + +out_unlock: + spin_unlock_irqrestore(&host->lock, flags); } static irqreturn_t pxamci_detect_irq(int irq, void *devid) @@ -618,11 +627,46 @@ static int pxamci_of_init(struct platform_device *pdev) return 0; } + +static int pxamci_of_init_dma(struct platform_device *pdev, + struct pxamci_host *host) +{ + struct device_node *np = pdev->dev.of_node; + u32 tmp; + int i; + int ret; + + i = of_property_match_string(np, "dma-names", "rx"); + if (i < 0) + return i; + + ret = of_property_read_u32_index(np, "dmas", 2 * i + 1, &tmp); + if (ret < 0) + return ret; + host->dma_drcmrrx = tmp; + + i = of_property_match_string(np, "dma-names", "tx"); + if (i < 0) + return i; + + ret = of_property_read_u32_index(np, "dmas", 2 * i + 1, &tmp); + if (ret < 0) + return ret; + host->dma_drcmrtx = tmp; + + return 0; +} #else static int pxamci_of_init(struct platform_device *pdev) { return 0; } + +static int pxamci_of_init_dma(struct platform_device *pdev, + struct pxamci_host *host) +{ + return -ENODATA; +} #endif static int pxamci_probe(struct platform_device *pdev) @@ -733,7 +777,7 @@ static int pxamci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); - if (!pdev->dev.of_node) { + if (pxamci_of_init_dma(pdev, host) < 0) { dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmarx) { ret = -ENXIO; @@ -896,35 +940,6 @@ static int pxamci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int pxamci_suspend(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int pxamci_resume(struct device *dev) -{ - struct mmc_host *mmc = dev_get_drvdata(dev); - int ret = 0; - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} - -static const struct dev_pm_ops pxamci_pm_ops = { - .suspend = pxamci_suspend, - .resume = pxamci_resume, -}; -#endif - static struct platform_driver pxamci_driver = { .probe = pxamci_probe, .remove = pxamci_remove, @@ -932,9 +947,6 @@ static struct platform_driver pxamci_driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, .of_match_table = of_match_ptr(pxa_mmc_dt_ids), -#ifdef CONFIG_PM - .pm = &pxamci_pm_ops, -#endif }, }; ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use 2013-12-10 9:27 ` Sergei Ianovich @ 2013-12-10 10:25 ` Sergei Ianovich 2013-12-10 10:48 ` Daniel Mack 0 siblings, 1 reply; 8+ messages in thread From: Sergei Ianovich @ 2013-12-10 10:25 UTC (permalink / raw) To: linux-arm-kernel On Tue, 2013-12-10 at 13:27 +0400, Sergei Ianovich wrote: > The device works in general, but it is slower than with the old DMA > and it reports sporadic failures like that This took 40 minutes on my ARM device: --->8--- # fsck.ext3 -cvf /dev/mmcblk0p1 e2fsck 1.42.5 (29-Jul-2012) Checking for bad blocks (read-only test): done /dev/mmcblk0p1: Updating bad block inode. Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/mmcblk0p1: ***** FILE SYSTEM WAS MODIFIED ***** /dev/mmcblk0p1: ***** REBOOT LINUX ***** 8649 inodes used (3.56%, out of 242880) 7 non-contiguous files (0.1%) 7 non-contiguous directories (0.1%) # of inodes with ind/dind/tind blocks: 540/3/0 91255 blocks used (9.40%, out of 970752) 0 bad blocks 1 large file 6502 regular files 860 directories 0 character device files 0 block device files 1 fifo 0 links 1277 symbolic links (1277 fast symbolic links) 0 sockets ------------ 8640 files --->8--- The same card immediately after on my x86_64 PC, in 2 minutes: --->8--- $ sudo fsck -cfv /dev/mmcblk0p1 fsck from util-linux 2.20.1 e2fsck 1.42.8 (20-Jun-2013) Checking for bad blocks (read-only test): done /dev/mmcblk0p1: Updating bad block inode. Pass 1: Checking inodes, blocks, and sizes Inodes that were part of a corrupted orphan linked list found. Fix<y>? yes Inode 24388 was part of the orphaned inode list. FIXED. Inode 24511 was part of the orphaned inode list. FIXED. Inode 24727 was part of the orphaned inode list. FIXED. Inode 32410 was part of the orphaned inode list. FIXED. Inode 32413 was part of the orphaned inode list. FIXED. Inode 57554 was part of the orphaned inode list. FIXED. Inode 57680 was part of the orphaned inode list. FIXED. Inode 57681 was part of the orphaned inode list. FIXED. Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information /dev/mmcblk0p1: ***** FILE SYSTEM WAS MODIFIED ***** 8649 inodes used (3.56%, out of 242880) 7 non-contiguous files (0.1%) 7 non-contiguous directories (0.1%) # of inodes with ind/dind/tind blocks: 540/3/0 91255 blocks used (9.40%, out of 970752) 0 bad blocks 1 large file 6502 regular files 860 directories 0 character device files 0 block device files 1 fifo 0 links 1277 symbolic links (1277 fast symbolic links) 0 sockets ------------ 8640 files --->8--- The same command with old DMA driver took 23 minutes. There was no DMA errors. When retested the card on PC, there was: Inodes that were part of a corrupted orphan linked list found. Fix<y>? yes Inode 57554 was part of the orphaned inode list. FIXED. The card was mounted as readonly rootfs while fsck run on ARM, so there may be some background noise. Conclusions: 1. The card itself is fine. 2. There are issues with new DMA driver. I am ready to test patches, without questions. 3. There are issues with the MMC stack in my ARM device. Please drop a pointer where to start digging. ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use 2013-12-10 10:25 ` Sergei Ianovich @ 2013-12-10 10:48 ` Daniel Mack 2013-12-10 15:04 ` Sergei Ianovich 0 siblings, 1 reply; 8+ messages in thread From: Daniel Mack @ 2013-12-10 10:48 UTC (permalink / raw) To: linux-arm-kernel On 12/10/2013 11:25 AM, Sergei Ianovich wrote: > On Tue, 2013-12-10 at 13:27 +0400, Sergei Ianovich wrote: >> The device works in general, but it is slower than with the old DMA >> and it reports sporadic failures like that > > This took 40 minutes on my ARM device: [...] > The same card immediately after on my x86_64 PC, in 2 minutes: [...] > The same command with old DMA driver took 23 minutes. There was no DMA > errors. I'd say something like bonnie++ is a more deterministic test for such things, considering that the first fsck might have fixed things that the 2nd didn't have to touch. Apart from that, your findings are interesting. I only tested pxamci with a Wifi card connected via SDIO, and didn't see such a big difference in performance. > Conclusions: > 1. The card itself is fine. > > 2. There are issues with new DMA driver. I am ready to test patches, > without questions. > > 3. There are issues with the MMC stack in my ARM device. Please drop a > pointer where to start digging. Alright, thanks a lot for offering help! You could start having a look at the DMA descriptors and see whether they differ in size, compared to the old implementation. Taking time stamps to measure the turnaround cycle of the transfers would be another thing that you can try. I'm not aware of any code in the mmp_pdma driver that would burn lots of CPU cycles, but that doesn't mean there aren't any. Daniel ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use 2013-12-10 10:48 ` Daniel Mack @ 2013-12-10 15:04 ` Sergei Ianovich 0 siblings, 0 replies; 8+ messages in thread From: Sergei Ianovich @ 2013-12-10 15:04 UTC (permalink / raw) To: linux-arm-kernel On Tue, 2013-12-10 at 11:48 +0100, Daniel Mack wrote: > I'd say something like bonnie++ is a more deterministic test for such > things, considering that the first fsck might have fixed things that the > 2nd didn't have to touch. The old driver: Version 1.96 ------Sequential Output------ --Sequential Input- --Random- Concurrency 1 -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP pac26 300M 41 81 280 1 246 2 278 96 3056 10 99.2 23 Latency 1424ms 1054ms 510ms 95978us 86277us 3510ms Version 1.96 ------Sequential Create------ --------Random Create-------- pac26 -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 354 42 16254 97 325 10 490 30 +++++ +++ 1320 37 Latency 2354ms 48094us 6165ms 2979ms 586us 1116us 1.96,1.96,pac26,1,1386675098,300M,,41,81,280,1,246,2,278,96,3056,10,99.2,23,16,,,,,354,42,16254,97,325,10,490,30,+++++,+++,1320,37,1424ms,1054ms,510ms,95978us,86277us,3510ms,2354ms,48094us,6165ms,2979ms,586us,1116us The new driver: Version 1.96 ------Sequential Output------ --Sequential Input- --Random- Concurrency 1 -Per Chr- --Block-- -Rewrite- -Per Chr- --Block-- --Seeks-- Machine Size K/sec %CP K/sec %CP K/sec %CP K/sec %CP K/sec %CP /sec %CP pac26 300M 38 77 0 0 218 2 267 93 1762 6 84.0 19 Latency 2522ms 138668225 792ms 67960us 141ms 16313ms Version 1.96 ------Sequential Create------ --------Random Create-------- pac26 -Create-- --Read--- -Delete-- -Create-- --Read--- -Delete-- files /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP /sec %CP 16 304 38 14930 95 383 13 525 31 +++++ +++ 1042 28 Latency 13481ms 49916us 7144ms 4075ms 624us 993us 1.96,1.96,pac26,1,1639,300M,,38,77,0,0,218,2,267,93,1762,6,84.0,19,16,,,,,304,38,14930,95,383,13,525,31,+++++,+++,1042,28,2522ms,138668225,792ms,67960us,141ms,16313ms,13481ms,49916us,7144ms,4075ms,624us,993us I forgot to run 'time bonnie++', so there is no hard numbers about total time. My impression is that the old and new driver tests have run for 30 and 60 minutes respectively. > Apart from that, your findings are interesting. I only tested pxamci > with a Wifi card connected via SDIO, and didn't see such a big > difference in performance. > > > Conclusions: > > 1. The card itself is fine. > > > > 2. There are issues with new DMA driver. I am ready to test patches, > > without questions. > > > > 3. There are issues with the MMC stack in my ARM device. Please drop a > > pointer where to start digging. > > Alright, thanks a lot for offering help! You could start having a look > at the DMA descriptors and see whether they differ in size, compared to > the old implementation. Taking time stamps to measure the turnaround > cycle of the transfers would be another thing that you can try. > > I'm not aware of any code in the mmp_pdma driver that would burn lots of > CPU cycles, but that doesn't mean there aren't any. I can test patches, but I am not sure I can provide any meaningful help with performance. Sorry. In point 3 I was talking about non-DMA related performance. The device has been busy running bonnie++, so I haven't had a change to verify. It looks like my device is working with 1-bit-wide bus instead of 4-bit-wide (Bad block checking ran at 19500000 bits per second which matches bus clock speed). ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 00/20] ARM: pxa: move core and drivers to dmaengine @ 2013-08-07 15:33 Daniel Mack 2013-08-07 15:33 ` [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use Daniel Mack 0 siblings, 1 reply; 8+ messages in thread From: Daniel Mack @ 2013-08-07 15:33 UTC (permalink / raw) To: linux-arm-kernel I've been working on teaching the mmp-pdma driver more functions and porting tree-wide scattered pxa specific drivers over to dmaengine implementations. I posted the first round of patches for mmp-pdma here: http://marc.info/?l=linux-arm-kernel&m=137587082530228 With the following patches applied, I can boot a PXA3xx board boot with all DMA runtime information determined from DT, using pxa3xx-nand, pxamci and audio components (cyclic DMA). However, the transition is quite intrusive and spans across several subsystem, and due to the nature of the current pxa DMA implementation, it cannot be gap-less. All drivers currently request an exclusive channel via code in arch/arm/plat-pxa/dma.c and then do direct register modifications regarding their obtained channel. We can't allow this with the mmp-pdma driver of course, and I also have no idea how to provide sane stubs for the existing hooks which end up in dmaengine calls. Hence, all drivers have to be ported over in one series, and all these changes should be merged by one pull request eventually in order to prevent both build and functional breakage. Haojian's repository seems most suitable for that, as he's the PXA maintainer. What I currently got with respect to existing drivers is the following: * pxa3xx-nand: ported (with an amended and rebased patch from Zhangfei Gao) and successfully tested. * pxamci (mmc): ported and successfully tested * pxa-pcm-lib (audio) and pxa-ssp: ported and successfully tested * spi: Code to make this driver compatible with dmaengine was already provided by Mika Westerberg, so we can now just purge the legacy bits. I personally only compile-tested this one. * pxa-serial: #if0'ed legacy was removed that wouldn't even compile when enabled. This can be re-done at some point if anyone's interested. * pata-pxa: I ported the driver over which was simple and straight forward, but I lack hardware to actually test it. Maybe Marek Vasut, the original author can help here? * pxaficp_ir (IRDA): I also ported this driver, but I can't test it either. Someone with access to hardware would greatly help here with a quick test. * smsc911x: There are three(!) SMSC 911x driver in the tree right now, and two of them have code for PXA-DMA. I'm not sure which of these are actually actively used in DMA mode, but I blindly ported over the code and compile-tested it. * camera driver: I started the transition, but I'm not sure how much sense that makes without access to the hardware. I'd much appreciate if anyone could volunteer for this piece; I'll happily share what I got so far. Sascha, Sachin, Guennadi? So, to summarize: pata-pxa, pxaficp_ir and smsc911x need testing, and the camera driver still needs to be ported. The transition path of my patch set is as follows: 1. port over all the drivers individually, breaking them functionally because at runtime, they DMA channel allocation will fail. But they will compile. 2. remove the init calls to the dma subsystem in both mach-pxa and mach-mmp (mach-mmp was only compile-tested) and instanciate the mmp-pdma device as regular platform_device. 3. remove the old implementation including its header file that has served us so well for 12+ years. Sorry, Nicolas ;) Regarding the procedure, my proposal is that many people give their Tested-by and Acked-by, I'll respin my series a couple of times and eventually Haojian can take it. Prerequisities: * Linux-3.11-rc4 * Ezequiel Garcia's pxa3xx-patches: http://lists.infradead.org/pipermail/linux-mtd/2013-August/047862.html * My mmp-pdma patches: http://marc.info/?l=linux-arm-kernel&m=137587082530228 FWIW, the patches can also be found in this tree, but be aware that I will rebase the commits frequently: https://github.com/zonque/linux/commits/pxa-dma Thanks, Daniel Daniel Mack (19): mtd: pxa3xx-nand: use mmp_pdma_filter_fn and dma_request_slave_channel_compat ARM: pxa: ssp: add shortcut for &pdev->dev ARM: pxa: ssp: add DT bindings ARM: pxa: ssp: use devm_ functions tty: serial: pxa: remove old cruft spi: spi-pxa2xx: remove legacy PXA DMA bits mmc: host: pxamci: switch over to dmaengine use ata: pdata_pxa: migrate over to dmaengine usage net: irda: pxaficp_ir: switch to dmaengine net: smc91x.c: switch to generic buf-to-buf DMA offload net: smc911x.c: switch to dmaengine API ASoC: pxa: pxa-ssp: add DT bindings ASoC: pxa: use snd_dmaengine_dai_dma_data ASoC: pxa: pxa-ssp: set dma filter data from startup hook ASoC: pxa: add DT bindings for pxa2xx-pcm ASoC: pxa: pxa-pcm-lib: switch over to snd-soc-dmaengine-pcm ARM: pxa: register static mmp_pdma device ARM: mmp: register static mmp_pdma device ARM: pxa: remove old DMA implementation Zhangfei Gao (1): mtd: pxa3xx-nand: replace pxa_request_dma with dmaengine .../devicetree/bindings/serial/mrvl,pxa-ssp.txt | 43 ++ .../devicetree/bindings/sound/mrvl,pxa-ssp.txt | 7 + .../devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt | 15 + arch/arm/mach-mmp/mmp2.c | 11 +- arch/arm/mach-mmp/pxa168.c | 11 +- arch/arm/mach-mmp/pxa910.c | 11 +- arch/arm/mach-pxa/devices.c | 26 ++ arch/arm/mach-pxa/devices.h | 1 + arch/arm/mach-pxa/include/mach/dma.h | 21 - arch/arm/mach-pxa/pxa25x.c | 9 +- arch/arm/mach-pxa/pxa27x.c | 9 +- arch/arm/mach-pxa/pxa3xx.c | 11 +- arch/arm/plat-pxa/Makefile | 2 - arch/arm/plat-pxa/dma.c | 391 ---------------- arch/arm/plat-pxa/include/plat/dma.h | 85 ---- arch/arm/plat-pxa/ssp.c | 144 +++--- drivers/ata/pata_pxa.c | 172 +++----- drivers/mmc/host/pxamci.c | 188 ++++---- drivers/mtd/nand/pxa3xx_nand.c | 130 +++--- drivers/net/ethernet/smsc/smc911x.c | 80 ++-- drivers/net/ethernet/smsc/smc911x.h | 83 ++-- drivers/net/ethernet/smsc/smc91x.c | 40 +- drivers/net/ethernet/smsc/smc91x.h | 71 ++- drivers/net/irda/pxaficp_ir.c | 242 ++++++---- drivers/spi/Kconfig | 9 +- drivers/spi/Makefile | 1 - drivers/spi/spi-pxa2xx-pxadma.c | 490 --------------------- drivers/spi/spi-pxa2xx.h | 6 +- drivers/tty/serial/pxa.c | 25 -- include/linux/spi/pxa2xx_spi.h | 1 - include/sound/pxa2xx-lib.h | 8 - sound/arm/Kconfig | 1 + sound/arm/pxa2xx-ac97.c | 26 +- sound/arm/pxa2xx-pcm-lib.c | 177 ++------ sound/arm/pxa2xx-pcm.c | 15 +- sound/arm/pxa2xx-pcm.h | 9 +- sound/soc/pxa/mmp-pcm.c | 8 +- sound/soc/pxa/mmp-sspa.c | 11 +- sound/soc/pxa/pxa-ssp.c | 51 ++- sound/soc/pxa/pxa2xx-ac97.c | 67 +-- sound/soc/pxa/pxa2xx-i2s.c | 28 +- sound/soc/pxa/pxa2xx-pcm.c | 43 +- 42 files changed, 921 insertions(+), 1858 deletions(-) create mode 100644 Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt create mode 100644 Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt create mode 100644 Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt delete mode 100644 arch/arm/mach-pxa/include/mach/dma.h delete mode 100644 arch/arm/plat-pxa/dma.c delete mode 100644 arch/arm/plat-pxa/include/plat/dma.h delete mode 100644 drivers/spi/spi-pxa2xx-pxadma.c -- 1.8.3.1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use 2013-08-07 15:33 [PATCH 00/20] ARM: pxa: move core and drivers to dmaengine Daniel Mack @ 2013-08-07 15:33 ` Daniel Mack 2014-10-15 18:32 ` Vasily Khoruzhick 0 siblings, 1 reply; 8+ messages in thread From: Daniel Mack @ 2013-08-07 15:33 UTC (permalink / raw) To: linux-arm-kernel Successfully testes on a PXA3xx board. 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 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use 2013-08-07 15:33 ` [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use Daniel Mack @ 2014-10-15 18:32 ` Vasily Khoruzhick 2014-10-16 17:57 ` Vasily Khoruzhick 0 siblings, 1 reply; 8+ 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] 8+ messages in thread
* [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 0 siblings, 0 replies; 8+ 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] 8+ messages in thread
end of thread, other threads:[~2014-10-16 17:57 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-12-10 9:24 [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use Sergei Ianovich [not found] <1375889649-14638-9-git-send-email-zonque> 2013-12-10 9:27 ` Sergei Ianovich 2013-12-10 10:25 ` Sergei Ianovich 2013-12-10 10:48 ` Daniel Mack 2013-12-10 15:04 ` Sergei Ianovich -- strict thread matches above, loose matches on Subject: below -- 2013-08-07 15:33 [PATCH 00/20] ARM: pxa: move core and drivers to dmaengine Daniel Mack 2013-08-07 15:33 ` [PATCH 08/20] mmc: host: pxamci: switch over to dmaengine use Daniel Mack 2014-10-15 18:32 ` Vasily Khoruzhick 2014-10-16 17:57 ` Vasily Khoruzhick
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).