fc5c27b
>From a1950cb3afb36a78df3ac9a545d99baf7cc93ca2 Mon Sep 17 00:00:00 2001
13f703f
From: Alon Levy <alevy@redhat.com>
13f703f
Date: Thu, 23 Jun 2011 20:02:18 +0200
fc5c27b
Subject: [PATCH 20/28] qxl: async io support using new spice api
13f703f
13f703f
Some of the QXL port i/o commands are waiting for the spice server to
13f703f
complete certain actions.  Add async versions for these commands, so we
13f703f
don't block the vcpu while the spice server processses the command.
13f703f
Instead the qxl device will raise an IRQ when done.
13f703f
13f703f
The async command processing relies on an added QXLInterface::async_complete
13f703f
and added QXLWorker::*_async additions, in spice server qxl >= 3.1
13f703f
13f703f
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
13f703f
Signed-off-by: Alon Levy     <alevy@redhat.com>
13f703f
---
13f703f
 hw/qxl-render.c    |    2 +-
13f703f
 hw/qxl.c           |  240 ++++++++++++++++++++++++++++++++++++++++++++--------
13f703f
 hw/qxl.h           |   16 +++-
13f703f
 ui/spice-display.c |   47 ++++++++--
13f703f
 ui/spice-display.h |   23 +++++-
13f703f
 5 files changed, 274 insertions(+), 54 deletions(-)
13f703f
13f703f
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
13f703f
index 60b822d..643ff2d 100644
13f703f
--- a/hw/qxl-render.c
13f703f
+++ b/hw/qxl-render.c
13f703f
@@ -125,7 +125,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
13f703f
 
13f703f
     memset(dirty, 0, sizeof(dirty));
13f703f
     qxl_spice_update_area(qxl, 0, &update,
13f703f
-                          dirty, ARRAY_SIZE(dirty), 1);
13f703f
+                          dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC);
13f703f
 
13f703f
     for (i = 0; i < ARRAY_SIZE(dirty); i++) {
13f703f
         if (qemu_spice_rect_is_empty(dirty+i)) {
13f703f
diff --git a/hw/qxl.c b/hw/qxl.c
13f703f
index 23e3240..d3109e4 100644
13f703f
--- a/hw/qxl.c
13f703f
+++ b/hw/qxl.c
13f703f
@@ -120,7 +120,7 @@ static QXLMode qxl_modes[] = {
13f703f
 static PCIQXLDevice *qxl0;
13f703f
 
13f703f
 static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
13f703f
-static void qxl_destroy_primary(PCIQXLDevice *d);
13f703f
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async);
13f703f
 static void qxl_reset_memslots(PCIQXLDevice *d);
13f703f
 static void qxl_reset_surfaces(PCIQXLDevice *d);
13f703f
 static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
13f703f
@@ -144,22 +144,47 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
13f703f
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
13f703f
                            struct QXLRect *area, struct QXLRect *dirty_rects,
13f703f
                            uint32_t num_dirty_rects,
13f703f
-                           uint32_t clear_dirty_region)
13f703f
+                           uint32_t clear_dirty_region,
13f703f
+                           qxl_async_io async)
13f703f
 {
13f703f
-    qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects,
13f703f
-                             num_dirty_rects, clear_dirty_region);
13f703f
+    if (async == QXL_SYNC) {
13f703f
+        qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area,
13f703f
+                        dirty_rects, num_dirty_rects, clear_dirty_region);
13f703f
+    } else {
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+        spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area,
13f703f
+                                    clear_dirty_region, 0);
13f703f
+#else
13f703f
+        abort();
13f703f
+#endif
13f703f
+    }
13f703f
 }
13f703f
 
13f703f
-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id)
13f703f
+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl,
13f703f
+                                                    uint32_t id)
13f703f
 {
13f703f
     qemu_mutex_lock(&qxl->track_lock);
13f703f
-    PANIC_ON(id >= NUM_SURFACES);
13f703f
-    qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
13f703f
     qxl->guest_surfaces.cmds[id] = 0;
13f703f
     qxl->guest_surfaces.count--;
13f703f
     qemu_mutex_unlock(&qxl->track_lock);
13f703f
 }
