From 08ba7ae35b15cd13b965d5fd5a835e0a0cb803e6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 13 Jun 2018 10:41:15 +0200 Subject: spi: sh-msiof: Make sure all DMA operations have completed In case of a bi-directional transfer, receive DMA may complete in the rcar-dmac driver before transmit DMA, due to scheduling latencies. As the MSIOF driver waits for completion of the receive DMA only, it may submit the next transmit DMA request before the previous one has completed. Make the driver more robust by waiting for the completion of both receive and transmit DMA, when applicable. Based on a patch in the BSP by Ryo Kataoka. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 53 +++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 24 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 0e74cbf9929d..539d6d1a277a 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -49,6 +49,7 @@ struct sh_msiof_spi_priv { struct platform_device *pdev; struct sh_msiof_spi_info *info; struct completion done; + struct completion done_txdma; unsigned int tx_fifo_size; unsigned int rx_fifo_size; unsigned int min_div_pow; @@ -649,19 +650,21 @@ static int sh_msiof_slave_abort(struct spi_master *master) p->slave_aborted = true; complete(&p->done); + complete(&p->done_txdma); return 0; } -static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p) +static int sh_msiof_wait_for_completion(struct sh_msiof_spi_priv *p, + struct completion *x) { if (spi_controller_is_slave(p->master)) { - if (wait_for_completion_interruptible(&p->done) || + if (wait_for_completion_interruptible(x) || p->slave_aborted) { dev_dbg(&p->pdev->dev, "interrupted\n"); return -EINTR; } } else { - if (!wait_for_completion_timeout(&p->done, HZ)) { + if (!wait_for_completion_timeout(x, HZ)) { dev_err(&p->pdev->dev, "timeout\n"); return -ETIMEDOUT; } @@ -711,7 +714,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, } /* wait for tx fifo to be emptied / rx fifo to be filled */ - ret = sh_msiof_wait_for_completion(p); + ret = sh_msiof_wait_for_completion(p, &p->done); if (ret) goto stop_reset; @@ -740,10 +743,7 @@ stop_ier: static void sh_msiof_dma_complete(void *arg) { - struct sh_msiof_spi_priv *p = arg; - - sh_msiof_write(p, IER, 0); - complete(&p->done); + complete(arg); } static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, @@ -764,7 +764,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, return -EAGAIN; desc_rx->callback = sh_msiof_dma_complete; - desc_rx->callback_param = p; + desc_rx->callback_param = &p->done; cookie = dmaengine_submit(desc_rx); if (dma_submit_error(cookie)) return cookie; @@ -782,13 +782,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, goto no_dma_tx; } - if (rx) { - /* No callback */ - desc_tx->callback = NULL; - } else { - desc_tx->callback = sh_msiof_dma_complete; - desc_tx->callback_param = p; - } + desc_tx->callback = sh_msiof_dma_complete; + desc_tx->callback_param = &p->done_txdma; cookie = dmaengine_submit(desc_tx); if (dma_submit_error(cookie)) { ret = cookie; @@ -805,6 +800,8 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, sh_msiof_write(p, IER, ier_bits); reinit_completion(&p->done); + if (tx) + reinit_completion(&p->done_txdma); p->slave_aborted = false; /* Now start DMA */ @@ -819,17 +816,24 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx, goto stop_dma; } - /* wait for tx/rx DMA completion */ - ret = sh_msiof_wait_for_completion(p); - if (ret) - goto stop_reset; + if (tx) { + /* wait for tx DMA completion */ + ret = sh_msiof_wait_for_completion(p, &p->done_txdma); + if (ret) + goto stop_reset; + } - if (!rx) { - reinit_completion(&p->done); - sh_msiof_write(p, IER, IER_TEOFE); + if (rx) { + /* wait for rx DMA completion */ + ret = sh_msiof_wait_for_completion(p, &p->done); + if (ret) + goto stop_reset; + sh_msiof_write(p, IER, 0); + } else { /* wait for tx fifo to be emptied */ - ret = sh_msiof_wait_for_completion(p); + sh_msiof_write(p, IER, IER_TEOFE); + ret = sh_msiof_wait_for_completion(p, &p->done); if (ret) goto stop_reset; } @@ -1327,6 +1331,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p->min_div_pow = chipdata->min_div_pow; init_completion(&p->done); + init_completion(&p->done_txdma); p->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(p->clk)) { -- cgit 1.4.1 From 931c4e9a72ae91d59c5332ffb6812911a749da8e Mon Sep 17 00:00:00 2001 From: Janek Kotas Date: Mon, 4 Jun 2018 11:24:44 +0000 Subject: spi: cadence: Change usleep_range() to udelay(), for atomic context The path "spi: cadence: Add usleep_range() for cdns_spi_fill_tx_fifo()" added a usleep_range() function call, which cannot be used in atomic context. However the cdns_spi_fill_tx_fifo() function can be called during an interrupt which may result in a kernel panic: BUG: scheduling while atomic: grep/561/0x00010002 Modules linked in: Preemption disabled at: [] wait_for_common+0x48/0x178 CPU: 0 PID: 561 Comm: grep Not tainted 4.17.0 #1 Hardware name: Cadence CSP (DT) Call trace: dump_backtrace+0x0/0x198 show_stack+0x14/0x20 dump_stack+0x8c/0xac __schedule_bug+0x6c/0xb8 __schedule+0x570/0x5d8 schedule+0x34/0x98 schedule_hrtimeout_range_clock+0x98/0x110 schedule_hrtimeout_range+0x10/0x18 usleep_range+0x64/0x98 cdns_spi_fill_tx_fifo+0x70/0xb0 cdns_spi_irq+0xd0/0xe0 __handle_irq_event_percpu+0x9c/0x128 handle_irq_event_percpu+0x34/0x88 handle_irq_event+0x48/0x78 handle_fasteoi_irq+0xbc/0x1b0 generic_handle_irq+0x24/0x38 __handle_domain_irq+0x84/0xf8 gic_handle_irq+0xc4/0x180 This patch replaces the function call with udelay() which can be used in an atomic context, like an interrupt. Signed-off-by: Jan Kotas Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-cadence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index f3dad6fcdc35..a568f35522f9 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -319,7 +319,7 @@ static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi) */ if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) - usleep_range(10, 20); + udelay(10); if (xspi->txbuf) cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); -- cgit 1.4.1 From fb9acf5f1f21f1de193523ff780bda375b4c2e21 Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Mon, 4 Jun 2018 16:34:25 +0200 Subject: spi: orion: fix CS GPIO handling again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code did not de-assert any CS GPIOs before probing slaves. This means that several CS signals could be active at once, garbling the communication. Whether this was actually a problem depended on the type of the SPI device attached (so my "spidev" for userspace access worked correctly because its probe was effectively a no-op), and on the state of the GPIO pins at SoC's boot. The code was already iterating through all DT children of the SPI controller, so this change re-uses that loop for CS GPIO setup as well. This means that this might change the number of the HW CS signal which is picked for all GPIO CS devices. Previously, the lowest one was used, but we now use the first one from the DT. With this move of the code, we can also finally initialize each GPIO CS lane before registering the SPI controller (which in turn probes for slaves). I tried to fix this in 544248623b95 already, but that only did it half way by registering the GPIOs properly. That patch failed to set their logic signals early enough, though. Signed-off-by: Jan Kundrát Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 77 +++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 37 deletions(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index d01a6adc726e..47ef6b1a2e76 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -681,9 +682,9 @@ static int orion_spi_probe(struct platform_device *pdev) goto out_rel_axi_clk; } - /* Scan all SPI devices of this controller for direct mapped devices */ for_each_available_child_of_node(pdev->dev.of_node, np) { u32 cs; + int cs_gpio; /* Get chip-select number from the "reg" property */ status = of_property_read_u32(np, "reg", &cs); @@ -694,6 +695,44 @@ static int orion_spi_probe(struct platform_device *pdev) continue; } + /* + * Initialize the CS GPIO: + * - properly request the actual GPIO signal + * - de-assert the logical signal so that all GPIO CS lines + * are inactive when probing for slaves + * - find an unused physical CS which will be driven for any + * slave which uses a CS GPIO + */ + cs_gpio = of_get_named_gpio(pdev->dev.of_node, "cs-gpios", cs); + if (cs_gpio > 0) { + char *gpio_name; + int cs_flags; + + if (spi->unused_hw_gpio == -1) { + dev_info(&pdev->dev, + "Selected unused HW CS#%d for any GPIO CSes\n", + cs); + spi->unused_hw_gpio = cs; + } + + gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, + "%s-CS%d", dev_name(&pdev->dev), cs); + if (!gpio_name) { + status = -ENOMEM; + goto out_rel_axi_clk; + } + + cs_flags = of_property_read_bool(np, "spi-cs-high") ? + GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH; + status = devm_gpio_request_one(&pdev->dev, cs_gpio, + cs_flags, gpio_name); + if (status) { + dev_err(&pdev->dev, + "Can't request GPIO for CS %d\n", cs); + goto out_rel_axi_clk; + } + } + /* * Check if an address is configured for this SPI device. If * not, the MBus mapping via the 'ranges' property in the 'soc' @@ -740,44 +779,8 @@ static int orion_spi_probe(struct platform_device *pdev) if (status < 0) goto out_rel_pm; - if (master->cs_gpios) { - int i; - for (i = 0; i < master->num_chipselect; ++i) { - char *gpio_name; - - if (!gpio_is_valid(master->cs_gpios[i])) { - continue; - } - - gpio_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, - "%s-CS%d", dev_name(&pdev->dev), i); - if (!gpio_name) { - status = -ENOMEM; - goto out_rel_master; - } - - status = devm_gpio_request(&pdev->dev, - master->cs_gpios[i], gpio_name); - if (status) { - dev_err(&pdev->dev, - "Can't request GPIO for CS %d\n", - master->cs_gpios[i]); - goto out_rel_master; - } - if (spi->unused_hw_gpio == -1) { - dev_info(&pdev->dev, - "Selected unused HW CS#%d for any GPIO CSes\n", - i); - spi->unused_hw_gpio = i; - } - } - } - - return status; -out_rel_master: - spi_unregister_master(master); out_rel_pm: pm_runtime_disable(&pdev->dev); out_rel_axi_clk: -- cgit 1.4.1 From 8570043e2cc659f375336fb8141917ca1b050234 Mon Sep 17 00:00:00 2001 From: Esben Haabendal Date: Wed, 20 Jun 2018 09:34:36 +0200 Subject: spi: spi-fsl-dspi: Fixup regmap configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mark volatile registers to avoid caching bugs. Note: SPI_MCR is marked volatile because of CLR_TXF and CLR_RXF bits. Signed-off-by: Esben Haabendal Acked-by: Martin Hundebøll Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 0630962ce442..1c1070114246 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -943,11 +943,23 @@ static int dspi_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); +static const struct regmap_range dspi_volatile_ranges[] = { + regmap_reg_range(SPI_MCR, SPI_TCR), + regmap_reg_range(SPI_SR, SPI_SR), + regmap_reg_range(SPI_PUSHR, SPI_RXFR3), +}; + +static const struct regmap_access_table dspi_volatile_table = { + .yes_ranges = dspi_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges), +}; + static const struct regmap_config dspi_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = 0x88, + .volatile_table = &dspi_volatile_table, }; static void dspi_init(struct fsl_dspi *dspi) -- cgit 1.4.1 From 2ba87a9bcc7a10aa28af9fbf5b4354b3168366e2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 11 Jul 2018 13:18:59 +0000 Subject: spi: cadence: Fix missing clk_disable_unprepare() on error in cnds_runtime_resume() Fix the missing clk_disable_unprepare() before return from cnds_runtime_resume() in the error handling case. Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- drivers/spi/spi-cadence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index a568f35522f9..7c88f74f7f47 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -739,7 +739,7 @@ static int __maybe_unused cnds_runtime_resume(struct device *dev) ret = clk_prepare_enable(xspi->ref_clk); if (ret) { dev_err(dev, "Cannot enable device clock.\n"); - clk_disable(xspi->pclk); + clk_disable_unprepare(xspi->pclk); return ret; } return 0; -- cgit 1.4.1 From 66b19d762378785d1568b5650935205edfeb0503 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 17 Jul 2018 16:23:10 +0200 Subject: spi: dw: fix possible race condition It is possible to get an interrupt as soon as it is requested. dw_spi_irq does spi_controller_get_devdata(master) and expects it to be different than NULL. However, spi_controller_set_devdata() is called after request_irq(), resulting in the following crash: CPU 0 Unable to handle kernel paging request at virtual address 00000030, epc == 8058e09c, ra == 8018ff90 [...] Call Trace: [<8058e09c>] dw_spi_irq+0x8/0x64 [<8018ff90>] __handle_irq_event_percpu+0x70/0x1d4 [<80190128>] handle_irq_event_percpu+0x34/0x8c [<801901c4>] handle_irq_event+0x44/0x80 [<801951a8>] handle_level_irq+0xdc/0x194 [<8018f580>] generic_handle_irq+0x38/0x50 [<804c6924>] ocelot_irq_handler+0x104/0x1c0 Signed-off-by: Alexandre Belloni Reviewed-by: Andy Shevchenko Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index f693bfe95ab9..a087464efdd7 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -485,6 +485,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); + spi_controller_set_devdata(master, dws); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), master); if (ret < 0) { @@ -518,7 +520,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) } } - spi_controller_set_devdata(master, dws); ret = devm_spi_register_controller(dev, master); if (ret) { dev_err(&master->dev, "problem registering spi master\n"); -- cgit 1.4.1 From 563a53f3906a6b43692498e5b3ae891fac93a4af Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Fri, 10 Aug 2018 11:13:52 +0200 Subject: spi: davinci: fix a NULL pointer dereference On non-OF systems spi->controlled_data may be NULL. This causes a NULL pointer derefence on dm365-evm. Signed-off-by: Bartosz Golaszewski Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/spi') diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 60d59b003aa4..4ffc0f495be8 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -217,7 +217,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) pdata = &dspi->pdata; /* program delay transfers if tx_delay is non zero */ - if (spicfg->wdelay) + if (spicfg && spicfg->wdelay) spidat1 |= SPIDAT1_WDEL; /* -- cgit 1.4.1