Commit 809b1b04 authored by Robin Gong's avatar Robin Gong Committed by Mark Brown

spi: introduce fallback to pio

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: default avatarRobin Gong <yibin.gong@nxp.com>
Link: https://lore.kernel.org/r/1592347329-28363-2-git-send-email-yibin.gong@nxp.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent c314360c
...@@ -982,6 +982,8 @@ static int __spi_unmap_msg(struct spi_controller *ctlr, struct spi_message *msg) ...@@ -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); spi_unmap_buf(ctlr, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
} }
ctlr->cur_msg_mapped = false;
return 0; return 0;
} }
#else /* !CONFIG_HAS_DMA */ #else /* !CONFIG_HAS_DMA */
...@@ -1234,8 +1236,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr, ...@@ -1234,8 +1236,17 @@ static int spi_transfer_one_message(struct spi_controller *ctlr,
if (xfer->tx_buf || xfer->rx_buf) { if (xfer->tx_buf || xfer->rx_buf) {
reinit_completion(&ctlr->xfer_completion); reinit_completion(&ctlr->xfer_completion);
fallback_pio:
ret = ctlr->transfer_one(ctlr, msg->spi, xfer); ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
if (ret < 0) { 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, SPI_STATISTICS_INCREMENT_FIELD(statm,
errors); errors);
SPI_STATISTICS_INCREMENT_FIELD(stats, SPI_STATISTICS_INCREMENT_FIELD(stats,
...@@ -1693,6 +1704,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr) ...@@ -1693,6 +1704,7 @@ void spi_finalize_current_message(struct spi_controller *ctlr)
spin_lock_irqsave(&ctlr->queue_lock, flags); spin_lock_irqsave(&ctlr->queue_lock, flags);
ctlr->cur_msg = NULL; ctlr->cur_msg = NULL;
ctlr->cur_msg_prepared = false; ctlr->cur_msg_prepared = false;
ctlr->fallback = false;
kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages); kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
spin_unlock_irqrestore(&ctlr->queue_lock, flags); spin_unlock_irqrestore(&ctlr->queue_lock, flags);
......
...@@ -447,6 +447,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -447,6 +447,8 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* If the driver does not set this, the SPI core takes the snapshot as * If the driver does not set this, the SPI core takes the snapshot as
* close to the driver hand-over as possible. * close to the driver hand-over as possible.
* @irq_flags: Interrupt enable state during PTP system timestamping * @irq_flags: Interrupt enable state during PTP system timestamping
* @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 * Each SPI controller can communicate with one or more @spi_device
* children. These make a small bus, sharing MOSI, MISO and SCK signals * children. These make a small bus, sharing MOSI, MISO and SCK signals
...@@ -602,6 +604,7 @@ struct spi_controller { ...@@ -602,6 +604,7 @@ struct spi_controller {
bool auto_runtime_pm; bool auto_runtime_pm;
bool cur_msg_prepared; bool cur_msg_prepared;
bool cur_msg_mapped; bool cur_msg_mapped;
bool fallback;
struct completion xfer_completion; struct completion xfer_completion;
size_t max_dma_len; size_t max_dma_len;
...@@ -847,6 +850,7 @@ extern void spi_res_release(struct spi_controller *ctlr, ...@@ -847,6 +850,7 @@ extern void spi_res_release(struct spi_controller *ctlr,
* back unset and they need the better resolution. * back unset and they need the better resolution.
* @timestamped_post: See above. The reason why both exist is that these * @timestamped_post: See above. The reason why both exist is that these
* booleans are also used to keep state in the core SPI logic. * 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. * SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf. * Protocol drivers should always provide @rx_buf and/or @tx_buf.
...@@ -940,6 +944,9 @@ struct spi_transfer { ...@@ -940,6 +944,9 @@ struct spi_transfer {
bool timestamped; bool timestamped;
struct list_head transfer_list; struct list_head transfer_list;
#define SPI_TRANS_FAIL_NO_START BIT(0)
u16 error;
}; };
/** /**
......
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