Introduce bus reset callback to support bus reset at qbus layer and a function to trigger bus reset.
Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp> --- hw/qdev.c | 39 +++++++++++++++++++++++++++++++++++++-- hw/qdev.h | 7 +++++++ 2 files changed, 44 insertions(+), 2 deletions(-) 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) -- 1.7.1.1