From c93a007a9a2bb5fabc7c641b43f092aff04c2542 Mon Sep 17 00:00:00 2001 From: Wojciech Jablonski Date: Fri, 13 Feb 2026 11:19:26 +0100 Subject: [PATCH 1/2] ipc4: notification: Internal IPC allocation Moving memory allocation for IPC4 notifications to the notification module. With this change all the logic needed for sending IPC4 notifications is contained within the notification module. Currently all the notifications are allocated out of the same memory pool, so the selection of a memory pool is not part of the function interface of the notification module, but we can easily modify that behavior by adding a pool ID parameter. This change enables robust implementation of the notification filtering feature without exposing additional symbols to LLEXT modules. Signed-off-by: Wojciech Jablonski --- src/audio/chain_dma.c | 16 +--- src/audio/dai-zephyr.c | 16 +--- src/audio/host-zephyr.c | 16 +--- src/audio/mixin_mixout/mixin_mixout.c | 10 +-- src/audio/pipeline/pipeline-stream.c | 10 +-- src/include/ipc4/notification.h | 13 ++-- src/ipc/ipc4/notification.c | 105 +++++++++++++------------- src/ipc/notification_pool.c | 1 - 8 files changed, 66 insertions(+), 121 deletions(-) diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index 3882c38f700e..5bf13fe733a9 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -26,7 +26,6 @@ #include #include #if CONFIG_XRUN_NOTIFICATIONS_ENABLE -#include #include #endif @@ -150,19 +149,8 @@ static int chain_get_dma_status(struct chain_dma_data *cd, struct dma_chan_data 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; - } + cd->xrun_notification_sent = send_gateway_xrun_notif_msg + (cd->link_connector_node_id.dw, cd->stream_direction); } else if (!ret) { cd->xrun_notification_sent = false; } diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index a082e8c40650..37b0b7c911ea 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -37,7 +37,6 @@ #include #if CONFIG_XRUN_NOTIFICATIONS_ENABLE -#include #include #endif @@ -1478,19 +1477,8 @@ static int dai_get_status(struct comp_dev *dev, struct dai_data *dd, struct dma_ int ret = sof_dma_get_status(dd->chan->dma, 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; - } + dd->xrun_notification_sent = send_copier_gateway_xrun_notif_msg + (dev->pipeline->pipeline_id, dev->direction); } else if (!ret) { dd->xrun_notification_sent = false; } diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 30cb465897ba..bdb5c5759274 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -33,7 +33,6 @@ #include #if CONFIG_XRUN_NOTIFICATIONS_ENABLE -#include #include #endif @@ -368,19 +367,8 @@ static int host_get_status(struct comp_dev *dev, struct host_data *hd, struct dm int ret = sof_dma_get_status(hd->chan->dma, 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; - } + hd->xrun_notification_sent = send_copier_gateway_xrun_notif_msg + (dev->pipeline->pipeline_id, dev->direction); } else if (!ret) { hd->xrun_notification_sent = false; } diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 1869099feb41..443c79dfad21 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -253,8 +252,6 @@ static void mixin_check_notify_underrun(struct comp_dev *dev, struct mixin_data const bool eos_detected = state == AUDIOBUF_STATE_END_OF_STREAM_FLUSH || state == AUDIOBUF_STATE_END_OF_STREAM; - struct ipc_msg *notify; - mixin_data->last_reported_underrun++; if (!source_avail || eos_detected) { @@ -273,13 +270,8 @@ static void mixin_check_notify_underrun(struct comp_dev *dev, struct mixin_data (eos_detected && mixin_data->eos_delay_periods == 0)) { mixin_data->last_reported_underrun = 0; - notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); - if (!notify) - return; - - mixer_underrun_notif_msg_init(notify, dev->ipc_config.id, eos_detected, + send_mixer_underrun_notif_msg(dev->ipc_config.id, eos_detected, source_avail, sinks_free); - ipc_msg_send(notify, notify->tx_data, false); } } } diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index 0b38574610de..8bfdfc182912 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -21,7 +21,6 @@ #include #include #include -#include #ifdef CONFIG_IPC_MAJOR_4 #include @@ -96,14 +95,7 @@ pipeline_should_report_enodata_on_trigger(struct comp_dev *rsrc, void pipeline_comp_copy_error_notify(const struct comp_dev *component, int err) { #ifdef CONFIG_IPC_MAJOR_4 - struct ipc_msg *notify; - - notify = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); - if (!notify) - return; - - process_data_error_notif_msg_init(notify, component->ipc_config.id, err); - ipc_msg_send(notify, notify->tx_data, false); + send_process_data_error_notif_msg(component->ipc_config.id, err); #endif } diff --git a/src/include/ipc4/notification.h b/src/include/ipc4/notification.h index 207dbfb7139c..23ade51bda5e 100644 --- a/src/include/ipc4/notification.h +++ b/src/include/ipc4/notification.h @@ -288,15 +288,12 @@ struct ipc4_resource_event_data_notification { #define IPC4_RESOURCE_EVENT_SIZE sizeof(struct ipc4_resource_event_data_notification) -void process_data_error_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id, - uint32_t error_code); +void send_process_data_error_notif_msg(uint32_t resource_id, uint32_t error_code); -void copier_gateway_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t pipeline_id); -void copier_gateway_overrun_notif_msg_init(struct ipc_msg *msg, uint32_t pipeline_id); -void gateway_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id); -void gateway_overrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id); +bool send_copier_gateway_xrun_notif_msg(uint32_t pipeline_id, enum sof_ipc_stream_direction dir); +bool send_gateway_xrun_notif_msg(uint32_t resource_id, enum sof_ipc_stream_direction dir); -void mixer_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id, uint32_t eos_flag, - uint32_t data_mixed, uint32_t expected_data_mixed); +void send_mixer_underrun_notif_msg(uint32_t resource_id, uint32_t eos_flag, uint32_t data_mixed, + uint32_t expected_data_mixed); #endif /* __IPC4_NOTIFICATION_H__ */ diff --git a/src/ipc/ipc4/notification.c b/src/ipc/ipc4/notification.c index f2a15b42f926..0e5a1aaa66ca 100644 --- a/src/ipc/ipc4/notification.c +++ b/src/ipc/ipc4/notification.c @@ -10,12 +10,19 @@ #include #include #include +#include #include -static void resource_notif_header_init(struct ipc_msg *msg) +static bool send_resource_notif(uint32_t resource_id, uint32_t event_type, uint32_t resource_type, + void *data, uint32_t data_size) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; + struct ipc_msg *msg = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); + + if (!msg) + return false; + + struct ipc4_resource_event_data_notification *notif = msg->tx_data; union ipc4_notification_header header; header.r.notif_type = SOF_IPC4_NOTIFY_RESOURCE_EVENT; @@ -23,72 +30,66 @@ static void resource_notif_header_init(struct ipc_msg *msg) header.r.rsp = SOF_IPC4_MESSAGE_DIR_MSG_REQUEST; header.r.msg_tgt = SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG; msg->header = header.dat; - memset(¬if_data->event_data, 0, sizeof(notif_data->event_data)); + + notif->resource_id = resource_id; + notif->event_type = event_type; + notif->resource_type = resource_type; + memset(¬if->event_data, 0, sizeof(notif->event_data)); + if (data && data_size) { + int ret = memcpy_s(¬if->event_data, sizeof(notif->event_data), data, data_size); + + if (ret) { + /* Most likely a simple coding mistake: + * Using a data type that is not included in the event_data union. + * Return true to prevent an infinite re-try loop in non-debug builds + */ + assert(false); + return true; + } + } + + ipc_msg_send(msg, msg->tx_data, false); + + return true; } -void copier_gateway_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t pipeline_id) +static enum sof_ipc4_resource_event_type dir_to_xrun_event(enum sof_ipc_stream_direction dir) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; - - resource_notif_header_init(msg); - notif_data->resource_id = pipeline_id; - notif_data->event_type = SOF_IPC4_GATEWAY_UNDERRUN_DETECTED; - notif_data->resource_type = SOF_IPC4_PIPELINE; + return (dir == SOF_IPC_STREAM_PLAYBACK) ? SOF_IPC4_GATEWAY_UNDERRUN_DETECTED : + SOF_IPC4_GATEWAY_OVERRUN_DETECTED; } -void gateway_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id) +bool send_copier_gateway_xrun_notif_msg(uint32_t pipeline_id, enum sof_ipc_stream_direction dir) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; - - resource_notif_header_init(msg); - notif_data->resource_id = resource_id; - notif_data->event_type = SOF_IPC4_GATEWAY_UNDERRUN_DETECTED; - notif_data->resource_type = SOF_IPC4_GATEWAY; + return send_resource_notif(pipeline_id, dir_to_xrun_event(dir), SOF_IPC4_PIPELINE, NULL, + 0); } -void copier_gateway_overrun_notif_msg_init(struct ipc_msg *msg, uint32_t pipeline_id) +bool send_gateway_xrun_notif_msg(uint32_t resource_id, enum sof_ipc_stream_direction dir) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; - - resource_notif_header_init(msg); - notif_data->resource_id = pipeline_id; - notif_data->event_type = SOF_IPC4_GATEWAY_OVERRUN_DETECTED; - notif_data->resource_type = SOF_IPC4_PIPELINE; + return send_resource_notif(resource_id, dir_to_xrun_event(dir), SOF_IPC4_GATEWAY, NULL, 0); } -void gateway_overrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id) +void send_mixer_underrun_notif_msg(uint32_t resource_id, uint32_t eos_flag, uint32_t data_mixed, + uint32_t expected_data_mixed) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; + struct ipc4_mixer_underrun_event_data mixer_underrun_data; - resource_notif_header_init(msg); - notif_data->resource_id = resource_id; - notif_data->event_type = SOF_IPC4_GATEWAY_OVERRUN_DETECTED; - notif_data->resource_type = SOF_IPC4_GATEWAY; -} + mixer_underrun_data.eos_flag = eos_flag; + mixer_underrun_data.data_mixed = data_mixed; + mixer_underrun_data.expected_data_mixed = expected_data_mixed; -void mixer_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id, uint32_t eos_flag, - uint32_t data_mixed, uint32_t expected_data_mixed) -{ - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; - - resource_notif_header_init(msg); - notif_data->resource_id = resource_id; - notif_data->event_type = SOF_IPC4_MIXER_UNDERRUN_DETECTED; - notif_data->resource_type = SOF_IPC4_PIPELINE; - notif_data->event_data.mixer_underrun.eos_flag = eos_flag; - notif_data->event_data.mixer_underrun.data_mixed = data_mixed; - notif_data->event_data.mixer_underrun.expected_data_mixed = expected_data_mixed; + send_resource_notif(resource_id, SOF_IPC4_MIXER_UNDERRUN_DETECTED, SOF_IPC4_PIPELINE, + &mixer_underrun_data, sizeof(mixer_underrun_data)); } -EXPORT_SYMBOL(mixer_underrun_notif_msg_init); +EXPORT_SYMBOL(send_mixer_underrun_notif_msg); -void process_data_error_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id, - uint32_t error_code) +void send_process_data_error_notif_msg(uint32_t resource_id, uint32_t error_code) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; + struct ipc4_process_data_error_event_data error_data; + + error_data.error_code = error_code; - resource_notif_header_init(msg); - notif_data->resource_id = resource_id; - notif_data->event_type = SOF_IPC4_PROCESS_DATA_ERROR; - notif_data->resource_type = SOF_IPC4_MODULE_INSTANCE; - notif_data->event_data.process_data_error.error_code = error_code; + send_resource_notif(resource_id, SOF_IPC4_PROCESS_DATA_ERROR, SOF_IPC4_MODULE_INSTANCE, + &error_data, sizeof(error_data)); } diff --git a/src/ipc/notification_pool.c b/src/ipc/notification_pool.c index 1627213f7829..7692928d0e8a 100644 --- a/src/ipc/notification_pool.c +++ b/src/ipc/notification_pool.c @@ -100,4 +100,3 @@ struct ipc_msg *ipc_notification_pool_get(size_t size) item->msg.tx_size = size; return &item->msg; } -EXPORT_SYMBOL(ipc_notification_pool_get); From 72c49bb0e49889c200843934a78d4c0d3cb180d2 Mon Sep 17 00:00:00 2001 From: Wojciech Jablonski Date: Mon, 16 Feb 2026 15:47:45 +0100 Subject: [PATCH 2/2] ipc4: notification: Add filtering feature Adding a handler for retrieving info about the IPC4 notification mask out of the LargeConfig. The notification mask is then used for filtering IPC4 notifications sent by the FW. This feature allows muting notifications of a given kind to enhance readability of logs during debugging. Also, this feature enhances reliability of certain tests run on FPGA-based setups where the FW notifications are too overwhelming for those setups. Signed-off-by: Wojciech Jablonski --- src/audio/base_fw.c | 14 +++++++++++++ src/include/ipc4/notification.h | 1 + src/ipc/ipc4/notification.c | 35 ++++++++++++++++++++++++++++++++- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 17c86fdb1df3..3d15720b6285 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -696,6 +697,17 @@ __cold static int basefw_get_large_config(struct comp_dev *dev, uint32_t param_i data_offset, data); }; +__cold static int basefw_notification_mask_info(const void *data) +{ + const struct ipc4_notification_mask_info *mask_info = data; + + assert_can_be_cold(); + + ipc4_update_notification_mask(mask_info->ntfy_mask, mask_info->enabled_mask); + + return IPC4_SUCCESS; +} + __cold static int basefw_astate_table(void) { assert_can_be_cold(); @@ -757,6 +769,8 @@ __cold static int basefw_set_large_config(struct comp_dev *dev, uint32_t param_i assert_can_be_cold(); switch (param_id) { + case IPC4_NOTIFICATION_MASK: + return basefw_notification_mask_info(data); case IPC4_ASTATE_TABLE: return basefw_astate_table(); case IPC4_DMA_CONTROL: diff --git a/src/include/ipc4/notification.h b/src/include/ipc4/notification.h index 23ade51bda5e..f8bf5d07dd99 100644 --- a/src/include/ipc4/notification.h +++ b/src/include/ipc4/notification.h @@ -295,5 +295,6 @@ bool send_gateway_xrun_notif_msg(uint32_t resource_id, enum sof_ipc_stream_direc void send_mixer_underrun_notif_msg(uint32_t resource_id, uint32_t eos_flag, uint32_t data_mixed, uint32_t expected_data_mixed); +void ipc4_update_notification_mask(uint32_t ntfy_mask, uint32_t enabled_mask); #endif /* __IPC4_NOTIFICATION_H__ */ diff --git a/src/ipc/ipc4/notification.c b/src/ipc/ipc4/notification.c index 0e5a1aaa66ca..9fd566ee1f93 100644 --- a/src/ipc/ipc4/notification.c +++ b/src/ipc/ipc4/notification.c @@ -14,11 +14,38 @@ #include +static uint32_t notification_mask = 0xFFFFFFFF; + +static bool is_notif_filtered_out(uint32_t event_type) +{ + uint32_t notif_idx; + + switch (event_type) { + case SOF_IPC4_GATEWAY_UNDERRUN_DETECTED: + notif_idx = IPC4_UNDERRUN_AT_GATEWAY_NOTIFICATION_MASK_IDX; + break; + case SOF_IPC4_MIXER_UNDERRUN_DETECTED: + notif_idx = IPC4_UNDERRUN_AT_MIXER_NOTIFICATION_MASK_IDX; + break; + case SOF_IPC4_GATEWAY_OVERRUN_DETECTED: + notif_idx = IPC4_OVERRUN_AT_GATEWAY_NOTIFICATION_MASK_IDX; + break; + default: + return false; + } + + return (notification_mask & BIT(notif_idx)) == 0; +} + static bool send_resource_notif(uint32_t resource_id, uint32_t event_type, uint32_t resource_type, void *data, uint32_t data_size) { - struct ipc_msg *msg = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); + struct ipc_msg *msg; + + if (is_notif_filtered_out(event_type)) + return true; //silently ignore + msg = ipc_notification_pool_get(IPC4_RESOURCE_EVENT_SIZE); if (!msg) return false; @@ -59,6 +86,12 @@ static enum sof_ipc4_resource_event_type dir_to_xrun_event(enum sof_ipc_stream_d SOF_IPC4_GATEWAY_OVERRUN_DETECTED; } +void ipc4_update_notification_mask(uint32_t ntfy_mask, uint32_t enabled_mask) +{ + notification_mask &= enabled_mask | (~ntfy_mask); + notification_mask |= enabled_mask & ntfy_mask; +} + bool send_copier_gateway_xrun_notif_msg(uint32_t pipeline_id, enum sof_ipc_stream_direction dir) { return send_resource_notif(pipeline_id, dir_to_xrun_event(dir), SOF_IPC4_PIPELINE, NULL,