From dbdbbd960618dc8af63ec2ec9dc07deae161b30c Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 9 Aug 2022 13:45:02 +0300 Subject: [PATCH 1/6] ipc: stream: Add new IPC stream structure Added a new IPC stream structure that will be used by the FW in order to notify the host that the drain operation is done. For the moment, the structure contains only the reply header since that's the only information we care about but, by adding a new IPC stream structure, we can send more information from FW regarding the drain operation if need be. Signed-off-by: Laurentiu Mihalcea --- src/include/ipc/stream.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/include/ipc/stream.h b/src/include/ipc/stream.h index 2d76fdc18693..fac6c209e45e 100644 --- a/src/include/ipc/stream.h +++ b/src/include/ipc/stream.h @@ -158,4 +158,9 @@ struct sof_ipc_stream_posn { int32_t xrun_size; /**< XRUN size in bytes */ } __attribute__((packed, aligned(4))); +/* drain information */ +struct sof_ipc_stream_drain { + struct sof_ipc_reply rhdr; +} __attribute__((packed, aligned(4))); + #endif /* __IPC_STREAM_H__ */ From f4beac926c6661e5aeb8a6f0cefabe2eb7ee3252 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 9 Aug 2022 14:00:13 +0300 Subject: [PATCH 2/6] ipc3: handler: common: Add drain notification support Added a new function used to notify the host that the drain operation has finished. Signed-off-by: Laurentiu Mihalcea --- src/include/sof/ipc/common.h | 5 ++++ src/ipc/ipc3/handler.c | 45 ++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/include/sof/ipc/common.h b/src/include/sof/ipc/common.h index d357c6f79360..d6d21bbedea4 100644 --- a/src/include/sof/ipc/common.h +++ b/src/include/sof/ipc/common.h @@ -197,4 +197,9 @@ void ipc_msg_reply(struct sof_ipc_reply *reply); */ void ipc_complete_cmd(struct ipc *ipc); +/** + * \brief Notify host that the drain operation is done. + */ +int ipc_stream_drain_notify(void); + #endif /* __SOF_DRIVERS_IPC_H__ */ diff --git a/src/ipc/ipc3/handler.c b/src/ipc/ipc3/handler.c index 981eac2561e5..da03ea3f9807 100644 --- a/src/ipc/ipc3/handler.c +++ b/src/ipc/ipc3/handler.c @@ -422,6 +422,51 @@ static int ipc_stream_position(uint32_t header) return 1; } +int ipc_stream_drain_notify(void) +{ + struct ipc *ipc = ipc_get(); + struct sof_ipc_stream stream; + struct sof_ipc_stream_drain drain; + struct ipc_comp_dev *pcm_dev; + + /* copy message with ABI safe method */ + IPC_COPY_CMD(stream, ipc->comp_data); + + /* get the pcm dev */ + pcm_dev = ipc_get_comp_by_id(ipc, stream.comp_id); + if (!pcm_dev) { + tr_err(&ipc_tr, "ipc: comp %d not found", stream.comp_id); + return -ENODEV; + } + + /* check core */ + if (!cpu_is_me(pcm_dev->core)) + return ipc_process_on_core(pcm_dev->core, false); + + /* prepare message */ + memset(&drain, 0, sizeof(drain)); + drain.rhdr.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_TRIG_DRAIN | + stream.comp_id; + drain.rhdr.hdr.size = sizeof(drain); + + if (!pcm_dev->cd->pipeline) { + tr_err(&ipc_tr, "ipc: comp %d pipeline not found", + stream.comp_id); + return -EINVAL; + } + + /* write message */ + mailbox_stream_write(pcm_dev->cd->pipeline->posn_offset, &drain, + sizeof(drain)); + + /* send IPC notification */ + struct ipc_msg *msg = ipc_msg_init(drain.rhdr.hdr.cmd, drain.rhdr.hdr.size); + + ipc_msg_send(msg, &drain, false); + + return 0; +} + static int ipc_stream_trigger(uint32_t header) { struct ipc *ipc = ipc_get(); From 31e7efb37feb3e15d2b65b45598dc9c6ac1defde Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 9 Aug 2022 14:03:44 +0300 Subject: [PATCH 3/6] audio: component: Add drain-related macros Added a few macros to prepare for drain operation support. Signed-off-by: Laurentiu Mihalcea --- src/include/sof/audio/component.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 0c68af51ca55..33ff9a4868af 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -65,6 +65,7 @@ struct timestamp_data; #define COMP_STATE_PAUSED 4 /**< Component paused */ #define COMP_STATE_ACTIVE 5 /**< Component active */ #define COMP_STATE_PRE_ACTIVE 6 /**< Component after early initialisation */ +#define COMP_STATE_DRAINING 7 /**< Component draining */ /** @}*/ /** \name Standard Component Stream Commands @@ -91,6 +92,7 @@ enum { COMP_TRIGGER_POST_STOP, /**< Finalize stop component stream */ COMP_TRIGGER_POST_PAUSE, /**< Finalize pause component stream */ COMP_TRIGGER_NO_ACTION, /**< No action required */ + COMP_TRIGGER_DRAIN, /**< Start drain operation */ }; /** @}*/ From bbd418e0dff3fe90f3b8e809212afdb1d98bdbec Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 9 Aug 2022 14:06:12 +0300 Subject: [PATCH 4/6] ipc3: handler: Add case for TRIG_DRAIN Since we want to support the drain operation we need to add a new case to the ipc_stream_trigger function that will handle the TRIG_DRAIN IPC message received from the host when the drain operation is to be started. Signed-off-by: Laurentiu Mihalcea --- src/ipc/ipc3/handler.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ipc/ipc3/handler.c b/src/ipc/ipc3/handler.c index da03ea3f9807..9c0ee5eee2dd 100644 --- a/src/ipc/ipc3/handler.c +++ b/src/ipc/ipc3/handler.c @@ -506,6 +506,9 @@ static int ipc_stream_trigger(uint32_t header) case SOF_IPC_STREAM_TRIG_RELEASE: cmd = COMP_TRIGGER_PRE_RELEASE; break; + case SOF_IPC_STREAM_TRIG_DRAIN: + cmd = COMP_TRIGGER_DRAIN; + break; /* XRUN is special case- TODO */ case SOF_IPC_STREAM_TRIG_XRUN: return 0; From ac46855ed59108429b7e0b1c71d2d173e72fbb01 Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 9 Aug 2022 14:11:50 +0300 Subject: [PATCH 5/6] audio: pipeline: pipeline-stream: Add support for TRIG_DRAIN We want to handle the TRIG_DRAIN IPC message from host. We're not really interested in changing the state of the components to COMP_STATE_DRAINING because, during draining, they behave as if they were in COMP_STATE_ACTIVE. Also, we're not really going to use the state of the components to figure out when to notify the host that the draining is over. Signed-off-by: Laurentiu Mihalcea --- src/audio/pipeline/pipeline-stream.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index c649cda4691d..e1609fe7f0ad 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -328,6 +328,7 @@ static int pipeline_comp_trigger(struct comp_dev *current, case COMP_TRIGGER_STOP: case COMP_TRIGGER_RELEASE: case COMP_TRIGGER_START: + case COMP_TRIGGER_DRAIN: break; } @@ -349,14 +350,21 @@ static int pipeline_comp_trigger(struct comp_dev *current, current->pipeline->trigger.pending = false; - /* send command to the component and update pipeline state */ - err = comp_trigger(current, ppl_data->cmd); - if (err < 0) - return err; + /* send command to the component and update pipeline state. + * + * if we're dealing with DRAIN trigger we don't want to update + * the state of the components since we're not using that + * information + */ + if (ppl_data->cmd != COMP_TRIGGER_DRAIN) { + err = comp_trigger(current, ppl_data->cmd); + if (err < 0) + return err; - if (err == PPL_STATUS_PATH_STOP) { - current->pipeline->trigger.aborted = true; - return err; + if (err == PPL_STATUS_PATH_STOP) { + current->pipeline->trigger.aborted = true; + return err; + } } switch (ppl_data->cmd) { From 379179534339e7a16860c44f17cff278073fa4ae Mon Sep 17 00:00:00 2001 From: Laurentiu Mihalcea Date: Tue, 9 Aug 2022 14:22:44 +0300 Subject: [PATCH 6/6] audio: pipeline: pipeline-schedule: Add draining support In order to handle the DRAIN operation, we first need to set the state of each of the pipelines to COMP_STATE_DRAINING. Having entered the COMP_STATE_DRAINING, if the pipeline_copy operation return value is <= 0 we can conclude that the draining is done and we can send a notification to the host (also we should set the state of the pipeline back to COMP_STATE_ACTIVE) Signed-off-by: Laurentiu Mihalcea --- src/audio/pipeline/pipeline-schedule.c | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index 2dc3ee5924a8..e7dd7f227c02 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -201,6 +202,25 @@ static enum task_state pipeline_task(void *arg) * copying below. */ err = pipeline_copy(p); + if (p->status == COMP_STATE_DRAINING) { + /* check the return value of the copy operation. + * + * if it's <= 0 then the draining opearation is over + * and we need to send a notification to the host + */ + if (err <= 0) { + /* set pipeline status back to ACTIVE */ + p->status = COMP_STATE_ACTIVE; + + /* notify host that draining is over */ + err = ipc_stream_drain_notify(); + + if (err < 0) { + pipe_err(p, "pipeline_task(): failed drain notify"); + return SOF_TASK_STATE_COMPLETED; + } + } + } if (err < 0) { /* try to recover */ err = pipeline_xrun_recover(p); @@ -320,6 +340,13 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, */ p->xrun_bytes = 1; } + break; + case COMP_TRIGGER_DRAIN: + list_for_item(tlist, &ctx->pipelines) { + p = container_of(tlist, struct pipeline, list); + p->xrun_bytes = 0; + p->status = COMP_STATE_DRAINING; + } } irq_local_enable(flags);