virtio: vioqueue_t

This commit is contained in:
Matheus
2023-12-31 16:10:32 -03:00
parent e49f617a90
commit 69978904b8
3 changed files with 41 additions and 33 deletions
+15 -9
View File
@@ -36,11 +36,17 @@ typedef struct {
size_t notifymultiplier; size_t notifymultiplier;
} viodevice_t; } viodevice_t;
typedef struct {
void *address;
size_t size;
uint16_t *notify;
uint16_t lastusedindex;
} vioqueue_t;
void virtio_init(); void virtio_init();
size_t virtio_queuesize(viodevice_t *viodevice, int queue); size_t virtio_queuesize(viodevice_t *viodevice, int queue);
uint16_t *virtio_queuenotifyaddress(viodevice_t *viodevice, int queue);
void virtio_enablequeue(viodevice_t *viodevice, int queue); void virtio_enablequeue(viodevice_t *viodevice, int queue);
void *virtio_createqueue(viodevice_t *viodevice, int queue, size_t size, int msix); void *virtio_createqueue(viodevice_t *viodevice, vioqueue_t *vioqueue, int queue, size_t size, int msix);
void virtio_enabledevice(viodevice_t *viodevice); void virtio_enabledevice(viodevice_t *viodevice);
#define VIO_CONFIG_STATUS_SET(x, v) (x)->config->status |= v #define VIO_CONFIG_STATUS_SET(x, v) (x)->config->status |= v
@@ -97,12 +103,12 @@ struct {
*/ */
#define VIO_QUEUE_BYTESIZE(s) (sizeof(viobuffer_t) * (s) + sizeof(uint16_t) * ((s) + 6) + sizeof(viousedentry_t) * (s)) #define VIO_QUEUE_BYTESIZE(s) (sizeof(viobuffer_t) * (s) + sizeof(uint16_t) * ((s) + 6) + sizeof(viousedentry_t) * (s))
#define VIO_QUEUE_BUFFERS(q, s) ((volatile viobuffer_t *)(q)) #define VIO_QUEUE_BUFFERS(q) ((volatile viobuffer_t *)(q)->address)
#define VIO_QUEUE_DRV(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t))) #define VIO_QUEUE_DRV(q) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t)))
#define VIO_QUEUE_DRV_IDX(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t)))[1] #define VIO_QUEUE_DRV_IDX(q) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t)))[1]
#define VIO_QUEUE_DRV_RING(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t) + 2 * sizeof(uint16_t))) #define VIO_QUEUE_DRV_RING(q) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t) + 2 * sizeof(uint16_t)))
#define VIO_QUEUE_DEV(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t) + sizeof(uint16_t) * ((s) + 3 + (1 - ((s) % 2))))) #define VIO_QUEUE_DEV(q) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t) + sizeof(uint16_t) * ((q)->size + 3 + (1 - ((q)->size % 2)))))
#define VIO_QUEUE_DEV_IDX(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t) + sizeof(uint16_t) * ((s) + 3 + (1 - ((s) % 2)))))[1] #define VIO_QUEUE_DEV_IDX(q) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t) + sizeof(uint16_t) * ((q)->size + 3 + (1 - ((q)->size % 2)))))[1]
#define VIO_QUEUE_DEV_RING(q, s) ((volatile viousedentry_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t) + sizeof(uint16_t) * ((s) + 5 + (1 - ((s) % 2))))) #define VIO_QUEUE_DEV_RING(q) ((volatile viousedentry_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t) + sizeof(uint16_t) * ((q)->size + 5 + (1 - ((q)->size % 2)))))
#endif #endif
+13 -17
View File
@@ -19,14 +19,11 @@ typedef struct {
viodevice_t *viodevice; viodevice_t *viodevice;
size_t capacity; size_t capacity;
int id; int id;
void *queue; vioqueue_t queue;
size_t queuesize;
dpc_t queuedpc; dpc_t queuedpc;
spinlock_t queuelock; spinlock_t queuelock;
semaphore_t queuesem; semaphore_t queuesem;
event_t *queuewaiting[QUEUE_MAX_SIZE / 2]; event_t *queuewaiting[QUEUE_MAX_SIZE / 2];
uint16_t *queuenotify;
uint16_t queuelastindex;
} vioblkdev_t; } vioblkdev_t;
typedef struct { typedef struct {
@@ -43,11 +40,11 @@ static scache_t *headercache;
static void vioblk_dpc(context_t *context, dpcarg_t arg) { static void vioblk_dpc(context_t *context, dpcarg_t arg) {
vioblkdev_t *blkdev = arg; vioblkdev_t *blkdev = arg;
volatile viobuffer_t *buffers = VIO_QUEUE_BUFFERS(blkdev->queue, blkdev->queuesize); volatile viobuffer_t *buffers = VIO_QUEUE_BUFFERS(&blkdev->queue);
spinlock_acquire(&blkdev->queuelock); spinlock_acquire(&blkdev->queuelock);
while (blkdev->queuelastindex != VIO_QUEUE_DEV_IDX(blkdev->queue, blkdev->queuesize)) { while (blkdev->queue.lastusedindex != VIO_QUEUE_DEV_IDX(&blkdev->queue)) {
int idx = blkdev->queuelastindex++ % blkdev->queuesize; int idx = blkdev->queue.lastusedindex++ % blkdev->queue.size;
int buffidx = VIO_QUEUE_DEV_RING(blkdev->queue, blkdev->queuesize)[idx].index; int buffidx = VIO_QUEUE_DEV_RING(&blkdev->queue)[idx].index;
__assert(blkdev->queuewaiting[buffidx / 2]); __assert(blkdev->queuewaiting[buffidx / 2]);
event_signal(blkdev->queuewaiting[buffidx / 2]); event_signal(blkdev->queuewaiting[buffidx / 2]);
blkdev->queuewaiting[buffidx / 2] = NULL; blkdev->queuewaiting[buffidx / 2] = NULL;
@@ -75,7 +72,7 @@ static void vioblk_enqueue(vioblkdev_t *blkdev, void *driver, size_t driverlen,
spinlock_acquire(&blkdev->queuelock); spinlock_acquire(&blkdev->queuelock);
int idx = 0; int idx = 0;
volatile viobuffer_t *buffers = VIO_QUEUE_BUFFERS(blkdev->queue, blkdev->queuesize); volatile viobuffer_t *buffers = VIO_QUEUE_BUFFERS(&blkdev->queue);
while (buffers[idx].address && idx < QUEUE_MAX_SIZE) while (buffers[idx].address && idx < QUEUE_MAX_SIZE)
++idx; ++idx;
@@ -90,12 +87,12 @@ static void vioblk_enqueue(vioblkdev_t *blkdev, void *driver, size_t driverlen,
buffers[idx + 1].length = devicelen; buffers[idx + 1].length = devicelen;
buffers[idx + 1].flags = VIO_QUEUE_BUFFER_DEVICE; buffers[idx + 1].flags = VIO_QUEUE_BUFFER_DEVICE;
size_t driveridx = VIO_QUEUE_DRV_IDX(blkdev->queue, blkdev->queuesize)++; size_t driveridx = VIO_QUEUE_DRV_IDX(&blkdev->queue)++;
VIO_QUEUE_DRV_RING(blkdev->queue, blkdev->queuesize)[driveridx % blkdev->queuesize] = idx; VIO_QUEUE_DRV_RING(&blkdev->queue)[driveridx % blkdev->queue.size] = idx;
blkdev->queuewaiting[idx / 2] = &event; blkdev->queuewaiting[idx / 2] = &event;
*blkdev->queuenotify = 0; *blkdev->queue.notify = 0;
spinlock_release(&blkdev->queuelock); spinlock_release(&blkdev->queuelock);
event_wait(&event, false); event_wait(&event, false);
@@ -151,7 +148,7 @@ int vioblk_newdevice(viodevice_t *viodevice) {
return 1; return 1;
} }
size_t intcount = pci_initmsix(viodevice->e); pci_initmsix(viodevice->e);
// TODO support several queues // TODO support several queues
// no extra features will be used yet // no extra features will be used yet
@@ -179,10 +176,9 @@ int vioblk_newdevice(viodevice_t *viodevice) {
__assert(hashtable_set(&inttable, blkdev, &isr->id, sizeof(isr->id), true) == 0); __assert(hashtable_set(&inttable, blkdev, &isr->id, sizeof(isr->id), true) == 0);
// initialize queue // initialize queue
blkdev->queuesize = min(QUEUE_MAX_SIZE, virtio_queuesize(viodevice, 0)); size_t size = min(QUEUE_MAX_SIZE, virtio_queuesize(viodevice, 0));
blkdev->queue = MAKE_HHDM(virtio_createqueue(viodevice, 0, blkdev->queuesize, 0)); virtio_createqueue(viodevice, &blkdev->queue, 0, size, 0);
blkdev->queuenotify = virtio_queuenotifyaddress(viodevice, 0); SEMAPHORE_INIT(&blkdev->queuesem, blkdev->queue.size / 2);
SEMAPHORE_INIT(&blkdev->queuesem, blkdev->queuesize / 2);
SPINLOCK_INIT(blkdev->queuelock); SPINLOCK_INIT(blkdev->queuelock);
virtio_enablequeue(viodevice, 0); virtio_enablequeue(viodevice, 0);
+11 -5
View File
@@ -33,12 +33,12 @@ void virtio_enablequeue(viodevice_t *viodevice, int queue) {
viodevice->config->queueenable = 1; viodevice->config->queueenable = 1;
} }
uint16_t *virtio_queuenotifyaddress(viodevice_t *viodevice, int queue) { static uint16_t *virtio_queuenotifyaddress(viodevice_t *viodevice, int queue) {
viodevice->config->queueselect = queue; viodevice->config->queueselect = queue;
return (uint16_t *)((uintptr_t)viodevice->notify + viodevice->config->queuenotifyoffset * viodevice->notifymultiplier); return (uint16_t *)((uintptr_t)viodevice->notify + viodevice->config->queuenotifyoffset * viodevice->notifymultiplier);
} }
void *virtio_createqueue(viodevice_t *viodevice, int queue, size_t size, int msix) { void *virtio_createqueue(viodevice_t *viodevice, vioqueue_t *vioqueue, int queue, size_t size, int msix) {
size_t bytesize = VIO_QUEUE_BYTESIZE(size); size_t bytesize = VIO_QUEUE_BYTESIZE(size);
size_t pagesize = ROUND_UP(bytesize, PAGE_SIZE) / PAGE_SIZE; size_t pagesize = ROUND_UP(bytesize, PAGE_SIZE) / PAGE_SIZE;
@@ -46,13 +46,19 @@ void *virtio_createqueue(viodevice_t *viodevice, int queue, size_t size, int msi
__assert(queuephys); __assert(queuephys);
memset(MAKE_HHDM(queuephys), 0, bytesize); memset(MAKE_HHDM(queuephys), 0, bytesize);
vioqueue->address = queuephys;
vioqueue->size = size;
vioqueue->notify = virtio_queuenotifyaddress(viodevice, queue);
viodevice->config->queueselect = queue; viodevice->config->queueselect = queue;
viodevice->config->queuesize = size; viodevice->config->queuesize = size;
viodevice->config->queuemsixvector = msix; viodevice->config->queuemsixvector = msix;
__assert(viodevice->config->queuemsixvector == msix); __assert(viodevice->config->queuemsixvector == msix);
viodevice->config->queuedesc = (uint64_t)VIO_QUEUE_BUFFERS(queuephys, size); viodevice->config->queuedesc = (uint64_t)VIO_QUEUE_BUFFERS(vioqueue);
viodevice->config->queuedriver = (uint64_t)VIO_QUEUE_DRV(queuephys, size); viodevice->config->queuedriver = (uint64_t)VIO_QUEUE_DRV(vioqueue);
viodevice->config->queuedevice = (uint64_t)VIO_QUEUE_DEV(queuephys, size); viodevice->config->queuedevice = (uint64_t)VIO_QUEUE_DEV(vioqueue);
vioqueue->address = MAKE_HHDM(queuephys);
return queuephys; return queuephys;
} }