1 /* virtio-pci.c - virtio ring management
3 * (c) Copyright 2008 Bull S.A.S.
5 * Author: Laurent Vivier <Laurent.Vivier@bull.net>
7 * some parts from Linux Virtio Ring
9 * Copyright Rusty Russell IBM Corporation 2007
11 * This work is licensed under the terms of the GNU GPL, version 2 or later.
12 * See the COPYING file in the top-level directory.
17 FILE_LICENCE ( GPL2_OR_LATER );
19 #include "etherboot.h"
21 #include "ipxe/virtio-ring.h"
22 #include "ipxe/virtio-pci.h"
25 printf("BUG: failure at %s:%d/%s()!\n", \
26 __FILE__, __LINE__, __FUNCTION__); \
29 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
34 * put at the begin of the free list the current desc[head]
37 void vring_detach(struct vring_virtqueue *vq, unsigned int head)
39 struct vring *vr = &vq->vring;
42 /* find end of given descriptor */
45 while (vr->desc[i].flags & VRING_DESC_F_NEXT)
48 /* link it with free list and point to it */
50 vr->desc[i].next = vq->free_head;
58 * get a buffer from the used list
62 void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
64 struct vring *vr = &vq->vring;
65 struct vring_used_elem *elem;
69 BUG_ON(!vring_more_used(vq));
71 elem = &vr->used->ring[vq->last_used_idx % vr->num];
77 opaque = vq->vdata[id];
86 void vring_add_buf(struct vring_virtqueue *vq,
87 struct vring_list list[],
88 unsigned int out, unsigned int in,
89 void *opaque, int num_added)
91 struct vring *vr = &vq->vring;
92 int i, avail, head, prev;
94 BUG_ON(out + in == 0);
98 for (i = head; out; i = vr->desc[i].next, out--) {
100 vr->desc[i].flags = VRING_DESC_F_NEXT;
101 vr->desc[i].addr = (u64)virt_to_phys(list->addr);
102 vr->desc[i].len = list->length;
106 for ( ; in; i = vr->desc[i].next, in--) {
108 vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
109 vr->desc[i].addr = (u64)virt_to_phys(list->addr);
110 vr->desc[i].len = list->length;
114 vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
118 vq->vdata[head] = opaque;
120 avail = (vr->avail->idx + num_added) % vr->num;
121 vr->avail->ring[avail] = head;
125 void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
127 struct vring *vr = &vq->vring;
130 vr->avail->idx += num_added;
133 if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
134 vp_notify(ioaddr, vq->queue_index);