13f703f
 
13f703f
+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id,
13f703f
+                                           qxl_async_io async)
13f703f
+{
13f703f
+    if (async) {
13f703f
+#if SPICE_INTERFACE_QXL_MINOR < 1
13f703f
+        abort();
13f703f
+#else
13f703f
+        spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id,
13f703f
+                                        (uint64_t)id);
13f703f
+#endif
13f703f
+    } else {
13f703f
+        qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id);
13f703f
+        qxl_spice_destroy_surface_wait_complete(qxl, id);
13f703f
+    }
13f703f
+}
13f703f
+
13f703f
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
13f703f
                                uint32_t count)
13f703f
 {
13f703f
@@ -176,15 +201,28 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl)
13f703f
     qxl->ssd.worker->reset_memslots(qxl->ssd.worker);
13f703f
 }
13f703f
 
13f703f
-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl)
13f703f
+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl)
13f703f
 {
13f703f
     qemu_mutex_lock(&qxl->track_lock);
13f703f
-    qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
13f703f
     memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds));
13f703f
     qxl->guest_surfaces.count = 0;
13f703f
     qemu_mutex_unlock(&qxl->track_lock);
13f703f
 }
13f703f
 
13f703f
+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async)
13f703f
+{
13f703f
+    if (async) {
13f703f
+#if SPICE_INTERFACE_QXL_MINOR < 1
13f703f
+        abort();
13f703f
+#else
13f703f
+        spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0);
13f703f
+#endif
13f703f
+    } else {
13f703f
+        qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker);
13f703f
+        qxl_spice_destroy_surfaces_complete(qxl);
13f703f
+    }
13f703f
+}
13f703f
+
13f703f
 void qxl_spice_reset_image_cache(PCIQXLDevice *qxl)
13f703f
 {
13f703f
     qxl->ssd.worker->reset_image_cache(qxl->ssd.worker);
13f703f
@@ -689,6 +727,38 @@ static int interface_flush_resources(QXLInstance *sin)
13f703f
     return ret;
13f703f
 }
13f703f
 
13f703f
+static void qxl_create_guest_primary_complete(PCIQXLDevice *d);
13f703f
+
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+
13f703f
+/* called from spice server thread context only */
13f703f
+static void interface_async_complete(QXLInstance *sin, uint64_t cookie)
13f703f
+{
13f703f
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
13f703f
+    uint32_t current_async;
13f703f
+
13f703f
+    qemu_mutex_lock(&qxl->async_lock);
13f703f
+    current_async = qxl->current_async;
13f703f
+    qxl->current_async = QXL_UNDEFINED_IO;
13f703f
+    qemu_mutex_unlock(&qxl->async_lock);
13f703f
+
13f703f
+    dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie);
13f703f
+    switch (current_async) {
13f703f
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
13f703f
+        qxl_create_guest_primary_complete(qxl);
13f703f
+        break;
13f703f
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
13f703f
+        qxl_spice_destroy_surfaces_complete(qxl);
13f703f
+        break;
13f703f
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
13f703f
+        qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie);
13f703f
+        break;
13f703f
+    }
13f703f
+    qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD);
13f703f
+}
13f703f
+
13f703f
+#endif
13f703f
+
13f703f
 static const QXLInterface qxl_interface = {
13f703f
     .base.type               = SPICE_INTERFACE_QXL,
13f703f
     .base.description        = "qxl gpu",
13f703f
@@ -708,6 +778,9 @@ static const QXLInterface qxl_interface = {
13f703f
     .req_cursor_notification = interface_req_cursor_notification,
13f703f
     .notify_update           = interface_notify_update,
13f703f
     .flush_resources         = interface_flush_resources,
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+    .async_complete          = interface_async_complete,
13f703f
+#endif
13f703f
 };
13f703f
 
13f703f
 static void qxl_enter_vga_mode(PCIQXLDevice *d)
13f703f
@@ -727,7 +800,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
13f703f
         return;
13f703f
     }
13f703f
     dprint(d, 1, "%s\n", __FUNCTION__);
13f703f
-    qxl_destroy_primary(d);
13f703f
+    qxl_destroy_primary(d, QXL_SYNC);
13f703f
 }
