QOM infrastructure fixes and device conversions

* GPIO conversion to QOM, continued
 * Device property description support
 * QTest cases for hotplug
 * Hotplug handler conversion
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJUPeRtAAoJEPou0S0+fgE/8EAP/1mMq3XzWk8p/DlNAfk0Za+h
 xaXW9aRmoVv3QQ6YEnv1/5XC3KjgznVCHgqQMpXu7gkDy9/aL6xjNAOh88UFriIE
 gYM/KpFoZ2kzu63Hhu9rAfzFylzZZDEVeAI060NulHnB8IgZ0/UJPkH5LqPBbsmb
 UpZEvX6unXNtLCTp/rV9of2FDnGl5aPtuHuTvcsz+DdPg6D7elrieiztVuhjftaO
 rGv8SnClN5cThojG8u4s5OVVIoQr1ZSrTA49lsMx/zo9/2OTDzkEl20nCwKt+yMC
 plYtZlq/ODUZu3v18TWUfJHlgRpe5EyXCWhZnmj88NM57zGIzCvvrvV8kSSnUW5v
 CKRCiCRpyS1i6gtGZMcUCh/jScChrco1yEIeEPee6lVjjplly8w3AYP7NxT4YXKA
 FDhg8zaM2CyTjRI2FYmwmxyMkLJRjOnIQU4lkpCc/xQd50kEFJE6f54rNGRTKbIw
 aMDItlTUnITOfq58NStDxcdfp7e+iyRQZo2aQOnD7pKGqONo1pNMoKZHHx/POlv+
 kNjoQAcBWd94bpr9FS1uBtqZ0Zt63ttJlvhdyw2ZGnMIK/Acxy8+fNthZsnU2FjB
 oEZOmGLVc+PPGJPzlRHeHwr3sbOA2Eu6LqMPYHZEYjk0MVZIp75kQfxfMA85fdoy
 5LR6/gwpnI2/jAEPaG6U
 =QFPx
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/afaerber/tags/qom-devices-for-peter' into staging

QOM infrastructure fixes and device conversions

* GPIO conversion to QOM, continued
* Device property description support
* QTest cases for hotplug
* Hotplug handler conversion

# gpg: Signature made Wed 15 Oct 2014 04:05:17 BST using RSA key ID 3E7E013F
# gpg: Good signature from "Andreas Färber <afaerber@suse.de>"
# gpg:                 aka "Andreas Färber <afaerber@suse.com>"

* remotes/afaerber/tags/qom-devices-for-peter: (47 commits)
  qdev: Drop legacy_name from qdev properties
  qmp: Print descriptions of object properties
  qdev: Set the object property's description to the qdev property's.
  qom: Add description field in ObjectProperty struct
  qdev: Add description field in PropertyInfo struct
  qdev: device_del: Search for to be unplugged device in 'peripheral' container
  qdev: HotplugHandler: Add support for unplugging BUS-less devices
  qdev: Drop legacy hotplug fields/methods
  usb: Convert usb devices to hotplug handler API
  usb: Convert usb-ccid to hotplug handler API
  usb-storage: Drop not needed "allow_hotplug = 0"
  usb-bot: Drop not needed "allow_hotplug = 0"
  usb-bot: Mark device as non hotpluggable
  scsi: Cleanup not used anymore SCSIBusInfo{hotplug, hot_unplug} fields
  scsi: Convert virtio-scsi HBA to hotplug handler API
  scsi: Convert pvscsi HBA to hotplug handler API
  scsi: Set SCSI BUS itself as default HotplugHandler
  s390x: Convert virtio-ccw to hotplug handler API
  s390x: Convert s390-virtio to hotplug handler API
  s390x: Drop not used allow_hotplug in event-facility
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2014-10-15 08:12:53 +01:00
commit 88e6599669
50 changed files with 746 additions and 227 deletions

View File

@ -354,8 +354,8 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
} }
} }
static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev, static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
PIIX4PMState *s = PIIX4_PM(hotplug_dev); PIIX4PMState *s = PIIX4_PM(hotplug_dev);
@ -615,7 +615,7 @@ static void piix4_pm_class_init(ObjectClass *klass, void *data)
dc->cannot_instantiate_with_device_add_yet = true; dc->cannot_instantiate_with_device_add_yet = true;
dc->hotpluggable = false; dc->hotpluggable = false;
hc->plug = piix4_device_plug_cb; hc->plug = piix4_device_plug_cb;
hc->unplug = piix4_device_unplug_cb; hc->unplug_request = piix4_device_unplug_request_cb;
adevc->ospm_status = piix4_ospm_status; adevc->ospm_status = piix4_ospm_status;
} }

View File

@ -904,6 +904,12 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
} }
port->elem.out_num = 0; port->elem.out_num = 0;
}
static void virtser_port_device_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev);
QTAILQ_INSERT_TAIL(&port->vser->ports, port, next); QTAILQ_INSERT_TAIL(&port->vser->ports, port, next);
port->ivq = port->vser->ivqs[port->id]; port->ivq = port->vser->ivqs[port->id];
@ -912,7 +918,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
add_port(port->vser, port->id); add_port(port->vser, port->id);
/* Send an update to the guest about this new port added */ /* Send an update to the guest about this new port added */
virtio_notify_config(vdev); virtio_notify_config(VIRTIO_DEVICE(hotplug_dev));
} }
static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) static void virtser_port_device_unrealize(DeviceState *dev, Error **errp)
@ -935,7 +941,6 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOSerial *vser = VIRTIO_SERIAL(dev); VirtIOSerial *vser = VIRTIO_SERIAL(dev);
BusState *bus;
uint32_t i, max_supported_ports; uint32_t i, max_supported_ports;
if (!vser->serial.max_virtserial_ports) { if (!vser->serial.max_virtserial_ports) {
@ -957,8 +962,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
/* Spawn a new virtio-serial bus on which the ports will ride as devices */ /* Spawn a new virtio-serial bus on which the ports will ride as devices */
qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS,
dev, vdev->bus_name); dev, vdev->bus_name);
bus = BUS(&vser->bus); qbus_set_hotplug_handler(BUS(&vser->bus), DEVICE(vser), errp);
bus->allow_hotplug = 1;
vser->bus.vser = vser; vser->bus.vser = vser;
QTAILQ_INIT(&vser->ports); QTAILQ_INIT(&vser->ports);
@ -1021,7 +1025,6 @@ static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
k->bus_type = TYPE_VIRTIO_SERIAL_BUS; k->bus_type = TYPE_VIRTIO_SERIAL_BUS;
k->realize = virtser_port_device_realize; k->realize = virtser_port_device_realize;
k->unrealize = virtser_port_device_unrealize; k->unrealize = virtser_port_device_unrealize;
k->unplug = qdev_simple_unplug_cb;
k->props = virtser_props; k->props = virtser_props;
} }
@ -1064,6 +1067,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
QLIST_INIT(&vserdevices.devices); QLIST_INIT(&vserdevices.devices);
@ -1077,6 +1081,8 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
vdc->reset = vser_reset; vdc->reset = vser_reset;
vdc->save = virtio_serial_save_device; vdc->save = virtio_serial_save_device;
vdc->load = virtio_serial_load_device; vdc->load = virtio_serial_load_device;
hc->plug = virtser_port_device_plug;
hc->unplug = qdev_simple_device_unplug_cb;
} }
static const TypeInfo virtio_device_info = { static const TypeInfo virtio_device_info = {
@ -1084,6 +1090,10 @@ static const TypeInfo virtio_device_info = {
.parent = TYPE_VIRTIO_DEVICE, .parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VirtIOSerial), .instance_size = sizeof(VirtIOSerial),
.class_init = virtio_serial_class_init, .class_init = virtio_serial_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
static void virtio_serial_register_types(void) static void virtio_serial_register_types(void)

View File

@ -23,6 +23,17 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
} }
} }
void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp)
{
HotplugHandlerClass *hdc = HOTPLUG_HANDLER_GET_CLASS(plug_handler);
if (hdc->unplug_request) {
hdc->unplug_request(plug_handler, plugged_dev, errp);
}
}
void hotplug_handler_unplug(HotplugHandler *plug_handler, void hotplug_handler_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, DeviceState *plugged_dev,
Error **errp) Error **errp)

View File

