virtio: refactor to have a handler per queue.

* enable to iterate on available entries in one interrupt call.
* negociate -> negotiate, (void *) -> (void* ), thanks axel and philippe!

Change-Id: Ie2d290797abcbf4c0f3cb5bfff71d091bb800fa6
This commit is contained in:
Jérôme Duval
2018-04-26 06:25:15 +00:00
parent 30764e3821
commit 6e82e42859
9 changed files with 229 additions and 118 deletions
+13 -9
View File
@@ -53,9 +53,9 @@ typedef void* virtio_device;
// queue cookie, issued by virtio bus manager // queue cookie, issued by virtio bus manager
typedef void* virtio_queue; typedef void* virtio_queue;
// callback function for requests // 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 // 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" #define VIRTIO_DEVICE_MODULE_NAME "bus_managers/virtio/device/v1"
@@ -93,8 +93,8 @@ typedef struct {
typedef struct { typedef struct {
driver_module_info info; driver_module_info info;
status_t (*negociate_features)(virtio_device cookie, uint32 supported, status_t (*negotiate_features)(virtio_device cookie, uint32 supported,
uint32* negociated, const char* (*get_feature_name)(uint32)); uint32* negotiated, const char* (*get_feature_name)(uint32));
status_t (*read_device_config)(virtio_device cookie, uint8 offset, status_t (*read_device_config)(virtio_device cookie, uint8 offset,
void* buffer, size_t bufferSize); void* buffer, size_t bufferSize);
@@ -102,20 +102,22 @@ typedef struct {
const void* buffer, size_t bufferSize); const void* buffer, size_t bufferSize);
status_t (*alloc_queues)(virtio_device cookie, size_t count, status_t (*alloc_queues)(virtio_device cookie, size_t count,
virtio_queue *queues); virtio_queue* queues);
status_t (*setup_interrupt)(virtio_device cookie, status_t (*setup_interrupt)(virtio_device cookie,
virtio_intr_func config_handler, void* driverCookie); 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, status_t (*queue_request)(virtio_queue queue,
const physical_entry *readEntry, const physical_entry* readEntry,
const physical_entry *writtenEntry, virtio_callback_func callback, const physical_entry* writtenEntry, void* cookie);
void *callbackCookie);
status_t (*queue_request_v)(virtio_queue queue, status_t (*queue_request_v)(virtio_queue queue,
const physical_entry* vector, const physical_entry* vector,
size_t readVectorCount, size_t writtenVectorCount, size_t readVectorCount, size_t writtenVectorCount,
virtio_callback_func callback, void *callbackCookie); void* cookie);
bool (*queue_is_full)(virtio_queue queue); bool (*queue_is_full)(virtio_queue queue);
@@ -123,6 +125,8 @@ typedef struct {
uint16 (*queue_size)(virtio_queue queue); uint16 (*queue_size)(virtio_queue queue);
void* (*queue_dequeue)(virtio_queue queue, uint16* _size);
} virtio_device_interface; } virtio_device_interface;
@@ -101,7 +101,7 @@ VirtioDevice::InitCheck()
status_t status_t
VirtioDevice::NegociateFeatures(uint32 supported, uint32* negociated, VirtioDevice::NegotiateFeatures(uint32 supported, uint32* negotiated,
const char* (*get_feature_name)(uint32)) const char* (*get_feature_name)(uint32))
{ {
fFeatures = 0; fFeatures = 0;
@@ -117,9 +117,9 @@ VirtioDevice::NegociateFeatures(uint32 supported, uint32* negociated,
fFeatures &= (VIRTIO_FEATURE_TRANSPORT_MASK fFeatures &= (VIRTIO_FEATURE_TRANSPORT_MASK
| VIRTIO_FEATURE_RING_INDIRECT_DESC | VIRTIO_FEATURE_RING_EVENT_IDX); | 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); return fController->write_guest_features(fCookie, fFeatures);
} }
@@ -14,7 +14,7 @@ device_manager_info *gDeviceManager = NULL;
static status_t static status_t
virtio_device_init(device_node *node, void **cookie) virtio_device_init(device_node *node, void **_device)
{ {
CALLED(); CALLED();
VirtioDevice *device = new(std::nothrow) VirtioDevice(node); VirtioDevice *device = new(std::nothrow) VirtioDevice(node);
@@ -27,25 +27,25 @@ virtio_device_init(device_node *node, void **cookie)
return result; return result;
} }
*cookie = device; *_device = device;
return B_OK; return B_OK;
} }
static void static void
virtio_device_uninit(void *cookie) virtio_device_uninit(void *_device)
{ {
CALLED(); CALLED();
VirtioDevice *device = (VirtioDevice *)cookie; VirtioDevice *device = (VirtioDevice *)_device;
delete device; delete device;
} }
static void static void
virtio_device_removed(void *cookie) virtio_device_removed(void *_device)
{ {
CALLED(); CALLED();
//VirtioDevice *device = (VirtioDevice *)cookie; //VirtioDevice *device = (VirtioDevice *)_device;
} }
@@ -53,73 +53,81 @@ virtio_device_removed(void *cookie)
status_t status_t
virtio_negociate_features(void* cookie, uint32 supported, virtio_negotiate_features(void* _device, uint32 supported,
uint32* negociated, const char* (*get_feature_name)(uint32)) uint32* negotiated, const char* (*get_feature_name)(uint32))
{ {
CALLED(); 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 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) size_t bufferSize)
{ {
CALLED(); CALLED();
VirtioDevice *device = (VirtioDevice *)cookie; VirtioDevice *device = (VirtioDevice *)_device;
return device->ReadDeviceConfig(offset, buffer, bufferSize); return device->ReadDeviceConfig(offset, buffer, bufferSize);
} }
status_t status_t
virtio_write_device_config(void* cookie, uint8 offset, virtio_write_device_config(void* _device, uint8 offset,
const void* buffer, size_t bufferSize) const void* buffer, size_t bufferSize)
{ {
CALLED(); CALLED();
VirtioDevice *device = (VirtioDevice *)cookie; VirtioDevice *device = (VirtioDevice *)_device;
return device->WriteDeviceConfig(offset, buffer, bufferSize); return device->WriteDeviceConfig(offset, buffer, bufferSize);
} }
status_t 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(); CALLED();
VirtioDevice *device = (VirtioDevice *)cookie; VirtioDevice *device = (VirtioDevice *)_device;
return device->AllocateQueues(count, queues); return device->AllocateQueues(count, queues);
} }
status_t 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) void *driverCookie)
{ {
CALLED(); CALLED();
VirtioDevice *device = (VirtioDevice *)cookie; VirtioDevice *device = (VirtioDevice *)_device;
return device->SetupInterrupt(config_handler, driverCookie); return device->SetupInterrupt(config_handler, driverCookie);
} }
status_t status_t
virtio_queue_request_v(virtio_queue cookie, const physical_entry* vector, virtio_queue_setup_interrupt(virtio_queue _queue, virtio_callback_func handler,
size_t readVectorCount, size_t writtenVectorCount, void *cookie)
virtio_callback_func callback, void *callbackCookie)
{ {
CALLED(); CALLED();
VirtioQueue *queue = (VirtioQueue *)cookie; VirtioQueue *queue = (VirtioQueue *)_queue;
return queue->QueueRequest(vector, readVectorCount, writtenVectorCount, return queue->SetupInterrupt(handler, cookie);
callback, callbackCookie);
} }
status_t status_t
virtio_queue_request(virtio_queue cookie, const physical_entry *readEntry, virtio_queue_request_v(virtio_queue _queue, const physical_entry* vector,
const physical_entry *writtenEntry, virtio_callback_func callback, size_t readVectorCount, size_t writtenVectorCount, void *cookie)
void *callbackCookie) {
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]; physical_entry entries[2];
if (readEntry != NULL) { if (readEntry != NULL) {
@@ -129,35 +137,42 @@ virtio_queue_request(virtio_queue cookie, const physical_entry *readEntry,
} else if (writtenEntry != NULL) } else if (writtenEntry != NULL)
entries[0] = *writtenEntry; entries[0] = *writtenEntry;
return virtio_queue_request_v(cookie, entries, readEntry != NULL ? 1 : 0, return virtio_queue_request_v(_queue, entries, readEntry != NULL ? 1 : 0,
writtenEntry != NULL? 1 : 0, callback, callbackCookie); writtenEntry != NULL? 1 : 0, cookie);
} }
bool 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(); return queue->IsFull();
} }
bool 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(); return queue->IsEmpty();
} }
uint16 uint16
virtio_queue_size(virtio_queue cookie) virtio_queue_size(virtio_queue _queue)
{ {
VirtioQueue *queue = (VirtioQueue *)cookie; VirtioQueue *queue = (VirtioQueue *)_queue;
return queue->Size(); return queue->Size();
} }
void*
virtio_queue_dequeue(virtio_queue _queue, uint16* _size)
{
VirtioQueue *queue = (VirtioQueue *)_queue;
return queue->Dequeue(_size);
}
// #pragma mark - // #pragma mark -
@@ -241,16 +256,18 @@ virtio_device_interface virtio_device_module = {
NULL, // resume NULL, // resume
}, },
virtio_negociate_features, virtio_negotiate_features,
virtio_read_device_config, virtio_read_device_config,
virtio_write_device_config, virtio_write_device_config,
virtio_alloc_queues, virtio_alloc_queues,
virtio_setup_interrupt, virtio_setup_interrupt,
virtio_queue_setup_interrupt,
virtio_queue_request, virtio_queue_request,
virtio_queue_request_v, virtio_queue_request_v,
virtio_queue_is_full, virtio_queue_is_full,
virtio_queue_is_empty, virtio_queue_is_empty,
virtio_queue_size virtio_queue_size,
virtio_queue_dequeue
}; };
virtio_for_controller_interface virtio_for_controller_module = { virtio_for_controller_interface virtio_for_controller_module = {
@@ -45,8 +45,8 @@ public:
status_t InitCheck(); status_t InitCheck();
uint32 ID() const { return fID; } uint32 ID() const { return fID; }
status_t NegociateFeatures(uint32 supported, status_t NegotiateFeatures(uint32 supported,
uint32* negociated, uint32* negotiated,
const char* (*get_feature_name)(uint32)); const char* (*get_feature_name)(uint32));
status_t ReadDeviceConfig(uint8 offset, void* buffer, status_t ReadDeviceConfig(uint8 offset, void* buffer,
@@ -114,17 +114,21 @@ public:
status_t QueueRequest(const physical_entry* vector, status_t QueueRequest(const physical_entry* vector,
size_t readVectorCount, size_t readVectorCount,
size_t writtenVectorCount, size_t writtenVectorCount,
virtio_callback_func callback, void *cookie);
void *callbackCookie);
status_t QueueRequestIndirect( status_t QueueRequestIndirect(
const physical_entry* vector, const physical_entry* vector,
size_t readVectorCount, size_t readVectorCount,
size_t writtenVectorCount, size_t writtenVectorCount,
virtio_callback_func callback, void *cookie);
void *callbackCookie);
status_t SetupInterrupt(virtio_callback_func handler,
void *cookie);
void EnableInterrupt(); void EnableInterrupt();
void DisableInterrupt(); void DisableInterrupt();
void* Dequeue(uint16* _size = NULL);
private: private:
void UpdateAvailable(uint16 index); void UpdateAvailable(uint16 index);
uint16 QueueVector(uint16 insertIndex, uint16 QueueVector(uint16 insertIndex,
@@ -132,7 +136,6 @@ private:
const physical_entry* vector, const physical_entry* vector,
size_t readVectorCount, size_t readVectorCount,
size_t writtenVectorCount); size_t writtenVectorCount);
void Finish();
VirtioDevice* fDevice; VirtioDevice* fDevice;
uint16 fQueueNumber; uint16 fQueueNumber;
@@ -149,6 +152,10 @@ private:
uint16 fIndirectMaxSize; uint16 fIndirectMaxSize;
TransferDescriptor** fDescriptors; TransferDescriptor** fDescriptors;
virtio_callback_func fCallback;
void* fCookie;
}; };
#endif // VIRTIO_PRIVATE_H #endif // VIRTIO_PRIVATE_H
@@ -56,11 +56,9 @@ public:
status_t InitCheck() { return fStatus; } status_t InitCheck() { return fStatus; }
void Callback();
uint16 Size() { return fDescriptorCount; } uint16 Size() { return fDescriptorCount; }
void SetTo(uint16 size, void SetTo(uint16 size, void *cookie);
virtio_callback_func callback, void* Cookie() { return fCookie; }
void *callbackCookie);
void Unset(); void Unset();
struct vring_desc* Indirect() { return fIndirect; } struct vring_desc* Indirect() { return fIndirect; }
phys_addr_t PhysAddr() { return fPhysAddr; } phys_addr_t PhysAddr() { return fPhysAddr; }
@@ -68,7 +66,6 @@ private:
status_t fStatus; status_t fStatus;
VirtioQueue* fQueue; VirtioQueue* fQueue;
void* fCookie; void* fCookie;
virtio_callback_func fCallback;
struct vring_desc* fIndirect; struct vring_desc* fIndirect;
size_t fAreaSize; size_t fAreaSize;
@@ -81,7 +78,6 @@ private:
TransferDescriptor::TransferDescriptor(VirtioQueue* queue, uint16 indirectMaxSize) TransferDescriptor::TransferDescriptor(VirtioQueue* queue, uint16 indirectMaxSize)
: fQueue(queue), : fQueue(queue),
fCookie(NULL), fCookie(NULL),
fCallback(NULL),
fIndirect(NULL), fIndirect(NULL),
fAreaSize(0), fAreaSize(0),
fArea(-1), fArea(-1),
@@ -119,19 +115,9 @@ TransferDescriptor::~TransferDescriptor()
void void
TransferDescriptor::Callback() TransferDescriptor::SetTo(uint16 size, void *cookie)
{ {
if (fCallback != NULL) fCookie = cookie;
fCallback(fQueue->Device()->DriverCookie(), fCookie);
}
void
TransferDescriptor::SetTo(uint16 size, virtio_callback_func callback,
void *callbackCookie)
{
fCookie = callbackCookie;
fCallback = callback;
fDescriptorCount = size; fDescriptorCount = size;
} }
@@ -140,7 +126,6 @@ void
TransferDescriptor::Unset() TransferDescriptor::Unset()
{ {
fCookie = NULL; fCookie = NULL;
fCallback = NULL;
fDescriptorCount = 0; fDescriptorCount = 0;
} }
@@ -158,7 +143,9 @@ VirtioQueue::VirtioQueue(VirtioDevice* device, uint16 queueNumber,
fRingHeadIndex(0), fRingHeadIndex(0),
fRingUsedIndex(0), fRingUsedIndex(0),
fStatus(B_OK), fStatus(B_OK),
fIndirectMaxSize(0) fIndirectMaxSize(0),
fCallback(NULL),
fCookie(NULL)
{ {
fDescriptors = new(std::nothrow) TransferDescriptor*[fRingSize]; fDescriptors = new(std::nothrow) TransferDescriptor*[fRingSize];
if (fDescriptors == NULL) { 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 void
VirtioQueue::DisableInterrupt() VirtioQueue::DisableInterrupt()
{ {
/*if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0) if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0)
fRing.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;*/ fRing.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
} }
void void
VirtioQueue::EnableInterrupt() VirtioQueue::EnableInterrupt()
{ {
/*if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0) if ((fDevice->Features() & VIRTIO_FEATURE_RING_EVENT_IDX) == 0)
fRing.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;*/ fRing.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
} }
@@ -236,52 +234,63 @@ status_t
VirtioQueue::Interrupt() VirtioQueue::Interrupt()
{ {
CALLED(); CALLED();
DisableInterrupt(); DisableInterrupt();
while (fRingUsedIndex != fRing.used->idx) if (fCallback != NULL)
Finish(); fCallback(Device()->DriverCookie(), fCookie);
EnableInterrupt(); EnableInterrupt();
return B_OK; return B_OK;
} }
void void*
VirtioQueue::Finish() 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); 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]; struct vring_used_elem *element = &fRing.used->ring[usedIndex];
uint16 descriptorIndex = element->id; uint16 descriptorIndex = element->id;
// uint32 length = element->len; // uint32 length = element->len;
fDescriptors[descriptorIndex]->Callback(); void* cookie = fDescriptors[descriptorIndex]->Cookie();
uint16 size = fDescriptors[descriptorIndex]->Size(); uint16 size = fDescriptors[descriptorIndex]->Size();
if (_size != NULL)
*_size = size;
if (size == 0)
panic("VirtioQueue::Dequeue() size is zero\n");
fDescriptors[descriptorIndex]->Unset(); fDescriptors[descriptorIndex]->Unset();
fRingFree += size; fRingFree += size;
size--; size--;
uint16 index = descriptorIndex; uint16 index = descriptorIndex;
while ((fRing.desc[index].flags & VRING_DESC_F_NEXT) != 0) { if ((fRing.desc[index].flags & VRING_DESC_F_INDIRECT) == 0) {
index = fRing.desc[index].next; while ((fRing.desc[index].flags & VRING_DESC_F_NEXT) != 0) {
size--; index = fRing.desc[index].next;
size--;
}
} }
if (size > 0) if (size > 0)
panic("VirtioQueue::Finish() descriptors left %d\n", size); panic("VirtioQueue::Dequeue() descriptors left %d\n", size);
fRing.desc[index].next = fRingHeadIndex; fRing.desc[index].next = fRingHeadIndex;
fRingHeadIndex = descriptorIndex; fRingHeadIndex = descriptorIndex;
TRACE("Finish() fRingHeadIndex: %u\n", fRingHeadIndex); TRACE("Dequeue() fRingHeadIndex: %u\n", fRingHeadIndex);
return cookie;
} }
status_t status_t
VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount, VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount,
size_t writtenVectorCount, virtio_callback_func callback, size_t writtenVectorCount, void *cookie)
void *callbackCookie)
{ {
CALLED(); CALLED();
size_t count = readVectorCount + writtenVectorCount; size_t count = readVectorCount + writtenVectorCount;
@@ -289,15 +298,14 @@ VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount,
return B_BAD_VALUE; return B_BAD_VALUE;
if ((fDevice->Features() & VIRTIO_FEATURE_RING_INDIRECT_DESC) != 0) { if ((fDevice->Features() & VIRTIO_FEATURE_RING_INDIRECT_DESC) != 0) {
return QueueRequestIndirect(vector, readVectorCount, return QueueRequestIndirect(vector, readVectorCount,
writtenVectorCount, callback, callbackCookie); writtenVectorCount, cookie);
} }
if (count > fRingFree) if (count > fRingFree)
return B_BUSY; return B_BUSY;
uint16 insertIndex = fRingHeadIndex; uint16 insertIndex = fRingHeadIndex;
fDescriptors[insertIndex]->SetTo(count, callback, fDescriptors[insertIndex]->SetTo(count, cookie);
callbackCookie);
// enqueue // enqueue
uint16 index = QueueVector(insertIndex, fRing.desc, vector, uint16 index = QueueVector(insertIndex, fRing.desc, vector,
@@ -317,7 +325,7 @@ VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount,
status_t status_t
VirtioQueue::QueueRequestIndirect(const physical_entry* vector, VirtioQueue::QueueRequestIndirect(const physical_entry* vector,
size_t readVectorCount, size_t writtenVectorCount, size_t readVectorCount, size_t writtenVectorCount,
virtio_callback_func callback, void *callbackCookie) void *cookie)
{ {
CALLED(); CALLED();
size_t count = readVectorCount + writtenVectorCount; size_t count = readVectorCount + writtenVectorCount;
@@ -325,8 +333,7 @@ VirtioQueue::QueueRequestIndirect(const physical_entry* vector,
return B_BUSY; return B_BUSY;
uint16 insertIndex = fRingHeadIndex; uint16 insertIndex = fRingHeadIndex;
fDescriptors[insertIndex]->SetTo(1, callback, fDescriptors[insertIndex]->SetTo(1, cookie);
callbackCookie);
// enqueue // enqueue
uint16 index = QueueVector(0, fDescriptors[insertIndex]->Indirect(), uint16 index = QueueVector(0, fDescriptors[insertIndex]->Indirect(),
@@ -364,15 +371,14 @@ VirtioQueue::QueueVector(uint16 insertIndex, struct vring_desc *desc,
CALLED(); CALLED();
uint16 index = insertIndex; uint16 index = insertIndex;
size_t total = readVectorCount + writtenVectorCount; 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].addr = vector[i].address;
desc[index].len = vector[i].size; desc[index].len = vector[i].size;
desc[index].flags = 0; desc[index].flags = 0;
if (i >= readVectorCount)
desc[index].flags |= VRING_DESC_F_WRITE;
if (i < total - 1) if (i < total - 1)
desc[index].flags |= VRING_DESC_F_NEXT; desc[index].flags |= VRING_DESC_F_NEXT;
index = desc[index].next; if (i >= readVectorCount)
desc[index].flags |= VRING_DESC_F_WRITE;
} }
return index; return index;
@@ -47,7 +47,7 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node)
(void **)&fVirtioDevice); (void **)&fVirtioDevice);
gDeviceManager->put_node(virtioParent); gDeviceManager->put_node(virtioParent);
fVirtio->negociate_features(fVirtioDevice, fVirtio->negotiate_features(fVirtioDevice,
0, &fFeatures, &get_feature_name); 0, &fFeatures, &get_feature_name);
fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue); fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue);
@@ -61,6 +61,13 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node)
ERROR("interrupt setup failed (%s)\n", strerror(fStatus)); ERROR("interrupt setup failed (%s)\n", strerror(fStatus));
return; 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); fInterruptCondition.Add(&fInterruptConditionEntry);
} }
status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &fEntry, status_t result = fVirtio->queue_request(fVirtioQueue, NULL, &fEntry,
_RequestCallback, this); this);
if (result != B_OK) { if (result != B_OK) {
ERROR("queueing failed (%s)\n", strerror(result)); ERROR("queueing failed (%s)\n", strerror(result));
return result; return result;
@@ -123,6 +130,10 @@ void
VirtioRNGDevice::_RequestCallback(void* driverCookie, void* cookie) VirtioRNGDevice::_RequestCallback(void* driverCookie, void* cookie)
{ {
VirtioRNGDevice* device = (VirtioRNGDevice*)driverCookie; VirtioRNGDevice* device = (VirtioRNGDevice*)driverCookie;
while (device->fVirtio->queue_dequeue(device->fVirtioQueue, NULL) != NULL)
;
device->_RequestInterrupt(); device->_RequestInterrupt();
} }
@@ -56,7 +56,7 @@ VirtioSCSIController::VirtioSCSIController(device_node *node)
(void **)&fVirtioDevice); (void **)&fVirtioDevice);
gDeviceManager->put_node(virtioParent); gDeviceManager->put_node(virtioParent);
fVirtio->negociate_features(fVirtioDevice, fVirtio->negotiate_features(fVirtioDevice,
VIRTIO_SCSI_F_CHANGE /*VIRTIO_SCSI_F_HOTPLUG*/, VIRTIO_SCSI_F_CHANGE /*VIRTIO_SCSI_F_HOTPLUG*/,
&fFeatures, &get_feature_name); &fFeatures, &get_feature_name);
@@ -101,7 +101,21 @@ VirtioSCSIController::VirtioSCSIController(device_node *node)
return; 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, fVirtio->queue_request_v(fRequestVirtioQueue, entries,
outCount, inCount, VirtioSCSIController::_RequestCallback, NULL); outCount, inCount, NULL);
result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT, result = fInterruptConditionEntry.Wait(B_RELATIVE_TIMEOUT,
fRequest->Timeout()); fRequest->Timeout());
@@ -269,6 +283,11 @@ VirtioSCSIController::_RequestCallback(void* driverCookie, void* cookie)
{ {
CALLED(); CALLED();
VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie; VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie;
while (controller->fVirtio->queue_dequeue(
controller->fRequestVirtioQueue, NULL) != NULL) {
}
controller->_RequestInterrupt(); controller->_RequestInterrupt();
} }
@@ -287,8 +306,15 @@ VirtioSCSIController::_EventCallback(void* driverCookie, void* cookie)
{ {
CALLED(); CALLED();
VirtioSCSIController* controller = (VirtioSCSIController*)driverCookie; 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); get_memory_map(event, sizeof(struct virtio_scsi_event), &entry, 1);
fVirtio->queue_request_v(fEventVirtioQueue, &entry, fVirtio->queue_request_v(fEventVirtioQueue, &entry,
0, 1, VirtioSCSIController::_EventCallback, event); 0, 1, event);
} }
@@ -188,6 +188,10 @@ virtio_block_callback(void* driverCookie, void* cookie)
{ {
virtio_block_driver_info* info = (virtio_block_driver_info*)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); 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, info->virtio->queue_request_v(info->virtio_queue, entries,
1 + (operation->IsWrite() ? operation->VecCount() : 0 ), 1 + (operation->IsWrite() ? operation->VecCount() : 0 ),
1 + (operation->IsWrite() ? 0 : operation->VecCount()), 1 + (operation->IsWrite() ? 0 : operation->VecCount()),
virtio_block_callback, info); info);
acquire_sem(info->sem_cb); 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, status = info->virtio->setup_interrupt(info->virtio_device,
virtio_block_config_callback, info); virtio_block_config_callback, info);
if (status == B_OK) {
status = info->virtio->queue_setup_interrupt(info->virtio_queue,
virtio_block_callback, info);
}
*_cookie = info; *_cookie = info;
return status; return status;
} }
@@ -78,6 +78,10 @@ typedef struct {
static device_manager_info* sDeviceManager; 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 * const char *
get_feature_name(uint32 feature) get_feature_name(uint32 feature)
{ {
@@ -143,7 +147,7 @@ virtio_net_init_device(void* _info, void** _cookie)
(void **)&info->virtio_device); (void **)&info->virtio_device);
sDeviceManager->put_node(parent); 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_STATUS | VIRTIO_NET_F_MAC
/* VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_MQ */, /* VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_MQ */,
&info->features, &get_feature_name); &info->features, &get_feature_name);
@@ -201,6 +205,29 @@ virtio_net_init_device(void* _info, void** _cookie)
return status; 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; *_cookie = info;
return B_OK; return B_OK;
} }
@@ -271,7 +298,9 @@ virtio_net_rx_done(void* driverCookie, void* cookie)
{ {
CALLED(); CALLED();
virtio_net_driver_info* info = (virtio_net_driver_info*)cookie; 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 // queue the rx buffer
status_t status = info->virtio->queue_request_v(info->rx_queues[0], 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) { if (status != B_OK) {
ERROR("rx queueing on queue %d failed (%s)\n", 0, strerror(status)); ERROR("rx queueing on queue %d failed (%s)\n", 0, strerror(status));
return status; return status;
@@ -316,7 +345,9 @@ virtio_net_tx_done(void* driverCookie, void* cookie)
{ {
CALLED(); CALLED();
virtio_net_driver_info* info = (virtio_net_driver_info*)cookie; 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 // queue the virtio_net_hdr + buffer data
status_t status = info->virtio->queue_request_v(info->tx_queues[0], 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) { if (status != B_OK) {
ERROR("tx queueing on queue %d failed (%s)\n", 0, strerror(status)); ERROR("tx queueing on queue %d failed (%s)\n", 0, strerror(status));
return status; return status;
} }
// wait for transmission done signal // 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) { if (status != B_OK) {
ERROR("acquire_sem(tx_done) failed (%s)\n", strerror(status)); ERROR("acquire_sem(tx_done) failed (%s)\n", strerror(status));
return status; return status;