1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_DRIVERS_VIRTUALIZATION_IVSHMEM_H_
8 #define ZEPHYR_INCLUDE_DRIVERS_VIRTUALIZATION_IVSHMEM_H_
9 
10 /**
11  * @brief Inter-VM Shared Memory (ivshmem) reference API
12  * @defgroup ivshmem Inter-VM Shared Memory (ivshmem) reference API
13  * @ingroup io_interfaces
14  * @{
15  */
16 
17 #include <zephyr/types.h>
18 #include <stddef.h>
19 #include <zephyr/device.h>
20 #include <zephyr/kernel.h>
21 
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25 
26 #define IVSHMEM_V2_PROTO_UNDEFINED	0x0000
27 #define IVSHMEM_V2_PROTO_NET		0x0001
28 
29 typedef size_t (*ivshmem_get_mem_f)(const struct device *dev,
30 				    uintptr_t *memmap);
31 
32 typedef uint32_t (*ivshmem_get_id_f)(const struct device *dev);
33 
34 typedef uint16_t (*ivshmem_get_vectors_f)(const struct device *dev);
35 
36 typedef int (*ivshmem_int_peer_f)(const struct device *dev,
37 				  uint32_t peer_id, uint16_t vector);
38 
39 typedef int (*ivshmem_register_handler_f)(const struct device *dev,
40 					  struct k_poll_signal *signal,
41 					  uint16_t vector);
42 
43 #ifdef CONFIG_IVSHMEM_V2
44 
45 typedef size_t (*ivshmem_get_rw_mem_section_f)(const struct device *dev,
46 					       uintptr_t *memmap);
47 
48 typedef size_t (*ivshmem_get_output_mem_section_f)(const struct device *dev,
49 						   uint32_t peer_id,
50 						   uintptr_t *memmap);
51 
52 typedef uint32_t (*ivshmem_get_state_f)(const struct device *dev,
53 					uint32_t peer_id);
54 
55 typedef int (*ivshmem_set_state_f)(const struct device *dev,
56 				   uint32_t state);
57 
58 typedef uint32_t (*ivshmem_get_max_peers_f)(const struct device *dev);
59 
60 typedef uint16_t (*ivshmem_get_protocol_f)(const struct device *dev);
61 
62 typedef int (*ivshmem_enable_interrupts_f)(const struct device *dev,
63 					   bool enable);
64 
65 #endif /* CONFIG_IVSHMEM_V2 */
66 
67 __subsystem struct ivshmem_driver_api {
68 	ivshmem_get_mem_f get_mem;
69 	ivshmem_get_id_f get_id;
70 	ivshmem_get_vectors_f get_vectors;
71 	ivshmem_int_peer_f int_peer;
72 	ivshmem_register_handler_f register_handler;
73 #ifdef CONFIG_IVSHMEM_V2
74 	ivshmem_get_rw_mem_section_f get_rw_mem_section;
75 	ivshmem_get_output_mem_section_f get_output_mem_section;
76 	ivshmem_get_state_f get_state;
77 	ivshmem_set_state_f set_state;
78 	ivshmem_get_max_peers_f get_max_peers;
79 	ivshmem_get_protocol_f get_protocol;
80 	ivshmem_enable_interrupts_f enable_interrupts;
81 #endif
82 };
83 
84 /**
85  * @brief Get the inter-VM shared memory
86  *
87  * Note: This API is not supported for ivshmem-v2, as
88  * the R/W and R/O areas may not be mapped contiguously.
89  * For ivshmem-v2, use the ivshmem_get_rw_mem_section,
90  * ivshmem_get_output_mem_section and ivshmem_get_state
91  * APIs to access the shared memory.
92  *
93  * @param dev Pointer to the device structure for the driver instance
94  * @param memmap A pointer to fill in with the memory address
95  *
96  * @return the size of the memory mapped, or 0
97  */
98 __syscall size_t ivshmem_get_mem(const struct device *dev,
99 				 uintptr_t *memmap);
100 
z_impl_ivshmem_get_mem(const struct device * dev,uintptr_t * memmap)101 static inline size_t z_impl_ivshmem_get_mem(const struct device *dev,
102 					    uintptr_t *memmap)
103 {
104 	const struct ivshmem_driver_api *api =
105 		(const struct ivshmem_driver_api *)dev->api;
106 
107 	return api->get_mem(dev, memmap);
108 }
109 
110 /**
111  * @brief Get our VM ID
112  *
113  * @param dev Pointer to the device structure for the driver instance
114  *
115  * @return our VM ID or 0 if we are not running on doorbell version
116  */
117 __syscall uint32_t ivshmem_get_id(const struct device *dev);
118 
z_impl_ivshmem_get_id(const struct device * dev)119 static inline uint32_t z_impl_ivshmem_get_id(const struct device *dev)
120 {
121 	const struct ivshmem_driver_api *api =
122 		(const struct ivshmem_driver_api *)dev->api;
123 
124 	return api->get_id(dev);
125 }
126 
127 /**
128  * @brief Get the number of interrupt vectors we can use
129  *
130  * @param dev Pointer to the device structure for the driver instance
131  *
132  * @return the number of available interrupt vectors
133  */
134 __syscall uint16_t ivshmem_get_vectors(const struct device *dev);
135 
z_impl_ivshmem_get_vectors(const struct device * dev)136 static inline uint16_t z_impl_ivshmem_get_vectors(const struct device *dev)
137 {
138 	const struct ivshmem_driver_api *api =
139 		(const struct ivshmem_driver_api *)dev->api;
140 
141 	return api->get_vectors(dev);
142 }
143 
144 /**
145  * @brief Interrupt another VM
146  *
147  * @param dev Pointer to the device structure for the driver instance
148  * @param peer_id The VM ID to interrupt
149  * @param vector The interrupt vector to use
150  *
151  * @return 0 on success, a negative errno otherwise
152  */
153 __syscall int ivshmem_int_peer(const struct device *dev,
154 			       uint32_t peer_id, uint16_t vector);
155 
z_impl_ivshmem_int_peer(const struct device * dev,uint32_t peer_id,uint16_t vector)156 static inline int z_impl_ivshmem_int_peer(const struct device *dev,
157 					  uint32_t peer_id, uint16_t vector)
158 {
159 	const struct ivshmem_driver_api *api =
160 		(const struct ivshmem_driver_api *)dev->api;
161 
162 	return api->int_peer(dev, peer_id, vector);
163 }
164 
165 /**
166  * @brief Register a vector notification (interrupt) handler
167  *
168  * @param dev Pointer to the device structure for the driver instance
169  * @param signal A pointer to a valid and ready to be signaled
170  *        struct k_poll_signal. Or NULL to unregister any handler
171  *        registered for the given vector.
172  * @param vector The interrupt vector to get notification from
173  *
174  * Note: The returned status, if positive, to a raised signal is the vector
175  *       that generated the signal. This lets the possibility to the user
176  *       to have one signal for all vectors, or one per-vector.
177  *
178  * @return 0 on success, a negative errno otherwise
179  */
180 __syscall int ivshmem_register_handler(const struct device *dev,
181 				       struct k_poll_signal *signal,
182 				       uint16_t vector);
183 
z_impl_ivshmem_register_handler(const struct device * dev,struct k_poll_signal * signal,uint16_t vector)184 static inline int z_impl_ivshmem_register_handler(const struct device *dev,
185 						  struct k_poll_signal *signal,
186 						  uint16_t vector)
187 {
188 	const struct ivshmem_driver_api *api =
189 		(const struct ivshmem_driver_api *)dev->api;
190 
191 	return api->register_handler(dev, signal, vector);
192 }
193 
194 #ifdef CONFIG_IVSHMEM_V2
195 
196 /**
197  * @brief Get the ivshmem read/write section (ivshmem-v2 only)
198  *
199  * @param dev Pointer to the device structure for the driver instance
200  * @param memmap A pointer to fill in with the memory address
201  *
202  * @return the size of the memory mapped, or 0
203  */
204 __syscall size_t ivshmem_get_rw_mem_section(const struct device *dev,
205 					    uintptr_t *memmap);
206 
z_impl_ivshmem_get_rw_mem_section(const struct device * dev,uintptr_t * memmap)207 static inline size_t z_impl_ivshmem_get_rw_mem_section(const struct device *dev,
208 						       uintptr_t *memmap)
209 {
210 	const struct ivshmem_driver_api *api =
211 		(const struct ivshmem_driver_api *)dev->api;
212 
213 	return api->get_rw_mem_section(dev, memmap);
214 }
215 
216 /**
217  * @brief Get the ivshmem output section for a peer (ivshmem-v2 only)
218  *
219  * @param dev Pointer to the device structure for the driver instance
220  * @param peer_id The VM ID whose output memory section to get
221  * @param memmap A pointer to fill in with the memory address
222  *
223  * @return the size of the memory mapped, or 0
224  */
225 __syscall size_t ivshmem_get_output_mem_section(const struct device *dev,
226 						uint32_t peer_id,
227 						uintptr_t *memmap);
228 
z_impl_ivshmem_get_output_mem_section(const struct device * dev,uint32_t peer_id,uintptr_t * memmap)229 static inline size_t z_impl_ivshmem_get_output_mem_section(const struct device *dev,
230 							   uint32_t peer_id,
231 							   uintptr_t *memmap)
232 {
233 	const struct ivshmem_driver_api *api =
234 		(const struct ivshmem_driver_api *)dev->api;
235 
236 	return api->get_output_mem_section(dev, peer_id, memmap);
237 }
238 
239 /**
240  * @brief Get the state value of a peer (ivshmem-v2 only)
241  *
242  * @param dev Pointer to the device structure for the driver instance
243  * @param peer_id The VM ID whose state to get
244  *
245  * @return the state value of the peer
246  */
247 __syscall uint32_t ivshmem_get_state(const struct device *dev,
248 				     uint32_t peer_id);
249 
z_impl_ivshmem_get_state(const struct device * dev,uint32_t peer_id)250 static inline uint32_t z_impl_ivshmem_get_state(const struct device *dev,
251 						uint32_t peer_id)
252 {
253 	const struct ivshmem_driver_api *api =
254 		(const struct ivshmem_driver_api *)dev->api;
255 
256 	return api->get_state(dev, peer_id);
257 }
258 
259 /**
260  * @brief Set our state (ivshmem-v2 only)
261  *
262  * @param dev Pointer to the device structure for the driver instance
263  * @param state The state value to set
264  *
265  * @return 0 on success, a negative errno otherwise
266  */
267 __syscall int ivshmem_set_state(const struct device *dev,
268 				uint32_t state);
269 
z_impl_ivshmem_set_state(const struct device * dev,uint32_t state)270 static inline int z_impl_ivshmem_set_state(const struct device *dev,
271 					   uint32_t state)
272 {
273 	const struct ivshmem_driver_api *api =
274 		(const struct ivshmem_driver_api *)dev->api;
275 
276 	return api->set_state(dev, state);
277 }
278 
279 /**
280  * @brief Get the maximum number of peers supported (ivshmem-v2 only)
281  *
282  * @param dev Pointer to the device structure for the driver instance
283  *
284  * @return the maximum number of peers supported, or 0
285  */
286 __syscall uint32_t ivshmem_get_max_peers(const struct device *dev);
287 
z_impl_ivshmem_get_max_peers(const struct device * dev)288 static inline uint32_t z_impl_ivshmem_get_max_peers(const struct device *dev)
289 {
290 	const struct ivshmem_driver_api *api =
291 		(const struct ivshmem_driver_api *)dev->api;
292 
293 	return api->get_max_peers(dev);
294 }
295 
296 /**
297  * @brief Get the protocol used by this ivshmem instance (ivshmem-v2 only)
298  *
299  * @param dev Pointer to the device structure for the driver instance
300  *
301  * @return the protocol
302  */
303 __syscall uint16_t ivshmem_get_protocol(const struct device *dev);
304 
z_impl_ivshmem_get_protocol(const struct device * dev)305 static inline uint16_t z_impl_ivshmem_get_protocol(const struct device *dev)
306 {
307 	const struct ivshmem_driver_api *api =
308 		(const struct ivshmem_driver_api *)dev->api;
309 
310 	return api->get_protocol(dev);
311 }
312 
313 /**
314  * @brief Set the interrupt enablement for our VM (ivshmem-v2 only)
315  *
316  * @param dev Pointer to the device structure for the driver instance
317  * @param enable True to enable interrupts, false to disable
318  *
319  * @return 0 on success, a negative errno otherwise
320  */
321 __syscall int ivshmem_enable_interrupts(const struct device *dev,
322 					bool enable);
323 
z_impl_ivshmem_enable_interrupts(const struct device * dev,bool enable)324 static inline int z_impl_ivshmem_enable_interrupts(const struct device *dev,
325 						   bool enable)
326 {
327 	const struct ivshmem_driver_api *api =
328 		(const struct ivshmem_driver_api *)dev->api;
329 
330 	return api->enable_interrupts(dev, enable);
331 }
332 
333 #endif /* CONFIG_IVSHMEM_V2 */
334 
335 #ifdef __cplusplus
336 }
337 #endif
338 
339 /**
340  * @}
341  */
342 
343 #include <zephyr/syscalls/ivshmem.h>
344 
345 #endif /* ZEPHYR_INCLUDE_DRIVERS_VIRTUALIZATION_IVSHMEM_H_ */
346