diff options
author | Ladi Prosek | 2016-12-16 14:07:08 +0100 |
---|---|---|
committer | Michael Brown | 2017-01-22 14:22:19 +0100 |
commit | fba3b39900af52e695d59bc34f28bb8d22526ddb (patch) | |
tree | 6b2b6062085e52e545306937e48fcf6af5774cca /src/drivers/bus | |
parent | [virtio] Simplify virtqueue shutdown (diff) | |
download | ipxe-fba3b39900af52e695d59bc34f28bb8d22526ddb.tar.gz ipxe-fba3b39900af52e695d59bc34f28bb8d22526ddb.tar.xz ipxe-fba3b39900af52e695d59bc34f28bb8d22526ddb.zip |
[virtio] Remove queue size limit in legacy virtio
Virtio 0.9 implementation was limited to the maximum virtqueue size of
MAX_QUEUE_NUM and the virtio-net driver would fail to initialize on hosts
exceeding this limit.
This commit lifts the restriction by allocating the queue memory based on
the actual queue size instead of using a fixed maximum. Note that virtio
1.0 still uses the MAX_QUEUE_NUM constant to cap the size (unfortunately
this functionality is not available in virtio 0.9).
Signed-off-by: Ladi Prosek <lprosek@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/bus')
-rw-r--r-- | src/drivers/bus/virtio-pci.c | 48 |
1 files changed, 39 insertions, 9 deletions
diff --git a/src/drivers/bus/virtio-pci.c b/src/drivers/bus/virtio-pci.c index c50602a3..402bf4f1 100644 --- a/src/drivers/bus/virtio-pci.c +++ b/src/drivers/bus/virtio-pci.c @@ -21,11 +21,37 @@ #include "ipxe/virtio-pci.h" #include "ipxe/virtio-ring.h" +static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num) +{ + size_t queue_size = PAGE_MASK + vring_size(num); + size_t vdata_size = num * sizeof(void *); + + vq->queue = zalloc(queue_size + vdata_size); + if (!vq->queue) { + return -ENOMEM; + } + + /* vdata immediately follows the ring */ + vq->vdata = (void **)(vq->queue + queue_size); + + return 0; +} + +void vp_free_vq(struct vring_virtqueue *vq) +{ + if (vq->queue) { + free(vq->queue); + vq->queue = NULL; + vq->vdata = NULL; + } +} + int vp_find_vq(unsigned int ioaddr, int queue_index, struct vring_virtqueue *vq) { struct vring * vr = &vq->vring; u16 num; + int rc; /* select the queue */ @@ -39,11 +65,6 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, return -1; } - if (num > MAX_QUEUE_NUM) { - DBG("VIRTIO-PCI ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); - return -1; - } - /* check if the queue is already active */ if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { @@ -54,8 +75,12 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, vq->queue_index = queue_index; /* initialize the queue */ - - vring_init(vr, num, (unsigned char*)&vq->queue); + rc = vp_alloc_vq(vq, num); + if (rc) { + DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n"); + return rc; + } + vring_init(vr, num, vq->queue); /* activate the queue * @@ -354,7 +379,7 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev, return -ENOENT; if (size & (size - 1)) { - DBG("VIRTIO-PCI %p: bad queue size %d", vdev, size); + DBG("VIRTIO-PCI %p: bad queue size %d\n", vdev, size); return -EINVAL; } @@ -371,7 +396,12 @@ int vpm_find_vqs(struct virtio_pci_modern_device *vdev, /* get offset of notification word for this vq */ off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off)); - vring_init(&vq->vring, size, (unsigned char *)vq->queue); + err = vp_alloc_vq(vq, size); + if (err) { + DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev); + return err; + } + vring_init(&vq->vring, size, vq->queue); /* activate the queue */ vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size)); |