From 6b8ac10e0dd4b49eda513c1aa5045b3b1660d350 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Jul 2019 11:15:41 -0700 Subject: spi: Remove dev_err() usage after platform_get_irq() We don't need dev_err() messages when platform_get_irq() fails now that platform_get_irq() prints an error message itself when something goes wrong. Let's remove these prints with a simple semantic patch. // @@ expression ret; struct platform_device *E; @@ ret = ( platform_get_irq(E, ...) | platform_get_irq_byname(E, ...) ); if ( \( ret < 0 \| ret <= 0 \) ) { ( -if (ret != -EPROBE_DEFER) -{ ... -dev_err(...); -... } | ... -dev_err(...); ) ... } // While we're here, remove braces on if statements that only have one statement (manually). Cc: Mark Brown Cc: linux-spi@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20190730181557.90391-42-swboyd@chromium.org Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 6f243a90c844..c96797844688 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1015,7 +1015,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) bs->irq = platform_get_irq(pdev, 0); if (bs->irq <= 0) { - dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq); err = bs->irq ? bs->irq : -ENODEV; goto out_controller_put; } -- cgit v1.2.3 From 3bd158c56a56e8767e569d7fbc66efbedc478077 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 4 Aug 2019 02:38:52 +0200 Subject: spi: bcm2835: Convert to use CS GPIO descriptors This converts the BCM2835 SPI master driver to use GPIO descriptors for chip select handling. The BCM2835 driver was relying on the core to drive the CS high/low so very small changes were needed for this part. If it managed to request the CS from the device tree node, all is pretty straight forward. However for native GPIOs this driver has a quite unorthodox loopback to request some GPIOs from the SoC GPIO chip by looking it up from the device tree using gpiochip_find() and then offseting hard into its numberspace. This has been augmented a bit by using gpiochip_request_own_desc() but this code really needs to be verified. If "native CS" is actually an SoC GPIO, why is it even done this way? Should this GPIO not just be defined in the device tree like any other CS GPIO? I'm confused. Cc: Lukas Wunner Cc: Stefan Wahren Cc: Martin Sperl Cc: Chris Boot Signed-off-by: Linus Walleij Link: https://lore.kernel.org/r/20190804003852.1312-1-linus.walleij@linaro.org Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 58 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 4b89e0a04ffd..fd2bfb4aa8c3 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -25,7 +25,9 @@ #include #include #include -#include +#include +#include /* FIXME: using chip internals */ +#include /* FIXME: using chip internals */ #include #include @@ -931,14 +933,19 @@ static int chip_match_name(struct gpio_chip *chip, void *data) static int bcm2835_spi_setup(struct spi_device *spi) { - int err; struct gpio_chip *chip; + enum gpio_lookup_flags lflags; + /* * sanity checking the native-chipselects */ if (spi->mode & SPI_NO_CS) return 0; - if (gpio_is_valid(spi->cs_gpio)) + /* + * The SPI core has successfully requested the CS GPIO line from the + * device tree, so we are done. + */ + if (spi->cs_gpiod) return 0; if (spi->chip_select > 1) { /* error in the case of native CS requested with CS > 1 @@ -949,29 +956,43 @@ static int bcm2835_spi_setup(struct spi_device *spi) "setup: only two native chip-selects are supported\n"); return -EINVAL; } - /* now translate native cs to GPIO */ + + /* + * Translate native CS to GPIO + * + * FIXME: poking around in the gpiolib internals like this is + * not very good practice. Find a way to locate the real problem + * and fix it. Why is the GPIO descriptor in spi->cs_gpiod + * sometimes not assigned correctly? Erroneous device trees? + */ /* get the gpio chip for the base */ chip = gpiochip_find("pinctrl-bcm2835", chip_match_name); if (!chip) return 0; - /* and calculate the real CS */ - spi->cs_gpio = chip->base + 8 - spi->chip_select; + /* + * Retrieve the corresponding GPIO line used for CS. + * The inversion semantics will be handled by the GPIO core + * code, so we pass GPIOS_OUT_LOW for "unasserted" and + * the correct flag for inversion semantics. The SPI_CS_HIGH + * on spi->mode cannot be checked for polarity in this case + * as the flag use_gpio_descriptors enforces SPI_CS_HIGH. + */ + if (of_property_read_bool(spi->dev.of_node, "spi-cs-high")) + lflags = GPIO_ACTIVE_HIGH; + else + lflags = GPIO_ACTIVE_LOW; + spi->cs_gpiod = gpiochip_request_own_desc(chip, 8 - spi->chip_select, + DRV_NAME, + lflags, + GPIOD_OUT_LOW); + if (IS_ERR(spi->cs_gpiod)) + return PTR_ERR(spi->cs_gpiod); /* and set up the "mode" and level */ - dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n", - spi->chip_select, spi->cs_gpio); - - /* set up GPIO as output and pull to the correct level */ - err = gpio_direction_output(spi->cs_gpio, - (spi->mode & SPI_CS_HIGH) ? 0 : 1); - if (err) { - dev_err(&spi->dev, - "could not set CS%i gpio %i as output: %i", - spi->chip_select, spi->cs_gpio, err); - return err; - } + dev_info(&spi->dev, "setting up native-CS%i to use GPIO\n", + spi->chip_select); return 0; } @@ -989,6 +1010,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ctlr); + ctlr->use_gpio_descriptors = true; ctlr->mode_bits = BCM2835_SPI_MODE_BITS; ctlr->bits_per_word_mask = SPI_BPW_MASK(8); ctlr->num_chipselect = 3; -- cgit v1.2.3 From 6ba794dfbb537719f96b8ba96c8bf73930969759 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Wed, 4 Sep 2019 21:58:48 +0800 Subject: spi: bcm2835: use devm_platform_ioremap_resource() to simplify code Use devm_platform_ioremap_resource() to simplify the code a bit. This is detected by coccinelle. Reported-by: Hulk Robot Signed-off-by: YueHaibing Link: https://lore.kernel.org/r/20190904135918.25352-7-yuehaibing@huawei.com Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index fd2bfb4aa8c3..fbd6d1ae4c5e 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -1001,7 +1001,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) { struct spi_controller *ctlr; struct bcm2835_spi *bs; - struct resource *res; int err; ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs)); @@ -1022,8 +1021,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) bs = spi_controller_get_devdata(ctlr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - bs->regs = devm_ioremap_resource(&pdev->dev, res); + bs->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bs->regs)) { err = PTR_ERR(bs->regs); goto out_controller_put; -- cgit v1.2.3 From 1513ceee70f2bd523e025efe0c715328e1a43ffd Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: spi: bcm2835: Drop dma_pending flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BCM2835 SPI driver uses a flag to keep track of whether a DMA transfer is in progress. The flag is used to avoid terminating DMA channels multiple times if a transfer finishes orderly while simultaneously the SPI core invokes the ->handle_err() callback because the transfer took too long. However terminating DMA channels multiple times is perfectly fine, so the flag is unnecessary for this particular purpose. The flag is also used to avoid invoking bcm2835_spi_undo_prologue() multiple times under this race condition. However multiple *concurrent* invocations can no longer happen since commit 2527704d8411 ("spi: bcm2835: Synchronize with callback on DMA termination") because the ->handle_err() callback now uses the _sync() variant when terminating DMA channels. The only raison d'être of the flag is therefore that bcm2835_spi_undo_prologue() cannot cope with multiple *sequential* invocations. Achieve that by setting tx_prologue to 0 at the end of the function. Subsequent invocations thus become no-ops. With that, the dma_pending flag becomes unnecessary, so drop it. Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Lukas Wunner Acked-by: Stefan Wahren Acked-by: Martin Sperl Link: https://lore.kernel.org/r/062b03b7f86af77a13ce0ec3b22e0bdbfcfba10d.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index fbd6d1ae4c5e..60255ac837f5 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -94,7 +94,6 @@ MODULE_PARM_DESC(polling_limit_us, * @rx_prologue: bytes received without DMA if first RX sglist entry's * length is not a multiple of 4 (to overcome hardware limitation) * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry - * @dma_pending: whether a DMA transfer is in progress * @debugfs_dir: the debugfs directory - neede to remove debugfs when * unloading the module * @count_transfer_polling: count of how often polling mode is used @@ -117,7 +116,6 @@ struct bcm2835_spi { int tx_prologue; int rx_prologue; unsigned int tx_spillover; - unsigned int dma_pending; struct dentry *debugfs_dir; u64 count_transfer_polling; @@ -541,6 +539,8 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs) sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4; sg_dma_len(&tfr->tx_sg.sgl[1]) += 4; } + + bs->tx_prologue = 0; } static void bcm2835_spi_dma_done(void *data) @@ -556,10 +556,8 @@ static void bcm2835_spi_dma_done(void *data) * is called the tx-dma must have finished - can't get to this * situation otherwise... */ - if (cmpxchg(&bs->dma_pending, true, false)) { - dmaengine_terminate_async(ctlr->dma_tx); - bcm2835_spi_undo_prologue(bs); - } + dmaengine_terminate_async(ctlr->dma_tx); + bcm2835_spi_undo_prologue(bs); /* and mark as completed */; complete(&ctlr->xfer_completion); @@ -634,9 +632,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, /* start TX early */ dma_async_issue_pending(ctlr->dma_tx); - /* mark as dma pending */ - bs->dma_pending = 1; - /* set the DMA length */ bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len); @@ -652,7 +647,6 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, if (ret) { /* need to reset on errors */ dmaengine_terminate_sync(ctlr->dma_tx); - bs->dma_pending = false; goto err_reset_hw; } @@ -917,11 +911,10 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr, struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); /* if an error occurred and we have an active dma, then terminate */ - if (cmpxchg(&bs->dma_pending, true, false)) { - dmaengine_terminate_sync(ctlr->dma_tx); - dmaengine_terminate_sync(ctlr->dma_rx); - bcm2835_spi_undo_prologue(bs); - } + dmaengine_terminate_sync(ctlr->dma_tx); + dmaengine_terminate_sync(ctlr->dma_rx); + bcm2835_spi_undo_prologue(bs); + /* and reset */ bcm2835_spi_reset_hw(ctlr); } -- cgit v1.2.3 From 571e31fa60b3697d5db26140e16d5c45c51c9815 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: spi: bcm2835: Cache CS register value for ->prepare_message() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BCM2835 SPI driver needs to set up the clock polarity in its ->prepare_message() hook before spi_transfer_one_message() asserts chip select to avoid a gratuitous clock signal edge (cf. commit acace73df2c1 ("spi: bcm2835: set up spi-mode before asserting cs-gpio")). Precalculate the CS register value (which selects the clock polarity) once in ->setup() and use that cached value in ->prepare_message() and ->transfer_one(). This avoids one MMIO read per message and one per transfer, yielding a small latency improvement. Additionally, a forthcoming commit will use the precalculated value to derive the register value for clearing the RX FIFO, which will eliminate the need for an RX dummy buffer when performing TX-only DMA transfers. Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Lukas Wunner Acked-by: Stefan Wahren Acked-by: Martin Sperl Link: https://lore.kernel.org/r/d17c1d7fcdc97fffa961b8737cfd80eeb14f9416.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 60255ac837f5..f01d18d521f2 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -68,6 +68,7 @@ #define BCM2835_SPI_FIFO_SIZE 64 #define BCM2835_SPI_FIFO_SIZE_3_4 48 #define BCM2835_SPI_DMA_MIN_LENGTH 96 +#define BCM2835_SPI_NUM_CS 3 /* raise as necessary */ #define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \ | SPI_NO_CS | SPI_3WIRE) @@ -94,6 +95,8 @@ MODULE_PARM_DESC(polling_limit_us, * @rx_prologue: bytes received without DMA if first RX sglist entry's * length is not a multiple of 4 (to overcome hardware limitation) * @tx_spillover: whether @tx_prologue spills over to second TX sglist entry + * @prepare_cs: precalculated CS register value for ->prepare_message() + * (uses slave-specific clock polarity and phase settings) * @debugfs_dir: the debugfs directory - neede to remove debugfs when * unloading the module * @count_transfer_polling: count of how often polling mode is used @@ -116,6 +119,7 @@ struct bcm2835_spi { int tx_prologue; int rx_prologue; unsigned int tx_spillover; + u32 prepare_cs[BCM2835_SPI_NUM_CS]; struct dentry *debugfs_dir; u64 count_transfer_polling; @@ -808,7 +812,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); unsigned long spi_hz, clk_hz, cdiv, spi_used_hz; unsigned long hz_per_byte, byte_limit; - u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); + u32 cs = bs->prepare_cs[spi->chip_select]; /* set clock */ spi_hz = tfr->speed_hz; @@ -833,15 +837,6 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, if (spi->mode & SPI_3WIRE && tfr->rx_buf && tfr->rx_buf != ctlr->dummy_rx) cs |= BCM2835_SPI_CS_REN; - else - cs &= ~BCM2835_SPI_CS_REN; - - /* - * The driver always uses software-controlled GPIO Chip Select. - * Set the hardware-controlled native Chip Select to an invalid - * value to prevent it from interfering. - */ - cs |= BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; /* set transmit buffers and length */ bs->tx_buf = tfr->tx_buf; @@ -878,7 +873,6 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr, { struct spi_device *spi = msg->spi; struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); - u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS); int ret; if (ctlr->can_dma) { @@ -893,14 +887,11 @@ static int bcm2835_spi_prepare_message(struct spi_controller *ctlr, return ret; } - cs &= ~(BCM2835_SPI_CS_CPOL | BCM2835_SPI_CS_CPHA); - - if (spi->mode & SPI_CPOL) - cs |= BCM2835_SPI_CS_CPOL; - if (spi->mode & SPI_CPHA) - cs |= BCM2835_SPI_CS_CPHA; - - bcm2835_wr(bs, BCM2835_SPI_CS, cs); + /* + * Set up clock polarity before spi_transfer_one_message() asserts + * chip select to avoid a gratuitous clock signal edge. + */ + bcm2835_wr(bs, BCM2835_SPI_CS, bs->prepare_cs[spi->chip_select]); return 0; } @@ -926,8 +917,23 @@ static int chip_match_name(struct gpio_chip *chip, void *data) static int bcm2835_spi_setup(struct spi_device *spi) { + struct bcm2835_spi *bs = spi_controller_get_devdata(spi->controller); struct gpio_chip *chip; enum gpio_lookup_flags lflags; + u32 cs; + + /* + * Precalculate SPI slave's CS register value for ->prepare_message(): + * The driver always uses software-controlled GPIO chip select, hence + * set the hardware-controlled native chip select to an invalid value + * to prevent it from interfering. + */ + cs = BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01; + if (spi->mode & SPI_CPOL) + cs |= BCM2835_SPI_CS_CPOL; + if (spi->mode & SPI_CPHA) + cs |= BCM2835_SPI_CS_CPHA; + bs->prepare_cs[spi->chip_select] = cs; /* * sanity checking the native-chipselects @@ -1005,7 +1011,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) ctlr->use_gpio_descriptors = true; ctlr->mode_bits = BCM2835_SPI_MODE_BITS; ctlr->bits_per_word_mask = SPI_BPW_MASK(8); - ctlr->num_chipselect = 3; + ctlr->num_chipselect = BCM2835_SPI_NUM_CS; ctlr->setup = bcm2835_spi_setup; ctlr->transfer_one = bcm2835_spi_transfer_one; ctlr->handle_err = bcm2835_spi_handle_err; -- cgit v1.2.3 From 8259bf667a0f9ea1a37bb71c7af9ebd550e9251d Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: spi: bcm2835: Speed up TX-only DMA transfers by clearing RX FIFO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BCM2835 SPI driver currently sets the SPI_CONTROLLER_MUST_RX flag. When performing a TX-only transfer, this flag causes the SPI core to allocate and DMA-map a dummy buffer into which the RX FIFO contents are copied. The dummy buffer is necessary because the chip is not capable of disabling the receiver or automatically throwing away received data. Not reading the RX FIFO isn't an option either since transmission is halted once it's full. Avoid the overhead induced by the dummy buffer by preallocating a reusable DMA transaction which cyclically clears the RX FIFO. The transaction requires very little CPU time to submit and generates no interrupts while running. Specifics are provided in kerneldoc comments. With a ks8851 Ethernet chip attached to the SPI controller, I am seeing a 30 us reduction in ping time with this commit (1.819 ms vs. 1.849 ms, average of 100,000 packets) as well as a 2% reduction in CPU time (75:08 vs. 76:39 for transmission of 5 GByte over the SPI bus). The commit uses the TX DMA interrupt to signal completion of a transfer. This interrupt is raised once all bytes have been written to the TX FIFO and it is then necessary to busy-wait for the TX FIFO to become empty before the transfer can be finalized. As an alternative approach, I have explored using the SPI controller's DONE interrupt to detect completion. This interrupt is signaled when the TX FIFO becomes empty, avoiding the need to busy-wait. However latency deteriorates compared to the present commit and surprisingly, CPU time is slightly higher as well: It turns out that in 45% of the cases, no busy-waiting is needed at all and in 76% of the cases, less than 10 busy-wait iterations are sufficient for the TX FIFO to drain. This was measured on an RT kernel. On a vanilla kernel, wakeup latency is worse and thus fewer iterations are needed. The measurements were made with an SPI clock of 20 MHz, they may differ slightly for slower or faster clock speeds. Previously we always used the RX DMA interrupt to signal completion of a transfer. Using the TX DMA interrupt now introduces a race condition: TX DMA is always started before RX DMA so that bytes are already clocked out while RX DMA is still being set up. But if a TX-only transfer is very short, then the TX DMA interrupt may occur before RX DMA is set up. If the interrupt happens to occur on the same CPU, setup of RX DMA may even be delayed until after the interrupt was handled. I've solved this by having the TX DMA callback clear the RX FIFO while busy-waiting for the TX FIFO to drain, thus avoiding a dependency on setup of RX DMA. Additionally, I am using a lock-free mechanism with two flags, tx_dma_active and rx_dma_active plus memory barriers to terminate RX DMA either by the TX DMA callback or immediately after setting it up, whichever wins the race. I've explored an alternative approach which temporarily disables the TX DMA callback until RX DMA has been set up (using tasklet_disable(), local_bh_disable() or local_irq_save()), but the performance was minimally worse. [Nathan Chancellor contributed a DMA mapping fixup for an early version of this commit, hence his Signed-off-by.] Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Nathan Chancellor Signed-off-by: Lukas Wunner Acked-by: Stefan Wahren Acked-by: Martin Sperl Cc: Robert Jarzmik Link: https://lore.kernel.org/r/874949385f28251e2dcaa9494e39a27b50e9f9e4.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 241 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 218 insertions(+), 23 deletions(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index f01d18d521f2..3fe823891861 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -106,6 +106,16 @@ MODULE_PARM_DESC(polling_limit_us, * These are counted as well in @count_transfer_polling and * @count_transfer_irq * @count_transfer_dma: count how often dma mode is used + * @chip_select: SPI slave currently selected + * (used by bcm2835_spi_dma_tx_done() to write @clear_rx_cs) + * @tx_dma_active: whether a TX DMA descriptor is in progress + * @rx_dma_active: whether a RX DMA descriptor is in progress + * (used by bcm2835_spi_dma_tx_done() to handle a race) + * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers + * (cyclically clears RX FIFO by writing @clear_rx_cs to CS register) + * @clear_rx_addr: bus address of @clear_rx_cs + * @clear_rx_cs: precalculated CS register value to clear RX FIFO + * (uses slave-specific clock polarity and phase settings) */ struct bcm2835_spi { void __iomem *regs; @@ -126,6 +136,13 @@ struct bcm2835_spi { u64 count_transfer_irq; u64 count_transfer_irq_after_polling; u64 count_transfer_dma; + + u8 chip_select; + unsigned int tx_dma_active; + unsigned int rx_dma_active; + struct dma_async_tx_descriptor *clear_rx_desc[BCM2835_SPI_NUM_CS]; + dma_addr_t clear_rx_addr; + u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned; }; #if defined(CONFIG_DEBUG_FS) @@ -455,7 +472,7 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr, if (!sg_is_last(&tfr->tx_sg.sgl[0])) bs->tx_prologue = sg_dma_len(&tfr->tx_sg.sgl[0]) & 3; - if (!sg_is_last(&tfr->rx_sg.sgl[0])) { + if (bs->rx_buf && !sg_is_last(&tfr->rx_sg.sgl[0])) { bs->rx_prologue = sg_dma_len(&tfr->rx_sg.sgl[0]) & 3; if (bs->rx_prologue > bs->tx_prologue) { @@ -547,7 +564,13 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs) bs->tx_prologue = 0; } -static void bcm2835_spi_dma_done(void *data) +/** + * bcm2835_spi_dma_rx_done() - callback for DMA RX channel + * @data: SPI master controller + * + * Used for bidirectional and RX-only transfers. + */ +static void bcm2835_spi_dma_rx_done(void *data) { struct spi_controller *ctlr = data; struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); @@ -561,14 +584,61 @@ static void bcm2835_spi_dma_done(void *data) * situation otherwise... */ dmaengine_terminate_async(ctlr->dma_tx); + bs->tx_dma_active = false; + bs->rx_dma_active = false; bcm2835_spi_undo_prologue(bs); /* and mark as completed */; complete(&ctlr->xfer_completion); } +/** + * bcm2835_spi_dma_tx_done() - callback for DMA TX channel + * @data: SPI master controller + * + * Used for TX-only transfers. + */ +static void bcm2835_spi_dma_tx_done(void *data) +{ + struct spi_controller *ctlr = data; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + + /* busy-wait for TX FIFO to empty */ + while (!(bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE)) + bcm2835_wr(bs, BCM2835_SPI_CS, + bs->clear_rx_cs[bs->chip_select]); + + bs->tx_dma_active = false; + smp_wmb(); + + /* + * In case of a very short transfer, RX DMA may not have been + * issued yet. The onus is then on bcm2835_spi_transfer_one_dma() + * to terminate it immediately after issuing. + */ + if (cmpxchg(&bs->rx_dma_active, true, false)) + dmaengine_terminate_async(ctlr->dma_rx); + + bcm2835_spi_undo_prologue(bs); + bcm2835_spi_reset_hw(ctlr); + complete(&ctlr->xfer_completion); +} + +/** + * bcm2835_spi_prepare_sg() - prepare and submit DMA descriptor for sglist + * @ctlr: SPI master controller + * @spi: SPI slave + * @tfr: SPI transfer + * @bs: BCM2835 SPI controller + * @is_tx: whether to submit DMA descriptor for TX or RX sglist + * + * Prepare and submit a DMA descriptor for the TX or RX sglist of @tfr. + * Return 0 on success or a negative error number. + */ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, + struct spi_device *spi, struct spi_transfer *tfr, + struct bcm2835_spi *bs, bool is_tx) { struct dma_chan *chan; @@ -585,8 +655,7 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, chan = ctlr->dma_tx; nents = tfr->tx_sg.nents; sgl = tfr->tx_sg.sgl; - flags = 0 /* no tx interrupt */; - + flags = tfr->rx_buf ? 0 : DMA_PREP_INTERRUPT; } else { dir = DMA_DEV_TO_MEM; chan = ctlr->dma_rx; @@ -599,10 +668,17 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, if (!desc) return -EINVAL; - /* set callback for rx */ + /* + * Completion is signaled by the RX channel for bidirectional and + * RX-only transfers; else by the TX channel for TX-only transfers. + */ if (!is_tx) { - desc->callback = bcm2835_spi_dma_done; + desc->callback = bcm2835_spi_dma_rx_done; + desc->callback_param = ctlr; + } else if (!tfr->rx_buf) { + desc->callback = bcm2835_spi_dma_tx_done; desc->callback_param = ctlr; + bs->chip_select = spi->chip_select; } /* submit it to DMA-engine */ @@ -611,12 +687,42 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, return dma_submit_error(cookie); } +/** + * bcm2835_spi_transfer_one_dma() - perform SPI transfer using DMA engine + * @ctlr: SPI master controller + * @spi: SPI slave + * @tfr: SPI transfer + * @cs: CS register + * + * For *bidirectional* transfers (both tx_buf and rx_buf are non-%NULL), set up + * the TX and RX DMA channel to copy between memory and FIFO register. + * + * For *TX-only* transfers (rx_buf is %NULL), copying the RX FIFO's contents to + * memory is pointless. However not reading the RX FIFO isn't an option either + * because transmission is halted once it's full. As a workaround, cyclically + * clear the RX FIFO by setting the CLEAR_RX bit in the CS register. + * + * The CS register value is precalculated in bcm2835_spi_setup(). Normally + * this is called only once, on slave registration. A DMA descriptor to write + * this value is preallocated in bcm2835_dma_init(). All that's left to do + * when performing a TX-only transfer is to submit this descriptor to the RX + * DMA channel. Latency is thereby minimized. The descriptor does not + * generate any interrupts while running. It must be terminated once the + * TX DMA channel is done. + * + * Clearing the RX FIFO is paced by the DREQ signal. The signal is asserted + * when the RX FIFO becomes half full, i.e. 32 bytes. (Tuneable with the DC + * register.) Reading 32 bytes from the RX FIFO would normally require 8 bus + * accesses, whereas clearing it requires only 1 bus access. So an 8-fold + * reduction in bus traffic and thus energy consumption is achieved. + */ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, struct spi_device *spi, struct spi_transfer *tfr, u32 cs) { struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); + dma_cookie_t cookie; int ret; /* update usage statistics */ @@ -629,13 +735,10 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs); /* setup tx-DMA */ - ret = bcm2835_spi_prepare_sg(ctlr, tfr, true); + ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true); if (ret) goto err_reset_hw; - /* start TX early */ - dma_async_issue_pending(ctlr->dma_tx); - /* set the DMA length */ bcm2835_wr(bs, BCM2835_SPI_DLEN, bs->tx_len); @@ -643,19 +746,43 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA | BCM2835_SPI_CS_DMAEN); + bs->tx_dma_active = true; + smp_wmb(); + + /* start TX early */ + dma_async_issue_pending(ctlr->dma_tx); + /* setup rx-DMA late - to run transfers while * mapping of the rx buffers still takes place * this saves 10us or more. */ - ret = bcm2835_spi_prepare_sg(ctlr, tfr, false); + if (bs->rx_buf) { + ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, false); + } else { + cookie = dmaengine_submit(bs->clear_rx_desc[spi->chip_select]); + ret = dma_submit_error(cookie); + } if (ret) { /* need to reset on errors */ dmaengine_terminate_sync(ctlr->dma_tx); + bs->tx_dma_active = false; goto err_reset_hw; } /* start rx dma late */ dma_async_issue_pending(ctlr->dma_rx); + bs->rx_dma_active = true; + smp_mb(); + + /* + * In case of a very short TX-only transfer, bcm2835_spi_dma_tx_done() + * may run before RX DMA is issued. Terminate RX DMA if so. + */ + if (!bs->rx_buf && !bs->tx_dma_active && + cmpxchg(&bs->rx_dma_active, true, false)) { + dmaengine_terminate_async(ctlr->dma_rx); + bcm2835_spi_reset_hw(ctlr); + } /* wait for wakeup in framework */ return 1; @@ -678,26 +805,42 @@ static bool bcm2835_spi_can_dma(struct spi_controller *ctlr, return true; } -static void bcm2835_dma_release(struct spi_controller *ctlr) +static void bcm2835_dma_release(struct spi_controller *ctlr, + struct bcm2835_spi *bs) { + int i; + if (ctlr->dma_tx) { dmaengine_terminate_sync(ctlr->dma_tx); dma_release_channel(ctlr->dma_tx); ctlr->dma_tx = NULL; } + if (ctlr->dma_rx) { dmaengine_terminate_sync(ctlr->dma_rx); + + for (i = 0; i < BCM2835_SPI_NUM_CS; i++) + if (bs->clear_rx_desc[i]) + dmaengine_desc_free(bs->clear_rx_desc[i]); + + if (bs->clear_rx_addr) + dma_unmap_single(ctlr->dma_rx->device->dev, + bs->clear_rx_addr, + sizeof(bs->clear_rx_cs), + DMA_TO_DEVICE); + dma_release_channel(ctlr->dma_rx); ctlr->dma_rx = NULL; } } -static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev) +static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, + struct bcm2835_spi *bs) { struct dma_slave_config slave_config; const __be32 *addr; dma_addr_t dma_reg_base; - int ret; + int ret, i; /* base address in dma-space */ addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL); @@ -727,17 +870,51 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev) if (ret) goto err_config; + /* + * The RX DMA channel is used bidirectionally: It either reads the + * RX FIFO or, in case of a TX-only transfer, cyclically writes a + * precalculated value to the CS register to clear the RX FIFO. + */ slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_CS); + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ret = dmaengine_slave_config(ctlr->dma_rx, &slave_config); if (ret) goto err_config; + bs->clear_rx_addr = dma_map_single(ctlr->dma_rx->device->dev, + bs->clear_rx_cs, + sizeof(bs->clear_rx_cs), + DMA_TO_DEVICE); + if (dma_mapping_error(ctlr->dma_rx->device->dev, bs->clear_rx_addr)) { + dev_err(dev, "cannot map clear_rx_cs - not using DMA mode\n"); + bs->clear_rx_addr = 0; + goto err_release; + } + + for (i = 0; i < BCM2835_SPI_NUM_CS; i++) { + bs->clear_rx_desc[i] = dmaengine_prep_dma_cyclic(ctlr->dma_rx, + bs->clear_rx_addr + i * sizeof(u32), + sizeof(u32), 0, + DMA_MEM_TO_DEV, 0); + if (!bs->clear_rx_desc[i]) { + dev_err(dev, "cannot prepare clear_rx_desc - not using DMA mode\n"); + goto err_release; + } + + ret = dmaengine_desc_set_reuse(bs->clear_rx_desc[i]); + if (ret) { + dev_err(dev, "cannot reuse clear_rx_desc - not using DMA mode\n"); + goto err_release; + } + } + /* all went well, so set can_dma */ ctlr->can_dma = bcm2835_spi_can_dma; - /* need to do TX AND RX DMA, so we need dummy buffers */ - ctlr->flags = SPI_CONTROLLER_MUST_RX | SPI_CONTROLLER_MUST_TX; + /* need to do TX DMA, so we need a dummy buffer */ + ctlr->flags = SPI_CONTROLLER_MUST_TX; return; @@ -745,7 +922,7 @@ err_config: dev_err(dev, "issue configuring dma: %d - not using DMA mode\n", ret); err_release: - bcm2835_dma_release(ctlr); + bcm2835_dma_release(ctlr, bs); err: return; } @@ -834,8 +1011,7 @@ static int bcm2835_spi_transfer_one(struct spi_controller *ctlr, bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv); /* handle all the 3-wire mode */ - if (spi->mode & SPI_3WIRE && tfr->rx_buf && - tfr->rx_buf != ctlr->dummy_rx) + if (spi->mode & SPI_3WIRE && tfr->rx_buf) cs |= BCM2835_SPI_CS_REN; /* set transmit buffers and length */ @@ -903,7 +1079,9 @@ static void bcm2835_spi_handle_err(struct spi_controller *ctlr, /* if an error occurred and we have an active dma, then terminate */ dmaengine_terminate_sync(ctlr->dma_tx); + bs->tx_dma_active = false; dmaengine_terminate_sync(ctlr->dma_rx); + bs->rx_dma_active = false; bcm2835_spi_undo_prologue(bs); /* and reset */ @@ -917,7 +1095,8 @@ static int chip_match_name(struct gpio_chip *chip, void *data) static int bcm2835_spi_setup(struct spi_device *spi) { - struct bcm2835_spi *bs = spi_controller_get_devdata(spi->controller); + struct spi_controller *ctlr = spi->controller; + struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); struct gpio_chip *chip; enum gpio_lookup_flags lflags; u32 cs; @@ -935,6 +1114,21 @@ static int bcm2835_spi_setup(struct spi_device *spi) cs |= BCM2835_SPI_CS_CPHA; bs->prepare_cs[spi->chip_select] = cs; + /* + * Precalculate SPI slave's CS register value to clear RX FIFO + * in case of a TX-only DMA transfer. + */ + if (ctlr->dma_rx) { + bs->clear_rx_cs[spi->chip_select] = cs | + BCM2835_SPI_CS_TA | + BCM2835_SPI_CS_DMAEN | + BCM2835_SPI_CS_CLEAR_RX; + dma_sync_single_for_device(ctlr->dma_rx->device->dev, + bs->clear_rx_addr, + sizeof(bs->clear_rx_cs), + DMA_TO_DEVICE); + } + /* * sanity checking the native-chipselects */ @@ -1002,7 +1196,8 @@ static int bcm2835_spi_probe(struct platform_device *pdev) struct bcm2835_spi *bs; int err; - ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs)); + ctlr = spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs), + dma_get_cache_alignment())); if (!ctlr) return -ENOMEM; @@ -1041,7 +1236,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) clk_prepare_enable(bs->clk); - bcm2835_dma_init(ctlr, &pdev->dev); + bcm2835_dma_init(ctlr, &pdev->dev, bs); /* initialise the hardware with the default polarities */ bcm2835_wr(bs, BCM2835_SPI_CS, @@ -1085,7 +1280,7 @@ static int bcm2835_spi_remove(struct platform_device *pdev) clk_disable_unprepare(bs->clk); - bcm2835_dma_release(ctlr); + bcm2835_dma_release(ctlr, bs); return 0; } -- cgit v1.2.3 From 2b8279aec1829da4dc645e8731c28d2f5458d652 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: spi: bcm2835: Speed up RX-only DMA transfers by zero-filling TX FIFO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BCM2835 SPI driver currently sets the SPI_CONTROLLER_MUST_TX flag. When performing an RX-only transfer, this flag causes the SPI core to allocate and DMA-map a dummy buffer which is copied to the TX FIFO. The dummy buffer is necessary because the chip is not capable of automatically clocking out null bytes. Avoid the overhead induced by the dummy buffer by preallocating a reusable DMA transaction which fills the TX FIFO by cyclically copying from the zero page. The transaction requires very little CPU time to submit and generates no interrupts while running. Specifics are provided in kerneldoc comments. [Nathan Chancellor contributed a DMA mapping fixup for an early version of this commit, hence his Signed-off-by.] Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Nathan Chancellor Signed-off-by: Lukas Wunner Acked-by: Stefan Wahren Acked-by: Martin Sperl Cc: Robert Jarzmik Link: https://lore.kernel.org/r/f45920af18dbf06e34129bbc406f53dc9c5d1075.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 93 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 11 deletions(-) (limited to 'drivers/spi/spi-bcm2835.c') diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 3fe823891861..8a0ea465cbe0 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -111,6 +111,9 @@ MODULE_PARM_DESC(polling_limit_us, * @tx_dma_active: whether a TX DMA descriptor is in progress * @rx_dma_active: whether a RX DMA descriptor is in progress * (used by bcm2835_spi_dma_tx_done() to handle a race) + * @fill_tx_desc: preallocated TX DMA descriptor used for RX-only transfers + * (cyclically copies from zero page to TX FIFO) + * @fill_tx_addr: bus address of zero page * @clear_rx_desc: preallocated RX DMA descriptor used for TX-only transfers * (cyclically clears RX FIFO by writing @clear_rx_cs to CS register) * @clear_rx_addr: bus address of @clear_rx_cs @@ -140,6 +143,8 @@ struct bcm2835_spi { u8 chip_select; unsigned int tx_dma_active; unsigned int rx_dma_active; + struct dma_async_tx_descriptor *fill_tx_desc; + dma_addr_t fill_tx_addr; struct dma_async_tx_descriptor *clear_rx_desc[BCM2835_SPI_NUM_CS]; dma_addr_t clear_rx_addr; u32 clear_rx_cs[BCM2835_SPI_NUM_CS] ____cacheline_aligned; @@ -469,14 +474,14 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr, bs->rx_prologue = 0; bs->tx_spillover = false; - if (!sg_is_last(&tfr->tx_sg.sgl[0])) + if (bs->tx_buf && !sg_is_last(&tfr->tx_sg.sgl[0])) bs->tx_prologue = sg_dma_len(&tfr->tx_sg.sgl[0]) & 3; if (bs->rx_buf && !sg_is_last(&tfr->rx_sg.sgl[0])) { bs->rx_prologue = sg_dma_len(&tfr->rx_sg.sgl[0]) & 3; if (bs->rx_prologue > bs->tx_prologue) { - if (sg_is_last(&tfr->tx_sg.sgl[0])) { + if (!bs->tx_buf || sg_is_last(&tfr->tx_sg.sgl[0])) { bs->tx_prologue = bs->rx_prologue; } else { bs->tx_prologue += 4; @@ -508,6 +513,9 @@ static void bcm2835_spi_transfer_prologue(struct spi_controller *ctlr, sg_dma_len(&tfr->rx_sg.sgl[0]) -= bs->rx_prologue; } + if (!bs->tx_buf) + return; + /* * Write remaining TX prologue. Adjust first entry in TX sglist. * Also adjust second entry if prologue spills over to it. @@ -552,6 +560,9 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs) sg_dma_len(&tfr->rx_sg.sgl[0]) += bs->rx_prologue; } + if (!bs->tx_buf) + goto out; + if (likely(!bs->tx_spillover)) { sg_dma_address(&tfr->tx_sg.sgl[0]) -= bs->tx_prologue; sg_dma_len(&tfr->tx_sg.sgl[0]) += bs->tx_prologue; @@ -560,7 +571,7 @@ static void bcm2835_spi_undo_prologue(struct bcm2835_spi *bs) sg_dma_address(&tfr->tx_sg.sgl[1]) -= 4; sg_dma_len(&tfr->tx_sg.sgl[1]) += 4; } - +out: bs->tx_prologue = 0; } @@ -575,10 +586,7 @@ static void bcm2835_spi_dma_rx_done(void *data) struct spi_controller *ctlr = data; struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr); - /* reset fifo and HW */ - bcm2835_spi_reset_hw(ctlr); - - /* and terminate tx-dma as we do not have an irq for it + /* terminate tx-dma as we do not have an irq for it * because when the rx dma will terminate and this callback * is called the tx-dma must have finished - can't get to this * situation otherwise... @@ -588,6 +596,9 @@ static void bcm2835_spi_dma_rx_done(void *data) bs->rx_dma_active = false; bcm2835_spi_undo_prologue(bs); + /* reset fifo and HW */ + bcm2835_spi_reset_hw(ctlr); + /* and mark as completed */; complete(&ctlr->xfer_completion); } @@ -715,6 +726,24 @@ static int bcm2835_spi_prepare_sg(struct spi_controller *ctlr, * register.) Reading 32 bytes from the RX FIFO would normally require 8 bus * accesses, whereas clearing it requires only 1 bus access. So an 8-fold * reduction in bus traffic and thus energy consumption is achieved. + * + * For *RX-only* transfers (tx_buf is %NULL), fill the TX FIFO by cyclically + * copying from the zero page. The DMA descriptor to do this is preallocated + * in bcm2835_dma_init(). It must be terminated once the RX DMA channel is + * done and can then be reused. + * + * The BCM2835 DMA driver autodetects when a transaction copies from the zero + * page and utilizes the DMA controller's ability to synthesize zeroes instead + * of copying them from memory. This reduces traffic on the memory bus. The + * feature is not available on so-called "lite" channels, but normally TX DMA + * is backed by a full-featured channel. + * + * Zero-filling the TX FIFO is paced by the DREQ signal. Unfortunately the + * BCM2835 SPI controller continues to assert DREQ even after the DLEN register + * has been counted down to zero (hardware erratum). Thus, when the transfer + * has finished, the DMA engine zero-fills the TX FIFO until it is half full. + * (Tuneable with the DC register.) So up to 9 gratuitous bus accesses are + * performed at the end of an RX-only transfer. */ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, struct spi_device *spi, @@ -735,7 +764,12 @@ static int bcm2835_spi_transfer_one_dma(struct spi_controller *ctlr, bcm2835_spi_transfer_prologue(ctlr, tfr, bs, cs); /* setup tx-DMA */ - ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true); + if (bs->tx_buf) { + ret = bcm2835_spi_prepare_sg(ctlr, spi, tfr, bs, true); + } else { + cookie = dmaengine_submit(bs->fill_tx_desc); + ret = dma_submit_error(cookie); + } if (ret) goto err_reset_hw; @@ -812,6 +846,16 @@ static void bcm2835_dma_release(struct spi_controller *ctlr, if (ctlr->dma_tx) { dmaengine_terminate_sync(ctlr->dma_tx); + + if (bs->fill_tx_desc) + dmaengine_desc_free(bs->fill_tx_desc); + + if (bs->fill_tx_addr) + dma_unmap_page_attrs(ctlr->dma_tx->device->dev, + bs->fill_tx_addr, sizeof(u32), + DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + dma_release_channel(ctlr->dma_tx); ctlr->dma_tx = NULL; } @@ -862,7 +906,11 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, goto err_release; } - /* configure DMAs */ + /* + * The TX DMA channel either copies a transfer's TX buffer to the FIFO + * or, in case of an RX-only transfer, cyclically copies from the zero + * page to the FIFO using a preallocated, reusable descriptor. + */ slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO); slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -870,6 +918,31 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, if (ret) goto err_config; + bs->fill_tx_addr = dma_map_page_attrs(ctlr->dma_tx->device->dev, + ZERO_PAGE(0), 0, sizeof(u32), + DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(ctlr->dma_tx->device->dev, bs->fill_tx_addr)) { + dev_err(dev, "cannot map zero page - not using DMA mode\n"); + bs->fill_tx_addr = 0; + goto err_release; + } + + bs->fill_tx_desc = dmaengine_prep_dma_cyclic(ctlr->dma_tx, + bs->fill_tx_addr, + sizeof(u32), 0, + DMA_MEM_TO_DEV, 0); + if (!bs->fill_tx_desc) { + dev_err(dev, "cannot prepare fill_tx_desc - not using DMA mode\n"); + goto err_release; + } + + ret = dmaengine_desc_set_reuse(bs->fill_tx_desc); + if (ret) { + dev_err(dev, "cannot reuse fill_tx_desc - not using DMA mode\n"); + goto err_release; + } + /* * The RX DMA channel is used bidirectionally: It either reads the * RX FIFO or, in case of a TX-only transfer, cyclically writes a @@ -913,8 +986,6 @@ static void bcm2835_dma_init(struct spi_controller *ctlr, struct device *dev, /* all went well, so set can_dma */ ctlr->can_dma = bcm2835_spi_can_dma; - /* need to do TX DMA, so we need a dummy buffer */ - ctlr->flags = SPI_CONTROLLER_MUST_TX; return; -- cgit v1.2.3