Skip to content

Commit 77e3aa8

Browse files
committed
tests: ipc: add tests for IPC message service
This adds a few basic tests for the IPC message service. Signed-off-by: Daniel Leung <daniel.leung@intel.com>
1 parent 226be91 commit 77e3aa8

File tree

7 files changed

+356
-0
lines changed

7 files changed

+356
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Copyright 2021 Google LLC
3+
# Copyright 2025 Intel Corporation
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
#
7+
8+
cmake_minimum_required(VERSION 3.20.0)
9+
10+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
11+
project(ipc_msg_service)
12+
13+
FILE(GLOB app_sources src/*.c)
14+
target_sources(app PRIVATE ${app_sources})
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2021 Carlo Caione <ccaione@baylibre.com>
3+
* Copyright 2025 Intel Corporation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
/ {
9+
ipc10: ipc10 {
10+
compatible = "ipc-msg-service-backend";
11+
offset = <10>;
12+
status = "okay";
13+
};
14+
15+
ipc20: ipc20 {
16+
compatible = "ipc-msg-service-backend";
17+
offset = <20>;
18+
status = "okay";
19+
};
20+
};
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3+
# Copyright (c) 2025 Intel Corporation
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
#
7+
8+
description: Backend binding to test the IPC message service
9+
10+
compatible: "ipc-msg-service-backend"
11+
12+
properties:
13+
offset:
14+
type: int
15+
required: true
16+
description: offset to add
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# Copyright 2021 Carlo Caione <ccaione@baylibre.com>
3+
# Copyright 2025 Intel Corporation
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
#
7+
8+
CONFIG_ZTEST=y
9+
CONFIG_IPC_MSG_SERVICE=y
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (c) 2021, Carlo Caione <ccaione@baylibre.com>
3+
* Copyright (c) 2025 Intel Corporation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*
7+
* Simple backend that adds an offset (defined into the DT) to whatever it is
8+
* passed in input as IPC message.
9+
*/
10+
11+
#include <zephyr/ipc/ipc_msg_service_backend.h>
12+
13+
#include <zephyr/device.h>
14+
#include <zephyr/kernel.h>
15+
#include <zephyr/logging/log.h>
16+
#include <zephyr/sys/util_macro.h>
17+
18+
#define DT_DRV_COMPAT ipc_msg_service_backend
19+
20+
struct backend_data_t {
21+
bool endpoint_registered;
22+
const struct ipc_msg_ept_cfg *cfg;
23+
};
24+
25+
struct backend_config_t {
26+
unsigned int offset;
27+
};
28+
29+
static int send(const struct device *instance, void *token, uint8_t msg_type, const void *msg_data)
30+
{
31+
const struct backend_config_t *dev_config;
32+
struct backend_data_t *dev_data;
33+
const struct ipc_msg_type_cmd *msg;
34+
struct ipc_msg_type_cmd cb_msg;
35+
int ret;
36+
37+
if (msg_type != IPC_MSG_TYPE_CMD) {
38+
return -ENOTSUP;
39+
}
40+
41+
dev_config = instance->config;
42+
dev_data = instance->data;
43+
msg = (const struct ipc_msg_type_cmd *)msg_data;
44+
45+
cb_msg.cmd = msg->cmd + dev_config->offset;
46+
47+
ret = dev_data->cfg->cb.event(IPC_MSG_EVT_REMOTE_DONE, NULL, dev_data->cfg->priv);
48+
ARG_UNUSED(ret);
49+
50+
ret = dev_data->cfg->cb.received(msg_type, &cb_msg, dev_data->cfg->priv);
51+
ARG_UNUSED(ret);
52+
53+
return 0;
54+
}
55+
56+
static int query(const struct device *instance, void *token, uint8_t query_type,
57+
const void *query_data, void *query_response)
58+
{
59+
struct backend_data_t *dev_data = instance->data;
60+
int ret;
61+
62+
ARG_UNUSED(query_data);
63+
ARG_UNUSED(query_response);
64+
65+
if (query_type == IPC_MSG_QUERY_IS_READY) {
66+
ret = dev_data->endpoint_registered ? 0 : -ENOENT;
67+
} else {
68+
ret = -ENOTSUP;
69+
}
70+
71+
return ret;
72+
}
73+
74+
static int register_ept(const struct device *instance, void **token,
75+
const struct ipc_msg_ept_cfg *cfg)
76+
{
77+
struct backend_data_t *data = instance->data;
78+
79+
data->cfg = cfg;
80+
data->endpoint_registered = true;
81+
82+
return 0;
83+
}
84+
85+
static int deregister_ept(const struct device *instance, void *token)
86+
{
87+
struct backend_data_t *data = instance->data;
88+
89+
data->cfg = NULL;
90+
data->endpoint_registered = false;
91+
92+
return 0;
93+
}
94+
95+
const static struct ipc_msg_service_backend backend_ops = {
96+
.query = query,
97+
.send = send,
98+
.register_endpoint = register_ept,
99+
.deregister_endpoint = deregister_ept,
100+
};
101+
102+
#define DEFINE_BACKEND_DEVICE(i) \
103+
static struct backend_config_t backend_config_##i = { \
104+
.offset = DT_INST_PROP(i, offset), \
105+
}; \
106+
\
107+
static struct backend_data_t backend_data_##i; \
108+
\
109+
DEVICE_DT_INST_DEFINE(i, NULL, NULL, &backend_data_##i, &backend_config_##i, POST_KERNEL, \
110+
CONFIG_IPC_MSG_SERVICE_REG_BACKEND_PRIORITY, &backend_ops);
111+
112+
DT_INST_FOREACH_STATUS_OKAY(DEFINE_BACKEND_DEVICE)
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Copyright 2021 Carlo Caione, <ccaione@baylibre.com>
3+
* Copyright 2025 Intel Corporation
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/device.h>
9+
#include <zephyr/devicetree.h>
10+
#include <zephyr/ztest.h>
11+
#include <zephyr/ipc/ipc_msg_service.h>
12+
13+
static K_SEM_DEFINE(evt_done_sem, 0, 1);
14+
15+
static int received_cb(uint8_t msg_type, const void *msg_data, void *priv)
16+
{
17+
uintptr_t expected = (uintptr_t)priv;
18+
const struct ipc_msg_type_cmd *msg = (const struct ipc_msg_type_cmd *)msg_data;
19+
20+
zassert_equal(msg_type, IPC_MSG_TYPE_CMD, "received incorrect type of message");
21+
22+
printk("<<< Received cmd: %d, expected: %ld\n", msg->cmd, expected);
23+
24+
zassert_equal(msg->cmd, expected, "msg doesn't match the expected value");
25+
26+
return 0;
27+
}
28+
29+
static int event_cb(uint8_t evt_type, const void *evt_data, void *priv)
30+
{
31+
ARG_UNUSED(evt_data);
32+
33+
zassert_equal(evt_type, IPC_MSG_EVT_REMOTE_DONE, "received incorrect event");
34+
35+
k_sem_give(&evt_done_sem);
36+
37+
return 0;
38+
}
39+
40+
static struct ipc_msg_ept_cfg ept_cfg = {
41+
.name = "test_ept",
42+
.cb = {
43+
.received = received_cb,
44+
.event = event_cb,
45+
},
46+
};
47+
48+
ZTEST(ipc_msg_service, test_ipc_msg_service_send)
49+
{
50+
const struct device *dev_10;
51+
const struct device *dev_20;
52+
struct ipc_msg_ept ept_10;
53+
struct ipc_msg_ept ept_20;
54+
struct ipc_msg_type_cmd msg;
55+
int ret;
56+
57+
dev_10 = DEVICE_DT_GET(DT_NODELABEL(ipc10));
58+
dev_20 = DEVICE_DT_GET(DT_NODELABEL(ipc20));
59+
60+
/*
61+
* We send 10 through the ipc10 instance so we expect 20 in the
62+
* receiving callback (10 + 10 == 20)
63+
*/
64+
msg.cmd = 10;
65+
printk(">>> Sending cmd %d\n", msg.cmd);
66+
67+
/* Save the expected result in priv */
68+
ept_cfg.priv = (void *)20;
69+
70+
ret = ipc_msg_service_register_endpoint(dev_10, &ept_10, &ept_cfg);
71+
zassert_ok(ret, "ipc_msg_service_register_endpoint() failed");
72+
73+
ret = ipc_msg_service_send(&ept_10, IPC_MSG_TYPE_CMD, (const void *)&msg);
74+
zassert_ok(ret, "ipc_msg_service_send() failed");
75+
76+
zassert_ok(k_sem_take(&evt_done_sem, K_MSEC(100)), "done event not received");
77+
78+
/*
79+
* We send 10 again this time through the ipc20 instance so we expect
80+
* 20 in the receiving callback (10 + 20 == 30)
81+
*/
82+
msg.cmd = 10;
83+
printk(">>> Sending cmd %d\n", msg.cmd);
84+
85+
/* Save the expected result in priv */
86+
ept_cfg.priv = (void *)30;
87+
88+
ret = ipc_msg_service_register_endpoint(dev_20, &ept_20, &ept_cfg);
89+
zassert_ok(ret, "ipc_msg_service_register_endpoint() failed");
90+
91+
ret = ipc_msg_service_send(&ept_20, IPC_MSG_TYPE_CMD, (const void *)&msg);
92+
zassert_ok(ret, "ipc_msg_service_send() failed");
93+
94+
zassert_ok(k_sem_take(&evt_done_sem, K_MSEC(100)), "done event not received");
95+
96+
/* Deregister the endpoint and ensure that we fail correctly. */
97+
ret = ipc_msg_service_deregister_endpoint(&ept_10);
98+
zassert_ok(ret, "ipc_msg_service_deregister_endpoint() failed");
99+
100+
ret = ipc_msg_service_deregister_endpoint(&ept_20);
101+
zassert_ok(ret, "ipc_msg_service_deregister_endpoint() failed");
102+
}
103+
104+
ZTEST(ipc_msg_service, test_ipc_msg_endpoint_not_registered)
105+
{
106+
const struct device *dev_10;
107+
struct ipc_msg_ept ept_10;
108+
int ret;
109+
110+
dev_10 = DEVICE_DT_GET(DT_NODELABEL(ipc10));
111+
112+
/* Register then de-register endpoint. */
113+
ret = ipc_msg_service_register_endpoint(dev_10, &ept_10, &ept_cfg);
114+
zassert_ok(ret, "ipc_msg_service_register_endpoint() failed");
115+
116+
ret = ipc_msg_service_deregister_endpoint(&ept_10);
117+
zassert_ok(ret, "ipc_msg_service_deregister_endpoint() failed");
118+
119+
/* Should fail as endpoint has already been de-registered. */
120+
ret = ipc_msg_service_send(&ept_10, IPC_MSG_TYPE_CMD, NULL);
121+
zassert_equal(ret, -ENOENT, "ipc_msg_service_send() should return -ENOENT");
122+
}
123+
124+
ZTEST(ipc_msg_service, test_ipc_msg_wrong_message_type)
125+
{
126+
const struct device *dev_10;
127+
struct ipc_msg_ept ept_10;
128+
struct ipc_msg_type_cmd msg = {.cmd = 10};
129+
int ret;
130+
131+
dev_10 = DEVICE_DT_GET(DT_NODELABEL(ipc10));
132+
133+
ret = ipc_msg_service_register_endpoint(dev_10, &ept_10, &ept_cfg);
134+
zassert_ok(ret, "ipc_msg_service_register_endpoint() failed");
135+
136+
/* IPC_MSG_TYPE_COMMON_MAX is not a value type. */
137+
ret = ipc_msg_service_send(&ept_10, IPC_MSG_TYPE_COMMON_MAX, (const void *)&msg);
138+
zassert_equal(ret, -ENOTSUP, "ipc_msg_service_send() should return -ENOTSUP");
139+
140+
zassert_equal(k_sem_take(&evt_done_sem, K_MSEC(100)), -EAGAIN,
141+
"done event received but should not");
142+
143+
ret = ipc_msg_service_deregister_endpoint(&ept_10);
144+
zassert_ok(ret, "ipc_msg_service_deregister_endpoint() failed");
145+
}
146+
147+
ZTEST(ipc_msg_service, test_ipc_msg_endpoint_query)
148+
{
149+
const struct device *dev_10;
150+
struct ipc_msg_ept ept_10;
151+
int ret;
152+
153+
dev_10 = DEVICE_DT_GET(DT_NODELABEL(ipc10));
154+
155+
/* Since endpointe has never registered, API pointer is not valid, hence -EIO. */
156+
ret = ipc_msg_service_query(&ept_10, IPC_MSG_QUERY_IS_READY, NULL, NULL);
157+
zassert_equal(ret, -EIO, "ipc_msg_service_query() should return -EIO");
158+
159+
ret = ipc_msg_service_register_endpoint(dev_10, &ept_10, &ept_cfg);
160+
zassert_ok(ret, "ipc_msg_service_register_endpoint() failed");
161+
162+
ret = ipc_msg_service_query(&ept_10, IPC_MSG_QUERY_IS_READY, NULL, NULL);
163+
zassert_equal(ret, 0, "ipc_msg_service_query() should return 0");
164+
165+
ret = ipc_msg_service_deregister_endpoint(&ept_10);
166+
zassert_ok(ret, "ipc_msg_service_deregister_endpoint() failed");
167+
168+
/* Now this will -ENOENT as API pointer has been set above. */
169+
ret = ipc_msg_service_query(&ept_10, IPC_MSG_QUERY_IS_READY, NULL, NULL);
170+
zassert_equal(ret, -ENOENT, "ipc_msg_service_query() should return -ENOENT");
171+
}
172+
173+
ZTEST_SUITE(ipc_msg_service, NULL, NULL, NULL, NULL, NULL);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#
2+
# Copyright 2021 Carlo Caione 2021 <ccaione@baylibre.com>
3+
# Copyright 2025 Intel Corporation
4+
#
5+
# SPDX-License-Identifier: Apache-2.0
6+
#
7+
8+
tests:
9+
ipc.ipc_msg_service:
10+
tags: ipc_msg_service
11+
harness: ztest
12+
platform_allow: qemu_cortex_a53

0 commit comments

Comments
 (0)