OpenAMP Library
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 
24 /* Error Codes */
25 #define VQ_ERROR_BASE -3000
26 #define ERROR_VRING_FULL (VQ_ERROR_BASE - 1)
27 #define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2)
28 #define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3)
29 #define ERROR_NO_MEM (VQ_ERROR_BASE - 4)
30 #define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5)
31 #define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6)
32 #define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7)
33 #define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8)
34 
35 #define VQUEUE_SUCCESS 0
36 
37 /* The maximum virtqueue size is 2^15. Use that value as the end of
38  * descriptor chain terminator since it will never be a valid index
39  * in the descriptor table. This is used to verify we are correctly
40  * handling vq_free_cnt.
41  */
42 #define VQ_RING_DESC_CHAIN_END 32768
43 
44 /* Support for indirect buffer descriptors. */
45 #define VIRTIO_RING_F_INDIRECT_DESC (1 << 28)
46 
47 /* Support to suppress interrupt until specific index is reached. */
48 #define VIRTIO_RING_F_EVENT_IDX (1 << 29)
49 
50 struct virtqueue_buf {
51  void *buf;
52  int len;
53 };
54 
55 struct vq_desc_extra {
56  void *cookie;
57  uint16_t ndescs;
58 };
59 
60 struct virtqueue {
62  const char *vq_name;
63  uint16_t vq_queue_index;
64  uint16_t vq_nentries;
65  void (*callback)(struct virtqueue *vq);
66  void (*notify)(struct virtqueue *vq);
67  struct vring vq_ring;
68  uint16_t vq_free_cnt;
69  uint16_t vq_queued_cnt;
70  void *shm_io; /* opaque pointer to data needed to allow v2p & p2v */
71 
72  /*
73  * Head of the free chain in the descriptor table. If
74  * there are no free descriptors, this will be set to
75  * VQ_RING_DESC_CHAIN_END.
76  */
77  uint16_t vq_desc_head_idx;
78 
79  /*
80  * Last consumed descriptor in the used table,
81  * trails vq_ring.used->idx.
82  */
83  uint16_t vq_used_cons_idx;
84 
85  /*
86  * Last consumed descriptor in the available table -
87  * used by the consumer side.
88  */
89  uint16_t vq_available_idx;
90 
91 #ifdef VQUEUE_DEBUG
92  bool vq_inuse;
93 #endif
94 
95  /*
96  * Used by the host side during callback. Cookie
97  * holds the address of buffer received from other side.
98  * Other fields in this structure are not used currently.
99  */
100 
101  struct vq_desc_extra vq_descx[0];
102 };
103 
104 /* struct to hold vring specific information */
106  void *vaddr;
107  uint32_t align;
108  uint16_t num_descs;
109  uint16_t pad;
110 };
111 
112 typedef void (*vq_callback)(struct virtqueue *);
113 typedef void (*vq_notify)(struct virtqueue *);
114 
115 #ifdef VQUEUE_DEBUG
116 #include <metal/log.h>
117 #include <metal/assert.h>
118 
119 #define VQASSERT(_vq, _exp, _msg) \
120  do { \
121  if (!(_exp)) { \
122  metal_log(METAL_LOG_EMERGENCY, \
123  "%s: %s - "_msg, __func__, (_vq)->vq_name); \
124  metal_assert(_exp); \
125  } \
126  } while (0)
127 
128 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \
129  VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index")
130 
131 #define VQ_RING_ASSERT_CHAIN_TERM(_vq) \
132  VQASSERT((_vq), (_vq)->vq_desc_head_idx == \
133  VQ_RING_DESC_CHAIN_END, \
134  "full ring terminated incorrectly: invalid head")
135 
136 #define VQ_PARAM_CHK(condition, status_var, status_err) \
137  do { \
138  if (((status_var) == 0) && (condition)) { \
139  status_var = status_err; \
140  } \
141  } while (0)
142 
143 #define VQUEUE_BUSY(vq) \
144  do { \
145  if (!(vq)->vq_inuse) \
146  (vq)->vq_inuse = true; \
147  else \
148  VQASSERT(vq, !(vq)->vq_inuse,\
149  "VirtQueue already in use"); \
150  } while (0)
151 
152 #define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false)
153 
154 #else
155 
156 #define VQASSERT(_vq, _exp, _msg)
157 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
158 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)
159 #define VQ_PARAM_CHK(condition, status_var, status_err)
160 #define VQUEUE_BUSY(vq)
161 #define VQUEUE_IDLE(vq)
162 
163 #endif
164 
182 int virtqueue_create(struct virtio_device *device, unsigned short id,
183  const char *name, struct vring_alloc_info *ring,
184  void (*callback)(struct virtqueue *vq),
185  void (*notify)(struct virtqueue *vq),
186  struct virtqueue *vq);
187 
188 /*
189  * virtqueue_set_shmem_io
190  *
191  * set virtqueue shared memory I/O region
192  *
193  * @vq - virt queue
194  * @io - pointer to the shared memory I/O region
195  */
196 static inline void virtqueue_set_shmem_io(struct virtqueue *vq,
197  struct metal_io_region *io)
198 {
199  vq->shm_io = io;
200 }
201 
216 int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list,
217  int readable, int writable, void *cookie);
218 
230 void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
231 
243 void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx,
244  uint32_t *len);
245 
257 int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
258  uint32_t len);
259 
267 void virtqueue_disable_cb(struct virtqueue *vq);
268 
278 int virtqueue_enable_cb(struct virtqueue *vq);
279 
287 void virtqueue_kick(struct virtqueue *vq);
288 
289 static inline struct virtqueue *virtqueue_allocate(unsigned int num_desc_extra)
290 {
291  struct virtqueue *vqs;
292  uint32_t vq_size = sizeof(struct virtqueue) +
293  num_desc_extra * sizeof(struct vq_desc_extra);
294 
295  vqs = (struct virtqueue *)metal_allocate_memory(vq_size);
296  if (vqs) {
297  memset(vqs, 0x00, vq_size);
298  }
299 
300  return vqs;
301 }
302 
310 void virtqueue_free(struct virtqueue *vq);
311 
319 void virtqueue_dump(struct virtqueue *vq);
320 
321 void virtqueue_notification(struct virtqueue *vq);
322 
332 uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
333 
334 uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
335 void *virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx);
336 
337 #if defined __cplusplus
338 }
339 #endif
340 
341 #endif /* VIRTQUEUE_H_ */
Definition: virtio.h:118
Definition: virtqueue.h:50
void * buf
Definition: virtqueue.h:51
int len
Definition: virtqueue.h:52
Definition: virtqueue.h:60
struct vq_desc_extra vq_descx[0]
Definition: virtqueue.h:101
void(* callback)(struct virtqueue *vq)
Definition: virtqueue.h:65
uint16_t vq_queue_index
Definition: virtqueue.h:63
void(* notify)(struct virtqueue *vq)
Definition: virtqueue.h:66
uint16_t vq_queued_cnt
Definition: virtqueue.h:69
uint16_t vq_available_idx
Definition: virtqueue.h:89
uint16_t vq_used_cons_idx
Definition: virtqueue.h:83
uint16_t vq_desc_head_idx
Definition: virtqueue.h:77
uint16_t vq_nentries
Definition: virtqueue.h:64
void * shm_io
Definition: virtqueue.h:70
uint16_t vq_free_cnt
Definition: virtqueue.h:68
const char * vq_name
Definition: virtqueue.h:62
struct virtio_device * vq_dev
Definition: virtqueue.h:61
struct vring vq_ring
Definition: virtqueue.h:67
Definition: virtqueue.h:55
void * cookie
Definition: virtqueue.h:56
uint16_t ndescs
Definition: virtqueue.h:57
Definition: virtqueue.h:105
void * vaddr
Definition: virtqueue.h:106
uint16_t pad
Definition: virtqueue.h:109
uint16_t num_descs
Definition: virtqueue.h:108
uint32_t align
Definition: virtqueue.h:107
Definition: virtio_ring.h:77
uint32_t virtqueue_get_desc_size(struct virtqueue *vq)
Definition: virtqueue.c:355
int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len)
Definition: virtqueue.c:243
void(* vq_notify)(struct virtqueue *)
Definition: virtqueue.h:113
void virtqueue_dump(struct virtqueue *vq)
Definition: virtqueue.c:336
void virtqueue_notification(struct virtqueue *vq)
Definition: virtqueue.c:615
int virtqueue_add_buffer(struct virtqueue *vq, struct virtqueue_buf *buf_list, int readable, int writable, void *cookie)
Definition: virtqueue.c:93
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx)
Definition: virtqueue.c:186
void virtqueue_free(struct virtqueue *vq)
Definition: virtqueue.c:198
void virtqueue_kick(struct virtqueue *vq)
Definition: virtqueue.c:321
void(* vq_callback)(struct virtqueue *)
Definition: virtqueue.h:112
static struct virtqueue * virtqueue_allocate(unsigned int num_desc_extra)
Definition: virtqueue.h:289
void * virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, uint32_t *len)
Definition: virtqueue.c:211
void * virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx)
Definition: virtqueue.c:148
static void virtqueue_set_shmem_io(struct virtqueue *vq, struct metal_io_region *io)
Definition: virtqueue.h:196
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:58
void * virtqueue_get_buffer_addr(struct virtqueue *vq, uint16_t idx)
Definition: virtqueue.c:192
void virtqueue_disable_cb(struct virtqueue *vq)
Definition: virtqueue.c:284
int virtqueue_enable_cb(struct virtqueue *vq)
Definition: virtqueue.c:279