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:
@@ -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
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user