diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-07-14 17:01:45 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-07-14 17:01:45 +0100 |
commit | 0a9934eef166836c8100fce72f7f837cb8b2ed2b (patch) | |
tree | 3b47e01deedcbf9133fa5733925156d75f4ed9ca | |
parent | 7a6d04e73fdd571234e05dcad96895fafb3f22f0 (diff) | |
parent | 7497bce6c2561f1215fe179e40837774f6243799 (diff) |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
Misc 2.1 fixes regarding character/serial devices and SCSI.
# gpg: Signature made Mon 14 Jul 2014 16:26:08 BST using RSA key ID 9B4D86F2
# gpg: Can't check signature: public key not found
* remotes/bonzini/tags/for-upstream:
serial-pci: remove memory regions from BAR before destroying them
virtio-scsi: fix with -M pc-i440fx-2.0
serial: change retry logic to avoid concurrency
qemu-char: fix deadlock with "-monitor pty"
scsi: Report error when lun number is in use
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | hw/char/serial-pci.c | 1 | ||||
-rw-r--r-- | hw/char/serial.c | 59 | ||||
-rw-r--r-- | hw/scsi/scsi-bus.c | 3 | ||||
-rw-r--r-- | include/hw/virtio/virtio-scsi.h | 2 | ||||
-rw-r--r-- | qemu-char.c | 23 |
5 files changed, 59 insertions, 29 deletions
diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index f53bb9c5d0..c133c33e7a 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -148,6 +148,7 @@ static void multi_serial_pci_exit(PCIDevice *dev) for (i = 0; i < pci->ports; i++) { s = pci->state + i; serial_exit_core(s); + memory_region_del_subregion(&pci->iobar, &s->io); memory_region_destroy(&s->io); g_free(pci->name[i]); } diff --git a/hw/char/serial.c b/hw/char/serial.c index 54180a9cba..764e1846cd 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -223,37 +223,42 @@ static gboolean serial_xmit(GIOChannel *chan, GIOCondition cond, void *opaque) { SerialState *s = opaque; - if (s->tsr_retry <= 0) { - if (s->fcr & UART_FCR_FE) { - if (fifo8_is_empty(&s->xmit_fifo)) { + do { + if (s->tsr_retry <= 0) { + if (s->fcr & UART_FCR_FE) { + if (fifo8_is_empty(&s->xmit_fifo)) { + return FALSE; + } + s->tsr = fifo8_pop(&s->xmit_fifo); + if (!s->xmit_fifo.num) { + s->lsr |= UART_LSR_THRE; + } + } else if ((s->lsr & UART_LSR_THRE)) { return FALSE; - } - s->tsr = fifo8_pop(&s->xmit_fifo); - if (!s->xmit_fifo.num) { + } else { + s->tsr = s->thr; s->lsr |= UART_LSR_THRE; + s->lsr &= ~UART_LSR_TEMT; } - } else if ((s->lsr & UART_LSR_THRE)) { - return FALSE; - } else { - s->tsr = s->thr; - s->lsr |= UART_LSR_THRE; - s->lsr &= ~UART_LSR_TEMT; } - } - if (s->mcr & UART_MCR_LOOP) { - /* in loopback mode, say that we just received a char */ - serial_receive1(s, &s->tsr, 1); - } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { - if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && - qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, serial_xmit, s) > 0) { - s->tsr_retry++; - return FALSE; + if (s->mcr & UART_MCR_LOOP) { + /* in loopback mode, say that we just received a char */ + serial_receive1(s, &s->tsr, 1); + } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { + if (s->tsr_retry >= 0 && s->tsr_retry < MAX_XMIT_RETRY && + qemu_chr_fe_add_watch(s->chr, G_IO_OUT|G_IO_HUP, + serial_xmit, s) > 0) { + s->tsr_retry++; + return FALSE; + } + s->tsr_retry = 0; + } else { + s->tsr_retry = 0; } - s->tsr_retry = 0; - } else { - s->tsr_retry = 0; - } + /* Transmit another byte if it is already available. It is only + possible when FIFO is enabled and not empty. */ + } while ((s->fcr & UART_FCR_FE) && !fifo8_is_empty(&s->xmit_fifo)); s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); @@ -293,7 +298,9 @@ static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); - serial_xmit(NULL, G_IO_OUT, s); + if (s->tsr_retry <= 0) { + serial_xmit(NULL, G_IO_OUT, s); + } } break; case 1: diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ea1ac09c8a..4341754253 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -177,7 +177,8 @@ static int scsi_qdev_init(DeviceState *qdev) d = scsi_device_find(bus, dev->channel, dev->id, dev->lun); assert(d); if (d->lun == dev->lun && dev != d) { - object_unparent(OBJECT(d)); + error_report("lun already used by '%s'", d->qdev.id); + goto err; } } diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 0419ee4252..188a2d9144 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -178,6 +178,8 @@ typedef struct { DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128) #define DEFINE_VIRTIO_SCSI_FEATURES(_state, _feature_field) \ + DEFINE_PROP_BIT("any_layout", _state, _feature_field, \ + VIRTIO_F_ANY_LAYOUT, true), \ DEFINE_PROP_BIT("hotplug", _state, _feature_field, VIRTIO_SCSI_F_HOTPLUG, \ true), \ DEFINE_PROP_BIT("param_change", _state, _feature_field, \ diff --git a/qemu-char.c b/qemu-char.c index 55e372cf32..7acc03f161 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -1089,6 +1089,7 @@ typedef struct { /* Protected by the CharDriverState chr_write_lock. */ int connected; guint timer_tag; + guint open_tag; } PtyCharDriver; static void pty_chr_update_read_handler_locked(CharDriverState *chr); @@ -1101,6 +1102,7 @@ static gboolean pty_chr_timer(gpointer opaque) qemu_mutex_lock(&chr->chr_write_lock); s->timer_tag = 0; + s->open_tag = 0; if (!s->connected) { /* Next poll ... */ pty_chr_update_read_handler_locked(chr); @@ -1203,12 +1205,26 @@ static gboolean pty_chr_read(GIOChannel *chan, GIOCondition cond, void *opaque) return TRUE; } +static gboolean qemu_chr_be_generic_open_func(gpointer opaque) +{ + CharDriverState *chr = opaque; + PtyCharDriver *s = chr->opaque; + + s->open_tag = 0; + qemu_chr_be_generic_open(chr); + return FALSE; +} + /* Called with chr_write_lock held. */ static void pty_chr_state(CharDriverState *chr, int connected) { PtyCharDriver *s = chr->opaque; if (!connected) { + if (s->open_tag) { + g_source_remove(s->open_tag); + s->open_tag = 0; + } remove_fd_in_watch(chr); s->connected = 0; /* (re-)connect poll interval for idle guests: once per second. @@ -1221,8 +1237,9 @@ static void pty_chr_state(CharDriverState *chr, int connected) s->timer_tag = 0; } if (!s->connected) { + g_assert(s->open_tag == 0); s->connected = 1; - qemu_chr_be_generic_open(chr); + s->open_tag = g_idle_add(qemu_chr_be_generic_open_func, chr); } if (!chr->fd_in_tag) { chr->fd_in_tag = io_add_watch_poll(s->fd, pty_chr_read_poll, @@ -1236,7 +1253,8 @@ static void pty_chr_close(struct CharDriverState *chr) PtyCharDriver *s = chr->opaque; int fd; - remove_fd_in_watch(chr); + qemu_mutex_lock(&chr->chr_write_lock); + pty_chr_state(chr, 0); fd = g_io_channel_unix_get_fd(s->fd); g_io_channel_unref(s->fd); close(fd); @@ -1244,6 +1262,7 @@ static void pty_chr_close(struct CharDriverState *chr) g_source_remove(s->timer_tag); s->timer_tag = 0; } + qemu_mutex_unlock(&chr->chr_write_lock); g_free(s); qemu_chr_be_event(chr, CHR_EVENT_CLOSED); } |