123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- /* virtio-pci.c - virtio ring management
- *
- * (c) Copyright 2008 Bull S.A.S.
- *
- * Author: Laurent Vivier <Laurent.Vivier@bull.net>
- *
- * some parts from Linux Virtio Ring
- *
- * Copyright Rusty Russell IBM Corporation 2007
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- *
- */
-
- #include "etherboot.h"
- #include "gpxe/io.h"
- #include "gpxe/virtio-ring.h"
- #include "gpxe/virtio-pci.h"
-
- #define BUG() do { \
- printf("BUG: failure at %s:%d/%s()!\n", \
- __FILE__, __LINE__, __FUNCTION__); \
- while(1); \
- } while (0)
- #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
-
- /*
- * vring_free
- *
- * put at the begin of the free list the current desc[head]
- */
-
- void vring_detach(struct vring_virtqueue *vq, unsigned int head)
- {
- struct vring *vr = &vq->vring;
- unsigned int i;
-
- /* find end of given descriptor */
-
- i = head;
- while (vr->desc[i].flags & VRING_DESC_F_NEXT)
- i = vr->desc[i].next;
-
- /* link it with free list and point to it */
-
- vr->desc[i].next = vq->free_head;
- wmb();
- vq->free_head = head;
- }
-
- /*
- * vring_get_buf
- *
- * get a buffer from the used list
- *
- */
-
- int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
- {
- struct vring *vr = &vq->vring;
- struct vring_used_elem *elem;
- u32 id;
- int ret;
-
- BUG_ON(!vring_more_used(vq));
-
- elem = &vr->used->ring[vq->last_used_idx % vr->num];
- wmb();
- id = elem->id;
- if (len != NULL)
- *len = elem->len;
-
- ret = vq->vdata[id];
-
- vring_detach(vq, id);
-
- vq->last_used_idx++;
-
- return ret;
- }
-
- void vring_add_buf(struct vring_virtqueue *vq,
- struct vring_list list[],
- unsigned int out, unsigned int in,
- int index, int num_added)
- {
- struct vring *vr = &vq->vring;
- int i, avail, head, prev;
-
- BUG_ON(out + in == 0);
-
- prev = 0;
- head = vq->free_head;
- for (i = head; out; i = vr->desc[i].next, out--) {
-
- vr->desc[i].flags = VRING_DESC_F_NEXT;
- vr->desc[i].addr = (u64)virt_to_phys(list->addr);
- vr->desc[i].len = list->length;
- prev = i;
- list++;
- }
- for ( ; in; i = vr->desc[i].next, in--) {
-
- vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
- vr->desc[i].addr = (u64)virt_to_phys(list->addr);
- vr->desc[i].len = list->length;
- prev = i;
- list++;
- }
- vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
-
- vq->free_head = i;
-
- vq->vdata[head] = index;
-
- avail = (vr->avail->idx + num_added) % vr->num;
- vr->avail->ring[avail] = head;
- wmb();
- }
-
- void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added)
- {
- struct vring *vr = &vq->vring;
-
- wmb();
- vr->avail->idx += num_added;
-
- mb();
- if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
- vp_notify(ioaddr, vq->queue_index);
- }
|