1 /*
2  * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <openamp/virtio_ring.h>
8 #include <openamp/rpmsg_virtio.h>
9 
10 #include <zephyr/ipc/ipc_static_vrings.h>
11 
12 /*
13  * Endpoint registration flow:
14  *
15  *	>>> Case #1: Endpoint registered on HOST first <<<
16  *
17  *  [B] backend
18  *  [O] OpenAMP
19  *
20  * REMOTE				HOST
21  * -----------------------------------------------------------------
22  *					[B] register_ept **
23  * [B] register_ept **
24  * [B] ipc_rpmsg_register_ept
25  * [B] rpmsg_create_ept
26  * [O] rpmsg_send_ns_message
27  * [O] virtqueue_kick
28  * [O] virtio_notify_cb
29  * [B] mbox_send
30  *					[B] mbox_callback
31  *					[B] mbox_callback_process
32  *					[B] virtqueue_notification
33  *					[O] rpmsg_virtio_rx_callback
34  *					[B] ns_bind_cb
35  *					[B] rpmsg_create_ept
36  *					[B] bound_cb
37  *					[B] rpmsg_send
38  *					[B] virtio_notify_cb
39  *					[B] mbox_send
40  * [B] mbox_callback
41  * [B] mbox_callback_process
42  * [B] virtqueue_notification
43  * [O] rpmsg_virtio_rx_callback
44  * [O] ept_cb
45  * [B] bound_cb
46  *
47  *	>>> Case #2: Endpoint registered on REMOTE first <<<
48  *
49  *  [B] backend
50  *  [O] OpenAMP
51  *
52  * REMOTE				HOST
53  * -----------------------------------------------------------------
54  * [B] register_ept **
55  * [B] ipc_rpmsg_register_ept
56  * [B] rpmsg_create_ept
57  * [O] rpmsg_send_ns_message
58  * [O] virtqueue_kick
59  * [O] virtio_notify_cb
60  * [O] mbox_send
61  *					[B] mbox_callback
62  *					[B] mbox_callback_process
63  *					[B] virtqueue_notification
64  *					[O] rpmsg_virtio_rx_callback
65  *					[B] ns_bind_cb
66  *
67  *					[B] register_ept **
68  *					[B] rpmsg_create_ept
69  *					[B] bound_cb
70  *					[B] rpmsg_send
71  *					[B] virtio_notify_cb
72  *					[B] mbox_send
73  * [B] mbox_callback
74  * [B] mbox_callback_process
75  * [B] virtqueue_notification
76  * [O] rpmsg_virtio_rx_callback
77  * [O] ept_cb
78  * [B] bound_cb
79  *
80  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
81  *
82  * Endpoint registration flow (with focus on backend):
83  *
84  *	>>> Case #1: Endpoint registered on HOST first <<<
85  *
86  * REMOTE				HOST
87  * -----------------------------------------------------------------
88  *					register_ept()
89  *					register_ept_on_host()
90  *					get_ept() returns NULL
91  *					name is cached in rpmsg_ept->name
92  * register_ept()
93  * register_ept_on_remote()
94  * ipc_rpmsg_register_ept()
95  *					ns_bind_cb()
96  *					get_ept() returns endpoint with cached name
97  *					advertise_ept()
98  *					rpmsg_create_ept()
99  *					bound_cb()
100  *					rpmsg_send()
101  * mbox_callback()
102  * mbox_callback_process()
103  * virtqueue_notification()
104  * ept_cb()
105  * bound_cb()
106  *
107  *	>>> Case #2: Endpoint registered on REMOTE first <<<
108  *
109  * REMOTE				HOST
110  * -----------------------------------------------------------------
111  * register_ept()
112  * register_ept_on_remote()
113  * ipc_rpmsg_register_ept()
114  *					ns_bind_cb()
115  *					get_ept() return NULL
116  *					name is cached in rpmsg_ept->name
117  *					...
118  *					register_ept()
119  *					register_ept_on_host()
120  *					get_ept() returns endpoint with cached name
121  *					advertise_ept()
122  *					rpmsg_create_ept()
123  *					bound_cb()
124  *					rpmsg-send()
125  * mbox_callback()
126  * mbox_callback_process()
127  * virtqueue_notification()
128  * ept_cb()
129  * bound_cb()
130  *
131  */
132 
133 /*
134  * Size of the status region (possibly a multiple of the cache line size).
135  */
136 #define VDEV_STATUS_SIZE	CONFIG_IPC_SERVICE_STATIC_VRINGS_MEM_ALIGNMENT
137 
138 #define VIRTQUEUE_ID_HOST	(0)
139 #define VIRTQUEUE_ID_REMOTE	(1)
140 
141 #define ROLE_HOST		VIRTIO_DEV_DRIVER
142 #define ROLE_REMOTE		VIRTIO_DEV_DEVICE
143 
vq_ring_size(unsigned int num,unsigned int buf_size)144 static inline size_t vq_ring_size(unsigned int num, unsigned int buf_size)
145 {
146 	return ROUND_UP((buf_size * num), MEM_ALIGNMENT);
147 }
148 
shm_size(unsigned int num,unsigned int buf_size)149 static inline size_t shm_size(unsigned int num, unsigned int buf_size)
150 {
151 	return (VRING_COUNT * (vq_ring_size(num, buf_size) +
152 		ROUND_UP(vring_size(num, MEM_ALIGNMENT), MEM_ALIGNMENT)));
153 }
154 
optimal_num_desc(size_t mem_size,unsigned int buf_size)155 static inline unsigned int optimal_num_desc(size_t mem_size, unsigned int buf_size)
156 {
157 	size_t available;
158 	unsigned int num_desc = 1;
159 
160 	available = mem_size - VDEV_STATUS_SIZE;
161 
162 	while (available > shm_size(num_desc, buf_size)) {
163 		num_desc++;
164 	}
165 
166 	/* if num_desc == 1 there is not enough memory */
167 	return (--num_desc == 0) ? 0 : (1 << LOG2(num_desc));
168 }
169