hrev51902 adds 1 changeset to branch 'master'
old head: 6e82e428596071bbde44e296d04740f1f5d54d03
new head: 61cd7e85d7ec458ad244d2074ddc5a437b81b742
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=61cd7e85d7ec+%5E6e82e4285960
----------------------------------------------------------------------------
61cd7e85d7ec: 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
[ Jérôme Duval <jerome.duval@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev51902
Commit: 61cd7e85d7ec458ad244d2074ddc5a437b81b742
URL: https://git.haiku-os.org/haiku/commit/?id=61cd7e85d7ec
Author: Jérôme Duval <jerome.duval@xxxxxxxxx>
Date: Sat Apr 21 14:52:10 2018 UTC
----------------------------------------------------------------------------
6 files changed, 112 insertions(+), 20 deletions(-)
headers/private/virtio/virtio.h | 5 ++
.../kernel/bus_managers/virtio/VirtioDevice.cpp | 64 +++++++++++++++-----
.../kernel/bus_managers/virtio/VirtioModule.cpp | 22 ++++++-
.../kernel/bus_managers/virtio/VirtioPrivate.h | 6 +-
.../kernel/bus_managers/virtio/VirtioQueue.cpp | 2 +-
src/add-ons/kernel/busses/virtio/virtio_pci.cpp | 33 +++++++++-
----------------------------------------------------------------------------
diff --git a/headers/private/virtio/virtio.h b/headers/private/virtio/virtio.h
index 1afd5dd052..24b44e15c1 100644
--- a/headers/private/virtio/virtio.h
+++ b/headers/private/virtio/virtio.h
@@ -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);
diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp
b/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp
index 0fa3985fde..ab5e8671e7 100644
--- a/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp
+++ b/src/add-ons/kernel/bus_managers/virtio/VirtioDevice.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2013, Jérôme Duval, korli@xxxxxxxxxxxxxxxx.
+ * Copyright 2013, 2018, Jérôme Duval, jerome.duval@xxxxxxxxx.
* 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] = "";
diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp
b/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp
index 7515f0b44d..74b77a5dac 100644
--- a/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp
+++ b/src/add-ons/kernel/bus_managers/virtio/VirtioModule.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2013, Jérôme Duval, korli@xxxxxxxxxxxxxxxx.
+ * Copyright 2013, 2018, Jérôme Duval, jerome.duval@xxxxxxxxx.
* 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,
diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h
b/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h
index b6db8a2744..f658eda0d7 100644
--- a/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h
+++ b/src/add-ons/kernel/bus_managers/virtio/VirtioPrivate.h
@@ -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;
diff --git a/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp
b/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp
index 4ed23b33b0..6d067c62a3 100644
--- a/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp
+++ b/src/add-ons/kernel/bus_managers/virtio/VirtioQueue.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2013, Jérôme Duval, korli@xxxxxxxxxxxxxxxx.
+ * Copyright 2013, 2018, Jérôme Duval, jerome.duval@xxxxxxxxx.
* Distributed under the terms of the MIT License.
*/
diff --git a/src/add-ons/kernel/busses/virtio/virtio_pci.cpp
b/src/add-ons/kernel/busses/virtio/virtio_pci.cpp
index c7f695dc9f..c969d132e7 100644
--- a/src/add-ons/kernel/busses/virtio/virtio_pci.cpp
+++ b/src/add-ons/kernel/busses/virtio/virtio_pci.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2013, Jérôme Duval, korli@xxxxxxxxxxxxxxxx.
+ * Copyright 2013, 2018, Jérôme Duval, jerome.duval@xxxxxxxxx.
* 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
};