diff --git a/headers/private/virtio/virtio.h b/headers/private/virtio/virtio.h index 12691a1e52..1afd5dd052 100644 --- a/headers/private/virtio/virtio.h +++ b/headers/private/virtio/virtio.h @@ -53,9 +53,9 @@ typedef void* virtio_device; // queue cookie, issued by virtio bus manager typedef void* virtio_queue; // callback function for requests -typedef void (*virtio_callback_func)(void* driverCookie, void *cookie); +typedef void (*virtio_callback_func)(void* driverCookie, void* cookie); // callback function for interrupts -typedef void (*virtio_intr_func)(void *cookie); +typedef void (*virtio_intr_func)(void* cookie); #define VIRTIO_DEVICE_MODULE_NAME "bus_managers/virtio/device/v1" @@ -93,8 +93,8 @@ typedef struct { typedef struct { driver_module_info info; - status_t (*negociate_features)(virtio_device cookie, uint32 supported, - uint32* negociated, const char* (*get_feature_name)(uint32)); + status_t (*negotiate_features)(virtio_device cookie, uint32 supported, + uint32* negotiated, const char* (*get_feature_name)(uint32)); status_t (*read_device_config)(virtio_device cookie, uint8 offset, void* buffer, size_t bufferSize); @@ -102,20 +102,22 @@ typedef struct { const void* buffer, size_t bufferSize); status_t (*alloc_queues)(virtio_device cookie, size_t count, - virtio_queue *queues); + virtio_queue* queues); status_t (*setup_interrupt)(virtio_device cookie, virtio_intr_func config_handler, void* driverCookie); + status_t (*queue_setup_interrupt)(virtio_queue queue, + virtio_callback_func handler, void* cookie); + status_t (*queue_request)(virtio_queue queue, - const physical_entry *readEntry, - const physical_entry *writtenEntry, virtio_callback_func callback, - void *callbackCookie); + const physical_entry* readEntry, + const physical_entry* writtenEntry, void* cookie); status_t (*queue_request_v)(virtio_queue queue, const physical_entry* vector, size_t readVectorCount, size_t writtenVectorCount, - virtio_callback_func callback, void *callbackCookie); + void* cookie); bool (*queue_is_full)(virtio_queue queue); @@ -123,6 +125,8 @@ typedef struct { uint16 (*queue_size)(virtio_queue queue); + void* (*queue_dequeue)(virtio_queue queue, uint16* _size); + } virtio_device_interface; diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp b/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp index 4364748c80..0fa3985fde 100644 --- a/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp +++ b/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp @@ -101,7 +101,7 @@ VirtioDevice::InitCheck() status_t -VirtioDevice::NegociateFeatures(uint32 supported, uint32* negociated, +VirtioDevice::NegotiateFeatures(uint32 supported, uint32* negotiated, const char* (*get_feature_name)(uint32)) { fFeatures = 0; @@ -117,9 +117,9 @@ VirtioDevice::NegociateFeatures(uint32 supported, uint32* negociated, fFeatures &= (VIRTIO_FEATURE_TRANSPORT_MASK | VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX); - *negociated = fFeatures; + *negotiated = fFeatures; - DumpFeatures("negociated features", fFeatures, get_feature_name); + DumpFeatures("negotiated features", fFeatures, get_feature_name); return fController->write_guest_features(fCookie, fFeatures); } diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp b/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp index 41b5860365..7515f0b44d 100644 --- a/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp +++ b/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp @@ -14,7 +14,7 @@ device_manager_info *gDeviceManager = NULL; static status_t -virtio_device_init(device_node *node, void **cookie) +virtio_device_init(device_node *node, void **_device) { CALLED(); VirtioDevice *device = new(std::nothrow) VirtioDevice(node); @@ -27,25 +27,25 @@ virtio_device_init(device_node *node, void **cookie) return result; } - *cookie = device; + *_device = device; return B_OK; } static void -virtio_device_uninit(void *cookie) +virtio_device_uninit(void *_device) { CALLED(); - VirtioDevice *device = (VirtioDevice *)cookie; + VirtioDevice *device = (VirtioDevice *)_device; delete device; } static void -virtio_device_removed(void *cookie) +virtio_device_removed(void *_device) { CALLED(); - //VirtioDevice *device = (VirtioDevice *)cookie; + //VirtioDevice *device = (VirtioDevice *)_device; } @@ -53,73 +53,81 @@ virtio_device_removed(void *cookie) status_t -virtio_negociate_features(void* cookie, uint32 supported, - uint32* negociated, const char* (*get_feature_name)(uint32)) +virtio_negotiate_features(void* _device, uint32 supported, + uint32* negotiated, const char* (*get_feature_name)(uint32)) { CALLED(); - VirtioDevice *device = (VirtioDevice *)cookie; + VirtioDevice *device = (VirtioDevice *)_device; - return device->NegociateFeatures(supported, negociated, get_feature_name); + return device->NegotiateFeatures(supported, negotiated, get_feature_name); } status_t -virtio_read_device_config(void* cookie, uint8 offset, void* buffer, +virtio_read_device_config(void* _device, uint8 offset, void* buffer, size_t bufferSize) { CALLED(); - VirtioDevice *device = (VirtioDevice *)cookie; + VirtioDevice *device = (VirtioDevice *)_device; return device->ReadDeviceConfig(offset, buffer, bufferSize); } status_t -virtio_write_device_config(void* cookie, uint8 offset, +virtio_write_device_config(void* _device, uint8 offset, const void* buffer, size_t bufferSize) { CALLED(); - VirtioDevice *device = (VirtioDevice *)cookie; + VirtioDevice *device = (VirtioDevice *)_device; return device->WriteDeviceConfig(offset, buffer, bufferSize); } status_t -virtio_alloc_queues(virtio_device cookie, size_t count, virtio_queue *queues) +virtio_alloc_queues(virtio_device _device, size_t count, virtio_queue *queues) { CALLED(); - VirtioDevice *device = (VirtioDevice *)cookie; + VirtioDevice *device = (VirtioDevice *)_device; return device->AllocateQueues(count, queues); } status_t -virtio_setup_interrupt(virtio_device cookie, virtio_intr_func config_handler, +virtio_setup_interrupt(virtio_device _device, virtio_intr_func config_handler, void *driverCookie) { CALLED(); - VirtioDevice *device = (VirtioDevice *)cookie; + VirtioDevice *device = (VirtioDevice *)_device; return device->SetupInterrupt(config_handler, driverCookie); } status_t -virtio_queue_request_v(virtio_queue cookie, const physical_entry* vector, - size_t readVectorCount, size_t writtenVectorCount, - virtio_callback_func callback, void *callbackCookie) +virtio_queue_setup_interrupt(virtio_queue _queue, virtio_callback_func handler, + void *cookie) { CALLED(); - VirtioQueue *queue = (VirtioQueue *)cookie; - return queue->QueueRequest(vector, readVectorCount, writtenVectorCount, - callback, callbackCookie); + VirtioQueue *queue = (VirtioQueue *)_queue; + return queue->SetupInterrupt(handler, cookie); } status_t -virtio_queue_request(virtio_queue cookie, const physical_entry *readEntry, - const physical_entry *writtenEntry, virtio_callback_func callback, - void *callbackCookie) +virtio_queue_request_v(virtio_queue _queue, const physical_entry* vector, + size_t readVectorCount, size_t writtenVectorCount, void *cookie) +{ + CALLED(); + VirtioQueue *queue = (VirtioQueue *)_queue; + return queue->QueueRequest(vector, readVectorCount, writtenVectorCount, + cookie); +} + + +status_t +virtio_queue_request(virtio_queue _queue, const physical_entry *readEntry, + const physical_entry *writtenEntry, void *cookie) { physical_entry entries[2]; if (readEntry != NULL) { @@ -129,35 +137,42 @@ virtio_queue_request(virtio_queue cookie, const physical_entry *readEntry, } else if (writtenEntry != NULL) entries[0] = *writtenEntry; - return virtio_queue_request_v(cookie, entries, readEntry != NULL ? 1 : 0, - writtenEntry != NULL? 1 : 0, callback, callbackCookie); + return virtio_queue_request_v(_queue, entries, readEntry != NULL ? 1 : 0, + writtenEntry != NULL? 1 : 0, cookie); } bool -virtio_queue_is_full(virtio_queue cookie) +virtio_queue_is_full(virtio_queue _queue) { - VirtioQueue *queue = (VirtioQueue *)cookie; + VirtioQueue *queue = (VirtioQueue *)_queue; return queue->IsFull(); } bool -virtio_queue_is_empty(virtio_queue cookie) +virtio_queue_is_empty(virtio_queue _queue) { - VirtioQueue *queue = (VirtioQueue *)cookie; + VirtioQueue *queue = (VirtioQueue *)_queue; return queue->IsEmpty(); } uint16 -virtio_queue_size(virtio_queue cookie) +virtio_queue_size(virtio_queue _queue) { - VirtioQueue *queue = (VirtioQueue *)cookie; + VirtioQueue *queue = (VirtioQueue *)_queue; return queue->Size(); } +void* +virtio_queue_dequeue(virtio_queue _queue, uint16* _size) +{ + VirtioQueue *queue = (VirtioQueue *)_queue; + return queue->Dequeue(_size); +} + // #pragma mark - @@ -241,16 +256,18 @@ virtio_device_interface virtio_device_module = { NULL, // resume }, - virtio_negociate_features, + virtio_negotiate_features, virtio_read_device_config, virtio_write_device_config, virtio_alloc_queues, virtio_setup_interrupt, + virtio_queue_setup_interrupt, virtio_queue_request, virtio_queue_request_v, virtio_queue_is_full, virtio_queue_is_empty, - virtio_queue_size + virtio_queue_size, + virtio_queue_dequeue }; virtio_for_controller_interface virtio_for_controller_module = { diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h b/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h index 4e0e0d132e..b6db8a2744 100644 --- a/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h +++ b/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h @@ -45,8 +45,8 @@ public: status_t InitCheck(); uint32 ID() const { return fID; } - status_t NegociateFeatures(uint32 supported, - uint32* negociated, + status_t NegotiateFeatures(uint32 supported, + uint32* negotiated, const char* (*get_feature_name)(uint32)); status_t ReadDeviceConfig(uint8 offset, void* buffer, @@ -114,17 +114,21 @@ public: status_t QueueRequest(const physical_entry* vector, size_t readVectorCount, size_t writtenVectorCount, - virtio_callback_func callback, - void *callbackCookie); + void *cookie); status_t QueueRequestIndirect( const physical_entry* vector, size_t readVectorCount, size_t writtenVectorCount, - virtio_callback_func callback, - void *callbackCookie); + void *cookie); + + status_t SetupInterrupt(virtio_callback_func handler, + void *cookie); + void EnableInterrupt(); void DisableInterrupt(); + void* Dequeue(uint16* _size = NULL); + private: void UpdateAvailable(uint16 index); uint16 QueueVector(uint16 insertIndex, @@ -132,7 +136,6 @@ private: const physical_entry* vector, size_t readVectorCount, size_t writtenVectorCount); - void Finish(); VirtioDevice* fDevice; uint16 fQueueNumber; @@ -149,6 +152,10 @@ private: uint16 fIndirectMaxSize; TransferDescriptor** fDescriptors; + + virtio_callback_func fCallback; + void* fCookie; + }; #endif // VIRTIO_PRIVATE_H diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp b/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp index 77aec1db14..4ed23b33b0 100644 --- a/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp +++ b/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp @@ -56,11 +56,9 @@ public: status_t InitCheck() { return fStatus; } - void Callback(); uint16 Size() { return fDescriptorCount; } - void SetTo(uint16 size, - virtio_callback_func callback, - void *callbackCookie); + void SetTo(uint16 size, void *cookie); + void* Cookie() { return fCookie; } void Unset(); struct vring_desc* Indirect() { return fIndirect; } phys_addr_t PhysAddr() { return fPhysAddr; } @@ -68,7 +66,6 @@ private: status_t fStatus; VirtioQueue* fQueue; void* fCookie; - virtio_callback_func fCallback; struct vring_desc* fIndirect; size_t fAreaSize; @@ -81,7 +78,6 @@ private: TransferDescriptor::TransferDescriptor(VirtioQueue* queue, uint16 indirectMaxSize) : fQueue(queue), fCookie(NULL), - fCallback(NULL), fIndirect(NULL), fAreaSize(0), fArea(-1), @@ -119,19 +115,9 @@ TransferDescriptor::~TransferDescriptor() void -TransferDescriptor::Callback() +TransferDescriptor::SetTo(uint16 size, void *cookie) { - if (fCallback != NULL) - fCallback(fQueue->Device()->DriverCookie(), fCookie); -} - - -void -TransferDescriptor::SetTo(uint16 size, virtio_callback_func callback, - void *callbackCookie) -{ - fCookie = callbackCookie; - fCallback = callback; + fCookie = cookie; fDescriptorCount = size; } @@ -140,7 +126,6 @@ void TransferDescriptor::Unset() { fCookie = NULL; - fCallback = NULL; fDescriptorCount = 0; } @@ -158,7 +143,9 @@ VirtioQueue::VirtioQueue(VirtioDevice* device, uint16 queueNumber, fRingHeadIndex(0), fRingUsedIndex(0), fStatus(B_OK), - fIndirectMaxSize(0) + fIndirectMaxSize(0), + fCallback(NULL), + fCookie(NULL) { fDescriptors = new(std::nothrow) TransferDescriptor*[fRingSize]; if (fDescriptors == NULL) { @@ -209,19 +196,30 @@ VirtioQueue::~VirtioQueue() } +status_t +VirtioQueue::SetupInterrupt(virtio_callback_func handler, void *cookie) +{ + fCallback = handler; + fCookie = cookie; + + return B_OK; +} + + + void VirtioQueue::DisableInterrupt() { - /*if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0) - fRing.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;*/ + if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0) + fRing.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; } void VirtioQueue::EnableInterrupt() { - /*if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0) - fRing.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;*/ + if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0) + fRing.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; } @@ -236,52 +234,63 @@ status_t VirtioQueue::Interrupt() { CALLED(); + DisableInterrupt(); - while (fRingUsedIndex != fRing.used->idx) - Finish(); + if (fCallback != NULL) + fCallback(Device()->DriverCookie(), fCookie); EnableInterrupt(); return B_OK; } -void -VirtioQueue::Finish() +void* +VirtioQueue::Dequeue(uint16 *_size) { - TRACE("Finish() fRingUsedIndex: %u\n", fRingUsedIndex); + TRACE("Dequeue() fRingUsedIndex: %u\n", fRingUsedIndex); + + if (fRingUsedIndex == fRing.used->idx) + return NULL; uint16 usedIndex = fRingUsedIndex++ & (fRingSize - 1); - TRACE("Finish() usedIndex: %u\n", usedIndex); + TRACE("Dequeue() usedIndex: %u\n", usedIndex); struct vring_used_elem *element = &fRing.used->ring[usedIndex]; uint16 descriptorIndex = element->id; // uint32 length = element->len; - fDescriptors[descriptorIndex]->Callback(); + void* cookie = fDescriptors[descriptorIndex]->Cookie(); uint16 size = fDescriptors[descriptorIndex]->Size(); + if (_size != NULL) + *_size = size; + if (size == 0) + panic("VirtioQueue::Dequeue() size is zero\n"); fDescriptors[descriptorIndex]->Unset(); fRingFree += size; size--; uint16 index = descriptorIndex; - while ((fRing.desc[index].flags & VRING_DESC_F_NEXT) != 0) { - index = fRing.desc[index].next; - size--; + if ((fRing.desc[index].flags & VRING_DESC_F_INDIRECT) == 0) { + while ((fRing.desc[index].flags & VRING_DESC_F_NEXT) != 0) { + index = fRing.desc[index].next; + size--; + } } if (size > 0) - panic("VirtioQueue::Finish() descriptors left %d\n", size); + panic("VirtioQueue::Dequeue() descriptors left %d\n", size); fRing.desc[index].next = fRingHeadIndex; fRingHeadIndex = descriptorIndex; - TRACE("Finish() fRingHeadIndex: %u\n", fRingHeadIndex); + TRACE("Dequeue() fRingHeadIndex: %u\n", fRingHeadIndex); + + return cookie; } status_t VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount, - size_t writtenVectorCount, virtio_callback_func callback, - void *callbackCookie) + size_t writtenVectorCount, void *cookie) { CALLED(); size_t count = readVectorCount + writtenVectorCount; @@ -289,15 +298,14 @@ VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount, return B_BAD_VALUE; if ((fDevice->Features() & VIRTIO_FEATURE_RING_INDIRECT_DESC) != 0) { return QueueRequestIndirect(vector, readVectorCount, - writtenVectorCount, callback, callbackCookie); + writtenVectorCount, cookie); } if (count > fRingFree) return B_BUSY; uint16 insertIndex = fRingHeadIndex; - fDescriptors[insertIndex]->SetTo(count, callback, - callbackCookie); + fDescriptors[insertIndex]->SetTo(count, cookie); // enqueue uint16 index = QueueVector(insertIndex, fRing.desc, vector, @@ -317,7 +325,7 @@ VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount, status_t VirtioQueue::QueueRequestIndirect(const physical_entry* vector, size_t readVectorCount, size_t writtenVectorCount, - virtio_callback_func callback, void *callbackCookie) + void *cookie) { CALLED(); size_t count = readVectorCount + writtenVectorCount; @@ -325,8 +333,7 @@ VirtioQueue::QueueRequestIndirect(const physical_entry* vector, return B_BUSY; uint16 insertIndex = fRingHeadIndex; - fDescriptors[insertIndex]->SetTo(1, callback, - callbackCookie); + fDescriptors[insertIndex]->SetTo(1, cookie); // enqueue uint16 index = QueueVector(0, fDescriptors[insertIndex]->Indirect(), @@ -364,15 +371,14 @@ VirtioQueue::QueueVector(uint16 insertIndex, struct vring_desc *desc, CALLED(); uint16 index = insertIndex; size_t total = readVectorCount + writtenVectorCount; - for (size_t i = 0; i < total; i++) { + for (size_t i = 0; i < total; i++, index = desc[index].next) { desc[index].addr = vector[i].address; desc[index].len = vector[i].size; desc[index].flags = 0; - if (i >= readVectorCount) - desc[index].flags |= VRING_DESC_F_WRITE; if (i < total - 1) desc[index].flags |= VRING_DESC_F_NEXT; - index = desc[index].next; + if (i >= readVectorCount) + desc[index].flags |= VRING_DESC_F_WRITE; } return index; diff --git a/src/add-ons/kernel/busses/random/VirtioRNGDevice.cpp b/src/add-ons/kernel/busses/random/VirtioRNGDevice.cpp index 2e569c8d38..f431e5b5ea 100644 --- a/src/add-ons/kernel/busses/random/VirtioRNGDevice.cpp +++ b/src/add-ons/kernel/busses/random/VirtioRNGDevice.cpp @@ -47,7 +47,7 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node) (void **)&fVirtioDevice); gDeviceManager->put_node(virtioParent); - fVirtio->negociate_features(fVirtioDevice, + fVirtio->negotiate_features(fVirtioDevice, 0, &fFeatures, &get_feature_name); fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue); @@ -61,6 +61,13 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node) ERROR("interrupt setup failed (%s)\n", strerror(fStatus)); return; } + + fStatus = fVirtio->queue_setup_interrupt(fVirtioQueue, _RequestCallback, + this); + if (fStatus != B_OK) { + ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus)); + return; + } } @@ -88,7 +95,7 @@ VirtioRNGDevice::Read(void* _buffer, size_t* _numBytes) fInterruptCondition.Add(&fInterruptConditionEntry); } status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &fEntry, - _RequestCallback, this); + this); if (result != B_OK) { ERROR("queueing failed (%s)\n", strerror(result)); return result; @@ -123,6 +130,10 @@ void VirtioRNGDevice::_RequestCallback(void* driverCookie, void* cookie) { VirtioRNGDevice* device = (VirtioRNGDevice*)driverCookie; + + while (device->fVirtio->queue_dequeue(device->fVirtioQueue, NULL) != NULL) + ; + device->_RequestInterrupt(); } diff --git a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp index eed726ca10..0a73d47c06 100644 --- a/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp +++ b/src/add-ons/kernel/busses/scsi/virtio/VirtioSCSIController.cpp @@ -56,7 +56,7 @@ VirtioSCSIController::VirtioSCSIController(device_node *node) (void **)&fVirtioDevice); gDeviceManager->put_node(virtioParent); - fVirtio->negociate_features(fVirtioDevice, + fVirtio->negotiate_features(fVirtioDevice, VIRTIO_SCSI_F_CHANGE /*VIRTIO_SCSI_F_HOTPLUG*/, &fFeatures, &get_feature_name); @@ -101,7 +101,21 @@ VirtioSCSIController::VirtioSCSIController(device_node *node) return; } + fStatus = fVirtio->queue_setup_interrupt(fControlVirtioQueue, + NULL, NULL); + if (fStatus == B_OK) { + fStatus = fVirtio->queue_setup_interrupt(fEventVirtioQueue, + VirtioSCSIController::_EventCallback, this); + } + if (fStatus == B_OK) { + fStatus = fVirtio->queue_setup_interrupt(fRequestVirtioQueue, + VirtioSCSIController::_RequestCallback, this); + } + if (fStatus != B_OK) { + ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus)); + return; + } } @@ -224,7 +238,7 @@ VirtioSCSIController::ExecuteRequest(scsi_ccb *ccb) } fVirtio->queue_request_v(fRequestVirtioQueue, entries, - outCount, inCount, VirtioSCSIController::_RequestCallback, NULL); + outCount, inCount, NULL); result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT, fRequest->Timeout()); @@ -269,6 +283,11 @@ VirtioSCSIController::_RequestCallback(void* driverCookie, void* cookie) { CALLED(); VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie; + + while (controller->fVirtio->queue_dequeue( + controller->fRequestVirtioQueue, NULL) != NULL) { + } + controller->_RequestInterrupt(); } @@ -287,8 +306,15 @@ VirtioSCSIController::_EventCallback(void* driverCookie, void* cookie) { CALLED(); VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie; - struct virtio_scsi_event* event = (struct virtio_scsi_event*)cookie; - controller->_EventInterrupt(event); + + while (true) { + virtio_scsi_event* event = (virtio_scsi_event*) + controller->fVirtio->queue_dequeue(controller->fEventVirtioQueue, + NULL); + if (event == NULL) + break; + controller->_EventInterrupt(event); + } } @@ -336,7 +362,7 @@ VirtioSCSIController::_SubmitEvent(uint32 eventNumber) get_memory_map(event, sizeof(struct virtio_scsi_event), &entry, 1); fVirtio->queue_request_v(fEventVirtioQueue, &entry, - 0, 1, VirtioSCSIController::_EventCallback, event); + 0, 1, event); } diff --git a/src/add-ons/kernel/drivers/disk/virtual/virtio_block/virtio_block.cpp b/src/add-ons/kernel/drivers/disk/virtual/virtio_block/virtio_block.cpp index a1a6d1d316..db98cb5055 100644 --- a/src/add-ons/kernel/drivers/disk/virtual/virtio_block/virtio_block.cpp +++ b/src/add-ons/kernel/drivers/disk/virtual/virtio_block/virtio_block.cpp @@ -188,6 +188,10 @@ virtio_block_callback(void* driverCookie, void* cookie) { virtio_block_driver_info* info = (virtio_block_driver_info*)cookie; + // consume all queued elements + while (info->virtio->queue_dequeue(info->virtio_queue, NULL) != NULL) + ; + release_sem_etc(info->sem_cb, 1, B_DO_NOT_RESCHEDULE); } @@ -224,7 +228,7 @@ do_io(void* cookie, IOOperation* operation) info->virtio->queue_request_v(info->virtio_queue, entries, 1 + (operation->IsWrite() ? operation->VecCount() : 0 ), 1 + (operation->IsWrite() ? 0 : operation->VecCount()), - virtio_block_callback, info); + info); acquire_sem(info->sem_cb); @@ -295,6 +299,11 @@ virtio_block_init_device(void* _info, void** _cookie) status = info->virtio->setup_interrupt(info->virtio_device, virtio_block_config_callback, info); + if (status == B_OK) { + status = info->virtio->queue_setup_interrupt(info->virtio_queue, + virtio_block_callback, info); + } + *_cookie = info; return status; } diff --git a/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp b/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp index 078a408af4..fc72f2b3b9 100644 --- a/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp +++ b/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp @@ -78,6 +78,10 @@ typedef struct { static device_manager_info* sDeviceManager; +static void virtio_net_rx_done(void* driverCookie, void* cookie); +static void virtio_net_tx_done(void* driverCookie, void* cookie); + + const char * get_feature_name(uint32 feature) { @@ -143,7 +147,7 @@ virtio_net_init_device(void* _info, void** _cookie) (void **)&info->virtio_device); sDeviceManager->put_node(parent); - info->virtio->negociate_features(info->virtio_device, + info->virtio->negotiate_features(info->virtio_device, VIRTIO_NET_F_STATUS | VIRTIO_NET_F_MAC /* VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_MQ */, &info->features, &get_feature_name); @@ -201,6 +205,29 @@ virtio_net_init_device(void* _info, void** _cookie) return status; } + status = info->virtio->queue_setup_interrupt(info->rx_queues[0], + virtio_net_rx_done, info); + if (status != B_OK) { + ERROR("queue interrupt setup failed (%s)\n", strerror(status)); + return status; + } + + status = info->virtio->queue_setup_interrupt(info->tx_queues[0], + virtio_net_tx_done, info); + if (status != B_OK) { + ERROR("queue interrupt setup failed (%s)\n", strerror(status)); + return status; + } + + if ((info->features & VIRTIO_NET_F_CTRL_VQ) != 0) { + status = info->virtio->queue_setup_interrupt(info->ctrl_queue, + NULL, info); + if (status != B_OK) { + ERROR("queue interrupt setup failed (%s)\n", strerror(status)); + return status; + } + } + *_cookie = info; return B_OK; } @@ -271,7 +298,9 @@ virtio_net_rx_done(void* driverCookie, void* cookie) { CALLED(); virtio_net_driver_info* info = (virtio_net_driver_info*)cookie; - release_sem_etc(info->rx_done, 1, B_DO_NOT_RESCHEDULE); + + while (info->virtio->queue_dequeue(info->rx_queues[0], NULL) != NULL) + release_sem_etc(info->rx_done, 1, B_DO_NOT_RESCHEDULE); } @@ -292,7 +321,7 @@ virtio_net_read(void* cookie, off_t pos, void* buffer, size_t* _length) // queue the rx buffer status_t status = info->virtio->queue_request_v(info->rx_queues[0], - entries, 0, 2, virtio_net_rx_done, info); + entries, 0, 2, info); if (status != B_OK) { ERROR("rx queueing on queue %d failed (%s)\n", 0, strerror(status)); return status; @@ -316,7 +345,9 @@ virtio_net_tx_done(void* driverCookie, void* cookie) { CALLED(); virtio_net_driver_info* info = (virtio_net_driver_info*)cookie; - release_sem_etc(info->tx_done, 1, B_DO_NOT_RESCHEDULE); + + while (info->virtio->queue_dequeue(info->tx_queues[0], NULL) != NULL) + release_sem_etc(info->tx_done, 1, B_DO_NOT_RESCHEDULE); } @@ -343,14 +374,14 @@ virtio_net_write(void* cookie, off_t pos, const void* buffer, // queue the virtio_net_hdr + buffer data status_t status = info->virtio->queue_request_v(info->tx_queues[0], - entries, 2, 0, virtio_net_tx_done, info); + entries, 2, 0, info); if (status != B_OK) { ERROR("tx queueing on queue %d failed (%s)\n", 0, strerror(status)); return status; } // wait for transmission done signal - status = acquire_sem_etc(info->tx_done, 1, B_RELATIVE_TIMEOUT, 10000); + status = acquire_sem_etc(info->tx_done, 1, B_RELATIVE_TIMEOUT, 100000); if (status != B_OK) { ERROR("acquire_sem(tx_done) failed (%s)\n", strerror(status)); return status;