virtio: Explicitly request queue sizes where needed.
Ensure that allocated queues can hold the amount of descriptors that were previously communicated to DMAResources in virtio_block and virtio_scsi. The queue allocations will now fail with B_BUFFER_OVERFLOW if the requested size cannot be provided. When requestedSizes are set to 0, no requirement is placed and the queue is sized to its advertised maximum. The requestedSizes argument can be NULL which implies all 0. Change-Id: Ifb1e032d48f8c07aedfe2bf941f32783842c8c12 Reviewed-on: https://review.haiku-os.org/c/haiku/+/8220 Reviewed-by: Jérôme Duval <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
a6a15d5e71
commit
b90dc7a4f3
@@ -117,7 +117,7 @@ typedef struct {
|
||||
const void* buffer, size_t bufferSize);
|
||||
|
||||
status_t (*alloc_queues)(virtio_device cookie, size_t count,
|
||||
virtio_queue* queues);
|
||||
virtio_queue* queues, uint16* requestedSizes);
|
||||
|
||||
void (*free_queues)(virtio_device cookie);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ VirtioBalloonDevice::VirtioBalloonDevice(device_node* node)
|
||||
fVirtio->negotiate_features(fVirtioDevice,
|
||||
0, &fFeatures, &get_feature_name);
|
||||
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 2, fVirtioQueues);
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 2, fVirtioQueues, NULL);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
|
||||
@@ -179,7 +179,8 @@ VirtioDevice::WriteDeviceConfig(uint8 offset, const void* buffer,
|
||||
|
||||
|
||||
status_t
|
||||
VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues)
|
||||
VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues,
|
||||
uint16 *requestedSizes)
|
||||
{
|
||||
if (count > VIRTIO_VIRTQUEUES_MAX_COUNT || queues == NULL)
|
||||
return B_BAD_VALUE;
|
||||
@@ -192,11 +193,24 @@ VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues)
|
||||
fQueueCount = count;
|
||||
for (size_t index = 0; index < count; index++) {
|
||||
uint16 size = fController->get_queue_ring_size(fCookie, index);
|
||||
fQueues[index] = new(std::nothrow) VirtioQueue(this, index, size);
|
||||
queues[index] = fQueues[index];
|
||||
status = B_NO_MEMORY;
|
||||
if (fQueues[index] != NULL)
|
||||
status = fQueues[index]->InitCheck();
|
||||
|
||||
uint16 requestedSize
|
||||
= requestedSizes != NULL ? requestedSizes[index] : 0;
|
||||
if (requestedSize != 0) {
|
||||
if (requestedSize > size)
|
||||
status = B_BUFFER_OVERFLOW;
|
||||
else
|
||||
size = requestedSize;
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
fQueues[index] = new(std::nothrow) VirtioQueue(this, index, size);
|
||||
queues[index] = fQueues[index];
|
||||
status = B_NO_MEMORY;
|
||||
if (fQueues[index] != NULL)
|
||||
status = fQueues[index]->InitCheck();
|
||||
}
|
||||
|
||||
if (status != B_OK) {
|
||||
_DestroyQueues(index + 1);
|
||||
return status;
|
||||
|
||||
@@ -97,11 +97,12 @@ virtio_write_device_config(void* _device, uint8 offset,
|
||||
|
||||
|
||||
status_t
|
||||
virtio_alloc_queues(virtio_device _device, size_t count, virtio_queue *queues)
|
||||
virtio_alloc_queues(virtio_device _device, size_t count, virtio_queue *queues,
|
||||
uint16 *requestedSizes)
|
||||
{
|
||||
CALLED();
|
||||
VirtioDevice *device = (VirtioDevice *)_device;
|
||||
return device->AllocateQueues(count, queues);
|
||||
return device->AllocateQueues(count, queues, requestedSizes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ public:
|
||||
const void* buffer, size_t bufferSize);
|
||||
|
||||
status_t AllocateQueues(size_t count,
|
||||
virtio_queue *queues);
|
||||
virtio_queue *queues,
|
||||
uint16 *requestedSizes);
|
||||
void FreeQueues();
|
||||
status_t SetupInterrupt(virtio_intr_func config_handler,
|
||||
void *driverCookie);
|
||||
|
||||
@@ -45,7 +45,7 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node)
|
||||
fVirtio->negotiate_features(fVirtioDevice,
|
||||
0, &fFeatures, &get_feature_name);
|
||||
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue);
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue, NULL);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
|
||||
@@ -82,7 +82,12 @@ VirtioSCSIController::VirtioSCSIController(device_node *node)
|
||||
}
|
||||
|
||||
::virtio_queue virtioQueues[3];
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 3, virtioQueues);
|
||||
uint16 requestedSizes[3] = { 0, 0, 0 };
|
||||
requestedSizes[2] = fConfig.seg_max + 2;
|
||||
// two entries are taken up by the header and result
|
||||
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 3, virtioQueues,
|
||||
requestedSizes);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
|
||||
@@ -43,11 +43,14 @@ VirtioQueue::~VirtioQueue()
|
||||
|
||||
|
||||
status_t
|
||||
VirtioQueue::Init()
|
||||
VirtioQueue::Init(uint16 requestedSize)
|
||||
{
|
||||
fDev->fRegs->queueSel = fId;
|
||||
TRACE("queueNumMax: %d\n", fDev->fRegs->queueNumMax);
|
||||
fQueueLen = fDev->fRegs->queueNumMax;
|
||||
if (requestedSize != 0 && requestedSize > fQueueLen)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
fDescCount = fQueueLen;
|
||||
fDev->fRegs->queueNum = fQueueLen;
|
||||
fLastUsed = 0;
|
||||
|
||||
@@ -48,7 +48,7 @@ struct VirtioQueue {
|
||||
|
||||
VirtioQueue(VirtioDevice *dev, int32 id);
|
||||
~VirtioQueue();
|
||||
status_t Init();
|
||||
status_t Init(uint16 requestedSize);
|
||||
|
||||
int32 AllocDesc();
|
||||
void FreeDesc(int32 idx);
|
||||
|
||||
@@ -466,7 +466,7 @@ virtio_device_write_device_config(virtio_device cookie, uint8 offset,
|
||||
|
||||
static status_t
|
||||
virtio_device_alloc_queues(virtio_device cookie, size_t count,
|
||||
virtio_queue* queues)
|
||||
virtio_queue* queues, uint16* requestedSizes)
|
||||
{
|
||||
TRACE("virtio_device_alloc_queues(%p, %" B_PRIuSIZE ")\n", cookie, count);
|
||||
VirtioDevice* dev = (VirtioDevice*)cookie;
|
||||
@@ -483,7 +483,8 @@ virtio_device_alloc_queues(virtio_device cookie, size_t count,
|
||||
if (!newQueues[i].IsSet())
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t res = newQueues[i]->Init();
|
||||
status_t res = newQueues[i]->Init(
|
||||
requestedSizes != NULL ? requestedSizes[i] : 0);
|
||||
if (res < B_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -286,12 +286,18 @@ virtio_block_init_device(void* _info, void** _cookie)
|
||||
TRACE("virtio_block: capacity: %" B_PRIu64 ", block_size %" B_PRIu32 "\n",
|
||||
info->capacity, info->block_size);
|
||||
|
||||
uint16 requestedSize = 0;
|
||||
if ((info->features & VIRTIO_BLK_F_SEG_MAX) != 0)
|
||||
requestedSize = info->config.seg_max + 2;
|
||||
// two entries are taken up by the header and result
|
||||
|
||||
status = info->virtio->alloc_queues(info->virtio_device, 1,
|
||||
&info->virtio_queue);
|
||||
&info->virtio_queue, &requestedSize);
|
||||
if (status != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
status = info->virtio->setup_interrupt(info->virtio_device,
|
||||
virtio_block_config_callback, info);
|
||||
|
||||
|
||||
@@ -485,7 +485,7 @@ virtio_gpu_init_device(void* _info, void** _cookie)
|
||||
// Setup queues
|
||||
::virtio_queue virtioQueues[2];
|
||||
status_t status = info->virtio->alloc_queues(info->virtio_device, 2,
|
||||
virtioQueues);
|
||||
virtioQueues, NULL);
|
||||
if (status != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||
return status;
|
||||
|
||||
@@ -283,7 +283,7 @@ virtio_input_init_device(void* _info, void** _cookie)
|
||||
InitPackets(info, 8);
|
||||
|
||||
status = info->virtio->alloc_queues(info->virtio_device, 1,
|
||||
&info->virtio_queue);
|
||||
&info->virtio_queue, NULL);
|
||||
if (status != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||
return status;
|
||||
|
||||
@@ -321,7 +321,7 @@ virtio_net_init_device(void* _info, void** _cookie)
|
||||
queueCount++;
|
||||
::virtio_queue virtioQueues[queueCount];
|
||||
status_t status = info->virtio->alloc_queues(info->virtio_device, queueCount,
|
||||
virtioQueues);
|
||||
virtioQueues, NULL);
|
||||
if (status != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||
return status;
|
||||
|
||||
Reference in New Issue
Block a user