13f703f
 
13f703f
 static void qxl_set_irq(PCIQXLDevice *d)
13f703f
@@ -824,13 +897,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
13f703f
 
13f703f
     if (qxl->mode != QXL_MODE_VGA) {
13f703f
         dprint(qxl, 1, "%s\n", __FUNCTION__);
13f703f
-        qxl_destroy_primary(qxl);
13f703f
+        qxl_destroy_primary(qxl, QXL_SYNC);
13f703f
         qxl_soft_reset(qxl);
13f703f
     }
13f703f
     vga_ioport_write(opaque, addr, val);
13f703f
 }
13f703f
 
13f703f
-static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
13f703f
+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta,
13f703f
+                            qxl_async_io async)
13f703f
 {
13f703f
     static const int regions[] = {
13f703f
         QXL_RAM_RANGE_INDEX,
13f703f
@@ -900,7 +974,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
13f703f
            __FUNCTION__, memslot.slot_id,
13f703f
            memslot.virt_start, memslot.virt_end);
13f703f
 
13f703f
-    qemu_spice_add_memslot(&d->ssd, &memslot);
13f703f
+    qemu_spice_add_memslot(&d->ssd, &memslot, async);
13f703f
     d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
13f703f
     d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
13f703f
     d->guest_slots[slot_id].delta = delta;
13f703f
@@ -925,7 +999,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
13f703f
 {
13f703f
     dprint(d, 1, "%s:\n", __FUNCTION__);
13f703f
     d->mode = QXL_MODE_UNDEFINED;
13f703f
-    qxl_spice_destroy_surfaces(d);
13f703f
+    qxl_spice_destroy_surfaces(d, QXL_SYNC);
13f703f
 }
13f703f
 
13f703f
 /* called from spice server thread context only */
13f703f
@@ -950,7 +1024,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
13f703f
     }
13f703f
 }
13f703f
 
13f703f
-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
13f703f
+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl)
13f703f
+{
13f703f
+    /* for local rendering */
13f703f
+    qxl_render_resize(qxl);
13f703f
+}
13f703f
+
13f703f
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm,
13f703f
+                                     qxl_async_io async)
13f703f
 {
13f703f
     QXLDevSurfaceCreate surface;
13f703f
     QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
13f703f
@@ -978,22 +1059,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
13f703f
 
13f703f
     qxl->mode = QXL_MODE_NATIVE;
13f703f
     qxl->cmdflags = 0;
13f703f
-    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface);
13f703f
+    qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async);
13f703f
 
13f703f
-    /* for local rendering */
13f703f
-    qxl_render_resize(qxl);
13f703f
+    if (async == QXL_SYNC) {
13f703f
+        qxl_create_guest_primary_complete(qxl);
13f703f
+    }
13f703f
 }
13f703f
 
13f703f
-static void qxl_destroy_primary(PCIQXLDevice *d)
13f703f
+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or
13f703f
+ * done (in QXL_SYNC case), 0 otherwise. */
13f703f
+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async)
13f703f
 {
13f703f
     if (d->mode == QXL_MODE_UNDEFINED) {
13f703f
-        return;
13f703f
+        return 0;
13f703f
     }
13f703f
 
13f703f
     dprint(d, 1, "%s\n", __FUNCTION__);
13f703f
 
13f703f
     d->mode = QXL_MODE_UNDEFINED;
13f703f
-    qemu_spice_destroy_primary_surface(&d->ssd, 0);
13f703f
+    qemu_spice_destroy_primary_surface(&d->ssd, 0, async);
13f703f
+    return 1;
13f703f
 }
13f703f
 
13f703f
 static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
13f703f
@@ -1023,10 +1108,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
13f703f
     }
13f703f
 
13f703f
     d->guest_slots[0].slot = slot;
13f703f
-    qxl_add_memslot(d, 0, devmem);
13f703f
+    qxl_add_memslot(d, 0, devmem, QXL_SYNC);
13f703f
 
13f703f
     d->guest_primary.surface = surface;
13f703f
-    qxl_create_guest_primary(d, 0);
13f703f
+    qxl_create_guest_primary(d, 0, QXL_SYNC);
13f703f
 
