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