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
ivshmem_ipm_send(const struct device * dev,int wait,uint32_t id,const void * data,int size)68 static int ivshmem_ipm_send(const struct device *dev, int wait, uint32_t id,
69 const void *data, int size)
70 {
71 ARG_UNUSED(wait);
72 ARG_UNUSED(data);
73 ARG_UNUSED(size);
74
75 struct ivshmem_ipm_config *dev_cfg = (struct ivshmem_ipm_config *)dev->config;
76
77 LOG_DBG("sending notification to the peer id 0x%x\n", id);
78 return ivshmem_int_peer(dev_cfg->ivshmem_dev, id, 0);
79 }
80
ivshmem_ipm_register_callback(const struct device * dev,ipm_callback_t cb,void * user_data)81 static void ivshmem_ipm_register_callback(const struct device *dev,
82 ipm_callback_t cb,
83 void *user_data)
84 {
85 struct ivshmem_ipm_data *dev_data = (struct ivshmem_ipm_data *)dev->data;
86
87 dev_data->cb = cb;
88 dev_data->user_data = user_data;
89 }
90
ivshmem_ipm_set_enabled(const struct device * dev,int enable)91 static int ivshmem_ipm_set_enabled(const struct device *dev, int enable)
92 {
93 /* some subsystems needs this minimal function just return success here*/
94 ARG_UNUSED(dev);
95 ARG_UNUSED(enable);
96
97 return 0;
98 }
99
ivshmem_ipm_init(const struct device * dev)100 static int ivshmem_ipm_init(const struct device *dev)
101 {
102 k_thread_create(&ivshmem_ev_loop_thread,
103 ivshmem_ev_loop_stack,
104 CONFIG_IPM_IVSHMEM_EVENT_LOOP_STACK_SIZE,
105 (k_thread_entry_t)ivshmem_ipm_event_loop_thread,
106 (void *)dev, NULL, NULL,
107 CONFIG_IPM_IVSHMEM_EVENT_LOOP_PRIO,
108 0, K_NO_WAIT);
109
110 return 0;
111 }
112
113 static const struct ipm_driver_api ivshmem_ipm_driver_api = {
114 .send = ivshmem_ipm_send,
115 .register_callback = ivshmem_ipm_register_callback,
116 .set_enabled = ivshmem_ipm_set_enabled
117 };
118
119 #define IPM_IVSHMEM_INIT(inst) \
120 static const struct ivshmem_ipm_config ivshmem_ipm_cfg_##inst = { \
121 .ivshmem_dev = \
122 DEVICE_DT_GET(DT_INST_PHANDLE(inst, ivshmem))\
123 }; \
124 static struct ivshmem_ipm_data ivshmem_ipm_data_##inst = { \
125 .cb = NULL, \
126 .user_data = NULL, \
127 }; \
128 DEVICE_DT_INST_DEFINE(inst, \
129 ivshmem_ipm_init, \
130 NULL, \
131 &ivshmem_ipm_data_##inst, &ivshmem_ipm_cfg_##inst, \
132 POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY, \
133 &ivshmem_ipm_driver_api); \
134
135 DT_INST_FOREACH_STATUS_OKAY(IPM_IVSHMEM_INIT);
136