From 0f45ef6a51177c7e47fde8aaff5205ae41efd3a5 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Wed, 17 Sep 2025 14:08:30 -0700 Subject: [PATCH 1/6] ipc: rework Zephyr IPC interface This reworks the Zephyr IPC interface to utilize the generic IPC service and backend. So we no longer have to maintain a SoC specific IPC driver. Signed-off-by: Daniel Leung --- app/boards/intel_adsp/Kconfig.defconfig | 2 + app/boards/intel_adsp_ace15_mtpm.conf | 3 + app/boards/intel_adsp_ace20_lnl.conf | 3 + app/boards/intel_adsp_ace30_ptl.conf | 3 + app/boards/intel_adsp_ace30_ptl_sim.conf | 4 +- app/boards/intel_adsp_ace30_wcl.conf | 3 + app/boards/intel_adsp_ace30_wcl_sim.conf | 3 + app/boards/intel_adsp_ace40_nvl.conf | 3 + app/boards/intel_adsp_ace40_nvls.conf | 3 + app/boards/intel_adsp_cavs25.conf | 3 + app/boards/intel_adsp_cavs25_tgph.conf | 5 + src/include/sof/ipc/common.h | 8 ++ src/ipc/ipc-zephyr.c | 116 ++++++++++++++++++----- src/platform/intel/ace/lib/watchdog.c | 3 +- 14 files changed, 136 insertions(+), 26 deletions(-) diff --git a/app/boards/intel_adsp/Kconfig.defconfig b/app/boards/intel_adsp/Kconfig.defconfig index a2ba2db15db6..e695bf4289fc 100644 --- a/app/boards/intel_adsp/Kconfig.defconfig +++ b/app/boards/intel_adsp/Kconfig.defconfig @@ -115,7 +115,9 @@ config DAI_INTEL_SSP default y config INTEL_ADSP_IPC + bool default y + depends on IPC_SERVICE_BACKEND_INTEL_ADSP_HOST_IPC config INTEL_ADSP_TIMER default y diff --git a/app/boards/intel_adsp_ace15_mtpm.conf b/app/boards/intel_adsp_ace15_mtpm.conf index 5266f38386d3..2278906cc008 100644 --- a/app/boards/intel_adsp_ace15_mtpm.conf +++ b/app/boards/intel_adsp_ace15_mtpm.conf @@ -85,3 +85,6 @@ CONFIG_LOG_BACKEND_SOF_PROBE=n CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_WINSTREAM_CONSOLE=n CONFIG_LOG_FLUSH_SLEEP_US=5000 + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace20_lnl.conf b/app/boards/intel_adsp_ace20_lnl.conf index abf6d1537330..fcea38859131 100644 --- a/app/boards/intel_adsp_ace20_lnl.conf +++ b/app/boards/intel_adsp_ace20_lnl.conf @@ -63,3 +63,6 @@ CONFIG_LOG_BACKEND_ADSP=n CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_WINSTREAM_CONSOLE=n CONFIG_LOG_FLUSH_SLEEP_US=5000 + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace30_ptl.conf b/app/boards/intel_adsp_ace30_ptl.conf index 48a923ab7870..7be338e68fa5 100644 --- a/app/boards/intel_adsp_ace30_ptl.conf +++ b/app/boards/intel_adsp_ace30_ptl.conf @@ -65,3 +65,6 @@ CONFIG_LOG_BACKEND_ADSP=n CONFIG_LOG_FLUSH_SLEEP_US=5000 CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_WINSTREAM_CONSOLE=n + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace30_ptl_sim.conf b/app/boards/intel_adsp_ace30_ptl_sim.conf index 477450d2d271..e85a10c56f0b 100644 --- a/app/boards/intel_adsp_ace30_ptl_sim.conf +++ b/app/boards/intel_adsp_ace30_ptl_sim.conf @@ -35,7 +35,6 @@ CONFIG_SOF_LOG_LEVEL_INF=n CONFIG_SOF_LOG_LEVEL_OFF=y CONFIG_ZEPHYR_LOG=n -CONFIG_INTEL_ADSP_IPC=y # Temporary disabled options @@ -45,3 +44,6 @@ CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y CONFIG_COMP_KPB=n CONFIG_USERSPACE=y + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace30_wcl.conf b/app/boards/intel_adsp_ace30_wcl.conf index 74a764883aad..b27eaf87fd8b 100644 --- a/app/boards/intel_adsp_ace30_wcl.conf +++ b/app/boards/intel_adsp_ace30_wcl.conf @@ -58,3 +58,6 @@ CONFIG_LOG_BACKEND_ADSP=n CONFIG_LOG_FLUSH_SLEEP_US=5000 CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_WINSTREAM_CONSOLE=n + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace30_wcl_sim.conf b/app/boards/intel_adsp_ace30_wcl_sim.conf index 288305be6313..eb0af8dd4197 100644 --- a/app/boards/intel_adsp_ace30_wcl_sim.conf +++ b/app/boards/intel_adsp_ace30_wcl_sim.conf @@ -41,3 +41,6 @@ CONFIG_PM_PREWAKEUP_CONV_MODE_CEIL=y CONFIG_COMP_KPB=n CONFIG_USERSPACE=y + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace40_nvl.conf b/app/boards/intel_adsp_ace40_nvl.conf index cfe332cd5075..e3f04d8efcd9 100644 --- a/app/boards/intel_adsp_ace40_nvl.conf +++ b/app/boards/intel_adsp_ace40_nvl.conf @@ -54,3 +54,6 @@ CONFIG_PM_DEVICE_RUNTIME_ASYNC=n # Zephyr / logging CONFIG_LOG_BACKEND_ADSP=n CONFIG_WINSTREAM_CONSOLE=n + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_ace40_nvls.conf b/app/boards/intel_adsp_ace40_nvls.conf index cfe332cd5075..e3f04d8efcd9 100644 --- a/app/boards/intel_adsp_ace40_nvls.conf +++ b/app/boards/intel_adsp_ace40_nvls.conf @@ -54,3 +54,6 @@ CONFIG_PM_DEVICE_RUNTIME_ASYNC=n # Zephyr / logging CONFIG_LOG_BACKEND_ADSP=n CONFIG_WINSTREAM_CONSOLE=n + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_cavs25.conf b/app/boards/intel_adsp_cavs25.conf index 0d39b072324c..c2ed5627854f 100644 --- a/app/boards/intel_adsp_cavs25.conf +++ b/app/boards/intel_adsp_cavs25.conf @@ -56,3 +56,6 @@ CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/app/boards/intel_adsp_cavs25_tgph.conf b/app/boards/intel_adsp_cavs25_tgph.conf index 2d6ac891cbd0..54d70bee24ed 100644 --- a/app/boards/intel_adsp_cavs25_tgph.conf +++ b/app/boards/intel_adsp_cavs25_tgph.conf @@ -1,3 +1,5 @@ +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n CONFIG_TIGERLAKE=y CONFIG_RIMAGE_SIGNING_SCHEMA="tgl-cavs" @@ -58,3 +60,6 @@ CONFIG_LOG_FUNC_NAME_PREFIX_DBG=y CONFIG_LOG_OUTPUT_FORMAT_LINUX_TIMESTAMP=y CONFIG_LOG_TIMESTAMP_64BIT=y CONFIG_WINSTREAM_CONSOLE=n + +# Use the new IPC message service in Zephyr +CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE=n diff --git a/src/include/sof/ipc/common.h b/src/include/sof/ipc/common.h index e46fc10b9521..61da9f8d3252 100644 --- a/src/include/sof/ipc/common.h +++ b/src/include/sof/ipc/common.h @@ -250,4 +250,12 @@ void ipc_complete_cmd(struct ipc *ipc); /* GDB stub: should enter GDB after completing the IPC processing */ extern bool ipc_enter_gdb; +/** + * \brief Send emergency IPC message. + * + * @param[in] data IPC data to be sent. + * @param[in] ext_data Extended data to be sent. + */ +void ipc_send_message_emergency(uint32_t data, uint32_t ext_data); + #endif /* __SOF_DRIVERS_IPC_H__ */ diff --git a/src/ipc/ipc-zephyr.c b/src/ipc/ipc-zephyr.c index 460089414cf7..41fb7f4676e0 100644 --- a/src/ipc/ipc-zephyr.c +++ b/src/ipc/ipc-zephyr.c @@ -13,7 +13,6 @@ #include -#include #include #include @@ -45,6 +44,11 @@ #include #include +#ifdef CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE +#include +#endif +#include + SOF_DEFINE_REG_UUID(zipc_task); LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); @@ -59,33 +63,88 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); */ static uint32_t g_last_data, g_last_ext_data; +struct k_sem *wait_ack_sem; + /** - * @brief cAVS IPC Message Handler Callback function. + * @brief cAVS IPC Message Received Callback function. * - * See @ref (*intel_adsp_ipc_handler_t) for function signature description. - * @return false so BUSY on the other side will not be cleared immediately but + * @return -1 so BUSY on the other side will not be cleared immediately but * will remain set until message would have been processed by scheduled task, i.e. * until ipc_platform_complete_cmd() call. */ -static bool message_handler(const struct device *dev, void *arg, uint32_t data, uint32_t ext_data) +static void ipc_receive_cb(const void *data, size_t cb_type, void *priv) { - struct ipc *ipc = (struct ipc *)arg; + struct intel_adsp_ipc_ept_priv_data *priv_data = priv; + + if (cb_type == INTEL_ADSP_IPC_CB_MSG) { + const struct intel_adsp_ipc_msg *msg = data; - k_spinlock_key_t key; + struct ipc *ipc = priv_data->priv; - key = k_spin_lock(&ipc->lock); + k_spinlock_key_t key; - g_last_data = data; - g_last_ext_data = ext_data; + key = k_spin_lock(&ipc->lock); + + g_last_data = msg->data; + g_last_ext_data = msg->ext_data; #if CONFIG_DEBUG_IPC_COUNTERS - increment_ipc_received_counter(); + increment_ipc_received_counter(); #endif - ipc_schedule_process(ipc); + ipc_schedule_process(ipc); - k_spin_unlock(&ipc->lock, key); + k_spin_unlock(&ipc->lock, key); - return false; + priv_data->cb_ret = -1; + } else if (cb_type == INTEL_ADSP_IPC_CB_DONE) { + if (wait_ack_sem) + k_sem_give(wait_ack_sem); + + priv_data->cb_ret = INTEL_ADSP_IPC_CB_RET_OKAY; + } +} + +static struct ipc_ept ipc_ept; +static struct intel_adsp_ipc_ept_priv_data ipc_ept_priv_data; +static struct ipc_ept_cfg ipc_ept_cfg = { + .name = "sof_ipc", + .cb = { + .received = ipc_receive_cb, + }, + .priv = &ipc_ept_priv_data, +}; + +static void ipc_ept_init(struct ipc *ipc) +{ + const struct device *ipc_dev = INTEL_ADSP_IPC_HOST_DEV; + + ipc_ept_priv_data.priv = ipc; + + ipc_service_register_endpoint(ipc_dev, &ipc_ept, &ipc_ept_cfg); +} + +static void ipc_complete(void) +{ + ipc_service_send(&ipc_ept, NULL, INTEL_ADSP_IPC_SEND_DONE); +} + +static bool ipc_is_complete(void) +{ + return ipc_service_send(&ipc_ept, NULL, INTEL_ADSP_IPC_SEND_IS_COMPLETE) == 0; +} + +static int ipc_send_message(uint32_t data, uint32_t ext_data) +{ + struct intel_adsp_ipc_msg msg = {.data = data, .ext_data = ext_data}; + + return ipc_service_send(&ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG); +} + +void ipc_send_message_emergency(uint32_t data, uint32_t ext_data) +{ + struct intel_adsp_ipc_msg msg = {.data = data, .ext_data = ext_data}; + + ipc_service_send(&ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG_EMERGENCY); } #ifdef CONFIG_PM_DEVICE @@ -159,8 +218,8 @@ static int ipc_device_resume_handler(const struct device *dev, void *arg) ipc->task_mask = 0; ipc->pm_prepare_D3 = false; - /* attach handlers */ - intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc); + /* initialize IPC endpoint */ + ipc_ept_init(ipc); /* schedule task */ #if CONFIG_TWB_IPC_TASK @@ -254,7 +313,7 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc) void ipc_platform_complete_cmd(struct ipc *ipc) { ARG_UNUSED(ipc); - intel_adsp_ipc_complete(INTEL_ADSP_IPC_HOST_DEV); + ipc_complete(); #if CONFIG_DEBUG_IPC_COUNTERS increment_ipc_processed_counter(); @@ -263,13 +322,13 @@ void ipc_platform_complete_cmd(struct ipc *ipc) int ipc_platform_send_msg(const struct ipc_msg *msg) { - if (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV)) + if (!ipc_is_complete()) return -EBUSY; /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); - return intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext); + return ipc_send_message(hdr->pri, hdr->ext); } void ipc_platform_send_msg_direct(const struct ipc_msg *msg) @@ -277,12 +336,12 @@ void ipc_platform_send_msg_direct(const struct ipc_msg *msg) /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); - intel_adsp_ipc_send_message_emergency(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext); + ipc_send_message_emergency(hdr->pri, hdr->ext); } int ipc_platform_poll_is_host_ready(void) { - return intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV); + return ipc_is_complete(); } int platform_ipc_init(struct ipc *ipc) @@ -300,8 +359,9 @@ int platform_ipc_init(struct ipc *ipc) #endif /* configure interrupt - work is done internally by Zephyr API */ - /* attach handlers */ - intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc); + /* initialize IPC endpoint */ + ipc_ept_init(ipc); + #ifdef CONFIG_PM intel_adsp_ipc_set_suspend_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_device_suspend_handler, ipc); @@ -312,11 +372,13 @@ int platform_ipc_init(struct ipc *ipc) return 0; } +#ifdef CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE static bool ipc_wait_complete(const struct device *dev, void *arg) { k_sem_give(arg); return false; } +#endif void ipc_platform_wait_ack(struct ipc *ipc) { @@ -324,10 +386,18 @@ void ipc_platform_wait_ack(struct ipc *ipc) k_sem_init(&ipc_wait_sem, 0, 1); +#ifdef CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, ipc_wait_complete, &ipc_wait_sem); +#else + wait_ack_sem = &ipc_wait_sem; +#endif if (k_sem_take(&ipc_wait_sem, Z_TIMEOUT_MS(10)) == -EAGAIN) tr_err(&ipc_tr, "Timeout waiting for host ack!"); +#ifdef CONFIG_INTEL_ADSP_IPC_OLD_INTERFACE intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, NULL, NULL); +#else + wait_ack_sem = NULL; +#endif } diff --git a/src/platform/intel/ace/lib/watchdog.c b/src/platform/intel/ace/lib/watchdog.c index dcae80da801d..2ee7369df3da 100644 --- a/src/platform/intel/ace/lib/watchdog.c +++ b/src/platform/intel/ace/lib/watchdog.c @@ -34,8 +34,7 @@ static void watchdog_primary_core_action_on_timeout(void) /* Send Watchdog Timeout IPC notification */ ipc4_notification_watchdog_init(¬if, cpu_get_id(), true); - intel_adsp_ipc_send_message_emergency(INTEL_ADSP_IPC_HOST_DEV, - notif.primary.dat, notif.extension.dat); + (void)ipc_send_message_emergency(notif.primary.dat, notif.extension.dat); } static void watchdog_secondary_core_action_on_timeout(void) From 82393de5689be13ea360c4829b8f78c41f4c4e63 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 31 Oct 2025 18:20:24 +0200 Subject: [PATCH 2/6] (PR10089 commits end here) Link: https://github.com/thesofproject/sof/pull/10089 From 420fa8ef2ae8ea80fa0b7b2b988a94e45eac2bb4 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 31 Oct 2025 15:38:08 +0200 Subject: [PATCH 3/6] ipc: ipc: abstract access to IPC payload Preparation to abstract use of mailboxes in code that handles IPC responses. Remove direct access to mailbox.h HOSTBOX definition, and instead use a function to get access to the payload. This allows to have the mailbox access code in one place and e.g. ensure the cache invalidation is done correctly. In a later step, this code will be moved to Zephyr IPC driver. This will allow to use SOF with generic IPC drivers (no need to map to mailbox.h). Signed-off-by: Kai Vehmanen --- src/include/sof/ipc/common.h | 6 ++++++ src/ipc/ipc-zephyr.c | 19 +++++++++++++++++++ src/ipc/ipc4/handler.c | 32 +++++++++++++------------------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/include/sof/ipc/common.h b/src/include/sof/ipc/common.h index 61da9f8d3252..0e563312e28c 100644 --- a/src/include/sof/ipc/common.h +++ b/src/include/sof/ipc/common.h @@ -213,6 +213,12 @@ int ipc_compact_write_msg(struct ipc_cmd_hdr *hdr); */ struct ipc_cmd_hdr *ipc_prepare_to_send(const struct ipc_msg *msg); +/** + * \brief Access IPC message payload (hostbox) from DSP. + *@param[in]bytes make bytes available to host processing + */ +uint32_t *ipc_access_msg_payload(size_t bytes); + /** * \brief Validate mailbox contents for valid IPC header. * @return pointer to header if valid or NULL. diff --git a/src/ipc/ipc-zephyr.c b/src/ipc/ipc-zephyr.c index 41fb7f4676e0..9021d60a6c91 100644 --- a/src/ipc/ipc-zephyr.c +++ b/src/ipc/ipc-zephyr.c @@ -339,6 +339,25 @@ void ipc_platform_send_msg_direct(const struct ipc_msg *msg) ipc_send_message_emergency(hdr->pri, hdr->ext); } +uint32_t *ipc_access_msg_payload(size_t bytes) +{ + /* + * TODO: intermediate step to put MAILBOX access here, + * this should be moved to Zephyr IPC driver + */ + uint32_t *hostbox = (uint32_t*)MAILBOX_HOSTBOX_BASE; + + /* + * TODO: can we invalidate whole hostbox upon IPC reception + * and skip these calls doen when incrementally + * parsing the message until full length of payload + * is known + */ + dcache_invalidate_region((__sparse_force void __sparse_cache *)hostbox, bytes); + + return hostbox; +} + int ipc_platform_poll_is_host_ready(void) { return ipc_is_complete(); diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 3eea8f623081..ec417c7f2df1 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -123,9 +123,7 @@ static inline const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data( { const struct ipc4_pipeline_set_state_data *ppl_data; - ppl_data = (const struct ipc4_pipeline_set_state_data *)MAILBOX_HOSTBOX_BASE; - dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_data, - sizeof(*ppl_data)); + ppl_data = (const struct ipc4_pipeline_set_state_data *)ipc_access_msg_payload(sizeof(*ppl_data));; return ppl_data; } @@ -999,12 +997,13 @@ static int ipc4_set_get_config_module_instance(struct ipc4_message_request *ipc4 __cold static void ipc4_prepare_for_kcontrol_get(struct comp_dev *dev, uint8_t param_id, char *data_out, uint32_t data_size) { - const char *hostbox; + const uint32_t *hostbox; #if CONFIG_LIBRARY + /* TODO: can we abstrac LIBRARY to use its own driver? */ hostbox = (const char *)ipc_get()->comp_data + sizeof(struct ipc4_module_large_config); #else - hostbox = (const char *)MAILBOX_HOSTBOX_BASE; + hostbox = ipc_access_msg_payload(data_size); #endif assert_can_be_cold(); @@ -1013,10 +1012,6 @@ __cold static void ipc4_prepare_for_kcontrol_get(struct comp_dev *dev, uint8_t p case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: case SOF_IPC4_ENUM_CONTROL_PARAM_ID: case SOF_IPC4_BYTES_CONTROL_PARAM_ID: - /* We have payload in hostbox */ - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - data_size); - /* Copy the control payload header from inbox to outbox */ memcpy_s(data_out, data_size, hostbox, sizeof(struct sof_ipc4_control_msg_payload)); @@ -1172,14 +1167,14 @@ __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_requ /* check for vendor param first */ if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { /* For now only vendor_config case uses payload from hostbox */ - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); + const uint32_t *ipc_payload = + ipc_access_msg_payload(config.extension.r.data_off_size); ret = ipc4_get_vendor_config_module_instance(dev, drv, config.extension.r.init_block, config.extension.r.final_block, &data_offset, data, - (const char *)MAILBOX_HOSTBOX_BASE); + (const char *)ipc_payload); } else { #if CONFIG_LIBRARY data += sizeof(reply); @@ -1297,8 +1292,7 @@ __cold static int ipc4_set_large_config_module_instance(struct ipc4_message_requ if (ret < 0) return IPC4_FAILURE; - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); + uint32_t *ipc_payload = ipc_access_msg_payload(config.extension.r.data_off_size); tr_dbg(&ipc_tr, "ipc4_set_large_config_module_instance %x : %x", (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); @@ -1333,13 +1327,14 @@ __cold static int ipc4_set_large_config_module_instance(struct ipc4_message_requ config.extension.r.init_block, config.extension.r.final_block, config.extension.r.data_off_size, - (const char *)MAILBOX_HOSTBOX_BASE); + (const char *)ipc_payload); } else { #if CONFIG_LIBRARY struct ipc *ipc = ipc_get(); const char *data = (const char *)ipc->comp_data + sizeof(config); #else - const char *data = (const char *)MAILBOX_HOSTBOX_BASE; + const char *data = + (const char *)ipc_access_msg_payload(config.extension.r.data_off_size); #endif ret = drv->ops.set_large_config(dev, config.extension.r.large_param_id, config.extension.r.init_block, config.extension.r.final_block, @@ -1439,10 +1434,9 @@ __cold static int ipc4_module_process_dx(struct ipc4_message_request *ipc4) return IPC4_INVALID_RESOURCE_ID; } - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - sizeof(dx_info)); + const uint32_t *ipc_payload = ipc_access_msg_payload(sizeof(dx_info)); ret = memcpy_s(&dx_info, sizeof(dx_info), - (const void *)MAILBOX_HOSTBOX_BASE, sizeof(dx_info)); + (const void *)ipc_payload, sizeof(dx_info)); if (ret < 0) return IPC4_FAILURE; From c0fe7527ef5f790d49356fb6b37ac63e5e719379 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 31 Oct 2025 15:56:45 +0200 Subject: [PATCH 4/6] ipc: move IPC payload write to SOF Zephyr IPC client code In commit 7ba1a08862d6 ("ipc4: add support for ipc4 boot message and data"), ipc_prepare_to_send() function was added to prepare the IPC client code to handle multiple IPC versions. This function has however not been used in all IPC client code in SOF, and when Intel IPC3 support was removed, only remaining usage is in ipc-zephyr.c. As usage is limited, change the semantics of ipc_prepare_to_send() to only modify the header fields (e.g. for IPC4 set the extension field), but remove the code to write payload to mailbox. Instead move this code to ipc-zephyr.c. This will allow to move the payload handling later to Zephyr drivers, and out from common codec. Signed-off-by: Kai Vehmanen --- src/ipc/ipc-zephyr.c | 6 ++++++ src/ipc/ipc3/handler.c | 2 -- src/ipc/ipc4/handler.c | 3 --- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ipc/ipc-zephyr.c b/src/ipc/ipc-zephyr.c index 9021d60a6c91..a1797e7ee63c 100644 --- a/src/ipc/ipc-zephyr.c +++ b/src/ipc/ipc-zephyr.c @@ -328,6 +328,9 @@ int ipc_platform_send_msg(const struct ipc_msg *msg) /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); + if (msg->tx_size) + mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); + return ipc_send_message(hdr->pri, hdr->ext); } @@ -336,6 +339,9 @@ void ipc_platform_send_msg_direct(const struct ipc_msg *msg) /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); + if (msg->tx_size) + mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); + ipc_send_message_emergency(hdr->pri, hdr->ext); } diff --git a/src/ipc/ipc3/handler.c b/src/ipc/ipc3/handler.c index 9f865960f1bf..15dae82a0975 100644 --- a/src/ipc/ipc3/handler.c +++ b/src/ipc/ipc3/handler.c @@ -1500,8 +1500,6 @@ struct ipc_cmd_hdr *ipc_prepare_to_send(const struct ipc_msg *msg) hdr[0] = msg->header; hdr[1] = 0; - mailbox_dspbox_write(0, msg->tx_data, msg->tx_size); - return ipc_to_hdr(hdr); } diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index ec417c7f2df1..81ef65231024 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -1592,9 +1592,6 @@ struct ipc_cmd_hdr *ipc_prepare_to_send(const struct ipc_msg *msg) msg_data.msg_out.pri = msg->header; msg_data.msg_out.ext = msg->extension; - if (msg->tx_size) - mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); - return &msg_data.msg_out; } From 4550361696b0aa7545bcafde4ff0948612297e65 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Tue, 4 Nov 2025 18:56:27 +0200 Subject: [PATCH 5/6] [DO NOT MERGE] west.yml: use Zephyr PR 98862 Link: https://github.com/zephyrproject-rtos/zephyr/pull/98862 --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 3d9e57b78b5c..ffc6440003ee 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: fb01c781b6c0ca6cee65ea853157704742c74cdd + revision: revision: pull/98862/head remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision From e764edcd05977ffdbeb2fb747d17a87035179a0d Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 3 Nov 2025 20:40:03 +0200 Subject: [PATCH 6/6] ipc: move IPC payload handling to IPC driver Move responsibility to write and read the IPC message payload to the Zephyr IPC driver. This change allows to use SOF IPC client code with multiple hardware backends and there's no assumption payload transport is a memory mapped payload buffer is exposed via mailbox.h. This depends on Zephyr commit TBD ("foo bar") that adds message payload to the interface. Signed-off-by: Kai Vehmanen --- src/ipc/ipc-zephyr.c | 66 +++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/src/ipc/ipc-zephyr.c b/src/ipc/ipc-zephyr.c index a1797e7ee63c..baf0e065cb36 100644 --- a/src/ipc/ipc-zephyr.c +++ b/src/ipc/ipc-zephyr.c @@ -16,8 +16,8 @@ #include #include -#include -#include +#include /* for sw_regs with CONFIG_DEBUG_IPC_COUNTERS */ +#include /* for sw_regs with CONFIG_DEBUG_IPC_COUNTERS */ #if defined(CONFIG_PM) #include #include @@ -61,7 +61,9 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL); * Filled with content of TDR and TDD registers. * When IPC message is read fills ipc_cmd_hdr. */ -static uint32_t g_last_data, g_last_ext_data; +static uint32_t g_last_data, g_last_ext_data, g_last_payload_length; + +static uint32_t *g_last_payload; struct k_sem *wait_ack_sem; @@ -87,6 +89,8 @@ static void ipc_receive_cb(const void *data, size_t cb_type, void *priv) g_last_data = msg->data; g_last_ext_data = msg->ext_data; + g_last_payload = msg->payload; + g_last_payload_length = msg->payload_length; #if CONFIG_DEBUG_IPC_COUNTERS increment_ipc_received_counter(); @@ -133,11 +137,9 @@ static bool ipc_is_complete(void) return ipc_service_send(&ipc_ept, NULL, INTEL_ADSP_IPC_SEND_IS_COMPLETE) == 0; } -static int ipc_send_message(uint32_t data, uint32_t ext_data) +static int ipc_send_message(struct intel_adsp_ipc_msg *msg) { - struct intel_adsp_ipc_msg msg = {.data = data, .ext_data = ext_data}; - - return ipc_service_send(&ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG); + return ipc_service_send(&ipc_ept, msg, INTEL_ADSP_IPC_SEND_MSG); } void ipc_send_message_emergency(uint32_t data, uint32_t ext_data) @@ -147,6 +149,11 @@ void ipc_send_message_emergency(uint32_t data, uint32_t ext_data) ipc_service_send(&ipc_ept, &msg, INTEL_ADSP_IPC_SEND_MSG_EMERGENCY); } +static void ipc_send_message_emergency_with_payload(struct intel_adsp_ipc_msg *msg) +{ + ipc_service_send(&ipc_ept, msg, INTEL_ADSP_IPC_SEND_MSG_EMERGENCY); +} + #ifdef CONFIG_PM_DEVICE /** * @brief IPC device suspend handler callback function. @@ -325,43 +332,38 @@ int ipc_platform_send_msg(const struct ipc_msg *msg) if (!ipc_is_complete()) return -EBUSY; - /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); - - if (msg->tx_size) - mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); - - return ipc_send_message(hdr->pri, hdr->ext); + struct intel_adsp_ipc_msg ipc_drv_msg = { + .data = hdr->pri, + .ext_data = hdr->ext, + .payload = (uintptr_t)msg->tx_data, + .payload_length = msg->tx_size + }; + + return ipc_send_message(&ipc_drv_msg); } void ipc_platform_send_msg_direct(const struct ipc_msg *msg) { /* prepare the message and copy to mailbox */ struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg); - - if (msg->tx_size) - mailbox_dspbox_write(0, (uint32_t *)msg->tx_data, msg->tx_size); - - ipc_send_message_emergency(hdr->pri, hdr->ext); + struct intel_adsp_ipc_msg ipc_drv_msg = { + .data = hdr->pri, + .ext_data = hdr->ext, + .payload = (uintptr_t)msg->tx_data, + .payload_length = msg->tx_size + }; + + ipc_send_message_emergency_with_payload(&ipc_drv_msg); } -uint32_t *ipc_access_msg_payload(size_t bytes) +uint32_t *ipc_access_msg_payload(size_t __unused bytes) { /* - * TODO: intermediate step to put MAILBOX access here, - * this should be moved to Zephyr IPC driver + * The IPC driver has flushed the + * cache on payload buffer, so no action needed here. */ - uint32_t *hostbox = (uint32_t*)MAILBOX_HOSTBOX_BASE; - - /* - * TODO: can we invalidate whole hostbox upon IPC reception - * and skip these calls doen when incrementally - * parsing the message until full length of payload - * is known - */ - dcache_invalidate_region((__sparse_force void __sparse_cache *)hostbox, bytes); - - return hostbox; + return g_last_payload; } int ipc_platform_poll_is_host_ready(void)