13f703f
     d->mode = QXL_MODE_COMPAT;
13f703f
     d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
13f703f
@@ -1044,6 +1129,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
13f703f
 {
13f703f
     PCIQXLDevice *d = opaque;
13f703f
     uint32_t io_port = addr - d->io_base;
13f703f
+    qxl_async_io async = QXL_SYNC;
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+    uint32_t orig_io_port = io_port;
13f703f
+#endif
13f703f
 
13f703f
     switch (io_port) {
13f703f
     case QXL_IO_RESET:
13f703f
@@ -1053,6 +1142,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
13f703f
     case QXL_IO_CREATE_PRIMARY:
13f703f
     case QXL_IO_UPDATE_IRQ:
13f703f
     case QXL_IO_LOG:
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
13f703f
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
13f703f
+#endif
13f703f
         break;
13f703f
     default:
13f703f
         if (d->mode != QXL_MODE_VGA) {
13f703f
@@ -1060,15 +1153,61 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
13f703f
         }
13f703f
         dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n",
13f703f
             __func__, io_port, io_port_to_string(io_port));
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+        /* be nice to buggy guest drivers */
13f703f
+        if (io_port >= QXL_IO_UPDATE_AREA_ASYNC &&
13f703f
+            io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) {
13f703f
+            qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
13f703f
+        }
13f703f
+#endif
13f703f
         return;
13f703f
     }
13f703f
 
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+    /* we change the io_port to avoid ifdeffery in the main switch */
13f703f
+    orig_io_port = io_port;
13f703f
+    switch (io_port) {
13f703f
+    case QXL_IO_UPDATE_AREA_ASYNC:
13f703f
+        io_port = QXL_IO_UPDATE_AREA;
13f703f
+        goto async_common;
13f703f
+    case QXL_IO_MEMSLOT_ADD_ASYNC:
13f703f
+        io_port = QXL_IO_MEMSLOT_ADD;
13f703f
+        goto async_common;
13f703f
+    case QXL_IO_CREATE_PRIMARY_ASYNC:
13f703f
+        io_port = QXL_IO_CREATE_PRIMARY;
13f703f
+        goto async_common;
13f703f
+    case QXL_IO_DESTROY_PRIMARY_ASYNC:
13f703f
+        io_port = QXL_IO_DESTROY_PRIMARY;
13f703f
+        goto async_common;
13f703f
+    case QXL_IO_DESTROY_SURFACE_ASYNC:
13f703f
+        io_port = QXL_IO_DESTROY_SURFACE_WAIT;
13f703f
+        goto async_common;
13f703f
+    case QXL_IO_DESTROY_ALL_SURFACES_ASYNC:
13f703f
+        io_port = QXL_IO_DESTROY_ALL_SURFACES;
13f703f
+async_common:
13f703f
+        async = QXL_ASYNC;
13f703f
+        qemu_mutex_lock(&d->async_lock);
13f703f
+        if (d->current_async != QXL_UNDEFINED_IO) {
13f703f
+            qxl_guest_bug(d, "%d async started before last (%d) complete",
13f703f
+                io_port, d->current_async);
13f703f
+            qemu_mutex_unlock(&d->async_lock);
13f703f
+            return;
13f703f
+        }
13f703f
+        d->current_async = orig_io_port;
13f703f
+        qemu_mutex_unlock(&d->async_lock);
13f703f
+        dprint(d, 2, "start async %d (%d)\n", io_port, val);
13f703f
+        break;
13f703f
+    default:
13f703f
+        break;
13f703f
+    }
13f703f
+#endif
13f703f
+
13f703f
     switch (io_port) {
13f703f
     case QXL_IO_UPDATE_AREA:
13f703f
     {
13f703f
         QXLRect update = d->ram->update_area;
13f703f
         qxl_spice_update_area(d, d->ram->update_surface,
13f703f
-                              &update, NULL, 0, 0);
13f703f
+                              &update, NULL, 0, 0, async);
13f703f
         break;
13f703f
     }
13f703f
     case QXL_IO_NOTIFY_CMD:
