[Spice-devel] [RfC PATCH 7/7] async qxl I/O
Gerd Hoffmann
kraxel at redhat.com
Wed Jun 22 01:46:06 PDT 2011
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
---
hw/qxl.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
hw/qxl.h | 3 +
2 files changed, 133 insertions(+), 4 deletions(-)
diff --git a/hw/qxl.c b/hw/qxl.c
index 03c871a..60caff9 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -28,6 +28,18 @@
#include "qxl.h"
+/* old spice-protocol */
+#ifndef QXL_INTERRUPT_IO_CMD
+#define QXL_INTERRUPT_IO_CMD (1 << 2)
+#define QXL_IO_UPDATE_AREA_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +1)
+#define QXL_IO_NOTIFY_OOM_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +2)
+#define QXL_IO_MEMSLOT_ADD_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +3)
+#define QXL_IO_CREATE_PRIMARY_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +4)
+#define QXL_IO_DESTROY_PRIMARY_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +5)
+#define QXL_IO_DESTROY_SURFACE_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +6)
+#define QXL_IO_DESTROY_ALL_SURFACES_ASYNC (QXL_IO_DESTROY_ALL_SURFACES +7)
+#endif
+
#undef SPICE_RING_PROD_ITEM
#define SPICE_RING_PROD_ITEM(r, ret) { \
typeof(r) start = r; \
@@ -910,22 +922,90 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
qxl_rom_set_dirty(d);
}
+struct qxl_io_async {
+ QXLDevMemSlot memslot;
+ QXLDevSurfaceCreate surface;
+ QXLRect update_area;
+ uint32_t update_surface;
+ uint32_t port;
+ uint32_t val;
+};
+
+static void *ioport_write_async(void *arg)
+{
+ PCIQXLDevice *d = arg;
+ struct qxl_io_async *io;
+ uint32_t io_port;
+ uint32_t val;
+ int ret;
+
+ while (true) {
+ ret = read(d->aio_pipe[0], &io, sizeof(io));
+ if (ret != sizeof(io)) {
+ break;
+ }
+ io_port = io->port;
+ val = io->val;
+
+ fprintf(stderr, "%s: 0x%x\n", __FUNCTION__, io_port);
+ switch (io_port) {
+ case QXL_IO_UPDATE_AREA_ASYNC:
+ qemu_spice_update_area(&d->ssd, io->update_surface,
+ &io->update_area, NULL, 0, 0);
+ break;
+ case QXL_IO_NOTIFY_OOM_ASYNC:
+ d->oom_running = 1;
+ qemu_spice_oom(&d->ssd);
+ d->oom_running = 0;
+ break;
+ case QXL_IO_MEMSLOT_ADD_ASYNC:
+ qemu_spice_add_memslot(&d->ssd, &io->memslot);
+ break;
+ case QXL_IO_CREATE_PRIMARY_ASYNC:
+ qemu_spice_create_primary_surface(&d->ssd, 0, &io->surface);
+ break;
+ case QXL_IO_DESTROY_PRIMARY_ASYNC:
+ qemu_spice_destroy_primary_surface(&d->ssd, 0);
+ break;
+ case QXL_IO_DESTROY_SURFACE_ASYNC:
+ qemu_spice_destroy_surface_wait(&d->ssd, val);
+ break;
+ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+ qemu_spice_destroy_surfaces(&d->ssd);
+ break;
+ }
+ qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+ qemu_free(io);
+ }
+ qemu_thread_exit(NULL);
+ return NULL;
+}
+
static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PCIQXLDevice *d = opaque;
uint32_t io_port = addr - d->io_base;
+ struct qxl_io_async *async;
+ int ret;
switch (io_port) {
case QXL_IO_RESET:
case QXL_IO_SET_MODE:
case QXL_IO_MEMSLOT_ADD:
+ case QXL_IO_MEMSLOT_ADD_ASYNC:
case QXL_IO_MEMSLOT_DEL:
case QXL_IO_CREATE_PRIMARY:
+ case QXL_IO_CREATE_PRIMARY_ASYNC:
break;
default:
if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
break;
dprint(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
+ /* be nice to buggy guest drivers */
+ if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
+ io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
+ qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+ }
return;
}
@@ -1010,6 +1090,46 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
case QXL_IO_DESTROY_ALL_SURFACES:
qemu_spice_destroy_surfaces(&d->ssd);
break;
+ case QXL_IO_MEMSLOT_ADD_ASYNC:
+ PANIC_ON(val >= NUM_MEMSLOTS);
+ PANIC_ON(d->guest_slots[val].active);
+ d->guest_slots[val].slot = d->ram->mem_slot;
+ async = qemu_mallocz(sizeof(*async));
+ qxl_add_memslot(d, val, 0, &async->memslot);
+ goto async_common;
+ case QXL_IO_CREATE_PRIMARY_ASYNC:
+ PANIC_ON(val != 0);
+ dprint(d, 1, "QXL_IO_CREATE_PRIMARY_ASYNC\n");
+ d->guest_primary.surface = d->ram->create_surface;
+ async = qemu_mallocz(sizeof(*async));
+ qxl_create_guest_primary(d, 0, &async->surface);
+ goto async_common;
+ case QXL_IO_DESTROY_PRIMARY_ASYNC:
+ PANIC_ON(val != 0);
+ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC\n");
+ if (d->mode != QXL_MODE_UNDEFINED) {
+ d->mode = QXL_MODE_UNDEFINED;
+ async = qemu_mallocz(sizeof(*async));
+ goto async_common;
+ } else {
+ qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
+ break;
+ }
+ case QXL_IO_UPDATE_AREA_ASYNC:
+ async = qemu_mallocz(sizeof(*async));
+ async->update_area = d->ram->update_area;
+ async->update_surface = d->ram->update_surface;
+ goto async_common;
+ case QXL_IO_NOTIFY_OOM_ASYNC:
+ case QXL_IO_DESTROY_SURFACE_ASYNC:
+ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
+ async = qemu_mallocz(sizeof(*async));
+ async_common:
+ async->port = io_port;
+ async->val = val;
+ ret = write(d->aio_pipe[1], &async, sizeof(async));
+ assert(ret == sizeof(async));
+ break;
default:
fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
abort();
@@ -1095,7 +1215,8 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
static void init_pipe_signaling(PCIQXLDevice *d)
{
- if (pipe(d->pipe) < 0) {
+ if (pipe(d->pipe) < 0 ||
+ pipe(d->aio_pipe) < 0 ) {
dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
return;
}
@@ -1233,6 +1354,10 @@ static int qxl_init_common(PCIQXLDevice *qxl)
pci_device_id = QXL_DEVICE_ID_STABLE;
pci_device_rev = QXL_REVISION_STABLE_V06;
break;
+ case 3: /* qxl-3 */
+ pci_device_id = QXL_DEVICE_ID_STABLE;
+ pci_device_rev = 3;
+ break;
default: /* experimental */
pci_device_id = QXL_DEVICE_ID_DEVEL;
pci_device_rev = 1;
@@ -1258,7 +1383,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);
- io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
+ io_size = msb_mask((QXL_IO_RANGE_SIZE+7) * 2 - 1);
if (qxl->revision == 1) {
io_size = 8;
}
@@ -1282,6 +1407,7 @@ static int qxl_init_common(PCIQXLDevice *qxl)
qemu_spice_add_interface(&qxl->ssd.qxl.base);
qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
+ qemu_thread_create(&qxl->aio_thread, ioport_write_async, qxl);
init_pipe_signaling(qxl);
qxl_reset_state(qxl);
@@ -1504,7 +1630,7 @@ static PCIDeviceInfo qxl_info_primary = {
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+ DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 3),
DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
@@ -1522,7 +1648,7 @@ static PCIDeviceInfo qxl_info_secondary = {
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
- DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2),
+ DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 3),
DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0),
DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
diff --git a/hw/qxl.h b/hw/qxl.h
index f6c450d..6dd38e6 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -30,6 +30,9 @@ typedef struct PCIQXLDevice {
int32_t num_memslots;
int32_t num_surfaces;
+ QemuThread aio_thread;
+ int aio_pipe[2];
+
struct guest_slots {
QXLMemSlot slot;
void *ptr;
--
1.7.1
More information about the Spice-devel
mailing list