aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/acpi_piix4.c8
-rw-r--r--hw/cadence_uart.c2
-rw-r--r--hw/cirrus_vga.c7
-rw-r--r--hw/e1000.c4
-rw-r--r--hw/eepro100.c4
-rw-r--r--hw/ide/ahci.c2
-rw-r--r--hw/ide/atapi.c6
-rw-r--r--hw/ide/core.c11
-rw-r--r--hw/imx_avic.c4
-rw-r--r--hw/imx_timer.c4
-rw-r--r--hw/ioh3420.c1
-rw-r--r--hw/kzm.c2
-rw-r--r--hw/lm4549.c2
-rw-r--r--hw/nseries.c14
-rw-r--r--hw/pc_piix.c12
-rw-r--r--hw/pflash_cfi01.c49
-rw-r--r--hw/pflash_cfi02.c37
-rw-r--r--hw/qxl.c108
-rw-r--r--hw/scsi-bus.c23
-rw-r--r--hw/scsi-disk.c44
-rw-r--r--hw/scsi.h2
-rw-r--r--hw/srp.h8
-rw-r--r--hw/sun4m.c14
-rw-r--r--hw/usb/dev-network.c49
-rw-r--r--hw/usb/hcd-ehci.c241
-rw-r--r--hw/usb/hcd-uhci.c5
-rw-r--r--hw/usb/host-linux.c2
-rw-r--r--hw/usb/redirect.c504
-rw-r--r--hw/vga-isa-mm.c1
-rw-r--r--hw/vga.c5
-rw-r--r--hw/virtio-net.c4
-rw-r--r--hw/vmware_vga.c1
-rw-r--r--hw/xen-host-pci-device.c6
-rw-r--r--hw/xen_nic.c1
-rw-r--r--hw/xen_pt.h4
-rw-r--r--hw/xen_pt_config_init.c14
-rw-r--r--hw/xilinx.h16
-rw-r--r--hw/xilinx_timer.c16
38 files changed, 924 insertions, 313 deletions
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index dad38870a..a48187fa7 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -73,6 +73,7 @@ typedef struct PIIX4PMState {
qemu_irq smi_irq;
int kvm_enabled;
Notifier machine_ready;
+ Notifier powerdown_notifier;
/* for pci hotplug */
struct gpe_regs gpe_cpu;
@@ -368,9 +369,9 @@ static void piix4_reset(void *opaque)
piix4_update_hotplug(s);
}
-static void piix4_powerdown(void *opaque, int irq, int power_failing)
+static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
{
- PIIX4PMState *s = opaque;
+ PIIX4PMState *s = container_of(n, PIIX4PMState, powerdown_notifier);
assert(s != NULL);
acpi_pm1_evt_power_down(&s->ar);
@@ -427,7 +428,8 @@ static int piix4_pm_initfn(PCIDevice *dev)
acpi_pm_tmr_init(&s->ar, pm_tmr_timer);
acpi_gpe_init(&s->ar, GPE_LEN);
- qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
+ s->powerdown_notifier.notify = piix4_pm_powerdown_req;
+ qemu_register_powerdown_notifier(&s->powerdown_notifier);
pm_smbus_init(&s->dev.qdev, &s->smb);
s->machine_ready.notify = piix4_pm_machine_ready;
diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c
index d98e53137..f8afc4ed2 100644
--- a/hw/cadence_uart.c
+++ b/hw/cadence_uart.c
@@ -404,7 +404,7 @@ static uint64_t uart_read(void *opaque, target_phys_addr_t offset,
uint32_t c = 0;
offset >>= 2;
- if (offset > R_MAX) {
+ if (offset >= R_MAX) {
return 0;
} else if (offset == R_TX_RX) {
uart_read_rx_fifo(s, &c);
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 035cc346b..4284c1e2a 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2441,6 +2441,8 @@ static uint32_t cirrus_vga_ioport_read(void *opaque, uint32_t addr)
VGACommonState *s = &c->vga;
int val, index;
+ qemu_flush_coalesced_mmio_buffer();
+
if (vga_ioport_invalid(s, addr)) {
val = 0xff;
} else {
@@ -2534,6 +2536,8 @@ static void cirrus_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
VGACommonState *s = &c->vga;
int index;
+ qemu_flush_coalesced_mmio_buffer();
+
/* check port range access depending on color/monochrome mode */
if (vga_ioport_invalid(s, addr)) {
return;
@@ -2854,6 +2858,7 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
/* I/O handler for LFB */
memory_region_init_io(&s->cirrus_linear_io, &cirrus_linear_io_ops, s,
"cirrus-linear-io", VGA_RAM_SIZE);
+ memory_region_set_flush_coalesced(&s->cirrus_linear_io);
/* I/O handler for LFB */
memory_region_init_io(&s->cirrus_linear_bitblt_io,
@@ -2861,10 +2866,12 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
s,
"cirrus-bitblt-mmio",
0x400000);
+ memory_region_set_flush_coalesced(&s->cirrus_linear_bitblt_io);
/* I/O handler for memory-mapped I/O */
memory_region_init_io(&s->cirrus_mmio_io, &cirrus_mmio_io_ops, s,
"cirrus-mmio", CIRRUS_PNPMMIO_SIZE);
+ memory_region_set_flush_coalesced(&s->cirrus_mmio_io);
s->real_vram_size =
(s->device_id == CIRRUS_ID_CLGD5446) ? 4096 * 1024 : 2048 * 1024;
diff --git a/hw/e1000.c b/hw/e1000.c
index ae8a6c552..ec3a7c4ec 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val)
s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1;
DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT],
s->mac_reg[RCTL]);
+ qemu_flush_queued_packets(&s->nic->nc);
}
static void
@@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val)
{
s->check_rxov = 0;
s->mac_reg[index] = val & 0xffff;
+ if (e1000_has_rxbufs(s, 1)) {
+ qemu_flush_queued_packets(&s->nic->nc);
+ }
}
static void
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 50d117e35..5b231163d 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
}
set_ru_state(s, ru_ready);
s->ru_offset = e100_read_reg4(s, SCBPointer);
+ qemu_flush_queued_packets(&s->nic->nc);
TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
break;
case RX_RESUME:
@@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size)
if (rfd_command & COMMAND_EL) {
/* EL bit is set, so this was the last frame. */
logout("receive: Running out of frames\n");
- set_ru_state(s, ru_suspended);
+ set_ru_state(s, ru_no_resources);
+ eepro100_rnr_interrupt(s);
}
if (rfd_command & COMMAND_S) {
/* S bit is set. */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 5ea3cadb0..68671bc4d 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1175,7 +1175,6 @@ void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports)
ad->port_no = i;
ad->port.dma = &ad->dma;
ad->port.dma->ops = &ahci_dma_ops;
- ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
}
}
@@ -1199,6 +1198,7 @@ void ahci_reset(AHCIState *s)
pr->irq_stat = 0;
pr->irq_mask = 0;
pr->scr_ctl = 0;
+ pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON;
ahci_reset_port(s, i);
}
}
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index f7f714c72..685cbaa88 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -875,6 +875,12 @@ static void cmd_start_stop_unit(IDEState *s, uint8_t* buf)
int sense;
bool start = buf[4] & 1;
bool loej = buf[4] & 2; /* load on start, eject on !start */
+ int pwrcnd = buf[4] & 0xf0;
+
+ if (pwrcnd) {
+ /* eject/load only happens for power condition == 0 */
+ return;
+ }
if (loej) {
if (!start && !s->tray_open && s->tray_locked) {
diff --git a/hw/ide/core.c b/hw/ide/core.c
index d65ef3d58..d6fb69c63 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -53,8 +53,6 @@ static const int smart_attributes[][12] = {
{ 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
/* airflow-temperature-celsius */
{ 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32},
- /* end of list */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
static int ide_handle_rw_error(IDEState *s, int error, int op);
@@ -1468,9 +1466,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
case SMART_READ_THRESH:
memset(s->io_buffer, 0, 0x200);
s->io_buffer[0] = 0x01; /* smart struct version */
- for (n=0; n<30; n++) {
- if (smart_attributes[n][0] == 0)
- break;
+ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
s->io_buffer[2+0+(n*12)] = smart_attributes[n][0];
s->io_buffer[2+1+(n*12)] = smart_attributes[n][11];
}
@@ -1484,10 +1480,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
case SMART_READ_DATA:
memset(s->io_buffer, 0, 0x200);
s->io_buffer[0] = 0x01; /* smart struct version */
- for (n=0; n<30; n++) {
- if (smart_attributes[n][0] == 0) {
- break;
- }
+ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) {
int i;
for(i = 0; i < 11; i++) {
s->io_buffer[2+i+(n*12)] = smart_attributes[n][i];
diff --git a/hw/imx_avic.c b/hw/imx_avic.c
index 4f010e8ee..b1a8fe6d4 100644
--- a/hw/imx_avic.c
+++ b/hw/imx_avic.c
@@ -6,9 +6,9 @@
*
* Copyright (c) 2008 OKL
* Copyright (c) 2011 NICTA Pty Ltd
- * Originally Written by Hans Jiang
+ * Originally written by Hans Jiang
*
- * This code is licenced under the GPL version 2 or later. See
+ * This code is licensed under the GPL version 2 or later. See
* the COPYING file in the top-level directory.
*
* TODO: implement vectors.
diff --git a/hw/imx_timer.c b/hw/imx_timer.c
index 16215ccf0..c28c53725 100644
--- a/hw/imx_timer.c
+++ b/hw/imx_timer.c
@@ -3,10 +3,10 @@
*
* Copyright (c) 2008 OK Labs
* Copyright (c) 2011 NICTA Pty Ltd
- * Originally Written by Hans Jiang
+ * Originally written by Hans Jiang
* Updated by Peter Chubb
*
- * This code is licenced under GPL version 2 or later. See
+ * This code is licensed under GPL version 2 or later. See
* the COPYING file in the top-level directory.
*
*/
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index 94a537c9b..4d314733b 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -125,7 +125,6 @@ static int ioh3420_initfn(PCIDevice *d)
rc = pcie_chassis_add_slot(s);
if (rc < 0) {
goto err_pcie_cap;
- return rc;
}
pcie_cap_root_init(d);
rc = pcie_aer_init(d, IOH_EP_AER_OFFSET);
diff --git a/hw/kzm.c b/hw/kzm.c
index 6a5e9dfac..68cd1b48b 100644
--- a/hw/kzm.c
+++ b/hw/kzm.c
@@ -5,7 +5,7 @@
* Written by Hans at OK-Labs
* Updated by Peter Chubb.
*
- * This code is licenced under the GPL, version 2 or later.
+ * This code is licensed under the GPL, version 2 or later.
* See the file `COPYING' in the top level directory.
*
* It (partially) emulates a Kyoto Microcomputer
diff --git a/hw/lm4549.c b/hw/lm4549.c
index 80b3ec4a5..e0137d54b 100644
--- a/hw/lm4549.c
+++ b/hw/lm4549.c
@@ -224,7 +224,7 @@ uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right)
This model supports 16-bit playback.
*/
- if (s->buffer_level >= LM4549_BUFFER_SIZE) {
+ if (s->buffer_level > LM4549_BUFFER_SIZE - 2) {
DPRINTF("write_sample Buffer full\n");
return 0;
}
diff --git a/hw/nseries.c b/hw/nseries.c
index 4df267032..6df71ebb4 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -189,6 +189,17 @@ static void n8x0_nand_setup(struct n800_s *s)
/* XXX: in theory should also update the OOB for both pages */
}
+static qemu_irq n8x0_system_powerdown;
+
+static void n8x0_powerdown_req(Notifier *n, void *opaque)
+{
+ qemu_irq_raise(n8x0_system_powerdown);
+}
+
+static Notifier n8x0_system_powerdown_notifier = {
+ .notify = n8x0_powerdown_req
+};
+
static void n8x0_i2c_setup(struct n800_s *s)
{
DeviceState *dev;
@@ -201,7 +212,8 @@ static void n8x0_i2c_setup(struct n800_s *s)
qdev_get_gpio_in(s->mpu->ih[0],
OMAP_INT_24XX_SYS_NIRQ));
- qemu_system_powerdown = qdev_get_gpio_in(dev, 3);
+ n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
+ qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
/* Attach a TMP105 PM chip (A0 wired to ground) */
dev = i2c_create_slave(i2c, "tmp105", N8X0_TMP105_ADDR);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index a771d7982..7229d2f16 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -359,8 +359,8 @@ static void pc_xen_hvm_init(ram_addr_t ram_size,
#define KVM_MACHINE_OPTIONS ""
#endif
-static QEMUMachine pc_machine_v1_2 = {
- .name = "pc-1.2",
+static QEMUMachine pc_machine_v1_3 = {
+ .name = "pc-1.3",
.alias = "pc",
.desc = "Standard PC",
.init = pc_init_pci,
@@ -369,6 +369,13 @@ static QEMUMachine pc_machine_v1_2 = {
.default_machine_opts = KVM_MACHINE_OPTIONS,
};
+static QEMUMachine pc_machine_v1_2 = {
+ .name = "pc-1.2",
+ .desc = "Standard PC",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+};
+
#define PC_COMPAT_1_1 \
{\
.driver = "virtio-scsi-pci",\
@@ -675,6 +682,7 @@ static QEMUMachine xenfv_machine = {
static void pc_machine_init(void)
{
+ qemu_register_machine(&pc_machine_v1_3);
qemu_register_machine(&pc_machine_v1_2);
qemu_register_machine(&pc_machine_v1_1);
qemu_register_machine(&pc_machine_v1_0);
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index d1c742379..855890d1f 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -41,6 +41,7 @@
#include "block.h"
#include "qemu-timer.h"
#include "exec-memory.h"
+#include "host-utils.h"
#define PFLASH_BUG(fmt, ...) \
do { \
@@ -320,7 +321,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
}
pfl->wcycle++;
pfl->cmd = cmd;
- return;
+ break;
case 1:
switch (pfl->cmd) {
case 0x10: /* Single Byte Program */
@@ -375,7 +376,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
default:
goto error_flash;
}
- return;
+ break;
case 2:
switch (pfl->cmd) {
case 0xe8: /* Block write */
@@ -406,7 +407,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
default:
goto error_flash;
}
- return;
+ break;
case 3: /* Confirm mode */
switch (pfl->cmd) {
case 0xe8: /* Block write */
@@ -422,7 +423,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
default:
goto error_flash;
}
- return;
+ break;
default:
/* Should never happen */
DPRINTF("%s: invalid write state\n", __func__);
@@ -543,42 +544,6 @@ static const MemoryRegionOps pflash_cfi01_ops_le = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-/* Count trailing zeroes of a 32 bits quantity */
-static int ctz32 (uint32_t n)
-{
- int ret;
-
- ret = 0;
- if (!(n & 0xFFFF)) {
- ret += 16;
- n = n >> 16;
- }
- if (!(n & 0xFF)) {
- ret += 8;
- n = n >> 8;
- }
- if (!(n & 0xF)) {
- ret += 4;
- n = n >> 4;
- }
- if (!(n & 0x3)) {
- ret += 2;
- n = n >> 2;
- }
- if (!(n & 0x1)) {
- ret++;
-#if 0 /* This is not necessary as n is never 0 */
- n = n >> 1;
-#endif
- }
-#if 0 /* This is not necessary as n is never 0 */
- if (!n)
- ret++;
-#endif
-
- return ret;
-}
-
pflash_t *pflash_cfi01_register(target_phys_addr_t base,
DeviceState *qdev, const char *name,
target_phys_addr_t size,
@@ -711,7 +676,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
pfl->cfi_table[0x33] = 'I';
pfl->cfi_table[0x34] = '1';
- pfl->cfi_table[0x35] = '1';
+ pfl->cfi_table[0x35] = '0';
pfl->cfi_table[0x36] = 0x00;
pfl->cfi_table[0x37] = 0x00;
@@ -723,6 +688,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base,
pfl->cfi_table[0x3b] = 0x00;
pfl->cfi_table[0x3c] = 0x00;
+ pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */
+
return pfl;
}
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index 3e2002e4b..8cb154958 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -40,6 +40,7 @@
#include "qemu-timer.h"
#include "block.h"
#include "exec-memory.h"
+#include "host-utils.h"
//#define PFLASH_DEBUG
#ifdef PFLASH_DEBUG
@@ -575,42 +576,6 @@ static const MemoryRegionOps pflash_cfi02_ops_le = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-/* Count trailing zeroes of a 32 bits quantity */
-static int ctz32 (uint32_t n)
-{
- int ret;
-
- ret = 0;
- if (!(n & 0xFFFF)) {
- ret += 16;
- n = n >> 16;
- }
- if (!(n & 0xFF)) {
- ret += 8;
- n = n >> 8;
- }
- if (!(n & 0xF)) {
- ret += 4;
- n = n >> 4;
- }
- if (!(n & 0x3)) {
- ret += 2;
- n = n >> 2;
- }
- if (!(n & 0x1)) {
- ret++;
-#if 0 /* This is not necessary as n is never 0 */
- n = n >> 1;
-#endif
- }
-#if 0 /* This is not necessary as n is never 0 */
- if (!n)
- ret++;
-#endif
-
- return ret;
-}
-
pflash_t *pflash_cfi02_register(target_phys_addr_t base,
DeviceState *qdev, const char *name,
target_phys_addr_t size,
diff --git a/hw/qxl.c b/hw/qxl.c
index 5b3f48426..33169f348 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -18,6 +18,8 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <zlib.h>
+
#include "qemu-common.h"
#include "qemu-timer.h"
#include "qemu-queue.h"
@@ -141,6 +143,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
{
+ trace_qxl_set_guest_bug(qxl->id);
qxl_send_events(qxl, QXL_INTERRUPT_ERROR);
qxl->guest_bug = 1;
if (qxl->guestdebug) {
@@ -201,6 +204,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie);
} else {
qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
+ qxl_spice_destroy_surface_wait_complete(qxl, id);
}
}
@@ -597,9 +601,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
case QXL_MODE_VGA:
ret = false;
qemu_mutex_lock(&qxl->ssd.lock);
- if (qxl->ssd.update != NULL) {
- update = qxl->ssd.update;
- qxl->ssd.update = NULL;
+ update = QTAILQ_FIRST(&qxl->ssd.updates);
+ if (update != NULL) {
+ QTAILQ_REMOVE(&qxl->ssd.updates, update, next);
*ext = update->ext;
ret = true;
}
@@ -953,6 +957,11 @@ static void interface_set_client_capabilities(QXLInstance *sin,
{
PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+ if (runstate_check(RUN_STATE_INMIGRATE) ||
+ runstate_check(RUN_STATE_POSTMIGRATE)) {
+ return;
+ }
+
qxl->shadow_rom.client_present = client_present;
memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps));
qxl->rom->client_present = client_present;
@@ -964,6 +973,79 @@ static void interface_set_client_capabilities(QXLInstance *sin,
#endif
+#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \
+ && SPICE_SERVER_VERSION >= 0x000b05
+
+static uint32_t qxl_crc32(const uint8_t *p, unsigned len)
+{
+ /*
+ * zlib xors the seed with 0xffffffff, and xors the result
+ * again with 0xffffffff; Both are not done with linux's crc32,
+ * which we want to be compatible with, so undo that.
+ */
+ return crc32(0xffffffff, p, len) ^ 0xffffffff;
+}
+
+/* called from main context only */
+static int interface_client_monitors_config(QXLInstance *sin,
+ VDAgentMonitorsConfig *monitors_config)
+{
+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+ QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);
+ int i;
+
+ /*
+ * Older windows drivers set int_mask to 0 when their ISR is called,
+ * then later set it to ~0. So it doesn't relate to the actual interrupts
+ * handled. However, they are old, so clearly they don't support this
+ * interrupt
+ */
+ if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||
+ !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {
+ trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,
+ qxl->ram->int_mask,
+ monitors_config);
+ return 0;
+ }
+ if (!monitors_config) {
+ return 1;
+ }
+ memset(&rom->client_monitors_config, 0,
+ sizeof(rom->client_monitors_config));
+ rom->client_monitors_config.count = monitors_config->num_of_monitors;
+ /* monitors_config->flags ignored */
+ if (rom->client_monitors_config.count >=
+ ARRAY_SIZE(rom->client_monitors_config.heads)) {
+ trace_qxl_client_monitors_config_capped(qxl->id,
+ monitors_config->num_of_monitors,
+ ARRAY_SIZE(rom->client_monitors_config.heads));
+ rom->client_monitors_config.count =
+ ARRAY_SIZE(rom->client_monitors_config.heads);
+ }
+ for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {
+ VDAgentMonConfig *monitor = &monitors_config->monitors[i];
+ QXLURect *rect = &rom->client_monitors_config.heads[i];
+ /* monitor->depth ignored */
+ rect->left = monitor->x;
+ rect->top = monitor->y;
+ rect->right = monitor->x + monitor->width;
+ rect->bottom = monitor->y + monitor->height;
+ }
+ rom->client_monitors_config_crc = qxl_crc32(
+ (const uint8_t *)&rom->client_monitors_config,
+ sizeof(rom->client_monitors_config));
+ trace_qxl_client_monitors_config_crc(qxl->id,
+ sizeof(rom->client_monitors_config),
+ rom->client_monitors_config_crc);
+
+ trace_qxl_interrupt_client_monitors_config(qxl->id,
+ rom->client_monitors_config.count,
+ rom->client_monitors_config.heads);
+ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);
+ return 1;
+}
+#endif
+
static const QXLInterface qxl_interface = {
.base.type = SPICE_INTERFACE_QXL,
.base.description = "qxl gpu",
@@ -988,6 +1070,10 @@ static const QXLInterface qxl_interface = {
#if SPICE_SERVER_VERSION >= 0x000b04
.set_client_capabilities = interface_set_client_capabilities,
#endif
+#if SPICE_SERVER_VERSION >= 0x000b05 && \
+ defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG)
+ .client_monitors_config = interface_client_monitors_config,
+#endif
};
static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -1402,7 +1488,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr,
break;
}
trace_qxl_io_unexpected_vga_mode(d->id,
- io_port, io_port_to_string(io_port));
+ addr, val, io_port_to_string(io_port));
/* be nice to buggy guest drivers */
if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
io_port < QXL_IO_RANGE_SIZE) {
@@ -1470,6 +1556,13 @@ async_common:
return;
}
+ if (update.left < 0 || update.top < 0 || update.left >= update.right ||
+ update.top >= update.bottom) {
+ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: "
+ "invalid area(%d,%d,%d,%d)\n", update.left,
+ update.right, update.top, update.bottom);
+ break;
+ }
if (async == QXL_ASYNC) {
cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO,
QXL_IO_UPDATE_AREA_ASYNC);
@@ -1501,6 +1594,7 @@ async_common:
qxl_set_mode(d, val, 0);
break;
case QXL_IO_LOG:
+ trace_qxl_io_log(d->id, d->ram->log_buf);
if (d->guestdebug) {
fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id,
qemu_get_clock_ns(vm_clock), d->ram->log_buf);
@@ -1594,9 +1688,9 @@ cancel_async:
static uint64_t ioport_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
- PCIQXLDevice *d = opaque;
+ PCIQXLDevice *qxl = opaque;
- trace_qxl_io_read_unexpected(d->id);
+ trace_qxl_io_read_unexpected(qxl->id);
return 0xff;
}
@@ -1626,6 +1720,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
uint32_t old_pending;
uint32_t le_events = cpu_to_le32(events);
+ trace_qxl_send_events(d->id, events);
assert(qemu_spice_display_is_running(&d->ssd));
old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
if ((old_pending & le_events) == le_events) {
@@ -1910,6 +2005,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
if (qxl->id == 0) {
vga_dirty_log_start(&qxl->vga);
}
+ memory_region_set_flush_coalesced(&qxl->io_bar);
pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 4981a0243..058d3b237 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -801,26 +801,39 @@ static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
return xfer * unit;
}
-static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+uint32_t scsi_data_cdb_length(uint8_t *buf)
+{
+ if ((buf[0] >> 5) == 0 && buf[4] == 0) {
+ return 256;
+ } else {
+ return scsi_cdb_length(buf);
+ }
+}
+
+uint32_t scsi_cdb_length(uint8_t *buf)
{
switch (buf[0] >> 5) {
case 0:
- cmd->xfer = buf[4];
+ return buf[4];
break;
case 1:
case 2:
- cmd->xfer = lduw_be_p(&buf[7]);
+ return lduw_be_p(&buf[7]);
break;
case 4:
- cmd->xfer = ldl_be_p(&buf[10]) & 0xffffffffULL;
+ return ldl_be_p(&buf[10]) & 0xffffffffULL;
break;
case 5:
- cmd->xfer = ldl_be_p(&buf[6]) & 0xffffffffULL;
+ return ldl_be_p(&buf[6]) & 0xffffffffULL;
break;
default:
return -1;
}
+}
+static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
+{
+ cmd->xfer = scsi_cdb_length(buf);
switch (buf[0]) {
case TEST_UNIT_READY:
case REWIND:
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1585683bc..95e91585e 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -678,7 +678,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
* is actually implemented, but we're good enough.
*/
outbuf[2] = 5;
- outbuf[3] = 2; /* Format 2 */
+ outbuf[3] = 2 | 0x10; /* Format 2, HiSup */
if (buflen > 36) {
outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */
@@ -1449,6 +1449,22 @@ invalid_field:
return;
}
+static inline bool check_lba_range(SCSIDiskState *s,
+ uint64_t sector_num, uint32_t nb_sectors)
+{
+ /*
+ * The first line tests that no overflow happens when computing the last
+ * sector. The second line tests that the last accessed sector is in
+ * range.
+ *
+ * Careful, the computations should not underflow for nb_sectors == 0,
+ * and a 0-block read to the first LBA beyond the end of device is
+ * valid.
+ */
+ return (sector_num <= sector_num + nb_sectors &&
+ sector_num + nb_sectors <= s->qdev.max_lba + 1);
+}
+
typedef struct UnmapCBData {
SCSIDiskReq *r;
uint8_t *inbuf;
@@ -1473,8 +1489,7 @@ static void scsi_unmap_complete(void *opaque, int ret)
if (data->count > 0 && !r->req.io_canceled) {
sector_num = ldq_be_p(&data->inbuf[0]);
nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL;
- if (sector_num > sector_num + nb_sectors ||
- sector_num + nb_sectors - 1 > s->qdev.max_lba) {
+ if (!check_lba_range(s, sector_num, nb_sectors)) {
scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE));
goto done;
}
@@ -1793,17 +1808,13 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
DPRINTF("Unmap (len %lu)\n", (long)r->req.cmd.xfer);
break;
case WRITE_SAME_10:
- nb_sectors = lduw_be_p(&req->cmd.buf[7]);
- goto write_same;
case WRITE_SAME_16:
- nb_sectors = ldl_be_p(&req->cmd.buf[10]) & 0xffffffffULL;
- write_same:
+ nb_sectors = scsi_data_cdb_length(r->req.cmd.buf);
if (bdrv_is_read_only(s->qdev.conf.bs)) {
scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED));
return 0;
}
- if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors ||
- r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) {
+ if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) {
goto illegal_lba;
}
@@ -1858,7 +1869,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
- int32_t len;
+ uint32_t len;
uint8_t command;
command = buf[0];
@@ -1868,18 +1879,17 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
+ len = scsi_data_cdb_length(r->req.cmd.buf);
switch (command) {
case READ_6:
case READ_10:
case READ_12:
case READ_16:
- len = r->req.cmd.xfer / s->qdev.blocksize;
- DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
+ DPRINTF("Read (sector %" PRId64 ", count %u)\n", r->req.cmd.lba, len);
if (r->req.cmd.buf[1] & 0xe0) {
goto illegal_request;
}
- if (r->req.cmd.lba > r->req.cmd.lba + len ||
- r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
+ if (!check_lba_range(s, r->req.cmd.lba, len)) {
goto illegal_lba;
}
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
@@ -1900,15 +1910,13 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf)
case VERIFY_10:
case VERIFY_12:
case VERIFY_16:
- len = r->req.cmd.xfer / s->qdev.blocksize;
- DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
+ DPRINTF("Write %s(sector %" PRId64 ", count %u)\n",
(command & 0xe) == 0xe ? "And Verify " : "",
r->req.cmd.lba, len);
if (r->req.cmd.buf[1] & 0xe0) {
goto illegal_request;
}
- if (r->req.cmd.lba > r->req.cmd.lba + len ||
- r->req.cmd.lba + len - 1 > s->qdev.max_lba) {
+ if (!check_lba_range(s, r->req.cmd.lba, len)) {
goto illegal_lba;
}
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
diff --git a/hw/scsi.h b/hw/scsi.h
index 1aeee4659..b8f73577d 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -218,6 +218,8 @@ extern const struct SCSISense sense_code_WRITE_PROTECTED;
#define SENSE_CODE(x) sense_code_ ## x
+uint32_t scsi_data_cdb_length(uint8_t *buf);
+uint32_t scsi_cdb_length(uint8_t *buf);
int scsi_sense_valid(SCSISense sense);
int scsi_build_sense(uint8_t *in_buf, int in_len,
uint8_t *buf, int len, bool fixed);
diff --git a/hw/srp.h b/hw/srp.h
index 3009bd56c..5e0cad5c1 100644
--- a/hw/srp.h
+++ b/hw/srp.h
@@ -177,13 +177,13 @@ struct srp_tsk_mgmt {
uint8_t reserved1[6];
uint64_t tag;
uint8_t reserved2[4];
- uint64_t lun QEMU_PACKED;
+ uint64_t lun;
uint8_t reserved3[2];
uint8_t tsk_mgmt_func;
uint8_t reserved4;
uint64_t task_tag;
uint8_t reserved5[8];
-};
+} QEMU_PACKED;
/*
* We need the packed attribute because the SRP spec only aligns the
@@ -198,14 +198,14 @@ struct srp_cmd {
uint8_t data_in_desc_cnt;
uint64_t tag;
uint8_t reserved2[4];
- uint64_t lun QEMU_PACKED;
+ uint64_t lun;
uint8_t reserved3;
uint8_t task_attr;
uint8_t reserved4;
uint8_t add_cdb_len;
uint8_t cdb[16];
uint8_t add_data[0];
-};
+} QEMU_PACKED;
enum {
SRP_RSP_FLAG_RSPVALID = 1 << 0,
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 0f909b5f8..c98cd5ec3 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -472,6 +472,17 @@ static void slavio_timer_init_all(target_phys_addr_t addr, qemu_irq master_irq,
}
}
+static qemu_irq slavio_system_powerdown;
+
+static void slavio_powerdown_req(Notifier *n, void *opaque)
+{
+ qemu_irq_raise(slavio_system_powerdown);
+}
+
+static Notifier slavio_system_powerdown_notifier = {
+ .notify = slavio_powerdown_req
+};
+
#define MISC_LEDS 0x01600000
#define MISC_CFG 0x01800000
#define MISC_DIAG 0x01a00000
@@ -514,7 +525,8 @@ static void slavio_misc_init(target_phys_addr_t base,
}
sysbus_connect_irq(s, 0, irq);
sysbus_connect_irq(s, 1, fdc_tc);
- qemu_system_powerdown = qdev_get_gpio_in(dev, 0);
+ slavio_system_powerdown = qdev_get_gpio_in(dev, 0);
+ qemu_register_powerdown_notifier(&slavio_system_powerdown_notifier);
}
static void ecc_init(target_phys_addr_t base, qemu_irq irq, uint32_t version)
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index c84892c98..e4a43599b 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s,
return 0;
}
+/* Prepare to receive the next packet */
+static void usb_net_reset_in_buf(USBNetState *s)
+{
+ s->in_ptr = s->in_len = 0;
+ qemu_flush_queued_packets(&s->nic->nc);
+}
+
static int rndis_parse(USBNetState *s, uint8_t *data, int length)
{
uint32_t msg_type;
@@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length)
case RNDIS_RESET_MSG:
rndis_clear_responsequeue(s);
- s->out_ptr = s->in_ptr = s->in_len = 0;
+ s->out_ptr = 0;
+ usb_net_reset_in_buf(s);
return rndis_reset_response(s, (rndis_reset_msg_type *) data);
case RNDIS_KEEPALIVE_MSG:
@@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
int ret = USB_RET_NAK;
if (s->in_ptr > s->in_len) {
- s->in_ptr = s->in_len = 0;
+ usb_net_reset_in_buf(s);
ret = USB_RET_NAK;
return ret;
}
@@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p)
if (s->in_ptr >= s->in_len &&
(is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) {
/* no short packet necessary */
- s->in_ptr = s->in_len = 0;
+ usb_net_reset_in_buf(s);
}
#ifdef TRAFFIC_DEBUG
@@ -1250,20 +1258,32 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
- struct rndis_packet_msg_type *msg;
+ uint8_t *in_buf = s->in_buf;
+ size_t total_size = size;
if (is_rndis(s)) {
- msg = (struct rndis_packet_msg_type *) s->in_buf;
if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
return -1;
}
- if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf))
- return -1;
+ total_size += sizeof(struct rndis_packet_msg_type);
+ }
+ if (total_size > sizeof(s->in_buf)) {
+ return -1;
+ }
+ /* Only accept packet if input buffer is empty */
+ if (s->in_len > 0) {
+ return 0;
+ }
+
+ if (is_rndis(s)) {
+ struct rndis_packet_msg_type *msg;
+
+ msg = (struct rndis_packet_msg_type *)in_buf;
memset(msg, 0, sizeof(struct rndis_packet_msg_type));
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
- msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type));
- msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8);
+ msg->MessageLength = cpu_to_le32(size + sizeof(*msg));
+ msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8);
msg->DataLength = cpu_to_le32(size);
/* msg->OOBDataOffset;
* msg->OOBDataLength;
@@ -1273,14 +1293,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz
* msg->VcHandle;
* msg->Reserved;
*/
- memcpy(msg + 1, buf, size);
- s->in_len = size + sizeof(struct rndis_packet_msg_type);
- } else {
- if (size > sizeof(s->in_buf))
- return -1;
- memcpy(s->in_buf, buf, size);
- s->in_len = size;
+ in_buf += sizeof(*msg);
}
+
+ memcpy(in_buf, buf, size);
+ s->in_len = total_size;
s->in_ptr = 0;
return size;
}
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 2f3e9c03a..6a5da8413 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -34,6 +34,7 @@
#include "monitor.h"
#include "trace.h"
#include "dma.h"
+#include "sysemu.h"
#define EHCI_DEBUG 0
@@ -139,6 +140,7 @@
#define NB_PORTS 6 // Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_QH 100 // Max allowable queue heads in a chain
+#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
/* Internal periodic / asynchronous schedule state machine states
*/
@@ -389,6 +391,9 @@ struct EHCIState {
USBBus bus;
qemu_irq irq;
MemoryRegion mem;
+ MemoryRegion mem_caps;
+ MemoryRegion mem_opreg;
+ MemoryRegion mem_ports;
int companion_count;
/* properties */
@@ -398,10 +403,10 @@ struct EHCIState {
* EHCI spec version 1.0 Section 2.3
* Host Controller Operational Registers
*/
+ uint8_t caps[OPREGBASE];
union {
- uint8_t mmio[MMIO_SIZE];
+ uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
struct {
- uint8_t cap[OPREGBASE];
uint32_t usbcmd;
uint32_t usbsts;
uint32_t usbintr;
@@ -411,9 +416,9 @@ struct EHCIState {
uint32_t asynclistaddr;
uint32_t notused[9];
uint32_t configflag;
- uint32_t portsc[NB_PORTS];
};
};
+ uint32_t portsc[NB_PORTS];
/*
* Internal states, shadow registers, etc
@@ -471,22 +476,12 @@ static const char *ehci_state_names[] = {
};
static const char *ehci_mmio_names[] = {
- [CAPLENGTH] = "CAPLENGTH",
- [HCIVERSION] = "HCIVERSION",
- [HCSPARAMS] = "HCSPARAMS",
- [HCCPARAMS] = "HCCPARAMS",
[USBCMD] = "USBCMD",
[USBSTS] = "USBSTS",
[USBINTR] = "USBINTR",
[FRINDEX] = "FRINDEX",
[PERIODICLISTBASE] = "P-LIST BASE",
[ASYNCLISTADDR] = "A-LIST ADDR",
- [PORTSC_BEGIN] = "PORTSC #0",
- [PORTSC_BEGIN + 4] = "PORTSC #1",
- [PORTSC_BEGIN + 8] = "PORTSC #2",
- [PORTSC_BEGIN + 12] = "PORTSC #3",
- [PORTSC_BEGIN + 16] = "PORTSC #4",
- [PORTSC_BEGIN + 20] = "PORTSC #5",
[CONFIGFLAG] = "CONFIGFLAG",
};
@@ -509,7 +504,8 @@ static const char *state2str(uint32_t state)
static const char *addr2str(target_phys_addr_t addr)
{
- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
+ addr + OPREGBASE);
}
static void ehci_trace_usbsts(uint32_t mask, int state)
@@ -853,10 +849,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr,
return NULL;
}
-static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
+static void ehci_queues_rip_unused(EHCIState *ehci, int async)
{
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
- const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL;
+ const char *warn = async ? "guest unlinked busy QH" : NULL;
uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4;
EHCIQueue *q, *tmp;
@@ -866,13 +862,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush)
q->ts = ehci->last_run_ns;
continue;
}
- if (!flush && ehci->last_run_ns < q->ts + maxage) {
+ if (ehci->last_run_ns < q->ts + maxage) {
continue;
}
ehci_free_queue(q, warn);
}
}
+static void ehci_queues_rip_unseen(EHCIState *ehci, int async)
+{
+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
+ EHCIQueue *q, *tmp;
+
+ QTAILQ_FOREACH_SAFE(q, head, next, tmp) {
+ if (!q->seen) {
+ ehci_free_queue(q, NULL);
+ }
+ }
+}
+
static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async)
{
EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues;
@@ -1018,7 +1026,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
}
s->companion_count++;
- s->mmio[0x05] = (s->companion_count << 4) | portcount;
+ s->caps[0x05] = (s->companion_count << 4) | portcount;
return 0;
}
@@ -1063,7 +1071,8 @@ static void ehci_reset(void *opaque)
}
}
- memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
+ memset(&s->opreg, 0x00, sizeof(s->opreg));
+ memset(&s->portsc, 0x00, sizeof(s->portsc));
s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
s->usbsts = USBSTS_HALT;
@@ -1090,50 +1099,35 @@ static void ehci_reset(void *opaque)
qemu_bh_cancel(s->async_bh);
}
-static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
+static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr,
+ unsigned size)
{
EHCIState *s = ptr;
- uint32_t val;
-
- val = s->mmio[addr];
-
- return val;
+ return s->caps[addr];
}
-static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
+static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr,
+ unsigned size)
{
EHCIState *s = ptr;
uint32_t val;
- val = s->mmio[addr] | (s->mmio[addr+1] << 8);
-
+ val = s->opreg[addr >> 2];
+ trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
return val;
}
-static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
+static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr,
+ unsigned size)
{
EHCIState *s = ptr;
uint32_t val;
- val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
- (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
-
- trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
+ val = s->portsc[addr >> 2];
+ trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val);
return val;
}
-static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val)
-{
- fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n");
- exit(1);
-}
-
-static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
-{
- fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n");
- exit(1);
-}
-
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
{
USBDevice *dev = s->ports[port].dev;
@@ -1162,11 +1156,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
}
}
-static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
+static void ehci_port_write(void *ptr, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
+ EHCIState *s = ptr;
+ int port = addr >> 2;
uint32_t *portsc = &s->portsc[port];
+ uint32_t old = *portsc;
USBDevice *dev = s->ports[port].dev;
+ trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);
+
/* Clear rwc bits */
*portsc &= ~(val & PORTSC_RWC_MASK);
/* The guest may clear, but not set the PED bit */
@@ -1198,39 +1198,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
*portsc &= ~PORTSC_RO_MASK;
*portsc |= val;
+ trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old);
}
-static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
+static void ehci_opreg_write(void *ptr, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
EHCIState *s = ptr;
- uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
+ uint32_t *mmio = s->opreg + (addr >> 2);
uint32_t old = *mmio;
int i;
- trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
-
- /* Only aligned reads are allowed on OHCI */
- if (addr & 3) {
- fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
- TARGET_FMT_plx "\n", addr);
- return;
- }
-
- if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
- handle_port_status_write(s, (addr-PORTSC)/4, val);
- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
- return;
- }
-
- if (addr < OPREGBASE) {
- fprintf(stderr, "usb-ehci: write attempt to read-only register"
- TARGET_FMT_plx "\n", addr);
- return;
- }
+ trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);
-
- /* Do any register specific pre-write processing here. */
- switch(addr) {
+ switch (addr + OPREGBASE) {
case USBCMD:
if (val & USBCMD_HCRESET) {
ehci_reset(s);
@@ -1241,7 +1222,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
/* not supporting dynamic frame list size at the moment */
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
fprintf(stderr, "attempt to set frame list size -- value %d\n",
- val & USBCMD_FLS);
+ (int)val & USBCMD_FLS);
val &= ~USBCMD_FLS;
}
@@ -1308,7 +1289,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
}
*mmio = val;
- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
+ trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old);
}
@@ -1732,7 +1713,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async)
ehci_set_usbsts(ehci, USBSTS_REC);
}
- ehci_queues_rip_unused(ehci, async, 0);
+ ehci_queues_rip_unused(ehci, async);
/* Find the head of the list (4.9.1.1) */
for(i = 0; i < MAX_QH; i++) {
@@ -2364,7 +2345,7 @@ static void ehci_advance_async_state(EHCIState *ehci)
*/
if (ehci->usbcmd & USBCMD_IAAD) {
/* Remove all unseen qhs from the async qhs queue */
- ehci_queues_rip_unused(ehci, async, 1);
+ ehci_queues_rip_unseen(ehci, async);
trace_usb_ehci_doorbell_ack();
ehci->usbcmd &= ~USBCMD_IAAD;
ehci_raise_irq(ehci, USBSTS_IAA);
@@ -2417,7 +2398,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
ehci_set_fetch_addr(ehci, async,entry);
ehci_set_state(ehci, async, EST_FETCHENTRY);
ehci_advance_state(ehci, async);
- ehci_queues_rip_unused(ehci, async, 0);
+ ehci_queues_rip_unused(ehci, async);
break;
default:
@@ -2446,7 +2427,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames)
if (ehci->frindex == 0x00004000) {
ehci_raise_irq(ehci, USBSTS_FLR);
ehci->frindex = 0;
- if (ehci->usbsts_frindex > 0x00004000) {
+ if (ehci->usbsts_frindex >= 0x00004000) {
ehci->usbsts_frindex -= 0x00004000;
} else {
ehci->usbsts_frindex = 0;
@@ -2481,6 +2462,19 @@ static void ehci_frame_timer(void *opaque)
}
for (i = 0; i < frames; i++) {
+ /*
+ * If we're running behind schedule, we should not catch up
+ * too fast, as that will make some guests unhappy:
+ * 1) We must process a minimum of MIN_FR_PER_TICK frames,
+ * otherwise we will never catch up
+ * 2) Process frames until the guest has requested an irq (IOC)
+ */
+ if (i >= MIN_FR_PER_TICK) {
+ ehci_commit_irq(ehci);
+ if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) {
+ break;
+ }
+ }
ehci_update_frindex(ehci, 1);
ehci_advance_periodic_state(ehci);
ehci->last_run_ns += FRAME_TIMER_NS;
@@ -2520,11 +2514,28 @@ static void ehci_async_bh(void *opaque)
ehci_advance_async_state(ehci);
}
-static const MemoryRegionOps ehci_mem_ops = {
- .old_mmio = {
- .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
- .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
- },
+static const MemoryRegionOps ehci_mmio_caps_ops = {
+ .read = ehci_caps_read,
+ .valid.min_access_size = 1,
+ .valid.max_access_size = 4,
+ .impl.min_access_size = 1,
+ .impl.max_access_size = 1,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps ehci_mmio_opreg_ops = {
+ .read = ehci_opreg_read,
+ .write = ehci_opreg_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static const MemoryRegionOps ehci_mmio_port_ops = {
+ .read = ehci_port_read,
+ .write = ehci_port_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
.endianness = DEVICE_LITTLE_ENDIAN,
};
@@ -2562,6 +2573,32 @@ static int usb_ehci_post_load(void *opaque, int version_id)
return 0;
}
+static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
+{
+ EHCIState *ehci = opaque;
+
+ /*
+ * We don't migrate the EHCIQueue-s, instead we rebuild them for the
+ * schedule in guest memory. We must do the rebuilt ASAP, so that
+ * USB-devices which have async handled packages have a packet in the
+ * ep queue to match the completion with.
+ */
+ if (state == RUN_STATE_RUNNING) {
+ ehci_advance_async_state(ehci);
+ }
+
+ /*
+ * The schedule rebuilt from guest memory could cause the migration dest
+ * to miss a QH unlink, and fail to cancel packets, since the unlinked QH
+ * will never have existed on the destination. Therefor we must flush the
+ * async schedule on savevm to catch any not yet noticed unlinks.
+ */
+ if (state == RUN_STATE_SAVE_VM) {
+ ehci_advance_async_state(ehci);
+ ehci_queues_rip_unseen(ehci, 1);
+ }
+}
+
static const VMStateDescription vmstate_ehci = {
.name = "ehci",
.version_id = 2,
@@ -2681,19 +2718,19 @@ static int usb_ehci_initfn(PCIDevice *dev)
pci_conf[0x6e] = 0x00;
pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
- // 2.2 host controller interface version
- s->mmio[0x00] = (uint8_t) OPREGBASE;
- s->mmio[0x01] = 0x00;
- s->mmio[0x02] = 0x00;
- s->mmio[0x03] = 0x01; // HC version
- s->mmio[0x04] = NB_PORTS; // Number of downstream ports
- s->mmio[0x05] = 0x00; // No companion ports at present
- s->mmio[0x06] = 0x00;
- s->mmio[0x07] = 0x00;
- s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable
- s->mmio[0x09] = 0x68; // EECP
- s->mmio[0x0a] = 0x00;
- s->mmio[0x0b] = 0x00;
+ /* 2.2 host controller interface version */
+ s->caps[0x00] = (uint8_t) OPREGBASE;
+ s->caps[0x01] = 0x00;
+ s->caps[0x02] = 0x00;
+ s->caps[0x03] = 0x01; /* HC version */
+ s->caps[0x04] = NB_PORTS; /* Number of downstream ports */
+ s->caps[0x05] = 0x00; /* No companion ports at present */
+ s->caps[0x06] = 0x00;
+ s->caps[0x07] = 0x00;
+ s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
+ s->caps[0x09] = 0x68; /* EECP */
+ s->caps[0x0a] = 0x00;
+ s->caps[0x0b] = 0x00;
s->irq = s->dev.irq[3];
@@ -2711,8 +2748,20 @@ static int usb_ehci_initfn(PCIDevice *dev)
usb_packet_init(&s->ipacket);
qemu_register_reset(ehci_reset, s);
+ qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s);
+
+ memory_region_init(&s->mem, "ehci", MMIO_SIZE);
+ memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
+ "capabilities", OPREGBASE);
+ memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
+ "operational", PORTSC_BEGIN - OPREGBASE);
+ memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
+ "ports", PORTSC_END - PORTSC_BEGIN);
+
+ memory_region_add_subregion(&s->mem, 0, &s->mem_caps);
+ memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg);
+ memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports);
- memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
return 0;
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
index c7c878635..cdc8bc3fb 100644
--- a/hw/usb/hcd-uhci.c
+++ b/hw/usb/hcd-uhci.c
@@ -1000,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
}
assert(ret == TD_RESULT_ASYNC_START);
assert(int_mask == 0);
+ if (ptd.ctrl & TD_CTRL_SPD) {
+ break;
+ }
plink = ptd.link;
}
}
@@ -1097,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s)
case TD_RESULT_ASYNC_START:
trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf);
- if (is_valid(td.link)) {
+ if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) {
uhci_fill_queue(s, &td);
}
link = curr_qh ? qh.link : td.link;
diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c
index 8df92074d..44f1a64b3 100644
--- a/hw/usb/host-linux.c
+++ b/hw/usb/host-linux.c
@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
/* Note request is (bRequestType << 8) | bRequest */
trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index);
- assert(p->result == 0);
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
}
/* The rest are asynchronous */
+ assert(p && p->result == 0);
if (length > sizeof(dev->data_buf)) {
fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n",
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 5301a69c4..b10241a13 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -43,7 +43,6 @@
#define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f))
#define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f))
-typedef struct Cancelled Cancelled;
typedef struct USBRedirDevice USBRedirDevice;
/* Struct to hold buffered packets (iso or int input packets) */
@@ -58,6 +57,7 @@ struct endp_data {
uint8_t type;
uint8_t interval;
uint8_t interface; /* bInterfaceNumber this ep belongs to */
+ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */
uint8_t iso_started;
uint8_t iso_error; /* For reporting iso errors to the HC */
uint8_t interrupt_started;
@@ -65,8 +65,20 @@ struct endp_data {
uint8_t bufpq_prefilled;
uint8_t bufpq_dropping_packets;
QTAILQ_HEAD(, buf_packet) bufpq;
- int bufpq_size;
- int bufpq_target_size;
+ int32_t bufpq_size;
+ int32_t bufpq_target_size;
+};
+
+struct PacketIdQueueEntry {
+ uint64_t id;
+ QTAILQ_ENTRY(PacketIdQueueEntry)next;
+};
+
+struct PacketIdQueue {
+ USBRedirDevice *dev;
+ const char *name;
+ QTAILQ_HEAD(, PacketIdQueueEntry) head;
+ int size;
};
struct USBRedirDevice {
@@ -86,7 +98,8 @@ struct USBRedirDevice {
int64_t next_attach_time;
struct usbredirparser *parser;
struct endp_data endpoint[MAX_ENDPOINTS];
- QTAILQ_HEAD(, Cancelled) cancelled;
+ struct PacketIdQueue cancelled;
+ struct PacketIdQueue already_in_flight;
/* Data for device filtering */
struct usb_redir_device_connect_header device_info;
struct usb_redir_interface_info_header interface_info;
@@ -94,11 +107,6 @@ struct USBRedirDevice {
int filter_rules_count;
};
-struct Cancelled {
- uint64_t id;
- QTAILQ_ENTRY(Cancelled)next;
-};
-
static void usbredir_hello(void *priv, struct usb_redir_hello_header *h);
static void usbredir_device_connect(void *priv,
struct usb_redir_device_connect_header *device_connect);
@@ -134,6 +142,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
static int usbredir_handle_status(USBRedirDevice *dev,
int status, int actual_len);
+#define VERSION "qemu usb-redir guest " QEMU_VERSION
+
/*
* Logging stuff
*/
@@ -232,6 +242,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
return 0;
}
+ /* Don't send new data to the chardev until our state is fully synced */
+ if (!runstate_check(RUN_STATE_RUNNING)) {
+ return 0;
+ }
+
return qemu_chr_fe_write(dev->cs, data, count);
}
@@ -239,37 +254,103 @@ static int usbredir_write(void *priv, uint8_t *data, int count)
* Cancelled and buffered packets helpers
*/
-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
+static void packet_id_queue_init(struct PacketIdQueue *q,
+ USBRedirDevice *dev, const char *name)
{
- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
- Cancelled *c;
+ q->dev = dev;
+ q->name = name;
+ QTAILQ_INIT(&q->head);
+ q->size = 0;
+}
+
+static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id)
+{
+ USBRedirDevice *dev = q->dev;
+ struct PacketIdQueueEntry *e;
+
+ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name);
- DPRINTF("cancel packet id %"PRIu64"\n", p->id);
+ e = g_malloc0(sizeof(struct PacketIdQueueEntry));
+ e->id = id;
+ QTAILQ_INSERT_TAIL(&q->head, e, next);
+ q->size++;
+}
- c = g_malloc0(sizeof(Cancelled));
- c->id = p->id;
- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next);
+static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id)
+{
+ USBRedirDevice *dev = q->dev;
+ struct PacketIdQueueEntry *e;
+
+ QTAILQ_FOREACH(e, &q->head, next) {
+ if (e->id == id) {
+ DPRINTF("removing packet id %"PRIu64" from %s queue\n",
+ id, q->name);
+ QTAILQ_REMOVE(&q->head, e, next);
+ q->size--;
+ g_free(e);
+ return 1;
+ }
+ }
+ return 0;
+}
+static void packet_id_queue_empty(struct PacketIdQueue *q)
+{
+ USBRedirDevice *dev = q->dev;
+ struct PacketIdQueueEntry *e, *next_e;
+
+ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name);
+
+ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) {
+ QTAILQ_REMOVE(&q->head, e, next);
+ g_free(e);
+ }
+ q->size = 0;
+}
+
+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
+{
+ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
+
+ packet_id_queue_add(&dev->cancelled, p->id);
usbredirparser_send_cancel_data_packet(dev->parser, p->id);
usbredirparser_do_write(dev->parser);
}
static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id)
{
- Cancelled *c;
-
if (!dev->dev.attached) {
return 1; /* Treat everything as cancelled after a disconnect */
}
+ return packet_id_queue_remove(&dev->cancelled, id);
+}
+
+static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev,
+ struct USBEndpoint *ep)
+{
+ static USBPacket *p;
+
+ QTAILQ_FOREACH(p, &ep->queue, queue) {
+ packet_id_queue_add(&dev->already_in_flight, p->id);
+ }
+}
- QTAILQ_FOREACH(c, &dev->cancelled, next) {
- if (c->id == id) {
- QTAILQ_REMOVE(&dev->cancelled, c, next);
- g_free(c);
- return 1;
- }
+static void usbredir_fill_already_in_flight(USBRedirDevice *dev)
+{
+ int ep;
+ struct USBDevice *udev = &dev->dev;
+
+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl);
+
+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]);
+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]);
}
- return 0;
+}
+
+static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id)
+{
+ return packet_id_queue_remove(&dev->already_in_flight, id);
}
static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev,
@@ -487,6 +568,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p,
DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id);
+ if (usbredir_already_in_flight(dev, p->id)) {
+ return USB_RET_ASYNC;
+ }
+
bulk_packet.endpoint = ep;
bulk_packet.length = p->iov.size;
bulk_packet.stream_id = 0;
@@ -567,6 +652,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep,
p->iov.size, p->id);
+ if (usbredir_already_in_flight(dev, p->id)) {
+ return USB_RET_ASYNC;
+ }
+
interrupt_packet.endpoint = ep;
interrupt_packet.length = p->iov.size;
@@ -709,6 +798,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p,
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
struct usb_redir_control_packet_header control_packet;
+ if (usbredir_already_in_flight(dev, p->id)) {
+ return USB_RET_ASYNC;
+ }
+
/* Special cases for certain standard device requests */
switch (request) {
case DeviceOutRequest | USB_REQ_SET_ADDRESS:
@@ -763,6 +856,7 @@ static void usbredir_chardev_close_bh(void *opaque)
usbredir_device_disconnect(dev);
if (dev->parser) {
+ DPRINTF("destroying usbredirparser\n");
usbredirparser_destroy(dev->parser);
dev->parser = NULL;
}
@@ -771,14 +865,13 @@ static void usbredir_chardev_close_bh(void *opaque)
static void usbredir_chardev_open(USBRedirDevice *dev)
{
uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, };
- char version[32];
+ int flags = 0;
/* Make sure any pending closes are handled (no-op if none pending) */
usbredir_chardev_close_bh(dev);
qemu_bh_cancel(dev->chardev_close_bh);
- strcpy(version, "qemu usb-redir guest ");
- pstrcat(version, sizeof(version), qemu_get_version());
+ DPRINTF("creating usbredirparser\n");
dev->parser = qemu_oom_check(usbredirparser_create());
dev->parser->priv = dev;
@@ -807,7 +900,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev)
usbredirparser_caps_set_cap(caps, usb_redir_cap_filter);
usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size);
usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids);
- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0);
+
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ flags |= usbredirparser_fl_no_hello;
+ }
+ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE,
+ flags);
usbredirparser_do_write(dev->parser);
}
@@ -853,6 +951,11 @@ static int usbredir_chardev_can_read(void *opaque)
return 0;
}
+ /* Don't read new data from the chardev until our state is fully synced */
+ if (!runstate_check(RUN_STATE_RUNNING)) {
+ return 0;
+ }
+
/* usbredir_parser_do_read will consume *all* data we give it */
return 1024 * 1024;
}
@@ -878,9 +981,11 @@ static void usbredir_chardev_event(void *opaque, int event)
switch (event) {
case CHR_EVENT_OPENED:
+ DPRINTF("chardev open\n");
usbredir_chardev_open(dev);
break;
case CHR_EVENT_CLOSED:
+ DPRINTF("chardev close\n");
qemu_bh_schedule(dev->chardev_close_bh);
break;
}
@@ -890,6 +995,15 @@ static void usbredir_chardev_event(void *opaque, int event)
* init + destroy
*/
+static void usbredir_vm_state_change(void *priv, int running, RunState state)
+{
+ USBRedirDevice *dev = priv;
+
+ if (state == RUN_STATE_RUNNING && dev->parser != NULL) {
+ usbredirparser_do_write(dev->parser); /* Flush any pending writes */
+ }
+}
+
static int usbredir_initfn(USBDevice *udev)
{
USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev);
@@ -914,7 +1028,8 @@ static int usbredir_initfn(USBDevice *udev)
dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev);
dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev);
- QTAILQ_INIT(&dev->cancelled);
+ packet_id_queue_init(&dev->cancelled, dev, "cancelled");
+ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight");
for (i = 0; i < MAX_ENDPOINTS; i++) {
QTAILQ_INIT(&dev->endpoint[i].bufpq);
}
@@ -927,19 +1042,17 @@ static int usbredir_initfn(USBDevice *udev)
qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read,
usbredir_chardev_read, usbredir_chardev_event, dev);
+ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev);
add_boot_device_path(dev->bootindex, &udev->qdev, NULL);
return 0;
}
static void usbredir_cleanup_device_queues(USBRedirDevice *dev)
{
- Cancelled *c, *next_c;
int i;
- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) {
- QTAILQ_REMOVE(&dev->cancelled, c, next);
- g_free(c);
- }
+ packet_id_queue_empty(&dev->cancelled);
+ packet_id_queue_empty(&dev->already_in_flight);
for (i = 0; i < MAX_ENDPOINTS; i++) {
usbredir_free_bufpq(dev, I2EP(i));
}
@@ -1118,6 +1231,7 @@ static void usbredir_device_disconnect(void *priv)
qemu_del_timer(dev->attach_timer);
if (dev->dev.attached) {
+ DPRINTF("detaching device\n");
usb_device_detach(&dev->dev);
/*
* Delay next usb device attach to give the guest a chance to see
@@ -1195,7 +1309,8 @@ static void usbredir_ep_info(void *priv,
usb_ep->ifnum = dev->endpoint[i].interface;
if (usbredirparser_peer_has_cap(dev->parser,
usb_redir_cap_ep_info_max_packet_size)) {
- usb_ep->max_packet_size = ep_info->max_packet_size[i];
+ dev->endpoint[i].max_packet_size =
+ usb_ep->max_packet_size = ep_info->max_packet_size[i];
}
if (ep_info->type[i] == usb_redir_type_bulk) {
usb_ep->pipeline = true;
@@ -1418,6 +1533,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id,
}
}
+/*
+ * Migration code
+ */
+
+static void usbredir_pre_save(void *priv)
+{
+ USBRedirDevice *dev = priv;
+
+ usbredir_fill_already_in_flight(dev);
+}
+
+static int usbredir_post_load(void *priv, int version_id)
+{
+ USBRedirDevice *dev = priv;
+ struct USBEndpoint *usb_ep;
+ int i;
+
+ switch (dev->device_info.speed) {
+ case usb_redir_speed_low:
+ dev->dev.speed = USB_SPEED_LOW;
+ break;
+ case usb_redir_speed_full:
+ dev->dev.speed = USB_SPEED_FULL;
+ break;
+ case usb_redir_speed_high:
+ dev->dev.speed = USB_SPEED_HIGH;
+ break;
+ case usb_redir_speed_super:
+ dev->dev.speed = USB_SPEED_SUPER;
+ break;
+ default:
+ dev->dev.speed = USB_SPEED_FULL;
+ }
+ dev->dev.speedmask = (1 << dev->dev.speed);
+
+ for (i = 0; i < MAX_ENDPOINTS; i++) {
+ usb_ep = usb_ep_get(&dev->dev,
+ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT,
+ i & 0x0f);
+ usb_ep->type = dev->endpoint[i].type;
+ usb_ep->ifnum = dev->endpoint[i].interface;
+ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size;
+ if (dev->endpoint[i].type == usb_redir_type_bulk) {
+ usb_ep->pipeline = true;
+ }
+ }
+ return 0;
+}
+
+/* For usbredirparser migration */
+static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused)
+{
+ USBRedirDevice *dev = priv;
+ uint8_t *data;
+ int len;
+
+ if (dev->parser == NULL) {
+ qemu_put_be32(f, 0);
+ return;
+ }
+
+ usbredirparser_serialize(dev->parser, &data, &len);
+ qemu_oom_check(data);
+
+ qemu_put_be32(f, len);
+ qemu_put_buffer(f, data, len);
+
+ free(data);
+}
+
+static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused)
+{
+ USBRedirDevice *dev = priv;
+ uint8_t *data;
+ int len, ret;
+
+ len = qemu_get_be32(f);
+ if (len == 0) {
+ return 0;
+ }
+
+ /*
+ * Our chardev should be open already at this point, otherwise
+ * the usbredir channel will be broken (ie spice without seamless)
+ */
+ if (dev->parser == NULL) {
+ ERROR("get_parser called with closed chardev, failing migration\n");
+ return -1;
+ }
+
+ data = g_malloc(len);
+ qemu_get_buffer(f, data, len);
+
+ ret = usbredirparser_unserialize(dev->parser, data, len);
+
+ g_free(data);
+
+ return ret;
+}
+
+static const VMStateInfo usbredir_parser_vmstate_info = {
+ .name = "usb-redir-parser",
+ .put = usbredir_put_parser,
+ .get = usbredir_get_parser,
+};
+
+
+/* For buffered packets (iso/irq) queue migration */
+static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused)
+{
+ struct endp_data *endp = priv;
+ struct buf_packet *bufp;
+ int remain = endp->bufpq_size;
+
+ qemu_put_be32(f, endp->bufpq_size);
+ QTAILQ_FOREACH(bufp, &endp->bufpq, next) {
+ qemu_put_be32(f, bufp->len);
+ qemu_put_be32(f, bufp->status);
+ qemu_put_buffer(f, bufp->data, bufp->len);
+ remain--;
+ }
+ assert(remain == 0);
+}
+
+static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused)
+{
+ struct endp_data *endp = priv;
+ struct buf_packet *bufp;
+ int i;
+
+ endp->bufpq_size = qemu_get_be32(f);
+ for (i = 0; i < endp->bufpq_size; i++) {
+ bufp = g_malloc(sizeof(struct buf_packet));
+ bufp->len = qemu_get_be32(f);
+ bufp->status = qemu_get_be32(f);
+ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */
+ qemu_get_buffer(f, bufp->data, bufp->len);
+ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next);
+ }
+ return 0;
+}
+
+static const VMStateInfo usbredir_ep_bufpq_vmstate_info = {
+ .name = "usb-redir-bufpq",
+ .put = usbredir_put_bufpq,
+ .get = usbredir_get_bufpq,
+};
+
+
+/* For endp_data migration */
+static const VMStateDescription usbredir_ep_vmstate = {
+ .name = "usb-redir-ep",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(type, struct endp_data),
+ VMSTATE_UINT8(interval, struct endp_data),
+ VMSTATE_UINT8(interface, struct endp_data),
+ VMSTATE_UINT16(max_packet_size, struct endp_data),
+ VMSTATE_UINT8(iso_started, struct endp_data),
+ VMSTATE_UINT8(iso_error, struct endp_data),
+ VMSTATE_UINT8(interrupt_started, struct endp_data),
+ VMSTATE_UINT8(interrupt_error, struct endp_data),
+ VMSTATE_UINT8(bufpq_prefilled, struct endp_data),
+ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data),
+ {
+ .name = "bufpq",
+ .version_id = 0,
+ .field_exists = NULL,
+ .size = 0,
+ .info = &usbredir_ep_bufpq_vmstate_info,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_INT32(bufpq_target_size, struct endp_data),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+/* For PacketIdQueue migration */
+static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused)
+{
+ struct PacketIdQueue *q = priv;
+ USBRedirDevice *dev = q->dev;
+ struct PacketIdQueueEntry *e;
+ int remain = q->size;
+
+ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size);
+ qemu_put_be32(f, q->size);
+ QTAILQ_FOREACH(e, &q->head, next) {
+ qemu_put_be64(f, e->id);
+ remain--;
+ }
+ assert(remain == 0);
+}
+
+static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused)
+{
+ struct PacketIdQueue *q = priv;
+ USBRedirDevice *dev = q->dev;
+ int i, size;
+ uint64_t id;
+
+ size = qemu_get_be32(f);
+ DPRINTF("get_packet_id_q %s size %d\n", q->name, size);
+ for (i = 0; i < size; i++) {
+ id = qemu_get_be64(f);
+ packet_id_queue_add(q, id);
+ }
+ assert(q->size == size);
+ return 0;
+}
+
+static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = {
+ .name = "usb-redir-packet-id-q",
+ .put = usbredir_put_packet_id_q,
+ .get = usbredir_get_packet_id_q,
+};
+
+static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = {
+ .name = "usb-redir-packet-id-queue",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ {
+ .name = "queue",
+ .version_id = 0,
+ .field_exists = NULL,
+ .size = 0,
+ .info = &usbredir_ep_packet_id_q_vmstate_info,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+/* For usb_redir_device_connect_header migration */
+static const VMStateDescription usbredir_device_info_vmstate = {
+ .name = "usb-redir-device-info",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header),
+ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header),
+ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header),
+ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header),
+ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header),
+ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header),
+ VMSTATE_UINT16(device_version_bcd,
+ struct usb_redir_device_connect_header),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+/* For usb_redir_interface_info_header migration */
+static const VMStateDescription usbredir_interface_info_vmstate = {
+ .name = "usb-redir-interface-info",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(interface_count,
+ struct usb_redir_interface_info_header),
+ VMSTATE_UINT8_ARRAY(interface,
+ struct usb_redir_interface_info_header, 32),
+ VMSTATE_UINT8_ARRAY(interface_class,
+ struct usb_redir_interface_info_header, 32),
+ VMSTATE_UINT8_ARRAY(interface_subclass,
+ struct usb_redir_interface_info_header, 32),
+ VMSTATE_UINT8_ARRAY(interface_protocol,
+ struct usb_redir_interface_info_header, 32),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+/* And finally the USBRedirDevice vmstate itself */
+static const VMStateDescription usbredir_vmstate = {
+ .name = "usb-redir",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .pre_save = usbredir_pre_save,
+ .post_load = usbredir_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_USB_DEVICE(dev, USBRedirDevice),
+ VMSTATE_TIMER(attach_timer, USBRedirDevice),
+ {
+ .name = "parser",
+ .version_id = 0,
+ .field_exists = NULL,
+ .size = 0,
+ .info = &usbredir_parser_vmstate_info,
+ .flags = VMS_SINGLE,
+ .offset = 0,
+ },
+ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1,
+ usbredir_ep_vmstate, struct endp_data),
+ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1,
+ usbredir_ep_packet_id_queue_vmstate,
+ struct PacketIdQueue),
+ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1,
+ usbredir_ep_packet_id_queue_vmstate,
+ struct PacketIdQueue),
+ VMSTATE_STRUCT(device_info, USBRedirDevice, 1,
+ usbredir_device_info_vmstate,
+ struct usb_redir_device_connect_header),
+ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1,
+ usbredir_interface_info_vmstate,
+ struct usb_redir_interface_info_header),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static Property usbredir_properties[] = {
DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
@@ -1438,6 +1869,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data)
uc->handle_reset = usbredir_handle_reset;
uc->handle_data = usbredir_handle_data;
uc->handle_control = usbredir_handle_control;
+ dc->vmsd = &usbredir_vmstate;
dc->props = usbredir_properties;
}
diff --git a/hw/vga-isa-mm.c b/hw/vga-isa-mm.c
index 44ae7d92c..306e6ba44 100644
--- a/hw/vga-isa-mm.c
+++ b/hw/vga-isa-mm.c
@@ -107,6 +107,7 @@ static void vga_mm_init(ISAVGAMMState *s, target_phys_addr_t vram_base,
s_ioport_ctrl = g_malloc(sizeof(*s_ioport_ctrl));
memory_region_init_io(s_ioport_ctrl, &vga_mm_ctrl_ops, s,
"vga-mm-ctrl", 0x100000);
+ memory_region_set_flush_coalesced(s_ioport_ctrl);
vga_io_memory = g_malloc(sizeof(*vga_io_memory));
/* XXX: endianness? */
diff --git a/hw/vga.c b/hw/vga.c
index 80299ea1d..afaef0d71 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -361,6 +361,8 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr)
VGACommonState *s = opaque;
int val, index;
+ qemu_flush_coalesced_mmio_buffer();
+
if (vga_ioport_invalid(s, addr)) {
val = 0xff;
} else {
@@ -453,6 +455,8 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
VGACommonState *s = opaque;
int index;
+ qemu_flush_coalesced_mmio_buffer();
+
/* check port range access depending on color/monochrome mode */
if (vga_ioport_invalid(s, addr)) {
return;
@@ -2338,6 +2342,7 @@ MemoryRegion *vga_init_io(VGACommonState *s,
vga_mem = g_malloc(sizeof(*vga_mem));
memory_region_init_io(vga_mem, &vga_mem_ops, s,
"vga-lowmem", 0x20000);
+ memory_region_set_flush_coalesced(vga_mem);
return vga_mem;
}
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index b1998b27d..649074329 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
VirtIONet *n = to_virtio_net(vdev);
qemu_flush_queued_packets(&n->nic->nc);
-
- /* We now have RX buffers, signal to the IO thread to break out of the
- * select to re-poll the tap file descriptor */
- qemu_notify_event();
}
static int virtio_net_can_receive(NetClientState *nc)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index b68e88367..e815a04e9 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1186,6 +1186,7 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
memory_region_init_io(&s->io_bar, &vmsvga_io_ops, &s->chip,
"vmsvga-io", 0x10);
+ memory_region_set_flush_coalesced(&s->io_bar);
pci_register_bar(&s->card, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io_bar);
vmsvga_init(&s->chip, pci_address_space(dev),
diff --git a/hw/xen-host-pci-device.c b/hw/xen-host-pci-device.c
index e7ff680ef..743b37b99 100644
--- a/hw/xen-host-pci-device.c
+++ b/hw/xen-host-pci-device.c
@@ -47,13 +47,13 @@ static int xen_host_pci_sysfs_path(const XenHostPCIDevice *d,
}
-/* This size should be enough to read the first 7 lines of a ressource file */
-#define XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE 400
+/* This size should be enough to read the first 7 lines of a resource file */
+#define XEN_HOST_PCI_RESOURCE_BUFFER_SIZE 400
static int xen_host_pci_get_resource(XenHostPCIDevice *d)
{
int i, rc, fd;
char path[PATH_MAX];
- char buf[XEN_HOST_PCI_RESSOURCE_BUFFER_SIZE];
+ char buf[XEN_HOST_PCI_RESOURCE_BUFFER_SIZE];
unsigned long long start, end, flags, size;
char *endptr, *s;
uint8_t type;
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index 8b79bfb73..cf7d5591b 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -415,6 +415,7 @@ static void net_event(struct XenDevice *xendev)
{
struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev);
net_tx_packets(netdev);
+ qemu_flush_queued_packets(&netdev->nic->nc);
}
static int net_free(struct XenDevice *xendev)
diff --git a/hw/xen_pt.h b/hw/xen_pt.h
index 41904ece9..112477a88 100644
--- a/hw/xen_pt.h
+++ b/hw/xen_pt.h
@@ -96,7 +96,7 @@ typedef struct XenPTRegion {
* - do NOT use ALL F for init_val, otherwise the tbl will not be registered.
*/
-/* emulated register infomation */
+/* emulated register information */
struct XenPTRegInfo {
uint32_t offset;
uint32_t size;
@@ -140,7 +140,7 @@ typedef int (*xen_pt_reg_size_init_fn)
(XenPCIPassthroughState *, const XenPTRegGroupInfo *,
uint32_t base_offset, uint8_t *size);
-/* emulated register group infomation */
+/* emulated register group information */
struct XenPTRegGroupInfo {
uint8_t grp_id;
XenPTRegisterGroupType grp_type;
diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c
index 00eb3d997..e524a4094 100644
--- a/hw/xen_pt_config_init.c
+++ b/hw/xen_pt_config_init.c
@@ -562,7 +562,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s,
return 0;
}
-/* Header Type0 reg static infomation table */
+/* Header Type0 reg static information table */
static XenPTRegInfo xen_pt_emu_reg_header0[] = {
/* Vendor ID reg */
{
@@ -753,7 +753,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = {
* Vital Product Data Capability
*/
-/* Vital Product Data Capability Structure reg static infomation table */
+/* Vital Product Data Capability Structure reg static information table */
static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
{
.offset = PCI_CAP_LIST_NEXT,
@@ -775,7 +775,7 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = {
* Vendor Specific Capability
*/
-/* Vendor Specific Capability Structure reg static infomation table */
+/* Vendor Specific Capability Structure reg static information table */
static XenPTRegInfo xen_pt_emu_reg_vendor[] = {
{
.offset = PCI_CAP_LIST_NEXT,
@@ -866,7 +866,7 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s,
return 0;
}
-/* PCI Express Capability Structure reg static infomation table */
+/* PCI Express Capability Structure reg static information table */
static XenPTRegInfo xen_pt_emu_reg_pcie[] = {
/* Next Pointer reg */
{
@@ -981,7 +981,7 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s,
return 0;
}
-/* Power Management Capability reg static infomation table */
+/* Power Management Capability reg static information table */
static XenPTRegInfo xen_pt_emu_reg_pm[] = {
/* Next Pointer reg */
{
@@ -1259,7 +1259,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
return 0;
}
-/* MSI Capability Structure reg static infomation table */
+/* MSI Capability Structure reg static information table */
static XenPTRegInfo xen_pt_emu_reg_msi[] = {
/* Next Pointer reg */
{
@@ -1396,7 +1396,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s,
return 0;
}
-/* MSI-X Capability Structure reg static infomation table */
+/* MSI-X Capability Structure reg static information table */
static XenPTRegInfo xen_pt_emu_reg_msix[] = {
/* Next Pointer reg */
{
diff --git a/hw/xilinx.h b/hw/xilinx.h
index 556c5aa9f..98300477a 100644
--- a/hw/xilinx.h
+++ b/hw/xilinx.h
@@ -21,9 +21,9 @@ xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq)
{
DeviceState *dev;
- dev = qdev_create(NULL, "xlnx,xps-timer");
+ dev = qdev_create(NULL, "xlnx.xps-timer");
qdev_prop_set_uint32(dev, "one-timer-only", oto);
- qdev_prop_set_uint32(dev, "frequency", freq);
+ qdev_prop_set_uint32(dev, "clock-frequency", freq);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
@@ -55,13 +55,17 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer,
int txmem, int rxmem)
{
DeviceState *dev;
+ Error *errp = NULL;
+
qemu_check_nic_model(nd, "xlnx.axi-ethernet");
dev = qdev_create(NULL, "xlnx.axi-ethernet");
qdev_set_nic_properties(dev, nd);
qdev_prop_set_uint32(dev, "rxmem", rxmem);
qdev_prop_set_uint32(dev, "txmem", txmem);
- object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected",
+ &errp);
+ assert_no_error(errp);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq);
@@ -74,8 +78,12 @@ xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer,
target_phys_addr_t base, qemu_irq irq,
qemu_irq irq2, int freqhz)
{
+ Error *errp = NULL;
+
qdev_prop_set_uint32(dev, "freqhz", freqhz);
- object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL);
+ object_property_set_link(OBJECT(dev), OBJECT(peer), "axistream-connected",
+ &errp);
+ assert_no_error(errp);
qdev_init_nofail(dev);
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index b562bd065..2e48ca2be 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -24,6 +24,7 @@
#include "sysbus.h"
#include "ptimer.h"
+#include "qemu-log.h"
#define D(x)
@@ -119,7 +120,7 @@ timer_read(void *opaque, target_phys_addr_t addr, unsigned int size)
break;
}
- D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
+ D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r));
return r;
}
@@ -127,7 +128,7 @@ static void timer_enable(struct xlx_timer *xt)
{
uint64_t count;
- D(printf("%s timer=%d down=%d\n", __func__,
+ D(fprintf(stderr, "%s timer=%d down=%d\n", __func__,
xt->nr, xt->regs[R_TCSR] & TCSR_UDT));
ptimer_stop(xt->ptimer);
@@ -152,7 +153,7 @@ timer_write(void *opaque, target_phys_addr_t addr,
addr >>= 2;
timer = timer_from_addr(addr);
xt = &t->timers[timer];
- D(printf("%s addr=%x val=%x (timer=%d off=%d)\n",
+ D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n",
__func__, addr * 4, value, timer, addr & 3));
/* Further decoding to address a specific timers reg. */
addr &= 3;
@@ -189,7 +190,7 @@ static void timer_hit(void *opaque)
{
struct xlx_timer *xt = opaque;
struct timerblock *t = xt->parent;
- D(printf("%s %d\n", __func__, timer));
+ D(fprintf(stderr, "%s %d\n", __func__, xt->nr));
xt->regs[R_TCSR] |= TCSR_TINT;
if (xt->regs[R_TCSR] & TCSR_ARHT)
@@ -217,14 +218,15 @@ static int xilinx_timer_init(SysBusDevice *dev)
ptimer_set_freq(xt->ptimer, t->freq_hz);
}
- memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx,xps-timer",
+ memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer",
R_MAX * 4 * num_timers(t));
sysbus_init_mmio(dev, &t->mmio);
return 0;
}
static Property xilinx_timer_properties[] = {
- DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 62 * 1000000),
+ DEFINE_PROP_UINT32("clock-frequency", struct timerblock, freq_hz,
+ 62 * 1000000),
DEFINE_PROP_UINT8("one-timer-only", struct timerblock, one_timer_only, 0),
DEFINE_PROP_END_OF_LIST(),
};
@@ -239,7 +241,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data)
}
static TypeInfo xilinx_timer_info = {
- .name = "xlnx,xps-timer",
+ .name = "xlnx.xps-timer",
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(struct timerblock),
.class_init = xilinx_timer_class_init,