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 #include "etherboot.h"
19 #include "gpxe/virtio-ring.h"
20 #include "gpxe/virtio-pci.h"
23 printf("BUG: failure at %s:%d/%s()!\n", \
24 __FILE__, __LINE__, __FUNCTION__); \
27 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
32 * put at the begin of the free list the current desc[head]
35 void vring_detach(struct vring_virtqueue
*vq
, unsigned int head
)
37 struct vring
*vr
= &vq
->vring
;
40 /* find end of given descriptor */
43 while (vr
->desc
[i
].flags
& VRING_DESC_F_NEXT
)
46 /* link it with free list and point to it */
48 vr
->desc
[i
].next
= vq
->free_head
;
56 * get a buffer from the used list
60 void *vring_get_buf(struct vring_virtqueue
*vq
, unsigned int *len
)
62 struct vring
*vr
= &vq
->vring
;
63 struct vring_used_elem
*elem
;
67 BUG_ON(!vring_more_used(vq
));
69 elem
= &vr
->used
->ring
[vq
->last_used_idx
% vr
->num
];
75 opaque
= vq
->vdata
[id
];
84 void vring_add_buf(struct vring_virtqueue
*vq
,
85 struct vring_list list
[],
86 unsigned int out
, unsigned int in
,
87 void *opaque
, int num_added
)
89 struct vring
*vr
= &vq
->vring
;
90 int i
, avail
, head
, prev
;
92 BUG_ON(out
+ in
== 0);
96 for (i
= head
; out
; i
= vr
->desc
[i
].next
, out
--) {
98 vr
->desc
[i
].flags
= VRING_DESC_F_NEXT
;
99 vr
->desc
[i
].addr
= (u64
)virt_to_phys(list
->addr
);
100 vr
->desc
[i
].len
= list
->length
;
104 for ( ; in
; i
= vr
->desc
[i
].next
, in
--) {
106 vr
->desc
[i
].flags
= VRING_DESC_F_NEXT
|VRING_DESC_F_WRITE
;
107 vr
->desc
[i
].addr
= (u64
)virt_to_phys(list
->addr
);
108 vr
->desc
[i
].len
= list
->length
;
112 vr
->desc
[prev
].flags
&= ~VRING_DESC_F_NEXT
;
116 vq
->vdata
[head
] = opaque
;
118 avail
= (vr
->avail
->idx
+ num_added
) % vr
->num
;
119 vr
->avail
->ring
[avail
] = head
;
123 void vring_kick(unsigned int ioaddr
, struct vring_virtqueue
*vq
, int num_added
)
125 struct vring
*vr
= &vq
->vring
;
128 vr
->avail
->idx
+= num_added
;
131 if (!(vr
->used
->flags
& VRING_USED_F_NO_NOTIFY
))
132 vp_notify(ioaddr
, vq
->queue_index
);