13f703f
@@ -1116,7 +1255,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
13f703f
             break;
13f703f
         }
13f703f
         d->guest_slots[val].slot = d->ram->mem_slot;
13f703f
-        qxl_add_memslot(d, val, 0);
13f703f
+        qxl_add_memslot(d, val, 0, async);
13f703f
         break;
13f703f
     case QXL_IO_MEMSLOT_DEL:
13f703f
         if (val >= NUM_MEMSLOTS) {
13f703f
@@ -1127,31 +1266,56 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
13f703f
         break;
13f703f
     case QXL_IO_CREATE_PRIMARY:
13f703f
         if (val != 0) {
13f703f
-            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0");
13f703f
-            break;
13f703f
+            qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0",
13f703f
+                          async);
13f703f
+            goto cancel_async;
13f703f
         }
13f703f
-        dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n");
13f703f
+        dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async);
13f703f
         d->guest_primary.surface = d->ram->create_surface;
13f703f
-        qxl_create_guest_primary(d, 0);
13f703f
+        qxl_create_guest_primary(d, 0, async);
13f703f
         break;
13f703f
     case QXL_IO_DESTROY_PRIMARY:
13f703f
         if (val != 0) {
13f703f
-            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0");
13f703f
-            break;
13f703f
+            qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0",
13f703f
+                          async);
13f703f
+            goto cancel_async;
13f703f
+        }
13f703f
+        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async,
13f703f
+               qxl_mode_to_string(d->mode));
13f703f
+        if (!qxl_destroy_primary(d, async)) {
13f703f
+            dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n",
13f703f
+                    qxl_mode_to_string(d->mode));
13f703f
+            goto cancel_async;
13f703f
         }
13f703f
-        dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode));
13f703f
-        qxl_destroy_primary(d);
13f703f
         break;
13f703f
     case QXL_IO_DESTROY_SURFACE_WAIT:
13f703f
-        qxl_spice_destroy_surface_wait(d, val);
13f703f
+        if (val >= NUM_SURFACES) {
13f703f
+            qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
13f703f
+                             "%d >= NUM_SURFACES", async, val);
13f703f
+            goto cancel_async;
13f703f
+        }
13f703f
+        qxl_spice_destroy_surface_wait(d, val, async);
13f703f
         break;
13f703f
     case QXL_IO_DESTROY_ALL_SURFACES:
13f703f
-        qxl_spice_destroy_surfaces(d);
13f703f
+        d->mode = QXL_MODE_UNDEFINED;
13f703f
+        qxl_spice_destroy_surfaces(d, async);
13f703f
         break;
13f703f
     default:
13f703f
         fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
13f703f
         abort();
13f703f
     }
13f703f
+    return;
13f703f
+cancel_async:
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+    if (async) {
13f703f
+        qxl_send_events(d, QXL_INTERRUPT_IO_CMD);
13f703f
+        qemu_mutex_lock(&d->async_lock);
13f703f
+        d->current_async = QXL_UNDEFINED_IO;
13f703f
+        qemu_mutex_unlock(&d->async_lock);
13f703f
+    }
13f703f
+#else
13f703f
+    return;
13f703f
+#endif
13f703f
 }
13f703f
 
13f703f
 static uint32_t ioport_read(void *opaque, uint32_t addr)
13f703f
@@ -1364,6 +1528,8 @@ static int qxl_init_common(PCIQXLDevice *qxl)
13f703f
     qxl->num_memslots = NUM_MEMSLOTS;
13f703f
     qxl->num_surfaces = NUM_SURFACES;
13f703f
     qemu_mutex_init(&qxl->track_lock);
13f703f
+    qemu_mutex_init(&qxl->async_lock);
13f703f
+    qxl->current_async = QXL_UNDEFINED_IO;
13f703f
 
13f703f
     switch (qxl->revision) {
13f703f
     case 1: /* spice 0.4 -- qxl-1 */
13f703f
@@ -1528,9 +1694,9 @@ static int qxl_post_load(void *opaque, int version)
13f703f
             if (!d->guest_slots[i].active) {
13f703f
                 continue;
13f703f
             }
13f703f
-            qxl_add_memslot(d, i, 0);
13f703f
+            qxl_add_memslot(d, i, 0, QXL_SYNC);
13f703f
         }
