libvirtqueue: Set queue size on initialization A virtqueue's queue size specifies the length of each ring and the length of the descriptor table.
diff --git a/libvirtqueue/CMakeLists.txt b/libvirtqueue/CMakeLists.txt index f780863..eaecf4a 100644 --- a/libvirtqueue/CMakeLists.txt +++ b/libvirtqueue/CMakeLists.txt
@@ -19,4 +19,4 @@ add_library(virtqueue STATIC EXCLUDE_FROM_ALL src/virtqueue.c) target_include_directories(virtqueue PUBLIC include) -target_link_libraries(virtqueue muslc) +target_link_libraries(virtqueue PUBLIC muslc PRIVATE utils)
diff --git a/libvirtqueue/include/virtqueue.h b/libvirtqueue/include/virtqueue.h index c26b571..ac3c6da 100644 --- a/libvirtqueue/include/virtqueue.h +++ b/libvirtqueue/include/virtqueue.h
@@ -14,11 +14,9 @@ #include <stdint.h> -#define RING_SIZE 256 -#define DESC_TABLE_SIZE 256 -#define VQ_DEV_POLL(vq) ((((vq)->a_ring_last_seen + 1) & (RING_SIZE - 1)) != (vq)->avail_ring->idx) -#define VQ_DRV_POLL(vq) ((((vq)->u_ring_last_seen + 1) & (RING_SIZE - 1)) != (vq)->used_ring->idx) +#define VQ_DEV_POLL(vq) ((((vq)->a_ring_last_seen + 1) & ((vq)->queue_len - 1)) != (vq)->avail_ring->idx) +#define VQ_DRV_POLL(vq) ((((vq)->u_ring_last_seen + 1) & ((vq)->queue_len - 1)) != (vq)->used_ring->idx) /* Flags for the buffers in the descriptor table */ typedef enum vq_flags { @@ -31,7 +29,7 @@ typedef struct vq_vring_avail { uint16_t flags; /* Interrupt suppression flag */ uint16_t idx; /* Index of the next free entry in the ring */ - uint16_t ring[RING_SIZE]; /* The ring of descriptor table entries */ + uint16_t ring[]; /* The ring of descriptor table entries */ } vq_vring_avail_t; /* Element of a used ring buffer */ @@ -44,7 +42,7 @@ typedef struct vq_vring_used { uint16_t flags; /* Interrupt suppression flag */ uint16_t idx; /* Index of the next free entry in the ring */ - struct vq_vring_used_elem ring[RING_SIZE]; /* The ring of descriptor table entries */ + struct vq_vring_used_elem ring[]; /* The ring of descriptor table entries */ } vq_vring_used_t; /* Entry in the descriptor table */ @@ -66,6 +64,7 @@ void (*notify)(void); /* Notify function to wake-up driver side */ void *cookie; /* User-defined cookie */ + unsigned queue_len; /* The number of entries in rings and descriptor table */ unsigned a_ring_last_seen; /* Index of the last seen element in the available ring */ struct vq_vring_avail *avail_ring; /* The available ring */ @@ -78,6 +77,7 @@ void (*notify)(void); /* Notify function to wake-up device side */ void *cookie; /* User-defined cookie */ + unsigned queue_len; /* The number of entries in rings and descriptor table */ unsigned free_desc_head; /* The head of the free list in the descriptor table */ unsigned u_ring_last_seen; /* Index of the last seen element in the used ring */ @@ -88,30 +88,32 @@ /* Initialise a driver-side virtqueue. * @param vq the driver virtqueue + * @param queue_len the length of rings and descriptor table * @param avail_ring pointer to the shared available ring * @param used_ring pointer to the shared used ring * @param desc pointer to the shared descriptor table * @param notify the notify function to wake up device side * @param cookie user's cookie */ -void virtqueue_init_driver(virtqueue_driver_t *vq, vq_vring_avail_t *avail_ring, +void virtqueue_init_driver(virtqueue_driver_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring, vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void), void *cookie); /* Initialise a device-side virtqueue. * @param vq the device virtqueue + * @param queue_len the length of rings and descriptor table * @param avail_ring pointer to the shared available ring * @param used_ring pointer to the shared used ring * @param desc pointer to the shared descriptor table * @param notify the notify function to wake up driver side * @param cookie user's cookie */ -void virtqueue_init_device(virtqueue_device_t *vq, vq_vring_avail_t *avail_ring, +void virtqueue_init_device(virtqueue_device_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring, vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void), void *cookie); /* Initialise the descriptor table (create the free list) */ -void virtqueue_init_desc_table(vq_vring_desc_t *table); +void virtqueue_init_desc_table(vq_vring_desc_t *table, unsigned queue_len); /* Initialise the available ring */ void virtqueue_init_avail_ring(vq_vring_avail_t *ring);
diff --git a/libvirtqueue/src/virtqueue.c b/libvirtqueue/src/virtqueue.c index 5ffb79d..e0631a0 100644 --- a/libvirtqueue/src/virtqueue.c +++ b/libvirtqueue/src/virtqueue.c
@@ -10,26 +10,39 @@ * @TAG(DATA61_BSD) */ +#include <utils/util.h> #include <virtqueue.h> -void virtqueue_init_driver(virtqueue_driver_t *vq, vq_vring_avail_t *avail_ring, +void virtqueue_init_driver(virtqueue_driver_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring, vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void), void *cookie) { + if (!IS_POWER_OF_2(queue_len)) { + ZF_LOGE("Invalid queue_len: %d, must be a power of 2.", queue_len); + } vq->free_desc_head = 0; - vq->u_ring_last_seen = RING_SIZE - 1; + vq->queue_len = queue_len; + vq->u_ring_last_seen = vq->queue_len - 1; vq->avail_ring = avail_ring; vq->used_ring = used_ring; vq->desc_table = desc; vq->notify = notify; vq->cookie = cookie; + virtqueue_init_desc_table(desc, vq->queue_len); + virtqueue_init_avail_ring(avail_ring); + virtqueue_init_used_ring(used_ring); + } -void virtqueue_init_device(virtqueue_device_t *vq, vq_vring_avail_t *avail_ring, +void virtqueue_init_device(virtqueue_device_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring, vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void), void *cookie) { - vq->a_ring_last_seen = RING_SIZE - 1; + if (!IS_POWER_OF_2(queue_len)) { + ZF_LOGE("Invalid queue_len: %d, must be a power of 2.", queue_len); + } + vq->queue_len = queue_len; + vq->a_ring_last_seen = vq->queue_len - 1; vq->avail_ring = avail_ring; vq->used_ring = used_ring; vq->desc_table = desc; @@ -37,10 +50,10 @@ vq->cookie = cookie; } -void virtqueue_init_desc_table(vq_vring_desc_t *table) +void virtqueue_init_desc_table(vq_vring_desc_t *table, unsigned queue_len) { unsigned i; - for (i = 0; i < DESC_TABLE_SIZE; i++) { + for (i = 0; i < queue_len; i++) { table[i].addr = 0; table[i].len = 0; table[i].flags = 0; @@ -67,7 +80,7 @@ vq_vring_desc_t *desc; new = vq->free_desc_head; - if (new == DESC_TABLE_SIZE) { + if (new == vq->queue_len) { return new; } vq->free_desc_head = vq->desc_table[new].next; @@ -79,9 +92,9 @@ desc->len = len; desc->flags = flag; - desc->next = DESC_TABLE_SIZE; + desc->next = vq->queue_len; - if (prev != DESC_TABLE_SIZE) { + if (prev < vq->queue_len) { desc = vq->desc_table + prev; desc->next = new; } @@ -107,7 +120,7 @@ static void vq_free_chain(virtqueue_driver_t *vq, unsigned head) { - while (head != DESC_TABLE_SIZE) { + while (head != vq->queue_len) { vq->desc_table[head].next = vq->free_desc_head; vq->free_desc_head = head; head = vq->desc_table[head].next; @@ -120,23 +133,23 @@ unsigned idx; /* If descriptor table full */ - if ((idx = vq_add_desc(vq, buf, len, flag, obj->cur)) == DESC_TABLE_SIZE) { + if ((idx = vq_add_desc(vq, buf, len, flag, obj->cur)) == vq->queue_len) { return 0; } obj->cur = idx; /* If this is the first buffer in the descriptor chain */ - if (obj->first == DESC_TABLE_SIZE) { + if (obj->first >= vq->queue_len) { obj->first = idx; vq->avail_ring->ring[vq->avail_ring->idx] = idx; - vq->avail_ring->idx = (vq->avail_ring->idx + 1) & (RING_SIZE - 1); + vq->avail_ring->idx = (vq->avail_ring->idx + 1) & (vq->queue_len - 1); } return 1; } int virtqueue_get_used_buf(virtqueue_driver_t *vq, virtqueue_ring_object_t *obj, uint32_t *len) { - unsigned next = (vq->u_ring_last_seen + 1) & (RING_SIZE - 1); + unsigned next = (vq->u_ring_last_seen + 1) & (vq->queue_len - 1); if (next == vq->used_ring->idx) { return 0; @@ -154,13 +167,13 @@ vq->used_ring->ring[cur].id = robj->first; vq->used_ring->ring[cur].len = len; - vq->used_ring->idx = (cur + 1) & (RING_SIZE - 1); + vq->used_ring->idx = (cur + 1) & (vq->queue_len - 1); return 1; } int virtqueue_get_available_buf(virtqueue_device_t *vq, virtqueue_ring_object_t *robj) { - unsigned next = (vq->a_ring_last_seen + 1) & (RING_SIZE - 1); + unsigned next = (vq->a_ring_last_seen + 1) & (vq->queue_len - 1); if (next == vq->avail_ring->idx) { return 0; @@ -173,8 +186,8 @@ void virtqueue_init_ring_object(virtqueue_ring_object_t *obj) { - obj->cur = DESC_TABLE_SIZE; - obj->first = DESC_TABLE_SIZE; + obj->cur = (uint32_t) -1; + obj->first = (uint32_t) -1; } uint32_t virtqueue_scattered_available_size(virtqueue_device_t *vq, virtqueue_ring_object_t *robj) @@ -182,7 +195,7 @@ uint32_t ret = 0; unsigned cur = robj->first; - while (cur != DESC_TABLE_SIZE) { + while (cur < vq->queue_len) { ret += vq->desc_table[cur].len; cur = vq->desc_table[cur].next; } @@ -194,7 +207,7 @@ { unsigned idx = robj->cur; - if (idx == DESC_TABLE_SIZE) { + if (idx >= vq->queue_len) { return 0; } @@ -211,7 +224,7 @@ int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj, void **buf, unsigned *len, vq_flags_t *flag) { - if (robj->cur == DESC_TABLE_SIZE) { + if (robj->cur >= vq->queue_len) { return 0; } robj->cur = vq_pop_desc(vq, robj->cur, buf, len, flag);