Add a compat property for older machine types. When this is used (via -M pc-0.13, for example), the new flow control mechanisms will not be used. This is done to keep migration from a machine started with older type on a pc-0.14+ qemu to an older machine working.
The property is named 'flow_control' and defaults to on. Reported-by: Alex Williamson <alex.william...@redhat.com> Signed-off-by: Amit Shah <amit.s...@redhat.com> --- hw/pc_piix.c | 16 ++++++++++ hw/virtio-pci.c | 2 + hw/virtio-serial-bus.c | 77 +++++++++++++++++++++++++++++++++++++++++------- hw/virtio-serial.h | 12 +++++++ 4 files changed, 96 insertions(+), 11 deletions(-) diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 7b74473..05b0449 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -243,6 +243,10 @@ static QEMUMachine pc_machine_v0_13 = { .driver = "PCI", .property = "command_serr_enable", .value = "off", + },{ + .driver = "virtio-serial-pci", + .property = "flow_control", + .value = stringify(0), }, { /* end of list */ } }, @@ -263,6 +267,10 @@ static QEMUMachine pc_machine_v0_12 = { .property = "vectors", .value = stringify(0), },{ + .driver = "virtio-serial-pci", + .property = "flow_control", + .value = stringify(0), + },{ .driver = "VGA", .property = "rombar", .value = stringify(0), @@ -298,6 +306,10 @@ static QEMUMachine pc_machine_v0_11 = { .property = "vectors", .value = stringify(0), },{ + .driver = "virtio-serial-pci", + .property = "flow_control", + .value = stringify(0), + },{ .driver = "ide-drive", .property = "ver", .value = "0.11", @@ -341,6 +353,10 @@ static QEMUMachine pc_machine_v0_10 = { .property = "vectors", .value = stringify(0), },{ + .driver = "virtio-serial-pci", + .property = "flow_control", + .value = stringify(0), + },{ .driver = "virtio-net-pci", .property = "vectors", .value = stringify(0), diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index 952b5d2..530ce9d 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -904,6 +904,8 @@ static PCIDeviceInfo virtio_info[] = { DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31), + DEFINE_PROP_UINT32("flow_control", VirtIOPCIProxy, + serial.flow_control, 1), DEFINE_PROP_END_OF_LIST(), }, .qdev.reset = virtio_pci_reset, diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index 1753785..f681646 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -49,6 +49,8 @@ struct VirtIOSerial { uint32_t *ports_map; struct virtio_console_config config; + + bool flow_control; }; static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id) @@ -123,12 +125,46 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) virtio_notify(vdev, vq); } +static void do_flush_queued_data_no_flow_control(VirtIOSerialPort *port, + VirtQueue *vq, + VirtIODevice *vdev) +{ + VirtQueueElement elem; + + while (!port->throttled && virtqueue_pop(vq, &elem)) { + uint8_t *buf; + size_t ret, buf_size; + + buf_size = iov_size(elem.out_sg, elem.out_num); + buf = qemu_malloc(buf_size); + ret = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, buf_size); + + /* + * have_data has been modified to return the number of bytes + * successfully consumed. We can't act upon that information + * in the no-flow-control implementation, so we'll discard it + * here. No callers currently use flow control, but they + * should take this into account for backward compatibility. + */ + port->info->have_data(port, buf, ret); + qemu_free(buf); + + virtqueue_push(vq, &elem, 0); + } + virtio_notify(vdev, vq); +} + static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, VirtIODevice *vdev) { assert(port); assert(virtio_queue_ready(vq)); + if (!virtio_serial_flow_control_enabled(port)) { + do_flush_queued_data_no_flow_control(port, vq, vdev); + return; + } + while (!port->throttled) { unsigned int i; @@ -296,6 +332,15 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle) flush_queued_data(port); } +bool virtio_serial_flow_control_enabled(VirtIOSerialPort *port) +{ + if (!port) { + return false; + } + + return port->vser->flow_control; +} + /* Guest wants to notify us of some event */ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len) { @@ -533,17 +578,19 @@ static void virtio_serial_save(QEMUFile *f, void *opaque) qemu_put_byte(f, port->guest_connected); qemu_put_byte(f, port->host_connected); - elem_popped = 0; - if (port->elem.out_num) { - elem_popped = 1; - } - qemu_put_be32s(f, &elem_popped); - if (elem_popped) { - qemu_put_be32s(f, &port->iov_idx); - qemu_put_be64s(f, &port->iov_offset); + if (virtio_serial_flow_control_enabled(port)) { + elem_popped = 0; + if (port->elem.out_num) { + elem_popped = 1; + } + qemu_put_be32s(f, &elem_popped); + if (elem_popped) { + qemu_put_be32s(f, &port->iov_idx); + qemu_put_be64s(f, &port->iov_offset); - qemu_put_buffer(f, (unsigned char *)&port->elem, - sizeof(port->elem)); + qemu_put_buffer(f, (unsigned char *)&port->elem, + sizeof(port->elem)); + } } } } @@ -816,6 +863,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf) VirtIOSerial *vser; VirtIODevice *vdev; uint32_t i, max_supported_ports; + unsigned int savevm_ver; if (!conf->max_virtserial_ports) return NULL; @@ -881,11 +929,18 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf) vser->qdev = dev; + vser->flow_control = true; + savevm_ver = 3; + if (!conf->flow_control) { + vser->flow_control = false; + savevm_ver = 2; + } + /* * Register for the savevm section with the virtio-console name * to preserve backward compat */ - register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save, + register_savevm(dev, "virtio-console", -1, savevm_ver, virtio_serial_save, virtio_serial_load, vser); return vdev; diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index de624c3..57d2dee 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -48,6 +48,13 @@ struct virtio_console_control { struct virtio_serial_conf { /* Max. number of ports we can have for a the virtio-serial device */ uint32_t max_virtserial_ports; + + /* + * Should this device behave the way it did in prior to pc-0.14 + * (ie. no flow control)? This will be necessary to allow + * migrations from a pre-0.14-machine type to older qemu code + */ + uint32_t flow_control; }; /* Some events for the internal messages (control packets) */ @@ -204,4 +211,9 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port); */ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle); +/* + * Does this machine type disable the use of flow control? + */ +bool virtio_serial_flow_control_enabled(VirtIOSerialPort *port); + #endif -- 1.7.3.5