summaryrefslogtreecommitdiffstats
path: root/src/drivers
diff options
context:
space:
mode:
authorLadi Prosek2016-12-16 14:07:08 +0100
committerMichael Brown2017-01-22 14:22:19 +0100
commitfba3b39900af52e695d59bc34f28bb8d22526ddb (patch)
tree6b2b6062085e52e545306937e48fcf6af5774cca /src/drivers
parent[virtio] Simplify virtqueue shutdown (diff)
downloadipxe-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')
-rw-r--r--src/drivers/bus/virtio-pci.c48
-rw-r--r--src/drivers/net/virtio-net.c1
2 files changed, 40 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));
diff --git a/src/drivers/net/virtio-net.c b/src/drivers/net/virtio-net.c
index de3333d2..eaf6ed38 100644
--- a/src/drivers/net/virtio-net.c
+++ b/src/drivers/net/virtio-net.c
@@ -185,6 +185,7 @@ static void virtnet_free_virtqueues ( struct net_device *netdev ) {
for ( i = 0; i < QUEUE_NB; i++ ) {
virtio_pci_unmap_capability ( &virtnet->virtqueue[i].notification );
+ vp_free_vq ( &virtnet->virtqueue[i] );
}
free ( virtnet->virtqueue );