Skip to content

Commit 7b50fa3

Browse files
tmlemankv2019i
authored andcommitted
sof: ipc: switch platform IPC to Zephyr service
This patch reworks the SOF IPC platform integration to use the generic Zephyr ipc_service instead of the Intel audio DSP specific driver. Before this change SOF was talking directly to the Intel ADSP IPC driver, which made the IPC path tightly coupled to that particular backend. All commands were sent and completed via intel_adsp_ipc_*() functions. The code now sends and receives IPC commands through a Zephyr ipc_service endpoint registered on the Intel ADSP host IPC instance, using sof_ipc_receive_cb() as the receive handler. Incoming messages are processed as before using the existing compact IPC path to process commands. Each IPC command is treated as a compact two-word ipc_cmd_hdr and a BUILD_ASSERT guarantees that the header size remains aligned with the transport format assumptions. This change is part of ongoing work to better integrate SOF with Zephyr and will allow other vendors to more easily integrate their own IPC backends. Signed-off-by: Tomasz Leman <tomasz.m.leman@intel.com>
1 parent fc73f9d commit 7b50fa3

File tree

1 file changed

+52
-24
lines changed

1 file changed

+52
-24
lines changed

src/ipc/ipc-zephyr.c

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@
1212
#include <autoconf.h>
1313

1414
#include <zephyr/kernel.h>
15-
15+
#include <zephyr/ipc/ipc_service.h>
16+
#ifdef CONFIG_INTEL_ADSP_IPC
17+
#include <zephyr/ipc/backends/intel_adsp_host_ipc.h>
1618
#include <intel_adsp_ipc.h>
19+
#endif
20+
1721
#include <sof/ipc/common.h>
1822

1923
#include <sof/ipc/schedule.h>
@@ -58,34 +62,39 @@ LOG_MODULE_DECLARE(ipc, CONFIG_SOF_LOG_LEVEL);
5862
* When IPC message is read fills ipc_cmd_hdr.
5963
*/
6064
static uint32_t g_last_data, g_last_ext_data;
65+
static struct ipc_ept sof_ipc_ept;
66+
static struct ipc_ept_cfg sof_ipc_ept_cfg;
67+
68+
BUILD_ASSERT(sizeof(struct ipc_cmd_hdr) == sizeof(uint32_t) * 2,
69+
"ipc_cmd_hdr must be exactly two 32-bit words");
6170

6271
/**
63-
* @brief cAVS IPC Message Handler Callback function.
72+
* @brief SOF IPC receive callback for Zephyr IPC service.
6473
*
65-
* See @ref (*intel_adsp_ipc_handler_t) for function signature description.
66-
* @return false so BUSY on the other side will not be cleared immediately but
67-
* will remain set until message would have been processed by scheduled task, i.e.
68-
* until ipc_platform_complete_cmd() call.
74+
* This callback is invoked by the Zephyr IPC service backend when a compact 2-word IPC message
75+
* arrives from the host. It stores the raw header words in g_last_data/g_last_ext_data and
76+
* schedules the SOF IPC task to process the command via ipc_platform_do_cmd().
6977
*/
70-
static bool message_handler(const struct device *dev, void *arg, uint32_t data, uint32_t ext_data)
78+
static void sof_ipc_receive_cb(const void *data, size_t len, void *priv)
7179
{
72-
struct ipc *ipc = (struct ipc *)arg;
73-
80+
struct ipc *ipc = (struct ipc *)priv;
81+
const uint32_t *msg = data;
7482
k_spinlock_key_t key;
7583

84+
__ASSERT(len == sizeof(uint32_t) * 2, "Unexpected IPC message length: %zu", len);
85+
__ASSERT(data, "IPC data pointer is NULL");
86+
7687
key = k_spin_lock(&ipc->lock);
7788

78-
g_last_data = data;
79-
g_last_ext_data = ext_data;
89+
g_last_data = msg[0];
90+
g_last_ext_data = msg[1];
8091

8192
#if CONFIG_DEBUG_IPC_COUNTERS
8293
increment_ipc_received_counter();
8394
#endif
8495
ipc_schedule_process(ipc);
8596

8697
k_spin_unlock(&ipc->lock, key);
87-
88-
return false;
8998
}
9099

91100
#ifdef CONFIG_PM_DEVICE
@@ -159,9 +168,6 @@ static int ipc_device_resume_handler(const struct device *dev, void *arg)
159168
ipc->task_mask = 0;
160169
ipc->pm_prepare_D3 = false;
161170

