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

login
register
mail settings
Submitter Isaku Yamahata
Date Aug. 5, 2010, 2:09 a.m.
Message ID <8fe13aa92c74e6e43e39d607f4f4c1884a20b89d.1280973617.git.yamahata@valinux.co.jp>
Download mbox | patch
Permalink /patch/60913/
State New
Headers show

Comments

Isaku Yamahata - Aug. 5, 2010, 2:09 a.m.
Introduce bus reset callback to support bus reset at qbus layer
and a function to trigger bus reset.
Now qdev reset callback is triggered by parent qbus reset callback.
And qdev should trigger child qbus reset callback.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
changes v1 -> v2
- eliminate qemu_register_reset() from qdev_create()
  as Gerd suggested.
- Inserted qdev_reset_default() as appropriate.
  This is required for qdev which has reset callback and child bus.
---
 hw/esp.c        |    2 ++
 hw/lsi53c895a.c |    1 +
 hw/qdev.c       |   42 +++++++++++++++++++++++++++++++++++++++---
 hw/qdev.h       |    7 +++++++
 4 files changed, 49 insertions(+), 3 deletions(-)

Patch

diff --git a/hw/esp.c b/hw/esp.c
index 349052a..cafc257 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -423,6 +423,8 @@  static void esp_hard_reset(DeviceState *d)
 {
     ESPState *s = container_of(d, ESPState, busdev.qdev);
 
+    qdev_reset_default(d);
+
     memset(s->rregs, 0, ESP_REGS);
     memset(s->wregs, 0, ESP_REGS);
     s->rregs[ESP_TCHI] = TCHI_FAS100A; // Indicate fas100a
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index bd7b661..33a8eb2 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2042,6 +2042,7 @@  static void lsi_scsi_reset(DeviceState *dev)
 {
     LSIState *s = DO_UPCAST(LSIState, dev.qdev, dev);
 
+    qdev_reset_default(dev);
     lsi_soft_reset(s);
 }
 
diff --git a/hw/qdev.c b/hw/qdev.c
index 322b315..8352f20 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)
@@ -275,8 +283,11 @@  DeviceState *qdev_device_add(QemuOpts *opts)
  */
 void qdev_reset(DeviceState *dev)
 {
-    if (dev->info->reset)
+    if (dev->info->reset) {
         dev->info->reset(dev);
+    } else {
+        qdev_reset_default(dev);
+    }
 }
 
 static void qdev_reset_fn(void *opaque)
@@ -299,7 +310,6 @@  int qdev_init(DeviceState *dev)
         qdev_free(dev);
         return rc;
     }
-    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 +681,29 @@  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);
+    } else {
+        qbus_reset_default(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 +738,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 device takes 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)