diff mbox series

[RFC,04/17] Add local reset methods in Device class

Message ID bc73ff96bc52397d1992f6f1b67fa8c71382264f.1553510737.git.damien.hedde@greensocs.com
State New
Headers show
Series multi-phase reset mechanism | expand

Commit Message

Damien Hedde March 25, 2019, 11:01 a.m. UTC
Add 3 methods in device class corresponding to the local part of
the 3-phases reset. This allows specialization classes not to care
about the ressetting counter and sub-buses. The exit phase method
is called only if resetting counter hits 0.

Also, these methods are called in `device_reset`. Specializations can switch
from the single-phase reset to the 3-phases reset with no effects on the
`device_reset` behavior.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
---
 hw/core/qdev.c         | 44 ++++++++++++++++++++++++++++++++++++++++++
 include/hw/qdev-core.h | 17 ++++++++++++++++
 2 files changed, 61 insertions(+)
diff mbox series

Patch

diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 98d173f34f..884a49efa4 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -280,21 +280,30 @@  static void device_reset_init_phase(Object *obj, bool cold)
     if (dc->reset) {
         dc->reset(dev);
     }
+    if (dc->reset_phases.init) {
+        dc->reset_phases.init(OBJECT(dev), cold);
+    }
 }
 
 static void device_reset_hold_phase(Object *obj)
 {
     DeviceState *dev = DEVICE(obj);
+    DeviceClass *dc = DEVICE_GET_CLASS(obj);
     BusState *child;
 
     QLIST_FOREACH(child, &dev->child_bus, sibling) {
         resettable_hold_phase(OBJECT(child));
     }
+
+    if (dc->reset_phases.hold) {
+        dc->reset_phases.hold(OBJECT(dev));
+    }
 }
 
 static void device_reset_exit_phase(Object *obj)
 {
     DeviceState *dev = DEVICE(obj);
+    DeviceClass *dc = DEVICE_GET_CLASS(obj);
     BusState *child;
 
     QLIST_FOREACH(child, &dev->child_bus, sibling) {
@@ -303,6 +312,12 @@  static void device_reset_exit_phase(Object *obj)
 
     assert(dev->resetting > 0);
     dev->resetting -= 1;
+
+    if (dev->resetting == 0) {
+        if (dc->reset_phases.exit) {
+            dc->reset_phases.exit(OBJECT(dev));
+        }
+    }
 }
 
 static int qdev_reset_one(DeviceState *dev, void *opaque)
@@ -1143,6 +1158,24 @@  void device_class_set_parent_unrealize(DeviceClass *dc,
     dc->unrealize = dev_unrealize;
 }
 
+void device_class_set_parent_reset_phases(DeviceClass *dc,
+                                   ResettableInitPhase dev_reset_init,
+                                   ResettableHoldPhase dev_reset_hold,
+                                   ResettableExitPhase dev_reset_exit,
+                                   ResettablePhases *parent_phases)
+{
+    *parent_phases = dc->reset_phases;
+    if (dev_reset_init) {
+        dc->reset_phases.init = dev_reset_init;
+    }
+    if (dev_reset_hold) {
+        dc->reset_phases.hold = dev_reset_hold;
+    }
+    if (dev_reset_exit) {
+        dc->reset_phases.exit = dev_reset_exit;
+    }
+}
+
 void device_reset(DeviceState *dev)
 {
     DeviceClass *klass = DEVICE_GET_CLASS(dev);
@@ -1150,6 +1183,17 @@  void device_reset(DeviceState *dev)
     if (klass->reset) {
         klass->reset(dev);
     }
+    dev->resetting += 1;
+    if (klass->reset_phases.init) {
+        klass->reset_phases.init(OBJECT(dev), false);
+    }
+    if (klass->reset_phases.hold) {
+        klass->reset_phases.hold(OBJECT(dev));
+    }
+    dev->resetting -= 1;
+    if (klass->reset_phases.exit) {
+        klass->reset_phases.exit(OBJECT(dev));
+    }
 }
 
 Object *qdev_get_machine(void)
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index f4aa8dbaa2..0ef4d6c920 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -6,6 +6,7 @@ 
 #include "qom/object.h"
 #include "hw/irq.h"
 #include "hw/hotplug.h"
+#include "hw/resettable.h"
 
 enum {
     DEV_NVECTORS_UNSPECIFIED = -1,
@@ -110,6 +111,7 @@  typedef struct DeviceClass {
     DeviceReset reset;
     DeviceRealize realize;
     DeviceUnrealize unrealize;
+    ResettablePhases reset_phases;
 
     /* device state */
     const struct VMStateDescription *vmsd;
@@ -455,6 +457,21 @@  void device_class_set_parent_unrealize(DeviceClass *dc,
                                        DeviceUnrealize dev_unrealize,
                                        DeviceUnrealize *parent_unrealize);
 
+/**
+ * @device_class_set_parent_reset_phases:
+ *
+ * Save @dc current reset phases into @parent_phases and override @dc phases
+ * by the given new methods (@dev_reset_init, @dev_reset_hold and
+ * @dev_reset_exit).
+ * Each phase is overriden only if the new one is not NULL allowing to
+ * override a subset of phases.
+ */
+void device_class_set_parent_reset_phases(DeviceClass *dc,
+                                   ResettableInitPhase dev_reset_init,
+                                   ResettableHoldPhase dev_reset_hold,
+                                   ResettableExitPhase dev_reset_exit,
+                                   ResettablePhases *parent_phases);
+
 const struct VMStateDescription *qdev_get_vmsd(DeviceState *dev);
 
 const char *qdev_fw_name(DeviceState *dev);