aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-07-14 17:01:45 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-07-14 17:01:45 +0100
commit0a9934eef166836c8100fce72f7f837cb8b2ed2b (patch)
tree3b47e01deedcbf9133fa5733925156d75f4ed9ca /hw
parent7a6d04e73fdd571234e05dcad96895fafb3f22f0 (diff)
parent7497bce6c2561f1215fe179e40837774f6243799 (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>
Diffstat (limited to 'hw')
-rw-r--r--hw/char/serial-pci.c1
-rw-r--r--hw/char/serial.c59
-rw-r--r--hw/scsi/scsi-bus.c3
3 files changed, 36 insertions, 27 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;
}
}