From 4f2228cce2816e46dcac0be50a259a0311a90252 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: dmaengine: bcm2835: Allow cyclic transactions without interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BCM2835 DMA driver currently requests an interrupt from the controller regardless whether or not the client has passed in the DMA_PREP_INTERRUPT flag. This causes unnecessary overhead for cyclic transactions which do not need an interrupt after each period. We're about to add such a use case, namely cyclic clearing of the SPI controller's RX FIFO, so amend the DMA driver to request an interrupt only if DMA_PREP_INTERRUPT was passed in. Ignore the period_len for such transactions and set it to the buffer length to make the driver's calculations work. Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Lukas Wunner Acked-by: Vinod Koul Acked-by: Stefan Wahren Acked-by: Martin Sperl Cc: Florian Kauer Link: https://lore.kernel.org/r/73cf37be56eb4cbe6f696057c719f3a38cbaf26e.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/dma/bcm2835-dma.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/dma') diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 8101ff2f05c1..b40fb555b98b 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -691,7 +691,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( struct bcm2835_desc *d; dma_addr_t src, dst; u32 info = BCM2835_DMA_WAIT_RESP; - u32 extra = BCM2835_DMA_INT_EN; + u32 extra = 0; size_t max_len = bcm2835_dma_max_frame_length(c); size_t frames; @@ -707,6 +707,11 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( return NULL; } + if (flags & DMA_PREP_INTERRUPT) + extra |= BCM2835_DMA_INT_EN; + else + period_len = buf_len; + /* * warn if buf_len is not a multiple of period_len - this may leed * to unexpected latencies for interrupts and thus audiable clicks @@ -778,7 +783,10 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan) /* stop DMA activity */ if (c->desc) { - vchan_terminate_vdesc(&c->desc->vd); + if (c->desc->vd.tx.flags & DMA_PREP_INTERRUPT) + vchan_terminate_vdesc(&c->desc->vd); + else + vchan_vdesc_fini(&c->desc->vd); c->desc = NULL; bcm2835_dma_abort(c); } -- cgit v1.2.3 From 6f6869dc97e8657e15d728c9a1ee3af2b9343990 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: dmaengine: bcm2835: Allow reusable descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DMA engine API requires DMA drivers to explicitly allow that descriptors are prepared once and reused multiple times. Only a single driver makes use of this functionality so far (pxa_dma.c, to speed up pxa_camera.c). We're about to add another use case for reusable descriptors in the BCM2835 SPI driver, so allow that in the BCM2835 DMA driver. Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Lukas Wunner Acked-by: Vinod Koul Acked-by: Stefan Wahren Acked-by: Martin Sperl Cc: Florian Kauer Cc: Robert Jarzmik Link: https://lore.kernel.org/r/bfc98a38225bbec4158440ad06cb9eee675e3e6f.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/dma/bcm2835-dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/dma') diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index b40fb555b98b..a65514fcb7f2 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -915,6 +915,7 @@ static int bcm2835_dma_probe(struct platform_device *pdev) od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | BIT(DMA_MEM_TO_MEM); od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + od->ddev.descriptor_reuse = true; od->ddev.dev = &pdev->dev; INIT_LIST_HEAD(&od->ddev.channels); -- cgit v1.2.3 From c3ef8207833206f53b1ea433dc25c0c9b30d4424 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: dmaengine: bcm2835: Document struct bcm2835_dmadev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the BCM2835 DMA driver's device data structure so that upcoming commits may add further members with proper kerneldoc. Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Lukas Wunner Acked-by: Vinod Koul Acked-by: Stefan Wahren Acked-by: Martin Sperl Cc: Florian Kauer Link: https://lore.kernel.org/r/78648f80f67d97bb7beecc1b9be6b6e4a45bc1d8.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/dma/bcm2835-dma.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/dma') diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index a65514fcb7f2..14358faf3bff 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -37,6 +37,12 @@ #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 #define BCM2835_DMA_CHAN_NAME_SIZE 8 +/** + * struct bcm2835_dmadev - BCM2835 DMA controller + * @ddev: DMA device + * @base: base address of register map + * @dma_parms: DMA parameters (to convey 1 GByte max segment size to clients) + */ struct bcm2835_dmadev { struct dma_device ddev; void __iomem *base; -- cgit v1.2.3 From bf75703d0912da7b1af72f14392c805b758c3fbc Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 11 Sep 2019 12:15:30 +0200 Subject: dmaengine: bcm2835: Avoid accessing memory when copying zeroes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The BCM2835 DMA controller is capable of synthesizing zeroes instead of copying them from a source address. The feature is enabled by setting the SRC_IGNORE bit in the Transfer Information field of a Control Block: "Do not perform source reads. In addition, destination writes will zero all the write strobes. This is used for fast cache fill operations." https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf The feature is only available on 8 of the 16 channels. The others are so-called "lite" channels with a limited feature set and performance. Enable the feature if a cyclic transaction copies from the zero page. This reduces traffic on the memory bus. A forthcoming use case is the BCM2835 SPI driver, which will cyclically copy from the zero page to the TX FIFO. The idea to use SRC_IGNORE was taken from an ancient GitHub conversation between Martin and Noralf: https://github.com/msperl/spi-bcm2835/issues/13#issuecomment-98180451 Tested-by: Nuno Sá Tested-by: Noralf Trønnes Signed-off-by: Lukas Wunner Acked-by: Vinod Koul Acked-by: Stefan Wahren Acked-by: Martin Sperl Cc: Florian Kauer Link: https://lore.kernel.org/r/b2286c904408745192e4beb3de3c88f73e4a7210.1568187525.git.lukas@wunner.de Signed-off-by: Mark Brown --- drivers/dma/bcm2835-dma.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/dma') diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c index 14358faf3bff..67100e4e1083 100644 --- a/drivers/dma/bcm2835-dma.c +++ b/drivers/dma/bcm2835-dma.c @@ -42,11 +42,14 @@ * @ddev: DMA device * @base: base address of register map * @dma_parms: DMA parameters (to convey 1 GByte max segment size to clients) + * @zero_page: bus address of zero page (to detect transactions copying from + * zero page and avoid accessing memory if so) */ struct bcm2835_dmadev { struct dma_device ddev; void __iomem *base; struct device_dma_parameters dma_parms; + dma_addr_t zero_page; }; struct bcm2835_dma_cb { @@ -693,6 +696,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( size_t period_len, enum dma_transfer_direction direction, unsigned long flags) { + struct bcm2835_dmadev *od = to_bcm2835_dma_dev(chan->device); struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); struct bcm2835_desc *d; dma_addr_t src, dst; @@ -743,6 +747,10 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic( dst = c->cfg.dst_addr; src = buf_addr; info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC; + + /* non-lite channels can write zeroes w/o accessing memory */ + if (buf_addr == od->zero_page && !c->is_lite_channel) + info |= BCM2835_DMA_S_IGNORE; } /* calculate number of frames */ @@ -845,6 +853,9 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od) list_del(&c->vc.chan.device_node); tasklet_kill(&c->vc.task); } + + dma_unmap_page_attrs(od->ddev.dev, od->zero_page, PAGE_SIZE, + DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); } static const struct of_device_id bcm2835_dma_of_match[] = { @@ -927,6 +938,14 @@ static int bcm2835_dma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, od); + od->zero_page = dma_map_page_attrs(od->ddev.dev, ZERO_PAGE(0), 0, + PAGE_SIZE, DMA_TO_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(od->ddev.dev, od->zero_page)) { + dev_err(&pdev->dev, "Failed to map zero page\n"); + return -ENOMEM; + } + /* Request DMA channel mask from device tree */ if (of_property_read_u32(pdev->dev.of_node, "brcm,dma-channel-mask", -- cgit v1.2.3