Patchwork [5/8] qdev: introduce bus reset callback and helper functions.

login
register
mail settings
Submitter Isaku Yamahata
Date July 30, 2010, 10:03 a.m.
Message ID <fd82eb4ef83c267ba66206e9faed8f1b3b9f316f.1280484023.git.yamahata@valinux.co.jp>
Download mbox | patch
Permalink /patch/60351/
State New
Headers show

Comments

Isaku Yamahata - July 30, 2010, 10:03 a.m.
Introduce bus reset callback to support bus reset at qbus layer
and a function to trigger bus reset.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
 hw/qdev.c |   39 +++++++++++++++++++++++++++++++++++++--
 hw/qdev.h |    7 +++++++
 2 files changed, 44 insertions(+), 2 deletions(-)

Patch

diff --git a/hw/qdev.c b/hw/qdev.c
index 322b315..ced89e3 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -256,6 +256,14 @@  DeviceState *qdev_device_add(QemuOpts *opts)
     return qdev;
 }
 
+void qdev_reset_default(DeviceState *dev)
+{
+    BusState *bus;
+    QLIST_FOREACH(bus, &dev->child_bus, sibling) {
+        qbus_reset(bus);
+    }
+}
+
 /*
  * reset the device.
  * Bring the device into initial known state (to some extent)
@@ -299,7 +307,11 @@  int qdev_init(DeviceState *dev)
         qdev_free(dev);
         return rc;
     }
-    qemu_register_reset(qdev_reset_fn, dev);
+    if (!dev->parent_bus->info->reset) {
+        /* If bus defines reset callback,  reset will be propagated
+           via bus reset callback. So don't register device reset callback */
+        qemu_register_reset(qdev_reset_fn, dev);
+    }
     if (dev->info->vmsd) {
         vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
                                        dev->instance_id_alias,
@@ -671,6 +683,26 @@  static BusState *qbus_find(const char *path)
     }
 }
 
+void qbus_reset_default(BusState *bus)
+{
+    DeviceState *dev;
+    QLIST_FOREACH(dev, &bus->children, sibling) {
+        qdev_reset(dev);
+    }
+}
+
+/* trigger bus reset */
+void qbus_reset(BusState *bus)
+{
+    if (bus->info->reset)
+        bus->info->reset(bus);
+}
+
+static void qbus_reset_fn(void *opaque)
+{
+    qbus_reset(opaque);
+}
+
 void qbus_create_inplace(BusState *bus, BusInfo *info,
                          DeviceState *parent, const char *name)
 {
@@ -705,7 +737,10 @@  void qbus_create_inplace(BusState *bus, BusInfo *info,
         QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
         parent->num_child_bus++;
     }
-
+    if (!parent || !parent->info || !parent->info->reset) {
+        /* parent device should take care of child bus reset */
+        qemu_register_reset(qbus_reset_fn, bus);
+    }
 }
 
 BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name)
diff --git a/hw/qdev.h b/hw/qdev.h
index 10f6769..af76f31 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -50,6 +50,7 @@  struct DeviceState {
 
 typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
 typedef char *(*bus_get_dev_path)(DeviceState *dev);
+typedef void (*bus_resetfn)(BusState *bus);
 
 struct BusInfo {
     const char *name;
@@ -57,6 +58,9 @@  struct BusInfo {
     bus_dev_printfn print_dev;
     bus_get_dev_path get_dev_path;
     Property *props;
+
+    /* bus reset callbacks */
+    bus_resetfn reset;
 };
 
 struct BusState {
@@ -163,6 +167,7 @@  extern DeviceInfo *device_info_list;
 
 void qdev_register(DeviceInfo *info);
 void qdev_reset(DeviceState *dev);
+void qdev_reset_default(DeviceState *dev);
 
 /* Register device properties.  */
 /* GPIO inputs also double as IRQ sinks.  */
@@ -179,6 +184,8 @@  void qbus_create_inplace(BusState *bus, BusInfo *info,
                          DeviceState *parent, const char *name);
 BusState *qbus_create(BusInfo *info, DeviceState *parent, const char *name);
 void qbus_free(BusState *bus);
+void qbus_reset(BusState *bus);
+void qbus_reset_default(BusState *bus);
 
 #define FROM_QBUS(type, dev) DO_UPCAST(type, qbus, dev)