Commit ede77d29 authored by Anthony Liguori's avatar Anthony Liguori
Browse files

Merge remote-tracking branch 'amit/for-anthony' into staging

parents ed7ec840 7edfe652
Loading
Loading
Loading
Loading
+16 −31
Original line number Diff line number Diff line
@@ -74,25 +74,26 @@ static void chr_event(void *opaque, int event)
    }
}

static int generic_port_init(VirtConsole *vcon, VirtIOSerialPort *port)
static int virtconsole_initfn(VirtIOSerialPort *port)
{
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
                                           vcon->port.dev.info);

    if (port->id == 0 && !info->is_console) {
        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
        return -1;
    }

    if (vcon->chr) {
        qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event,
                              vcon);
        vcon->port.info->have_data = flush_buf;
        vcon->port.info->guest_open = guest_open;
        vcon->port.info->guest_close = guest_close;
        info->have_data = flush_buf;
        info->guest_open = guest_open;
        info->guest_close = guest_close;
    }
    return 0;
}

/* Virtio Console Ports */
static int virtconsole_initfn(VirtIOSerialPort *port)
{
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);

    port->is_console = true;
    return generic_port_init(vcon, port);
    return 0;
}

static int virtconsole_exitfn(VirtIOSerialPort *port)
@@ -113,10 +114,10 @@ static int virtconsole_exitfn(VirtIOSerialPort *port)
static VirtIOSerialPortInfo virtconsole_info = {
    .qdev.name     = "virtconsole",
    .qdev.size     = sizeof(VirtConsole),
    .is_console    = true,
    .init          = virtconsole_initfn,
    .exit          = virtconsole_exitfn,
    .qdev.props = (Property[]) {
        DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
        DEFINE_PROP_CHR("chardev", VirtConsole, chr),
        DEFINE_PROP_STRING("name", VirtConsole, port.name),
@@ -130,26 +131,10 @@ static void virtconsole_register(void)
}
device_init(virtconsole_register)

/* Generic Virtio Serial Ports */
static int virtserialport_initfn(VirtIOSerialPort *port)
{
    VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);

    if (port->id == 0) {
        /*
         * Disallow a generic port at id 0, that's reserved for
         * console ports.
         */
        error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
        return -1;
    }
    return generic_port_init(vcon, port);
}