162-
/* attach handlers */
163-
intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc);
164-
165171
/* schedule task */
166172
#if CONFIG_TWB_IPC_TASK
167173
scheduler_twb_task_init(&ipc->ipc_task, SOF_UUID(zipc_task_uuid),
@@ -254,7 +260,10 @@ enum task_state ipc_platform_do_cmd(struct ipc *ipc)
254260
void ipc_platform_complete_cmd(struct ipc *ipc)
255261
{
256262
ARG_UNUSED(ipc);
257-
intel_adsp_ipc_complete(INTEL_ADSP_IPC_HOST_DEV);
263+
int ret = ipc_service_release_rx_buffer(&sof_ipc_ept, NULL);
264+
265+
if (ret < 0)
266+
tr_warn(&ipc_tr, "ipc_service_release_rx_buffer() failed: %d", ret);
258267

259268
#if CONFIG_DEBUG_IPC_COUNTERS
260269
increment_ipc_processed_counter();
@@ -263,30 +272,34 @@ void ipc_platform_complete_cmd(struct ipc *ipc)
263272

264273
int ipc_platform_send_msg(const struct ipc_msg *msg)
265274
{
266-
if (!intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV))
275+
if (ipc_service_get_tx_buffer_size(&sof_ipc_ept) == 0)
267276
return -EBUSY;
268277

269278
/* prepare the message and copy to mailbox */
270279
struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg);
271280

272-
return intel_adsp_ipc_send_message(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext);
281+
return ipc_service_send(&sof_ipc_ept, hdr, sizeof(*hdr));
273282
}
274283

275284
void ipc_platform_send_msg_direct(const struct ipc_msg *msg)
276285
{
277286
/* prepare the message and copy to mailbox */
278287
struct ipc_cmd_hdr *hdr = ipc_prepare_to_send(msg);
288+
int ret = ipc_service_send_critical(&sof_ipc_ept, hdr, sizeof(*hdr));
279289

280-
intel_adsp_ipc_send_message_emergency(INTEL_ADSP_IPC_HOST_DEV, hdr->pri, hdr->ext);
290+
if (ret < 0)
291+
tr_err(&ipc_tr, "ipc_service_send_critical() failed: %d", ret);
281292
}
282293

283294
int ipc_platform_poll_is_host_ready(void)
284295
{
285-
return intel_adsp_ipc_is_complete(INTEL_ADSP_IPC_HOST_DEV);
296+
return ipc_service_get_tx_buffer_size(&sof_ipc_ept) > 0;
286297
}
287298

288299
int platform_ipc_init(struct ipc *ipc)
289300
{
301+
int ret;
302+
290303
ipc_set_drvdata(ipc, NULL);
291304

292305
/* schedule task */
@@ -300,9 +313,22 @@ int platform_ipc_init(struct ipc *ipc)
300313
#endif
301314
/* configure interrupt - work is done internally by Zephyr API */
302315

303-
/* attach handlers */
304-
intel_adsp_ipc_set_message_handler(INTEL_ADSP_IPC_HOST_DEV, message_handler, ipc);
305-
#ifdef CONFIG_PM
316+
sof_ipc_ept_cfg.name = "sof_ipc";
317+
sof_ipc_ept_cfg.prio = 0;
318+
sof_ipc_ept_cfg.cb.received = sof_ipc_receive_cb;
319+
sof_ipc_ept_cfg.priv = ipc;
320+
321+
/*
322+
* TODO: INTEL_ADSP_IPC_HOST_DEV is currently hardcoded for Intel ADSP platform.
323+
* This needs to be made generic/configurable when additional vendor IPC backends
324+
* become available (e.g., via devicetree, Kconfig, or platform-specific device selection).
325+
*/
326+
ret = ipc_service_register_endpoint(INTEL_ADSP_IPC_HOST_DEV,
327+
&sof_ipc_ept, &sof_ipc_ept_cfg);
328+
if (ret < 0)
329+
return ret;
330+
331+
#if defined(CONFIG_PM) && defined(CONFIG_INTEL_ADSP_IPC)
306332
intel_adsp_ipc_set_suspend_handler(INTEL_ADSP_IPC_HOST_DEV,
307333
ipc_device_suspend_handler, ipc);
308334
intel_adsp_ipc_set_resume_handler(INTEL_ADSP_IPC_HOST_DEV,
@@ -312,6 +338,7 @@ int platform_ipc_init(struct ipc *ipc)
312338
return 0;
313339
}
314340

341+
#ifdef CONFIG_INTEL_ADSP_IPC
315342
static bool ipc_wait_complete(const struct device *dev, void *arg)
316343
{
317344
k_sem_give(arg);
@@ -331,3 +358,4 @@ void ipc_platform_wait_ack(struct ipc *ipc)
331358

332359
intel_adsp_ipc_set_done_handler(INTEL_ADSP_IPC_HOST_DEV, NULL, NULL);
333360
}
361+
#endif /* CONFIG_INTEL_ADSP_IPC */

0 commit comments

Comments
 (0)