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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user