From 61cd7e85d7ec458ad244d2074ddc5a437b81b742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 21 Apr 2018 16:52:10 +0200 Subject: [PATCH] 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 --- headers/private/virtio/virtio.h | 5 ++ .../bus_managers/virtio/VirtioDevice.cpp | 64 ++++++++++++++----- .../bus_managers/virtio/VirtioModule.cpp | 22 ++++++- .../bus_managers/virtio/VirtioPrivate.h | 6 +- .../bus_managers/virtio/VirtioQueue.cpp | 2 +- .../kernel/busses/virtio/virtio_pci.cpp | 33 +++++++++- 6 files changed, 112 insertions(+), 20 deletions(-) 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@users.berlios.de. + * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com. * 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@users.berlios.de. + * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com. * 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@users.berlios.de. + * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com. * 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@users.berlios.de. + * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com. * 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 };