1/*
2 * Copyright (c) 2014 ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#ifndef VIRTIO_VIRTQUEUE_H
11#define VIRTIO_VIRTQUEUE_H
12
13#include <barrelfish/barrelfish.h>
14
15#ifdef __VIRTIO_HOST__
16#include <virtio/virtio_host.h>
17#endif
18
19/*
20 * Extracted from the Virtio Specification 1.0
21 * http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
22 *
23 * VIRQUEUES:
24 *
25 * Size is determined by a 16bit integer.
26 * The queue consists of a descriptor table, available ring, used ring
27 * Each of the three parts are physically-contiguous in guest memory.
28 *
29 */
30
31// forward definition
32struct virtqueue;
33
34/// interrupt handler for virtqueue interrupts
35typedef void (*virtq_intr_hander_t)(struct virtqueue *, void *);
36
37/// virtqueue default alignment
38#define VIRTQUEUE_ALIGNMENT 4096
39
40/// the maximum length of the name field
41#define VIRTQUEUE_NAME_SIZE 32
42
43/// the maximum number of elements in a vring
44#define VIRTQUEUE_SIZE_MAX (1<<15)
45
46/// this value marks the end of a descriptor chain
47#define VIRTQUEUE_CHAIN_END VIRTQUEUE_SIZE_MAX
48
49/// Feature flag indicating that the ring supports indirect descriptors
50#define VIRTIO_RING_F_INDIRECT_DESC 28
51
52/// Feature flag indicating that the ring supports interrupt suppression
53#define VIRTIO_RING_F_EVENT_IDX     29
54
55
56/**
57 * this structure holds necessary data to allocate a new virtqueue
58 *
59 * XXX: this may be a bit revised and split into two different structs
60 *      one for the host and one for the guest
61 */
62struct virtqueue_setup {
63    char name[VIRTQUEUE_NAME_SIZE];     ///< the name of the queue
64    struct virtio_device *device;       ///< device this queue belongs to
65    uint16_t queue_id;                  ///< the id of this queue
66    uint16_t vring_ndesc;               ///< size of the vring
67    lvaddr_t vring_align;               ///< alignment of the vring
68    uint16_t max_indirect;              ///< maximum indirect descriptors
69#ifdef __VIRTIO_HOST__
70    virtq_work_handler_t worker_fn;     ///< callback when new work arrives
71    void *worker_arg;                   ///< argument for the worker function
72#else
73    uint8_t buffer_bits;                ///< when non zero, will allocate buffer
74    uint8_t header_bits;                ///< allocate additional space for headers
75    uint8_t auto_add;                   ///< adds this virtqueue to the device
76    void *intr_arg;                     ///< argument for the interrupt handler
77    virtq_intr_hander_t intr_handler;   ///< interrupt handler function
78#endif
79};
80
81/**
82 *
83 */
84enum virtqueue_intr_postpone {
85   VIRTQUEUE_INTR_POSTPONE_SHORT,
86   VIRTQUEUE_INTR_POSTPONE_LONG,
87   VIRTQUEUE_INTR_POSTPONE_EMPTIED,
88};
89
90
91/**
92 * \brief allocates and initiates a new virtqueue structure
93 *
94 * \param setup  pointer to the setup information
95 * \param vq     pointer where to store the new virtqueue pointer
96 *
97 * \returns SYS_ERR_OK on success
98 */
99errval_t virtio_virtqueue_alloc(struct virtqueue_setup *setup,
100                                struct virtqueue **vq);
101
102/**
103 * \brief allocates and initiates a new virtqueue structure
104 *
105 * \param setup     pointer to the setup information
106 * \param vring_cap capability to be used for the vring
107 * \param vq        pointer where to store the new virtqueue pointer
108 *
109 * \returns SYS_ERR_OK on success
110 */
111errval_t virtio_virtqueue_alloc_with_caps(struct virtqueue_setup *setup,
112                                          struct capref vring_cap,
113                                          struct virtqueue **vq);
114
115/**
116 * \brief frees the resources of previously allocated virtqueues
117 *
118 * \param vq pointer to the virtqueue memory to be freed
119 *
120 * \returns SYS_ERR_OK on success
121 */
122errval_t virtio_virtqueue_free(struct virtqueue *vq);
123
124/*
125void    *virtqueue_drain(struct virtqueue *vq, int *last);
126int  virtqueue_reinit(struct virtqueue *vq, uint16_t size);
127*/
128
129
130/*
131 * ===========================================================================
132 * Getter functions for certain values of the virtqueue structure
133 */
134
135/**
136 * \brief Returns the physical address of the vring.
137 *
138 * \param vq pointer to the virtqueue structure
139 *
140 * \returns the physical address of the vring
141 */
142lpaddr_t virtio_virtqueue_get_vring_paddr(struct virtqueue *vq);
143
144
145/**
146 * \brief Returns the frame capability of the vring
147 *
148 * \param vq        pointer to the virtqueue structure
149 * \param ret_cap   memory location where to store the capref
150 */
151void virtio_virtqueue_get_vring_cap(struct virtqueue *vq,
152                                    struct capref *ret_cap);
153
154/**
155 * \brief Returns the queue index of the virtqueue of the device
156 *
157 * \param vq pointer to the virtqueue structure
158 *
159 * \returns queue index
160 */
161uint16_t virtio_virtqueue_get_queue_index(struct virtqueue *vq);
162
163/**
164 * \brief returns the alignment of the vring
165 *
166 * \param the virtqueue to get the alignment from
167 *
168 * \returns vring alignment
169 */
170lvaddr_t virtio_virtqueue_get_vring_align(struct virtqueue *vq);
171
172/**
173 * \brief Returns the number of elements (number of descriptors)in the vring of
174 *        this virtqueue
175 *
176 * \param vq pointer to the virtqueue structure
177 *
178 * \returns number of elements in the vring
179 */
180uint16_t virtio_virtqueue_get_num_desc(struct virtqueue *vq);
181
182/**
183 * \brief Checks if the virtqueue is empty
184 *
185 * \param vq pointer to the virtqueue structure
186 *
187 * \returns 0 the queue is not empty
188 *          1 the queue is empty
189 */
190bool virtio_virtqueue_is_empty(struct virtqueue *vq);
191
192/**
193 * \brief Checks if the virtqueue is full
194 *
195 * \param vq pointer to the virtqueue structure
196 *
197 * \returns 0 the queue is not full
198 *          1 the queue is full
199 */
200bool virtio_virtqueue_is_full(struct virtqueue *vq);
201
202/**
203 * \brief Calculates the number of used descriptors in this queue
204 *
205 * \param vq pointer to the virtqueue structure
206 *
207 * \returns number of used descriptors
208 */
209uint16_t virtio_virtqueue_get_num_used(struct virtqueue *vq);
210
211/**
212 * \brief returns the number of bits if there are alrady allocated buffers
213 *        for this queue
214 *
215 * \param vq the virtqueue
216 *
217 * \returns size of allocated buffers
218 *          0 if none
219 */
220uint8_t virtio_virtqueue_has_buffers(struct virtqueue *vq);
221
222/**
223 * \brief returns the virtual base of the previously allocated buffer
224 *
225 * \param vq the virtqueue
226 *
227 * \returns virtual address of allocated buffers
228 *          0 if no buffers are allocated
229 */
230lvaddr_t virtio_virtqueue_buffer_vbase(struct virtqueue *vq);
231
232/*
233 * ===========================================================================
234 * Interrupt handling
235 */
236
237/**
238 * \brief enables the interrupts on the next descriptor processed
239 *
240 * \param vq the virtqueue to enable the interrupts
241 *
242 * \returns 1 if the interrupts have been enabled
243 *          0 if the interrupts have not been enabled
244 */
245bool virtio_virtqueue_intr_enable(struct virtqueue *vq);
246
247/**
248 * \brief postpones the interrupt to a later point of time
249 *
250 * \param vq the virtqueue to enable the interrupts
251 * \param
252 *
253 * \returns 1 if the interrupts have been enabled
254 *          0 if the interrupts have not been enabled
255 */
256bool virtio_virtqueue_intr_postpone(struct virtqueue *vq,
257                                    enum virtqueue_intr_postpone hint);
258
259/**
260 * \brief checks if the interrupts can be disabled
261 *
262 * \param vq virtual queue to check
263 *
264 * \returns 1 if the interrupts have been disabled
265 *          0 if the interrupts are not changed
266 *
267 */
268bool virtio_virtqueue_intr_filter(struct virtqueue *vq);
269
270/**
271 * \brief calls the interrupt handler for this virtqueue
272 *
273 * \param vq virtqueue to call the intr handler for
274 */
275void virtio_virtqueue_intr_handle(struct virtqueue *vq);
276
277/**
278 * \brief disables the interrupts for the given virtqueue by giving a hint
279 *        to the host
280 *
281 * \param vq        virtqueue to disable the interrupts
282 */
283void virtio_virtqueue_intr_disable(struct virtqueue *vq);
284
285
286/**
287 * \brief notifies the host about the new queued descriptors
288 *
289 * \param vq virtqueue to notify the host
290 */
291void virtio_virtqueue_notify_host(struct virtqueue *vq);
292
293
294/**
295 * \brief masks the ring features out of a features bit mask
296 *
297 * \param features  the features to mask
298 *
299 * \returns bitmask of masked features
300 */
301static inline uint64_t virtio_virtqueue_mask_features(uint64_t features)
302{
303    uint64_t mask;
304
305    mask = (1 << VIRTIO_TRANSPORT_F_START) - 1;
306    mask |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
307    mask |= (1 <<VIRTIO_RING_F_EVENT_IDX);
308
309    return (features & mask);
310}
311
312/*
313 * ===========================================================================
314 * Virtqueue Queue Management
315 */
316
317/**
318 * \brief Enqueues a new descriptor chain into the virtqueue
319 *
320 * \param vq     the virtqueue the descriptor chain gets enqueued in
321 * \param bl     list of buffers to enqueue into the virtqueue
322 * \param st     state associated with this descriptor chain
323 * \param num_wr number of writable descriptors
324 * \param num_rd number of readable descriptors
325 *
326 * \returns SYS_ERR_OK on success
327 *          VIRTIO_ERR_* on failure
328 */
329errval_t virtio_virtqueue_desc_enqueue(struct virtqueue *vq,
330                                       struct virtio_buffer_list *bl,
331                                       void *st,
332                                       uint16_t writeable,
333                                       uint16_t readable);
334
335/**
336 * \brief dequeues a descriptor chain form the virtqueue
337 *
338 * \param vq     the virtqueue to dequeue descriptors from
339 * \param ret_bl returns the associated buffer list structure
340 * \param ret_st returns the associated state of the queue list
341 *
342 * \returns SYS_ERR_OK when the dequeue is successful
343 *          VIRTIO_ERR_NO_DESC_AVAIL when there was no descriptor to dequeue
344 *          VIRTIO_ERR_* if there was an error
345 */
346errval_t virtio_virtqueue_desc_dequeue(struct virtqueue *vq,
347                                       struct virtio_buffer_list **ret_bl,
348                                       void **ret_st);
349
350
351/**
352 * \brief polls the virtqueue
353 *
354 * \param vq         the virtqueue to dequeue descriptors from
355 * \param ret_bl     returns the associated buffer list structure
356 * \param ret_st     returns the associated state of the queue list
357 * \param handle_msg flag to have messages handled
358 *
359 * \returns SYS_ERR_OK when the dequeue is successful
360 *          VIRTIO_ERR_* if there was an error
361 */
362errval_t virtio_virtqueue_poll(struct virtqueue *vq,
363                               struct virtio_buffer_list **ret_bl,
364                               void **ret_st,
365                               uint8_t handle_msg);
366
367/**
368 * \brief returns a buffer allocator based on the buffers with the virtqueue
369 *        (if any)
370 *
371 * \param vq the virtqueue to get the buffer allocator
372 * \param alloc returns the pointer to the allocator
373 *
374 * \returns SYS_ERR_OK on SUCCESS
375 *          VIRTIO_ERR_BUFFER_SIZE if there are no buffers allocated
376 */
377errval_t virtio_virtqueue_get_buf_alloc(struct virtqueue *vq,
378                                        struct virtio_buffer_allocator **alloc);
379
380#endif // VIRTIO_VIRTQUEUE_H
381