@ -112,7 +112,7 @@ static void set_drive(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_drive = { PropertyInfo qdev_prop_drive = {
.name = "str", .name = "str",
.legacy_name = "drive", .description = "ID of a drive to use as a backend",
.get = get_drive, .get = get_drive,
.set = set_drive, .set = set_drive,
.release = release_drive, .release = release_drive,
@ -169,7 +169,7 @@ static void set_chr(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_chr = { PropertyInfo qdev_prop_chr = {
.name = "str", .name = "str",
.legacy_name = "chr", .description = "ID of a chardev to use as a backend",
.get = get_chr, .get = get_chr,
.set = set_chr, .set = set_chr,
.release = release_chr, .release = release_chr,
@ -248,7 +248,7 @@ static void set_netdev(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_netdev = { PropertyInfo qdev_prop_netdev = {
.name = "str", .name = "str",
.legacy_name = "netdev", .description = "ID of a netdev to use as a backend",
.get = get_netdev, .get = get_netdev,
.set = set_netdev, .set = set_netdev,
}; };
@ -328,7 +328,7 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_vlan = { PropertyInfo qdev_prop_vlan = {
.name = "int32", .name = "int32",
.legacy_name = "vlan", .description = "Integer VLAN id to connect to",
.print = print_vlan, .print = print_vlan,
.get = get_vlan, .get = get_vlan,
.set = set_vlan, .set = set_vlan,

View File

@ -120,7 +120,7 @@ static void prop_set_bit(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_bit = { PropertyInfo qdev_prop_bit = {
.name = "bool", .name = "bool",
.legacy_name = "on/off", .description = "on/off",
.get = prop_get_bit, .get = prop_get_bit,
.set = prop_set_bit, .set = prop_set_bit,
}; };
@ -455,7 +455,7 @@ inval:
PropertyInfo qdev_prop_macaddr = { PropertyInfo qdev_prop_macaddr = {
.name = "str", .name = "str",
.legacy_name = "macaddr", .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac, .get = get_mac,
.set = set_mac, .set = set_mac,
}; };
@ -477,7 +477,8 @@ QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
PropertyInfo qdev_prop_bios_chs_trans = { PropertyInfo qdev_prop_bios_chs_trans = {
.name = "BiosAtaTranslation", .name = "BiosAtaTranslation",
.legacy_name = "bios-chs-trans", .description = "Logical CHS translation algorithm, "
"auto/none/lba/large/rechs",
.enum_table = BiosAtaTranslation_lookup, .enum_table = BiosAtaTranslation_lookup,
.get = get_enum, .get = get_enum,
.set = set_enum, .set = set_enum,
@ -551,7 +552,7 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
PropertyInfo qdev_prop_pci_devfn = { PropertyInfo qdev_prop_pci_devfn = {
.name = "int32", .name = "int32",
.legacy_name = "pci-devfn", .description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn, .print = print_pci_devfn,
.get = get_int32, .get = get_int32,
.set = set_pci_devfn, .set = set_pci_devfn,
@ -598,7 +599,7 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque,
PropertyInfo qdev_prop_blocksize = { PropertyInfo qdev_prop_blocksize = {
.name = "uint16", .name = "uint16",
.legacy_name = "blocksize", .description = "A power of two between 512 and 32768",
.get = get_uint16, .get = get_uint16,
.set = set_blocksize, .set = set_blocksize,
}; };
@ -706,7 +707,8 @@ inval:
PropertyInfo qdev_prop_pci_host_devaddr = { PropertyInfo qdev_prop_pci_host_devaddr = {
.name = "str", .name = "str",
.legacy_name = "pci-host-devaddr", .description = "Address (bus/device/function) of "
"the host device, example: 04:10.0",
.get = get_pci_host_devaddr, .get = get_pci_host_devaddr,
.set = set_pci_host_devaddr, .set = set_pci_host_devaddr,
}; };

View File

@ -85,10 +85,6 @@ static void bus_add_child(BusState *bus, DeviceState *child)
char name[32]; char name[32];
BusChild *kid = g_malloc0(sizeof(*kid)); BusChild *kid = g_malloc0(sizeof(*kid));
if (qdev_hotplug) {
assert(bus->allow_hotplug);
}
kid->index = bus->max_index++; kid->index = bus->max_index++;
kid->child = child; kid->child = child;
object_ref(OBJECT(kid->child)); object_ref(OBJECT(kid->child));
@ -112,6 +108,24 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
bus_add_child(bus, dev); bus_add_child(bus, dev);
} }
static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler,
Error **errp)
{
object_property_set_link(OBJECT(bus), OBJECT(handler),
QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
}
void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, Error **errp)
{
qbus_set_hotplug_handler_internal(bus, OBJECT(handler), errp);
}
void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp)
{
qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp);
}
/* Create a new device. This only initializes the device state structure /* Create a new device. This only initializes the device state structure
and allows properties to be set. qdev_init should be called to and allows properties to be set. qdev_init should be called to
initialize the actual device emulation. */ initialize the actual device emulation. */
@ -209,11 +223,30 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
dev->alias_required_for_version = required_for_version; dev->alias_required_for_version = required_for_version;
} }
static HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
{
HotplugHandler *hotplug_ctrl = NULL;
if (dev->parent_bus && dev->parent_bus->hotplug_handler) {
hotplug_ctrl = dev->parent_bus->hotplug_handler;
} else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
MachineState *machine = MACHINE(qdev_get_machine());
MachineClass *mc = MACHINE_GET_CLASS(machine);
if (mc->get_hotplug_handler) {
hotplug_ctrl = mc->get_hotplug_handler(machine, dev);
}
}
return hotplug_ctrl;
}
void qdev_unplug(DeviceState *dev, Error **errp) void qdev_unplug(DeviceState *dev, Error **errp)
{ {
DeviceClass *dc = DEVICE_GET_CLASS(dev); DeviceClass *dc = DEVICE_GET_CLASS(dev);
HotplugHandler *hotplug_ctrl;
HotplugHandlerClass *hdc;
if (dev->parent_bus && !dev->parent_bus->allow_hotplug) { if (dev->parent_bus && !qbus_is_hotpluggable(dev->parent_bus)) {
error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name); error_set(errp, QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
return; return;
} }
@ -226,13 +259,18 @@ void qdev_unplug(DeviceState *dev, Error **errp)
qdev_hot_removed = true; qdev_hot_removed = true;
if (dev->parent_bus && dev->parent_bus->hotplug_handler) { hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_unplug(dev->parent_bus->hotplug_handler, dev, errp); /* hotpluggable device MUST have HotplugHandler, if it doesn't
* then something is very wrong with it */
g_assert(hotplug_ctrl);
/* If device supports async unplug just request it to be done,
* otherwise just remove it synchronously */
hdc = HOTPLUG_HANDLER_GET_CLASS(hotplug_ctrl);
if (hdc->unplug_request) {
hotplug_handler_unplug_request(hotplug_ctrl, dev, errp);
} else { } else {
assert(dc->unplug != NULL); hotplug_handler_unplug(hotplug_ctrl, dev, errp);
if (dc->unplug(dev) < 0) { /* legacy handler */
error_set(errp, QERR_UNDEFINED_ERROR);
}
} }
} }
@ -269,14 +307,13 @@ void qbus_reset_all_fn(void *opaque)
} }
/* can be used as ->unplug() callback for the simple cases */ /* can be used as ->unplug() callback for the simple cases */
int qdev_simple_unplug_cb(DeviceState *dev) void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{ {
/* just zap it */ /* just zap it */
object_unparent(OBJECT(dev)); object_unparent(OBJECT(dev));
return 0;
} }
/* Like qdev_init(), but terminate program via error_report() instead of /* Like qdev_init(), but terminate program via error_report() instead of
returning an error value. This is okay during machine creation. returning an error value. This is okay during machine creation.
Don't use for hotplug, because there callers need to recover from Don't use for hotplug, because there callers need to recover from
@ -337,10 +374,20 @@ static NamedGPIOList *qdev_get_named_gpio_list(DeviceState *dev,
void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler, void qdev_init_gpio_in_named(DeviceState *dev, qemu_irq_handler handler,
const char *name, int n) const char *name, int n)
{ {
int i;
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
char *propname = g_strdup_printf("%s[*]", name ? name : "unnamed-gpio-in");
assert(gpio_list->num_out == 0 || !name);
gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler, gpio_list->in = qemu_extend_irqs(gpio_list->in, gpio_list->num_in, handler,
dev, n); dev, n);
for (i = gpio_list->num_in; i < gpio_list->num_in + n; i++) {
object_property_add_child(OBJECT(dev), propname,
OBJECT(gpio_list->in[i]), &error_abort);
}
g_free(propname);
gpio_list->num_in += n; gpio_list->num_in += n;
} }
@ -352,11 +399,24 @@ void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n)
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins, void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
const char *name, int n) const char *name, int n)
{ {
int i;
NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name); NamedGPIOList *gpio_list = qdev_get_named_gpio_list(dev, name);
char *propname = g_strdup_printf("%s[*]", name ? name : "unnamed-gpio-out");
assert(gpio_list->num_in == 0 || !name);
assert(gpio_list->num_out == 0); assert(gpio_list->num_out == 0);
gpio_list->num_out = n; gpio_list->num_out = n;
gpio_list->out = pins; gpio_list->out = pins;
for (i = 0; i < n; ++i) {
memset(&pins[i], 0, sizeof(*pins));
object_property_add_link(OBJECT(dev), propname, TYPE_IRQ,
(Object **)&pins[i],
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
}
g_free(propname);
} }
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n) void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n)
@ -766,6 +826,11 @@ void qdev_property_add_static(DeviceState *dev, Property *prop,
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;
} }
object_property_set_description(obj, prop->name,
prop->info->description,
&error_abort);
if (prop->qtype == QTYPE_NONE) { if (prop->qtype == QTYPE_NONE) {
return; return;
} }
@ -811,6 +876,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
{ {
DeviceState *dev = DEVICE(obj); DeviceState *dev = DEVICE(obj);
DeviceClass *dc = DEVICE_GET_CLASS(dev); DeviceClass *dc = DEVICE_GET_CLASS(dev);
HotplugHandler *hotplug_ctrl;
BusState *bus; BusState *bus;
Error *local_err = NULL; Error *local_err = NULL;
@ -838,20 +904,9 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
goto fail; goto fail;
} }
if (dev->parent_bus && dev->parent_bus->hotplug_handler) { hotplug_ctrl = qdev_get_hotplug_handler(dev);
hotplug_handler_plug(dev->parent_bus->hotplug_handler, if (hotplug_ctrl) {
dev, &local_err); hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
} else if (object_dynamic_cast(qdev_get_machine(), TYPE_MACHINE)) {
HotplugHandler *hotplug_ctrl;
MachineState *machine = MACHINE(qdev_get_machine());
MachineClass *mc = MACHINE_GET_CLASS(machine);
if (mc->get_hotplug_handler) {
hotplug_ctrl = mc->get_hotplug_handler(machine, dev);
if (hotplug_ctrl) {
hotplug_handler_plug(hotplug_ctrl, dev, &local_err);
}
}
} }
if (local_err != NULL) { if (local_err != NULL) {
@ -925,7 +980,7 @@ static bool device_get_hotpluggable(Object *obj, Error **errp)
DeviceState *dev = DEVICE(obj); DeviceState *dev = DEVICE(obj);
return dc->hotpluggable && (dev->parent_bus == NULL || return dc->hotpluggable && (dev->parent_bus == NULL ||
dev->parent_bus->allow_hotplug); qbus_is_hotpluggable(dev->parent_bus));
} }
static bool device_get_hotplugged(Object *obj, Error **err) static bool device_get_hotplugged(Object *obj, Error **err)

View File

@ -24,18 +24,10 @@
/* icc-bridge implementation */ /* icc-bridge implementation */
static void icc_bus_init(Object *obj)
{
BusState *b = BUS(obj);
b->allow_hotplug = true;
}
static const TypeInfo icc_bus_info = { static const TypeInfo icc_bus_info = {
.name = TYPE_ICC_BUS, .name = TYPE_ICC_BUS,
.parent = TYPE_BUS, .parent = TYPE_BUS,
.instance_size = sizeof(ICCBus), .instance_size = sizeof(ICCBus),
.instance_init = icc_bus_init,
}; };

View File

@ -774,7 +774,7 @@ static void *acpi_set_bsel(PCIBus *bus, void *opaque)
unsigned *bsel_alloc = opaque; unsigned *bsel_alloc = opaque;
unsigned *bus_bsel; unsigned *bus_bsel;
if (bus->qbus.allow_hotplug) { if (qbus_is_hotpluggable(BUS(bus))) {
bus_bsel = g_malloc(sizeof *bus_bsel); bus_bsel = g_malloc(sizeof *bus_bsel);
*bus_bsel = (*bsel_alloc)++; *bus_bsel = (*bsel_alloc)++;

View File

@ -607,8 +607,8 @@ static void ich9_device_plug_cb(HotplugHandler *hotplug_dev,
ich9_pm_device_plug_cb(&lpc->pm, dev, errp); ich9_pm_device_plug_cb(&lpc->pm, dev, errp);
} }
static void ich9_device_unplug_cb(HotplugHandler *hotplug_dev, static void ich9_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
error_setg(errp, "acpi: device unplug request for not supported device" error_setg(errp, "acpi: device unplug request for not supported device"
" type: %s", object_get_typename(OBJECT(dev))); " type: %s", object_get_typename(OBJECT(dev)));
@ -676,7 +676,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
*/ */
dc->cannot_instantiate_with_device_add_yet = true; dc->cannot_instantiate_with_device_add_yet = true;
hc->plug = ich9_device_plug_cb; hc->plug = ich9_device_plug_cb;
hc->unplug = ich9_device_unplug_cb; hc->unplug_request = ich9_device_unplug_request_cb;
adevc->ospm_status = ich9_pm_ospm_status; adevc->ospm_status = ich9_pm_ospm_status;
} }

View File

@ -150,7 +150,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data)
dc->vmsd = &pci_bridge_dev_vmstate; dc->vmsd = &pci_bridge_dev_vmstate;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
hc->plug = shpc_device_hotplug_cb; hc->plug = shpc_device_hotplug_cb;
hc->unplug = shpc_device_hot_unplug_cb; hc->unplug_request = shpc_device_hot_unplug_request_cb;
} }
static const TypeInfo pci_bridge_dev_info = { static const TypeInfo pci_bridge_dev_info = {

View File

@ -77,7 +77,7 @@ static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon,
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
return NULL; return NULL;
} }
if (!((BusState*)bus)->allow_hotplug) { if (!qbus_is_hotpluggable(BUS(bus))) {
monitor_printf(mon, "PCI bus doesn't support hotplug\n"); monitor_printf(mon, "PCI bus doesn't support hotplug\n");
return NULL; return NULL;
} }
@ -227,7 +227,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
monitor_printf(mon, "Invalid PCI device address %s\n", devaddr); monitor_printf(mon, "Invalid PCI device address %s\n", devaddr);
return NULL; return NULL;
} }
if (!((BusState*)bus)->allow_hotplug) { if (!qbus_is_hotpluggable(BUS(bus))) {
monitor_printf(mon, "PCI bus doesn't support hotplug\n"); monitor_printf(mon, "PCI bus doesn't support hotplug\n");
return NULL; return NULL;
} }

