Skip to content
Merged
2 changes: 1 addition & 1 deletion src/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ config COMP_CHAIN_DMA

config XRUN_NOTIFICATIONS_ENABLE
bool "Enable xrun notification"
default n
default y
depends on IPC_MAJOR_4
help
Enable xrun notifications sending to host
Expand Down
75 changes: 27 additions & 48 deletions src/audio/chain_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
#include <zephyr/pm/policy.h>
#include <rtos/init.h>
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
#include <sof/ipc/notification_pool.h>
#include <ipc4/notification.h>
#include <sof/ipc/msg.h>
#include <ipc/header.h>
#endif

#define DT_NUM_HDA_HOST_IN DT_PROP(DT_INST(0, intel_adsp_hda_host_in), dma_channels)
Expand Down Expand Up @@ -59,7 +58,6 @@ struct chain_dma_data {
uint8_t cs;
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
bool xrun_notification_sent;
struct ipc_msg *msg_xrun;
#endif

/* local host DMA config */
Expand Down Expand Up @@ -145,33 +143,32 @@ static size_t chain_get_transferred_data_size(const uint32_t out_read_pos, const
return buff_size - in_read_pos + out_read_pos;
}

#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
static void handle_xrun(struct chain_dma_data *cd)
/* get status from dma and check for xrun */
static int chain_get_dma_status(struct chain_dma_data *cd, struct dma_chan_data *chan,
struct dma_status *stat)
{
int ret;

if (cd->link_connector_node_id.f.dma_type == ipc4_hda_link_output_class &&
!cd->xrun_notification_sent) {
tr_warn(&chain_dma_tr, "handle_xrun(): underrun detected");
xrun_notif_msg_init(cd->msg_xrun, cd->link_connector_node_id.dw,
SOF_IPC4_GATEWAY_UNDERRUN_DETECTED);
ipc_msg_send(cd->msg_xrun, NULL, true);
cd->xrun_notification_sent = true;
} else if (cd->link_connector_node_id.f.dma_type == ipc4_hda_link_input_class &&
!cd->xrun_notification_sent) {
tr_warn(&chain_dma_tr, "handle_xrun(): overrun detected");
xrun_notif_msg_init(cd->msg_xrun, cd->link_connector_node_id.dw,
SOF_IPC4_GATEWAY_OVERRUN_DETECTED);
ipc_msg_send(cd->msg_xrun, NULL, true);
cd->xrun_notification_sent = true;
} else {
/* if xrun_notification_sent is already set, then it means that link was
* able to reach stability therefore next underrun/overrun should be reported.
*/
int ret = dma_get_status(chan->dma->z_dev, chan->index, stat);
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
if (ret == -EPIPE && !cd->xrun_notification_sent) {
struct ipc_msg *notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE);

if (notify) {
if (cd->stream_direction == SOF_IPC_STREAM_PLAYBACK)
gateway_underrun_notif_msg_init(notify,
cd->link_connector_node_id.dw);
else
gateway_overrun_notif_msg_init(notify,
cd->link_connector_node_id.dw);

ipc_msg_send(notify, notify->tx_data, false);
cd->xrun_notification_sent = true;
}
} else if (!ret) {
cd->xrun_notification_sent = false;
}
}
#endif
return ret;
}

