Browse Source

[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>
tags/v1.20.1
Ladi Prosek 8 years ago
parent
commit
fba3b39900

+ 39
- 9
src/drivers/bus/virtio-pci.c View File

21
 #include "ipxe/virtio-pci.h"
21
 #include "ipxe/virtio-pci.h"
22
 #include "ipxe/virtio-ring.h"
22
 #include "ipxe/virtio-ring.h"
23
 
23
 
24
+static int vp_alloc_vq(struct vring_virtqueue *vq, u16 num)
25
+{
26
+    size_t queue_size = PAGE_MASK + vring_size(num);
27
+    size_t vdata_size = num * sizeof(void *);
28
+
29
+    vq->queue = zalloc(queue_size + vdata_size);
30
+    if (!vq->queue) {
31
+        return -ENOMEM;
32
+    }
33
+
34
+    /* vdata immediately follows the ring */
35
+    vq->vdata = (void **)(vq->queue + queue_size);
36
+
37
+    return 0;
38
+}
39
+
40
+void vp_free_vq(struct vring_virtqueue *vq)
41
+{
42
+    if (vq->queue) {
43
+        free(vq->queue);
44
+        vq->queue = NULL;
45
+        vq->vdata = NULL;
46
+    }
47
+}
48
+
24
 int vp_find_vq(unsigned int ioaddr, int queue_index,
49
 int vp_find_vq(unsigned int ioaddr, int queue_index,
25
                struct vring_virtqueue *vq)
50
                struct vring_virtqueue *vq)
26
 {
51
 {
27
    struct vring * vr = &vq->vring;
52
    struct vring * vr = &vq->vring;
28
    u16 num;
53
    u16 num;
54
+   int rc;
29
 
55
 
30
    /* select the queue */
56
    /* select the queue */
31
 
57
 
39
            return -1;
65
            return -1;
40
    }
66
    }
41
 
67
 
42
-   if (num > MAX_QUEUE_NUM) {
43
-           DBG("VIRTIO-PCI ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM);
44
-           return -1;
45
-   }
46
-
47
    /* check if the queue is already active */
68
    /* check if the queue is already active */
48
 
69
 
49
    if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
70
    if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
54
    vq->queue_index = queue_index;
75
    vq->queue_index = queue_index;
55
 
76
 
56
    /* initialize the queue */
77
    /* initialize the queue */
57
-
58
-   vring_init(vr, num, (unsigned char*)&vq->queue);
78
+   rc = vp_alloc_vq(vq, num);
79
+   if (rc) {
80
+           DBG("VIRTIO-PCI ERROR: failed to allocate queue memory\n");
81
+           return rc;
82
+   }
83
+   vring_init(vr, num, vq->queue);
59
 
84
 
60
    /* activate the queue
85
    /* activate the queue
61
     *
86
     *
354
             return -ENOENT;
379
             return -ENOENT;
355
 
380
 
356
         if (size & (size - 1)) {
381
         if (size & (size - 1)) {
357
-            DBG("VIRTIO-PCI %p: bad queue size %d", vdev, size);
382
+            DBG("VIRTIO-PCI %p: bad queue size %d\n", vdev, size);
358
             return -EINVAL;
383
             return -EINVAL;
359
         }
384
         }
360
 
385
 
371
         /* get offset of notification word for this vq */
396
         /* get offset of notification word for this vq */
372
         off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
397
         off = vpm_ioread16(vdev, &vdev->common, COMMON_OFFSET(queue_notify_off));
373
 
398
 
374
-        vring_init(&vq->vring, size, (unsigned char *)vq->queue);
399
+        err = vp_alloc_vq(vq, size);
400
+        if (err) {
401
+            DBG("VIRTIO-PCI %p: failed to allocate queue memory\n", vdev);
402
+            return err;
403
+        }
404
+        vring_init(&vq->vring, size, vq->queue);
375
 
405
 
376
         /* activate the queue */
406
         /* activate the queue */
377
         vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));
407
         vpm_iowrite16(vdev, &vdev->common, size, COMMON_OFFSET(queue_size));

+ 1
- 0
src/drivers/net/virtio-net.c View File

185
 
185
 
186
 	for ( i = 0; i < QUEUE_NB; i++ ) {
186
 	for ( i = 0; i < QUEUE_NB; i++ ) {
187
 		virtio_pci_unmap_capability ( &virtnet->virtqueue[i].notification );
187
 		virtio_pci_unmap_capability ( &virtnet->virtqueue[i].notification );
188
+		vp_free_vq ( &virtnet->virtqueue[i] );
188
 	}
189
 	}
189
 
190
 
190
 	free ( virtnet->virtqueue );
191
 	free ( virtnet->virtqueue );

+ 2
- 0
src/include/ipxe/virtio-pci.h View File

196
 
196
 
197
 struct vring_virtqueue;
197
 struct vring_virtqueue;
198
 
198
 
199
+void vp_free_vq(struct vring_virtqueue *vq);
199
 int vp_find_vq(unsigned int ioaddr, int queue_index,
200
 int vp_find_vq(unsigned int ioaddr, int queue_index,
200
                struct vring_virtqueue *vq);
201
                struct vring_virtqueue *vq);
201
 
202
 
203
+
202
 /* Virtio 1.0 I/O routines abstract away the three possible HW access
204
 /* Virtio 1.0 I/O routines abstract away the three possible HW access
203
  * mechanisms - memory, port I/O, and PCI cfg space access. Also built-in
205
  * mechanisms - memory, port I/O, and PCI cfg space access. Also built-in
204
  * are endianness conversions - to LE on write and from LE on read. */
206
  * are endianness conversions - to LE on write and from LE on read. */

+ 2
- 4
src/include/ipxe/virtio-ring.h View File

71
          + PAGE_MASK) & ~PAGE_MASK) + \
71
          + PAGE_MASK) & ~PAGE_MASK) + \
72
          (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
72
          (sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
73
 
73
 
74
-typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
75
-
76
 struct vring_virtqueue {
74
 struct vring_virtqueue {
77
-   virtio_queue_t queue;
75
+   unsigned char *queue;
78
    struct vring vring;
76
    struct vring vring;
79
    u16 free_head;
77
    u16 free_head;
80
    u16 last_used_idx;
78
    u16 last_used_idx;
81
-   void *vdata[MAX_QUEUE_NUM];
79
+   void **vdata;
82
    /* PCI */
80
    /* PCI */
83
    int queue_index;
81
    int queue_index;
84
    struct virtio_pci_region notification;
82
    struct virtio_pci_region notification;

Loading…
Cancel
Save