1 /*
2 * Copyright (c) 2023 Linaro.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT linaro_ivshmem_ipm
8
9 #include <stdint.h>
10 #include <string.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/ipm.h>
13 #include <zephyr/drivers/virtualization/ivshmem.h>
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(ipm_ivshmem, CONFIG_IPM_LOG_LEVEL);
16
17 K_THREAD_STACK_DEFINE(ivshmem_ev_loop_stack, CONFIG_IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE);
18 static struct k_thread ivshmem_ev_loop_thread;
19
20 struct ivshmem_ipm_data {
21 ipm_callback_t cb;
22 void *user_data;
23 };
24
25 struct ivshmem_ipm_config {
26 const struct device *ivshmem_dev;
27 };
28
ivshmem_ipm_event_loop_thread(void * arg,void * p2,void * p3)29 static void ivshmem_ipm_event_loop_thread(void *arg, void *p2, void *p3)
30 {
31 ARG_UNUSED(p2);
32 ARG_UNUSED(p3);
33
34 unsigned int poll_signaled;
35 int ivshmem_vector_rx;
36 struct k_poll_signal sig;
37 struct k_poll_event events[] = {
38 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL,
39 K_POLL_MODE_NOTIFY_ONLY,
40 &sig),
41 };
42
43 const struct device *dev = (const struct device *)arg;
44 struct ivshmem_ipm_data *dev_data = (struct ivshmem_ipm_data *)dev->data;
45 struct ivshmem_ipm_config *dev_cfg = (struct ivshmem_ipm_config *)dev->config;
46
47 k_poll_signal_init(&sig);
48 int ret = ivshmem_register_handler(dev_cfg->ivshmem_dev, &sig, 0);
49
50 if (ret < 0) {
51 LOG_ERR("registering handlers must be supported: %d\n", ret);
52 k_panic();
53 }
54
55 while (1) {
56 LOG_DBG("%s: waiting interrupt from client...\n", __func__);
57 ret = k_poll(events, ARRAY_SIZE(events), K_FOREVER);
58
59 k_poll_signal_check(&sig, &poll_signaled, &ivshmem_vector_rx);
60 /* get ready for next signal */
61 k_poll_signal_reset(&sig);
62
63 if (dev_data->cb) {
64 dev_data->cb(dev, dev_data->user_data, 0, NULL);
65 }
66 }
67 }
68
ivshmem_ipm_send(const struct device * dev,int wait,uint32_t id,const void * data,int size)69 static int ivshmem_ipm_send(const struct device *dev, int wait, uint32_t id,
70 const void *data, int size)
71 {
72 ARG_UNUSED(wait);
73 ARG_UNUSED(data);
74 ARG_UNUSED(size);
75
76 struct ivshmem_ipm_config *dev_cfg = (struct ivshmem_ipm_config *)dev->config;
77
78 LOG_DBG("sending notification to the peer id 0x%x\n", id);
79 return ivshmem_int_peer(dev_cfg->ivshmem_dev, id, 0);
80 }
81
ivshmem_ipm_register_callback(const struct device * dev,ipm_callback_t cb,void * user_data)82 static void ivshmem_ipm_register_callback(const struct device *dev,
83 ipm_callback_t cb,
84 void *user_data)
85 {
86 struct ivshmem_ipm_data *dev_data = (struct ivshmem_ipm_data *)dev->data;
87
88 dev_data->cb = cb;
89 dev_data->user_data = user_data;
90 }
91
ivshmem_ipm_set_enabled(const struct device * dev,int enable)92 static int ivshmem_ipm_set_enabled(const struct device *dev, int enable)
93 {
94 /* some subsystems needs this minimal function just return success here*/
95 ARG_UNUSED(dev);
96 ARG_UNUSED(enable);
97
98 return 0;
99 }
100
ivshmem_ipm_init(const struct device * dev)101 static int ivshmem_ipm_init(const struct device *dev)
102 {
103 k_thread_create(&ivshmem_ev_loop_thread,
104 ivshmem_ev_loop_stack,
105 CONFIG_IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE,
106 ivshmem_ipm_event_loop_thread,
107 (void *)dev, NULL, NULL,
108 CONFIG_IPM_IVSHMEM_EVENT_LOOP_PRIO,
109 0, K_NO_WAIT);
110
111 return 0;
112 }
113
114 static DEVICE_API(ipm, ivshmem_ipm_driver_api) = {
115 .send = ivshmem_ipm_send,
116 .register_callback = ivshmem_ipm_register_callback,
117 .set_enabled = ivshmem_ipm_set_enabled
118 };
119
120 #define IPM_IVSHMEM_INIT(inst) \
121 static const struct ivshmem_ipm_config ivshmem_ipm_cfg_##inst = { \
122 .ivshmem_dev = \
123 DEVICE_DT_GET(DT_INST_PHANDLE(inst, ivshmem))\
124 }; \
125 static struct ivshmem_ipm_data ivshmem_ipm_data_##inst = { \
126 .cb = NULL, \
127 .user_data = NULL, \
128 }; \
129 DEVICE_DT_INST_DEFINE(inst, \
130 ivshmem_ipm_init, \
131 NULL, \
132 &ivshmem_ipm_data_##inst, &ivshmem_ipm_cfg_##inst, \
133 POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, \
134 &ivshmem_ipm_driver_api); \
135
136 DT_INST_FOREACH_STATUS_OKAY(IPM_IVSHMEM_INIT);
137