Introudce fallback pio way at spi core level so that the tx/rx buffer
mapped by spi core for dma could be unmap and fallback pio again. Hence no
need the below patch where 'dma_sync_sg_for_devic' to sync fresh data back
into 'device' memory and sync to 'cpu' again in spi core.
https://www.spinics.net/lists/arm-kernel/msg812236.html
If you want to use this fallback feature, please set xfer->error with
SPI_TRANS_FAIL_NO_START in case dma transfer failed(but no any data push
into spi bus yet) in spi client driver and add 'master->fallback' checking
in your can_dma() to ensure spi core can fallback to pio next time.
change from:
v2:
1. Add error flag in stuct spi_transfer and fallback to pio if spi client
return SPI_TRANS_FAIL_NO_START failure before dma transfer start.
2. Remove SPI_MASTER_FALLBACK set on master->flags since the above error
flag could ensure no any impact for other spi client drivers which don't
need this feature.
Robin Gong (2):
spi: introduce fallback to pio
spi: imx: add fallback feature
drivers/spi/spi-imx.c | 23 +++++------------------
drivers/spi/spi.c | 11 +++++++++++
include/linux/spi/spi.h | 4 ++++
3 files changed, 20 insertions(+), 18 deletions(-)
--
2.7.4
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 <[email protected]>
---
drivers/spi/spi.c | 12 ++++++++++++
include/linux/spi/spi.h | 7 +++++++
2 files changed, 19 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 8158e28..6fa5659 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,17 @@ 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 &&
+ (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,
@@ -1693,6 +1704,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..b4917df 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -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
* close to the driver hand-over as possible.
* @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
* children. These make a small bus, sharing MOSI, MISO and SCK signals
@@ -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;
@@ -847,6 +850,7 @@ extern void spi_res_release(struct spi_controller *ctlr,
* 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.
@@ -940,6 +944,9 @@ struct spi_transfer {
bool timestamped;
struct list_head transfer_list;
+
+#define SPI_TRANS_FAIL_NO_START BIT(0)
+ u16 error;
};
/**
--
2.7.4
Add fallback pio feature in case dma transfer failed before start.
Besides, another whole pio transfer including setup_transfer will be
issued by spi core, no need to restore jobs like commit bcd8e7761ec9 ("spi:
imx: fallback to PIO if dma setup failure").
Signed-off-by: Robin Gong <[email protected]>
---
drivers/spi/spi-imx.c | 35 ++++++++++++++---------------------
1 file changed, 14 insertions(+), 21 deletions(-)
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index b7a85e3..2b8d339 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -224,7 +224,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi,
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(master);
- if (!use_dma)
+ if (!use_dma || master->fallback)
return false;
if (!master->dma_rx)
@@ -1364,11 +1364,12 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
ret = spi_imx_dma_configure(master);
if (ret)
- return ret;
+ goto dma_failure_no_start;
if (!spi_imx->devtype_data->setup_wml) {
dev_err(spi_imx->dev, "No setup_wml()?\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto dma_failure_no_start;
}
spi_imx->devtype_data->setup_wml(spi_imx);
@@ -1379,8 +1380,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
rx->sgl, rx->nents, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_rx)
- return -EINVAL;
+ if (!desc_rx) {
+ ret = -EINVAL;
+ goto dma_failure_no_start;
+ }
desc_rx->callback = spi_imx_dma_rx_callback;
desc_rx->callback_param = (void *)spi_imx;
@@ -1425,6 +1428,10 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
}
return transfer->len;
+/* fallback to pio */
+dma_failure_no_start:
+ transfer->error |= SPI_TRANS_FAIL_NO_START;
+ return ret;
}
static int spi_imx_pio_transfer(struct spi_device *spi,
@@ -1507,7 +1514,6 @@ static int spi_imx_transfer(struct spi_device *spi,
struct spi_transfer *transfer)
{
struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
- int ret;
/* flush rxfifo before transfer */
while (spi_imx->devtype_data->rx_available(spi_imx))
@@ -1516,21 +1522,8 @@ static int spi_imx_transfer(struct spi_device *spi,
if (spi_imx->slave_mode)
return spi_imx_pio_transfer_slave(spi, transfer);
- /*
- * fallback PIO mode if dma setup error happen, for example sdma
- * firmware may not be updated as ERR009165 required.
- */
- if (spi_imx->usedma) {
- ret = spi_imx_dma_transfer(spi_imx, transfer);
- if (ret != -EINVAL)
- return ret;
-
- spi_imx->devtype_data->disable_dma(spi_imx);
-
- spi_imx->usedma = false;
- spi_imx->dynamic_burst = spi_imx->devtype_data->dynamic_burst;
- dev_dbg(&spi->dev, "Fallback to PIO mode\n");
- }
+ if (spi_imx->usedma)
+ return spi_imx_dma_transfer(spi_imx, transfer);
return spi_imx_pio_transfer(spi, transfer);
}
--
2.7.4
On Wed, 17 Jun 2020 06:42:07 +0800, Robin Gong wrote:
> Introudce fallback pio way at spi core level so that the tx/rx buffer
> mapped by spi core for dma could be unmap and fallback pio again. Hence no
> need the below patch where 'dma_sync_sg_for_devic' to sync fresh data back
> into 'device' memory and sync to 'cpu' again in spi core.
> https://www.spinics.net/lists/arm-kernel/msg812236.html
>
> If you want to use this fallback feature, please set xfer->error with
> SPI_TRANS_FAIL_NO_START in case dma transfer failed(but no any data push
> into spi bus yet) in spi client driver and add 'master->fallback' checking
> in your can_dma() to ensure spi core can fallback to pio next time.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
Thanks!
[1/2] spi: introduce fallback to pio
commit: 809b1b04df898b6d182069146231a3cbf5f2d9cc
[2/2] spi: imx: add fallback feature
commit: 7a908832ace7543ca996303928bfed7190dd2cdd
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark