From 251831bd4f4903415da7f0ce04dc0de26bc43f1d Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sun, 12 Mar 2017 11:11:43 +0000 Subject: [PATCH 1/5] spi: xlp: update for ARCH_VULCAN2 ARCH_VULCAN arm64 platform (for Broadcom Vulcan ARM64 processors) has been discontinued. Cavium's ThunderX2 CN99XX (ARCH_THUNDER2) will be the next revision of the platform. Update compile dependencies and ACPI ID to reflect this change. There is not need to retain ARCH_VULCAN since the Vulcan processor was never in production and ARCH_VULCAN will be deleted soon. Signed-off-by: Jayachandran C Signed-off-by: Mark Brown --- drivers/acpi/acpi_apd.c | 1 + drivers/spi/Kconfig | 2 +- drivers/spi/spi-xlp.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c index 7dd70927991e..89e74d0a6c33 100644 --- a/drivers/acpi/acpi_apd.c +++ b/drivers/acpi/acpi_apd.c @@ -164,6 +164,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = { #ifdef CONFIG_ARM64 { "APMC0D0F", APD_ADDR(xgene_i2c_desc) }, { "BRCM900D", APD_ADDR(vulcan_spi_desc) }, + { "CAV900D", APD_ADDR(vulcan_spi_desc) }, #endif { } }; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..8c40b5216ad6 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -705,7 +705,7 @@ config SPI_XILINX config SPI_XLP tristate "Netlogic XLP SPI controller driver" - depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST + depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST help Enable support for the SPI controller on the Netlogic XLP SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX diff --git a/drivers/spi/spi-xlp.c b/drivers/spi/spi-xlp.c index bea7a93a6046..80cb4d6af892 100644 --- a/drivers/spi/spi-xlp.c +++ b/drivers/spi/spi-xlp.c @@ -442,6 +442,7 @@ static int xlp_spi_probe(struct platform_device *pdev) #ifdef CONFIG_ACPI static const struct acpi_device_id xlp_spi_acpi_match[] = { { "BRCM900D", 0 }, + { "CAV900D", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, xlp_spi_acpi_match); From 1351aaeb50b2ae5eb5469b3d3d0a84073a127a39 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Fri, 24 Mar 2017 12:12:15 +0530 Subject: [PATCH 2/5] spi: spi-ti-qspi: Use dma_engine wrapper for dma memcpy call Instead of calling device_prep_dma_memcpy() directly with dma_device pointer, use the newly introduced dmaengine_prep_dma_memcpy() wrapper API. Signed-off-by: Vignesh R Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index ec6fb09e2e17..bd19a20a122e 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -401,8 +401,7 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, struct dma_async_tx_descriptor *tx; int ret; - tx = dma_dev->device_prep_dma_memcpy(chan, dma_dst, dma_src, - len, flags); + tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags); if (!tx) { dev_err(qspi->dev, "device_prep_dma_memcpy error\n"); return -EIO; From cb3c8e5ade3f01839ce0a9388ddc9729de4e2d6d Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Mon, 27 Mar 2017 10:59:28 +0530 Subject: [PATCH 3/5] spi: spi-ti-qspi: Remove unused dma_dev variable commit 1351aaeb50b2 ("spi: spi-ti-qspi: Use dma_engine wrapper for dma memcpy call") introduced this warning: drivers/spi/spi-ti-qspi.c: In function 'ti_qspi_dma_xfer': drivers/spi/spi-ti-qspi.c:398:21: warning: unused variable 'dma_dev' [-Wunused-variable] struct dma_device *dma_dev = chan->device; Fix it by removing the unused variable. Signed-off-by: Vignesh R Reported-by: Stephen Rothwell Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index bd19a20a122e..804914ebfd9d 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -395,7 +395,6 @@ static int ti_qspi_dma_xfer(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; From 2bca34455b257d75080d87e800ae14afe49001bf Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 11 Apr 2017 17:22:24 +0530 Subject: [PATCH 4/5] spi: Add can_dma like interface for spi_flash_read Add an interface analogous to ->can_dma() for spi_flash_read() interface. This will enable SPI controller drivers to inform SPI core when not to do DMA mappings. Signed-off-by: Vignesh R Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- include/linux/spi/spi.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 656dd3e3220c..5e1bb43b8a8f 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2811,7 +2811,7 @@ int spi_flash_read(struct spi_device *spi, mutex_lock(&master->bus_lock_mutex); mutex_lock(&master->io_mutex); - if (master->dma_rx) { + if (master->dma_rx && master->spi_flash_can_dma(spi, msg)) { rx_dev = master->dma_rx->device->dev; ret = spi_map_buf(master, rx_dev, &msg->rx_sg, msg->buf, msg->len, diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 75c6bd0ac605..cd8ae65568e3 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -375,6 +375,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @unprepare_message: undo any work done by prepare_message(). * @spi_flash_read: to support spi-controller hardwares that provide * accelerated interface to read from flash devices. + * @spi_flash_can_dma: analogous to can_dma() interface, but for + * controllers implementing spi_flash_read. * @flash_read_supported: spi device supports flash read * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS * number. Any individual value may be -ENOENT for CS lines that @@ -538,6 +540,8 @@ struct spi_master { struct spi_message *message); int (*spi_flash_read)(struct spi_device *spi, struct spi_flash_read_message *msg); + bool (*spi_flash_can_dma)(struct spi_device *spi, + struct spi_flash_read_message *msg); bool (*flash_read_supported)(struct spi_device *spi); /* From c687c46e9e4527c4b4d82bc3cca58c1b08bcfb83 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 11 Apr 2017 17:22:25 +0530 Subject: [PATCH 5/5] spi: spi-ti-qspi: Use bounce buffer if read buffer is not DMA'ble Flash filesystems like JFFS2, UBIFS and MTD block layer can provide vmalloc'd or kmap'd buffers that cannot be mapped using dma_map_sg() and can potentially be in memory region above 32bit addressable region(ie buffers belonging to memory region backed by LPAE) of DMA, implement spi_flash_can_dma() interface to inform SPI core not to map such buffers. When buffers are not mapped for DMA, then use a pre allocated bounce buffer(64K = typical flash erase sector size) to read from flash and then do a copy to actual destination buffer. This is approach is much faster than using memcpy using CPU and also reduces CPU load. With this patch, UBIFS read speed is ~18MB/s and CPU utilization <20% on DRA74 Rev H EVM. Performance degradation is negligible when compared with non bounce buffer case while using UBIFS. Signed-off-by: Vignesh R Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 66 ++++++++++++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 804914ebfd9d..23a06148b8ae 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -57,6 +58,8 @@ struct ti_qspi { struct ti_qspi_regs ctx_reg; dma_addr_t mmap_phys_base; + dma_addr_t rx_bb_dma_addr; + void *rx_bb_addr; struct dma_chan *rx_chan; u32 spi_max_frequency; @@ -126,6 +129,8 @@ struct ti_qspi { #define QSPI_SETUP_ADDR_SHIFT 8 #define QSPI_SETUP_DUMMY_SHIFT 10 +#define QSPI_DMA_BUFFER_SIZE SZ_64K + static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, unsigned long reg) { @@ -429,6 +434,35 @@ static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst, return 0; } +static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, + struct spi_flash_read_message *msg) +{ + size_t readsize = msg->len; + void *to = msg->buf; + dma_addr_t dma_src = qspi->mmap_phys_base + msg->from; + int ret = 0; + + /* + * Use bounce buffer as FS like jffs2, ubifs may pass + * buffers that does not belong to kernel lowmem region. + */ + while (readsize != 0) { + size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE, + readsize); + + ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr, + dma_src, xfer_len); + if (ret != 0) + return ret; + memcpy(to, qspi->rx_bb_addr, xfer_len); + readsize -= xfer_len; + dma_src += xfer_len; + to += xfer_len; + } + + return ret; +} + static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg, loff_t from) { @@ -496,6 +530,12 @@ static void ti_qspi_setup_mmap_read(struct spi_device *spi, QSPI_SPI_SETUP_REG(spi->chip_select)); } +static bool ti_qspi_spi_flash_can_dma(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + return virt_addr_valid(msg->buf); +} + static int ti_qspi_spi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { @@ -509,15 +549,12 @@ static int ti_qspi_spi_flash_read(struct spi_device *spi, ti_qspi_setup_mmap_read(spi, msg); if (qspi->rx_chan) { - if (msg->cur_msg_mapped) { + if (msg->cur_msg_mapped) ret = ti_qspi_dma_xfer_sg(qspi, msg->rx_sg, msg->from); - if (ret) - goto err_unlock; - } else { - dev_err(qspi->dev, "Invalid address for DMA\n"); - ret = -EIO; + else + ret = ti_qspi_dma_bounce_buffer(qspi, msg); + if (ret) goto err_unlock; - } } else { memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len); } @@ -718,6 +755,17 @@ static int ti_qspi_probe(struct platform_device *pdev) ret = 0; goto no_dma; } + qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev, + QSPI_DMA_BUFFER_SIZE, + &qspi->rx_bb_dma_addr, + GFP_KERNEL | GFP_DMA); + if (!qspi->rx_bb_addr) { + dev_err(qspi->dev, + "dma_alloc_coherent failed, using PIO mode\n"); + dma_release_channel(qspi->rx_chan); + goto no_dma; + } + master->spi_flash_can_dma = ti_qspi_spi_flash_can_dma; master->dma_rx = qspi->rx_chan; init_completion(&qspi->transfer_complete); if (res_mmap) @@ -757,6 +805,10 @@ static int ti_qspi_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (qspi->rx_bb_addr) + dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE, + qspi->rx_bb_addr, + qspi->rx_bb_dma_addr); if (qspi->rx_chan) dma_release_channel(qspi->rx_chan);