View File

@ -262,8 +262,8 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP); PCI_EXP_HP_EV_PDC | PCI_EXP_HP_EV_ABP);
} }
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
Error **errp) DeviceState *dev, Error **errp)
{ {
uint8_t *exp_cap; uint8_t *exp_cap;

View File

@ -154,7 +154,7 @@ static void pcie_slot_class_init(ObjectClass *oc, void *data)
dc->props = pcie_slot_props; dc->props = pcie_slot_props;
hc->plug = pcie_cap_slot_hotplug_cb; hc->plug = pcie_cap_slot_hotplug_cb;
hc->unplug = pcie_cap_slot_hot_unplug_cb; hc->unplug_request = pcie_cap_slot_hot_unplug_request_cb;
} }
static const TypeInfo pcie_slot_type_info = { static const TypeInfo pcie_slot_type_info = {

View File

@ -549,8 +549,8 @@ void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
shpc_interrupt_update(pci_hotplug_dev); shpc_interrupt_update(pci_hotplug_dev);
} }
void shpc_device_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
Error **errp) DeviceState *dev, Error **errp)
{ {
Error *local_err = NULL; Error *local_err = NULL;
PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev); PCIDevice *pci_hotplug_dev = PCI_DEVICE(hotplug_dev);

View File

@ -333,7 +333,6 @@ static int init_event_facility(SCLPEventFacility *event_facility)
/* Spawn a new bus for SCLP events */ /* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
TYPE_SCLP_EVENTS_BUS, sdev, NULL); TYPE_SCLP_EVENTS_BUS, sdev, NULL);
event_facility->sbus.qbus.allow_hotplug = 0;
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
if (!quiesce) { if (!quiesce) {
@ -408,7 +407,6 @@ static void event_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->bus_type = TYPE_SCLP_EVENTS_BUS; dc->bus_type = TYPE_SCLP_EVENTS_BUS;
dc->unplug = qdev_simple_unplug_cb;
dc->realize = event_realize; dc->realize = event_realize;
dc->unrealize = event_unrealize; dc->unrealize = event_unrealize;
} }

View File

@ -102,7 +102,7 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
bus->next_ring = bus->dev_page + TARGET_PAGE_SIZE; bus->next_ring = bus->dev_page + TARGET_PAGE_SIZE;
/* Enable hotplugging */ /* Enable hotplugging */
_bus->allow_hotplug = 1; qbus_set_hotplug_handler(_bus, dev, &error_abort);
/* Allocate RAM for VirtIO device pages (descriptors, queues, rings) */ /* Allocate RAM for VirtIO device pages (descriptors, queues, rings) */
*ram_size += S390_DEVICE_PAGES * TARGET_PAGE_SIZE; *ram_size += S390_DEVICE_PAGES * TARGET_PAGE_SIZE;
@ -600,7 +600,6 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
dc->init = s390_virtio_busdev_init; dc->init = s390_virtio_busdev_init;
dc->bus_type = TYPE_S390_VIRTIO_BUS; dc->bus_type = TYPE_S390_VIRTIO_BUS;
dc->unplug = qdev_simple_unplug_cb;
dc->reset = s390_virtio_busdev_reset; dc->reset = s390_virtio_busdev_reset;
} }
@ -681,6 +680,10 @@ static const TypeInfo s390_virtio_bridge_info = {
.parent = TYPE_SYS_BUS_DEVICE, .parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SysBusDevice), .instance_size = sizeof(SysBusDevice),
.class_init = s390_virtio_bridge_class_init, .class_init = s390_virtio_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
/* virtio-s390-bus */ /* virtio-s390-bus */
@ -689,13 +692,10 @@ static void virtio_s390_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOS390Device *dev) VirtIOS390Device *dev)
{ {
DeviceState *qdev = DEVICE(dev); DeviceState *qdev = DEVICE(dev);
BusState *qbus;
char virtio_bus_name[] = "virtio-bus"; char virtio_bus_name[] = "virtio-bus";
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_S390_BUS, qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_S390_BUS,
qdev, virtio_bus_name); qdev, virtio_bus_name);
qbus = BUS(bus);
qbus->allow_hotplug = 1;
} }
static void virtio_s390_bus_class_init(ObjectClass *klass, void *data) static void virtio_s390_bus_class_init(ObjectClass *klass, void *data)

View File

@ -230,7 +230,7 @@ VirtualCssBus *virtual_css_bus_init(void)
cbus = VIRTUAL_CSS_BUS(bus); cbus = VIRTUAL_CSS_BUS(bus);
/* Enable hotplugging */ /* Enable hotplugging */
bus->allow_hotplug = 1; qbus_set_hotplug_handler(bus, dev, &error_abort);
return cbus; return cbus;
} }
@ -1590,7 +1590,8 @@ static int virtio_ccw_busdev_exit(DeviceState *dev)
return _info->exit(_dev); return _info->exit(_dev);
} }
static int virtio_ccw_busdev_unplug(DeviceState *dev) static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{ {
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
SubchDev *sch = _dev->sch; SubchDev *sch = _dev->sch;
@ -1609,7 +1610,6 @@ static int virtio_ccw_busdev_unplug(DeviceState *dev)
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0);
object_unparent(OBJECT(dev)); object_unparent(OBJECT(dev));
return 0;
} }
static Property virtio_ccw_properties[] = { static Property virtio_ccw_properties[] = {
@ -1624,9 +1624,7 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
dc->props = virtio_ccw_properties; dc->props = virtio_ccw_properties;
dc->init = virtio_ccw_busdev_init; dc->init = virtio_ccw_busdev_init;
dc->exit = virtio_ccw_busdev_exit; dc->exit = virtio_ccw_busdev_exit;
dc->unplug = virtio_ccw_busdev_unplug;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS; dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
} }
static const TypeInfo virtio_ccw_device_info = { static const TypeInfo virtio_ccw_device_info = {
@ -1650,8 +1648,10 @@ static int virtual_css_bridge_init(SysBusDevice *dev)
static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) static void virtual_css_bridge_class_init(ObjectClass *klass, void *data)
{ {
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->init = virtual_css_bridge_init; k->init = virtual_css_bridge_init;
hc->unplug = virtio_ccw_busdev_unplug;
} }
static const TypeInfo virtual_css_bridge_info = { static const TypeInfo virtual_css_bridge_info = {
@ -1659,6 +1659,10 @@ static const TypeInfo virtual_css_bridge_info = {
.parent = TYPE_SYS_BUS_DEVICE, .parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SysBusDevice), .instance_size = sizeof(SysBusDevice),
.class_init = virtual_css_bridge_class_init, .class_init = virtual_css_bridge_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
/* virtio-ccw-bus */ /* virtio-ccw-bus */
@ -1667,13 +1671,10 @@ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
VirtioCcwDevice *dev) VirtioCcwDevice *dev)
{ {
DeviceState *qdev = DEVICE(dev); DeviceState *qdev = DEVICE(dev);
BusState *qbus;
char virtio_bus_name[] = "virtio-bus"; char virtio_bus_name[] = "virtio-bus";
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS, qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS,
qdev, virtio_bus_name); qdev, virtio_bus_name);
qbus = BUS(bus);
qbus->allow_hotplug = 1;
} }
static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)

View File