static VirtIOSerialPortInfo virtserialport_info = {
    .qdev.name     = "virtserialport",
    .qdev.size     = sizeof(VirtConsole),
    .init          = virtserialport_initfn,
    .init          = virtconsole_initfn,
    .exit          = virtconsole_exitfn,
    .qdev.props = (Property[]) {
        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
+46 −37
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ struct VirtIOSerial {
    /* Arrays of ivqs and ovqs: one per port */
    VirtQueue **ivqs, **ovqs;

    VirtIOSerialBus *bus;
    VirtIOSerialBus bus;

    DeviceState *qdev;

@@ -129,9 +129,13 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                                 VirtIODevice *vdev)
{
    VirtIOSerialPortInfo *info;

    assert(port);
    assert(virtio_queue_ready(vq));

    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);

    while (!port->throttled) {
        unsigned int i;

@@ -149,7 +153,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
            ssize_t ret;

            buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
            ret = port->info->have_data(port,
            ret = info->have_data(port,
                                  port->elem.out_sg[i].iov_base
                                  + port->iov_offset,
                                  buf_size);
@@ -285,6 +289,13 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
    return 0;
}

static void flush_queued_data_bh(void *opaque)
{
    VirtIOSerialPort *port = opaque;

    flush_queued_data(port);
}

void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
{
    if (!port) {
@@ -295,14 +306,14 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
    if (throttle) {
        return;
    }

    flush_queued_data(port);
    qemu_bh_schedule(port->bh);
}

/* Guest wants to notify us of some event */
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
{
    struct VirtIOSerialPort *port;
    struct VirtIOSerialPortInfo *info;
    struct virtio_console_control cpkt, *gcpkt;
    uint8_t *buffer;
    size_t buffer_len;
@@ -321,11 +332,13 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
    if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
        return;

    info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);

    switch(cpkt.event) {
    case VIRTIO_CONSOLE_DEVICE_READY:
        if (!cpkt.value) {
            error_report("virtio-serial-bus: Guest failure in adding device %s\n",
                         vser->bus->qbus.name);
                         vser->bus.qbus.name);
            break;
        }
        /*
@@ -340,7 +353,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
    case VIRTIO_CONSOLE_PORT_READY:
        if (!cpkt.value) {
            error_report("virtio-serial-bus: Guest failure in adding port %u for device %s\n",
                         port->id, vser->bus->qbus.name);
                         port->id, vser->bus.qbus.name);
            break;
        }
        /*
@@ -350,7 +363,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
         * this port is a console port so that the guest can hook it
         * up to hvc.
         */
        if (port->is_console) {
        if (info->is_console) {
            send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
        }

@@ -379,21 +392,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
         * initialised. If some app is interested in knowing about
         * this event, let it know.
         */
        if (port->info->guest_ready) {
            port->info->guest_ready(port);
        if (info->guest_ready) {
            info->guest_ready(port);
        }
        break;

    case VIRTIO_CONSOLE_PORT_OPEN:
        port->guest_connected = cpkt.value;
        if (cpkt.value && port->info->guest_open) {
        if (cpkt.value && info->guest_open) {
            /* Send the guest opened notification if an app is interested */
            port->info->guest_open(port);
            info->guest_open(port);
        }

        if (!cpkt.value && port->info->guest_close) {
        if (!cpkt.value && info->guest_close) {
            /* Send the guest closed notification if an app is interested */
            port->info->guest_close(port);
            info->guest_close(port);
        }
        break;
    }
@@ -442,11 +455,13 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
    VirtIOSerial *vser;
    VirtIOSerialPort *port;
    VirtIOSerialPortInfo *info;

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
    port = find_port_by_vq(vser, vq);
    info = port ? DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info) : NULL;

    if (!port || !port->host_connected || !port->info->have_data) {
    if (!port || !port->host_connected || !info->have_data) {
        discard_vq_data(vq, vdev);
        return;
    }
@@ -467,7 +482,7 @@ static uint32_t get_features(VirtIODevice *vdev, uint32_t features)

    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);

    if (vser->bus->max_nr_ports > 1) {
    if (vser->bus.max_nr_ports > 1) {
        features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
    }
    return features;
@@ -644,16 +659,6 @@ static struct BusInfo virtser_bus_info = {
    .print_dev = virtser_bus_dev_print,
};

static VirtIOSerialBus *virtser_bus_new(DeviceState *dev)
{
    VirtIOSerialBus *bus;

    bus = FROM_QBUS(VirtIOSerialBus, qbus_create(&virtser_bus_info, dev, NULL));
    bus->qbus.allow_hotplug = 1;

    return bus;
}

static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
@@ -726,13 +731,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
    bool plugging_port0;

    port->vser = bus->vser;
    port->bh = qemu_bh_new(flush_queued_data_bh, port);

    /*
     * Is the first console port we're seeing? If so, put it up at
     * location 0. This is done for backward compatibility (old
     * kernel, new qemu).
     */
    plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
    plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);

    if (find_port_by_id(port->vser, port->id)) {
        error_report("virtio-serial-bus: A port already exists at id %u\n",
@@ -759,7 +765,6 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
        return -1;
    }

    port->info = info;
    ret = info->init(port);
    if (ret) {
        return ret;
@@ -790,15 +795,18 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int virtser_port_qdev_exit(DeviceState *qdev)
{
    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
    VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
                                           port->dev.info);
    VirtIOSerial *vser = port->vser;

    qemu_bh_delete(port->bh);
    remove_port(port->vser, port->id);

    QTAILQ_REMOVE(&vser->ports, port, next);

    if (port->info->exit)
        port->info->exit(port);

    if (info->exit) {
        info->exit(port);
    }
    return 0;
}

@@ -835,11 +843,12 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);

    /* Spawn a new virtio-serial bus on which the ports will ride as devices */
    vser->bus = virtser_bus_new(dev);
    vser->bus->vser = vser;
    qbus_create_inplace(&vser->bus.qbus, &virtser_bus_info, dev, NULL);
    vser->bus.qbus.allow_hotplug = 1;
    vser->bus.vser = vser;
    QTAILQ_INIT(&vser->ports);

    vser->bus->max_nr_ports = conf->max_virtserial_ports;
    vser->bus.max_nr_ports = conf->max_virtserial_ports;
    vser->ivqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
    vser->ovqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));

@@ -859,7 +868,7 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
    /* control queue: guest to host */
    vser->c_ovq = virtio_add_queue(vdev, 32, control_out);

    for (i = 1; i < vser->bus->max_nr_ports; i++) {
    for (i = 1; i < vser->bus.max_nr_ports; i++) {
        /* Add a per-port queue for host to guest transfers */
        vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
        /* Add a per-per queue for guest to host transfers */
+8 −3
Original line number Diff line number Diff line
@@ -75,7 +75,6 @@ typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
 */
struct VirtIOSerialPort {
    DeviceState dev;
    VirtIOSerialPortInfo *info;

    QTAILQ_ENTRY(VirtIOSerialPort) next;

@@ -119,8 +118,10 @@ struct VirtIOSerialPort {
    uint32_t iov_idx;
    uint64_t iov_offset;

    /* Identify if this is a port that binds with hvc in the guest */
    uint8_t is_console;
    /*
     * When unthrottling we use a bottom-half to call flush_queued_data.
     */
    QEMUBH *bh;

    /* Is the corresponding guest device open? */
    bool guest_connected;
@@ -132,6 +133,10 @@ struct VirtIOSerialPort {

struct VirtIOSerialPortInfo {
    DeviceInfo qdev;

    /* Is this a device that binds with hvc in the guest? */
    bool is_console;

    /*
     * The per-port (or per-app) init function that's called when a
     * new device is found on the bus.