diff mbox series

[RFC,1/7] hw/qdev: Introduce DeviceClass::[un]wire() handlers

Message ID 20240209123226.32576-2-philmd@linaro.org
State New
Headers show
Series hw/qdev: Split 'wiring' phase from 'realize' | expand

Commit Message

Philippe Mathieu-Daudé Feb. 9, 2024, 12:32 p.m. UTC
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
---
 include/hw/qdev-core.h |  8 +++++++-
 hw/core/qdev.c         | 21 ++++++++++++++++++++-
 2 files changed, 27 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index d47536eadb..2ca33aea3b 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -101,8 +101,12 @@  typedef void (*BusUnrealize)(BusState *bus);
  * @props: Properties accessing state fields.
  * @realize: Callback function invoked when the #DeviceState:realized
  * property is changed to %true.
+ * @wire: Callback function called after @realize to connect IRQs,
+ * clocks and map memories. Can not fail.
+ * @unwire: Callback function to undo @wire. Called before @unrealize.
+ * Can not fail.
  * @unrealize: Callback function invoked when the #DeviceState:realized
- * property is changed to %false.
+ * property is changed to %false. Can not fail.
  * @hotpluggable: indicates if #DeviceClass is hotpluggable, available
  * as readonly "hotpluggable" property of #DeviceState instance
  *
@@ -161,6 +165,8 @@  struct DeviceClass {
      */
     DeviceReset reset;
     DeviceRealize realize;
+    void (*wire)(DeviceState *dev);
+    void (*unwire)(DeviceState *dev);
     DeviceUnrealize unrealize;
 
     /**
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index c68d0f7c51..1d399aae71 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -303,6 +303,16 @@  bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp)
 
 void qdev_unrealize(DeviceState *dev)
 {
+    DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+    if (dc->unwire) {
+        if (!dc->wire) {
+            error_report("disconnect() without connect() for type '%s'",
+                         object_get_typename(OBJECT(dev)));
+            abort();
+        }
+        dc->unwire(dev);
+    }
     object_property_set_bool(OBJECT(dev), "realized", false, &error_abort);
 }
 
@@ -601,8 +611,17 @@  static void device_set_realized(Object *obj, bool value, Error **errp)
         dev->pending_deleted_event = true;
         DEVICE_LISTENER_CALL(unrealize, Reverse, dev);
     }
-
     assert(local_err == NULL);
+
+    if (dc->wire) {
+        if (!dc->unwire) {
+            warn_report_once("wire() without unwire() for type '%s'",
+                             object_get_typename(OBJECT(dev)));
+        }
+        dc->wire(dev);
+    }
+
+    /* At this point the device is "guest visible". */
     return;
 
 child_realize_fail: