From patchwork Mon Jul 29 14:56:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Hedde X-Patchwork-Id: 1138448 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=greensocs.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (1024-bit key; secure) header.d=greensocs.com header.i=@greensocs.com header.b="EnWuoyn6"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45y30C3rKzz9s3l for ; Tue, 30 Jul 2019 01:05:31 +1000 (AEST) Received: from localhost ([::1]:53010 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hs7DN-0005Pp-HI for incoming@patchwork.ozlabs.org; Mon, 29 Jul 2019 11:05:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:37905) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hs77H-0004Bg-T9 for qemu-devel@nongnu.org; Mon, 29 Jul 2019 10:59:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hs77D-0004bY-Rv for qemu-devel@nongnu.org; Mon, 29 Jul 2019 10:59:11 -0400 Received: from beetle.greensocs.com ([5.135.226.135]:47988) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hs772-0004PP-Qz; Mon, 29 Jul 2019 10:58:57 -0400 Received: from kouign-amann.bar.greensocs.com (unknown [172.16.11.117]) by beetle.greensocs.com (Postfix) with ESMTPS id A311D96F59; Mon, 29 Jul 2019 14:58:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1564412335; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rxGn1CVCZ0DI+UxefdppQg1uDC8rnLqqzLKgyNbd95U=; b=EnWuoyn6PiWNMjrwMLvec93loNTSro61pVSsk/pHdEPRSvWq9ulcjbpoIws9Eu7+zhkJqs Xj29nVkqbjZiqLsp+05tiu1+QmvrPucS1gqQA+RYrmtnoTHHCLoI9rumR/Jky8xeImQumG CQADDhNmj2m1HoNQhkcnVnvlsFLgedc= From: Damien Hedde To: qemu-devel@nongnu.org Date: Mon, 29 Jul 2019 16:56:25 +0200 Message-Id: <20190729145654.14644-5-damien.hedde@greensocs.com> X-Mailer: git-send-email 2.22.0 In-Reply-To: <20190729145654.14644-1-damien.hedde@greensocs.com> References: <20190729145654.14644-1-damien.hedde@greensocs.com> MIME-Version: 1.0 ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=greensocs.com; s=mail; t=1564412335; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rxGn1CVCZ0DI+UxefdppQg1uDC8rnLqqzLKgyNbd95U=; b=YHkgyGAQulCF1XXnb8+AQB7dROmvHjBWLvYsj6VlvBCg4plVjF+LlD9HyM/hNt6Fy9UYj9 TmgOUx5wsWG8WL8VCdjGlTuLrCZmM5ZXd3WvgBbjY7AHl2E54A+GDVYTmeTt+wDdayXChA +eTGHSSbEx3tFgQ3IL3ZsX35pGIZu0g= ARC-Seal: i=1; s=mail; d=greensocs.com; t=1564412335; a=rsa-sha256; cv=none; b=l26Udfv/6iNz5ygpEeeY/wjm68EJ/xCx0jBg73FjM2fyOer7WkKI4UdOQq0yJ4U+u1jRkT zqqUmQBwx45UCbKY9gcSrDF9lB0GWWQDdSd0tDKuuY/RygkNsVYoh+kMikzFGpT8BvbMQI 797d7V9jyKcZbJqrjlUW3b7XNaucUFY= ARC-Authentication-Results: i=1; beetle.greensocs.com; none X-Spam: Yes X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 5.135.226.135 Subject: [Qemu-devel] [PATCH v3 04/33] make Device and Bus Resettable X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: fam@euphon.net, peter.maydell@linaro.org, walling@linux.ibm.com, dmitry.fleytman@gmail.com, mst@redhat.com, mark.cave-ayland@ilande.co.uk, kraxel@redhat.com, edgar.iglesias@xilinx.com, hare@suse.com, qemu-block@nongnu.org, david@redhat.com, pasic@linux.ibm.com, borntraeger@de.ibm.com, marcandre.lureau@redhat.com, rth@twiddle.net, thuth@redhat.com, ehabkost@redhat.com, alistair@alistair23.me, qemu-s390x@nongnu.org, qemu-arm@nongnu.org, clg@kaod.org, jsnow@redhat.com, david@gibson.dropbear.id.au, Damien Hedde , berrange@redhat.com, cohuck@redhat.com, mark.burton@greensocs.com, qemu-ppc@nongnu.org, pbonzini@redhat.com Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" This add Resettable interface implementation for both Bus and Device. *resetting* counter and *reset_is_cold* flag are added in DeviceState and BusState. Compatibility with existing code base is ensured. The legacy bus or device reset method is called in the new exit phase and the other 2 phases are let empty. Using the exit phase guarantee that legacy resets are called in the "post" order (ie: children then parent) in hierarchical reset. That is the same order as legacy qdev_reset_all or qbus_reset_all were using. New *device_reset* and *bus_reset* function are proposed with an additional boolean argument telling whether the reset is cold or warm. Helper functions *device_reset_[warm|cold]* and *bus_reset_[warm|cold]* are defined also as helpers. Also add a [device|bus]_is_resetting and [device|bus]_is_reset_cold functions telling respectively whether the object is currently under reset and if the current reset is cold or not. Signed-off-by: Damien Hedde --- hw/core/bus.c | 85 ++++++++++++++++++++++++++++++++++++++++++ hw/core/qdev.c | 82 ++++++++++++++++++++++++++++++++++++++++ include/hw/qdev-core.h | 84 ++++++++++++++++++++++++++++++++++++++--- tests/Makefile.include | 1 + 4 files changed, 247 insertions(+), 5 deletions(-) diff --git a/hw/core/bus.c b/hw/core/bus.c index 17bc1edcde..08a97addb6 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -22,6 +22,7 @@ #include "qemu/module.h" #include "hw/qdev.h" #include "qapi/error.h" +#include "hw/resettable.h" void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp) { @@ -68,6 +69,75 @@ int qbus_walk_children(BusState *bus, return 0; } +void bus_reset(BusState *bus, bool cold) +{ + resettable_reset(OBJECT(bus), cold); +} + +bool bus_is_resetting(BusState *bus) +{ + return (bus->resetting != 0); +} + +bool bus_is_reset_cold(BusState *bus) +{ + return bus->reset_is_cold; +} + +static uint32_t bus_get_reset_count(Object *obj) +{ + BusState *bus = BUS(obj); + return bus->resetting; +} + +static uint32_t bus_increment_reset_count(Object *obj) +{ + BusState *bus = BUS(obj); + return ++bus->resetting; +} + +static uint32_t bus_decrement_reset_count(Object *obj) +{ + BusState *bus = BUS(obj); + return --bus->resetting; +} + +static bool bus_set_reset_cold(Object *obj, bool cold) +{ + BusState *bus = BUS(obj); + bool old = bus->reset_is_cold; + bus->reset_is_cold = cold; + return old; +} + +static bool bus_set_hold_needed(Object *obj, bool hold_needed) +{ + BusState *bus = BUS(obj); + bool old = bus->reset_hold_needed; + bus->reset_hold_needed = hold_needed; + return old; +} + +static void bus_foreach_reset_child(Object *obj, void (*func)(Object *)) +{ + BusState *bus = BUS(obj); + BusChild *kid; + + QTAILQ_FOREACH(kid, &bus->children, sibling) { + func(OBJECT(kid->child)); + } +} + +static void bus_obj_legacy_reset(Object *obj) +{ + BusState *bus = BUS(obj); + BusClass *bc = BUS_GET_CLASS(obj); + + if (bc->reset) { + bc->reset(bus); + } +} + static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) { const char *typename = object_get_typename(OBJECT(bus)); @@ -192,6 +262,8 @@ static void qbus_initfn(Object *obj) NULL); object_property_add_bool(obj, "realized", bus_get_realized, bus_set_realized, NULL); + + bus->resetting = 0; } static char *default_bus_get_fw_dev_path(DeviceState *dev) @@ -202,9 +274,18 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev) static void bus_class_init(ObjectClass *class, void *data) { BusClass *bc = BUS_CLASS(class); + ResettableClass *rc = RESETTABLE_CLASS(class); class->unparent = bus_unparent; bc->get_fw_dev_path = default_bus_get_fw_dev_path; + + rc->phases.exit = bus_obj_legacy_reset; + rc->get_count = bus_get_reset_count; + rc->increment_count = bus_increment_reset_count; + rc->decrement_count = bus_decrement_reset_count; + rc->foreach_child = bus_foreach_reset_child; + rc->set_cold = bus_set_reset_cold; + rc->set_hold_needed = bus_set_hold_needed; } static void qbus_finalize(Object *obj) @@ -223,6 +304,10 @@ static const TypeInfo bus_info = { .instance_init = qbus_initfn, .instance_finalize = qbus_finalize, .class_init = bus_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_RESETTABLE }, + { } + }, }; static void bus_register_types(void) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 043e058396..559ced070d 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -254,6 +254,64 @@ HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev) return hotplug_ctrl; } +void device_reset(DeviceState *dev, bool cold) +{ + resettable_reset(OBJECT(dev), cold); +} + +bool device_is_resetting(DeviceState *dev) +{ + return (dev->resetting != 0); +} + +bool device_is_reset_cold(DeviceState *dev) +{ + return dev->reset_is_cold; +} + +static uint32_t device_get_reset_count(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + return dev->resetting; +} + +static uint32_t device_increment_reset_count(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + return ++dev->resetting; +} + +static uint32_t device_decrement_reset_count(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + return --dev->resetting; +} + +static bool device_set_reset_cold(Object *obj, bool cold) +{ + DeviceState *dev = DEVICE(obj); + bool old = dev->reset_is_cold; + dev->reset_is_cold = cold; + return old; +} + +static bool device_set_hold_needed(Object *obj, bool hold_needed) +{ + DeviceState *dev = DEVICE(obj); + bool old = dev->reset_hold_needed; + dev->reset_hold_needed = hold_needed; + return old; +} + +static void device_foreach_reset_child(Object *obj, void (*func)(Object *)) +{ + DeviceState *dev = DEVICE(obj); + BusState *bus; + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + func(OBJECT(bus)); + } +} + static int qdev_reset_one(DeviceState *dev, void *opaque) { device_legacy_reset(dev); @@ -954,6 +1012,7 @@ static void device_initfn(Object *obj) dev->instance_id_alias = -1; dev->realized = false; + dev->resetting = 0; object_property_add_bool(obj, "realized", device_get_realized, device_set_realized, NULL); @@ -1046,9 +1105,20 @@ static void device_unparent(Object *obj) } } +static void device_obj_legacy_reset(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + DeviceClass *dc = DEVICE_GET_CLASS(dev); + + if (dc->reset) { + dc->reset(dev); + } +} + static void device_class_init(ObjectClass *class, void *data) { DeviceClass *dc = DEVICE_CLASS(class); + ResettableClass *rc = RESETTABLE_CLASS(class); class->unparent = device_unparent; @@ -1060,6 +1130,14 @@ static void device_class_init(ObjectClass *class, void *data) */ dc->hotpluggable = true; dc->user_creatable = true; + + rc->phases.exit = device_obj_legacy_reset; + rc->get_count = device_get_reset_count; + rc->increment_count = device_increment_reset_count; + rc->decrement_count = device_decrement_reset_count; + rc->foreach_child = device_foreach_reset_child; + rc->set_cold = device_set_reset_cold; + rc->set_hold_needed = device_set_hold_needed; } void device_class_set_parent_reset(DeviceClass *dc, @@ -1117,6 +1195,10 @@ static const TypeInfo device_type_info = { .class_init = device_class_init, .abstract = true, .class_size = sizeof(DeviceClass), + .interfaces = (InterfaceInfo[]) { + { TYPE_RESETTABLE }, + { } + }, }; static void qdev_register_types(void) diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 690ce72433..eeb75611c8 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -7,6 +7,7 @@ #include "hw/irq.h" #include "hw/hotplug.h" #include "sysemu/sysemu.h" +#include "hw/resettable.h" enum { DEV_NVECTORS_UNSPECIFIED = -1, @@ -132,6 +133,10 @@ struct NamedGPIOList { /** * DeviceState: * @realized: Indicates whether the device has been fully constructed. + * @resetting: Indicates whether the device is under reset. Also + * used to count how many times reset has been initiated on the device. + * @reset_is_cold: If the device is under reset, indicates whether it is cold + * or warm. * * This structure should not be accessed directly. We declare it here * so that it can be embedded in individual device state structures. @@ -153,6 +158,9 @@ struct DeviceState { int num_child_bus; int instance_id_alias; int alias_required_for_version; + uint32_t resetting; + bool reset_is_cold; + bool reset_hold_needed; }; struct DeviceListener { @@ -199,6 +207,10 @@ typedef struct BusChild { /** * BusState: * @hotplug_handler: link to a hotplug handler associated with bus. + * @resetting: Indicates whether the bus is under reset. Also + * used to count how many times reset has been initiated on the bus. + * @reset_is_cold: If the bus is under reset, indicates whether it is cold + * or warm. */ struct BusState { Object obj; @@ -210,6 +222,9 @@ struct BusState { int num_children; QTAILQ_HEAD(, BusChild) children; QLIST_ENTRY(BusState) sibling; + uint32_t resetting; + bool reset_is_cold; + bool reset_hold_needed; }; /** @@ -376,6 +391,70 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, void *opaque); +/** + * device_reset: + * Resets the device @dev, @cold tell whether to do a cold or warm reset. + * Uses the ressetable interface. + * Base behavior is to reset the device and its qdev/qbus subtree. + */ +void device_reset(DeviceState *dev, bool cold); + +static inline void device_reset_warm(DeviceState *dev) +{ + device_reset(dev, false); +} + +static inline void device_reset_cold(DeviceState *dev) +{ + device_reset(dev, true); +} + +/** + * bus_reset: + * Resets the bus @bus, @cold tell whether to do a cold or warm reset. + * Uses the ressetable interface. + * Base behavior is to reset the bus and its qdev/qbus subtree. + */ +void bus_reset(BusState *bus, bool cold); + +static inline void bus_reset_warm(BusState *bus) +{ + bus_reset(bus, false); +} + +static inline void bus_reset_cold(BusState *bus) +{ + bus_reset(bus, true); +} + +/** + * device_is_resetting: + * Tell whether the device @dev is currently under reset. + */ +bool device_is_resetting(DeviceState *dev); + +/** + * device_is_reset_cold: + * Tell whether the device @dev is currently under reset cold or warm reset. + * + * Note: only valid when device_is_resetting returns true. + */ +bool device_is_reset_cold(DeviceState *dev); + +/** + * bus_is_resetting: + * Tell whether the bus @bus is currently under reset. + */ +bool bus_is_resetting(BusState *bus); + +/** + * bus_is_reset_cold: + * Tell whether the bus @bus is currently under reset cold or warm reset. + * + * Note: only valid when bus_is_resetting returns true. + */ +bool bus_is_reset_cold(BusState *bus); + void qdev_reset_all(DeviceState *dev); void qdev_reset_all_fn(void *opaque); @@ -413,11 +492,6 @@ void qdev_machine_init(void); */ void device_legacy_reset(DeviceState *dev); -static inline void device_reset(DeviceState *dev) -{ - device_legacy_reset(dev); -} - void device_class_set_parent_reset(DeviceClass *dc, DeviceReset dev_reset, DeviceReset *parent_reset); diff --git a/tests/Makefile.include b/tests/Makefile.include index fd7fdb8658..1c0a5345b9 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -561,6 +561,7 @@ tests/fp/%: tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\ + hw/core/resettable.o \ hw/core/bus.o \ hw/core/irq.o \ hw/core/fw-path-provider.o \