13f703f
-        qxl_create_guest_primary(d, 1);
13f703f
+        qxl_create_guest_primary(d, 1, QXL_SYNC);
13f703f
 
13f703f
         /* replay surface-create and cursor-set commands */
13f703f
         cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
13f703f
diff --git a/hw/qxl.h b/hw/qxl.h
13f703f
index 32ca5a0..1046205 100644
13f703f
--- a/hw/qxl.h
13f703f
+++ b/hw/qxl.h
13f703f
@@ -15,6 +15,8 @@ enum qxl_mode {
13f703f
     QXL_MODE_NATIVE,
13f703f
 };
13f703f
 
13f703f
+#define QXL_UNDEFINED_IO UINT32_MAX
13f703f
+
13f703f
 typedef struct PCIQXLDevice {
13f703f
     PCIDevice          pci;
13f703f
     SimpleSpiceDisplay ssd;
13f703f
@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice {
13f703f
     int32_t            num_memslots;
13f703f
     int32_t            num_surfaces;
13f703f
 
13f703f
+    uint32_t           current_async;
13f703f
+    QemuMutex          async_lock;
13f703f
+
13f703f
     struct guest_slots {
13f703f
         QXLMemSlot     slot;
13f703f
         void           *ptr;
13f703f
@@ -104,13 +109,12 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
13f703f
 void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
13f703f
                            struct QXLRect *area, struct QXLRect *dirty_rects,
13f703f
                            uint32_t num_dirty_rects,
13f703f
-                           uint32_t clear_dirty_region);
13f703f
-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id);
13f703f
+                           uint32_t clear_dirty_region,
13f703f
+                           qxl_async_io async);
13f703f
 void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext,
13f703f
                                uint32_t count);
13f703f
 void qxl_spice_oom(PCIQXLDevice *qxl);
13f703f
 void qxl_spice_reset_memslots(PCIQXLDevice *qxl);
13f703f
-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl);
13f703f
 void qxl_spice_reset_image_cache(PCIQXLDevice *qxl);
13f703f
 void qxl_spice_reset_cursor(PCIQXLDevice *qxl);
13f703f
 
13f703f
@@ -122,3 +126,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
13f703f
 void qxl_render_resize(PCIQXLDevice *qxl);
13f703f
 void qxl_render_update(PCIQXLDevice *qxl);
13f703f
 void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id,
13f703f
+                                 struct QXLRect *area,
13f703f
+                                 uint32_t clear_dirty_region,
13f703f
+                                 int is_vga);
13f703f
+#endif
13f703f
diff --git a/ui/spice-display.c b/ui/spice-display.c
13f703f
index af10ae8..683d454 100644
13f703f
--- a/ui/spice-display.c
13f703f
+++ b/ui/spice-display.c
13f703f
@@ -62,10 +62,18 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
13f703f
     dest->right = MAX(dest->right, r->right);
13f703f
 }
13f703f
 
13f703f
-
13f703f
-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot)
13f703f
-{
13f703f
-    ssd->worker->add_memslot(ssd->worker, memslot);
13f703f
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
13f703f
+                            qxl_async_io async)
13f703f
+{
13f703f
+    if (async != QXL_SYNC) {
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+        spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0);
13f703f
+#else
13f703f
+        abort();
13f703f
+#endif
13f703f
+    } else {
13f703f
+        ssd->worker->add_memslot(ssd->worker, memslot);
13f703f
+    }
13f703f
 }
13f703f
 
13f703f
 void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
13f703f
@@ -74,14 +82,33 @@ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid)
13f703f
 }
13f703f
 
13f703f
 void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
13f703f
-                                       QXLDevSurfaceCreate *surface)
13f703f
-{
13f703f
-    ssd->worker->create_primary_surface(ssd->worker, id, surface);
13f703f
+                                       QXLDevSurfaceCreate *surface,
13f703f
+                                       qxl_async_io async)
13f703f
+{
13f703f
+    if (async != QXL_SYNC) {
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+        spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0);
13f703f
+#else
13f703f
+        abort();
13f703f
+#endif
13f703f
+    } else {
13f703f
+        ssd->worker->create_primary_surface(ssd->worker, id, surface);
13f703f
+    }
13f703f
 }
