From: Robin Gong <yibin.gong@nxp.com>
Date: Wed, 17 Jun 2020 06:42:08 +0800
Subject: spi: introduce fallback to pio
Git-commit: 809b1b04df898b6d182069146231a3cbf5f2d9cc
Patch-mainline: v5.9-rc1
References: jsc#SLE-16106
Add fallback to pio mode in case dma transfer failed with error status
SPI_TRANS_FAIL_NO_START.
If spi client driver want to enable this feature please set xfer->error in
the proper place such as dmaengine_prep_slave_sg() failure detect(but no
any data put into spi bus yet). Besides, add master->fallback checking in
its can_dma() so that spi core could switch to pio next time. Please refer
to spi-imx.c.
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
Link: https://lore.kernel.org/r/1592347329-28363-2-git-send-email-yibin.gong@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Acked-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
---
drivers/spi/spi.c | 12 ++++++++++++
include/linux/spi/spi.h | 7 +++++++
2 files changed, 19 insertions(+)
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -982,6 +982,8 @@ static int __spi_unmap_msg(struct spi_co
spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
}
+ ctlr->cur_msg_mapped = false;
+
return 0;
}
#else /* !CONFIG_HAS_DMA */
@@ -1231,8 +1233,17 @@ static int spi_transfer_one_message(stru
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 &&
+ (xfer->error & SPI_TRANS_FAIL_NO_START)) {
+ __spi_unmap_msg(ctlr, msg);
+ ctlr->fallback = true;
+ xfer->error &= ~SPI_TRANS_FAIL_NO_START;
+ goto fallback_pio;
+ }
+
SPI_STATISTICS_INCREMENT_FIELD(statm,
errors);
SPI_STATISTICS_INCREMENT_FIELD(stats,
@@ -1688,6 +1699,7 @@ void spi_finalize_current_message(struct
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);
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -437,6 +437,8 @@ static inline void spi_unregister_driver
* @spi_transfer->ptp_sts_word_post were transmitted.
* If the driver does not set this, the SPI core takes the snapshot as
* close to the driver hand-over as possible.
+ * @fallback: fallback to pio if dma transfer return failure with
+ * SPI_TRANS_FAIL_NO_START.
*
* Each SPI controller can communicate with one or more @spi_device
* children. These make a small bus, sharing MOSI, MISO and SCK signals
@@ -592,6 +594,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;
@@ -835,6 +838,7 @@ extern void spi_res_release(struct spi_c
* back unset and they need the better resolution.
* @timestamped_post: See above. The reason why both exist is that these
* booleans are also used to keep state in the core SPI logic.
+ * @error: Error status logged by spi controller driver.
*
* SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
@@ -929,6 +933,9 @@ struct spi_transfer {
bool timestamped_post;
struct list_head transfer_list;
+
+#define SPI_TRANS_FAIL_NO_START BIT(0)
+ u16 error;
};
/**