From 9f117d41841e13ca29cc2a10ac03258339ea1f8b Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Feb 2014 16:36:44 +0100 Subject: define hotplug interface Provide a generic hotplug interface for hotplug handlers. Intended for replacing hotplug mechanism used by PCI/PCIE/SHPC code and will be used for memory hotplug. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/Makefile.objs | 1 + hw/core/hotplug.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 hw/core/hotplug.c (limited to 'hw/core') diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 950146c6ff..9e324befd6 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -2,6 +2,7 @@ common-obj-y += qdev.o qdev-properties.o # irq.o needed for qdev GPIO handling: common-obj-y += irq.o +common-obj-y += hotplug.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o diff --git a/hw/core/hotplug.c b/hw/core/hotplug.c new file mode 100644 index 0000000000..5573d9d2d9 --- /dev/null +++ b/hw/core/hotplug.c @@ -0,0 +1,48 @@ +/* + * Hotplug handler interface. + * + * Copyright (c) 2014 Red Hat Inc. + * + * Authors: + * Igor Mammedov , + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ +#include "hw/hotplug.h" +#include "qemu/module.h" + +void hotplug_handler_plug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +{ + HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); + + if (hdc->plug) { + hdc->plug(plug_handler, plugged_dev, errp); + } +} + +void hotplug_handler_unplug(HotplugHandler *plug_handler, + DeviceState *plugged_dev, + Error **errp) +{ + HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler); + + if (hdc->unplug) { + hdc->unplug(plug_handler, plugged_dev, errp); + } +} + +static const TypeInfo hotplug_handler_info = { + .name = TYPE_HOTPLUG_HANDLER, + .parent = TYPE_INTERFACE, + .class_size = sizeof(HotplugHandlerClass), +}; + +static void hotplug_handler_register_types(void) +{ + type_register_static(&hotplug_handler_info); +} + +type_init(hotplug_handler_register_types) -- cgit v1.2.1 From 0ee4de6ce1d403b3d8017b340cec772c3c5c106f Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Feb 2014 16:36:45 +0100 Subject: qdev: add to BusState "hotplug-handler" link It will allow to reuse field with different BUSes, reducing code duplication. Field is intended for replacing 'hotplug_qdev' field in PCIBus and also will allow to avoid adding equivalent field to DimmBus with possiblitity to refactor other BUSes to use it instead of custom field. In addition once all users of allow_hotplug field are converted to new API, link could replace allow_hotplug field in qdev hotplug code. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/qdev.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'hw/core') diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 82a9123038..c9f0c330e2 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -32,6 +32,7 @@ #include "qapi/visitor.h" #include "qapi/qmp/qjson.h" #include "monitor/monitor.h" +#include "hw/hotplug.h" int qdev_hotplug = 0; static bool qdev_hot_added = false; @@ -870,6 +871,9 @@ static void qbus_initfn(Object *obj) BusState *bus = BUS(obj); QTAILQ_INIT(&bus->children); + object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, + TYPE_HOTPLUG_HANDLER, + (Object **)&bus->hotplug_handler, NULL); } static char *default_bus_get_fw_dev_path(DeviceState *dev) -- cgit v1.2.1 From 1a37eca107cece3ed454bae29eef0bd1fac4a244 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Feb 2014 16:36:46 +0100 Subject: qdev: add "hotpluggable" property to Device Currently it's possible to make PCIDevice not hotpluggable by using no_hotplug field of PCIDeviceClass. However it limits this only to PCI devices and prevents from generalizing hotplug code. So add similar field to DeviceClass so it could be reused with other Devices and would allow to replace PCI specific hotplug callbacks with generic implementation. Following patches will replace PCIDeviceClass.no_hotplug with this new property. In addition expose field as "hotpluggable" readonly property, to make it possible to read its value via QOM interface. Make DeviceClass hotpluggable by default as it was assumed before. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/qdev.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'hw/core') diff --git a/hw/core/qdev.c b/hw/core/qdev.c index c9f0c330e2..5c864dbfa7 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -215,6 +215,12 @@ void qdev_unplug(DeviceState *dev, Error **errp) } assert(dc->unplug != NULL); + if (!dc->hotpluggable) { + error_set(errp, QERR_DEVICE_NO_HOTPLUG, + object_get_typename(OBJECT(dev))); + return; + } + qdev_hot_removed = true; if (dc->unplug(dev) < 0) { @@ -694,6 +700,11 @@ static void device_set_realized(Object *obj, bool value, Error **err) DeviceClass *dc = DEVICE_GET_CLASS(dev); Error *local_err = NULL; + if (dev->hotplugged && !dc->hotpluggable) { + error_set(err, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); + return; + } + if (value && !dev->realized) { if (!obj->parent && local_err == NULL) { static int unattached_count; @@ -734,6 +745,14 @@ static void device_set_realized(Object *obj, bool value, Error **err) dev->realized = value; } +static bool device_get_hotpluggable(Object *obj, Error **err) +{ + DeviceClass *dc = DEVICE_GET_CLASS(obj); + DeviceState *dev = DEVICE(obj); + + return dc->hotpluggable && dev->parent_bus->allow_hotplug; +} + static void device_initfn(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -750,6 +769,8 @@ static void device_initfn(Object *obj) object_property_add_bool(obj, "realized", device_get_realized, device_set_realized, NULL); + object_property_add_bool(obj, "hotpluggable", + device_get_hotpluggable, NULL, NULL); class = object_get_class(OBJECT(dev)); do { @@ -786,6 +807,14 @@ static void device_class_base_init(ObjectClass *class, void *data) * so do not propagate them to the subclasses. */ klass->props = NULL; + + /* by default all devices were considered as hotpluggable, + * so with intent to check it in generic qdev_unplug() / + * device_set_realized() functions make every device + * hotpluggable. Devices that shouldn't be hotpluggable, + * should override it in their class_init() + */ + klass->hotpluggable = true; } static void device_unparent(Object *obj) -- cgit v1.2.1 From 5e95494380ecf83c97d28f72134ab45e0cace8f9 Mon Sep 17 00:00:00 2001 From: Igor Mammedov Date: Wed, 5 Feb 2014 16:36:52 +0100 Subject: hw/pci: switch to a generic hotplug handling for PCIDevice make qdev_unplug()/device_set_realized() to call hotplug handler's plug/unplug methods if available and remove not needed anymore hot(un)plug handling from PCIDevice. In case if hotplug handler is not available, revert to the legacy hotplug method for compatibility with not yet converted buses. Signed-off-by: Igor Mammedov Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/core/qdev.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'hw/core') diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 5c864dbfa7..64b66e07ef 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -213,7 +213,6 @@ void qdev_unplug(DeviceState *dev, Error **errp) error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); return; } - assert(dc->unplug != NULL); if (!dc->hotpluggable) { error_set(errp, QERR_DEVICE_NO_HOTPLUG, @@ -223,9 +222,13 @@ void qdev_unplug(DeviceState *dev, Error **errp) qdev_hot_removed = true; - if (dc->unplug(dev) < 0) { - error_set(errp, QERR_UNDEFINED_ERROR); - return; + if (dev->parent_bus && dev->parent_bus->hotplug_handler) { + hotplug_handler_unplug(dev->parent_bus->hotplug_handler, dev, errp); + } else { + assert(dc->unplug != NULL); + if (dc->unplug(dev) < 0) { /* legacy handler */ + error_set(errp, QERR_UNDEFINED_ERROR); + } } } @@ -720,6 +723,12 @@ static void device_set_realized(Object *obj, bool value, Error **err) dc->realize(dev, &local_err); } + if (dev->parent_bus && dev->parent_bus->hotplug_handler && + local_err == NULL) { + hotplug_handler_plug(dev->parent_bus->hotplug_handler, + dev, &local_err); + } + if (qdev_get_vmsd(dev) && local_err == NULL) { vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev, dev->instance_id_alias, -- cgit v1.2.1