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);
|
const void* buffer, size_t bufferSize);
|
||||||
|
|
||||||
status_t (*alloc_queues)(virtio_device cookie, size_t count,
|
status_t (*alloc_queues)(virtio_device cookie, size_t count,
|
||||||
virtio_queue* queues);
|
virtio_queue* queues, uint16* requestedSizes);
|
||||||
|
|
||||||
void (*free_queues)(virtio_device cookie);
|
void (*free_queues)(virtio_device cookie);
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ VirtioBalloonDevice::VirtioBalloonDevice(device_node* node)
|
|||||||
fVirtio->negotiate_features(fVirtioDevice,
|
fVirtio->negotiate_features(fVirtioDevice,
|
||||||
0, &fFeatures, &get_feature_name);
|
0, &fFeatures, &get_feature_name);
|
||||||
|
|
||||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 2, fVirtioQueues);
|
fStatus = fVirtio->alloc_queues(fVirtioDevice, 2, fVirtioQueues, NULL);
|
||||||
if (fStatus != B_OK) {
|
if (fStatus != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -179,7 +179,8 @@ VirtioDevice::WriteDeviceConfig(uint8 offset, const void* buffer,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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)
|
if (count > VIRTIO_VIRTQUEUES_MAX_COUNT || queues == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -192,11 +193,24 @@ VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues)
|
|||||||
fQueueCount = count;
|
fQueueCount = count;
|
||||||
for (size_t index = 0; index < count; index++) {
|
for (size_t index = 0; index < count; index++) {
|
||||||
uint16 size = fController->get_queue_ring_size(fCookie, index);
|
uint16 size = fController->get_queue_ring_size(fCookie, index);
|
||||||
fQueues[index] = new(std::nothrow) VirtioQueue(this, index, size);
|
|
||||||
queues[index] = fQueues[index];
|
uint16 requestedSize
|
||||||
status = B_NO_MEMORY;
|
= requestedSizes != NULL ? requestedSizes[index] : 0;
|
||||||
if (fQueues[index] != NULL)
|
if (requestedSize != 0) {
|
||||||
status = fQueues[index]->InitCheck();
|
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) {
|
if (status != B_OK) {
|
||||||
_DestroyQueues(index + 1);
|
_DestroyQueues(index + 1);
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -97,11 +97,12 @@ virtio_write_device_config(void* _device, uint8 offset,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
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();
|
CALLED();
|
||||||
VirtioDevice *device = (VirtioDevice *)_device;
|
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);
|
const void* buffer, size_t bufferSize);
|
||||||
|
|
||||||
status_t AllocateQueues(size_t count,
|
status_t AllocateQueues(size_t count,
|
||||||
virtio_queue *queues);
|
virtio_queue *queues,
|
||||||
|
uint16 *requestedSizes);
|
||||||
void FreeQueues();
|
void FreeQueues();
|
||||||
status_t SetupInterrupt(virtio_intr_func config_handler,
|
status_t SetupInterrupt(virtio_intr_func config_handler,
|
||||||
void *driverCookie);
|
void *driverCookie);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ VirtioRNGDevice::VirtioRNGDevice(device_node *node)
|
|||||||
fVirtio->negotiate_features(fVirtioDevice,
|
fVirtio->negotiate_features(fVirtioDevice,
|
||||||
0, &fFeatures, &get_feature_name);
|
0, &fFeatures, &get_feature_name);
|
||||||
|
|
||||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue);
|
fStatus = fVirtio->alloc_queues(fVirtioDevice, 1, &fVirtioQueue, NULL);
|
||||||
if (fStatus != B_OK) {
|
if (fStatus != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -82,7 +82,12 @@ VirtioSCSIController::VirtioSCSIController(device_node *node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
::virtio_queue virtioQueues[3];
|
::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) {
|
if (fStatus != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -43,11 +43,14 @@ VirtioQueue::~VirtioQueue()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
VirtioQueue::Init()
|
VirtioQueue::Init(uint16 requestedSize)
|
||||||
{
|
{
|
||||||
fDev->fRegs->queueSel = fId;
|
fDev->fRegs->queueSel = fId;
|
||||||
TRACE("queueNumMax: %d\n", fDev->fRegs->queueNumMax);
|
TRACE("queueNumMax: %d\n", fDev->fRegs->queueNumMax);
|
||||||
fQueueLen = fDev->fRegs->queueNumMax;
|
fQueueLen = fDev->fRegs->queueNumMax;
|
||||||
|
if (requestedSize != 0 && requestedSize > fQueueLen)
|
||||||
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
fDescCount = fQueueLen;
|
fDescCount = fQueueLen;
|
||||||
fDev->fRegs->queueNum = fQueueLen;
|
fDev->fRegs->queueNum = fQueueLen;
|
||||||
fLastUsed = 0;
|
fLastUsed = 0;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ struct VirtioQueue {
|
|||||||
|
|
||||||
VirtioQueue(VirtioDevice *dev, int32 id);
|
VirtioQueue(VirtioDevice *dev, int32 id);
|
||||||
~VirtioQueue();
|
~VirtioQueue();
|
||||||
status_t Init();
|
status_t Init(uint16 requestedSize);
|
||||||
|
|
||||||
int32 AllocDesc();
|
int32 AllocDesc();
|
||||||
void FreeDesc(int32 idx);
|
void FreeDesc(int32 idx);
|
||||||
|
|||||||
@@ -466,7 +466,7 @@ virtio_device_write_device_config(virtio_device cookie, uint8 offset,
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
virtio_device_alloc_queues(virtio_device cookie, size_t count,
|
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);
|
TRACE("virtio_device_alloc_queues(%p, %" B_PRIuSIZE ")\n", cookie, count);
|
||||||
VirtioDevice* dev = (VirtioDevice*)cookie;
|
VirtioDevice* dev = (VirtioDevice*)cookie;
|
||||||
@@ -483,7 +483,8 @@ virtio_device_alloc_queues(virtio_device cookie, size_t count,
|
|||||||
if (!newQueues[i].IsSet())
|
if (!newQueues[i].IsSet())
|
||||||
return B_NO_MEMORY;
|
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)
|
if (res < B_OK)
|
||||||
return res;
|
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",
|
TRACE("virtio_block: capacity: %" B_PRIu64 ", block_size %" B_PRIu32 "\n",
|
||||||
info->capacity, info->block_size);
|
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,
|
status = info->virtio->alloc_queues(info->virtio_device, 1,
|
||||||
&info->virtio_queue);
|
&info->virtio_queue, &requestedSize);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = info->virtio->setup_interrupt(info->virtio_device,
|
status = info->virtio->setup_interrupt(info->virtio_device,
|
||||||
virtio_block_config_callback, info);
|
virtio_block_config_callback, info);
|
||||||
|
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ virtio_gpu_init_device(void* _info, void** _cookie)
|
|||||||
// Setup queues
|
// Setup queues
|
||||||
::virtio_queue virtioQueues[2];
|
::virtio_queue virtioQueues[2];
|
||||||
status_t status = info->virtio->alloc_queues(info->virtio_device, 2,
|
status_t status = info->virtio->alloc_queues(info->virtio_device, 2,
|
||||||
virtioQueues);
|
virtioQueues, NULL);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ virtio_input_init_device(void* _info, void** _cookie)
|
|||||||
InitPackets(info, 8);
|
InitPackets(info, 8);
|
||||||
|
|
||||||
status = info->virtio->alloc_queues(info->virtio_device, 1,
|
status = info->virtio->alloc_queues(info->virtio_device, 1,
|
||||||
&info->virtio_queue);
|
&info->virtio_queue, NULL);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ virtio_net_init_device(void* _info, void** _cookie)
|
|||||||
queueCount++;
|
queueCount++;
|
||||||
::virtio_queue virtioQueues[queueCount];
|
::virtio_queue virtioQueues[queueCount];
|
||||||
status_t status = info->virtio->alloc_queues(info->virtio_device, queueCount,
|
status_t status = info->virtio->alloc_queues(info->virtio_device, queueCount,
|
||||||
virtioQueues);
|
virtioQueues, NULL);
|
||||||
if (status != B_OK) {
|
if (status != B_OK) {
|
||||||
ERROR("queue allocation failed (%s)\n", strerror(status));
|
ERROR("queue allocation failed (%s)\n", strerror(status));
|
||||||
return status;
|
return status;
|
||||||
|
|||||||
Reference in New Issue
Block a user