@ -23,9 +23,11 @@ static Property scsi_props[] = {
static void scsi_bus_class_init(ObjectClass *klass, void *data) static void scsi_bus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *k = BUS_CLASS(klass); BusClass *k = BUS_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->get_dev_path = scsibus_get_dev_path; k->get_dev_path = scsibus_get_dev_path;
k->get_fw_dev_path = scsibus_get_fw_dev_path; k->get_fw_dev_path = scsibus_get_fw_dev_path;
hc->unplug = qdev_simple_device_unplug_cb;
} }
static const TypeInfo scsi_bus_info = { static const TypeInfo scsi_bus_info = {
@ -33,6 +35,10 @@ static const TypeInfo scsi_bus_info = {
.parent = TYPE_BUS, .parent = TYPE_BUS,
.instance_size = sizeof(SCSIBus), .instance_size = sizeof(SCSIBus),
.class_init = scsi_bus_class_init, .class_init = scsi_bus_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
static int next_scsi_bus; static int next_scsi_bus;
@ -92,7 +98,7 @@ void scsi_bus_new(SCSIBus *bus, size_t bus_size, DeviceState *host,
qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS, host, bus_name); qbus_create_inplace(bus, bus_size, TYPE_SCSI_BUS, host, bus_name);
bus->busnr = next_scsi_bus++; bus->busnr = next_scsi_bus++;
bus->info = info; bus->info = info;
bus->qbus.allow_hotplug = 1; qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
} }
static void scsi_dma_restart_bh(void *opaque) static void scsi_dma_restart_bh(void *opaque)
@ -202,10 +208,6 @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp)
} }
dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb, dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
dev); dev);
if (bus->info->hotplug) {
bus->info->hotplug(bus, dev);
}
} }
static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp) static void scsi_qdev_unrealize(DeviceState *qdev, Error **errp)
@ -1937,17 +1939,6 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
return 0; return 0;
} }
static int scsi_qdev_unplug(DeviceState *qdev)
{
SCSIDevice *dev = SCSI_DEVICE(qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
if (bus->info->hot_unplug) {
bus->info->hot_unplug(bus, dev);
}
return qdev_simple_unplug_cb(qdev);
}
static const VMStateInfo vmstate_info_scsi_requests = { static const VMStateInfo vmstate_info_scsi_requests = {
.name = "scsi-requests", .name = "scsi-requests",
.get = get_scsi_requests, .get = get_scsi_requests,
@ -2011,7 +2002,6 @@ static void scsi_device_class_init(ObjectClass *klass, void *data)
set_bit(DEVICE_CATEGORY_STORAGE, k->categories); set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
k->bus_type = TYPE_SCSI_BUS; k->bus_type = TYPE_SCSI_BUS;
k->realize = scsi_qdev_realize; k->realize = scsi_qdev_realize;
k->unplug = scsi_qdev_unplug;
k->unrealize = scsi_qdev_unrealize; k->unrealize = scsi_qdev_unrealize;
k->props = scsi_props; k->props = scsi_props;
} }

View File

@ -737,26 +737,29 @@ static void virtio_scsi_change(SCSIBus *bus, SCSIDevice *dev, SCSISense sense)
} }
} }
static void virtio_scsi_hotplug(SCSIBus *bus, SCSIDevice *dev) static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{ {
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
VirtIODevice *vdev = VIRTIO_DEVICE(s);
if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) { if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET, virtio_scsi_push_event(VIRTIO_SCSI(hotplug_dev), SCSI_DEVICE(dev),
VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_RESCAN); VIRTIO_SCSI_EVT_RESET_RESCAN);
} }
} }
static void virtio_scsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev) static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{ {
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); VirtIODevice *vdev = VIRTIO_DEVICE(hotplug_dev);
VirtIODevice *vdev = VIRTIO_DEVICE(s);
if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) { if ((vdev->guest_features >> VIRTIO_SCSI_F_HOTPLUG) & 1) {
virtio_scsi_push_event(s, dev, VIRTIO_SCSI_T_TRANSPORT_RESET, virtio_scsi_push_event(VIRTIO_SCSI(hotplug_dev), SCSI_DEVICE(dev),
VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_REMOVED); VIRTIO_SCSI_EVT_RESET_REMOVED);
} }
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
} }
static struct SCSIBusInfo virtio_scsi_scsi_info = { static struct SCSIBusInfo virtio_scsi_scsi_info = {
@ -768,8 +771,6 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = {
.complete = virtio_scsi_command_complete, .complete = virtio_scsi_command_complete,
.cancel = virtio_scsi_request_cancelled, .cancel = virtio_scsi_request_cancelled,
.change = virtio_scsi_change, .change = virtio_scsi_change,
.hotplug = virtio_scsi_hotplug,
.hot_unplug = virtio_scsi_hot_unplug,
.parse_cdb = virtio_scsi_parse_cdb, .parse_cdb = virtio_scsi_parse_cdb,
.get_sg_list = virtio_scsi_get_sg_list, .get_sg_list = virtio_scsi_get_sg_list,
.save_request = virtio_scsi_save_request, .save_request = virtio_scsi_save_request,
@ -853,6 +854,8 @@ static void virtio_scsi_device_realize(DeviceState *dev, Error **errp)
scsi_bus_new(&s->bus, sizeof(s->bus), dev, scsi_bus_new(&s->bus, sizeof(s->bus), dev,
&virtio_scsi_scsi_info, vdev->bus_name); &virtio_scsi_scsi_info, vdev->bus_name);
/* override default SCSI bus hotplug-handler, with virtio-scsi's one */
qbus_set_hotplug_handler(BUS(&s->bus), dev, &error_abort);
if (!dev->hotplugged) { if (!dev->hotplugged) {
scsi_bus_legacy_handle_cmdline(&s->bus, &err); scsi_bus_legacy_handle_cmdline(&s->bus, &err);
@ -915,6 +918,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
dc->props = virtio_scsi_properties; dc->props = virtio_scsi_properties;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
@ -923,6 +927,8 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data)
vdc->set_config = virtio_scsi_set_config; vdc->set_config = virtio_scsi_set_config;
vdc->get_features = virtio_scsi_get_features; vdc->get_features = virtio_scsi_get_features;
vdc->reset = virtio_scsi_reset; vdc->reset = virtio_scsi_reset;
hc->plug = virtio_scsi_hotplug;
hc->unplug = virtio_scsi_hotunplug;
} }
static const TypeInfo virtio_scsi_common_info = { static const TypeInfo virtio_scsi_common_info = {
@ -939,6 +945,10 @@ static const TypeInfo virtio_scsi_info = {
.instance_size = sizeof(VirtIOSCSI), .instance_size = sizeof(VirtIOSCSI),
.instance_init = virtio_scsi_instance_init, .instance_init = virtio_scsi_instance_init,
.class_init = virtio_scsi_class_init, .class_init = virtio_scsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
static void virtio_register_types(void) static void virtio_register_types(void)

View File

@ -524,17 +524,20 @@ pvscsi_send_msg(PVSCSIState *s, SCSIDevice *dev, uint32_t msg_type)
} }
static void static void
pvscsi_hotplug(SCSIBus *bus, SCSIDevice *dev) pvscsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
{ {
PVSCSIState *s = container_of(bus, PVSCSIState, bus); PVSCSIState *s = PVSCSI(hotplug_dev);
pvscsi_send_msg(s, dev, PVSCSI_MSG_DEV_ADDED);
pvscsi_send_msg(s, SCSI_DEVICE(dev), PVSCSI_MSG_DEV_ADDED);
} }
static void static void
pvscsi_hot_unplug(SCSIBus *bus, SCSIDevice *dev) pvscsi_hot_unplug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp)
{ {
PVSCSIState *s = container_of(bus, PVSCSIState, bus); PVSCSIState *s = PVSCSI(hotplug_dev);
pvscsi_send_msg(s, dev, PVSCSI_MSG_DEV_REMOVED);
pvscsi_send_msg(s, SCSI_DEVICE(dev), PVSCSI_MSG_DEV_REMOVED);
qdev_simple_device_unplug_cb(hotplug_dev, dev, errp);
} }
static void static void
@ -1057,8 +1060,6 @@ static const struct SCSIBusInfo pvscsi_scsi_info = {
.get_sg_list = pvscsi_get_sg_list, .get_sg_list = pvscsi_get_sg_list,
.complete = pvscsi_command_complete, .complete = pvscsi_command_complete,
.cancel = pvscsi_request_cancelled, .cancel = pvscsi_request_cancelled,
.hotplug = pvscsi_hotplug,
.hot_unplug = pvscsi_hot_unplug,
}; };
static int static int
@ -1092,6 +1093,8 @@ pvscsi_init(PCIDevice *pci_dev)
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev), scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
&pvscsi_scsi_info, NULL); &pvscsi_scsi_info, NULL);
/* override default SCSI bus hotplug-handler, with pvscsi's one */
qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(s), &error_abort);
pvscsi_reset_state(s); pvscsi_reset_state(s);
return 0; return 0;
@ -1187,6 +1190,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->init = pvscsi_init; k->init = pvscsi_init;
k->exit = pvscsi_uninit; k->exit = pvscsi_uninit;
@ -1199,6 +1203,8 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
dc->props = pvscsi_properties; dc->props = pvscsi_properties;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
k->config_write = pvscsi_write_config; k->config_write = pvscsi_write_config;
hc->unplug = pvscsi_hot_unplug;
hc->plug = pvscsi_hotplug;
} }
static const TypeInfo pvscsi_info = { static const TypeInfo pvscsi_info = {
@ -1206,6 +1212,10 @@ static const TypeInfo pvscsi_info = {
.parent = TYPE_PCI_DEVICE, .parent = TYPE_PCI_DEVICE,
.instance_size = sizeof(PVSCSIState), .instance_size = sizeof(PVSCSIState),
.class_init = pvscsi_class_init, .class_init = pvscsi_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
static void static void

View File

@ -24,10 +24,12 @@ static Property usb_props[] = {
static void usb_bus_class_init(ObjectClass *klass, void *data) static void usb_bus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *k = BUS_CLASS(klass); BusClass *k = BUS_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
k->print_dev = usb_bus_dev_print; k->print_dev = usb_bus_dev_print;
k->get_dev_path = usb_get_dev_path; k->get_dev_path = usb_get_dev_path;
k->get_fw_dev_path = usb_get_fw_dev_path; k->get_fw_dev_path = usb_get_fw_dev_path;
hc->unplug = qdev_simple_device_unplug_cb;
} }
static const TypeInfo usb_bus_info = { static const TypeInfo usb_bus_info = {
@ -35,6 +37,10 @@ static const TypeInfo usb_bus_info = {
.parent = TYPE_BUS, .parent = TYPE_BUS,
.instance_size = sizeof(USBBus), .instance_size = sizeof(USBBus),
.class_init = usb_bus_class_init, .class_init = usb_bus_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
static int next_usb_bus = 0; static int next_usb_bus = 0;
@ -79,9 +85,9 @@ void usb_bus_new(USBBus *bus, size_t bus_size,
USBBusOps *ops, DeviceState *host) USBBusOps *ops, DeviceState *host)
{ {
qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL); qbus_create_inplace(bus, bus_size, TYPE_USB_BUS, host, NULL);
qbus_set_bus_hotplug_handler(BUS(bus), &error_abort);
bus->ops = ops; bus->ops = ops;
bus->busnr = next_usb_bus++; bus->busnr = next_usb_bus++;
bus->qbus.allow_hotplug = 1; /* Yes, we can */
QTAILQ_INIT(&bus->free); QTAILQ_INIT(&bus->free);
QTAILQ_INIT(&bus->used); QTAILQ_INIT(&bus->used);
QTAILQ_INSERT_TAIL(&busses, bus, next); QTAILQ_INSERT_TAIL(&busses, bus, next);
@ -701,7 +707,6 @@ static void usb_device_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *k = DEVICE_CLASS(klass); DeviceClass *k = DEVICE_CLASS(klass);
k->bus_type = TYPE_USB_BUS; k->bus_type = TYPE_USB_BUS;
k->unplug = qdev_simple_unplug_cb;
k->realize = usb_qdev_realize; k->realize = usb_qdev_realize;
k->unrealize = usb_qdev_unrealize; k->unrealize = usb_qdev_unrealize;
k->props = usb_props; k->props = usb_props;

View File

@ -1312,8 +1312,8 @@ static void ccid_realize(USBDevice *dev, Error **errp)
usb_desc_init(dev); usb_desc_init(dev);
qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev), qbus_create_inplace(&s->bus, sizeof(s->bus), TYPE_CCID_BUS, DEVICE(dev),
NULL); NULL);
qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(dev), &error_abort);
s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP); s->intr = usb_ep_get(dev, USB_TOKEN_IN, CCID_INT_IN_EP);
s->bus.qbus.allow_hotplug = 1;
s->card = NULL; s->card = NULL;
s->migration_state = MIGRATION_NONE; s->migration_state = MIGRATION_NONE;
s->migration_target_ip = 0; s->migration_target_ip = 0;
@ -1439,6 +1439,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
USBDeviceClass *uc = USB_DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
uc->realize = ccid_realize; uc->realize = ccid_realize;
uc->product_desc = "QEMU USB CCID"; uc->product_desc = "QEMU USB CCID";
@ -1451,6 +1452,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data)
dc->vmsd = &ccid_vmstate; dc->vmsd = &ccid_vmstate;
dc->props = ccid_properties; dc->props = ccid_properties;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories); set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
hc->unplug = qdev_simple_device_unplug_cb;
} }
static const TypeInfo ccid_info = { static const TypeInfo ccid_info = {
@ -1458,6 +1460,10 @@ static const TypeInfo ccid_info = {
.parent = TYPE_USB_DEVICE, .parent = TYPE_USB_DEVICE,
.instance_size = sizeof(USBCCIDState), .instance_size = sizeof(USBCCIDState),
.class_init = ccid_class_initfn, .class_init = ccid_class_initfn,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ }
}
}; };
static void ccid_card_class_init(ObjectClass *klass, void *data) static void ccid_card_class_init(ObjectClass *klass, void *data)

