virtio-ring.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "etherboot.h"
00018 #include "gpxe/io.h"
00019 #include "gpxe/virtio-ring.h"
00020 #include "gpxe/virtio-pci.h"
00021
00022 #define BUG() do { \
00023 printf("BUG: failure at %s:%d/%s()!\n", \
00024 __FILE__, __LINE__, __FUNCTION__); \
00025 while(1); \
00026 } while (0)
00027 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
00028
00029
00030
00031
00032
00033
00034
00035 void vring_detach(struct vring_virtqueue *vq, unsigned int head)
00036 {
00037 struct vring *vr = &vq->vring;
00038 unsigned int i;
00039
00040
00041
00042 i = head;
00043 while (vr->desc[i].flags & VRING_DESC_F_NEXT)
00044 i = vr->desc[i].next;
00045
00046
00047
00048 vr->desc[i].next = vq->free_head;
00049 wmb();
00050 vq->free_head = head;
00051 }
00052
00053
00054
00055
00056
00057
00058
00059
00060 int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
00061 {
00062 struct vring *vr = &vq->vring;
00063 struct vring_used_elem *elem;
00064 u32 id;
00065 int ret;
00066
00067 BUG_ON(!vring_more_used(vq));
00068
00069 elem = &vr->used->ring[vq->last_used_idx % vr->num];
00070 wmb();
00071 id = elem->id;
00072 if (len != NULL)
00073 *len = elem->len;
00074
00075 ret = vq->vdata[id];
00076
00077 vring_detach(vq, id);
00078
00079 vq->last_used_idx++;
00080
00081 return ret;
00082 }
00083
00084 void vring_add_buf(struct vring_virtqueue *vq,
00085 struct vring_list list[],
00086 unsigned int out, unsigned int in,
00087 int index, int num_added)
00088 {
00089 struct vring *vr = &vq->vring;
00090 int i, avail, head, prev;
00091
00092 BUG_ON(out + in == 0);
00093
00094 prev = 0;
00095 head = vq->free_head;
00096 for (i = head; out; i = vr->desc[i].next, out--) {
00097
00098 vr->desc[i].flags = VRING_DESC_F_NEXT;
00099 vr->desc[i].addr = (u64)virt_to_phys(list->addr);
00100 vr->desc[i].len = list->length;
00101 prev = i;
00102 list++;
00103 }
00104 for ( ; in; i = vr->desc[i].next, in--) {
00105
00106 vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
00107 vr->desc[i].addr = (u64)virt_to_phys(list->addr);
00108 vr->desc[i].len = list->length;
00109 prev = i;
00110 list++;
00111 }
00112 vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
00113
00114 vq->free_head = i;
00115
00116 vq->vdata[head] = index;
00117
00118 avail = (vr->avail->idx + num_added) % vr->num;
00119 vr->avail->ring[avail] = head;
00120 wmb();
00121 }
00122
00123 void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
00124 {
00125 struct vring *vr = &vq->vring;
00126
00127 wmb();
00128 vr->avail->idx += num_added;
00129
00130 mb();
00131 if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
00132 vp_notify(ioaddr, vq->queue_index);
00133 }
00134