@@ -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);
@@ -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) \
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@nxp.com> --- drivers/spi/spi.c | 11 +++++++++++ include/linux/spi/spi.h | 4 ++++ 2 files changed, 15 insertions(+)