static enum task_state chain_task_run(void *data)
{
Expand All @@ -185,16 +182,13 @@ static enum task_state chain_task_run(void *data)
/* Link DMA can return -EPIPE and current status if xrun occurs, then it is not critical
* and flow shall continue. Other error values will be treated as critical.
*/
ret = dma_get_status(cd->chan_link->dma->z_dev, cd->chan_link->index, &stat);
ret = chain_get_dma_status(cd, cd->chan_link, &stat);
switch (ret) {
case 0:
break;
case -EPIPE:
tr_warn(&chain_dma_tr, "chain_task_run(): dma_get_status() link xrun occurred,"
" ret = %d", ret);
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
handle_xrun(cd);
#endif
break;
default:
tr_err(&chain_dma_tr, "chain_task_run(): dma_get_status() error, ret = %d", ret);
Expand All @@ -206,7 +200,7 @@ static enum task_state chain_task_run(void *data)
link_read_pos = stat.read_position;

/* Host DMA does not report xruns. All error values will be treated as critical. */
ret = dma_get_status(cd->chan_host->dma->z_dev, cd->chan_host->index, &stat);
ret = chain_get_dma_status(cd, cd->chan_host, &stat);
if (ret < 0) {
tr_err(&chain_dma_tr, "chain_task_run(): dma_get_status() error, ret = %d", ret);
return SOF_TASK_STATE_COMPLETED;
Expand Down Expand Up @@ -685,20 +679,9 @@ __cold static struct comp_dev *chain_task_create(const struct comp_driver *drv,
comp_set_drvdata(dev, cd);

ret = chain_task_init(dev, host_dma_id, link_dma_id, fifo_size);
if (ret)
goto error_cd;

#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
cd->msg_xrun = ipc_msg_init(header.dat,
sizeof(struct ipc4_resource_event_data_notification));
if (!cd->msg_xrun)
goto error_cd;
cd->xrun_notification_sent = false;
#endif

return dev;
if (!ret)
return dev;

error_cd:
rfree(cd);
error:
rfree(dev);
Expand All @@ -711,10 +694,6 @@ __cold static void chain_task_free(struct comp_dev *dev)

assert_can_be_cold();

#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
ipc_msg_free(cd->msg_xrun);
#endif

chain_release(dev);
rfree(cd);
rfree(dev);
Expand Down
3 changes: 3 additions & 0 deletions src/audio/copier/host_copier.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ struct host_data {
/* stream info */
struct sof_ipc_stream_posn posn; /* TODO: update this */
struct ipc_msg *msg; /**< host notification */
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
bool xrun_notification_sent;
#endif
uint32_t dma_buffer_size; /* dma buffer size */
#if CONFIG_HOST_DMA_STREAM_SYNCHRONIZATION
bool is_grouped;
Expand Down
35 changes: 33 additions & 2 deletions src/audio/dai-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
#include <stddef.h>
#include <stdint.h>

#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
#include <sof/ipc/notification_pool.h>
#include <ipc4/notification.h>
#endif

#include "copier/copier.h"
#include "copier/dai_copier.h"
#include "copier/copier_gain.h"
Expand Down Expand Up @@ -1462,6 +1467,32 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
return dai_common_trigger(dd, dev, cmd);
}

/* get status from dma and check for xrun */
static int dai_get_status(struct comp_dev *dev, struct dai_data *dd, struct dma_status *stat)
{
int ret = dma_get_status(dd->chan->dma->z_dev, dd->chan->index, stat);
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
if (ret == -EPIPE && !dd->xrun_notification_sent) {
struct ipc_msg *notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE);

if (notify) {
if (dev->direction == SOF_IPC_STREAM_PLAYBACK)
copier_gateway_underrun_notif_msg_init(notify,
dev->pipeline->pipeline_id);
else
copier_gateway_overrun_notif_msg_init(notify,
dev->pipeline->pipeline_id);

ipc_msg_send(notify, notify->tx_data, false);
dd->xrun_notification_sent = true;
}
} else if (!ret) {
dd->xrun_notification_sent = false;
}
#endif
return ret;
}

/* report xrun occurrence */
static void dai_report_xrun(struct dai_data *dd, struct comp_dev *dev, uint32_t bytes)
{
Expand Down Expand Up @@ -1499,7 +1530,7 @@ int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev,
struct dma_status stat;

/* get data sizes from DMA */
ret = dma_get_status(dd[i]->chan->dma->z_dev, dd[i]->chan->index, &stat);
ret = dai_get_status(dev, dd[i], &stat);
switch (ret) {
case 0:
break;
Expand Down Expand Up @@ -1633,7 +1664,7 @@ int dai_common_copy(struct dai_data *dd, struct comp_dev *dev, pcm_converter_fun
int ret;

/* get data sizes from DMA */
ret = dma_get_status(dd->chan->dma->z_dev, dd->chan->index, &stat);
ret = dai_get_status(dev, dd, &stat);
switch (ret) {
case 0:
break;
Expand Down
33 changes: 32 additions & 1 deletion src/audio/host-zephyr.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
#include <stddef.h>
#include <stdint.h>

#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
#include <sof/ipc/notification_pool.h>
#include <ipc4/notification.h>
#endif

#include "copier/copier.h"
#include "copier/host_copier.h"

Expand Down Expand Up @@ -359,6 +364,32 @@ static void host_dma_cb(struct comp_dev *dev, size_t bytes)
host_common_one_shot(hd, bytes);
}

/* get status from dma and check for xrun */
static int host_get_status(struct comp_dev *dev, struct host_data *hd, struct dma_status *stat)
{
int ret = dma_get_status(hd->chan->dma->z_dev, hd->chan->index, stat);
#if CONFIG_XRUN_NOTIFICATIONS_ENABLE
if (ret == -EPIPE && !hd->xrun_notification_sent) {
struct ipc_msg *notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE);

if (notify) {
if (dev->direction == SOF_IPC_STREAM_PLAYBACK)
copier_gateway_underrun_notif_msg_init(notify,
dev->pipeline->pipeline_id);
else
copier_gateway_overrun_notif_msg_init(notify,
dev->pipeline->pipeline_id);

ipc_msg_send(notify, notify->tx_data, false);
hd->xrun_notification_sent = true;
}
} else if (!ret) {
hd->xrun_notification_sent = false;
}
#endif
return ret;
}

/* Minimum time between 2 consecutive "no bytes to copy" messages in milliseconds */
#define SOF_MIN_NO_BYTES_INTERVAL_MS 20

Expand All @@ -378,7 +409,7 @@ static uint32_t host_get_copy_bytes_normal(struct host_data *hd, struct comp_dev
int ret;

/* get data sizes from DMA */
ret = dma_get_status(hd->chan->dma->z_dev, hd->chan->index, &dma_stat);
ret = host_get_status(dev, hd, &dma_stat);
if (ret < 0) {
comp_err(dev, "dma_get_status() failed, ret = %u",
ret);
Expand Down
Loading
Loading