OpenAMP Library  353
virtqueue.h
Go to the documentation of this file.
1 #ifndef VIRTQUEUE_H_
2 #define VIRTQUEUE_H_
3 
4 /*-
5  * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
6  * All rights reserved.
7  *
8  * SPDX-License-Identifier: BSD-2-Clause
9  *
10  * $FreeBSD$
11  */
12 
13 #include <stdbool.h>
14 #include <stdint.h>
15 
16 #if defined __cplusplus
17 extern "C" {
18 #endif
19 
20 #include <openamp/virtio_ring.h>
21 #include <metal/alloc.h>
22 #include <metal/io.h>
23 #include <metal/cache.h>
24 
25 /* Error Codes */
26 #define VQ_ERROR_BASE -3000
27 #define ERROR_VRING_FULL (VQ_ERROR_BASE - 1)
28 #define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2)
29 #define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3)
30 #define ERROR_NO_MEM (VQ_ERROR_BASE - 4)
31 #define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5)
32 #define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6)
33 #define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7)
34 #define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8)
35 
36 #define VQUEUE_SUCCESS 0
37 
38 /* The maximum virtqueue size is 2^15. Use that value as the end of
39  * descriptor chain terminator since it will never be a valid index
40  * in the descriptor table. This is used to verify we are correctly
41  * handling vq_free_cnt.
42  */
43 #define VQ_RING_DESC_CHAIN_END 32768
44 
45 /* Support for indirect buffer descriptors. */
46 #define VIRTIO_RING_F_INDIRECT_DESC (1 << 28)
47 
48 /* Support to suppress interrupt until specific index is reached. */
49 #define VIRTIO_RING_F_EVENT_IDX (1 << 29)
50 
51 #if defined(VIRTIO_USE_DCACHE)
52 #define VRING_FLUSH(x, s) metal_cache_flush(x, s)
53 #define VRING_INVALIDATE(x, s) metal_cache_invalidate(x, s)
54 #else
55 #define VRING_FLUSH(x, s) do { } while (0)
56 #define VRING_INVALIDATE(x, s) do { } while (0)
57 #endif /* VIRTIO_USE_DCACHE */
58 
60 struct virtqueue_buf {
62  void *buf;
63 
65  int len;
66 };
67 
69 struct vq_desc_extra {
71  void *cookie;
72 
74  uint16_t ndescs;
75 };
76 
78 struct virtqueue {
81 
83  const char *vq_name;
84 
86  uint16_t vq_queue_index;
87 
89  uint16_t vq_nentries;
90 
92  void (*callback)(struct virtqueue *vq);
93 
95  void *priv;
96 
98  void (*notify)(struct virtqueue *vq);
99 
101  struct vring vq_ring;
102 
104  uint16_t vq_free_cnt;
105 
107  uint16_t vq_queued_cnt;
108 
113  struct metal_io_region *shm_io;
114 
120 
123 
126 
127 #ifdef VQUEUE_DEBUG
129  bool vq_inuse;
130 #endif
131 
136  struct vq_desc_extra vq_descx[0];
137 };
138 
142  void *vaddr;
143 
145  uint32_t align;
146 
148  uint16_t num_descs;
149 
151  uint16_t pad;
152 };
153 
154 typedef void (*vq_callback)(struct virtqueue *);
155 typedef void (*vq_notify)(struct virtqueue *);
156 
157 #ifdef VQUEUE_DEBUG
158 #include <metal/log.h>
159 #include <metal/assert.h>
160 
161 #define VQASSERT(_vq, _exp, _msg) \
162  do { \
163  if (!(_exp)) { \
164  metal_log(METAL_LOG_EMERGENCY, \
165  "%s: %s - "_msg, __func__, (_vq)->vq_name); \
166  metal_assert(_exp); \
167  } \
168  } while (0)
169 
170 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \
171  VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index")
172 
173 #define VQ_RING_ASSERT_CHAIN_TERM(_vq) \
174  VQASSERT((_vq), (_vq)->vq_desc_head_idx == \
175  VQ_RING_DESC_CHAIN_END, \
176  "full ring terminated incorrectly: invalid head")
177 
178 #define VQ_PARAM_CHK(condition, status_var, status_err) \
179  do { \
180  if (((status_var) == 0) && (condition)) { \
181  status_var = status_err; \
182  } \
183  } while (0)
184 
185 #define VQUEUE_BUSY(vq) \
186  do { \
187  if (!(vq)->vq_inuse) \
188  (vq)->vq_inuse = true; \
189  else \
190  VQASSERT(vq, !(vq)->vq_inuse,\
191  "VirtQueue already in use"); \
192  } while (0)
193 
194 #define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false)
195 
196 #else
197 
198 #define VQASSERT(_vq, _exp, _msg)
199 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
200 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)
201 #define VQ_PARAM_CHK(condition, status_var, status_err)
202 #define VQUEUE_BUSY(vq)
203 #define VQUEUE_IDLE(vq)
204 
205 #endif
206 
224 int virtqueue_create(struct virtio_device *device, unsigned short id,
225  const char *name, struct vring_alloc_info *ring,
226  void (*callback)(struct virtqueue *vq),
227  void (*notify)(struct virtqueue *vq),
228  struct virtqueue *vq);
229 
230 /*
231  * virtqueue_set_shmem_io
232  *
233  * set virtqueue shared memory I/O region
234  *
235  * @vq - virt queue
236  * @io - pointer to the shared memory I/O region
237  */
238 static inline void virtqueue_set_shmem_io(struct virtqueue *vq,
239  struct metal_io_region *io)
240 {
241  vq->shm_io = io;
242 }
243 
258 int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list,
259  int readable, int writable, void *cookie);
260 
272 void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
273 
285 void *virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx,
286  uint32_t *len);
287 
310 void *virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx,
311  uint16_t *next_idx, uint32_t *next_len);
312 
324 int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
325  uint32_t len);
326 
334 void virtqueue_disable_cb(struct virtqueue *vq);
335 
345 int virtqueue_enable_cb(struct virtqueue *vq);
346 
354 void virtqueue_kick(struct virtqueue *vq);
355 
356 static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra)
357 {
358  struct virtqueue *vqs;
359  uint32_t vq_size = sizeof(struct virtqueue) +
360  num_desc_extra * sizeof(struct vq_desc_extra);
361 
362  vqs = (struct virtqueue *)metal_allocate_memory(vq_size);
363  if (vqs) {
364  memset(vqs, 0x00, vq_size);
365  }
366 
367  return vqs;
368 }
369 
377 void virtqueue_free(struct virtqueue *vq);
378 
386 void virtqueue_dump(struct virtqueue *vq);
387 
388 void virtqueue_notification(struct virtqueue *vq);
389 
399 uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
400 
401 uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
402 void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx);
403 
411 static inline int virtqueue_empty(struct virtqueue *vq)
412 {
413  return (vq->vq_nentries == vq->vq_free_cnt);
414 }
415 
423 static inline int virtqueue_full(struct virtqueue *vq)
424 {
425  return (vq->vq_free_cnt == 0);
426 }
427 
428 #if defined __cplusplus
429 }
430 #endif
431 
432 #endif /* VIRTQUEUE_H_ */
Structure definition for virtio devices for use by the applications/drivers.
Definition: virtio.h:188
Buffer descriptor.
Definition: virtqueue.h:60
void * buf
Address of the buffer.
Definition: virtqueue.h:62
int len
Size of the buffer.
Definition: virtqueue.h:65
Local virtio queue to manage a virtio ring for sending or receiving.
Definition: virtqueue.h:78
struct metal_io_region * shm_io
Metal I/O region of the buffers.
Definition: virtqueue.h:113
struct vq_desc_extra vq_descx[0]
Used by the host side during callback.
Definition: virtqueue.h:136
void(* callback)(struct virtqueue *vq)
Function to invoke, when message is available on the virtio queue.
Definition: virtqueue.h:92
uint16_t vq_queue_index
Index of the virtio queue.
Definition: virtqueue.h:86
void(* notify)(struct virtqueue *vq)
Function to invoke, to inform the other side about an update in the virtio queue.
Definition: virtqueue.h:98
uint16_t vq_queued_cnt
Number of queued buffer in the virtio ring.
Definition: virtqueue.h:107
uint16_t vq_available_idx
Last consumed descriptor in the available table, used by the consumer side.
Definition: virtqueue.h:125
uint16_t vq_used_cons_idx
Last consumed descriptor in the used table, trails vq_ring.used->idx.
Definition: virtqueue.h:122
uint16_t vq_desc_head_idx
Head of the free chain in the descriptor table.
Definition: virtqueue.h:119
uint16_t vq_nentries
Max number of buffers in the virtio queue.
Definition: virtqueue.h:89
void * priv
Private data associated to the virtio queue.
Definition: virtqueue.h:95
uint16_t vq_free_cnt
Number of free descriptor in the virtio ring.
Definition: virtqueue.h:104
const char * vq_name
Name of the virtio queue.
Definition: virtqueue.h:83
struct virtio_device * vq_dev
Associated virtio device.
Definition: virtqueue.h:80
struct vring vq_ring
Associated virtio ring.
Definition: virtqueue.h:101
Vring descriptor extra information for buffer list management.
Definition: virtqueue.h:69
void * cookie
Pointer to first descriptor.
Definition: virtqueue.h:71
uint16_t ndescs
Number of chained descriptors.
Definition: virtqueue.h:74
Virtio ring specific information.
Definition: virtqueue.h:140
void * vaddr
Vring address.
Definition: virtqueue.h:142
uint16_t pad
Padding.
Definition: virtqueue.h:151
uint16_t num_descs
Number of descriptors in the vring.
Definition: virtqueue.h:148
uint32_t align
Vring alignment.
Definition: virtqueue.h:145
The virtqueue layout structure.
Definition: virtio_ring.h:157
void * virtqueue_get_first_avail_buffer(struct virtqueue *vq, uint16_t *avail_idx, uint32_t *len)
Definition: virtqueue.c:203
uint32_t virtqueue_get_desc_size(struct virtqueue *vq)
Definition: virtqueue.c:367
static int virtqueue_empty(struct virtqueue *vq)
Test if virtqueue is empty.
Definition: virtqueue.h:411
int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len)
Definition: virtqueue.c:258
void(* vq_notify)(struct virtqueue *)
Definition: virtqueue.h:155
void virtqueue_dump(struct virtqueue *vq)
Definition: virtqueue.c:348
void virtqueue_notification(struct virtqueue *vq)
Definition: virtqueue.c:620
int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, int readable, int writable, void *cookie)
Definition: virtqueue.c:80
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx)
Definition: virtqueue.c:174
void virtqueue_free(struct virtqueue *vq)
Definition: virtqueue.c:190
void virtqueue_kick(struct virtqueue *vq)
Definition: virtqueue.c:333
static int virtqueue_full(struct virtqueue *vq)
Test if virtqueue is full.
Definition: virtqueue.h:423
void(* vq_callback)(struct virtqueue *)
Definition: virtqueue.h:154
static struct virtqueue * virtqueue_allocate(unsigned int num_desc_extra)
Definition: virtqueue.h:356
void * virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx)
Definition: virtqueue.c:135
static void virtqueue_set_shmem_io(struct virtqueue *vq, struct metal_io_region *io)
Definition: virtqueue.h:238
int virtqueue_create(struct virtio_device *device, unsigned short id, const char *name, struct vring_alloc_info *ring, void(*callback)(struct virtqueue *vq), void(*notify)(struct virtqueue *vq), struct virtqueue *vq)
Definition: virtqueue.c:45
void * virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx)
Definition: virtqueue.c:182
void virtqueue_disable_cb(struct virtqueue *vq)
Definition: virtqueue.c:300
void * virtqueue_get_next_avail_buffer(struct virtqueue *vq, uint16_t idx, uint16_t *next_idx, uint32_t *next_len)
Definition: virtqueue.c:234
int virtqueue_enable_cb(struct virtqueue *vq)
Definition: virtqueue.c:295