diff mbox series

[v4,04/24] ASoC: renesas: rz-ssi: Terminate all the DMA transactions

Message ID 20241210170953.2936724-5-claudiu.beznea.uj@bp.renesas.com (mailing list archive)
State New
Delegated to: Kieran Bingham
Headers show
Series Add audio support for the Renesas RZ/G3S SoC | expand

Commit Message

Claudiu Beznea Dec. 10, 2024, 5:09 p.m. UTC
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The stop trigger invokes rz_ssi_stop() and rz_ssi_stream_quit().
- The purpose of rz_ssi_stop() is to disable TX/RX, terminate DMA
  transactions, and set the controller to idle.
- The purpose of rz_ssi_stream_quit() is to reset the substream-specific
  software data by setting strm->running and strm->substream appropriately.

The function rz_ssi_is_stream_running() checks if both strm->substream and
strm->running are valid and returns true if so. Its implementation is as
follows:

static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm)
{
    return strm->substream && strm->running;
}

When the controller is configured in full-duplex mode (with both playback
and capture active), the rz_ssi_stop() function does not modify the
controller settings when called for the first substream in the full-duplex
setup. Instead, it simply sets strm->running = 0 and returns if the
companion substream is still running. The following code illustrates this:

static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
{
    strm->running = 0;

    if (rz_ssi_is_stream_running(&ssi->playback) ||
        rz_ssi_is_stream_running(&ssi->capture))
        return 0;

    // ...
}

The controller settings, along with the DMA termination (for the last
stopped substream), are only applied when the last substream in the
full-duplex setup is stopped.

While applying the controller settings only when the last substream stops
is not problematic, terminating the DMA operations for only one substream
causes failures when starting and stopping full-duplex operations multiple
times in a loop.

To address this issue, call dmaengine_terminate_async() for both substreams
involved in the full-duplex setup when the last substream in the setup is
stopped.

Fixes: 4f8cd05a4305 ("ASoC: sh: rz-ssi: Add full duplex support")
Cc: stable@vger.kernel.org
Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v4:
- updated patch description

Changes in v3:
- collected tags
- use proper fixes commit SHA1 and description
- s/sh/renesas in patch title

Changes in v2:
- none

 sound/soc/renesas/rz-ssi.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

Comments

Geert Uytterhoeven Dec. 11, 2024, 12:35 p.m. UTC | #1
On Tue, Dec 10, 2024 at 6:10 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> The stop trigger invokes rz_ssi_stop() and rz_ssi_stream_quit().
> - The purpose of rz_ssi_stop() is to disable TX/RX, terminate DMA
>   transactions, and set the controller to idle.
> - The purpose of rz_ssi_stream_quit() is to reset the substream-specific
>   software data by setting strm->running and strm->substream appropriately.
>
> The function rz_ssi_is_stream_running() checks if both strm->substream and
> strm->running are valid and returns true if so. Its implementation is as
> follows:
>
> static inline bool rz_ssi_is_stream_running(struct rz_ssi_stream *strm)
> {
>     return strm->substream && strm->running;
> }
>
> When the controller is configured in full-duplex mode (with both playback
> and capture active), the rz_ssi_stop() function does not modify the
> controller settings when called for the first substream in the full-duplex
> setup. Instead, it simply sets strm->running = 0 and returns if the
> companion substream is still running. The following code illustrates this:
>
> static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
> {
>     strm->running = 0;
>
>     if (rz_ssi_is_stream_running(&ssi->playback) ||
>         rz_ssi_is_stream_running(&ssi->capture))
>         return 0;
>
>     // ...
> }
>
> The controller settings, along with the DMA termination (for the last
> stopped substream), are only applied when the last substream in the
> full-duplex setup is stopped.
>
> While applying the controller settings only when the last substream stops
> is not problematic, terminating the DMA operations for only one substream
> causes failures when starting and stopping full-duplex operations multiple
> times in a loop.
>
> To address this issue, call dmaengine_terminate_async() for both substreams
> involved in the full-duplex setup when the last substream in the setup is
> stopped.
>
> Fixes: 4f8cd05a4305 ("ASoC: sh: rz-ssi: Add full duplex support")
> Cc: stable@vger.kernel.org
> Reviewed-by: Biju Das <biju.das.jz@bp.renesas.com>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v4:
> - updated patch description

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert
diff mbox series

Patch

diff --git a/sound/soc/renesas/rz-ssi.c b/sound/soc/renesas/rz-ssi.c
index 6efd017aaa7f..2d8721156099 100644
--- a/sound/soc/renesas/rz-ssi.c
+++ b/sound/soc/renesas/rz-ssi.c
@@ -415,8 +415,12 @@  static int rz_ssi_stop(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
 	rz_ssi_reg_mask_setl(ssi, SSICR, SSICR_TEN | SSICR_REN, 0);
 
 	/* Cancel all remaining DMA transactions */
-	if (rz_ssi_is_dma_enabled(ssi))
-		dmaengine_terminate_async(strm->dma_ch);
+	if (rz_ssi_is_dma_enabled(ssi)) {
+		if (ssi->playback.dma_ch)
+			dmaengine_terminate_async(ssi->playback.dma_ch);
+		if (ssi->capture.dma_ch)
+			dmaengine_terminate_async(ssi->capture.dma_ch);
+	}
 
 	rz_ssi_set_idle(ssi);