2424#include <sof/ut.h>
2525#include <zephyr/pm/policy.h>
2626#include <rtos/init.h>
27+ #if CONFIG_IPC4_XRUN_NOTIFICATIONS_ENABLE
28+ #include <ipc4/notification.h>
29+ #include <sof/ipc/msg.h>
30+ #include <ipc/header.h>
31+ #endif
2732
2833static const struct comp_driver comp_chain_dma ;
2934static const uint32_t max_chain_number = DAI_NUM_HDA_OUT + DAI_NUM_HDA_IN ;
@@ -47,6 +52,10 @@ struct chain_dma_data {
4752 enum sof_ipc_stream_direction stream_direction ;
4853 /* container size in bytes */
4954 uint8_t cs ;
55+ #if CONFIG_IPC4_XRUN_NOTIFICATIONS_ENABLE
56+ bool xrun_notification_sent ;
57+ struct ipc_msg * msg_xrun ;
58+ #endif
5059
5160 /* local host DMA config */
5261 struct dma * dma_host ;
@@ -131,6 +140,34 @@ static size_t chain_get_transferred_data_size(const uint32_t out_read_pos, const
131140 return buff_size - in_read_pos + out_read_pos ;
132141}
133142
143+ #if CONFIG_IPC4_XRUN_NOTIFICATIONS_ENABLE
144+ static void handle_xrun (struct chain_dma_data * cd )
145+ {
146+ int ret ;
147+
148+ if (cd -> link_connector_node_id .f .dma_type == ipc4_hda_link_output_class &&
149+ !cd -> xrun_notification_sent ) {
150+ tr_warn (& chain_dma_tr , "handle_xrun(): underrun detected" );
151+ xrun_notif_msg_init (cd -> msg_xrun , cd -> link_connector_node_id .dw ,
152+ SOF_IPC4_GATEWAY_UNDERRUN_DETECTED );
153+ ipc_msg_send (cd -> msg_xrun , NULL , true);
154+ cd -> xrun_notification_sent = true;
155+ } else if (cd -> link_connector_node_id .f .dma_type == ipc4_hda_link_input_class &&
156+ !cd -> xrun_notification_sent ) {
157+ tr_warn (& chain_dma_tr , "handle_xrun(): overrun detected" );
158+ xrun_notif_msg_init (cd -> msg_xrun , cd -> link_connector_node_id .dw ,
159+ SOF_IPC4_GATEWAY_OVERRUN_DETECTED );
160+ ipc_msg_send (cd -> msg_xrun , NULL , true);
161+ cd -> xrun_notification_sent = true;
162+ } else {
163+ /* if xrun_notification_sent is already set, then it means that link was
164+ * able to reach stability therefore next underrun/overrun should be reported.
165+ */
166+ cd -> xrun_notification_sent = false;
167+ }
168+ }
169+ #endif
170+
134171static enum task_state chain_task_run (void * data )
135172{
136173 size_t link_avail_bytes , link_free_bytes , host_avail_bytes , host_free_bytes ;
@@ -150,6 +187,9 @@ static enum task_state chain_task_run(void *data)
150187 case - EPIPE :
151188 tr_warn (& chain_dma_tr , "chain_task_run(): dma_get_status() link xrun occurred,"
152189 " ret = %u" , ret );
190+ #if CONFIG_IPC4_XRUN_NOTIFICATIONS_ENABLE
191+ handle_xrun (cd );
192+ #endif
153193 break ;
154194 default :
155195 tr_err (& chain_dma_tr , "chain_task_run(): dma_get_status() error, ret = %u" , ret );
@@ -622,6 +662,14 @@ static struct comp_dev *chain_task_create(const struct comp_driver *drv,
622662 if (ret )
623663 goto error_cd ;
624664
665+ #if CONFIG_IPC4_XRUN_NOTIFICATIONS_ENABLE
666+ cd -> msg_xrun = ipc_msg_init (header .dat ,
667+ sizeof (struct ipc4_resource_event_data_notification ));
668+ if (!cd -> msg_xrun )
669+ goto error_cd ;
670+ cd -> xrun_notification_sent = false;
671+ #endif
672+
625673 return dev ;
626674
627675error_cd :
0 commit comments