Virtio: implemented indirect descriptors feature.
* indirect descriptors count hardcoded to 128. * already activated for virtio_block driver.
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user