View File

@ -632,7 +632,6 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
error_propagate(errp, err); error_propagate(errp, err);
return; return;
} }
s->bus.qbus.allow_hotplug = 0;
usb_msd_handle_reset(dev); usb_msd_handle_reset(dev);
if (bdrv_key_required(bs)) { if (bdrv_key_required(bs)) {
@ -653,7 +652,6 @@ static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
usb_desc_init(dev); usb_desc_init(dev);
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev), scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&usb_msd_scsi_info_bot, NULL); &usb_msd_scsi_info_bot, NULL);
s->bus.qbus.allow_hotplug = 0;
usb_msd_handle_reset(dev); usb_msd_handle_reset(dev);
} }
@ -770,9 +768,11 @@ static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data)
static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data)
{ {
USBDeviceClass *uc = USB_DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
uc->realize = usb_msd_realize_bot; uc->realize = usb_msd_realize_bot;
usb_msd_class_initfn_common(klass); usb_msd_class_initfn_common(klass);
dc->hotpluggable = false;
} }
static const TypeInfo msd_info = { static const TypeInfo msd_info = {

View File

@ -89,9 +89,6 @@ typedef struct {
VirtioBusState bus; VirtioBusState bus;
} VirtIOMMIOProxy; } VirtIOMMIOProxy;
static void virtio_mmio_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOMMIOProxy *dev);
static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
{ {
VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque; VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque;
@ -362,7 +359,8 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d); VirtIOMMIOProxy *proxy = VIRTIO_MMIO(d);
SysBusDevice *sbd = SYS_BUS_DEVICE(d); SysBusDevice *sbd = SYS_BUS_DEVICE(d);
virtio_mmio_bus_new(&proxy->bus, sizeof(proxy->bus), proxy); qbus_create_inplace(&proxy->bus, sizeof(proxy->bus), TYPE_VIRTIO_MMIO_BUS,
d, NULL);
sysbus_init_irq(sbd, &proxy->irq); sysbus_init_irq(sbd, &proxy->irq);
memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy, memory_region_init_io(&proxy->iomem, OBJECT(d), &virtio_mem_ops, proxy,
TYPE_VIRTIO_MMIO, 0x200); TYPE_VIRTIO_MMIO, 0x200);
@ -393,17 +391,6 @@ static const TypeInfo virtio_mmio_info = {
/* virtio-mmio-bus. */ /* virtio-mmio-bus. */
static void virtio_mmio_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOMMIOProxy *dev)
{
DeviceState *qdev = DEVICE(dev);
BusState *qbus;
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_MMIO_BUS, qdev, NULL);
qbus = BUS(bus);
qbus->allow_hotplug = 0;
}
static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data) static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data)
{ {
BusClass *bus_class = BUS_CLASS(klass); BusClass *bus_class = BUS_CLASS(klass);

View File

@ -1542,13 +1542,10 @@ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
VirtIOPCIProxy *dev) VirtIOPCIProxy *dev)
{ {
DeviceState *qdev = DEVICE(dev); DeviceState *qdev = DEVICE(dev);
BusState *qbus;
char virtio_bus_name[] = "virtio-bus"; char virtio_bus_name[] = "virtio-bus";
qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev, qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev,
virtio_bus_name); virtio_bus_name);
qbus = BUS(bus);
qbus->allow_hotplug = 1;
} }
static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)

View File

@ -47,7 +47,12 @@ typedef void (*hotplug_fn)(HotplugHandler *plug_handler,
* *
* @parent: Opaque parent interface. * @parent: Opaque parent interface.
* @plug: plug callback. * @plug: plug callback.
* @unplug_request: unplug request callback.
* Used as a means to initiate device unplug for devices that
* require asynchronous unplug handling.
* @unplug: unplug callback. * @unplug: unplug callback.
* Used for device removal with devices that implement
* asynchronous and synchronous (suprise) removal.
*/ */
typedef struct HotplugHandlerClass { typedef struct HotplugHandlerClass {
/* <private> */ /* <private> */
@ -55,6 +60,7 @@ typedef struct HotplugHandlerClass {
/* <public> */ /* <public> */
hotplug_fn plug; hotplug_fn plug;
hotplug_fn unplug_request;
hotplug_fn unplug; hotplug_fn unplug;
} HotplugHandlerClass; } HotplugHandlerClass;
@ -67,10 +73,18 @@ void hotplug_handler_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, DeviceState *plugged_dev,
Error **errp); Error **errp);
/**
* hotplug_handler_unplug_request:
*
* Calls #HotplugHandlerClass.unplug_request callback of @plug_handler.
*/
void hotplug_handler_unplug_request(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp);
/** /**
* hotplug_handler_unplug: * hotplug_handler_unplug:
* *
* Call #HotplugHandlerClass.unplug callback of @plug_handler. * Calls #HotplugHandlerClass.unplug callback of @plug_handler.
*/ */
void hotplug_handler_unplug(HotplugHandler *plug_handler, void hotplug_handler_unplug(HotplugHandler *plug_handler,
DeviceState *plugged_dev, DeviceState *plugged_dev,

View File

@ -128,6 +128,6 @@ extern const VMStateDescription vmstate_pcie_device;
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp); Error **errp);
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void pcie_cap_slot_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
Error **errp); DeviceState *dev, Error **errp);
#endif /* QEMU_PCIE_H */ #endif /* QEMU_PCIE_H */

View File

@ -46,8 +46,8 @@ void shpc_cap_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int len);
void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp); Error **errp);
void shpc_device_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, void shpc_device_hot_unplug_request_cb(HotplugHandler *hotplug_dev,
Error **errp); DeviceState *dev, Error **errp);
extern VMStateInfo shpc_vmstate_info; extern VMStateInfo shpc_vmstate_info;
#define SHPC_VMSTATE(_field, _type) \ #define SHPC_VMSTATE(_field, _type) \

View File

@ -126,7 +126,6 @@ typedef struct DeviceClass {
/* Private to qdev / bus. */ /* Private to qdev / bus. */
qdev_initfn init; /* TODO remove, once users are converted to realize */ qdev_initfn init; /* TODO remove, once users are converted to realize */
qdev_event unplug;
qdev_event exit; /* TODO remove, once users are converted to unrealize */ qdev_event exit; /* TODO remove, once users are converted to unrealize */
const char *bus_type; const char *bus_type;
} DeviceClass; } DeviceClass;
@ -210,7 +209,6 @@ struct BusState {
Object obj; Object obj;
DeviceState *parent; DeviceState *parent;
const char *name; const char *name;
int allow_hotplug;
HotplugHandler *hotplug_handler; HotplugHandler *hotplug_handler;
int max_index; int max_index;
bool realized; bool realized;
@ -232,7 +230,7 @@ struct Property {
struct PropertyInfo { struct PropertyInfo {
const char *name; const char *name;
const char *legacy_name; const char *description;
const char **enum_table; const char **enum_table;
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len); int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
ObjectPropertyAccessor *get; ObjectPropertyAccessor *get;
@ -264,7 +262,8 @@ void qdev_init_nofail(DeviceState *dev);
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version); int required_for_version);
void qdev_unplug(DeviceState *dev, Error **errp); void qdev_unplug(DeviceState *dev, Error **errp);
int qdev_simple_unplug_cb(DeviceState *dev); void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
void qdev_machine_creation_done(void); void qdev_machine_creation_done(void);
bool qdev_machine_modified(void); bool qdev_machine_modified(void);
@ -361,11 +360,13 @@ extern int qdev_hotplug;
char *qdev_get_dev_path(DeviceState *dev); char *qdev_get_dev_path(DeviceState *dev);
static inline void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler,
Error **errp) Error **errp);
void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp);
static inline bool qbus_is_hotpluggable(BusState *bus)
{ {
object_property_set_link(OBJECT(bus), OBJECT(handler), return bus->hotplug_handler;
QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
bus->allow_hotplug = 1;
} }
#endif #endif

View File

@ -146,8 +146,6 @@ struct SCSIBusInfo {
void (*transfer_data)(SCSIRequest *req, uint32_t arg); void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid); void (*complete)(SCSIRequest *req, uint32_t arg, size_t resid);
void (*cancel)(SCSIRequest *req); void (*cancel)(SCSIRequest *req);
void (*hotplug)(SCSIBus *bus, SCSIDevice *dev);
void (*hot_unplug)(SCSIBus *bus, SCSIDevice *dev);
void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense); void (*change)(SCSIBus *bus, SCSIDevice *dev, SCSISense sense);
QEMUSGList *(*get_sg_list)(SCSIRequest *req); QEMUSGList *(*get_sg_list)(SCSIRequest *req);