13f703f
 
13f703f
-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id)
13f703f
+
13f703f
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
13f703f
+                                        uint32_t id, qxl_async_io async)
13f703f
 {
13f703f
-    ssd->worker->destroy_primary_surface(ssd->worker, id);
13f703f
+    if (async != QXL_SYNC) {
13f703f
+#if SPICE_INTERFACE_QXL_MINOR >= 1
13f703f
+        spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0);
13f703f
+#else
13f703f
+        abort();
13f703f
+#endif
13f703f
+    } else {
13f703f
+        ssd->worker->destroy_primary_surface(ssd->worker, id);
13f703f
+    }
13f703f
 }
13f703f
 
13f703f
 void qemu_spice_wakeup(SimpleSpiceDisplay *ssd)
13f703f
@@ -198,7 +225,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
13f703f
     memset(&memslot, 0, sizeof(memslot));
13f703f
     memslot.slot_group_id = MEMSLOT_GROUP_HOST;
13f703f
     memslot.virt_end = ~0;
13f703f
-    qemu_spice_add_memslot(ssd, &memslot);
13f703f
+    qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC);
13f703f
 }
13f703f
 
13f703f
 void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
13f703f
@@ -218,14 +245,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
13f703f
     surface.mem        = (intptr_t)ssd->buf;
13f703f
     surface.group_id   = MEMSLOT_GROUP_HOST;
13f703f
 
13f703f
-    qemu_spice_create_primary_surface(ssd, 0, &surface);
13f703f
+    qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC);
13f703f
 }
13f703f
 
13f703f
 void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
13f703f
 {
13f703f
     dprint(1, "%s:\n", __FUNCTION__);
13f703f
 
13f703f
-    qemu_spice_destroy_primary_surface(ssd, 0);
13f703f
+    qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC);
13f703f
 }
13f703f
 
13f703f
 void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
13f703f
diff --git a/ui/spice-display.h b/ui/spice-display.h
13f703f
index abe99c7..1388641 100644
13f703f
--- a/ui/spice-display.h
13f703f
+++ b/ui/spice-display.h
13f703f
@@ -33,6 +33,20 @@
13f703f
 
13f703f
 #define NUM_SURFACES 1024
13f703f
 
13f703f
+/*
13f703f
+ * Internal enum to differenciate between options for
13f703f
+ * io calls that have a sync (old) version and an _async (new)
13f703f
+ * version:
13f703f
+ *  QXL_SYNC: use the old version
13f703f
+ *  QXL_ASYNC: use the new version and make sure there are no two
13f703f
+ *   happening at the same time. This is used for guest initiated
13f703f
+ *   calls
13f703f
+ */
13f703f
+typedef enum qxl_async_io {
13f703f
+    QXL_SYNC,
13f703f
+    QXL_ASYNC,
13f703f
+} qxl_async_io;
13f703f
+
13f703f
 typedef struct SimpleSpiceDisplay SimpleSpiceDisplay;
13f703f
 typedef struct SimpleSpiceUpdate SimpleSpiceUpdate;
13f703f
 
13f703f
@@ -82,12 +96,15 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
13f703f
 void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
13f703f
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
13f703f
 
13f703f
-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot);
13f703f
+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot,
13f703f
+                            qxl_async_io async);
13f703f
 void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid,
13f703f
                             uint32_t sid);
13f703f
 void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id,
13f703f
-                                       QXLDevSurfaceCreate *surface);
13f703f
-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id);
13f703f
+                                       QXLDevSurfaceCreate *surface,
13f703f
+                                       qxl_async_io async);
13f703f
+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd,
13f703f
+                                        uint32_t id, qxl_async_io async);
13f703f
 void qemu_spice_wakeup(SimpleSpiceDisplay *ssd);
13f703f
 void qemu_spice_start(SimpleSpiceDisplay *ssd);
13f703f
 void qemu_spice_stop(SimpleSpiceDisplay *ssd);
13f703f
-- 
13f703f
1.7.5.1
13f703f