virtio-ring.c

Go to the documentation of this file.
00001 /* virtio-pci.c - virtio ring management
00002  *
00003  * (c) Copyright 2008 Bull S.A.S.
00004  *
00005  *  Author: Laurent Vivier <Laurent.Vivier@bull.net>
00006  *
00007  *  some parts from Linux Virtio Ring
00008  *
00009  *  Copyright Rusty Russell IBM Corporation 2007
00010  *
00011  * This work is licensed under the terms of the GNU GPL, version 2 or later.
00012  * See the COPYING file in the top-level directory.
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  * vring_free
00031  *
00032  * put at the begin of the free list the current desc[head]
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    /* find end of given descriptor */
00041 
00042    i = head;
00043    while (vr->desc[i].flags & VRING_DESC_F_NEXT)
00044            i = vr->desc[i].next;
00045 
00046    /* link it with free list and point to it */
00047 
00048    vr->desc[i].next = vq->free_head;
00049    wmb();
00050    vq->free_head = head;
00051 }
00052 
00053 /*
00054  * vring_get_buf
00055  *
00056  * get a buffer from the used list
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 

Generated on Tue Apr 6 20:00:52 2010 for gPXE by  doxygen 1.5.7.1