iPXE
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 FILE_LICENCE ( GPL2_OR_LATER );
00018 
00019 #include "etherboot.h"
00020 #include "ipxe/io.h"
00021 #include "ipxe/virtio-pci.h"
00022 #include "ipxe/virtio-ring.h"
00023 
00024 #define BUG() do { \
00025    printf("BUG: failure at %s:%d/%s()!\n", \
00026           __FILE__, __LINE__, __FUNCTION__); \
00027    while(1); \
00028 } while (0)
00029 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
00030 
00031 /*
00032  * vring_free
00033  *
00034  * put at the begin of the free list the current desc[head]
00035  */
00036 
00037 void vring_detach(struct vring_virtqueue *vq, unsigned int head)
00038 {
00039    struct vring *vr = &vq->vring;
00040    unsigned int i;
00041 
00042    /* find end of given descriptor */
00043 
00044    i = head;
00045    while (vr->desc[i].flags & VRING_DESC_F_NEXT)
00046            i = vr->desc[i].next;
00047 
00048    /* link it with free list and point to it */
00049 
00050    vr->desc[i].next = vq->free_head;
00051    wmb();
00052    vq->free_head = head;
00053 }
00054 
00055 /*
00056  * vring_get_buf
00057  *
00058  * get a buffer from the used list
00059  *
00060  */
00061 
00062 void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
00063 {
00064    struct vring *vr = &vq->vring;
00065    struct vring_used_elem *elem;
00066    u32 id;
00067    void *opaque;
00068 
00069    BUG_ON(!vring_more_used(vq));
00070 
00071    elem = &vr->used->ring[vq->last_used_idx % vr->num];
00072    wmb();
00073    id = elem->id;
00074    if (len != NULL)
00075            *len = elem->len;
00076 
00077    opaque = vq->vdata[id];
00078 
00079    vring_detach(vq, id);
00080 
00081    vq->last_used_idx++;
00082 
00083    return opaque;
00084 }
00085 
00086 void vring_add_buf(struct vring_virtqueue *vq,
00087                    struct vring_list list[],
00088                    unsigned int out, unsigned int in,
00089                    void *opaque, int num_added)
00090 {
00091    struct vring *vr = &vq->vring;
00092    int i, avail, head, prev;
00093 
00094    BUG_ON(out + in == 0);
00095 
00096    prev = 0;
00097    head = vq->free_head;
00098    for (i = head; out; i = vr->desc[i].next, out--) {
00099 
00100            vr->desc[i].flags = VRING_DESC_F_NEXT;
00101            vr->desc[i].addr = (u64)virt_to_phys(list->addr);
00102            vr->desc[i].len = list->length;
00103            prev = i;
00104            list++;
00105    }
00106    for ( ; in; i = vr->desc[i].next, in--) {
00107 
00108            vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
00109            vr->desc[i].addr = (u64)virt_to_phys(list->addr);
00110            vr->desc[i].len = list->length;
00111            prev = i;
00112            list++;
00113    }
00114    vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
00115 
00116    vq->free_head = i;
00117 
00118    vq->vdata[head] = opaque;
00119 
00120    avail = (vr->avail->idx + num_added) % vr->num;
00121    vr->avail->ring[avail] = head;
00122    wmb();
00123 }
00124 
00125 void vring_kick(struct virtio_pci_modern_device *vdev, unsigned int ioaddr,
00126                 struct vring_virtqueue *vq, int num_added)
00127 {
00128    struct vring *vr = &vq->vring;
00129 
00130    wmb();
00131    vr->avail->idx += num_added;
00132 
00133    mb();
00134    if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY)) {
00135            if (vdev) {
00136                    /* virtio 1.0 */
00137                    vpm_notify(vdev, vq);
00138            } else {
00139                    /* legacy virtio */
00140                    vp_notify(ioaddr, vq->queue_index);
00141            }
00142    }
00143 }