1 /*
2 * Copyright (c) 2020-2021, Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ipc/rpmsg_service.h>
8
9 #include "rpmsg_backend.h"
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/init.h>
13 #include <zephyr/logging/log.h>
14
15 #include <openamp/open_amp.h>
16
17
18 #define LOG_MODULE_NAME rpmsg_service
19 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_RPMSG_SERVICE_LOG_LEVEL);
20
21 #define MASTER IS_ENABLED(CONFIG_RPMSG_SERVICE_MODE_MASTER)
22
23 static struct virtio_device vdev;
24 static struct rpmsg_virtio_device rvdev;
25 static struct metal_io_region *io;
26 static bool ep_crt_started;
27
28 #if MASTER
29 static struct rpmsg_virtio_shm_pool shpool;
30 #endif
31
32 static struct {
33 const char *name;
34 rpmsg_ept_cb cb;
35 struct rpmsg_endpoint ep;
36 volatile bool bound;
37 } endpoints[CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS];
38
rpmsg_service_unbind(struct rpmsg_endpoint * ep)39 static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
40 {
41 rpmsg_destroy_ept(ep);
42 }
43
44 #if MASTER
45
ns_bind_cb(struct rpmsg_device * rdev,const char * name,uint32_t dest)46 static void ns_bind_cb(struct rpmsg_device *rdev,
47 const char *name,
48 uint32_t dest)
49 {
50 int err;
51
52 for (int i = 0; i < CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS; ++i) {
53 if (strcmp(name, endpoints[i].name) == 0) {
54 err = rpmsg_create_ept(&endpoints[i].ep,
55 rdev,
56 name,
57 RPMSG_ADDR_ANY,
58 dest,
59 endpoints[i].cb,
60 rpmsg_service_unbind);
61
62 if (err != 0) {
63 LOG_ERR("Creating remote endpoint %s"
64 " failed wirh error %d", name, err);
65 } else {
66 endpoints[i].bound = true;
67 }
68
69 return;
70 }
71 }
72
73 LOG_ERR("Remote endpoint %s not registered locally", name);
74 }
75
76 #endif
77
rpmsg_service_init(void)78 static int rpmsg_service_init(void)
79 {
80 int32_t err;
81
82 LOG_DBG("RPMsg service initialization start");
83
84 err = rpmsg_backend_init(&io, &vdev);
85 if (err) {
86 LOG_ERR("RPMsg backend init failed with error %d", err);
87 return err;
88 }
89
90 #if MASTER
91 rpmsg_virtio_init_shm_pool(&shpool, (void *)SHM_START_ADDR, SHM_SIZE);
92 err = rpmsg_init_vdev(&rvdev, &vdev, ns_bind_cb, io, &shpool);
93 #else
94 err = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL);
95 #endif
96
97 if (err) {
98 LOG_ERR("rpmsg_init_vdev failed %d", err);
99 return err;
100 }
101
102 ep_crt_started = true;
103
104 #if !MASTER
105 struct rpmsg_device *rdev;
106
107 rdev = rpmsg_virtio_get_rpmsg_device(&rvdev);
108
109 for (int i = 0; i < CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS; ++i) {
110 if (endpoints[i].name) {
111 err = rpmsg_create_ept(&endpoints[i].ep,
112 rdev,
113 endpoints[i].name,
114 RPMSG_ADDR_ANY,
115 RPMSG_ADDR_ANY,
116 endpoints[i].cb,
117 rpmsg_service_unbind);
118
119 if (err) {
120 LOG_ERR("rpmsg_create_ept failed %d", err);
121 return err;
122 }
123 }
124 }
125 #endif
126
127 LOG_DBG("RPMsg service initialized");
128
129 return 0;
130 }
131
rpmsg_service_register_endpoint(const char * name,rpmsg_ept_cb cb)132 int rpmsg_service_register_endpoint(const char *name, rpmsg_ept_cb cb)
133 {
134 if (ep_crt_started) {
135 return -EINPROGRESS;
136 }
137
138 for (int i = 0; i < CONFIG_RPMSG_SERVICE_NUM_ENDPOINTS; ++i) {
139 if (!endpoints[i].name) {
140 endpoints[i].name = name;
141 endpoints[i].cb = cb;
142
143 return i;
144 }
145 }
146
147 LOG_ERR("No free slots to register endpoint %s", name);
148
149 return -ENOMEM;
150 }
151
rpmsg_service_endpoint_is_bound(int endpoint_id)152 bool rpmsg_service_endpoint_is_bound(int endpoint_id)
153 {
154 return endpoints[endpoint_id].bound;
155 }
156
rpmsg_service_send(int endpoint_id,const void * data,size_t len)157 int rpmsg_service_send(int endpoint_id, const void *data, size_t len)
158 {
159 return rpmsg_send(&endpoints[endpoint_id].ep, data, len);
160 }
161
162 SYS_INIT(rpmsg_service_init, POST_KERNEL, CONFIG_RPMSG_SERVICE_INIT_PRIORITY);
163