diff --git a/kernel-src/include/kernel/virtio.h b/kernel-src/include/kernel/virtio.h index d5ba638c..b3a51e05 100644 --- a/kernel-src/include/kernel/virtio.h +++ b/kernel-src/include/kernel/virtio.h @@ -36,11 +36,17 @@ typedef struct { size_t notifymultiplier; } viodevice_t; +typedef struct { + void *address; + size_t size; + uint16_t *notify; + uint16_t lastusedindex; +} vioqueue_t; + void virtio_init(); 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_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); #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_BUFFERS(q, s) ((volatile viobuffer_t *)(q)) -#define VIO_QUEUE_DRV(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * 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_RING(q, s) ((volatile uint16_t *)((uintptr_t)(q) + (s) * 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_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_RING(q, s) ((volatile viousedentry_t *)((uintptr_t)(q) + (s) * sizeof(viobuffer_t) + sizeof(uint16_t) * ((s) + 5 + (1 - ((s) % 2))))) +#define VIO_QUEUE_BUFFERS(q) ((volatile viobuffer_t *)(q)->address) +#define VIO_QUEUE_DRV(q) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t))) +#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) ((volatile uint16_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t) + 2 * sizeof(uint16_t))) +#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) ((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) ((volatile viousedentry_t *)((uintptr_t)(q)->address + (q)->size * sizeof(viobuffer_t) + sizeof(uint16_t) * ((q)->size + 5 + (1 - ((q)->size % 2))))) #endif diff --git a/kernel-src/io/block/vioblk.c b/kernel-src/io/block/vioblk.c index 886c80d4..7576b152 100644 --- a/kernel-src/io/block/vioblk.c +++ b/kernel-src/io/block/vioblk.c @@ -19,14 +19,11 @@ typedef struct { viodevice_t *viodevice; size_t capacity; int id; - void *queue; - size_t queuesize; + vioqueue_t queue; dpc_t queuedpc; spinlock_t queuelock; semaphore_t queuesem; event_t *queuewaiting[QUEUE_MAX_SIZE / 2]; - uint16_t *queuenotify; - uint16_t queuelastindex; } vioblkdev_t; typedef struct { @@ -43,11 +40,11 @@ static scache_t *headercache; static void vioblk_dpc(context_t *context, dpcarg_t 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); - while (blkdev->queuelastindex != VIO_QUEUE_DEV_IDX(blkdev->queue, blkdev->queuesize)) { - int idx = blkdev->queuelastindex++ % blkdev->queuesize; - int buffidx = VIO_QUEUE_DEV_RING(blkdev->queue, blkdev->queuesize)[idx].index; + while (blkdev->queue.lastusedindex != VIO_QUEUE_DEV_IDX(&blkdev->queue)) { + int idx = blkdev->queue.lastusedindex++ % blkdev->queue.size; + int buffidx = VIO_QUEUE_DEV_RING(&blkdev->queue)[idx].index; __assert(blkdev->queuewaiting[buffidx / 2]); event_signal(blkdev->queuewaiting[buffidx / 2]); 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); 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) ++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].flags = VIO_QUEUE_BUFFER_DEVICE; - size_t driveridx = VIO_QUEUE_DRV_IDX(blkdev->queue, blkdev->queuesize)++; - VIO_QUEUE_DRV_RING(blkdev->queue, blkdev->queuesize)[driveridx % blkdev->queuesize] = idx; + size_t driveridx = VIO_QUEUE_DRV_IDX(&blkdev->queue)++; + VIO_QUEUE_DRV_RING(&blkdev->queue)[driveridx % blkdev->queue.size] = idx; blkdev->queuewaiting[idx / 2] = &event; - *blkdev->queuenotify = 0; + *blkdev->queue.notify = 0; spinlock_release(&blkdev->queuelock); event_wait(&event, false); @@ -151,7 +148,7 @@ int vioblk_newdevice(viodevice_t *viodevice) { return 1; } - size_t intcount = pci_initmsix(viodevice->e); + pci_initmsix(viodevice->e); // TODO support several queues // 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); // initialize queue - blkdev->queuesize = min(QUEUE_MAX_SIZE, virtio_queuesize(viodevice, 0)); - blkdev->queue = MAKE_HHDM(virtio_createqueue(viodevice, 0, blkdev->queuesize, 0)); - blkdev->queuenotify = virtio_queuenotifyaddress(viodevice, 0); - SEMAPHORE_INIT(&blkdev->queuesem, blkdev->queuesize / 2); + size_t size = min(QUEUE_MAX_SIZE, virtio_queuesize(viodevice, 0)); + virtio_createqueue(viodevice, &blkdev->queue, 0, size, 0); + SEMAPHORE_INIT(&blkdev->queuesem, blkdev->queue.size / 2); SPINLOCK_INIT(blkdev->queuelock); virtio_enablequeue(viodevice, 0); diff --git a/kernel-src/io/virtio.c b/kernel-src/io/virtio.c index 89bdbed1..3f2d0508 100644 --- a/kernel-src/io/virtio.c +++ b/kernel-src/io/virtio.c @@ -33,12 +33,12 @@ void virtio_enablequeue(viodevice_t *viodevice, int queue) { viodevice->config->queueenable = 1; } -uint16_t *virtio_queuenotifyaddress(viodevice_t *viodevice, int queue) { - viodevice->config->queueselect = queue; - return (uint16_t *)((uintptr_t)viodevice->notify + viodevice->config->queuenotifyoffset * viodevice->notifymultiplier); +static uint16_t *virtio_queuenotifyaddress(viodevice_t *viodevice, int queue) { + viodevice->config->queueselect = queue; + 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 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); memset(MAKE_HHDM(queuephys), 0, bytesize); + vioqueue->address = queuephys; + vioqueue->size = size; + vioqueue->notify = virtio_queuenotifyaddress(viodevice, queue); + viodevice->config->queueselect = queue; viodevice->config->queuesize = size; viodevice->config->queuemsixvector = msix; __assert(viodevice->config->queuemsixvector == msix); - viodevice->config->queuedesc = (uint64_t)VIO_QUEUE_BUFFERS(queuephys, size); - viodevice->config->queuedriver = (uint64_t)VIO_QUEUE_DRV(queuephys, size); - viodevice->config->queuedevice = (uint64_t)VIO_QUEUE_DEV(queuephys, size); + viodevice->config->queuedesc = (uint64_t)VIO_QUEUE_BUFFERS(vioqueue); + viodevice->config->queuedriver = (uint64_t)VIO_QUEUE_DRV(vioqueue); + viodevice->config->queuedevice = (uint64_t)VIO_QUEUE_DEV(vioqueue); + + vioqueue->address = MAKE_HHDM(queuephys); return queuephys; }