* RE: [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be started
2026-06-24 15:19 [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be started Javier Fernandez Pastrana
@ 2026-06-24 15:27 ` Carlos Song
2026-06-24 15:31 ` sashiko-bot
2026-06-24 16:30 ` Frank Li
2 siblings, 0 replies; 4+ messages in thread
From: Carlos Song @ 2026-06-24 15:27 UTC (permalink / raw)
To: Javier Fernandez Pastrana, Mark Brown, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-spi@vger.kernel.org,
imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Cc: stable@vger.kernel.org
> -----Original Message-----
> From: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
> Sent: Wednesday, June 24, 2026 11:20 PM
> To: Mark Brown <broonie@kernel.org>; Frank Li <frank.li@nxp.com>; Sascha
> Hauer <s.hauer@pengutronix.de>; Pengutronix Kernel Team
> <kernel@pengutronix.de>; Fabio Estevam <festevam@gmail.com>; Carlos Song
> <carlos.song@nxp.com>; linux-spi@vger.kernel.org; imx@lists.linux.dev;
> linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org
> Cc: javier.pastrana@linutronix.de; stable@vger.kernel.org
> Subject: [EXT] [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be
> started
>
> [Some people who received this message don't often get email from
> javier.pastrana@linutronix.de. Learn why this is important at
> https://aka.ms/LearnAboutSenderIdentification ]
>
> Caution: This is an external email. Please take care when clicking links or opening
> attachments. When in doubt, report the message using the 'Report this email'
> button
>
>
> When spi_imx_can_dma() selects DMA, the ECSPI is configured for DMA:
> spi_imx_setupxfer() sets CTRL.SMC and clears dynamic_burst, and
> spi_imx_dma_transfer() programs the dynamic-burst BURST_LENGTH and the
> SDMA watermarks.
>
> If the DMA descriptor cannot be prepared (dmaengine_prep_slave_single()
> returns NULL), the transfer is failed with SPI_TRANS_FAIL_NO_START and falls
> back to PIO. The dynamic-burst DMA path uses its own bounce buffers instead of
> the SPI core's mapping, so xfer->{tx,rx}_sg_mapped are not set and the core's
> DMA->PIO retry is skipped; the driver falls back to PIO internally. But none of the
> DMA-mode configuration is undone, so the PIO transfer runs with CTRL.SMC set,
> the wrong burst length and dynamic_burst cleared, and the transferred data is
> corrupted.
>
> This is easily hit on i.MX8MP boards that describe ECSPI DMA in the device tree
> but run SDMA on ROM firmware (no external sdma-imx7d.bin):
> every ECSPI DMA prepare fails. An Infineon SLB9670 TPM on ECSPI1 then returns
> shifted TPM2_GetCapability data, is flagged "field failure mode", /dev/tpmrm0 is
> never created.
>
> Set controller->fallback before re-running spi_imx_setupxfer() so the ECSPI is
> reconfigured exactly like a normal PIO transfer. With
> controller->fallback set, spi_imx_setupxfer() sees spi_imx_can_dma()
> return false, so it clears spi_imx->usedma and reprograms the controller (clears
> CTRL.SMC, restores dynamic_burst and the PIO burst length). No explicit
> spi_imx->usedma = false is needed: setupxfer() already updates it from the
> can_dma() result.
>
> Fixes: faa8e404ad8e ("spi: imx: support dynamic burst length for ECSPI DMA
> mode")
> Cc: stable@vger.kernel.org
> Signed-off-by: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
Hi,
LGTM. Thank you!
Acked-by: Carlos Song <carlos.song@nxp.com>
> ---
> v2: drop redundant spi_imx->usedma = false; spi_imx_setupxfer() already
> clears it via spi_imx_can_dma() (Carlos Song)
>
> drivers/spi/spi-imx.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index
> 480d1e8b281f..1837cc7b0b96 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -2152,7 +2152,8 @@ static int spi_imx_transfer_one(struct spi_controller
> *controller,
> if (spi_imx->usedma) {
> ret = spi_imx_dma_transfer(spi_imx, transfer);
> if (transfer->error & SPI_TRANS_FAIL_NO_START) {
> - spi_imx->usedma = false;
> + controller->fallback = true;
> + spi_imx_setupxfer(spi, transfer);
> if (spi_imx->target_mode)
> return spi_imx_pio_transfer_target(spi,
> transfer);
> else
> --
> 2.47.3
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be started
2026-06-24 15:19 [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be started Javier Fernandez Pastrana
2026-06-24 15:27 ` Carlos Song
@ 2026-06-24 15:31 ` sashiko-bot
2026-06-24 16:30 ` Frank Li
2 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-06-24 15:31 UTC (permalink / raw)
To: Javier Fernandez Pastrana; +Cc: Frank.Li, imx
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
Pre-existing issues:
- [High] Missing SPI_TRANS_FAIL_NO_START flag when TX DMA preparation or submission fails, preventing PIO fallback.
- [High] Mid-transfer DMA failure incorrectly triggers a full PIO fallback, causing duplicate data transmission and corrupting the SPI stream.
- [High] Failure to clear `SPI_TRANS_FAIL_NO_START` after an internal PIO fallback leaks stale error state, causing subsequent transfers to silently duplicate data.
--
commit 5c8ab49e90372d3c0d5a4aca24ae8e97fcecafbc
Author: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
spi: imx: reconfigure for PIO when DMA cannot be started
When ECSPI DMA descriptor preparation fails, the driver falls back to PIO
internally without un-doing the DMA-mode controller configuration, leading
to corrupted data. This commit forces the controller to reconfigure for
PIO by setting the fallback flag and re-running the setup transfer
routine.
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
> index ae9912905c67a..79a6c1a60b0a0 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -2152,7 +2152,8 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
> if (spi_imx->usedma) {
> ret = spi_imx_dma_transfer(spi_imx, transfer);
> if (transfer->error & SPI_TRANS_FAIL_NO_START) {
[Severity: High]
This isn't a bug introduced by this patch, but if a transfer succeeds
internally via the PIO fallback here, doesn't transfer->error still retain
the SPI_TRANS_FAIL_NO_START flag?
If an SPI client reuses the spi_transfer object, and the next transfer
finishes successfully via DMA, this condition checks only the error flag
without verifying if the DMA transfer actually failed (ret < 0).
Would this cause the successful DMA transfer to incorrectly evaluate this
condition as true and redundantly re-transmit the data via PIO?
> - spi_imx->usedma = false;
> + controller->fallback = true;
> + spi_imx_setupxfer(spi, transfer);
> if (spi_imx->target_mode)
> return spi_imx_pio_transfer_target(spi, transfer);
> else
> return spi_imx_pio_transfer(spi, transfer);
> }
[Severity: High]
This is also a pre-existing issue, but does this fallback logic account for
partially completed DMA transmissions?
If a large transfer is split into multiple DMA packages in
spi_imx_dma_transfer() and a subsequent package fails,
spi_imx_dma_package_transfer() unconditionally sets SPI_TRANS_FAIL_NO_START:
spi_imx_dma_package_transfer() {
...
dma_failure_no_start:
transfer->error |= SPI_TRANS_FAIL_NO_START;
return ret;
}
Since earlier packages were already physically transmitted over the SPI bus,
would triggering a full PIO fallback here restart the transfer from the
beginning and corrupt the SPI stream by transmitting duplicate data?
[Severity: High]
Another pre-existing issue related to the DMA fallback: what happens if TX
DMA descriptor preparation or submission fails in spi_imx_dma_submit()?
drivers/spi/spi-imx.c:spi_imx_dma_submit() {
...
desc_tx = dmaengine_prep_slave_single(controller->dma_tx, ...);
if (!desc_tx)
goto dmaengine_terminate_rx;
...
cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) {
...
goto dmaengine_terminate_tx;
}
...
}
It appears these error paths return without setting the
SPI_TRANS_FAIL_NO_START flag. Does this prevent the PIO fallback from
triggering for TX DMA failures, causing the transfer to drop instead?
> return ret;
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260624151958.18626-1-javier.pastrana@linutronix.de?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be started
2026-06-24 15:19 [PATCH v2] spi: imx: reconfigure for PIO when DMA cannot be started Javier Fernandez Pastrana
2026-06-24 15:27 ` Carlos Song
2026-06-24 15:31 ` sashiko-bot
@ 2026-06-24 16:30 ` Frank Li
2 siblings, 0 replies; 4+ messages in thread
From: Frank Li @ 2026-06-24 16:30 UTC (permalink / raw)
To: Javier Fernandez Pastrana
Cc: Mark Brown, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Carlos Song, linux-spi, imx, linux-arm-kernel,
linux-kernel, stable
On Wed, Jun 24, 2026 at 05:19:58PM +0200, Javier Fernandez Pastrana wrote:
>
> When spi_imx_can_dma() selects DMA, the ECSPI is configured for DMA:
> spi_imx_setupxfer() sets CTRL.SMC and clears dynamic_burst, and
> spi_imx_dma_transfer() programs the dynamic-burst BURST_LENGTH and the
> SDMA watermarks.
>
> If the DMA descriptor cannot be prepared (dmaengine_prep_slave_single()
> returns NULL), the transfer is failed with SPI_TRANS_FAIL_NO_START and
> falls back to PIO. The dynamic-burst DMA path uses its own bounce
> buffers instead of the SPI core's mapping, so xfer->{tx,rx}_sg_mapped
> are not set and the core's DMA->PIO retry is skipped; the driver falls
> back to PIO internally. But none of the DMA-mode configuration is
> undone, so the PIO transfer runs with CTRL.SMC set, the wrong burst
> length and dynamic_burst cleared, and the transferred data is corrupted.
>
> This is easily hit on i.MX8MP boards that describe ECSPI DMA in the
> device tree but run SDMA on ROM firmware (no external sdma-imx7d.bin):
> every ECSPI DMA prepare fails. An Infineon SLB9670 TPM on ECSPI1 then
> returns shifted TPM2_GetCapability data, is flagged "field failure
> mode", /dev/tpmrm0 is never created.
>
> Set controller->fallback before re-running spi_imx_setupxfer() so the
> ECSPI is reconfigured exactly like a normal PIO transfer. With
> controller->fallback set, spi_imx_setupxfer() sees spi_imx_can_dma()
> return false, so it clears spi_imx->usedma and reprograms the controller
> (clears CTRL.SMC, restores dynamic_burst and the PIO burst length). No
> explicit spi_imx->usedma = false is needed: setupxfer() already updates
> it from the can_dma() result.
>
> Fixes: faa8e404ad8e ("spi: imx: support dynamic burst length for ECSPI DMA mode")
> Cc: stable@vger.kernel.org
> Signed-off-by: Javier Fernandez Pastrana <javier.pastrana@linutronix.de>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> v2: drop redundant spi_imx->usedma = false; spi_imx_setupxfer() already
> clears it via spi_imx_can_dma() (Carlos Song)
>
> drivers/spi/spi-imx.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
> index 480d1e8b281f..1837cc7b0b96 100644
> --- a/drivers/spi/spi-imx.c
> +++ b/drivers/spi/spi-imx.c
> @@ -2152,7 +2152,8 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
> if (spi_imx->usedma) {
> ret = spi_imx_dma_transfer(spi_imx, transfer);
> if (transfer->error & SPI_TRANS_FAIL_NO_START) {
> - spi_imx->usedma = false;
> + controller->fallback = true;
> + spi_imx_setupxfer(spi, transfer);
> if (spi_imx->target_mode)
> return spi_imx_pio_transfer_target(spi, transfer);
> else
> --
> 2.47.3
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread