From: Sasha Levin Date: Mon, 28 Nov 2011 17:54:27 +0000 (+0200) Subject: kvm tools: Support virtio indirect buffers X-Git-Tag: next-20111129~3^2 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=870a88b23331118c7999451a7f5601de517251f2;p=karo-tx-linux.git kvm tools: Support virtio indirect buffers Indirect buffers are ring descriptors which point to more (even more) descriptors. This can be used to increase the effective ring capacity, which helps the guest to batch large requests - very useful for blk devices. This patch also enables indirect buffers for virtio-net and virtio-blk. The patch is based on the lguest's code which does the same. Signed-off-by: Sasha Levin Signed-off-by: Pekka Enberg --- diff --git a/tools/kvm/virtio/blk.c b/tools/kvm/virtio/blk.c index 8c6f90b88f5c..d1a0197d1346 100644 --- a/tools/kvm/virtio/blk.c +++ b/tools/kvm/virtio/blk.c @@ -148,7 +148,8 @@ static u32 get_host_features(struct kvm *kvm, void *dev) { return 1UL << VIRTIO_BLK_F_SEG_MAX | 1UL << VIRTIO_BLK_F_FLUSH - | 1UL << VIRTIO_RING_F_EVENT_IDX; + | 1UL << VIRTIO_RING_F_EVENT_IDX + | 1UL << VIRTIO_RING_F_INDIRECT_DESC; } static void set_guest_features(struct kvm *kvm, void *dev, u32 features) diff --git a/tools/kvm/virtio/core.c b/tools/kvm/virtio/core.c index a6f180ed0a26..fe9d58855439 100644 --- a/tools/kvm/virtio/core.c +++ b/tools/kvm/virtio/core.c @@ -33,27 +33,56 @@ struct vring_used_elem *virt_queue__set_used_elem(struct virt_queue *queue, u32 return used_elem; } +/* + * Each buffer in the virtqueues is actually a chain of descriptors. This + * function returns the next descriptor in the chain, or vq->vring.num if we're + * at the end. + */ +static unsigned next_desc(struct vring_desc *desc, + unsigned int i, unsigned int max) +{ + unsigned int next; + + /* If this descriptor says it doesn't chain, we're done. */ + if (!(desc[i].flags & VRING_DESC_F_NEXT)) + return max; + + /* Check they're not leading us off end of descriptors. */ + next = desc[i].next; + /* Make sure compiler knows to grab that: we don't want it changing! */ + wmb(); + + return next; +} + u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[], u16 *out, u16 *in, u16 head, struct kvm *kvm) { struct vring_desc *desc; u16 idx; + u16 max; idx = head; *out = *in = 0; + max = vq->vring.num; + desc = vq->vring.desc; + + if (desc[idx].flags & VRING_DESC_F_INDIRECT) { + + max = desc[idx].len / sizeof(struct vring_desc); + desc = guest_flat_to_host(kvm, desc[idx].addr); + idx = 0; + } do { - desc = virt_queue__get_desc(vq, idx); - iov[*out + *in].iov_base = guest_flat_to_host(kvm, desc->addr); - iov[*out + *in].iov_len = desc->len; - if (desc->flags & VRING_DESC_F_WRITE) + /* Grab the first descriptor, and check it's OK. */ + iov[*out + *in].iov_len = desc[idx].len; + iov[*out + *in].iov_base = guest_flat_to_host(kvm, desc[idx].addr); + /* If this is an input descriptor, increment that count. */ + if (desc[idx].flags & VRING_DESC_F_WRITE) (*in)++; else (*out)++; - if (desc->flags & VRING_DESC_F_NEXT) - idx = desc->next; - else - break; - } while (1); + } while ((idx = next_desc(desc, idx, max)) != max); return head; } diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c index ce34555e8d54..3fb50541ee45 100644 --- a/tools/kvm/virtio/net.c +++ b/tools/kvm/virtio/net.c @@ -318,7 +318,8 @@ static u32 get_host_features(struct kvm *kvm, void *dev) | 1UL << VIRTIO_NET_F_GUEST_UFO | 1UL << VIRTIO_NET_F_GUEST_TSO4 | 1UL << VIRTIO_NET_F_GUEST_TSO6 - | 1UL << VIRTIO_RING_F_EVENT_IDX; + | 1UL << VIRTIO_RING_F_EVENT_IDX + | 1UL << VIRTIO_RING_F_INDIRECT_DESC; } static void set_guest_features(struct kvm *kvm, void *dev, u32 features)