virtio: add API to uninit a device.

* free interrupts, free queues, return to init state.
* this will be used by virtio_net on interface uninit.

Change-Id: I7c1e6facc37cf6bfe19628576fdf2c0bac9e5c38
This commit is contained in:
Jérôme Duval
2018-04-26 06:25:41 +00:00
parent 6e82e42859
commit 61cd7e85d7
6 changed files with 112 additions and 20 deletions
+5
View File
@@ -85,6 +85,7 @@ typedef struct {
uint16 (*get_queue_ring_size)(void* cookie, uint16 queue);
status_t (*setup_queue)(void* cookie, uint16 queue, phys_addr_t phy);
status_t (*setup_interrupt)(void* cookie, uint16 queueCount);
status_t (*free_interrupt)(void* cookie);
void (*notify_queue)(void* cookie, uint16 queue);
} virtio_sim_interface;
@@ -104,9 +105,13 @@ typedef struct {
status_t (*alloc_queues)(virtio_device cookie, size_t count,
virtio_queue* queues);
void (*free_queues)(virtio_device cookie);
status_t (*setup_interrupt)(virtio_device cookie,
virtio_intr_func config_handler, void* driverCookie);
status_t (*free_interrupts)(virtio_device cookie);
status_t (*queue_setup_interrupt)(virtio_queue queue,
virtio_callback_func handler, void* cookie);
@@ -1,5 +1,5 @@
/*
* Copyright 2013, Jérôme Duval, [email protected].
* Copyright 2013, 2018, Jérôme Duval, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -63,6 +63,7 @@ VirtioDevice::VirtioDevice(device_node *node)
fConfigHandler(NULL),
fDriverCookie(NULL)
{
CALLED();
device_node *parent = gDeviceManager->get_parent_node(node);
fStatus = gDeviceManager->get_driver(parent,
(driver_module_info **)&fController, &fCookie);
@@ -86,10 +87,10 @@ VirtioDevice::VirtioDevice(device_node *node)
VirtioDevice::~VirtioDevice()
{
for (size_t index = 0; index < fQueueCount; index++) {
delete fQueues[index];
if (fQueues != NULL) {
_DestroyQueues(fQueueCount);
}
delete fQueues;
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_RESET);
}
@@ -109,7 +110,7 @@ VirtioDevice::NegotiateFeatures(uint32 supported, uint32* negotiated,
if (status != B_OK)
return status;
DumpFeatures("read features", fFeatures, get_feature_name);
_DumpFeatures("read features", fFeatures, get_feature_name);
fFeatures &= supported;
@@ -119,7 +120,7 @@ VirtioDevice::NegotiateFeatures(uint32 supported, uint32* negotiated,
*negotiated = fFeatures;
DumpFeatures("negotiated features", fFeatures, get_feature_name);
_DumpFeatures("negotiated features", fFeatures, get_feature_name);
return fController->write_guest_features(fCookie, fFeatures);
}
@@ -148,13 +149,11 @@ VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues)
if (count > VIRTIO_VIRTQUEUES_MAX_COUNT || queues == NULL)
return B_BAD_VALUE;
status_t status = B_OK;
fQueues = new(std::nothrow) VirtioQueue*[count];
if (fQueues == NULL) {
status = B_NO_MEMORY;
goto err;
}
if (fQueues == NULL)
return B_NO_MEMORY;
status_t status = B_OK;
fQueueCount = count;
for (size_t index = 0; index < count; index++) {
uint16 size = fController->get_queue_ring_size(fCookie, index);
@@ -163,14 +162,24 @@ VirtioDevice::AllocateQueues(size_t count, virtio_queue *queues)
status = B_NO_MEMORY;
if (fQueues[index] != NULL)
status = fQueues[index]->InitCheck();
if (status != B_OK)
goto err;
if (status != B_OK) {
_DestroyQueues(index + 1);
return status;
}
}
return B_OK;
}
err:
return status;
void
VirtioDevice::FreeQueues()
{
if (fQueues != NULL)
_DestroyQueues(fQueueCount);
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_RESET);
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_DRIVER);
}
@@ -192,6 +201,18 @@ VirtioDevice::SetupInterrupt(virtio_intr_func configHandler, void *driverCookie)
}
status_t
VirtioDevice::FreeInterrupts()
{
for (size_t index = 0; index < fQueueCount; index++)
fQueues[index]->DisableInterrupt();
fController->set_status(fCookie, VIRTIO_CONFIG_STATUS_DRIVER);
return fController->free_interrupt(fCookie);
}
status_t
VirtioDevice::SetupQueue(uint16 queueNumber, phys_addr_t physAddr)
{
@@ -236,7 +257,18 @@ VirtioDevice::ConfigInterrupt()
void
VirtioDevice::DumpFeatures(const char* title, uint32 features,
VirtioDevice::_DestroyQueues(size_t count)
{
for (size_t i = 0; i < count; i++) {
delete fQueues[i];
}
delete[] fQueues;
fQueues = NULL;
}
void
VirtioDevice::_DumpFeatures(const char* title, uint32 features,
const char* (*get_feature_name)(uint32))
{
char features_string[512] = "";
@@ -1,5 +1,5 @@
/*
* Copyright 2013, Jérôme Duval, [email protected].
* Copyright 2013, 2018, Jérôme Duval, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -94,6 +94,15 @@ virtio_alloc_queues(virtio_device _device, size_t count, virtio_queue *queues)
}
void
virtio_free_queues(virtio_device _device)
{
CALLED();
VirtioDevice *device = (VirtioDevice *)_device;
device->FreeQueues();
}
status_t
virtio_setup_interrupt(virtio_device _device, virtio_intr_func config_handler,
void *driverCookie)
@@ -104,6 +113,15 @@ virtio_setup_interrupt(virtio_device _device, virtio_intr_func config_handler,
}
status_t
virtio_free_interrupts(virtio_device _device)
{
CALLED();
VirtioDevice *device = (VirtioDevice *)_device;
return device->FreeInterrupts();
}
status_t
virtio_queue_setup_interrupt(virtio_queue _queue, virtio_callback_func handler,
void *cookie)
@@ -260,7 +278,9 @@ virtio_device_interface virtio_device_module = {
virtio_read_device_config,
virtio_write_device_config,
virtio_alloc_queues,
virtio_free_queues,
virtio_setup_interrupt,
virtio_free_interrupts,
virtio_queue_setup_interrupt,
virtio_queue_request,
virtio_queue_request_v,
@@ -56,8 +56,10 @@ public:
status_t AllocateQueues(size_t count,
virtio_queue *queues);
void FreeQueues();
status_t SetupInterrupt(virtio_intr_func config_handler,
void *driverCookie);
status_t FreeInterrupts();
uint16 Alignment() const { return fAlignment; }
uint32 Features() const { return fFeatures; }
@@ -72,9 +74,11 @@ public:
status_t ConfigInterrupt();
private:
void DumpFeatures(const char* title,
void _DumpFeatures(const char* title,
uint32 features,
const char* (*get_feature_name)(uint32));
void _DestroyQueues(size_t count);
device_node * fNode;
@@ -1,5 +1,5 @@
/*
* Copyright 2013, Jérôme Duval, [email protected].
* Copyright 2013, 2018, Jérôme Duval, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -1,5 +1,5 @@
/*
* Copyright 2013, Jérôme Duval, [email protected].
* Copyright 2013, 2018, Jérôme Duval, [email protected].
* Distributed under the terms of the MIT License.
*/
@@ -390,6 +390,36 @@ setup_interrupt(void* cookie, uint16 queueCount)
}
status_t
free_interrupt(void* cookie)
{
CALLED();
virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
pci_info *pciInfo = &bus->info;
if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt,
bus);
int32 irq = bus->irq + 1;
for (int32 queue = 0; queue < bus->queue_count; queue++, irq++) {
remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt,
&bus->cookies[queue]);
}
delete[] bus->cookies;
} else
remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
if (sPCIx86Module != NULL && bus->irq_type != VIRTIO_IRQ_LEGACY) {
sPCIx86Module->disable_msi(pciInfo->bus, pciInfo->device,
pciInfo->function);
sPCIx86Module->unconfigure_msi(pciInfo->bus, pciInfo->device,
pciInfo->function);
}
return B_OK;
}
void
notify_queue(void* cookie, uint16 queue)
{
@@ -640,6 +670,7 @@ static virtio_sim_interface gVirtioPCIDeviceModule = {
get_queue_ring_size,
setup_queue,
setup_interrupt,
free_interrupt,
notify_queue
};