View File

@ -338,6 +338,7 @@ typedef struct ObjectProperty
{ {
gchar *name; gchar *name;
gchar *type; gchar *type;
gchar *description;
ObjectPropertyAccessor *get; ObjectPropertyAccessor *get;
ObjectPropertyAccessor *set; ObjectPropertyAccessor *set;
ObjectPropertyResolve *resolve; ObjectPropertyResolve *resolve;
@ -1274,6 +1275,19 @@ void object_property_add_alias(Object *obj, const char *name,
Object *target_obj, const char *target_name, Object *target_obj, const char *target_name,
Error **errp); Error **errp);
/**
* object_property_set_description:
* @obj: the object owning the property
* @name: the name of the property
* @description: the description of the property on the object
* @errp: if an error occurs, a pointer to an area to store the error
*
* Set an object property's description.
*
*/
void object_property_set_description(Object *obj, const char *name,
const char *description, Error **errp);
/** /**
* object_child_foreach: * object_child_foreach:
* @obj: the object whose children will be navigated * @obj: the object whose children will be navigated

View File

@ -1615,11 +1615,13 @@
# #
# @name: the name of the property # @name: the name of the property
# @type: the typename of the property # @type: the typename of the property
# @description: #optional if specified, the description of the property.
# (since 2.2)
# #
# Since: 1.2 # Since: 1.2
## ##
{ 'type': 'DevicePropertyInfo', { 'type': 'DevicePropertyInfo',
'data': { 'name': 'str', 'type': 'str' } } 'data': { 'name': 'str', 'type': 'str', '*description': 'str' } }
## ##
# @device-list-properties: # @device-list-properties:

View File

@ -213,9 +213,14 @@ int qdev_device_help(QemuOpts *opts)
} }
for (prop = prop_list; prop; prop = prop->next) { for (prop = prop_list; prop; prop = prop->next) {
error_printf("%s.%s=%s\n", driver, error_printf("%s.%s=%s", driver,
prop->value->name, prop->value->name,
prop->value->type); prop->value->type);
if (prop->value->has_description) {
error_printf(" (%s)\n", prop->value->description);
} else {
error_printf("\n");
}
} }
qapi_free_DevicePropertyInfoList(prop_list); qapi_free_DevicePropertyInfoList(prop_list);
@ -487,7 +492,8 @@ DeviceState *qdev_device_add(QemuOpts *opts)
} }
dc = DEVICE_CLASS(oc); dc = DEVICE_CLASS(oc);
if (dc->cannot_instantiate_with_device_add_yet) { if (dc->cannot_instantiate_with_device_add_yet ||
(qdev_hotplug && !dc->hotpluggable)) {
qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver",
"pluggable device type"); "pluggable device type");
return NULL; return NULL;
@ -515,7 +521,7 @@ DeviceState *qdev_device_add(QemuOpts *opts)
return NULL; return NULL;
} }
} }
if (qdev_hotplug && bus && !bus->allow_hotplug) { if (qdev_hotplug && bus && !qbus_is_hotpluggable(bus)) {
qerror_report(QERR_BUS_NO_HOTPLUG, bus->name); qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
return NULL; return NULL;
} }
@ -685,15 +691,20 @@ int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
void qmp_device_del(const char *id, Error **errp) void qmp_device_del(const char *id, Error **errp)
{ {
DeviceState *dev; Object *obj;
char *root_path = object_get_canonical_path(qdev_get_peripheral());
char *path = g_strdup_printf("%s/%s", root_path, id);
dev = qdev_find_recursive(sysbus_get_default(), id); g_free(root_path);
if (!dev) { obj = object_resolve_path_type(path, TYPE_DEVICE, NULL);
g_free(path);
if (!obj) {
error_set(errp, QERR_DEVICE_NOT_FOUND, id); error_set(errp, QERR_DEVICE_NOT_FOUND, id);
return; return;
} }
qdev_unplug(dev, errp); qdev_unplug(DEVICE(obj), errp);
} }
void qdev_machine_init(void) void qdev_machine_init(void)

13
qmp.c
View File

@ -442,7 +442,8 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
*/ */
static DevicePropertyInfo *make_device_property_info(ObjectClass *klass, static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
const char *name, const char *name,
const char *default_type) const char *default_type,
const char *description)
{ {
DevicePropertyInfo *info; DevicePropertyInfo *info;
Property *prop; Property *prop;
@ -465,7 +466,9 @@ static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
info = g_malloc0(sizeof(*info)); info = g_malloc0(sizeof(*info));
info->name = g_strdup(prop->name); info->name = g_strdup(prop->name);
info->type = g_strdup(prop->info->legacy_name ?: prop->info->name); info->type = g_strdup(prop->info->name);
info->has_description = !!prop->info->description;
info->description = g_strdup(prop->info->description);
return info; return info;
} }
klass = object_class_get_parent(klass); klass = object_class_get_parent(klass);
@ -475,6 +478,9 @@ static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
info = g_malloc0(sizeof(*info)); info = g_malloc0(sizeof(*info));
info->name = g_strdup(name); info->name = g_strdup(name);
info->type = g_strdup(default_type); info->type = g_strdup(default_type);
info->has_description = !!description;
info->description = g_strdup(description);
return info; return info;
} }
@ -521,7 +527,8 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
continue; continue;
} }
info = make_device_property_info(klass, prop->name, prop->type); info = make_device_property_info(klass, prop->name, prop->type,
prop->description);
if (!info) { if (!info) {
continue; continue;
} }

View File

@ -369,6 +369,7 @@ static void object_property_del_all(Object *obj)
g_free(prop->name); g_free(prop->name);
g_free(prop->type); g_free(prop->type);
g_free(prop->description);
g_free(prop); g_free(prop);
} }
} }
@ -803,6 +804,7 @@ void object_property_del(Object *obj, const char *name, Error **errp)
g_free(prop->name); g_free(prop->name);
g_free(prop->type); g_free(prop->type);
g_free(prop->description);
g_free(prop); g_free(prop);
} }
@ -1010,11 +1012,19 @@ char *object_property_print(Object *obj, const char *name, bool human,
Error **errp) Error **errp)
{ {
StringOutputVisitor *mo; StringOutputVisitor *mo;
char *string; char *string = NULL;
Error *local_err = NULL;
mo = string_output_visitor_new(human); mo = string_output_visitor_new(human);
object_property_get(obj, string_output_get_visitor(mo), name, errp); object_property_get(obj, string_output_get_visitor(mo), name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
string = string_output_get_string(mo); string = string_output_get_string(mo);
out:
string_output_visitor_cleanup(mo); string_output_visitor_cleanup(mo);
return string; return string;
} }
@ -1634,6 +1644,7 @@ void object_property_add_alias(Object *obj, const char *name,
ObjectProperty *op; ObjectProperty *op;
ObjectProperty *target_prop; ObjectProperty *target_prop;
gchar *prop_type; gchar *prop_type;
Error *local_err = NULL;
target_prop = object_property_find(target_obj, target_name, errp); target_prop = object_property_find(target_obj, target_name, errp);
if (!target_prop) { if (!target_prop) {
@ -1655,12 +1666,36 @@ void object_property_add_alias(Object *obj, const char *name,
property_get_alias, property_get_alias,
property_set_alias, property_set_alias,
property_release_alias, property_release_alias,
prop, errp); prop, &local_err);
if (local_err) {
error_propagate(errp, local_err);
g_free(prop);
goto out;
}
op->resolve = property_resolve_alias; op->resolve = property_resolve_alias;
object_property_set_description(obj, name,
target_prop->description,
&error_abort);
out:
g_free(prop_type); g_free(prop_type);
} }
void object_property_set_description(Object *obj, const char *name,
const char *description, Error **errp)
{
ObjectProperty *op;
op = object_property_find(obj, name, errp);
if (!op) {
return;
}
g_free(op->description);
op->description = g_strdup(description);
}
static void object_instance_init(Object *obj) static void object_instance_init(Object *obj)
{ {
object_property_add_str(obj, "type", qdev_get_type, NULL, NULL); object_property_add_str(obj, "type", qdev_get_type, NULL, NULL);

View File

@ -8044,7 +8044,7 @@ static void powerpc_set_compat(Object *obj, Visitor *v,
static PropertyInfo powerpc_compat_propinfo = { static PropertyInfo powerpc_compat_propinfo = {
.name = "str", .name = "str",
.legacy_name = "powerpc-server-compat", .description = "compatibility mode, power6/power7/power8",
.get = powerpc_get_compat, .get = powerpc_get_compat,
.set = powerpc_set_compat, .set = powerpc_set_compat,
}; };

View File

@ -301,6 +301,7 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
libqos-pc-obj-y += tests/libqos/malloc-pc.o libqos-pc-obj-y += tests/libqos/malloc-pc.o
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o
libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
tests/rtc-test$(EXESUF): tests/rtc-test.o tests/rtc-test$(EXESUF): tests/rtc-test.o
tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o
@ -324,8 +325,8 @@ tests/ne2000-test$(EXESUF): tests/ne2000-test.o
tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o
tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y) tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o $(libqos-virtio-obj-y)
tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o $(libqos-pc-obj-y)
tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o $(libqos-pc-obj-y)
tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o
tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o tests/virtio-9p-test$(EXESUF): tests/virtio-9p-test.o
tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o
@ -343,10 +344,10 @@ tests/ac97-test$(EXESUF): tests/ac97-test.o
tests/es1370-test$(EXESUF): tests/es1370-test.o tests/es1370-test$(EXESUF): tests/es1370-test.o
tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o tests/usb-hcd-ohci-test$(EXESUF): tests/usb-hcd-ohci-test.o $(libqos-usb-obj-y)
tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o tests/usb-hcd-uhci-test$(EXESUF): tests/usb-hcd-uhci-test.o $(libqos-usb-obj-y)
tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y) tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-usb-obj-y)
tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o tests/usb-hcd-xhci-test$(EXESUF): tests/usb-hcd-xhci-test.o $(libqos-usb-obj-y)
tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y) tests/vhost-user-test$(EXESUF): tests/vhost-user-test.o qemu-char.o qemu-timer.o $(qtest-obj-y)
tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a

View File

