Add SPI_CONTROLLER_FALLBACK to fallback to pio mode in case dma transfer failed. If spi client driver want to enable this feature please set master->flags with SPI_MASTER_FALLBACK and add master->fallback checking in its can_dma() as spi-imx.c Signed-off-by: Robin Gong <yibin.gong@xxxxxxx> --- drivers/spi/spi.c | 11 +++++++++++ include/linux/spi/spi.h | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 8158e28..3bf860c 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -982,6 +982,8 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } + ctlr->cur_msg_mapped = false; + return 0; } #else /* !CONFIG_HAS_DMA */ @@ -1234,8 +1236,16 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, if (xfer->tx_buf || xfer->rx_buf) { reinit_completion(&ctlr->xfer_completion); +fallback_pio: ret = ctlr->transfer_one(ctlr, msg->spi, xfer); if (ret < 0) { + if (ctlr->cur_msg_mapped && + (ctlr->flags & SPI_CONTROLLER_FALLBACK)) { + __spi_unmap_msg(ctlr, msg); + ctlr->fallback = true; + goto fallback_pio; + } + SPI_STATISTICS_INCREMENT_FIELD(statm, errors); SPI_STATISTICS_INCREMENT_FIELD(stats, @@ -1693,6 +1703,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr) spin_lock_irqsave(&ctlr->queue_lock, flags); ctlr->cur_msg = NULL; ctlr->cur_msg_prepared = false; + ctlr->fallback = false; kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); spin_unlock_irqrestore(&ctlr->queue_lock, flags); diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index aac57b5..95291fe4 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -506,6 +506,8 @@ struct spi_controller { #define SPI_CONTROLLER_MUST_TX BIT(4) /* requires tx */ #define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */ +/* fallback to PIO if DMA failed */ +#define SPI_CONTROLLER_FALLBACK BIT(6) /* flag indicating this is an SPI slave controller */ bool slave; @@ -602,6 +604,7 @@ struct spi_controller { bool auto_runtime_pm; bool cur_msg_prepared; bool cur_msg_mapped; + bool fallback; struct completion xfer_completion; size_t max_dma_len; @@ -1517,6 +1520,7 @@ of_find_spi_device_by_node(struct device_node *node) #define SPI_MASTER_NO_TX SPI_CONTROLLER_NO_TX #define SPI_MASTER_MUST_RX SPI_CONTROLLER_MUST_RX #define SPI_MASTER_MUST_TX SPI_CONTROLLER_MUST_TX +#define SPI_MASTER_FALLBACK SPI_CONTROLLER_FALLBACK #define spi_master_get_devdata(_ctlr) spi_controller_get_devdata(_ctlr) #define spi_master_set_devdata(_ctlr, _data) \ -- 2.7.4