From 10e69b5397018b383e9370e979eb2b316b8f07fc 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 | 22 +++--- src/audio/dai-zephyr.c | 20 ++---- src/audio/host-zephyr.c | 22 +++--- src/audio/mixin_mixout/mixin_mixout.c | 10 +-- src/audio/pipeline/pipeline-stream.c | 10 +-- src/include/ipc4/notification.h | 15 ++-- src/ipc/ipc4/notification.c | 100 +++++++++++++------------- src/ipc/notification_pool.c | 1 - 8 files changed, 81 insertions(+), 119 deletions(-) diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index 25672b3e7227..528753924bca 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,14 @@ 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; - } + uint32_t node_id = cd->link_connector_node_id.dw; + bool notif_sent = false; + + if (cd->stream_direction == SOF_IPC_STREAM_PLAYBACK) + notif_sent = send_gateway_underrun_notif_msg(node_id); + else + notif_sent = send_gateway_overrun_notif_msg(node_id); + cd->xrun_notification_sent = notif_sent; } else if (!ret) { cd->xrun_notification_sent = false; } diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 3c9229953cfc..ace2b460f529 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,14 @@ 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); + uint32_t ppl_id = dev->pipeline->pipeline_id; + bool notif_sent = false; - 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; - } + if (dev->direction == SOF_IPC_STREAM_PLAYBACK) + notif_sent = send_copier_gateway_underrun_notif_msg(ppl_id); + else + notif_sent = send_copier_gateway_overrun_notif_msg(ppl_id); + dd->xrun_notification_sent = notif_sent; } else if (!ret) { dd->xrun_notification_sent = false; } diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index a8f16e98c7b8..cef21ae3d07f 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,14 @@ 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; - } + uint32_t ppl_id = dev->pipeline->pipeline_id; + bool notif_sent = false; + + if (dev->direction == SOF_IPC_STREAM_PLAYBACK) + notif_sent = send_copier_gateway_underrun_notif_msg(ppl_id); + else + notif_sent = send_copier_gateway_overrun_notif_msg(ppl_id); + hd->xrun_notification_sent = notif_sent; } 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..1942aa9613dc 100644 --- a/src/include/ipc4/notification.h +++ b/src/include/ipc4/notification.h @@ -288,15 +288,14 @@ 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_underrun_notif_msg(uint32_t pipeline_id); +bool send_copier_gateway_overrun_notif_msg(uint32_t pipeline_id); +bool send_gateway_underrun_notif_msg(uint32_t resource_id); +bool send_gateway_overrun_notif_msg(uint32_t resource_id); -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..5baf4b96f296 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,63 @@ 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)); -} -void copier_gateway_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t pipeline_id) -{ - struct ipc4_resource_event_data_notification *notif_data = msg->tx_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) + memcpy_s(¬if->event_data, sizeof(notif->event_data), data, data_size); + + ipc_msg_send(msg, msg->tx_data, false); - 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 true; } -void gateway_underrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id) +bool send_copier_gateway_underrun_notif_msg(uint32_t pipeline_id) { - 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, SOF_IPC4_GATEWAY_UNDERRUN_DETECTED, + SOF_IPC4_PIPELINE, NULL, 0); } -void copier_gateway_overrun_notif_msg_init(struct ipc_msg *msg, uint32_t pipeline_id) +bool send_gateway_underrun_notif_msg(uint32_t resource_id) { - 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, SOF_IPC4_GATEWAY_UNDERRUN_DETECTED, + SOF_IPC4_GATEWAY, NULL, 0); } -void gateway_overrun_notif_msg_init(struct ipc_msg *msg, uint32_t resource_id) +bool send_copier_gateway_overrun_notif_msg(uint32_t pipeline_id) { - struct ipc4_resource_event_data_notification *notif_data = msg->tx_data; + return send_resource_notif(pipeline_id, SOF_IPC4_GATEWAY_OVERRUN_DETECTED, + SOF_IPC4_PIPELINE, NULL, 0); +} - 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; +bool send_gateway_overrun_notif_msg(uint32_t resource_id) +{ + return send_resource_notif(resource_id, SOF_IPC4_GATEWAY_OVERRUN_DETECTED, + SOF_IPC4_GATEWAY, NULL, 0); } -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) { - 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; + struct ipc4_mixer_underrun_event_data mixer_underrun_data; + + mixer_underrun_data.eos_flag = eos_flag; + mixer_underrun_data.data_mixed = data_mixed; + mixer_underrun_data.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 b9ebeb7c45229f7e613a3662258f3f7d673f022f 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 | 15 ++++++++++++++ src/include/ipc4/notification.h | 1 + src/ipc/ipc4/notification.c | 35 ++++++++++++++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 17c86fdb1df3..d6a26bfc220d 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,18 @@ __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 char *data) +{ + struct ipc4_notification_mask_info *mask_info; + + assert_can_be_cold(); + + mask_info = (struct ipc4_notification_mask_info *)data; + 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 +770,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 1942aa9613dc..3d0a1a171715 100644 --- a/src/include/ipc4/notification.h +++ b/src/include/ipc4/notification.h @@ -297,5 +297,6 @@ bool send_gateway_overrun_notif_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); +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 5baf4b96f296..cc0f3256132a 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; @@ -43,6 +70,12 @@ static bool send_resource_notif(uint32_t resource_id, uint32_t event_type, uint3 return true; } +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_underrun_notif_msg(uint32_t pipeline_id) { return send_resource_notif(pipeline_id, SOF_IPC4_GATEWAY_UNDERRUN_DETECTED,