@ -20,6 +20,9 @@
#include <glib.h> #include <glib.h>
#define ACPI_PCIHP_ADDR 0xae00
#define PCI_EJ_BASE 0x0008
typedef struct QPCIBusPC typedef struct QPCIBusPC
{ {
QPCIBus bus; QPCIBus bus;
@ -247,3 +250,49 @@ void qpci_free_pc(QPCIBus *bus)
g_free(s); g_free(s);
} }
void qpci_plug_device_test(const char *driver, const char *id,
uint8_t slot, const char *opts)
{
QDict *response;
char *cmd;
cmd = g_strdup_printf("{'execute': 'device_add',"
" 'arguments': {"
" 'driver': '%s',"
" 'addr': '%d',"
" %s%s"
" 'id': '%s'"
"}}", driver, slot,
opts ? opts : "", opts ? "," : "",
id);
response = qmp(cmd);
g_free(cmd);
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
}
void qpci_unplug_acpi_device_test(const char *id, uint8_t slot)
{
QDict *response;
char *cmd;
cmd = g_strdup_printf("{'execute': 'device_del',"
" 'arguments': {"
" 'id': '%s'"
"}}", id);
response = qmp(cmd);
g_free(cmd);
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
outb(ACPI_PCIHP_ADDR + PCI_EJ_BASE, 1 << slot);
response = qmp("");
g_assert(response);
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
QDECREF(response);
}

View File

@ -87,4 +87,7 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value);
void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr); void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr);
void qpci_iounmap(QPCIDevice *dev, void *data); void qpci_iounmap(QPCIDevice *dev, void *data);
void qpci_plug_device_test(const char *driver, const char *id,
uint8_t slot, const char *opts);
void qpci_unplug_acpi_device_test(const char *id, uint8_t slot);
#endif #endif

71
tests/libqos/usb.c Normal file
View File

@ -0,0 +1,71 @@
/*
* common code shared by usb tests
*
* Copyright (c) 2014 Red Hat, Inc
*
* Authors:
* Gerd Hoffmann <kraxel@redhat.com>
* John Snow <jsnow@redhat.com>
* Igor Mammedov <imammedo@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include <glib.h>
#include <string.h>
#include "libqtest.h"
#include "qemu/osdep.h"
#include "hw/usb/uhci-regs.h"
#include "libqos/usb.h"
void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, uint32_t devfn, int bar)
{
hc->dev = qpci_device_find(pcibus, devfn);
g_assert(hc->dev != NULL);
qpci_device_enable(hc->dev);
hc->base = qpci_iomap(hc->dev, bar, NULL);
g_assert(hc->base != NULL);
}
void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
{
void *addr = hc->base + 0x10 + 2 * port;
uint16_t value = qpci_io_readw(hc->dev, addr);
uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
g_assert((value & mask) == (expect & mask));
}
void usb_test_hotplug(const char *hcd_id, const int port,
void (*port_check)(void))
{
QDict *response;
char *cmd;
cmd = g_strdup_printf("{'execute': 'device_add',"
" 'arguments': {"
" 'driver': 'usb-tablet',"
" 'port': '%d',"
" 'bus': '%s.0',"
" 'id': 'usbdev%d'"
"}}", port, hcd_id, port);
response = qmp(cmd);
g_free(cmd);
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
if (port_check) {
port_check();
}
cmd = g_strdup_printf("{'execute': 'device_del',"
" 'arguments': {"
" 'id': 'usbdev%d'"
"}}", port);
response = qmp(cmd);
g_free(cmd);
g_assert(response);
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
}

17
tests/libqos/usb.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef LIBQOS_USB_H
#define LIBQOS_USB_H
#include "libqos/pci-pc.h"
struct qhc {
QPCIDevice *dev;
void *base;
};
void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc,
uint32_t devfn, int bar);
void uhci_port_test(struct qhc *hc, int port, uint16_t expect);
void usb_test_hotplug(const char *bus_name, const int port,
void (*port_check)(void));
#endif

View File

@ -15,11 +15,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/usb/uhci-regs.h" #include "hw/usb/uhci-regs.h"
#include "hw/usb/ehci-regs.h" #include "hw/usb/ehci-regs.h"
#include "libqos/usb.h"
struct qhc {
QPCIDevice *dev;
void *base;
};
static QPCIBus *pcibus; static QPCIBus *pcibus;
static struct qhc uhci1; static struct qhc uhci1;
@ -29,15 +25,6 @@ static struct qhc ehci1;
/* helpers */ /* helpers */
static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar)
{
hc->dev = qpci_device_find(pcibus, devfn);
g_assert(hc->dev != NULL);
qpci_device_enable(hc->dev);
hc->base = qpci_iomap(hc->dev, bar, NULL);
g_assert(hc->base != NULL);
}
#if 0 #if 0
static void uhci_port_update(struct qhc *hc, int port, static void uhci_port_update(struct qhc *hc, int port,
uint16_t set, uint16_t clear) uint16_t set, uint16_t clear)
@ -52,19 +39,6 @@ static void uhci_port_update(struct qhc *hc, int port,
} }
#endif #endif
static void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
{
void *addr = hc->base + 0x10 + 2 * port;
uint16_t value = qpci_io_readw(hc->dev, addr);
uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
#if 0
fprintf(stderr, "%s: %d, have 0x%04x, want 0x%04x\n",
__func__, port, value & mask, expect & mask);
#endif
g_assert((value & mask) == (expect & mask));
}
static void ehci_port_test(struct qhc *hc, int port, uint32_t expect) static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
{ {
void *addr = hc->base + 0x64 + 4 * port; void *addr = hc->base + 0x64 + 4 * port;
@ -88,10 +62,10 @@ static void pci_init(void)
pcibus = qpci_init_pc(); pcibus = qpci_init_pc();
g_assert(pcibus != NULL); g_assert(pcibus != NULL);
pci_init_one(&uhci1, QPCI_DEVFN(0x1d, 0), 4); qusb_pci_init_one(pcibus, &uhci1, QPCI_DEVFN(0x1d, 0), 4);
pci_init_one(&uhci2, QPCI_DEVFN(0x1d, 1), 4); qusb_pci_init_one(pcibus, &uhci2, QPCI_DEVFN(0x1d, 1), 4);
pci_init_one(&uhci3, QPCI_DEVFN(0x1d, 2), 4); qusb_pci_init_one(pcibus, &uhci3, QPCI_DEVFN(0x1d, 2), 4);
pci_init_one(&ehci1, QPCI_DEVFN(0x1d, 7), 0); qusb_pci_init_one(pcibus, &ehci1, QPCI_DEVFN(0x1d, 7), 0);
} }
static void pci_uhci_port_1(void) static void pci_uhci_port_1(void)
@ -154,6 +128,19 @@ static void pci_ehci_port_2(void)
} }
} }
static void pci_ehci_port_3_hotplug(void)
{
/* check for presence of hotplugged usb-tablet */
g_assert(pcibus != NULL);
ehci_port_test(&ehci1, 2, PORTSC_PPOWER | PORTSC_CONNECT);
}
static void pci_ehci_port_hotplug(void)
{
usb_test_hotplug("ich9-ehci-1", 3, pci_ehci_port_3_hotplug);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
@ -165,6 +152,7 @@ int main(int argc, char **argv)
qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config); qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2); qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2); qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
qtest_add_func("/ehci/pci/ehci-port-3-hotplug", pci_ehci_port_hotplug);
qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7," qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
"multifunction=on,id=ich9-ehci-1 " "multifunction=on,id=ich9-ehci-1 "

View File

@ -11,15 +11,18 @@
#include <string.h> #include <string.h>
#include "libqtest.h" #include "libqtest.h"
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "libqos/usb.h"
static void test_ohci_init(void) static void test_ohci_init(void)
{ {
qtest_start("-device pci-ohci,id=ohci");
qtest_end();
} }
static void test_ohci_hotplug(void)
{
usb_test_hotplug("ohci", 1, NULL);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -28,8 +31,11 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/ohci/pci/init", test_ohci_init); qtest_add_func("/ohci/pci/init", test_ohci_init);
qtest_add_func("/ohci/pci/hotplug", test_ohci_hotplug);
qtest_start("-device pci-ohci,id=ohci");
ret = g_test_run(); ret = g_test_run();
qtest_end();
return ret; return ret;
} }

View File

