1 /*
2  * rpmsg based on virtio
3  *
4  * Copyright (C) 2018 Linaro, Inc.
5  *
6  * All rights reserved.
7  * Copyright (c) 2016 Freescale Semiconductor, Inc. All rights reserved.
8  *
9  * SPDX-License-Identifier: BSD-3-Clause
10  */
11 
12 #ifndef _RPMSG_VIRTIO_H_
13 #define _RPMSG_VIRTIO_H_
14 
15 #include <metal/io.h>
16 #include <metal/mutex.h>
17 #include <metal/cache.h>
18 #include <openamp/rpmsg.h>
19 #include <openamp/virtio.h>
20 
21 #if defined __cplusplus
22 extern "C" {
23 #endif
24 
25 /* Configurable parameters */
26 #ifndef RPMSG_BUFFER_SIZE
27 #define RPMSG_BUFFER_SIZE	(512)
28 #endif
29 
30 /* The feature bitmap for virtio rpmsg */
31 #define VIRTIO_RPMSG_F_NS	0 /* RP supports name service notifications */
32 
33 #ifdef VIRTIO_CACHED_BUFFERS
34 #warning "VIRTIO_CACHED_BUFFERS is deprecated, please use VIRTIO_USE_DCACHE"
35 #endif
36 #if defined(VIRTIO_CACHED_BUFFERS) || defined(VIRTIO_USE_DCACHE)
37 #define BUFFER_FLUSH(x, s)		CACHE_FLUSH(x, s)
38 #define BUFFER_INVALIDATE(x, s)		CACHE_INVALIDATE(x, s)
39 #else
40 #define BUFFER_FLUSH(x, s)		do { } while (0)
41 #define BUFFER_INVALIDATE(x, s)		do { } while (0)
42 #endif /* VIRTIO_CACHED_BUFFERS || VIRTIO_USE_DCACHE */
43 
44 /* Callback handler for rpmsg virtio service */
45 typedef int (*rpmsg_virtio_notify_wait_cb)(struct rpmsg_device *rdev, uint32_t id);
46 
47 /** @brief Shared memory pool used for RPMsg buffers */
48 struct rpmsg_virtio_shm_pool {
49 	/** Base address of the memory pool */
50 	void *base;
51 
52 	/** Available memory size */
53 	size_t avail;
54 
55 	/** Total pool size */
56 	size_t size;
57 };
58 
59 /**
60  * @brief Configuration of RPMsg device based on virtio
61  *
62  * This structure is used by the RPMsg virtio host to configure the virtiio
63  * layer.
64  */
65 struct rpmsg_virtio_config {
66 	/** The size of the buffer used to send data from host to remote */
67 	uint32_t h2r_buf_size;
68 
69 	/** The size of the buffer used to send data from remote to host */
70 	uint32_t r2h_buf_size;
71 
72 	/** The flag for splitting shared memory pool to TX and RX */
73 	bool split_shpool;
74 };
75 
76 /** @brief Representation of a RPMsg device based on virtio */
77 struct rpmsg_virtio_device {
78 	/** RPMsg device */
79 	struct rpmsg_device rdev;
80 
81 	/** Structure containing virtio configuration */
82 	struct rpmsg_virtio_config config;
83 
84 	/** Pointer to the virtio device */
85 	struct virtio_device *vdev;
86 
87 	/** Pointer to receive virtqueue */
88 	struct virtqueue *rvq;
89 
90 	/** Pointer to send virtqueue */
91 	struct virtqueue *svq;
92 
93 	/** Pointer to the shared buffer I/O region */
94 	struct metal_io_region *shbuf_io;
95 
96 	/** Pointer to the shared buffers pool */
97 	struct rpmsg_virtio_shm_pool *shpool;
98 
99 	/**
100 	 * RPMsg buffer reclaimer that contains buffers released by the
101 	 * \ref rpmsg_virtio_release_tx_buffer function
102 	 */
103 	struct metal_list reclaimer;
104 
105 	/**
106 	 * Callback handler for rpmsg virtio service, called when service
107 	 * can't get tx buffer
108 	 */
109 	rpmsg_virtio_notify_wait_cb notify_wait_cb;
110 };
111 
112 #define RPMSG_REMOTE	VIRTIO_DEV_DEVICE
113 #define RPMSG_HOST	VIRTIO_DEV_DRIVER
114 
115 /**
116  * @brief Set the virtio callback to manage the wait for TX buffer availability.
117  *
118  * @param rvdev			Pointer to rpmsg virtio device.
119  * @param notify_wait_cb	Callback handler to wait buffer notification.
120  */
rpmsg_virtio_set_wait_cb(struct rpmsg_virtio_device * rvdev,rpmsg_virtio_notify_wait_cb notify_wait_cb)121 static inline void rpmsg_virtio_set_wait_cb(struct rpmsg_virtio_device *rvdev,
122 					    rpmsg_virtio_notify_wait_cb notify_wait_cb)
123 {
124 	rvdev->notify_wait_cb = notify_wait_cb;
125 }
126 
127 /**
128  * @brief Get rpmsg virtio device role.
129  *
130  * @param rvdev	Pointer to rpmsg virtio device.
131  *
132  * @return VIRTIO_DEV_DEVICE or VIRTIO_DEV_DRIVER
133  */
134 static inline unsigned int
rpmsg_virtio_get_role(struct rpmsg_virtio_device * rvdev)135 rpmsg_virtio_get_role(struct rpmsg_virtio_device *rvdev)
136 {
137 	return rvdev->vdev->role;
138 }
139 
140 /**
141  * @brief Set rpmsg virtio device status.
142  *
143  * Deprecated: Use virtio_set_status() instead
144  *
145  * @param rvdev		Pointer to rpmsg virtio device.
146  * @param status	Value to be set as rpmsg virtio device status.
147  */
148 __deprecated
rpmsg_virtio_set_status(struct rpmsg_virtio_device * rvdev,uint8_t status)149 static inline void rpmsg_virtio_set_status(struct rpmsg_virtio_device *rvdev,
150 					   uint8_t status)
151 {
152 	rvdev->vdev->func->set_status(rvdev->vdev, status);
153 }
154 
155 /**
156  * @brief Retrieve rpmsg virtio device status.
157  *
158  * Deprecated: Use virtio_get_status() instead
159  *
160  * @param rvdev	Pointer to rpmsg virtio device.
161  *
162  * @return The rpmsg virtio device status.
163  */
164 __deprecated
rpmsg_virtio_get_status(struct rpmsg_virtio_device * rvdev)165 static inline uint8_t rpmsg_virtio_get_status(struct rpmsg_virtio_device *rvdev)
166 {
167 	return rvdev->vdev->func->get_status(rvdev->vdev);
168 }
169 
170 /**
171  * @brief Get the rpmsg virtio device features.
172  *
173  * Deprecated: Use virtio_get_features() instead
174  *
175  * @param rvdev	Pointer to the rpmsg virtio device.
176  *
177  * @return The features supported by both the rpmsg driver and rpmsg device.
178  */
179 __deprecated
180 static inline uint32_t
rpmsg_virtio_get_features(struct rpmsg_virtio_device * rvdev)181 rpmsg_virtio_get_features(struct rpmsg_virtio_device *rvdev)
182 {
183 	return rvdev->vdev->func->get_features(rvdev->vdev);
184 }
185 
186 /**
187  * @brief Retrieve configuration data from the rpmsg virtio device.
188  *
189  * Deprecated: Use virtio_read_config() instead
190  *
191  * @param rvdev		Pointer to the rpmsg virtio device.
192  * @param offset	Offset of the data within the configuration area.
193  * @param dst		Address of the buffer that will hold the data.
194  * @param length	Length of the data to be retrieved.
195  */
196 __deprecated
197 static inline void
rpmsg_virtio_read_config(struct rpmsg_virtio_device * rvdev,uint32_t offset,void * dst,int length)198 rpmsg_virtio_read_config(struct rpmsg_virtio_device *rvdev,
199 			 uint32_t offset, void *dst, int length)
200 {
201 	rvdev->vdev->func->read_config(rvdev->vdev, offset, dst, length);
202 }
203 
204 /**
205  * @brief Write configuration data to the rpmsg virtio device.
206  *
207  * Deprecated: Use virtio_write_config() instead
208  *
209  * @param rvdev		Pointer to the rpmsg virtio device.
210  * @param offset	Offset of the data within the configuration area.
211  * @param src		Address of the buffer that holds the data to write.
212  * @param length	Length of the data to be written.
213  *
214  * @return 0 on success, otherwise error code.
215  */
216 __deprecated
217 static inline void
rpmsg_virtio_write_config(struct rpmsg_virtio_device * rvdev,uint32_t offset,void * src,int length)218 rpmsg_virtio_write_config(struct rpmsg_virtio_device *rvdev,
219 			 uint32_t offset, void *src, int length)
220 {
221 	rvdev->vdev->func->write_config(rvdev->vdev, offset, src, length);
222 }
223 
224 /**
225  * @brief Create the rpmsg virtio device virtqueue.
226  *
227  * Deprecated: Use virtio_create_virtqueues() instead
228  *
229  * @param rvdev		Pointer to the rpmsg virtio device.
230  * @param flags		Create flag.
231  * @param nvqs		The virtqueue number.
232  * @param names		Virtqueue names.
233  * @param callbacks	Virtqueue callback functions.
234  *
235  * @return 0 on success, otherwise error code.
236  */
237 __deprecated
238 static inline int
rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device * rvdev,int flags,unsigned int nvqs,const char * names[],vq_callback * callbacks)239 rpmsg_virtio_create_virtqueues(struct rpmsg_virtio_device *rvdev,
240 			       int flags, unsigned int nvqs,
241 			       const char *names[],
242 			       vq_callback *callbacks)
243 {
244 	return virtio_create_virtqueues(rvdev->vdev, flags, nvqs, names,
245 					callbacks, NULL);
246 }
247 
248 /**
249  * @brief Delete the virtqueues created in rpmsg_virtio_create_virtqueues()
250  *
251  * Deprecated: Use virtio_delete_virtqueues() instead
252  *
253  * @param rvdev	Pointer to the rpmsg virtio device
254  */
255 __deprecated
256 static inline void
rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device * rvdev)257 rpmsg_virtio_delete_virtqueues(struct rpmsg_virtio_device *rvdev)
258 {
259 	virtio_delete_virtqueues(rvdev->vdev);
260 }
261 
262 /**
263  * @brief Get rpmsg virtio buffer size
264  *
265  * @param rdev	Pointer to the rpmsg device
266  *
267  * @return Next available buffer size for text, negative value for failure
268  */
269 int rpmsg_virtio_get_tx_buffer_size(struct rpmsg_device *rdev);
270 
271 /**
272  * @brief  Get rpmsg virtio Rx buffer size
273  *
274  * @param rdev	Pointer to the rpmsg device
275  *
276  * @return Next available buffer size for text, negative value for failure
277  */
278 int rpmsg_virtio_get_rx_buffer_size(struct rpmsg_device *rdev);
279 
280 /**
281  * @brief Get rpmsg virtio Tx buffer size
282  *
283  * This function is same as rpmsg_virtio_get_tx_buffer_size(), keep it here
284  * to maintain the forward compatibility.
285  *
286  * @param rdev	Pointer to the rpmsg device.
287  *
288  * @return Next available buffer size for text, negative value for failure.
289  */
rpmsg_virtio_get_buffer_size(struct rpmsg_device * rdev)290 static inline int rpmsg_virtio_get_buffer_size(struct rpmsg_device *rdev)
291 {
292 	return rpmsg_virtio_get_tx_buffer_size(rdev);
293 }
294 
295 /**
296  * @brief Initialize rpmsg virtio device
297  *
298  * Host side:
299  * Initialize RPMsg virtio queues and shared buffers, the address of shm can be
300  * ANY. In this case, function will get shared memory from system shared memory
301  * pools. If the vdev has the RPMsg name service feature, this API will create
302  * a name service endpoint.
303  *
304  * Remote side:
305  * This API will not return until the driver ready is set by the host side.
306  *
307  * @param rvdev		Pointer to the rpmsg virtio device
308  * @param vdev		Pointer to the virtio device
309  * @param ns_bind_cb	Callback handler for name service announcement without
310  *                      local endpoints waiting to bind.
311  * @param shm_io	Pointer to the share memory I/O region.
312  * @param shpool	Pointer to shared memory pool.
313  *			rpmsg_virtio_init_shm_pool has to be called first to
314  *			fill this structure.
315  *
316  * @return Status of function execution
317  */
318 int rpmsg_init_vdev(struct rpmsg_virtio_device *rvdev,
319 		    struct virtio_device *vdev,
320 		    rpmsg_ns_bind_cb ns_bind_cb,
321 		    struct metal_io_region *shm_io,
322 		    struct rpmsg_virtio_shm_pool *shpool);
323 
324 /**
325  * @brief Initialize rpmsg virtio device with config
326  *
327  * Host side:
328  * Initialize RPMsg virtio queues and shared buffers, the address of shm can be
329  * ANY. In this case, function will get shared memory from system shared memory
330  * pools. If the vdev has the RPMsg name service feature, this API will create
331  * a name service endpoint.
332  * Sizes of virtio data buffers used by the initialized RPMsg instance are set
333  * to values read from the passed configuration structure.
334  *
335  * Remote side:
336  * This API will not return until the driver ready is set by the host side.
337  * Sizes of virtio data buffers are set by the host side. Values passed in the
338  * configuration structure have no effect.
339  *
340  * @param rvdev		Pointer to the rpmsg virtio device
341  * @param vdev		Pointer to the virtio device
342  * @param ns_bind_cb	Callback handler for name service announcement without
343  *                      local endpoints waiting to bind.
344  * @param shm_io	Pointer to the share memory I/O region.
345  * @param shpool	Pointer to shared memory pool array.
346  *			If the config->split_shpool is turn on, the array will
347  *			contain two elements, the shpool of txshpool and
348  *			rxshpool, Otherwise, the array has only one element,
349  *			and txshpool rxshpool shares a shpool.
350  *			And rpmsg_virtio_init_shm_pool has to be called first
351  *			to fill each shpool in this array.
352  * @param config	Pointer to configuration structure
353  *
354  * @return Status of function execution
355  */
356 int rpmsg_init_vdev_with_config(struct rpmsg_virtio_device *rvdev,
357 				struct virtio_device *vdev,
358 				rpmsg_ns_bind_cb ns_bind_cb,
359 				struct metal_io_region *shm_io,
360 				struct rpmsg_virtio_shm_pool *shpool,
361 				const struct rpmsg_virtio_config *config);
362 
363 /**
364  * @brief Deinitialize rpmsg virtio device
365  *
366  * @param rvdev	Pointer to the rpmsg virtio device
367  */
368 void rpmsg_deinit_vdev(struct rpmsg_virtio_device *rvdev);
369 
370 /**
371  * @brief Initialize default shared buffers pool
372  *
373  * RPMsg virtio has default shared buffers pool implementation.
374  * The memory assigned to this pool will be dedicated to the RPMsg
375  * virtio. This function has to be called before calling rpmsg_init_vdev,
376  * to initialize the rpmsg_virtio_shm_pool structure.
377  *
378  * @param shpool	Pointer to the shared buffers pool structure
379  * @param shbuf		Pointer to the beginning of shared buffers
380  * @param size		Shared buffers total size
381  */
382 void rpmsg_virtio_init_shm_pool(struct rpmsg_virtio_shm_pool *shpool,
383 				void *shbuf, size_t size);
384 
385 /**
386  * @brief Get RPMsg device from RPMsg virtio device
387  *
388  * @param rvdev	Pointer to RPMsg virtio device
389  *
390  * @return RPMsg device pointed by RPMsg virtio device
391  */
392 static inline struct rpmsg_device *
rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device * rvdev)393 rpmsg_virtio_get_rpmsg_device(struct rpmsg_virtio_device *rvdev)
394 {
395 	if (!rvdev)
396 		return NULL;
397 
398 	return &rvdev->rdev;
399 }
400 
401 /**
402  * @brief Get buffer in the shared memory pool
403  *
404  * RPMsg virtio has default shared buffers pool implementation.
405  * The memory assigned to this pool will be dedicated to the RPMsg
406  * virtio. If you prefer to have other shared buffers allocation,
407  * you can implement your rpmsg_virtio_shm_pool_get_buffer function.
408  *
409  * @param shpool	Pointer to the shared buffers pool
410  * @param size		Shared buffers total size
411  *
412  * @return Buffer pointer if free buffer is available, NULL otherwise.
413  */
414 metal_weak void *
415 rpmsg_virtio_shm_pool_get_buffer(struct rpmsg_virtio_shm_pool *shpool,
416 				 size_t size);
417 
418 #if defined __cplusplus
419 }
420 #endif
421 
422 #endif	/* _RPMSG_VIRTIO_H_ */
423