From patchwork Sun Aug 26 15:51:38 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 180101 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 06B072C00F6 for ; Mon, 27 Aug 2012 09:18:39 +1000 (EST) Received: from localhost ([::1]:46660 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T5m6H-00079a-1j for incoming@patchwork.ozlabs.org; Sun, 26 Aug 2012 19:18:37 -0400 Received: from eggs.gnu.org ([208.118.235.92]:38649) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T5m5J-0004tJ-Lk for qemu-devel@nongnu.org; Sun, 26 Aug 2012 19:17:38 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1T5m5I-0003ea-Dq for qemu-devel@nongnu.org; Sun, 26 Aug 2012 19:17:37 -0400 Received: from cpe-70-123-140-180.austin.res.rr.com ([70.123.140.180]:50521 helo=localhost6.localdomain6) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1T5m5I-0003cZ-6N for qemu-devel@nongnu.org; Sun, 26 Aug 2012 19:17:36 -0400 Received: from localhost6.localdomain6 (localhost.localdomain [127.0.0.1]) by localhost6.localdomain6 (8.14.4/8.14.4/Debian-2ubuntu2) with ESMTP id q7QFpr5C005242; Sun, 26 Aug 2012 10:51:53 -0500 Received: (from anthony@localhost) by localhost6.localdomain6 (8.14.4/8.14.4/Submit) id q7QFpqoP005232; Sun, 26 Aug 2012 10:51:52 -0500 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Sun, 26 Aug 2012 10:51:38 -0500 Message-Id: <1345996298-4892-10-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1345996298-4892-1-git-send-email-aliguori@us.ibm.com> References: <1345996298-4892-1-git-send-email-aliguori@us.ibm.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 70.123.140.180 Cc: Paolo Bonzini , Anthony Liguori , Liu Ping Fan , Andreas Faerber Subject: [Qemu-devel] [PATCH 9/9] hotplug: refactor hotplug to leverage new QOM functions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 1) DeviceState::unplug requests for an eject to happen - the default implementation is a forced eject 2) A bus can eject a device by setting the parent_bus to NULL - this detaches the device from the bus - this does *not* cause the device to disappear 3) The current implementation on unplug also registers an eject notifier - the eject notifier will detach the device the parent. This will cause the device to disappear 4) A purely guest initiated unplug will not delete a device but will cause the device to appear detached from the guests PoV. Signed-off-by: Anthony Liguori --- hw/acpi_piix4.c | 3 ++- hw/pci.c | 10 +++++++++- hw/pcie.c | 2 +- hw/qdev.c | 22 ++++++++++++++++++++++ hw/qdev.h | 2 ++ hw/shpc.c | 2 +- hw/xen_platform.c | 2 +- 7 files changed, 38 insertions(+), 5 deletions(-) diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 72d6e5c..eac53b3 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -305,7 +305,8 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots) if (pc->no_hotplug) { slot_free = false; } else { - qdev_free(qdev); + /* Force eject of device */ + qdev_set_parent_bus(qdev, NULL); } } } diff --git a/hw/pci.c b/hw/pci.c index 437af70..cc555c2 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -46,6 +46,14 @@ static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); static int pcibus_reset(BusState *qbus); +static void pcibus_remove_child(BusState *bus, DeviceState *dev) +{ + PCIDevice *pci_dev = PCI_DEVICE(dev); + PCIBus *pci_bus = PCI_BUS(bus); + + pci_bus->devices[pci_dev->devfn] = NULL; +} + static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), DEFINE_PROP_STRING("romfile", PCIDevice, romfile), @@ -65,6 +73,7 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) k->get_dev_path = pcibus_get_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path; k->reset = pcibus_reset; + k->remove_child = pcibus_remove_child; } static const TypeInfo pci_bus_info = { @@ -833,7 +842,6 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus, static void do_pci_unregister_device(PCIDevice *pci_dev) { qemu_free_irqs(pci_dev->irq); - pci_dev->bus->devices[pci_dev->devfn] = NULL; pci_config_free(pci_dev); } diff --git a/hw/pcie.c b/hw/pcie.c index 7c92f19..d10ffea 100644 --- a/hw/pcie.c +++ b/hw/pcie.c @@ -235,7 +235,7 @@ static int pcie_cap_slot_hotplug(DeviceState *qdev, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); } else { - qdev_free(&pci_dev->qdev); + qdev_set_parent_bus(DEVICE(pci_dev), NULL); pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC); diff --git a/hw/qdev.c b/hw/qdev.c index 525a0cb..be41f00 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -62,6 +62,7 @@ static void qdev_property_add_legacy(DeviceState *dev, Property *prop, static void bus_remove_child(BusState *bus, DeviceState *child) { + BusClass *bc = BUS_GET_CLASS(bus); BusChild *kid; QTAILQ_FOREACH(kid, &bus->children, sibling) { @@ -71,6 +72,11 @@ static void bus_remove_child(BusState *bus, DeviceState *child) snprintf(name, sizeof(name), "child[%d]", kid->index); QTAILQ_REMOVE(&bus->children, kid, sibling); object_property_del(OBJECT(bus), name, NULL); + + if (bc->remove_child) { + bc->remove_child(bus, kid->child); + } + g_free(kid); return; } @@ -192,9 +198,20 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, dev->alias_required_for_version = required_for_version; } +static void qdev_finish_unplug(Notifier *notifier, void *data) +{ + DeviceState *dev = DEVICE(data); + + /* unparent the object -- this should release the last reference to the + child*/ + object_unparent(OBJECT(dev)); + g_free(notifier); +} + void qdev_unplug(DeviceState *dev, Error **errp) { DeviceClass *dc = DEVICE_GET_CLASS(dev); + Notifier *notifier; if (!dev->parent_bus->allow_hotplug) { error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); @@ -204,6 +221,11 @@ void qdev_unplug(DeviceState *dev, Error **errp) qdev_hot_removed = true; + notifier = g_malloc0(sizeof(*notifier)); + notifier->notify = qdev_finish_unplug; + + notifier_list_add(&dev->eject_notifier, notifier); + if (dc->unplug(dev) < 0) { error_set(errp, QERR_UNDEFINED_ERROR); return; diff --git a/hw/qdev.h b/hw/qdev.h index 5009072..7ae8d5d 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -99,6 +99,8 @@ struct BusClass { */ char *(*get_fw_dev_path)(DeviceState *dev); int (*reset)(BusState *bus); + + void (*remove_child)(BusState *bus, DeviceState *dev); }; typedef struct BusChild { diff --git a/hw/shpc.c b/hw/shpc.c index a5baf24..ce507e7 100644 --- a/hw/shpc.c +++ b/hw/shpc.c @@ -253,7 +253,7 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot) ++devfn) { PCIDevice *affected_dev = shpc->sec_bus->devices[devfn]; if (affected_dev) { - qdev_free(&affected_dev->qdev); + qdev_set_parent_bus(DEVICE(affected_dev), NULL); } } } diff --git a/hw/xen_platform.c b/hw/xen_platform.c index 0d6c2ff..5c5ecf8 100644 --- a/hw/xen_platform.c +++ b/hw/xen_platform.c @@ -87,7 +87,7 @@ static void unplug_nic(PCIBus *b, PCIDevice *d, void *o) { if (pci_get_word(d->config + PCI_CLASS_DEVICE) == PCI_CLASS_NETWORK_ETHERNET) { - qdev_free(&d->qdev); + qdev_set_parent_bus(dev, NULL); } }