1 /*
2 * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/ipc/ipc_rpmsg.h>
9
rpmsg_service_unbind(struct rpmsg_endpoint * ep)10 static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
11 {
12 rpmsg_destroy_ept(ep);
13 }
14
ns_bind_cb(struct rpmsg_device * rdev,const char * name,uint32_t dest)15 static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
16 {
17 struct rpmsg_virtio_device *p_rvdev;
18 struct ipc_rpmsg_instance *instance;
19 struct ipc_rpmsg_ept *ept;
20 int err;
21
22 p_rvdev = CONTAINER_OF(rdev, struct rpmsg_virtio_device, rdev);
23 instance = CONTAINER_OF(p_rvdev->shpool, struct ipc_rpmsg_instance, shm_pool);
24
25 for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
26 ept = &instance->endpoint[i];
27
28 if (strcmp(name, ept->name) == 0) {
29 /*
30 * The destination address is 'dest' so ns_bind_cb() is
31 * *NOT* called on the REMOTE side. The bound_cb()
32 * function will eventually take care of notifying the
33 * REMOTE side if needed.
34 */
35 err = rpmsg_create_ept(&ept->ep, rdev, name, RPMSG_ADDR_ANY,
36 dest, instance->cb, rpmsg_service_unbind);
37 if (err != 0) {
38 return;
39 }
40
41 ept->bound = true;
42 if (instance->bound_cb) {
43 instance->bound_cb(ept);
44 }
45 }
46 }
47 }
48
ipc_rpmsg_register_ept(struct ipc_rpmsg_instance * instance,unsigned int role,struct ipc_rpmsg_ept * ept)49 int ipc_rpmsg_register_ept(struct ipc_rpmsg_instance *instance, unsigned int role,
50 struct ipc_rpmsg_ept *ept)
51 {
52 struct rpmsg_device *rdev;
53
54 if (!instance || !ept) {
55 return -EINVAL;
56 }
57
58 rdev = rpmsg_virtio_get_rpmsg_device(&instance->rvdev);
59
60 if (role == RPMSG_REMOTE) {
61 /*
62 * The destination address is RPMSG_ADDR_ANY, this will trigger
63 * the ns_bind_cb() callback function on the HOST side.
64 */
65 return rpmsg_create_ept(&ept->ep, rdev, ept->name, RPMSG_ADDR_ANY,
66 RPMSG_ADDR_ANY, instance->cb, rpmsg_service_unbind);
67 }
68
69 return RPMSG_SUCCESS;
70 }
71
ipc_rpmsg_init(struct ipc_rpmsg_instance * instance,unsigned int role,unsigned int buffer_size,struct metal_io_region * shm_io,struct virtio_device * vdev,void * shb,size_t size,rpmsg_ns_bind_cb p_bind_cb)72 int ipc_rpmsg_init(struct ipc_rpmsg_instance *instance,
73 unsigned int role,
74 unsigned int buffer_size,
75 struct metal_io_region *shm_io,
76 struct virtio_device *vdev,
77 void *shb, size_t size,
78 rpmsg_ns_bind_cb p_bind_cb)
79 {
80 rpmsg_ns_bind_cb bind_cb = p_bind_cb;
81
82 if (!instance || !shb) {
83 return -EINVAL;
84 }
85
86 if (p_bind_cb == NULL) {
87 bind_cb = ns_bind_cb;
88 }
89
90 if (role == RPMSG_HOST) {
91 struct rpmsg_virtio_config config = { 0 };
92
93 config.h2r_buf_size = (uint32_t) buffer_size;
94 config.r2h_buf_size = (uint32_t) buffer_size;
95
96 rpmsg_virtio_init_shm_pool(&instance->shm_pool, shb, size);
97
98 return rpmsg_init_vdev_with_config(&instance->rvdev, vdev, bind_cb,
99 shm_io, &instance->shm_pool,
100 &config);
101 } else {
102 return rpmsg_init_vdev(&instance->rvdev, vdev, bind_cb, shm_io, NULL);
103 }
104 }
105
ipc_rpmsg_deinit(struct ipc_rpmsg_instance * instance,unsigned int role)106 int ipc_rpmsg_deinit(struct ipc_rpmsg_instance *instance,
107 unsigned int role)
108 {
109 if (!instance) {
110 return -EINVAL;
111 }
112
113 rpmsg_deinit_vdev(&instance->rvdev);
114
115 if (role == RPMSG_HOST) {
116 memset(&instance->shm_pool, 0, sizeof(struct rpmsg_virtio_shm_pool));
117 }
118
119 return 0;
120 }
121