From e6489e945411f51d92001528657b6a3f4bcc2c5e Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Mon, 19 Dec 2022 18:51:28 +0100 Subject: [PATCH] audio: dai-zephyr/host-zephyr: stop dma only once Until now, one dma channel could be stopped multiple times without any problems. From commit af6d827b64 on zephyr it is required that the start and stop calls be perfectly balanced. Zephyr device power manager stores an internal counter. Counter is incremented if device is used and decremented on device release. In this case when we call dma_start() and dma_stop(). If dma_stop() is called more times than dma_start() power manager will reaport a error -EALREADY. Signed-off-by: Tomasz Leman --- src/audio/dai-zephyr.c | 23 ++++++++++++++++++----- src/audio/host-zephyr.c | 14 +++++++++----- src/ipc/ipc4/dai.c | 4 +++- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 3d097c4a42a5..0a8d618a4e9e 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -1014,9 +1014,11 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) /* only start the DAI if we are not XRUN handling */ if (dd->xrun == 0) { /* recover valid start position */ - ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); - if (ret < 0) - return ret; + if (dev->state == COMP_STATE_ACTIVE) { + ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); + if (ret < 0) + return ret; + } /* dma_config needed after stop */ ret = dma_config(dd->chan->dma->z_dev, dd->chan->index, dd->z_config); @@ -1054,12 +1056,23 @@ static int dai_comp_trigger_internal(struct comp_dev *dev, int cmd) dai_trigger_op(dd->dai, cmd, dev->direction); #else dai_trigger_op(dd->dai, cmd, dev->direction); - ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); + if (dev->state == COMP_STATE_ACTIVE) { + ret = dma_stop(dd->chan->dma->z_dev, dd->chan->index); + } else { + comp_warn(dev, "dma was stopped earlier"); + ret = 0; + } #endif break; case COMP_TRIGGER_PAUSE: comp_dbg(dev, "dai_comp_trigger_internal(), PAUSE"); - ret = dma_suspend(dd->chan->dma->z_dev, dd->chan->index); + if (dev->state == COMP_STATE_ACTIVE) { + ret = dma_suspend(dd->chan->dma->z_dev, dd->chan->index); + } else { + comp_warn(dev, "dma was stopped earlier"); + ret = 0; + } + dai_trigger_op(dd->dai, cmd, dev->direction); break; case COMP_TRIGGER_PRE_START: diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 54f73e45cb1f..c01cb18bd39d 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -627,10 +627,13 @@ static int host_trigger(struct comp_dev *dev, int cmd) break; case COMP_TRIGGER_STOP: case COMP_TRIGGER_XRUN: - ret = dma_stop(hd->chan->dma->z_dev, hd->chan->index); - if (ret < 0) - comp_err(dev, "host_trigger(): dma stop failed: %d", - ret); + if (dev->state == COMP_STATE_ACTIVE) { + ret = dma_stop(hd->chan->dma->z_dev, hd->chan->index); + if (ret < 0) + comp_err(dev, "host_trigger(): dma stop failed: %d", + ret); + } + break; default: break; @@ -1048,7 +1051,8 @@ static int host_reset(struct comp_dev *dev) comp_dbg(dev, "host_reset()"); if (hd->chan) { - dma_stop(hd->chan->dma->z_dev, hd->chan->index); + if (dev->state == COMP_STATE_ACTIVE) + dma_stop(hd->chan->dma->z_dev, hd->chan->index); /* remove callback */ notifier_unregister(dev, hd->chan, NOTIFIER_ID_DMA_COPY); diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 5be3ff8dc140..1f9ff09c8558 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -172,7 +172,9 @@ void dai_dma_release(struct comp_dev *dev) * TODO: refine power management when stream is paused */ #if CONFIG_ZEPHYR_NATIVE_DRIVERS - dma_stop(dd->chan->dma->z_dev, dd->chan->index); + /* if reset is after pause dma has already been stopped */ + if (dev->state != COMP_STATE_PAUSED) + dma_stop(dd->chan->dma->z_dev, dd->chan->index); /* remove callback */ notifier_unregister(dev, dd->chan, NOTIFIER_ID_DMA_COPY);