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
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;
@@ -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);
}
@@ -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 = {
@@ -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
@@ -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;
@@ -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();
}
@@ -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);
}
@@ -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;
}
@@ -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;