@@ -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
@@ -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);
}
@@ -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)
@@ -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)
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(-)