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;
} 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
+13 -17
View File
@@ -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);
+13 -7
View File
@@ -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;
}