Commit 2cbee7f8 authored by Cezary Gapinski's avatar Cezary Gapinski Committed by Mark Brown

spi: stm32: fix DMA configuration with only one channel

When SPI driver is configured to work only with TX or RX DMA channel
then dmaengine functions can dereferene NULL pointer.

Running full-duplex mode when when only RX or TX DMA channel is
available can cause overrun condition or incorrect writing to transmit
buffer so disable this types of DMA configuration and go back to
interrupt mode.
Signed-off-by: default avatarCezary Gapinski <cezary.gapinski@gmail.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent d4c9134a
...@@ -427,9 +427,9 @@ static void stm32_spi_disable(struct stm32_spi *spi) ...@@ -427,9 +427,9 @@ static void stm32_spi_disable(struct stm32_spi *spi)
if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0))
stm32_spi_read_rxfifo(spi, true); stm32_spi_read_rxfifo(spi, true);
if (spi->cur_usedma && spi->tx_buf) if (spi->cur_usedma && spi->dma_tx)
dmaengine_terminate_all(spi->dma_tx); dmaengine_terminate_all(spi->dma_tx);
if (spi->cur_usedma && spi->rx_buf) if (spi->cur_usedma && spi->dma_rx)
dmaengine_terminate_all(spi->dma_rx); dmaengine_terminate_all(spi->dma_rx);
stm32_spi_clr_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE); stm32_spi_clr_bits(spi, STM32_SPI_CR1, SPI_CR1_SPE);
...@@ -750,7 +750,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, ...@@ -750,7 +750,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
spin_lock_irqsave(&spi->lock, flags); spin_lock_irqsave(&spi->lock, flags);
rx_dma_desc = NULL; rx_dma_desc = NULL;
if (spi->rx_buf) { if (spi->rx_buf && spi->dma_rx) {
stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM); stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM);
dmaengine_slave_config(spi->dma_rx, &rx_dma_conf); dmaengine_slave_config(spi->dma_rx, &rx_dma_conf);
...@@ -765,7 +765,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, ...@@ -765,7 +765,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
} }
tx_dma_desc = NULL; tx_dma_desc = NULL;
if (spi->tx_buf) { if (spi->tx_buf && spi->dma_tx) {
stm32_spi_dma_config(spi, &tx_dma_conf, DMA_MEM_TO_DEV); stm32_spi_dma_config(spi, &tx_dma_conf, DMA_MEM_TO_DEV);
dmaengine_slave_config(spi->dma_tx, &tx_dma_conf); dmaengine_slave_config(spi->dma_tx, &tx_dma_conf);
...@@ -776,8 +776,11 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, ...@@ -776,8 +776,11 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
DMA_PREP_INTERRUPT); DMA_PREP_INTERRUPT);
} }
if ((spi->tx_buf && !tx_dma_desc) || if ((spi->tx_buf && spi->dma_tx && !tx_dma_desc) ||
(spi->rx_buf && !rx_dma_desc)) (spi->rx_buf && spi->dma_rx && !rx_dma_desc))
goto dma_desc_error;
if (spi->cur_comm == SPI_FULL_DUPLEX && (!tx_dma_desc || !rx_dma_desc))
goto dma_desc_error; goto dma_desc_error;
if (rx_dma_desc) { if (rx_dma_desc) {
...@@ -822,7 +825,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, ...@@ -822,7 +825,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
return 1; return 1;
dma_submit_error: dma_submit_error:
if (spi->rx_buf) if (spi->dma_rx)
dmaengine_terminate_all(spi->dma_rx); dmaengine_terminate_all(spi->dma_rx);
dma_desc_error: dma_desc_error:
...@@ -832,6 +835,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, ...@@ -832,6 +835,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi,
dev_info(spi->dev, "DMA issue: fall back to irq transfer\n"); dev_info(spi->dev, "DMA issue: fall back to irq transfer\n");
spi->cur_usedma = false;
return stm32_spi_transfer_one_irq(spi); return stm32_spi_transfer_one_irq(spi);
} }
...@@ -984,7 +988,7 @@ static int stm32_spi_transfer_one(struct spi_master *master, ...@@ -984,7 +988,7 @@ static int stm32_spi_transfer_one(struct spi_master *master,
spi->rx_len = spi->rx_buf ? transfer->len : 0; spi->rx_len = spi->rx_buf ? transfer->len : 0;
spi->cur_usedma = (master->can_dma && spi->cur_usedma = (master->can_dma &&
stm32_spi_can_dma(master, spi_dev, transfer)); master->can_dma(master, spi_dev, transfer));
ret = stm32_spi_transfer_one_setup(spi, spi_dev, transfer); ret = stm32_spi_transfer_one_setup(spi, spi_dev, transfer);
if (ret) { if (ret) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment