Merge remote-tracking branch 'amit/for-anthony' into staging
This commit is contained in:
commit
ede77d297f
|
@ -74,25 +74,26 @@ static void chr_event(void *opaque, int event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int generic_port_init(VirtConsole *vcon, VirtIOSerialPort *port)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Virtio Console Ports */
|
|
||||||
static int virtconsole_initfn(VirtIOSerialPort *port)
|
static int virtconsole_initfn(VirtIOSerialPort *port)
|
||||||
{
|
{
|
||||||
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
|
||||||
|
VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
|
||||||
|
vcon->port.dev.info);
|
||||||
|
|
||||||
port->is_console = true;
|
if (port->id == 0 && !info->is_console) {
|
||||||
return generic_port_init(vcon, port);
|
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);
|
||||||
|
info->have_data = flush_buf;
|
||||||
|
info->guest_open = guest_open;
|
||||||
|
info->guest_close = guest_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int virtconsole_exitfn(VirtIOSerialPort *port)
|
static int virtconsole_exitfn(VirtIOSerialPort *port)
|
||||||
|
@ -113,10 +114,10 @@ static int virtconsole_exitfn(VirtIOSerialPort *port)
|
||||||
static VirtIOSerialPortInfo virtconsole_info = {
|
static VirtIOSerialPortInfo virtconsole_info = {
|
||||||
.qdev.name = "virtconsole",
|
.qdev.name = "virtconsole",
|
||||||
.qdev.size = sizeof(VirtConsole),
|
.qdev.size = sizeof(VirtConsole),
|
||||||
|
.is_console = true,
|
||||||
.init = virtconsole_initfn,
|
.init = virtconsole_initfn,
|
||||||
.exit = virtconsole_exitfn,
|
.exit = virtconsole_exitfn,
|
||||||
.qdev.props = (Property[]) {
|
.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_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
|
||||||
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
|
DEFINE_PROP_CHR("chardev", VirtConsole, chr),
|
||||||
DEFINE_PROP_STRING("name", VirtConsole, port.name),
|
DEFINE_PROP_STRING("name", VirtConsole, port.name),
|
||||||
|
@ -130,26 +131,10 @@ static void virtconsole_register(void)
|
||||||
}
|
}
|
||||||
device_init(virtconsole_register)
|
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 = {
|
static VirtIOSerialPortInfo virtserialport_info = {
|
||||||
.qdev.name = "virtserialport",
|
.qdev.name = "virtserialport",
|
||||||
.qdev.size = sizeof(VirtConsole),
|
.qdev.size = sizeof(VirtConsole),
|
||||||
.init = virtserialport_initfn,
|
.init = virtconsole_initfn,
|
||||||
.exit = virtconsole_exitfn,
|
.exit = virtconsole_exitfn,
|
||||||
.qdev.props = (Property[]) {
|
.qdev.props = (Property[]) {
|
||||||
DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
|
DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct VirtIOSerial {
|
||||||
/* Arrays of ivqs and ovqs: one per port */
|
/* Arrays of ivqs and ovqs: one per port */
|
||||||
VirtQueue **ivqs, **ovqs;
|
VirtQueue **ivqs, **ovqs;
|
||||||
|
|
||||||
VirtIOSerialBus *bus;
|
VirtIOSerialBus bus;
|
||||||
|
|
||||||
DeviceState *qdev;
|
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,
|
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||||
VirtIODevice *vdev)
|
VirtIODevice *vdev)
|
||||||
{
|
{
|
||||||
|
VirtIOSerialPortInfo *info;
|
||||||
|
|
||||||
assert(port);
|
assert(port);
|
||||||
assert(virtio_queue_ready(vq));
|
assert(virtio_queue_ready(vq));
|
||||||
|
|
||||||
|
info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
|
||||||
|
|
||||||
while (!port->throttled) {
|
while (!port->throttled) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -149,7 +153,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
|
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->elem.out_sg[i].iov_base
|
||||||
+ port->iov_offset,
|
+ port->iov_offset,
|
||||||
buf_size);
|
buf_size);
|
||||||
|
@ -285,6 +289,13 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
|
||||||
return 0;
|
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)
|
void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
|
||||||
{
|
{
|
||||||
if (!port) {
|
if (!port) {
|
||||||
|
@ -295,14 +306,14 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
|
||||||
if (throttle) {
|
if (throttle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
qemu_bh_schedule(port->bh);
|
||||||
flush_queued_data(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Guest wants to notify us of some event */
|
/* Guest wants to notify us of some event */
|
||||||
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct VirtIOSerialPort *port;
|
struct VirtIOSerialPort *port;
|
||||||
|
struct VirtIOSerialPortInfo *info;
|
||||||
struct virtio_console_control cpkt, *gcpkt;
|
struct virtio_console_control cpkt, *gcpkt;
|
||||||
uint8_t *buffer;
|
uint8_t *buffer;
|
||||||
size_t buffer_len;
|
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)
|
if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
|
||||||
|
|
||||||
switch(cpkt.event) {
|
switch(cpkt.event) {
|
||||||
case VIRTIO_CONSOLE_DEVICE_READY:
|
case VIRTIO_CONSOLE_DEVICE_READY:
|
||||||
if (!cpkt.value) {
|
if (!cpkt.value) {
|
||||||
error_report("virtio-serial-bus: Guest failure in adding device %s\n",
|
error_report("virtio-serial-bus: Guest failure in adding device %s\n",
|
||||||
vser->bus->qbus.name);
|
vser->bus.qbus.name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -340,7 +353,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
|
||||||
case VIRTIO_CONSOLE_PORT_READY:
|
case VIRTIO_CONSOLE_PORT_READY:
|
||||||
if (!cpkt.value) {
|
if (!cpkt.value) {
|
||||||
error_report("virtio-serial-bus: Guest failure in adding port %u for device %s\n",
|
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;
|
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
|
* this port is a console port so that the guest can hook it
|
||||||
* up to hvc.
|
* up to hvc.
|
||||||
*/
|
*/
|
||||||
if (port->is_console) {
|
if (info->is_console) {
|
||||||
send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
|
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
|
* initialised. If some app is interested in knowing about
|
||||||
* this event, let it know.
|
* this event, let it know.
|
||||||
*/
|
*/
|
||||||
if (port->info->guest_ready) {
|
if (info->guest_ready) {
|
||||||
port->info->guest_ready(port);
|
info->guest_ready(port);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIRTIO_CONSOLE_PORT_OPEN:
|
case VIRTIO_CONSOLE_PORT_OPEN:
|
||||||
port->guest_connected = cpkt.value;
|
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 */
|
/* 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 */
|
/* Send the guest closed notification if an app is interested */
|
||||||
port->info->guest_close(port);
|
info->guest_close(port);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -442,11 +455,13 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
|
||||||
{
|
{
|
||||||
VirtIOSerial *vser;
|
VirtIOSerial *vser;
|
||||||
VirtIOSerialPort *port;
|
VirtIOSerialPort *port;
|
||||||
|
VirtIOSerialPortInfo *info;
|
||||||
|
|
||||||
vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
|
vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
|
||||||
port = find_port_by_vq(vser, vq);
|
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);
|
discard_vq_data(vq, vdev);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -467,7 +482,7 @@ static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
|
||||||
|
|
||||||
vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
|
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);
|
features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
|
||||||
}
|
}
|
||||||
return features;
|
return features;
|
||||||
|
@ -644,16 +659,6 @@ static struct BusInfo virtser_bus_info = {
|
||||||
.print_dev = virtser_bus_dev_print,
|
.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)
|
static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
|
||||||
{
|
{
|
||||||
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
||||||
|
@ -726,13 +731,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
|
||||||
bool plugging_port0;
|
bool plugging_port0;
|
||||||
|
|
||||||
port->vser = bus->vser;
|
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
|
* Is the first console port we're seeing? If so, put it up at
|
||||||
* location 0. This is done for backward compatibility (old
|
* location 0. This is done for backward compatibility (old
|
||||||
* kernel, new qemu).
|
* 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)) {
|
if (find_port_by_id(port->vser, port->id)) {
|
||||||
error_report("virtio-serial-bus: A port already exists at id %u\n",
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
port->info = info;
|
|
||||||
ret = info->init(port);
|
ret = info->init(port);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
return 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)
|
static int virtser_port_qdev_exit(DeviceState *qdev)
|
||||||
{
|
{
|
||||||
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
|
||||||
|
VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
|
||||||
|
port->dev.info);
|
||||||
VirtIOSerial *vser = port->vser;
|
VirtIOSerial *vser = port->vser;
|
||||||
|
|
||||||
|
qemu_bh_delete(port->bh);
|
||||||
remove_port(port->vser, port->id);
|
remove_port(port->vser, port->id);
|
||||||
|
|
||||||
QTAILQ_REMOVE(&vser->ports, port, next);
|
QTAILQ_REMOVE(&vser->ports, port, next);
|
||||||
|
|
||||||
if (port->info->exit)
|
if (info->exit) {
|
||||||
port->info->exit(port);
|
info->exit(port);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,11 +843,12 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
|
||||||
vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
|
vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
|
||||||
|
|
||||||
/* 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 */
|
||||||
vser->bus = virtser_bus_new(dev);
|
qbus_create_inplace(&vser->bus.qbus, &virtser_bus_info, dev, NULL);
|
||||||
vser->bus->vser = vser;
|
vser->bus.qbus.allow_hotplug = 1;
|
||||||
|
vser->bus.vser = vser;
|
||||||
QTAILQ_INIT(&vser->ports);
|
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->ivqs = qemu_malloc(conf->max_virtserial_ports * sizeof(VirtQueue *));
|
||||||
vser->ovqs = 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 */
|
/* control queue: guest to host */
|
||||||
vser->c_ovq = virtio_add_queue(vdev, 32, control_out);
|
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 */
|
/* Add a per-port queue for host to guest transfers */
|
||||||
vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
|
vser->ivqs[i] = virtio_add_queue(vdev, 128, handle_input);
|
||||||
/* Add a per-per queue for guest to host transfers */
|
/* Add a per-per queue for guest to host transfers */
|
||||||
|
|
|
@ -75,7 +75,6 @@ typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
|
||||||
*/
|
*/
|
||||||
struct VirtIOSerialPort {
|
struct VirtIOSerialPort {
|
||||||
DeviceState dev;
|
DeviceState dev;
|
||||||
VirtIOSerialPortInfo *info;
|
|
||||||
|
|
||||||
QTAILQ_ENTRY(VirtIOSerialPort) next;
|
QTAILQ_ENTRY(VirtIOSerialPort) next;
|
||||||
|
|
||||||
|
@ -119,8 +118,10 @@ struct VirtIOSerialPort {
|
||||||
uint32_t iov_idx;
|
uint32_t iov_idx;
|
||||||
uint64_t iov_offset;
|
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? */
|
/* Is the corresponding guest device open? */
|
||||||
bool guest_connected;
|
bool guest_connected;
|
||||||
|
@ -132,6 +133,10 @@ struct VirtIOSerialPort {
|
||||||
|
|
||||||
struct VirtIOSerialPortInfo {
|
struct VirtIOSerialPortInfo {
|
||||||
DeviceInfo qdev;
|
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
|
* The per-port (or per-app) init function that's called when a
|
||||||
* new device is found on the bus.
|
* new device is found on the bus.
|
||||||
|
|
Loading…
Reference in New Issue