83d2fb54f551797b4a38c43df23d76c319d4930b
1 #ifndef VIRTQUEUE_H_
2 #define VIRTQUEUE_H_
4 /*-
5 * Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice unmodified, this list of conditions, and the following
13 * disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * $FreeBSD$
30 */
32 #include <stdint.h>
33 typedef uint8_t boolean;
35 #include "openamp/virtio_ring.h"
36 #include "openamp/env.h"
37 #include "openamp/llist.h"
39 /*Error Codes*/
40 #define VQ_ERROR_BASE -3000
41 #define ERROR_VRING_FULL (VQ_ERROR_BASE - 1)
42 #define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2)
43 #define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3)
44 #define ERROR_NO_MEM (VQ_ERROR_BASE - 4)
45 #define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5)
46 #define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6)
47 #define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7)
48 #define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8)
50 #define true 1
51 #define false 0
52 #define VQUEUE_SUCCESS 0
53 #define VQUEUE_DEBUG false
55 //TODO:
56 /* This is temporary macro to replace C NULL support.
57 * At the moment all the RTL specific functions are present in env.
58 * */
59 #define VQ_NULL 0
61 /* The maximum virtqueue size is 2^15. Use that value as the end of
62 * descriptor chain terminator since it will never be a valid index
63 * in the descriptor table. This is used to verify we are correctly
64 * handling vq_free_cnt.
65 */
66 #define VQ_RING_DESC_CHAIN_END 32768
67 #define VIRTQUEUE_FLAG_INDIRECT 0x0001
68 #define VIRTQUEUE_FLAG_EVENT_IDX 0x0002
69 #define VIRTQUEUE_MAX_NAME_SZ 32
71 /* Support for indirect buffer descriptors. */
72 #define VIRTIO_RING_F_INDIRECT_DESC (1 << 28)
74 /* Support to suppress interrupt until specific index is reached. */
75 #define VIRTIO_RING_F_EVENT_IDX (1 << 29)
77 /*
78 * Hint on how long the next interrupt should be postponed. This is
79 * only used when the EVENT_IDX feature is negotiated.
80 */
81 typedef enum {
82 VQ_POSTPONE_SHORT,
83 VQ_POSTPONE_LONG,
84 VQ_POSTPONE_EMPTIED /* Until all available desc are used. */
85 } vq_postpone_t;
87 struct virtqueue {
88 //TODO: Need to define proper structure for
89 // virtio device with RPmsg and paravirtualization.
91 struct virtio_device *vq_dev;
92 char vq_name[VIRTQUEUE_MAX_NAME_SZ];
93 uint16_t vq_queue_index;
94 uint16_t vq_nentries;
95 uint32_t vq_flags;
96 int vq_alignment;
97 int vq_ring_size;
98 boolean vq_inuse;
99 void *vq_ring_mem;
100 void (*callback) (struct virtqueue * vq);
101 void (*notify) (struct virtqueue * vq);
102 int vq_max_indirect_size;
103 int vq_indirect_mem_size;
104 struct vring vq_ring;
105 uint16_t vq_free_cnt;
106 uint16_t vq_queued_cnt;
108 /*
109 * Head of the free chain in the descriptor table. If
110 * there are no free descriptors, this will be set to
111 * VQ_RING_DESC_CHAIN_END.
112 */
113 uint16_t vq_desc_head_idx;
115 /*
116 * Last consumed descriptor in the used table,
117 * trails vq_ring.used->idx.
118 */
119 uint16_t vq_used_cons_idx;
121 /*
122 * Last consumed descriptor in the available table -
123 * used by the consumer side.
124 */
125 uint16_t vq_available_idx;
127 uint8_t padd;
129 /*
130 * Used by the host side during callback. Cookie
131 * holds the address of buffer received from other side.
132 * Other fields in this structure are not used currently.
133 */
135 struct vq_desc_extra {
136 void *cookie;
137 struct vring_desc *indirect;
138 uint32_t indirect_paddr;
139 uint16_t ndescs;
140 } vq_descx[0];
141 };
143 /* struct to hold vring specific information */
144 struct vring_alloc_info {
145 void *vaddr;
146 uint32_t align;
147 uint16_t num_descs;
148 uint16_t pad;
149 };
151 typedef void vq_callback(struct virtqueue *);
152 typedef void vq_notify(struct virtqueue *);
154 #if (VQUEUE_DEBUG == true)
156 #define VQASSERT(_vq, _exp, _msg) do{ \
157 if (!(_exp)){ printf("%s: %s - "_msg, __func__, (_vq)->vq_name); while(1);} \
158 } while(0)
160 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) \
161 VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, \
162 "invalid ring index")
164 #define VQ_RING_ASSERT_CHAIN_TERM(_vq) \
165 VQASSERT((_vq), (_vq)->vq_desc_head_idx == \
166 VQ_RING_DESC_CHAIN_END, "full ring terminated incorrectly: invalid head")
168 #define VQ_PARAM_CHK(condition, status_var, status_err) \
169 if ((status_var == 0) && (condition)) \
170 { \
171 status_var = status_err; \
172 }
174 #define VQUEUE_BUSY(vq) if ((vq)->vq_inuse == false) \
175 (vq)->vq_inuse = true; \
176 else \
177 VQASSERT(vq, (vq)->vq_inuse == false, \
178 "VirtQueue already in use")
180 #define VQUEUE_IDLE(vq) ((vq)->vq_inuse = false)
182 #else
184 #define KASSERT(cond, str)
185 #define VQASSERT(_vq, _exp, _msg)
186 #define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
187 #define VQ_RING_ASSERT_CHAIN_TERM(_vq)
188 #define VQ_PARAM_CHK(condition, status_var, status_err)
189 #define VQUEUE_BUSY(vq)
190 #define VQUEUE_IDLE(vq)
192 #endif
194 int virtqueue_create(struct virtio_device *device, unsigned short id,
195 char *name, struct vring_alloc_info *ring,
196 void (*callback) (struct virtqueue * vq),
197 void (*notify) (struct virtqueue * vq),
198 struct virtqueue **v_queue);
200 int virtqueue_add_buffer(struct virtqueue *vq, struct llist *buffer,
201 int readable, int writable, void *cookie);
203 int virtqueue_add_single_buffer(struct virtqueue *vq, void *cookie,
204 void *buffer_addr, uint32_t len, int writable,
205 boolean has_next);
207 void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t * len);
209 void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t * avail_idx,
210 uint32_t * len);
212 int virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx,
213 uint32_t len);
215 void virtqueue_disable_cb(struct virtqueue *vq);
217 int virtqueue_enable_cb(struct virtqueue *vq);
219 void virtqueue_kick(struct virtqueue *vq);
221 void virtqueue_free(struct virtqueue *vq);
223 void virtqueue_dump(struct virtqueue *vq);
225 void virtqueue_notification(struct virtqueue *vq);
227 uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
229 #endif /* VIRTQUEUE_H_ */