2 * Copyright (c) 2014 ETH Zurich.
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.
11 #include <barrelfish/barrelfish.h>
13 #include <virtio/virtio.h>
14 #include <virtio/virtio_ring.h>
15 #include <virtio/virtqueue.h>
20 #define IS_POW2(num) (((num) != 0) && (((num) & (~(num) + 1)) == (num)))
23 #define VIRTQUEUE_FLAG_INDIRECT 0x0001
24 #define VIRTQUEUE_FLAG_EVENT_IDX 0x0002
27 * this data structure stores additional information to the descriptors
29 struct vring_desc_info
31 void *buf; ///< virtual address of this descriptor
32 struct capref cap; ///< capability of this descriptor
33 size_t size; ///< the size of the capability in bytes
34 lpaddr_t paddr; ///< physical address of this descriptor
35 lpaddr_t offset; ///< offset into the capability for mapping
39 * this data structure represents a VirtIO queue. It contains additional
40 * information not stored with the vring structure
44 /* device information */
45 struct virtio_device *device; ///< pointer to to the virtio device
46 uint16_t queue_index; ///< index of this queue in the device
47 char name[VIRTQUEUE_NAME_SIZE]; ///< name of the queue for debugging
49 /* vring information */
50 struct vring vring; ///< vring data structure
51 uint16_t vring_ndesc; ///< number of descriptors of this vring
52 uint32_t flags; ///< flags
53 uint16_t free_head; ///< head of the free descriptor chain
54 uint16_t free_count; ///< number of available free descriptors
55 uint16_t used_tail; ///< last consumed descriptor used table
56 uint16_t used_count; ///< number of queued used descriptors
58 /* vring memory information */
59 struct capref vring_cap; ///< capability of the vring data structure
60 lvaddr_t vring_vaddr; ///< virtual address of the vring in memory
61 lpaddr_t vring_paddr; ///< physical address of the vring
62 size_t vring_size; ///< the size of the vring in memory
63 lvaddr_t vring_align; ///< the alignment of the vring
65 /* interrupt handling */
66 virtq_intr_hander_t intr_handler; ///< interrupt handler
67 void *intr_arg; ///< user argument for the handler
69 struct vring_desc_info vring_di[0]; ///< array of additional desc information
71 /* indirect descriptors */
72 uint16_t max_indirect;
74 struct vq_desc_extra {
75 void *cookie; << virtual address?
76 struct vring_desc *indirect;
77 vm_paddr_t indirect_paddr;
84 * \brief sets the interrupt threshold to num_desc processed descriptors
86 * \param vq virtqueue to enable the interrupts
87 * \param num_desc the interrupt threshold
89 * \returns 1 if the interrupts have been enabled
90 * 0 if the interrupts have not been enabled
92 static bool virtqueue_interrupt_enable(struct virtqueue *vq,
95 if (vq->flags & VIRTQUEUE_FLAG_EVENT_IDX) {
96 uint16_t *used_event = vring_get_used_event(&vq->vring);
97 *used_event = vq->used_tail + num_desc;
99 vq->vring.avail->flags &= ~VIRTIO_RING_AVAIL_F_NO_INTERRUPT;
102 assert(!"NYI: memory barrier mb()");
104 if (virtio_virtqueue_get_num_used(vq) > num_desc) {
113 * \brief initializes the vring structure of the virtqueue
115 * \param vq virtqueue of the vring to initialize
117 static void virtqueue_init_vring(struct virtqueue *vq)
119 struct vring *vr = &vq->vring;
122 assert(vq->vring_ndesc);
123 assert(vq->vring_vaddr);
126 * initialize the vring structure in memory
128 vring_init(vr, vq->vring_ndesc, vq->vring_align, (void *)vq->vring_vaddr);
131 * initialize the descriptor chains
134 for (i = 0; i < vq->vring_ndesc; ++i) {
135 vr->desc[i].next = i+1;
137 vr->desc[i].next = VIRTQUEUE_CHAIN_END;
143 * ============================================================================
145 * ============================================================================
150 * ----------------------------------------------------------------------------
151 * Virtqueue Allocation / Deallocation
155 * \brief allocates and initiates a new virtqueue structure
157 * \param setup pointer to the setup information
158 * \param vq pointer where to store the new virtqueue pointer
160 * \returns SYS_ERR_OK on success
162 errval_t virtio_virtqueue_alloc(struct virtqueue_setup *setup,
163 struct virtqueue **vq)
169 if (setup->vring_ndesc == 0 || !IS_POW2(setup->vring_ndesc)) {
170 VIRTIO_DEBUG_VQ("ERROR: invalid size: %u\n", setup->vring_ndesc);
171 return VIRTIO_ERR_SIZE_INVALID;
174 size_t size = vring_size(setup->vring_ndesc, setup->vring_align);
175 size = ROUND_UP(size, BASE_PAGE_SIZE);
177 struct capref vring_cap;
179 err = frame_alloc(&vring_cap, size, &framesize);
180 if (err_is_fail(err)) {
184 VIRTIO_DEBUG_VQ("Allocated memory for vring: [%lx & %lx]",
185 (uint64_t)size, (uint64_t)framesize);
187 err = virtio_virtqueue_alloc_with_caps(setup, vring_cap, vq);
188 if (err_is_fail(err)) {
189 cap_destroy(vring_cap);
197 * \brief allocates and initiates a new virtqueue structure
199 * \param setup pointer to the setup information
200 * \param vring_cap capability to be used for the vring
201 * \param vq pointer where to store the new virtqueue pointer
203 * \returns SYS_ERR_OK on success
205 errval_t virtio_virtqueue_alloc_with_caps(struct virtqueue_setup *setup,
206 struct capref vring_cap,
207 struct virtqueue **ret_vq)
213 if (setup->vring_ndesc == 0 || !IS_POW2(setup->vring_ndesc)) {
214 VIRTIO_DEBUG_VQ("ERROR: invalid size: %u\n", setup->vring_ndesc);
215 return VIRTIO_ERR_SIZE_INVALID;
218 if (setup->max_indirect > VIRTIO_RING_MAX_INDIRECT) {
219 VIRTIO_DEBUG_VQ("ERROR: too many indirect descriptors requested: [%u / %u]\n", setup->vring_ndesc, VIRTIO_RING_MAX_INDIRECT);
220 return VIRTIO_ERR_MAX_INDIRECT;
223 assert(!capref_is_null(vring_cap));
225 struct frame_identity id;
226 err = invoke_frame_identify(vring_cap, &id);
227 if (err_is_fail(err)) {
231 size_t vring_mem_size = vring_size(setup->vring_ndesc, setup->vring_align);
232 vring_mem_size = ROUND_UP(vring_mem_size, BASE_PAGE_SIZE);
234 if (vring_mem_size > (1UL << id.bits)) {
235 VIRTIO_DEBUG_VQ("ERROR: supplied cap was too small %lx, needed %lx\n",
236 ((1UL << id.bits)), (uint64_t)vring_mem_size);
237 return VIRTIO_ERR_CAP_SIZE;
241 err = vspace_map_one_frame(&vring_addr, vring_mem_size, vring_cap, NULL, NULL);
242 if (err_is_fail(err)) {
246 struct virtqueue *vq = calloc(1, sizeof(struct virtqueue)
247 + (setup->vring_ndesc * sizeof(struct vring_desc_info)));
249 vspace_unmap(vring_addr);
250 return LIB_ERR_MALLOC_FAIL;
253 vq->device = setup->device;
254 strncpy(vq->name, setup->name, sizeof(vq->name));
255 vq->queue_index = setup->queue_id;
256 vq->vring_ndesc = setup->vring_ndesc;
257 vq->vring_align = setup->vring_align;
258 vq->vring_size = vring_mem_size;
259 vq->vring_cap = vring_cap;
260 vq->vring_paddr = id.base;
261 vq->vring_vaddr = (lvaddr_t)vring_addr;
262 vq->free_count = setup->vring_ndesc;
265 vq->intr_handler = setup->intr_handler;
266 vq->intr_arg = setup->intr_arg;
268 if (setup->max_indirect > 0) {
270 * TODO: initialize indirect descriptors
275 if (VIRTIO_BUS_WITH_FEATURE(dev, VIRTIO_RING_F_EVENT_IDX) != 0)
276 vq->vq_flags |= VIRTQUEUE_FLAG_EVENT_IDX;
279 virtqueue_init_vring(vq);
280 virtio_virtqueue_intr_disable(vq);
291 * \brief frees the resources of previously allocated virtqueues
293 * \param vq pointer to the virtqueue memory to be freed
295 * \returns SYS_ERR_OK on success
297 errval_t virtio_virtqueue_free(struct virtqueue *vq)
299 assert(!"NYI: virtio_virtqueue_free");
305 * ----------------------------------------------------------------------------
306 * Virtqueue Getter Functions
310 * \brief Returns the physical address of the vring.
312 * \param vq pointer to the virtqueue structure
314 * \returns the physical address of the vring
316 lpaddr_t virtio_virtqueue_get_vring_paddr(struct virtqueue *vq)
318 return vq->vring_paddr;
322 * \brief returns the alignment of the vring
324 * \param the virtqueue to get the alignment from
326 * \returns vring alignment
328 lvaddr_t virtio_virtqueue_get_vring_align(struct virtqueue *vq)
330 return vq->vring_align;
334 * \brief Returns the frame capability of the vring
336 * \param vq pointer to the virtqueue structure
337 * \param ret_cap memory location where to store the capref
339 void virtio_virtqueue_get_vring_cap(struct virtqueue *vq,
340 struct capref *ret_cap)
343 *ret_cap = vq->vring_cap;
348 * \brief Returns the number of elements (number of descriptors)in the vring of
351 * \param vq pointer to the virtqueue structure
353 * \returns number of elements in the vring
355 uint16_t virtio_virtqueue_get_num_desc(struct virtqueue *vq)
357 return vq->vring_ndesc;
361 * \brief Returns the queue index of the virtqueue of the device
363 * \param vq pointer to the virtqueue structure
365 * \returns queue index
367 uint16_t virtio_virtqueue_get_queue_index(struct virtqueue *vq)
369 return vq->queue_index;
374 * \brief Checks if the virtqueue is empty
376 * \param vq pointer to the virtqueue structure
378 * \returns 0 the queue is not empty
379 * 1 the queue is empty
381 bool virtio_virtqueue_is_empty(struct virtqueue *vq)
383 return (vq->vring_ndesc == vq->free_count);
387 * \brief Checks if the virtqueue is full
389 * \param vq pointer to the virtqueue structure
391 * \returns 0 the queue is not full
392 * 1 the queue is full
394 bool virtio_virtqueue_is_full(struct virtqueue *vq)
396 return (vq->free_count == 0);
400 * \brief Calculates the number of used descriptors in this queue
402 * \param vq pointer to the virtqueue structure
404 * \returns number of used descriptors
406 uint16_t virtio_virtqueue_get_num_used(struct virtqueue *vq)
410 num_used = vq->vring.used->idx - vq->used_tail;
413 assert(num_used <= vq->vring_ndesc);
419 * ----------------------------------------------------------------------------
424 * \brief checks if the interrupts can be disabled
426 * \param vq virtual queue to check
428 * \returns 1 if the interrupts have been disabled
429 * 0 if the interrupts are not changed
432 bool virtio_virtqueue_intr_filter(struct virtqueue *vq)
434 if (vq->used_tail == vq->vring.used->idx) {
438 virtio_virtqueue_intr_disable(vq);
444 * \brief calls the interrupt handler for this virtqueue
446 * \param vq virtqueue to call the intr handler for
448 void virtio_virtqueue_intr_handle(struct virtqueue *vq)
450 if (vq->intr_handler == NULL) {
451 VIRTIO_DEBUG_VQ("Notice: Interrupt handler is not set\n");
454 vq->intr_handler(vq, vq->intr_arg);
459 * \brief enables the interrupts on the next descriptor processed
461 * \param vq the virtqueue to enable the interrupts
463 * \returns 1 if the interrupts have been enabled
464 * 0 if the interrupts have not been enabled
466 bool virtio_virtqueue_intr_enable(struct virtqueue *vq)
468 return virtqueue_interrupt_enable(vq, 0);
472 * \brief postpones the interrupt to a later point of time
474 * \param vq the virtqueue to enable the interrupts
477 * \returns 1 if the interrupts have been enabled
478 * 0 if the interrupts have not been enabled
480 bool virtio_virtqueue_intr_postpone(struct virtqueue *vq,
481 enum virtqueue_intr_postpone hint)
483 uint16_t ndesc = vq->vring.avail->idx - vq->used_tail;
486 case VIRTQUEUE_INTR_POSTPONE_SHORT:
489 case VIRTQUEUE_INTR_POSTPONE_LONG:
490 ndesc = (ndesc * 3) / 4;
492 case VIRTQUEUE_INTR_POSTPONE_EMPTIED:
496 return virtqueue_interrupt_enable(vq, ndesc);
501 * \brief disables the interrupts for the given virtqueue
503 * \param vq virtqueue to disable the interrupts
505 void virtio_virtqueue_intr_disable(struct virtqueue *vq)
507 if (vq->flags & VIRTQUEUE_FLAG_EVENT_IDX) {
508 uint16_t *used_event = vring_get_used_event(&vq->vring);
509 *used_event = vq->used_tail - vq->vring_ndesc - 1;
511 vq->vring.avail->flags |= VIRTIO_RING_AVAIL_F_NO_INTERRUPT;
516 * \brief notifies the host about the new queued descriptors
518 * \param vq virtqueue to notify the host
520 void virtio_virtqueue_notify_host(struct virtqueue *vq)
522 assert(!"NYI: host notify");
527 * We layout the vring structure in memory as follows:
530 * // The actual descriptors (16 bytes each)
531 * struct vring_desc desc[num];
533 * // A ring of available descriptor heads with free-running index.
534 * uint16_t avail_flags;
535 * uint16_t avail_idx;
536 * uint16_t available[num];
537 * uint16_t used_event_idx;
539 * // Padding to the next align boundary.
542 * // A ring of used descriptor heads with free-running index.
543 * uint16_t used_flags;
545 * struct vring_used_elem used[num];
546 * uint16_t avail_event_idx;
551 * \brief Maps the given capability and initializes the vring on the memory
552 * backed by the supplied capability
554 * \param vr pointer to the vring structure to be initialized
555 * \param num the number of elements in the ring
556 * \param align alignment constraints for the vring
557 * \param cap frame capability used as backing memory for the structure
559 * \return SYS_ERR_OK on success
562 errval_t vring_init_from_cap(struct vring *vr,
569 /* num must be a power of two */
570 assert(((num != 0) && ((num & (~num + 1)) == num)));
572 size_t size = vring_size(num, align);
574 struct frame_identity id;
575 err = invoke_frame_identify(cap, &id);
576 if (err_is_fail(err)) {
577 return err_push(err, LIB_ERR_FRAME_IDENTIFY);
580 /* check if we have enough space in the given cap */
581 if ((1UL << id.bits) < size) {
582 return SYS_ERR_INVALID_SIZE_BITS;
586 err = vspace_map_one_frame(&addr, (1UL << id.bits), cap, NULL, NULL);
587 if (err_is_fail(err)) {
588 return err_push(err, LIB_ERR_VSPACE_MAP);
591 vring_init(vr, num, align, addr);
597 * \brief allocates a new vring structure
599 * \param vr pointer to the vring structure
600 * \param num the number of queue elements
601 * \param align the alignment constraints for the vring
602 * \param ret_frame returned frame capability
604 * \return SYS_ERR_OK on success
607 errval_t vring_alloc(struct vring *vr,
610 struct capref *ret_frame)
614 /* num must be a power of two */
615 assert(((num != 0) && ((num & (~num + 1)) == num)));
617 size_t size = vring_size(num, align);
620 err = frame_alloc(&frame, size, &size);
621 if (err_is_fail(err)) {
625 err = vring_init_from_cap(vr, num, align, frame);
626 if (err_is_fail(err)) {
638 * \brief frees the resources used by the vring structure
640 * \param vr the vring to be freed
642 * \return SYS_ERR_OK on success
645 errval_t vring_free(struct vring *vr)
649 err = vspace_unmap(vr->desc);
650 if (err_is_fail(err)) {
654 assert(!"NYI: returning the cap to the origin");
659 * ----------------------------------------------------------------------------
668 errval_t virtio_virtqueue_desc_alloc(struct virtqueue *vq,
671 errval_t virtio_virtqueue_desc_enq(struct virtqueue *vq,
674 assert(!"NYI: virtio_virtqueue_enq");
678 void *virtio_virtqueue_desc_deq(struct virtqueue *vq)
685 void *virtio_virtqueue_poll(struct virtqueue *vq)