|
|
1.1 ! root 1: /* virtio-pci.c - virtio ring management ! 2: * ! 3: * (c) Copyright 2008 Bull S.A.S. ! 4: * ! 5: * Author: Laurent Vivier <[email protected]> ! 6: * ! 7: * some parts from Linux Virtio Ring ! 8: * ! 9: * Copyright Rusty Russell IBM Corporation 2007 ! 10: * ! 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. ! 13: * ! 14: * ! 15: */ ! 16: ! 17: FILE_LICENCE ( GPL2_OR_LATER ); ! 18: ! 19: #include "etherboot.h" ! 20: #include "ipxe/io.h" ! 21: #include "ipxe/virtio-ring.h" ! 22: #include "ipxe/virtio-pci.h" ! 23: ! 24: #define BUG() do { \ ! 25: printf("BUG: failure at %s:%d/%s()!\n", \ ! 26: __FILE__, __LINE__, __FUNCTION__); \ ! 27: while(1); \ ! 28: } while (0) ! 29: #define BUG_ON(condition) do { if (condition) BUG(); } while (0) ! 30: ! 31: /* ! 32: * vring_free ! 33: * ! 34: * put at the begin of the free list the current desc[head] ! 35: */ ! 36: ! 37: void vring_detach(struct vring_virtqueue *vq, unsigned int head) ! 38: { ! 39: struct vring *vr = &vq->vring; ! 40: unsigned int i; ! 41: ! 42: /* find end of given descriptor */ ! 43: ! 44: i = head; ! 45: while (vr->desc[i].flags & VRING_DESC_F_NEXT) ! 46: i = vr->desc[i].next; ! 47: ! 48: /* link it with free list and point to it */ ! 49: ! 50: vr->desc[i].next = vq->free_head; ! 51: wmb(); ! 52: vq->free_head = head; ! 53: } ! 54: ! 55: /* ! 56: * vring_get_buf ! 57: * ! 58: * get a buffer from the used list ! 59: * ! 60: */ ! 61: ! 62: void *vring_get_buf(struct vring_virtqueue *vq, unsigned int *len) ! 63: { ! 64: struct vring *vr = &vq->vring; ! 65: struct vring_used_elem *elem; ! 66: u32 id; ! 67: void *opaque; ! 68: ! 69: BUG_ON(!vring_more_used(vq)); ! 70: ! 71: elem = &vr->used->ring[vq->last_used_idx % vr->num]; ! 72: wmb(); ! 73: id = elem->id; ! 74: if (len != NULL) ! 75: *len = elem->len; ! 76: ! 77: opaque = vq->vdata[id]; ! 78: ! 79: vring_detach(vq, id); ! 80: ! 81: vq->last_used_idx++; ! 82: ! 83: return opaque; ! 84: } ! 85: ! 86: void vring_add_buf(struct vring_virtqueue *vq, ! 87: struct vring_list list[], ! 88: unsigned int out, unsigned int in, ! 89: void *opaque, int num_added) ! 90: { ! 91: struct vring *vr = &vq->vring; ! 92: int i, avail, head, prev; ! 93: ! 94: BUG_ON(out + in == 0); ! 95: ! 96: prev = 0; ! 97: head = vq->free_head; ! 98: for (i = head; out; i = vr->desc[i].next, out--) { ! 99: ! 100: vr->desc[i].flags = VRING_DESC_F_NEXT; ! 101: vr->desc[i].addr = (u64)virt_to_phys(list->addr); ! 102: vr->desc[i].len = list->length; ! 103: prev = i; ! 104: list++; ! 105: } ! 106: for ( ; in; i = vr->desc[i].next, in--) { ! 107: ! 108: vr->desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; ! 109: vr->desc[i].addr = (u64)virt_to_phys(list->addr); ! 110: vr->desc[i].len = list->length; ! 111: prev = i; ! 112: list++; ! 113: } ! 114: vr->desc[prev].flags &= ~VRING_DESC_F_NEXT; ! 115: ! 116: vq->free_head = i; ! 117: ! 118: vq->vdata[head] = opaque; ! 119: ! 120: avail = (vr->avail->idx + num_added) % vr->num; ! 121: vr->avail->ring[avail] = head; ! 122: wmb(); ! 123: } ! 124: ! 125: void vring_kick(unsigned int ioaddr, struct vring_virtqueue *vq, int num_added) ! 126: { ! 127: struct vring *vr = &vq->vring; ! 128: ! 129: wmb(); ! 130: vr->avail->idx += num_added; ! 131: ! 132: mb(); ! 133: if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY)) ! 134: vp_notify(ioaddr, vq->queue_index); ! 135: } ! 136:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.