mirror of https://github.com/ipxe/ipxe.git
[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>pull/58/merge
parent
b782a56be7
commit
fba3b39900
|
@ -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));
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -196,9 +196,11 @@ static inline void vp_del_vq(unsigned int ioaddr, int queue_index)
|
|||
|
||||
struct vring_virtqueue;
|
||||
|
||||
void vp_free_vq(struct vring_virtqueue *vq);
|
||||
int vp_find_vq(unsigned int ioaddr, int queue_index,
|
||||
struct vring_virtqueue *vq);
|
||||
|
||||
|
||||
/* Virtio 1.0 I/O routines abstract away the three possible HW access
|
||||
* mechanisms - memory, port I/O, and PCI cfg space access. Also built-in
|
||||
* are endianness conversions - to LE on write and from LE on read. */
|
||||
|
|
|
@ -71,14 +71,12 @@ struct vring {
|
|||
+ PAGE_MASK) & ~PAGE_MASK) + \
|
||||
(sizeof(struct vring_used) + sizeof(struct vring_used_elem) * num))
|
||||
|
||||
typedef unsigned char virtio_queue_t[PAGE_MASK + vring_size(MAX_QUEUE_NUM)];
|
||||
|
||||
struct vring_virtqueue {
|
||||
virtio_queue_t queue;
|
||||
unsigned char *queue;
|
||||
struct vring vring;
|
||||
u16 free_head;
|
||||
u16 last_used_idx;
|
||||
void *vdata[MAX_QUEUE_NUM];
|
||||
void **vdata;
|
||||
/* PCI */
|
||||
int queue_index;
|
||||
struct virtio_pci_region notification;
|
||||
|
|
Loading…
Reference in New Issue