@ -11,15 +11,69 @@
#include <string.h> #include <string.h>
#include "libqtest.h" #include "libqtest.h"
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "libqos/usb.h"
#include "hw/usb/uhci-regs.h"
static void test_uhci_init(void) static void test_uhci_init(void)
{ {
qtest_start("-device piix3-usb-uhci,id=uhci");
qtest_end();
} }
static void test_port(int port)
{
QPCIBus *pcibus;
struct qhc uhci;
g_assert(port > 0);
pcibus = qpci_init_pc();
g_assert(pcibus != NULL);
qusb_pci_init_one(pcibus, &uhci, QPCI_DEVFN(0x1d, 0), 4);
uhci_port_test(&uhci, port - 1, UHCI_PORT_CCS);
}
static void test_port_1(void)
{
test_port(1);
}
static void test_port_2(void)
{
test_port(2);
}
static void test_uhci_hotplug(void)
{
usb_test_hotplug("uhci", 2, test_port_2);
}
static void test_usb_storage_hotplug(void)
{
QDict *response;
response = qmp("{'execute': 'device_add',"
" 'arguments': {"
" 'driver': 'usb-storage',"
" 'drive': 'drive0',"
" 'id': 'usbdev0'"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("{'execute': 'device_del',"
" 'arguments': {"
" 'id': 'usbdev0'"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("");
g_assert(response);
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
QDECREF(response);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -28,8 +82,15 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/uhci/pci/init", test_uhci_init); qtest_add_func("/uhci/pci/init", test_uhci_init);
qtest_add_func("/uhci/pci/port1", test_port_1);
qtest_add_func("/uhci/pci/hotplug", test_uhci_hotplug);
qtest_add_func("/uhci/pci/hotplug/usb-storage", test_usb_storage_hotplug);
qtest_start("-device piix3-usb-uhci,id=uhci,addr=1d.0"
" -drive id=drive0,if=none,file=/dev/null"
" -device usb-tablet,bus=uhci.0,port=1");
ret = g_test_run(); ret = g_test_run();
qtest_end();
return ret; return ret;
} }

View File

@ -11,15 +11,74 @@
#include <string.h> #include <string.h>
#include "libqtest.h" #include "libqtest.h"
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "libqos/usb.h"
static void test_xhci_init(void) static void test_xhci_init(void)
{ {
qtest_start("-device nec-usb-xhci,id=xhci");
qtest_end();
} }
static void test_xhci_hotplug(void)
{
usb_test_hotplug("xhci", 1, NULL);
}
static void test_usb_uas_hotplug(void)
{
QDict *response;
response = qmp("{'execute': 'device_add',"
" 'arguments': {"
" 'driver': 'usb-uas',"
" 'id': 'uas'"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("{'execute': 'device_add',"
" 'arguments': {"
" 'driver': 'scsi-hd',"
" 'drive': 'drive0',"
" 'id': 'scsi-hd'"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
/* TODO:
UAS HBA driver in libqos, to check that
added disk is visible after BUS rescan
*/
response = qmp("{'execute': 'device_del',"
" 'arguments': {"
" 'id': 'scsi-hd'"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("");
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
QDECREF(response);
response = qmp("{'execute': 'device_del',"
" 'arguments': {"
" 'id': 'uas'"
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("");
g_assert(response);
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
QDECREF(response);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -28,8 +87,13 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/xhci/pci/init", test_xhci_init); qtest_add_func("/xhci/pci/init", test_xhci_init);
qtest_add_func("/xhci/pci/hotplug", test_xhci_hotplug);
qtest_add_func("/xhci/pci/hotplug/usb-uas", test_usb_uas_hotplug);
qtest_start("-device nec-usb-xhci,id=xhci"
" -drive id=drive0,if=none,file=/dev/null");
ret = g_test_run(); ret = g_test_run();
qtest_end();
return ret; return ret;
} }

View File

@ -45,6 +45,8 @@
#define PCI_SLOT 0x04 #define PCI_SLOT 0x04
#define PCI_FN 0x00 #define PCI_FN 0x00
#define PCI_SLOT_HP 0x06
typedef struct QVirtioBlkReq { typedef struct QVirtioBlkReq {
uint32_t type; uint32_t type;
uint32_t ioprio; uint32_t ioprio;
@ -55,7 +57,7 @@ typedef struct QVirtioBlkReq {
static QPCIBus *test_start(void) static QPCIBus *test_start(void)
{ {
char cmdline[100]; char *cmdline;
char tmp_path[] = "/tmp/qtest.XXXXXX"; char tmp_path[] = "/tmp/qtest.XXXXXX";
int fd, ret; int fd, ret;
@ -66,11 +68,14 @@ static QPCIBus *test_start(void)
g_assert_cmpint(ret, ==, 0); g_assert_cmpint(ret, ==, 0);
close(fd); close(fd);
snprintf(cmdline, 100, "-drive if=none,id=drive0,file=%s " cmdline = g_strdup_printf("-drive if=none,id=drive0,file=%s "
"-device virtio-blk-pci,drive=drive0,addr=%x.%x", "-drive if=none,id=drive1,file=/dev/null "
tmp_path, PCI_SLOT, PCI_FN); "-device virtio-blk-pci,id=drv0,drive=drive0,"
"addr=%x.%x",
tmp_path, PCI_SLOT, PCI_FN);
qtest_start(cmdline); qtest_start(cmdline);
unlink(tmp_path); unlink(tmp_path);
g_free(cmdline);
return qpci_init_pc(); return qpci_init_pc();
} }
@ -80,14 +85,14 @@ static void test_end(void)
qtest_end(); qtest_end();
} }
static QVirtioPCIDevice *virtio_blk_init(QPCIBus *bus) static QVirtioPCIDevice *virtio_blk_init(QPCIBus *bus, int slot)
{ {
QVirtioPCIDevice *dev; QVirtioPCIDevice *dev;
dev = qvirtio_pci_device_find(bus, QVIRTIO_BLK_DEVICE_ID); dev = qvirtio_pci_device_find(bus, QVIRTIO_BLK_DEVICE_ID);
g_assert(dev != NULL); g_assert(dev != NULL);
g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_BLK_DEVICE_ID); g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_BLK_DEVICE_ID);
g_assert_cmphex(dev->pdev->devfn, ==, ((PCI_SLOT << 3) | PCI_FN)); g_assert_cmphex(dev->pdev->devfn, ==, ((slot << 3) | PCI_FN));
qvirtio_pci_device_enable(dev); qvirtio_pci_device_enable(dev);
qvirtio_reset(&qvirtio_pci, &dev->vdev); qvirtio_reset(&qvirtio_pci, &dev->vdev);
@ -147,7 +152,7 @@ static void pci_basic(void)
bus = test_start(); bus = test_start();
dev = virtio_blk_init(bus); dev = virtio_blk_init(bus, PCI_SLOT);
/* MSI-X is not enabled */ /* MSI-X is not enabled */
addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX; addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
@ -293,7 +298,7 @@ static void pci_indirect(void)
bus = test_start(); bus = test_start();
dev = virtio_blk_init(bus); dev = virtio_blk_init(bus, PCI_SLOT);
/* MSI-X is not enabled */ /* MSI-X is not enabled */
addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX; addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
@ -384,7 +389,7 @@ static void pci_config(void)
bus = test_start(); bus = test_start();
dev = virtio_blk_init(bus); dev = virtio_blk_init(bus, PCI_SLOT);
/* MSI-X is not enabled */ /* MSI-X is not enabled */
addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX; addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
@ -425,7 +430,7 @@ static void pci_msix(void)
bus = test_start(); bus = test_start();
alloc = pc_alloc_init(); alloc = pc_alloc_init();
dev = virtio_blk_init(bus); dev = virtio_blk_init(bus, PCI_SLOT);
qpci_msix_enable(dev->pdev); qpci_msix_enable(dev->pdev);
qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0); qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0);
@ -534,7 +539,7 @@ static void pci_idx(void)
bus = test_start(); bus = test_start();
alloc = pc_alloc_init(); alloc = pc_alloc_init();
dev = virtio_blk_init(bus); dev = virtio_blk_init(bus, PCI_SLOT);
qpci_msix_enable(dev->pdev); qpci_msix_enable(dev->pdev);
qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0); qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0);
@ -637,6 +642,27 @@ static void pci_idx(void)
test_end(); test_end();
} }
static void hotplug(void)
{
QPCIBus *bus;
QVirtioPCIDevice *dev;
bus = test_start();
/* plug secondary disk */
qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
"'drive': 'drive1'");
dev = virtio_blk_init(bus, PCI_SLOT_HP);
g_assert(dev);
qvirtio_pci_device_disable(dev);
g_free(dev);
/* unplug secondary disk */
qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
test_end();
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
@ -648,6 +674,7 @@ int main(int argc, char **argv)
g_test_add_func("/virtio/blk/pci/config", pci_config); g_test_add_func("/virtio/blk/pci/config", pci_config);
g_test_add_func("/virtio/blk/pci/msix", pci_msix); g_test_add_func("/virtio/blk/pci/msix", pci_msix);
g_test_add_func("/virtio/blk/pci/idx", pci_idx); g_test_add_func("/virtio/blk/pci/idx", pci_idx);
g_test_add_func("/virtio/blk/pci/hotplug", hotplug);
ret = g_test_run(); ret = g_test_run();

View File

@ -11,18 +11,28 @@
#include <string.h> #include <string.h>
#include "libqtest.h" #include "libqtest.h"
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "libqos/pci.h"
#define PCI_SLOT_HP 0x06
/* Tests only initialization so far. TODO: Replace with functional tests */ /* Tests only initialization so far. TODO: Replace with functional tests */
static void pci_nop(void) static void pci_nop(void)
{ {
} }
static void hotplug(void)
{
qpci_plug_device_test("virtio-net-pci", "net1", PCI_SLOT_HP, NULL);
qpci_unplug_acpi_device_test("net1", PCI_SLOT_HP);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/virtio/net/pci/nop", pci_nop); qtest_add_func("/virtio/net/pci/nop", pci_nop);
qtest_add_func("/virtio/net/pci/hotplug", hotplug);
qtest_start("-device virtio-net-pci"); qtest_start("-device virtio-net-pci");
ret = g_test_run(); ret = g_test_run();

View File

@ -11,18 +11,28 @@
#include <string.h> #include <string.h>
#include "libqtest.h" #include "libqtest.h"
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "libqos/pci.h"
#define PCI_SLOT_HP 0x06
/* Tests only initialization so far. TODO: Replace with functional tests */ /* Tests only initialization so far. TODO: Replace with functional tests */
static void pci_nop(void) static void pci_nop(void)
{ {
} }
static void hotplug(void)
{
qpci_plug_device_test("virtio-rng-pci", "rng1", PCI_SLOT_HP, NULL);
qpci_unplug_acpi_device_test("rng1", PCI_SLOT_HP);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/virtio/rng/pci/nop", pci_nop); qtest_add_func("/virtio/rng/pci/nop", pci_nop);
qtest_add_func("/virtio/rng/pci/hotplug", hotplug);
qtest_start("-device virtio-rng-pci"); qtest_start("-device virtio-rng-pci");
ret = g_test_run(); ret = g_test_run();

View File

@ -17,14 +17,43 @@ static void pci_nop(void)
{ {
} }
static void hotplug(void)
{
QDict *response;
response = qmp("{\"execute\": \"device_add\","
" \"arguments\": {"
" \"driver\": \"scsi-hd\","
" \"id\": \"scsi-hd\","
" \"drive\": \"drv1\""
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("{\"execute\": \"device_del\","
" \"arguments\": {"
" \"id\": \"scsi-hd\""
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
QDECREF(response);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/virtio/scsi/pci/nop", pci_nop); qtest_add_func("/virtio/scsi/pci/nop", pci_nop);
qtest_add_func("/virtio/scsi/pci/hotplug", hotplug);
qtest_start("-drive id=drv0,if=none,file=/dev/null " qtest_start("-drive id=drv0,if=none,file=/dev/null "
"-drive id=drv1,if=none,file=/dev/null "
"-device virtio-scsi-pci,id=vscsi0 " "-device virtio-scsi-pci,id=vscsi0 "
"-device scsi-hd,bus=vscsi0.0,drive=drv0"); "-device scsi-hd,bus=vscsi0.0,drive=drv0");
ret = g_test_run(); ret = g_test_run();

View File

@ -17,12 +17,39 @@ static void pci_nop(void)
{ {
} }
static void hotplug(void)
{
QDict *response;
response = qmp("{\"execute\": \"device_add\","
" \"arguments\": {"
" \"driver\": \"virtserialport\","
" \"id\": \"hp-port\""
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
QDECREF(response);
response = qmp("{\"execute\": \"device_del\","
" \"arguments\": {"
" \"id\": \"hp-port\""
"}}");
g_assert(response);
g_assert(!qdict_haskey(response, "error"));
g_assert(qdict_haskey(response, "event"));
g_assert(!strcmp(qdict_get_str(response, "event"), "DEVICE_DELETED"));
QDECREF(response);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int ret; int ret;
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("/virtio/serial/pci/nop", pci_nop); qtest_add_func("/virtio/serial/pci/nop", pci_nop);
qtest_add_func("/virtio/serial/pci/hotplug", hotplug);
qtest_start("-device virtio-serial-pci"); qtest_start("-device virtio-serial-pci");
ret = g_test_run(); ret = g_test_run();