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