Virtio: implemented indirect descriptors feature.

* indirect descriptors count hardcoded to 128.
* already activated for virtio_block driver.
This commit is contained in:
Jérôme Duval
2013-07-23 23:00:20 +02:00
parent 17c55998dc
commit b5ccadd7c2
3 changed files with 105 additions and 18 deletions
@@ -115,7 +115,7 @@ VirtioDevice::NegociateFeatures(uint32 supported, uint32* negociated,
// filter our own features // filter our own features
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; *negociated = fFeatures;
@@ -254,4 +254,3 @@ VirtioDevice::DumpFeatures(const char* title, uint32 features,
} }
TRACE("%s: %s\n", title, features_string); TRACE("%s: %s\n", title, features_string);
} }
@@ -145,6 +145,8 @@ private:
size_t fAreaSize; size_t fAreaSize;
area_id fArea; area_id fArea;
uint16 fIndirectMaxSize;
TransferDescriptor** fDescriptors; TransferDescriptor** fDescriptors;
}; };
@@ -51,36 +51,69 @@ alloc_mem(void **virt, phys_addr_t *phy, size_t size, uint32 protection,
class TransferDescriptor { class TransferDescriptor {
public: public:
TransferDescriptor(VirtioQueue* queue, TransferDescriptor(VirtioQueue* queue,
uint16 size, uint16 indirectMaxSize);
virtio_callback_func callback,
void *callbackCookie);
~TransferDescriptor(); ~TransferDescriptor();
status_t InitCheck() { return fStatus; }
void Callback(); void Callback();
uint16 Size() { return fDescriptorCount; } uint16 Size() { return fDescriptorCount; }
void SetTo(uint16 size,
virtio_callback_func callback,
void *callbackCookie);
void Unset();
struct vring_desc* Indirect() { return fIndirect; }
phys_addr_t PhysAddr() { return fPhysAddr; }
private: private:
status_t fStatus;
VirtioQueue* fQueue; VirtioQueue* fQueue;
void* fCookie; void* fCookie;
virtio_callback_func fCallback; virtio_callback_func fCallback;
struct vring_desc* fIndirect; struct vring_desc* fIndirect;
size_t fAreaSize; size_t fAreaSize;
area_id fArea; area_id fArea;
phys_addr_t fPhysAddr;
uint16 fDescriptorCount; uint16 fDescriptorCount;
}; };
TransferDescriptor::TransferDescriptor(VirtioQueue* queue, uint16 size, TransferDescriptor::TransferDescriptor(VirtioQueue* queue, uint16 indirectMaxSize)
virtio_callback_func callback, void *callbackCookie)
: fQueue(queue), : fQueue(queue),
fCookie(callbackCookie), fCookie(NULL),
fCallback(callback), fCallback(NULL),
fDescriptorCount(size) fIndirect(NULL),
fAreaSize(0),
fArea(-1),
fDescriptorCount(0)
{ {
fStatus = B_OK;
struct vring_desc* virtAddr;
phys_addr_t physAddr;
if (indirectMaxSize > 0) {
fAreaSize = indirectMaxSize * sizeof(struct vring_desc);
fArea = alloc_mem((void **)&virtAddr, &physAddr, fAreaSize, 0,
"virtqueue");
if (fArea < B_OK) {
fStatus = fArea;
return;
}
memset(virtAddr, 0, fAreaSize);
fIndirect = virtAddr;
fPhysAddr = physAddr;
for (uint16 i = 0; i < indirectMaxSize - 1; i++)
fIndirect[i].next = i + 1;
fIndirect[indirectMaxSize - 1].next = UINT16_MAX;
}
} }
TransferDescriptor::~TransferDescriptor() TransferDescriptor::~TransferDescriptor()
{ {
if (fArea > B_OK)
delete_area(fArea);
} }
@@ -92,6 +125,25 @@ TransferDescriptor::Callback()
} }
void
TransferDescriptor::SetTo(uint16 size, virtio_callback_func callback,
void *callbackCookie)
{
fCookie = callbackCookie;
fCallback = callback;
fDescriptorCount = size;
}
void
TransferDescriptor::Unset()
{
fCookie = NULL;
fCallback = NULL;
fDescriptorCount = 0;
}
// #pragma mark - // #pragma mark -
@@ -104,7 +156,8 @@ VirtioQueue::VirtioQueue(VirtioDevice* device, uint16 queueNumber,
fRingFree(ringSize), fRingFree(ringSize),
fRingHeadIndex(0), fRingHeadIndex(0),
fRingUsedIndex(0), fRingUsedIndex(0),
fStatus(B_OK) fStatus(B_OK),
fIndirectMaxSize(0)
{ {
fDescriptors = new(std::nothrow) TransferDescriptor*[fRingSize]; fDescriptors = new(std::nothrow) TransferDescriptor*[fRingSize];
if (fDescriptors == NULL) { if (fDescriptors == NULL) {
@@ -128,6 +181,17 @@ VirtioQueue::VirtioQueue(VirtioDevice* device, uint16 queueNumber,
fRing.desc[i].next = i + 1; fRing.desc[i].next = i + 1;
fRing.desc[fRingSize - 1].next = UINT16_MAX; fRing.desc[fRingSize - 1].next = UINT16_MAX;
if ((fDevice->Features() & VIRTIO_FEATURE_RING_INDIRECT_DESC) != 0)
fIndirectMaxSize = 128;
for (uint16 i = 0; i < fRingSize; i++) {
fDescriptors[i] = new TransferDescriptor(this, fIndirectMaxSize);
if (fDescriptors[i] == NULL || fDescriptors[i]->InitCheck() != B_OK) {
fStatus = B_NO_MEMORY;
return;
}
}
DisableInterrupt(); DisableInterrupt();
device->SetupQueue(fQueueNumber, physAddr); device->SetupQueue(fQueueNumber, physAddr);
@@ -137,6 +201,9 @@ VirtioQueue::VirtioQueue(VirtioDevice* device, uint16 queueNumber,
VirtioQueue::~VirtioQueue() VirtioQueue::~VirtioQueue()
{ {
delete_area(fArea); delete_area(fArea);
for (uint16 i = 0; i < fRingSize; i++) {
delete fDescriptors[i];
}
delete[] fDescriptors; delete[] fDescriptors;
} }
@@ -191,6 +258,7 @@ VirtioQueue::Finish()
fDescriptors[descriptorIndex]->Callback(); fDescriptors[descriptorIndex]->Callback();
uint16 size = fDescriptors[descriptorIndex]->Size(); uint16 size = fDescriptors[descriptorIndex]->Size();
fDescriptors[descriptorIndex]->Unset();
fRingFree += size; fRingFree += size;
size--; size--;
@@ -203,8 +271,6 @@ VirtioQueue::Finish()
if (size > 0) if (size > 0)
panic("VirtioQueue::Finish() descriptors left %d\n", size); panic("VirtioQueue::Finish() descriptors left %d\n", size);
// TODO TransferDescriptors are leaked, can't delete in interrupt handler.
fRing.desc[index].next = fRingHeadIndex; fRing.desc[index].next = fRingHeadIndex;
fRingHeadIndex = descriptorIndex; fRingHeadIndex = descriptorIndex;
TRACE("Finish() fRingHeadIndex: %u\n", fRingHeadIndex); TRACE("Finish() fRingHeadIndex: %u\n", fRingHeadIndex);
@@ -229,10 +295,8 @@ VirtioQueue::QueueRequest(const physical_entry* vector, size_t readVectorCount,
return B_BUSY; return B_BUSY;
uint16 insertIndex = fRingHeadIndex; uint16 insertIndex = fRingHeadIndex;
fDescriptors[insertIndex] = new(std::nothrow) TransferDescriptor(this, fDescriptors[insertIndex]->SetTo(count, callback,
count, callback, callbackCookie); callbackCookie);
if (fDescriptors[insertIndex] == NULL)
return B_NO_MEMORY;
// enqueue // enqueue
uint16 index = QueueVector(insertIndex, fRing.desc, vector, uint16 index = QueueVector(insertIndex, fRing.desc, vector,
@@ -254,7 +318,29 @@ VirtioQueue::QueueRequestIndirect(const physical_entry* vector,
size_t readVectorCount, size_t writtenVectorCount, size_t readVectorCount, size_t writtenVectorCount,
virtio_callback_func callback, void *callbackCookie) virtio_callback_func callback, void *callbackCookie)
{ {
// TODO CALLED();
size_t count = readVectorCount + writtenVectorCount;
if (count > fRingFree || count > fIndirectMaxSize)
return B_BUSY;
uint16 insertIndex = fRingHeadIndex;
fDescriptors[insertIndex]->SetTo(1, callback,
callbackCookie);
// enqueue
uint16 index = QueueVector(0, fDescriptors[insertIndex]->Indirect(),
vector, readVectorCount, writtenVectorCount);
fRing.desc[insertIndex].addr = fDescriptors[insertIndex]->PhysAddr();
fRing.desc[insertIndex].len = index * sizeof(struct vring_desc);
fRing.desc[insertIndex].flags = VRING_DESC_F_INDIRECT;
fRingHeadIndex = fRing.desc[insertIndex].next;
fRingFree--;
UpdateAvailable(insertIndex);
NotifyHost();
return B_OK; return B_OK;
} }