Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / src / 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  *  Adopted for Seabios: Gleb Natapov <gleb@redhat.com>
12  *
13  * This work is licensed under the terms of the GNU LGPLv3
14  * See the COPYING file in the top-level directory.
15  *
16  *
17  */
18
19 #include "virtio-ring.h"
20 #include "virtio-pci.h"
21 #include "biosvar.h" // GET_GLOBAL
22 #include "util.h" // dprintf
23
24 #define BUG() do {                                      \
25         dprintf(1, "BUG: failure at %s:%d/%s()!\n",     \
26                 __FILE__, __LINE__, __func__);          \
27                 while(1);                               \
28         } while (0)
29 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
30
31 /*
32  * vring_more_used
33  *
34  * is there some used buffers ?
35  *
36  */
37
38 int vring_more_used(struct vring_virtqueue *vq)
39 {
40     struct vring_used *used = GET_FLATPTR(vq->vring.used);
41     int more = GET_FLATPTR(vq->last_used_idx) != GET_FLATPTR(used->idx);
42     /* Make sure ring reads are done after idx read above. */
43     smp_rmb();
44     return more;
45 }
46
47 /*
48  * vring_free
49  *
50  * put at the begin of the free list the current desc[head]
51  */
52
53 void vring_detach(struct vring_virtqueue *vq, unsigned int head)
54 {
55     struct vring *vr = &vq->vring;
56     struct vring_desc *desc = GET_FLATPTR(vr->desc);
57     unsigned int i;
58
59     /* find end of given descriptor */
60
61     i = head;
62     while (GET_FLATPTR(desc[i].flags) & VRING_DESC_F_NEXT)
63         i = GET_FLATPTR(desc[i].next);
64
65     /* link it with free list and point to it */
66
67     SET_FLATPTR(desc[i].next, GET_FLATPTR(vq->free_head));
68     SET_FLATPTR(vq->free_head, head);
69 }
70
71 /*
72  * vring_get_buf
73  *
74  * get a buffer from the used list
75  *
76  */
77
78 int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
79 {
80     struct vring *vr = &vq->vring;
81     struct vring_used_elem *elem;
82     struct vring_used *used = GET_FLATPTR(vq->vring.used);
83     u32 id;
84     int ret;
85
86 //    BUG_ON(!vring_more_used(vq));
87
88     elem = &used->ring[GET_FLATPTR(vq->last_used_idx) % GET_FLATPTR(vr->num)];
89     id = GET_FLATPTR(elem->id);
90     if (len != NULL)
91         *len = GET_FLATPTR(elem->len);
92
93     ret = GET_FLATPTR(vq->vdata[id]);
94
95     vring_detach(vq, id);
96
97     SET_FLATPTR(vq->last_used_idx, GET_FLATPTR(vq->last_used_idx) + 1);
98
99     return ret;
100 }
101
102 void vring_add_buf(struct vring_virtqueue *vq,
103                    struct vring_list list[],
104                    unsigned int out, unsigned int in,
105                    int index, int num_added)
106 {
107     struct vring *vr = &vq->vring;
108     int i, av, head, prev;
109     struct vring_desc *desc = GET_FLATPTR(vr->desc);
110     struct vring_avail *avail = GET_FLATPTR(vr->avail);
111
112     BUG_ON(out + in == 0);
113
114     prev = 0;
115     head = GET_FLATPTR(vq->free_head);
116     for (i = head; out; i = GET_FLATPTR(desc[i].next), out--) {
117         SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT);
118         SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
119         SET_FLATPTR(desc[i].len, list->length);
120         prev = i;
121         list++;
122     }
123     for ( ; in; i = GET_FLATPTR(desc[i].next), in--) {
124         SET_FLATPTR(desc[i].flags, VRING_DESC_F_NEXT|VRING_DESC_F_WRITE);
125         SET_FLATPTR(desc[i].addr, (u64)virt_to_phys(list->addr));
126         SET_FLATPTR(desc[i].len, list->length);
127         prev = i;
128         list++;
129     }
130     SET_FLATPTR(desc[prev].flags,
131                 GET_FLATPTR(desc[prev].flags) & ~VRING_DESC_F_NEXT);
132
133     SET_FLATPTR(vq->free_head, i);
134
135     SET_FLATPTR(vq->vdata[head], index);
136
137     av = (GET_FLATPTR(avail->idx) + num_added) % GET_FLATPTR(vr->num);
138     SET_FLATPTR(avail->ring[av], head);
139 }
140
141 void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
142 {
143     struct vring *vr = &vq->vring;
144     struct vring_avail *avail = GET_FLATPTR(vr->avail);
145
146     /* Make sure idx update is done after ring write. */
147     smp_wmb();
148     SET_FLATPTR(avail->idx, GET_FLATPTR(avail->idx) + num_added);
149
150     vp_notify(ioaddr, GET_FLATPTR(vq->queue_index));
151 }