Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / bus / virtio-ring.c
1 /* virtio-pci.c - virtio ring management
2  *
3  * (c) Copyright 2008 Bull S.A.S.
4  *
5  *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
6  *
7  *  some parts from Linux Virtio Ring
8  *
9  *  Copyright Rusty Russell IBM Corporation 2007
10  *
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.
13  *
14  *
15  */
16
17 FILE_LICENCE ( GPL2_OR_LATER );
18
19 #include "etherboot.h"
20 #include "ipxe/io.h"
21 #include "ipxe/virtio-ring.h"
22 #include "ipxe/virtio-pci.h"
23
24 #define BUG() do { \
25    printf("BUG: failure at %s:%d/%s()!\n", \
26           __FILE__, __LINE__, __FUNCTION__); \
27    while(1); \
28 } while (0)
29 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
30
31 /*
32  * vring_free
33  *
34  * put at the begin of the free list the current desc[head]
35  */
36
37 void vring_detach(struct vring_virtqueue *vq, unsigned int head)
38 {
39    struct vring *vr = &vq->vring;
40    unsigned int i;
41
42    /* find end of given descriptor */
43
44    i = head;
45    while (vr->desc[i].flags & VRING_DESC_F_NEXT)
46            i = vr->desc[i].next;
47
48    /* link it with free list and point to it */
49
50    vr->desc[i].next = vq->free_head;
51    wmb();
52    vq->free_head = head;
53 }
54
55 /*
56  * vring_get_buf
57  *
58  * get a buffer from the used list
59  *
60  */
61
62 void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
63 {
64    struct vring *vr = &vq->vring;
65    struct vring_used_elem *elem;
66    u32 id;
67    void *opaque;
68
69    BUG_ON(!vring_more_used(vq));
70
71    elem = &vr->used->ring[vq->last_used_idx % vr->num];
72    wmb();
73    id = elem->id;
74    if (len != NULL)
75            *len = elem->len;
76
77    opaque = vq->vdata[id];
78
79    vring_detach(vq, id);
80
81    vq->last_used_idx++;
82
83    return opaque;
84 }
85
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)
90 {
91    struct vring *vr = &vq->vring;
92    int i, avail, head, prev;
93
94    BUG_ON(out + in == 0);
95
96    prev = 0;
97    head = vq->free_head;
98    for (i = head; out; i = vr->desc[i].next, out--) {
99
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;
103            prev = i;
104            list++;
105    }
106    for ( ; in; i = vr->desc[i].next, in--) {
107
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;
111            prev = i;
112            list++;
113    }
114    vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
115
116    vq->free_head = i;
117
118    vq->vdata[head] = opaque;
119
120    avail = (vr->avail->idx + num_added) % vr->num;
121    vr->avail->ring[avail] = head;
122    wmb();
123 }
124
125 void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
126 {
127    struct vring *vr = &vq->vring;
128
129    wmb();
130    vr->avail->idx += num_added;
131
132    mb();
133    if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
134            vp_notify(ioaddr, vq->queue_index);
135 }
136