* [PATCH 0/2] spi: Add DMA support for ti-qspi @ 2016-04-05 3:49 Vignesh R [not found] ` <1459828192-5531-1-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> 2016-04-05 3:49 ` [PATCH 2/2] spi: spi-ti-qspi: Add DMA support for QSPI mmap read Vignesh R 0 siblings, 2 replies; 5+ messages in thread From: Vignesh R @ 2016-04-05 3:49 UTC (permalink / raw) To: Mark Brown; +Cc: linux-spi, linux-kernel, linux-omap, Vignesh R This series adds support for DMA during QSPI flash read via memory mapped mode. Tested on DRA74 EVM on linux-next with patch for mtd support[1] applied. Also tested with series[2] from Boris refractoring spi_map_buf(). [1]http://lists.infradead.org/pipermail/linux-mtd/2016-March/066335.html [2]http://www.spinics.net/lists/linux-mm/msg104694.html Vignesh R (2): spi: Add DMA support for spi_flash_read() spi: spi-ti-qspi: Add DMA support for QSPI mmap read drivers/spi/spi-ti-qspi.c | 132 +++++++++++++++++++++++++++++++++++++++++----- drivers/spi/spi.c | 15 ++++++ include/linux/spi/spi.h | 2 + 3 files changed, 137 insertions(+), 12 deletions(-) -- 2.8.0 ^ permalink raw reply [flat|nested] 5+ messages in thread
[parent not found: <1459828192-5531-1-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org>]
* [PATCH 1/2] spi: Add DMA support for spi_flash_read() [not found] ` <1459828192-5531-1-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> @ 2016-04-05 3:49 ` Vignesh R [not found] ` <1459828192-5531-2-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> 0 siblings, 1 reply; 5+ messages in thread From: Vignesh R @ 2016-04-05 3:49 UTC (permalink / raw) To: Mark Brown Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-omap-u79uwXL29TY76Z2rM5mHXA, Vignesh R Few SPI devices provide accelerated read interfaces to read from SPI-NOR flash devices. These hardwares also support DMA to transfer data from flash to memory either via mem-to-mem DMA or dedicated slave DMA channels. Hence, add support for DMA in order to improve throughput and reduce CPU load. Use spi_map_buf() to get sg table for the buffer and pass it to SPI driver. Signed-off-by: Vignesh R <vigneshr-l0cyMroinI0@public.gmane.org> --- drivers/spi/spi.c | 15 +++++++++++++++ include/linux/spi/spi.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index de2f2f90d799..2fb97f5b79ab 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2722,6 +2722,7 @@ int spi_flash_read(struct spi_device *spi, { struct spi_master *master = spi->master; + struct device *rx_dev = NULL; int ret; if ((msg->opcode_nbits == SPI_NBITS_DUAL || @@ -2747,8 +2748,22 @@ int spi_flash_read(struct spi_device *spi, return ret; } } + mutex_lock(&master->bus_lock_mutex); + if (master->dma_rx) { + rx_dev = master->dma_rx->device->dev; + ret = spi_map_buf(master, rx_dev, &msg->rx_sg, + msg->buf, msg->len, + DMA_FROM_DEVICE); + if (ret != 0) + goto err; + } ret = master->spi_flash_read(spi, msg); + if (master->dma_rx) + spi_unmap_buf(master, rx_dev, &msg->rx_sg, + DMA_FROM_DEVICE); + +err: mutex_unlock(&master->bus_lock_mutex); if (master->auto_runtime_pm) pm_runtime_put(master->dev.parent); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 857a9a1d82b5..5b9c745eda92 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -1141,6 +1141,7 @@ static inline ssize_t spi_w8r16be(struct spi_device *spi, u8 cmd) * @opcode_nbits: number of lines to send opcode * @addr_nbits: number of lines to send address * @data_nbits: number of lines for data + * @rx_sg: Scatterlist for receive data */ struct spi_flash_read_message { void *buf; @@ -1153,6 +1154,7 @@ struct spi_flash_read_message { u8 opcode_nbits; u8 addr_nbits; u8 data_nbits; + struct sg_table rx_sg; }; /* SPI core interface for flash read support */ -- 2.8.0 -- To unsubscribe from this list: send the line "unsubscribe linux-spi" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 5+ messages in thread
[parent not found: <1459828192-5531-2-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org>]
* Re: [PATCH 1/2] spi: Add DMA support for spi_flash_read() [not found] ` <1459828192-5531-2-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> @ 2016-04-12 4:31 ` Mark Brown 2016-04-12 8:20 ` Vignesh R 0 siblings, 1 reply; 5+ messages in thread From: Mark Brown @ 2016-04-12 4:31 UTC (permalink / raw) To: Vignesh R Cc: linux-spi-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-omap-u79uwXL29TY76Z2rM5mHXA [-- Attachment #1: Type: text/plain, Size: 556 bytes --] On Tue, Apr 05, 2016 at 09:19:51AM +0530, Vignesh R wrote: > mutex_lock(&master->bus_lock_mutex); > + if (master->dma_rx) { > + rx_dev = master->dma_rx->device->dev; > + ret = spi_map_buf(master, rx_dev, &msg->rx_sg, > + msg->buf, msg->len, > + DMA_FROM_DEVICE); > + if (ret != 0) > + goto err; > + } This is unconditionally DMA mapping the buffer if DMA is supported. That's going to be common but I'm not sure it'll be universal, we need to think of something better here. I'm not immediately seeing what though. Possibly a flag... [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 473 bytes --] ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/2] spi: Add DMA support for spi_flash_read() 2016-04-12 4:31 ` Mark Brown @ 2016-04-12 8:20 ` Vignesh R 0 siblings, 0 replies; 5+ messages in thread From: Vignesh R @ 2016-04-12 8:20 UTC (permalink / raw) To: Mark Brown; +Cc: linux-spi, linux-kernel, linux-omap On 04/12/2016 10:01 AM, Mark Brown wrote: > On Tue, Apr 05, 2016 at 09:19:51AM +0530, Vignesh R wrote: > >> mutex_lock(&master->bus_lock_mutex); >> + if (master->dma_rx) { >> + rx_dev = master->dma_rx->device->dev; >> + ret = spi_map_buf(master, rx_dev, &msg->rx_sg, >> + msg->buf, msg->len, >> + DMA_FROM_DEVICE); >> + if (ret != 0) >> + goto err; >> + } > > This is unconditionally DMA mapping the buffer if DMA is supported. > That's going to be common but I'm not sure it'll be universal, we need > to think of something better here. I'm not immediately seeing what > though. Possibly a flag... > Ok, I will introduced a flag along the lines of cur_msg_mapped currently part of spi_message struct. This reminds me the issue of possible kmap'd buffers(falling in PKMAP_BASE - PAGE_OFFSET-1 region) that might be passed to spi_map_buf() which are not currently being handled properly. Boris attempted to fix this in generic way[1] but was rejected as it couldn't handle all type of caches. I was wondering whether you would accept a patch returning error when kmap'd buffers are passed to spi_map_buf()? Or would it still make sense to port changes from that series to handle kmap'd buffers to SPI core alone? [1]https://lkml.org/lkml/2016/3/31/462 -- Regards Vignesh ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/2] spi: spi-ti-qspi: Add DMA support for QSPI mmap read 2016-04-05 3:49 [PATCH 0/2] spi: Add DMA support for ti-qspi Vignesh R [not found] ` <1459828192-5531-1-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> @ 2016-04-05 3:49 ` Vignesh R 1 sibling, 0 replies; 5+ messages in thread From: Vignesh R @ 2016-04-05 3:49 UTC (permalink / raw) To: Mark Brown; +Cc: linux-spi, linux-kernel, linux-omap, Vignesh R Use mem-to-mem DMA to read from flash when reading in mmap mode. This gives improved read performance and reduces CPU load. With this patch the raw-read throughput is ~16MB/s on DRA74 EVM. And CPU load is <20%. UBIFS read ~13 MB/s. Signed-off-by: Vignesh R <vigneshr@ti.com> --- drivers/spi/spi-ti-qspi.c | 132 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index eac3c960b2de..1f6a11a45891 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -41,6 +41,8 @@ struct ti_qspi_regs { }; struct ti_qspi { + struct completion transfer_complete; + /* list synchronization */ struct mutex list_lock; @@ -54,6 +56,9 @@ struct ti_qspi { struct ti_qspi_regs ctx_reg; + dma_addr_t mmap_phys_base; + struct dma_chan *rx_chan; + u32 spi_max_frequency; u32 cmd; u32 dc; @@ -377,6 +382,78 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) return 0; } +static void qspi_dma_callback(void *param) +{ + struct ti_qspi *qspi = param; + + complete(&qspi->transfer_complete); +} + +static int qspi_dma_transfer(struct ti_qspi *qspi, dma_addr_t dma_dst, + dma_addr_t dma_src, size_t len) +{ + struct dma_chan *chan = qspi->rx_chan; + struct dma_device *dma_dev = chan->device; + dma_cookie_t cookie; + enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + struct dma_async_tx_descriptor *tx = NULL; + int ret; + + tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, + len, flags); + if (!tx) { + dev_err(qspi->dev, "device_prep_dma_memcpy error\n"); + ret = -EIO; + goto err; + } + + tx->callback = qspi_dma_callback; + tx->callback_param = qspi; + cookie = tx->tx_submit(tx); + + ret = dma_submit_error(cookie); + if (ret) { + dev_err(qspi->dev, "dma_submit_error %d\n", cookie); + goto err; + } + + dma_async_issue_pending(chan); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + msecs_to_jiffies(len)); + if (ret <= 0) { + dmaengine_terminate_all(chan); + dev_err(qspi->dev, "DMA wait_for_completion_timeout\n"); + if (!ret) + ret = -ETIMEDOUT; + goto err; + } + + ret = 0; + +err: + return ret; +} + +static int qspi_dma_sg(struct ti_qspi *qspi, + struct spi_flash_read_message *msg) +{ + struct scatterlist *sg; + dma_addr_t dma_src = qspi->mmap_phys_base + msg->from; + dma_addr_t dma_dst; + int i, len, ret = 0; + + for_each_sg(msg->rx_sg.sgl, sg, msg->rx_sg.nents, i) { + dma_dst = sg_dma_address(sg); + len = sg_dma_len(sg); + ret = qspi_dma_transfer(qspi, dma_dst, dma_src, len); + if (ret != 0) + return ret; + dma_src += len; + } + + return ret; +} + static void ti_qspi_enable_memory_map(struct spi_device *spi) { struct ti_qspi *qspi = spi_master_get_devdata(spi->master); @@ -435,9 +512,17 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi, if (!qspi->mmap_enabled) ti_qspi_enable_memory_map(spi); ti_qspi_setup_mmap_read(spi, msg); - memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); + + if (qspi->rx_chan) { + ret = qspi_dma_sg(qspi, msg); + if (ret != 0) + goto err; + } else { + memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); + } msg->retlen = msg->len; +err: mutex_unlock(&qspi->list_lock); return ret; @@ -525,6 +610,7 @@ static int ti_qspi_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; u32 max_freq; int ret = 0, num_cs, irq; + dma_cap_mask_t mask; master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); if (!master) @@ -539,6 +625,7 @@ static int ti_qspi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | SPI_BPW_MASK(8); + master->spi_flash_read = ti_qspi_spi_flash_read; if (!of_property_read_u32(np, "num-cs", &num_cs)) master->num_chipselect = num_cs; @@ -581,17 +668,6 @@ static int ti_qspi_probe(struct platform_device *pdev) goto free_master; } - if (res_mmap) { - qspi->mmap_base = devm_ioremap_resource(&pdev->dev, - res_mmap); - master->spi_flash_read = ti_qspi_spi_flash_read; - if (IS_ERR(qspi->mmap_base)) { - dev_err(&pdev->dev, - "falling back to PIO mode\n"); - master->spi_flash_read = NULL; - } - } - qspi->mmap_enabled = false; if (of_property_read_bool(np, "syscon-chipselects")) { qspi->ctrl_base = @@ -626,6 +702,33 @@ static int ti_qspi_probe(struct platform_device *pdev) if (ret) goto free_master; + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + + qspi->rx_chan = dma_request_channel(mask, NULL, NULL); + if (!qspi->rx_chan) { + dev_err(qspi->dev, + "No Rx DMA available, trying mmap mode\n"); + ret = 0; + goto no_dma; + } + master->dma_rx = qspi->rx_chan; + init_completion(&qspi->transfer_complete); + if (res_mmap) + qspi->mmap_phys_base = (dma_addr_t)res_mmap->start; + +no_dma: + if (!qspi->rx_chan && res_mmap) { + qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); + if (IS_ERR(qspi->mmap_base)) { + dev_info(&pdev->dev, + "mmap failed with error %ld using PIO mode\n", + PTR_ERR(qspi->mmap_base)); + qspi->mmap_base = NULL; + master->spi_flash_read = NULL; + } + } + qspi->mmap_enabled = false; return 0; free_master: @@ -635,9 +738,14 @@ free_master: static int ti_qspi_remove(struct platform_device *pdev) { + struct ti_qspi *qspi = platform_get_drvdata(pdev); + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (qspi->rx_chan) + dma_release_channel(qspi->rx_chan); + return 0; } -- 2.8.0 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2016-04-12 8:20 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-04-05 3:49 [PATCH 0/2] spi: Add DMA support for ti-qspi Vignesh R [not found] ` <1459828192-5531-1-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> 2016-04-05 3:49 ` [PATCH 1/2] spi: Add DMA support for spi_flash_read() Vignesh R [not found] ` <1459828192-5531-2-git-send-email-vigneshr-l0cyMroinI0@public.gmane.org> 2016-04-12 4:31 ` Mark Brown 2016-04-12 8:20 ` Vignesh R 2016-04-05 3:49 ` [PATCH 2/2] spi: spi-ti-qspi: Add DMA support for QSPI mmap read Vignesh R
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).