Re: [PATCH] dw_spi: add DMA support
On Tue, 30 Nov 2010 23:13:22 +0800 Linus Walleij linus.wall...@stericsson.com wrote: 2010/11/23 Feng Tang feng.t...@intel.com: Thanks for the reviews, I made some dma change as you suggested, pls help to review. This is looking much better. I guess there is a corresponding patch to drivers/dma/* to provide the proper interfaces for this to work? Anyway, Acked-by: Linus Walleij linus.wall...@stericsson.com Yes, there will be some changed to the corresponding dma driver. Thanks again for the review - Feng Yours, Linus Walleij -- Increase Visibility of Your 3D Game App Earn a Chance To Win $500! Tap into the largest installed PC base get more eyes on your game by optimizing for Intel(R) Graphics Technology. Get started today with the Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs. http://p.sf.net/sfu/intelisp-dev2dev ___ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general
Re: [PATCH] dw_spi: add DMA support
2010/11/23 Feng Tang feng.t...@intel.com: Thanks for the reviews, I made some dma change as you suggested, pls help to review. This is looking much better. I guess there is a corresponding patch to drivers/dma/* to provide the proper interfaces for this to work? Anyway, Acked-by: Linus Walleij linus.wall...@stericsson.com Yours, Linus Walleij -- Increase Visibility of Your 3D Game App Earn a Chance To Win $500! Tap into the largest installed PC base get more eyes on your game by optimizing for Intel(R) Graphics Technology. Get started today with the Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs. http://p.sf.net/sfu/intelisp-dev2dev ___ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general
Re: [PATCH] dw_spi: add DMA support
On Tue, 23 Nov 2010 14:48:39 +0800 Linus Walleij linus.ml.wall...@gmail.com wrote: This is much better than last time but I still have questions... 2010/11/18 Alan Cox a...@lxorguk.ukuu.org.uk: + /* 1. Init rx channel */ + rxs = dw_dma-dmas_rx; + ds = rxs-dma_slave; + ds-direction = DMA_FROM_DEVICE; + rxs-hs_mode = LNW_DMA_HW_HS; + rxs-cfg_mode = LNW_DMA_PER_TO_MEM; + ds-src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ds-dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + ds-src_maxburst = 16; + ds-dst_maxburst = 16; This is great stuff! That is exactly how ds is to be set up. I would prefer that you don't dereference the this rxs thing here but whatever. + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_SLAVE, mask); This is not elegant. Are you going to do memcpy() or slave transfers? What you want to do is fix your DMA engine so that just asking for DMA_SLAVE works. + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_MEMCPY, mask); Here again... +static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) +{ (...) + flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; + if (dws-tx_dma) { + txdesc = txchan-device-device_prep_dma_memcpy(txchan, + dws-dma_addr, dws-tx_dma, + dws-len, flag); + txdesc-callback = dw_spi_dma_done; + txdesc-callback_param = dws-tx_param; + } + + /* 3. start the RX dma transfer */ + if (dws-rx_dma) { + rxdesc = rxchan-device-device_prep_dma_memcpy(rxchan, + dws-rx_dma, dws-dma_addr, + dws-len, flag); + rxdesc-callback = dw_spi_dma_done; + rxdesc-callback_param = dws-rx_param; + } Using device_prep_dma_memcpy() for this is still nonsense, it should be device_prep_slave_sg(). I know the DMA driver needs fixing in order for this to work properly, so why not fix it? These are the most important concerns I raised last iteration, so I challenge you to fix drivers/dma/dw_dmac.c or wherever the real problem sits. Can you describe where the problem with fixing this to use real slave sglists is? Yours, Linus Walleij Hi Linus, Thanks for the reviews, I made some dma change as you suggested, pls help to review. Thanks, Feng From b77efc5945e31442b53b285d6a3f77def376ebb3 Mon Sep 17 00:00:00 2001 From: Feng Tang feng.t...@intel.com Date: Tue, 23 Nov 2010 17:34:28 +0800 Subject: [PATCH] spi/dw_spi: add DMA support dw_spi driver in upstream only supports PIO mode, and this patch will support it to cowork with the Designware DMA controller used on Intel Moorestown platform It has been tested with a Option GTM501L 3G modem, to use DMA mode, DMA controller 2 of Moorestown has to be enabled Signed-off-by: Feng Tang feng.t...@intel.com [Typo fix and renames to match intel_mid_dma renaming] Signed-off-by: Vinod Koul vinod.k...@intel.com [Clean up, change dma interface suggested by Linus Walleij] Signed-off-by: Feng Tang feng.t...@intel.com [Fix timing delay, add cpu_relax] Signed-off-by: Arjan van de Ven ar...@linux.intel.com Signed-off-by: Alan Cox a...@linux.intel.com --- drivers/spi/Kconfig|4 + drivers/spi/Makefile |3 +- drivers/spi/dw_spi.c | 48 ++ drivers/spi/dw_spi_mid.c | 225 drivers/spi/dw_spi_pci.c | 14 ++- include/linux/spi/dw_spi.h | 24 - 6 files changed, 288 insertions(+), 30 deletions(-) create mode 100644 drivers/spi/dw_spi_mid.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 78f9fd0..d53c830 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -396,6 +396,10 @@ config SPI_DW_PCI tristate PCI interface driver for DW SPI core depends on SPI_DESIGNWARE PCI +config SPI_DW_MID_DMA + bool DMA support for DW SPI controller on Intel Moorestown platform + depends on SPI_DW_PCI INTEL_MID_DMAC + config SPI_DW_MMIO tristate Memory-mapped io interface driver for DW SPI core depends on SPI_DESIGNWARE HAVE_CLK diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 8bc1a5a..5e6e812 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,7 +17,8 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_COLDFIRE_QSPI)+= coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o -obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o +obj-$(CONFIG_SPI_DW_PCI) += dw_spi_midpci.o +dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.o obj-$(CONFIG_SPI_DW_MMIO)
Re: [PATCH] dw_spi: add DMA support
This is much better than last time but I still have questions... 2010/11/18 Alan Cox a...@lxorguk.ukuu.org.uk: + /* 1. Init rx channel */ + rxs = dw_dma-dmas_rx; + ds = rxs-dma_slave; + ds-direction = DMA_FROM_DEVICE; + rxs-hs_mode = LNW_DMA_HW_HS; + rxs-cfg_mode = LNW_DMA_PER_TO_MEM; + ds-src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ds-dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + ds-src_maxburst = 16; + ds-dst_maxburst = 16; This is great stuff! That is exactly how ds is to be set up. I would prefer that you don't dereference the this rxs thing here but whatever. + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_SLAVE, mask); This is not elegant. Are you going to do memcpy() or slave transfers? What you want to do is fix your DMA engine so that just asking for DMA_SLAVE works. + dma_cap_set(DMA_SLAVE, mask); + dma_cap_set(DMA_MEMCPY, mask); Here again... +static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) +{ (...) + flag = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; + if (dws-tx_dma) { + txdesc = txchan-device-device_prep_dma_memcpy(txchan, + dws-dma_addr, dws-tx_dma, + dws-len, flag); + txdesc-callback = dw_spi_dma_done; + txdesc-callback_param = dws-tx_param; + } + + /* 3. start the RX dma transfer */ + if (dws-rx_dma) { + rxdesc = rxchan-device-device_prep_dma_memcpy(rxchan, + dws-rx_dma, dws-dma_addr, + dws-len, flag); + rxdesc-callback = dw_spi_dma_done; + rxdesc-callback_param = dws-rx_param; + } Using device_prep_dma_memcpy() for this is still nonsense, it should be device_prep_slave_sg(). I know the DMA driver needs fixing in order for this to work properly, so why not fix it? These are the most important concerns I raised last iteration, so I challenge you to fix drivers/dma/dw_dmac.c or wherever the real problem sits. Can you describe where the problem with fixing this to use real slave sglists is? Yours, Linus Walleij -- Increase Visibility of Your 3D Game App Earn a Chance To Win $500! Tap into the largest installed PC base get more eyes on your game by optimizing for Intel(R) Graphics Technology. Get started today with the Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs. http://p.sf.net/sfu/intelisp-dev2dev ___ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general
[PATCH] dw_spi: add DMA support
From: Feng Tang feng.t...@intel.com dw_spi driver in upstream only supports PIO mode, and this patch will support it to cowork with the Designware DMA controller used on Intel Moorestown platform It has been tested with a Option GTM501L 3G modem, to use DMA mode, DMA controller 2 of Moorestown has to be enabled Signed-off-by: Feng Tang feng.t...@intel.com [Typo fix and renames to match intel_mid_dma renaming] Signed-off-by: Vinod Koul vinod.k...@intel.com [Clean up] Signed-off-by: Feng Tang feng.t...@intel.com [Fix timing delay, add cpu_relax] Signed-off-by: Arjan van de Ven ar...@linux.intel.com Signed-off-by: Alan Cox a...@linux.intel.com --- drivers/spi/Kconfig|4 + drivers/spi/Makefile |3 - drivers/spi/dw_spi.c | 48 + drivers/spi/dw_spi_mid.c | 246 drivers/spi/dw_spi_pci.c | 14 ++- include/linux/spi/dw_spi.h | 15 +++ 6 files changed, 305 insertions(+), 25 deletions(-) create mode 100644 drivers/spi/dw_spi_mid.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 82e45cf..6e6a638 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -404,6 +404,10 @@ config SPI_DW_PCI tristate PCI interface driver for DW SPI core depends on SPI_DESIGNWARE PCI +config SPI_DW_MID_DMA + bool DMA support for DW SPI controller on Intel Moorestown platform + depends on SPI_DW_PCI INTEL_MID_DMAC + config SPI_DW_MMIO tristate Memory-mapped io interface driver for DW SPI core depends on SPI_DESIGNWARE HAVE_CLK diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b427c2e..4949370 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,7 +17,8 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_COLDFIRE_QSPI)+= coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o -obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o +obj-$(CONFIG_SPI_DW_PCI) += dw_spi_midpci.o +dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.o obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 9043931..69cc223 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) static void wait_till_not_busy(struct dw_spi *dws) { - unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); + unsigned long end = jiffies + 1 + usecs_to_jiffies(5000); while (time_before(jiffies, end)) { if (!(dw_readw(dws, sr) SR_BUSY)) return; + cpu_relax(); } dev_err(dws-master-dev, - DW SPI: Status keeps busy for 1000us after a read/write!\n); + DW SPI: Status keeps busy for 5000us after a read/write!\n); } static void flush(struct dw_spi *dws) { - while (dw_readw(dws, sr) SR_RF_NOT_EMPT) + while (dw_readw(dws, sr) SR_RF_NOT_EMPT) { dw_readw(dws, dr); + cpu_relax(); + } wait_till_not_busy(dws); } @@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws) */ static int map_dma_buffers(struct dw_spi *dws) { - if (!dws-cur_msg-is_dma_mapped || !dws-dma_inited - || !dws-cur_chip-enable_dma) + if (!dws-cur_msg-is_dma_mapped + || !dws-dma_inited + || !dws-cur_chip-enable_dma + || !dws-dma_ops) return 0; if (dws-cur_transfer-tx_dma) @@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg) tasklet_schedule(dws-pump_transfers); } -static void transfer_complete(struct dw_spi *dws) +void dw_spi_xfer_done(struct dw_spi *dws) { /* Update total byte transfered return count actual bytes read */ dws-cur_msg-actual_length += dws-len; @@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws) } else tasklet_schedule(dws-pump_transfers); } +EXPORT_SYMBOL_GPL(dw_spi_xfer_done); static irqreturn_t interrupt_transfer(struct dw_spi *dws) { @@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) if (dws-tx_end dws-tx) spi_umask_intr(dws, SPI_INT_TXEI); else - transfer_complete(dws); + dw_spi_xfer_done(dws); } return IRQ_HANDLED; @@ -414,11 +420,7 @@ static void poll_transfer(struct dw_spi *dws) while (dws-write(dws)) dws-read(dws); - transfer_complete(dws); -} - -static void dma_transfer(struct dw_spi *dws, int cs_change) -{ + dw_spi_xfer_done(dws); }
Re: [PATCH] dw_spi: add DMA support
There *is* a generic runtime channel control interface as of kernel 2.6.36. Compare to this snippet from the PL022 DMA Not when this driver was done. support that was merged into becoming 2.6.37 a day ago or so (behold the beauty in drivers/spi/amba-pl022.c): Funnily enough I've already moved to using the proper fields in the next version of all the DMA using patches so that bit is cool, but I've not done the other stuff you then point out so I'll go through your example and tidy up. -- Nokia and ATT present the 2010 Calling All Innovators-North America contest Create new apps games for the Nokia N8 for consumers in U.S. and Canada $10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store http://p.sf.net/sfu/nokia-dev2dev ___ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general
Re: [PATCH] dw_spi: add DMA support
2010/10/22 Alan Cox a...@lxorguk.ukuu.org.uk: (...) +static int mid_spi_dma_init(struct dw_spi *dws) +{ + struct mid_dma *dw_dma = dws-dma_priv; + struct intel_mid_dma_slave *rxs, *txs; + dma_cap_mask_t mask; + + dws-txchan = NULL; + dws-rxchan = NULL; + + /*get pci device for DMA*/ + dws-dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x813, NULL); + + /* 1. Init rx channel */ + rxs = dw_dma-dmas_rx; + + rxs-dirn = DMA_FROM_DEVICE; + rxs-hs_mode = LNW_DMA_HW_HS; + rxs-cfg_mode = LNW_DMA_PER_TO_MEM; + rxs-src_width = LNW_DMA_WIDTH_16BIT; + rxs-dst_width = LNW_DMA_WIDTH_32BIT; + rxs-src_msize = LNW_DMA_MSIZE_16; + rxs-dst_msize = LNW_DMA_MSIZE_16; Hm, hm hm. You go configure these channel characteristics by derferencing and writing private data. There *is* a generic runtime channel control interface as of kernel 2.6.36. Compare to this snippet from the PL022 DMA support that was merged into becoming 2.6.37 a day ago or so (behold the beauty in drivers/spi/amba-pl022.c): struct dma_slave_config rx_conf = { .src_addr = SSP_DR(pl022-phybase), .direction = DMA_FROM_DEVICE, .src_maxburst = pl022-vendor-fifodepth 1, }; (...) struct dma_chan *rxchan = pl022-dma_rx_channel; (...) switch (pl022-read) { case READING_NULL: /* Use the same as for writing */ rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; break; case READING_U8: rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; break; case READING_U16: rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; break; case READING_U32: rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; break; } rxchan-device-device_control(rxchan, DMA_SLAVE_CONFIG, (unsigned long) rx_conf); I don't know if I'm particularly biased by being infatuated by my own interface, but can't you just implement the DMA_SLAVE_CONFIG command for the DW DMA controller instead of this custom stuff? + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + dma_cap_set(DMA_SLAVE, mask); What are you doing? Normally you want *either* a memcpy channel (which wouldn't require the kind of setup you do above, hell memcpy shan't be any different from the C library function memcpy()!) *or* you want a slave channel. Most probably you should drop dma_cap_set(DMA_MEMCPY, mask), if it is needed your DMAengine driver is likely weird. Then I think I get the answer later on: + dws-rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws); Aha generic DMA engine, that's cool! :) So then again, use the DMA-engine configuration mechanism, and get the slave channel will ya? (...) +static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change) (...) + /* 3. start the RX dma transfer */ + if (dws-rx_dma) { + rxdesc = rxchan-device-device_prep_dma_memcpy(rxchan, + dws-rx_dma, dws-dma_addr, + dws-len, flag); So you're still using the memcpy() prepare function in order to be able to supply the endpoint address. Incidentally, that is an additional argument that you can pass to the generic channel control mechanism using .src_addr/.dst_addr respectively. And the DW controller does *indeed* have a device_prep_slave_sg hook. My recommendation: put generic channel control into the DMA driver you're using and inspect amba-pl022.c for an idea on how to do this. Since the .device_prep_slave_sg command only takes SGlists you will have to wrap your buffers in SGlists but I'm working on a simplifying wrapper for that. Yours, Linus Walleij -- Nokia and ATT present the 2010 Calling All Innovators-North America contest Create new apps games for the Nokia N8 for consumers in U.S. and Canada $10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store http://p.sf.net/sfu/nokia-dev2dev ___ spi-devel-general mailing list spi-devel-general@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/spi-devel-general
[PATCH] dw_spi: add DMA support
From: Feng Tang feng.t...@intel.com dw_spi driver in upstream only supports PIO mode, and this patch will support it to cowork with the Designware DMA controller used on Intel Moorestown platform It has been tested with a Option GTM501L 3G modem, to use DMA mode, DMA controller 2 of Moorestown has to be enabled Signed-off-by: Feng Tang feng.t...@intel.com [Typo fix and renames to match intel_mid_dma renaming] Signed-off-by: Vinod Koul vinod.k...@intel.com [Clean up] Signed-off-by: Feng Tang feng.t...@intel.com [Fix timing delay, add cpu_relax] Signed-off-by: Arjan van de Ven ar...@linux.intel.com Signed-off-by: Alan Cox a...@linux.intel.com --- drivers/spi/Kconfig|4 + drivers/spi/Makefile |3 - drivers/spi/dw_spi.c | 48 + drivers/spi/dw_spi_mid.c | 243 drivers/spi/dw_spi_pci.c | 14 ++- include/linux/spi/dw_spi.h | 15 +++ 6 files changed, 302 insertions(+), 25 deletions(-) create mode 100644 drivers/spi/dw_spi_mid.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 82e45cf..6e6a638 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -404,6 +404,10 @@ config SPI_DW_PCI tristate PCI interface driver for DW SPI core depends on SPI_DESIGNWARE PCI +config SPI_DW_MID_DMA + bool DMA support for DW SPI controller on Intel Moorestown platform + depends on SPI_DW_PCI INTEL_MID_DMAC + config SPI_DW_MMIO tristate Memory-mapped io interface driver for DW SPI core depends on SPI_DESIGNWARE HAVE_CLK diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index b427c2e..4949370 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,7 +17,8 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o obj-$(CONFIG_SPI_COLDFIRE_QSPI)+= coldfire_qspi.o obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o -obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o +obj-$(CONFIG_SPI_DW_PCI) += dw_spi_midpci.o +dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.o obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c index 9043931..69cc223 100644 --- a/drivers/spi/dw_spi.c +++ b/drivers/spi/dw_spi.c @@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) static void wait_till_not_busy(struct dw_spi *dws) { - unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); + unsigned long end = jiffies + 1 + usecs_to_jiffies(5000); while (time_before(jiffies, end)) { if (!(dw_readw(dws, sr) SR_BUSY)) return; + cpu_relax(); } dev_err(dws-master-dev, - DW SPI: Status keeps busy for 1000us after a read/write!\n); + DW SPI: Status keeps busy for 5000us after a read/write!\n); } static void flush(struct dw_spi *dws) { - while (dw_readw(dws, sr) SR_RF_NOT_EMPT) + while (dw_readw(dws, sr) SR_RF_NOT_EMPT) { dw_readw(dws, dr); + cpu_relax(); + } wait_till_not_busy(dws); } @@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws) */ static int map_dma_buffers(struct dw_spi *dws) { - if (!dws-cur_msg-is_dma_mapped || !dws-dma_inited - || !dws-cur_chip-enable_dma) + if (!dws-cur_msg-is_dma_mapped + || !dws-dma_inited + || !dws-cur_chip-enable_dma + || !dws-dma_ops) return 0; if (dws-cur_transfer-tx_dma) @@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg) tasklet_schedule(dws-pump_transfers); } -static void transfer_complete(struct dw_spi *dws) +void dw_spi_xfer_done(struct dw_spi *dws) { /* Update total byte transfered return count actual bytes read */ dws-cur_msg-actual_length += dws-len; @@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws) } else tasklet_schedule(dws-pump_transfers); } +EXPORT_SYMBOL_GPL(dw_spi_xfer_done); static irqreturn_t interrupt_transfer(struct dw_spi *dws) { @@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) if (dws-tx_end dws-tx) spi_umask_intr(dws, SPI_INT_TXEI); else - transfer_complete(dws); + dw_spi_xfer_done(dws); } return IRQ_HANDLED; @@ -414,11 +420,7 @@ static void poll_transfer(struct dw_spi *dws) while (dws-write(dws)) dws-read(dws); - transfer_complete(dws); -} - -static void dma_transfer(struct dw_spi *dws, int cs_change) -{ + dw_spi_xfer_done(dws); }