ipc4: Fix chain DMA trigger handling

We need to deliver the PPL_STATUS_SCHEDULED from pipeline_trigger() to
calling ipc4_process_chain_dma() function. Added "bool *delay" parameter
to ipc4_trigger_chain_dma() for that, since there is no clean way to use
IPC4 status values for that purpose.

The most complex is the case where an active stream is shut down with a
single message (both active and allocate bits zero). In this situation the
stream has to be paused and reset in another thread, but the freeing
the pipeline has to be done in messaging thread, since chained DMA
pipelines are not cleaned up automatically.

Signed-off-by: Jyri Sarha <jyri.sarha@intel.com>
This commit is contained in:
Jyri Sarha 2022-11-22 21:07:20 +02:00 committed by Kai Vehmanen
parent 880857b3f7
commit 35f2e5f84f
3 changed files with 28 additions and 7 deletions

View File

@ -51,7 +51,7 @@ struct comp_dev *ipc4_get_comp_dev(uint32_t comp_id);
int ipc4_add_comp_dev(struct comp_dev *dev);
const struct comp_driver *ipc4_get_drv(uint8_t *uuid);
int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma);
int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma);
int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *delay);
#else
#error "No or invalid IPC MAJOR version selected."
#endif

View File

@ -454,6 +454,7 @@ static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4)
{
struct ipc4_chain_dma cdma;
struct ipc *ipc = ipc_get();
bool delay = false;
int ret;
memcpy_s(&cdma, sizeof(cdma), ipc4, sizeof(cdma));
@ -471,13 +472,25 @@ static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4)
}
atomic_set(&msg_data.delayed_reply, 1);
ret = ipc4_trigger_chain_dma(ipc, &cdma);
ret = ipc4_trigger_chain_dma(ipc, &cdma, &delay);
/* it is not scheduled in another thread */
if (ret != PPL_STATUS_SCHEDULED) {
if (!delay) {
atomic_set(&msg_data.delayed_reply, 0);
msg_data.delayed_error = 0;
} else {
ret = 0;
} else if (!cdma.primary.r.allocate) {
uint32_t pipeline_id = IPC4_COMP_ID(cdma.primary.r.host_dma_id
+ IPC4_MAX_MODULE_COUNT,
cdma.primary.r.link_dma_id);
/* waiting for pipeline reset done */
ipc_wait_for_compound_msg();
ret = ipc_pipeline_free(ipc, pipeline_id);
if (ret < 0) {
tr_err(&ipc_tr, "failed to free chain dma %d", ret);
ret = IPC4_BAD_STATE;
} else {
ret = IPC4_SUCCESS;
}
}
return ret;

View File

@ -722,12 +722,13 @@ int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma)
return ret;
}
int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma)
int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma,
bool *delay)
{
struct ipc_comp_dev *ipc_pipe;
struct comp_dev *host;
uint32_t pipeline_id;
int ret;
int ret = 0;
pipeline_id = IPC4_COMP_ID(cdma->primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT,
cdma->primary.r.link_dma_id);
@ -746,6 +747,10 @@ int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma)
if (ret < 0) {
tr_err(&ipc_tr, "failed to disable chain dma %d", ret);
return IPC4_BAD_STATE;
} else if (ret == PPL_STATUS_SCHEDULED) {
/* pipeline reset will be done by schedule thread */
*delay = true;
return IPC4_SUCCESS;
}
}
@ -789,6 +794,9 @@ int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma)
}
}
if (ret == PPL_STATUS_SCHEDULED)
*delay = true;
return IPC4_SUCCESS;
}