diff --git a/.gitignore b/.gitignore index 4bebbc7..8c3b708 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ qemu-kvm-0.13.0-25fdf4a.tar.gz /qemu-kvm-0.15.0-fda1906.tar.gz /qemu-kvm-0.15.0-59fadcc.tar.gz /qemu-kvm-0.15.0-0af4922.tar.gz +/qemu-kvm-0.15.0.tar.gz diff --git a/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch index 4786a30..5a7dc4c 100644 --- a/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch +++ b/0001-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch @@ -1,7 +1,7 @@ ->From a0ca79b6cb44fea156174f937c7398befe884048 Mon Sep 17 00:00:00 2001 +>From c0295cc7cc626a2d51de58ac0a9eeee94b6cc9d4 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 21:57:47 +0100 -Subject: [PATCH 01/25] char: Split out tcp socket close code in a separate +Subject: [PATCH 01/28] char: Split out tcp socket close code in a separate function Signed-off-by: Amit Shah diff --git a/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch index 7793103..2f3bd6a 100644 --- a/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch +++ b/0002-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch @@ -1,7 +1,7 @@ ->From 7cda5b9b8b24b778751a402f2b5e6b7d716f1800 Mon Sep 17 00:00:00 2001 +>From 9e799828d3a805184687792254c379ba4887ec60 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 20:31:45 +0100 -Subject: [PATCH 02/25] char: Add a QemuChrHandlers struct to initialise +Subject: [PATCH 02/28] char: Add a QemuChrHandlers struct to initialise chardev handlers Instead of passing each handler in the qemu_add_handlers() function, diff --git a/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch index 53b1857..92d01aa 100644 --- a/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch +++ b/0003-iohandlers-Add-enable-disable_write_fd_handler-funct.patch @@ -1,7 +1,7 @@ ->From 28a0d9d78a886205765f513be2d522592b9ffd42 Mon Sep 17 00:00:00 2001 +>From c8cf564bc5c080540287ecd5bd944d85873755df Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 20:32:58 +0100 -Subject: [PATCH 03/25] iohandlers: Add enable/disable_write_fd_handler() +Subject: [PATCH 03/28] iohandlers: Add enable/disable_write_fd_handler() functions These will be used to provide a cleaner API for the nonblocking case. diff --git a/0004-char-Add-framework-for-a-write-unblocked-callback.patch b/0004-char-Add-framework-for-a-write-unblocked-callback.patch index 2b4baa0..c4bd019 100644 --- a/0004-char-Add-framework-for-a-write-unblocked-callback.patch +++ b/0004-char-Add-framework-for-a-write-unblocked-callback.patch @@ -1,7 +1,7 @@ ->From 7058d42cf3e2fab291bd4c42604ef510a46bebe0 Mon Sep 17 00:00:00 2001 +>From 3ad2ca8e46ba078e69254ca5886de89b30f823bb Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 21:41:42 +0100 -Subject: [PATCH 04/25] char: Add framework for a 'write unblocked' callback +Subject: [PATCH 04/28] char: Add framework for a 'write unblocked' callback The char layer can let users know that the driver will block on further input. For users interested in not blocking, they can assign a function diff --git a/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch index 0ca829d..383ba63 100644 --- a/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch +++ b/0005-char-Update-send_all-to-handle-nonblocking-chardev-w.patch @@ -1,7 +1,7 @@ ->From 92303bbcdb1a2877bce80e25836d47056060403d Mon Sep 17 00:00:00 2001 +>From a962453ed73a671f566cc94858dc21ab694cc85f Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 22:00:27 +0100 -Subject: [PATCH 05/25] char: Update send_all() to handle nonblocking chardev +Subject: [PATCH 05/28] char: Update send_all() to handle nonblocking chardev write requests The send_all function is modified to return to the caller in case the diff --git a/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch index 897e36d..49bf64d 100644 --- a/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch +++ b/0006-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch @@ -1,7 +1,7 @@ ->From 569b1773afa2b30ec9c64cc71815d6c499cd02c0 Mon Sep 17 00:00:00 2001 +>From 5fc1c0fc4c8153ea927aa8580c78c484f966be64 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 22:02:47 +0100 -Subject: [PATCH 06/25] char: Equip the unix/tcp backend to handle nonblocking +Subject: [PATCH 06/28] char: Equip the unix/tcp backend to handle nonblocking writes# Now that the infrastructure is in place to return -EAGAIN to callers, diff --git a/0007-char-Throttle-when-host-connection-is-down.patch b/0007-char-Throttle-when-host-connection-is-down.patch index 99f0f5b..7a131d8 100644 --- a/0007-char-Throttle-when-host-connection-is-down.patch +++ b/0007-char-Throttle-when-host-connection-is-down.patch @@ -1,7 +1,7 @@ ->From edcb78965b9cab18004c30721d46138000a2c810 Mon Sep 17 00:00:00 2001 +>From 5121e48706408e28c811e74d3e6da5b78aa9137d Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 22:05:10 +0100 -Subject: [PATCH 07/25] char: Throttle when host connection is down# +Subject: [PATCH 07/28] char: Throttle when host connection is down# When the host-side connection goes down, throttle the virtio-serial bus and later unthrottle when a connection gets established. This helps diff --git a/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch index 2b30604..740e25d 100644 --- a/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch +++ b/0008-virtio-console-Enable-port-throttling-when-chardev-i.patch @@ -1,7 +1,7 @@ ->From 06a1e88d3e4dc55e94da35928686571b56b8f7a4 Mon Sep 17 00:00:00 2001 +>From 8750ea70a68e74ca3ecea6149d1d5289cc77dae3 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Mon, 21 Mar 2011 22:06:41 +0100 -Subject: [PATCH 08/25] virtio-console: Enable port throttling when chardev is +Subject: [PATCH 08/28] virtio-console: Enable port throttling when chardev is slow to consume data When a chardev indicates it can't accept more data, we tell the diff --git a/0009-spice-qemu-char.c-add-throttling.patch b/0009-spice-qemu-char.c-add-throttling.patch index 112adc8..17bebaa 100644 --- a/0009-spice-qemu-char.c-add-throttling.patch +++ b/0009-spice-qemu-char.c-add-throttling.patch @@ -1,7 +1,7 @@ ->From faa8f1ed4cb40ce4699882a88650a42ca70f0b6b Mon Sep 17 00:00:00 2001 +>From a649fba41737329ae13a5b0b4f20798ddf97e2a2 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Tue, 22 Mar 2011 12:27:59 +0200 -Subject: [PATCH 09/25] spice-qemu-char.c: add throttling +Subject: [PATCH 09/28] spice-qemu-char.c: add throttling BZ: 672191 diff --git a/0010-spice-qemu-char.c-remove-intermediate-buffer.patch b/0010-spice-qemu-char.c-remove-intermediate-buffer.patch index 0396245..ca23ed9 100644 --- a/0010-spice-qemu-char.c-remove-intermediate-buffer.patch +++ b/0010-spice-qemu-char.c-remove-intermediate-buffer.patch @@ -1,7 +1,7 @@ ->From b8af15fd71aa0d0eb0f7df053759eaa85176af46 Mon Sep 17 00:00:00 2001 +>From 63350d37305a8fc5b6a8fb2fbacfb8a6a91956fd Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Tue, 22 Mar 2011 12:28:00 +0200 -Subject: [PATCH 10/25] spice-qemu-char.c: remove intermediate buffer +Subject: [PATCH 10/28] spice-qemu-char.c: remove intermediate buffer BZ: 672191 upstream: not submitted (explained below) diff --git a/0011-usb-redir-Add-flow-control-support.patch b/0011-usb-redir-Add-flow-control-support.patch index 838d679..ab8de4f 100644 --- a/0011-usb-redir-Add-flow-control-support.patch +++ b/0011-usb-redir-Add-flow-control-support.patch @@ -1,7 +1,7 @@ ->From 267e2a453cab2966edd3cbef520351dd4880765c Mon Sep 17 00:00:00 2001 +>From e7903f889f3105efe7e3876925926e8e91919b0f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 19 Jul 2011 10:56:19 +0200 -Subject: [PATCH 11/25] usb-redir: Add flow control support +Subject: [PATCH 11/28] usb-redir: Add flow control support Signed-off-by: Hans de Goede --- diff --git a/0012-spice-add-worker-wrapper-functions.patch b/0012-spice-add-worker-wrapper-functions.patch new file mode 100644 index 0000000..a750ca6 --- /dev/null +++ b/0012-spice-add-worker-wrapper-functions.patch @@ -0,0 +1,323 @@ +>From 67d29af45ebb1539eaaa2bfb599350c790306111 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Jun 2011 10:34:25 +0200 +Subject: [PATCH 12/28] spice: add worker wrapper functions. + +Add wrapper functions for all spice worker calls. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 4 +- + hw/qxl.c | 32 +++++++++--------- + ui/spice-display.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++--- + ui/spice-display.h | 22 ++++++++++++ + 4 files changed, 129 insertions(+), 24 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 1316066..bef5f14 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl) + update.bottom = qxl->guest_primary.surface.height; + + memset(dirty, 0, sizeof(dirty)); +- qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1); ++ qemu_spice_update_area(&qxl->ssd, 0, &update, ++ dirty, ARRAY_SIZE(dirty), 1); + + for (i = 0; i < ARRAY_SIZE(dirty); i++) { + if (qemu_spice_rect_is_empty(dirty+i)) { +diff --git a/hw/qxl.c b/hw/qxl.c +index a6fb7f0..5deb776 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -684,8 +684,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + dprint(d, 1, "%s: start%s\n", __FUNCTION__, + loadvm ? " (loadvm)" : ""); + +- d->ssd.worker->reset_cursor(d->ssd.worker); +- d->ssd.worker->reset_image_cache(d->ssd.worker); ++ qemu_spice_reset_cursor(&d->ssd); ++ qemu_spice_reset_image_cache(&d->ssd); + qxl_reset_surfaces(d); + qxl_reset_memslots(d); + +@@ -790,7 +790,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) + __FUNCTION__, memslot.slot_id, + memslot.virt_start, memslot.virt_end); + +- d->ssd.worker->add_memslot(d->ssd.worker, &memslot); ++ qemu_spice_add_memslot(&d->ssd, &memslot); + d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; + d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; + d->guest_slots[slot_id].delta = delta; +@@ -800,14 +800,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) + static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) + { + dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); +- d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id); ++ qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id); + d->guest_slots[slot_id].active = 0; + } + + static void qxl_reset_memslots(PCIQXLDevice *d) + { + dprint(d, 1, "%s:\n", __FUNCTION__); +- d->ssd.worker->reset_memslots(d->ssd.worker); ++ qemu_spice_reset_memslots(&d->ssd); + memset(&d->guest_slots, 0, sizeof(d->guest_slots)); + } + +@@ -815,7 +815,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + { + dprint(d, 1, "%s:\n", __FUNCTION__); + d->mode = QXL_MODE_UNDEFINED; +- d->ssd.worker->destroy_surfaces(d->ssd.worker); ++ qemu_spice_destroy_surfaces(&d->ssd); + memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); + } + +@@ -869,7 +869,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) + + qxl->mode = QXL_MODE_NATIVE; + qxl->cmdflags = 0; +- qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface); ++ qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface); + + /* for local rendering */ + qxl_render_resize(qxl); +@@ -884,7 +884,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d) + dprint(d, 1, "%s\n", __FUNCTION__); + + d->mode = QXL_MODE_UNDEFINED; +- d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0); ++ qemu_spice_destroy_primary_surface(&d->ssd, 0); + } + + static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) +@@ -956,15 +956,15 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + case QXL_IO_UPDATE_AREA: + { + QXLRect update = d->ram->update_area; +- d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface, +- &update, NULL, 0, 0); ++ qemu_spice_update_area(&d->ssd, d->ram->update_surface, ++ &update, NULL, 0, 0); + break; + } + case QXL_IO_NOTIFY_CMD: +- d->ssd.worker->wakeup(d->ssd.worker); ++ qemu_spice_wakeup(&d->ssd); + break; + case QXL_IO_NOTIFY_CURSOR: +- d->ssd.worker->wakeup(d->ssd.worker); ++ qemu_spice_wakeup(&d->ssd); + break; + case QXL_IO_UPDATE_IRQ: + qxl_set_irq(d); +@@ -978,7 +978,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + break; + } + d->oom_running = 1; +- d->ssd.worker->oom(d->ssd.worker); ++ qemu_spice_oom(&d->ssd); + d->oom_running = 0; + break; + case QXL_IO_SET_MODE: +@@ -1016,10 +1016,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + qxl_destroy_primary(d); + break; + case QXL_IO_DESTROY_SURFACE_WAIT: +- d->ssd.worker->destroy_surface_wait(d->ssd.worker, val); ++ qemu_spice_destroy_surface_wait(&d->ssd, val); + break; + case QXL_IO_DESTROY_ALL_SURFACES: +- d->ssd.worker->destroy_surfaces(d->ssd.worker); ++ qemu_spice_destroy_surfaces(&d->ssd); + break; + default: + fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); +@@ -1424,7 +1424,7 @@ static int qxl_post_load(void *opaque, int version) + cmds[out].cmd.type = QXL_CMD_CURSOR; + cmds[out].group_id = MEMSLOT_GROUP_GUEST; + out++; +- d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out); ++ qemu_spice_loadvm_commands(&d->ssd, cmds, out); + qemu_free(cmds); + + break; +diff --git a/ui/spice-display.c b/ui/spice-display.c +index feeee73..1e6a38f 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -62,6 +62,89 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) + dest->right = MAX(dest->right, r->right); + } + ++ ++void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, ++ struct QXLRect *area, struct QXLRect *dirty_rects, ++ uint32_t num_dirty_rects, ++ uint32_t clear_dirty_region) ++{ ++ ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects, ++ num_dirty_rects, clear_dirty_region); ++} ++ ++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot) ++{ ++ ssd->worker->add_memslot(ssd->worker, memslot); ++} ++ ++void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) ++{ ++ ssd->worker->del_memslot(ssd->worker, gid, sid); ++} ++ ++void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, ++ QXLDevSurfaceCreate *surface) ++{ ++ ssd->worker->create_primary_surface(ssd->worker, id, surface); ++} ++ ++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id) ++{ ++ ssd->worker->destroy_primary_surface(ssd->worker, id); ++} ++ ++void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id) ++{ ++ ssd->worker->destroy_surface_wait(ssd->worker, id); ++} ++ ++void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, ++ struct QXLCommandExt *ext, uint32_t count) ++{ ++ ssd->worker->loadvm_commands(ssd->worker, ext, count); ++} ++ ++void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->wakeup(ssd->worker); ++} ++ ++void qemu_spice_oom(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->oom(ssd->worker); ++} ++ ++void qemu_spice_start(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->start(ssd->worker); ++} ++ ++void qemu_spice_stop(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->stop(ssd->worker); ++} ++ ++void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->reset_memslots(ssd->worker); ++} ++ ++void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->destroy_surfaces(ssd->worker); ++} ++ ++void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->reset_image_cache(ssd->worker); ++} ++ ++void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd) ++{ ++ ssd->worker->reset_cursor(ssd->worker); ++} ++ ++ + static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { + SimpleSpiceUpdate *update; +@@ -161,7 +244,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) + memset(&memslot, 0, sizeof(memslot)); + memslot.slot_group_id = MEMSLOT_GROUP_HOST; + memslot.virt_end = ~0; +- ssd->worker->add_memslot(ssd->worker, &memslot); ++ qemu_spice_add_memslot(ssd, &memslot); + } + + void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) +@@ -181,14 +264,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + surface.mem = (intptr_t)ssd->buf; + surface.group_id = MEMSLOT_GROUP_HOST; + +- ssd->worker->create_primary_surface(ssd->worker, 0, &surface); ++ qemu_spice_create_primary_surface(ssd, 0, &surface); + } + + void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) + { + dprint(1, "%s:\n", __FUNCTION__); + +- ssd->worker->destroy_primary_surface(ssd->worker, 0); ++ qemu_spice_destroy_primary_surface(ssd, 0); + } + + void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) +@@ -196,9 +279,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) + SimpleSpiceDisplay *ssd = opaque; + + if (running) { +- ssd->worker->start(ssd->worker); ++ qemu_spice_start(ssd); + } else { +- ssd->worker->stop(ssd->worker); ++ qemu_spice_stop(ssd); + } + ssd->running = running; + } +@@ -267,7 +350,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + + if (ssd->notify) { + ssd->notify = 0; +- ssd->worker->wakeup(ssd->worker); ++ qemu_spice_wakeup(ssd); + dprint(2, "%s: notify\n", __FUNCTION__); + } + } +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 2f95f68..5b06b11 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -80,3 +80,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + int x, int y, int w, int h); + void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); + void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); ++ ++void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, ++ struct QXLRect *area, struct QXLRect *dirty_rects, ++ uint32_t num_dirty_rects, ++ uint32_t clear_dirty_region); ++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot); ++void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, ++ uint32_t sid); ++void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, ++ QXLDevSurfaceCreate *surface); ++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id); ++void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id); ++void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, ++ struct QXLCommandExt *ext, uint32_t count); ++void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); ++void qemu_spice_oom(SimpleSpiceDisplay *ssd); ++void qemu_spice_start(SimpleSpiceDisplay *ssd); ++void qemu_spice_stop(SimpleSpiceDisplay *ssd); ++void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd); ++void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd); ++void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd); ++void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd); +-- +1.7.5.1 + diff --git a/0012-usb-redir-Call-qemu_chr_guest_open-close.patch b/0012-usb-redir-Call-qemu_chr_guest_open-close.patch deleted file mode 100644 index cddbe9d..0000000 --- a/0012-usb-redir-Call-qemu_chr_guest_open-close.patch +++ /dev/null @@ -1,37 +0,0 @@ ->From eea72a6f70c7b4cf632c3637e12d4689ce6ff0f5 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 21 Jul 2011 16:28:06 +0200 -Subject: [PATCH 12/25] usb-redir: Call qemu_chr_guest_open/close - -To let the chardev now we're ready start receiving data. This is necessary -with the spicevmc chardev to get it registered with the spice-server. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 3 +++ - 1 files changed, 3 insertions(+), 0 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 6932beb..d1aafda 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -840,6 +840,8 @@ static int usbredir_initfn(USBDevice *udev) - udev->auto_attach = 0; - - qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); -+ /* Let the other side know we are ready */ -+ qemu_chr_guest_open(dev->cs); - - return 0; - } -@@ -861,6 +863,7 @@ static void usbredir_handle_destroy(USBDevice *udev) - { - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - -+ qemu_chr_guest_close(dev->cs); - qemu_chr_close(dev->cs); - /* Note must be done after qemu_chr_close, as that causes a close event */ - qemu_bh_delete(dev->open_close_bh); --- -1.7.5.1 - diff --git a/0013-spice-add-qemu_spice_display_init_common.patch b/0013-spice-add-qemu_spice_display_init_common.patch new file mode 100644 index 0000000..d40d24e --- /dev/null +++ b/0013-spice-add-qemu_spice_display_init_common.patch @@ -0,0 +1,84 @@ +>From c28ee0e7c851fc58ac6ef8f5137fc35cc55b607c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Jun 2011 10:42:25 +0200 +Subject: [PATCH 13/28] spice: add qemu_spice_display_init_common + +Factor out SimpleSpiceDisplay initialization into +qemu_spice_display_init_common() and call it from +both qxl.c (for vga mode) and spice-display.c + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 7 +------ + ui/spice-display.c | 17 +++++++++++------ + ui/spice-display.h | 1 + + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 5deb776..2127fa3 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1315,12 +1315,7 @@ static int qxl_init_primary(PCIDevice *dev) + + vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, + qxl_hw_screen_dump, qxl_hw_text_update, qxl); +- qxl->ssd.ds = vga->ds; +- qemu_mutex_init(&qxl->ssd.lock); +- qxl->ssd.mouse_x = -1; +- qxl->ssd.mouse_y = -1; +- qxl->ssd.bufsize = (16 * 1024 * 1024); +- qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize); ++ qemu_spice_display_init_common(&qxl->ssd, vga->ds); + + qxl0 = qxl; + register_displaychangelistener(vga->ds, &display_listener); +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 1e6a38f..93e25bf 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -286,6 +286,16 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) + ssd->running = running; + } + ++void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) ++{ ++ ssd->ds = ds; ++ qemu_mutex_init(&ssd->lock); ++ ssd->mouse_x = -1; ++ ssd->mouse_y = -1; ++ ssd->bufsize = (16 * 1024 * 1024); ++ ssd->buf = qemu_malloc(ssd->bufsize); ++} ++ + /* display listener callbacks */ + + void qemu_spice_display_update(SimpleSpiceDisplay *ssd, +@@ -499,12 +509,7 @@ static DisplayChangeListener display_listener = { + void qemu_spice_display_init(DisplayState *ds) + { + assert(sdpy.ds == NULL); +- sdpy.ds = ds; +- qemu_mutex_init(&sdpy.lock); +- sdpy.mouse_x = -1; +- sdpy.mouse_y = -1; +- sdpy.bufsize = (16 * 1024 * 1024); +- sdpy.buf = qemu_malloc(sdpy.bufsize); ++ qemu_spice_display_init_common(&sdpy, ds); + register_displaychangelistener(ds, &display_listener); + + sdpy.qxl.base.sif = &dpy_interface.base; +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 5b06b11..eb7a573 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -75,6 +75,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); + void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); + void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); + void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason); ++void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds); + + void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + int x, int y, int w, int h); +-- +1.7.5.1 + diff --git a/0013-spice-qemu-char-Generate-chardev-open-close-events.patch b/0013-spice-qemu-char-Generate-chardev-open-close-events.patch deleted file mode 100644 index 87e0f45..0000000 --- a/0013-spice-qemu-char-Generate-chardev-open-close-events.patch +++ /dev/null @@ -1,90 +0,0 @@ ->From c79ffc7e3357317bd81f2abefa4743eaf8101a4e Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 21 Jul 2011 15:36:40 +0200 -Subject: [PATCH 13/25] spice-qemu-char: Generate chardev open/close events - -Define a state callback and make that generate chardev open/close events when -called by the spice-server. - -Note that for all but the newest spice-server versions (which have a fix for -this) the code ignores these events for a spicevmc with a subtype of vdagent, -this subtype specific knowledge is undesirable, but unavoidable for now, see: -http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html - -Signed-off-by: Hans de Goede ---- - spice-qemu-char.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- - 1 files changed, 45 insertions(+), 1 deletions(-) - -diff --git a/spice-qemu-char.c b/spice-qemu-char.c -index 2b8aec4..1f4f1ec 100644 ---- a/spice-qemu-char.c -+++ b/spice-qemu-char.c -@@ -89,11 +89,50 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - return bytes; - } - -+static void vmc_state(SpiceCharDeviceInstance *sin, int connected) -+{ -+ SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); -+ int event; -+ -+#if SPICE_SERVER_VERSION < 0x000901 -+ /* -+ * spice-server calls the state callback for the agent channel when the -+ * spice client connects / disconnects. Given that not the client but -+ * the server is doing the parsing of the messages this is wrong as the -+ * server is still listening. Worse, this causes the parser in the server -+ * to go out of sync, so we ignore state calls for subtype vdagent -+ * spicevmc chardevs. For the full story see: -+ * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html -+ */ -+ if (strcmp(sin->subtype, "vdagent") == 0) { -+ return; -+ } -+#endif -+ -+ if ((scd->chr->opened && connected) || -+ (!scd->chr->opened && !connected)) { -+ return; -+ } -+ -+ if (connected) { -+ scd->chr->opened = 1; -+ event = CHR_EVENT_OPENED; -+ } else { -+ scd->chr->opened = 0; -+ event = CHR_EVENT_CLOSED; -+ } -+ -+ if (scd->chr->chr_event) { -+ scd->chr->chr_event(scd->chr->handler_opaque, event); -+ } -+} -+ - static SpiceCharDeviceInterface vmc_interface = { - .base.type = SPICE_INTERFACE_CHAR_DEVICE, - .base.description = "spice virtual channel char device", - .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, - .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, -+ .state = vmc_state, - .write = vmc_write, - .read = vmc_read, - }; -@@ -222,7 +261,12 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) - chr->chr_guest_close = spice_chr_guest_close; - s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s); - -- qemu_chr_generic_open(chr); -+#if SPICE_SERVER_VERSION < 0x000901 -+ /* See comment in vmc_state() */ -+ if (strcmp(subtype, "vdagent") == 0) { -+ qemu_chr_generic_open(chr); -+ } -+#endif - - *_chr = chr; - return 0; --- -1.7.5.1 - diff --git a/0014-spice-add-worker-wrapper-functions.patch b/0014-spice-add-worker-wrapper-functions.patch deleted file mode 100644 index 2fcb2d8..0000000 --- a/0014-spice-add-worker-wrapper-functions.patch +++ /dev/null @@ -1,323 +0,0 @@ ->From e52026748bb0b6e29f7703cc9fe8f8d6f5f345f8 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Jun 2011 10:34:25 +0200 -Subject: [PATCH 14/25] spice: add worker wrapper functions. - -Add wrapper functions for all spice worker calls. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 4 +- - hw/qxl.c | 32 +++++++++--------- - ui/spice-display.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++--- - ui/spice-display.h | 22 ++++++++++++ - 4 files changed, 129 insertions(+), 24 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 1316066..bef5f14 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl) - update.bottom = qxl->guest_primary.surface.height; - - memset(dirty, 0, sizeof(dirty)); -- qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update, -- dirty, ARRAY_SIZE(dirty), 1); -+ qemu_spice_update_area(&qxl->ssd, 0, &update, -+ dirty, ARRAY_SIZE(dirty), 1); - - for (i = 0; i < ARRAY_SIZE(dirty); i++) { - if (qemu_spice_rect_is_empty(dirty+i)) { -diff --git a/hw/qxl.c b/hw/qxl.c -index a6fb7f0..5deb776 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -684,8 +684,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) - dprint(d, 1, "%s: start%s\n", __FUNCTION__, - loadvm ? " (loadvm)" : ""); - -- d->ssd.worker->reset_cursor(d->ssd.worker); -- d->ssd.worker->reset_image_cache(d->ssd.worker); -+ qemu_spice_reset_cursor(&d->ssd); -+ qemu_spice_reset_image_cache(&d->ssd); - qxl_reset_surfaces(d); - qxl_reset_memslots(d); - -@@ -790,7 +790,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) - __FUNCTION__, memslot.slot_id, - memslot.virt_start, memslot.virt_end); - -- d->ssd.worker->add_memslot(d->ssd.worker, &memslot); -+ qemu_spice_add_memslot(&d->ssd, &memslot); - d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; - d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; - d->guest_slots[slot_id].delta = delta; -@@ -800,14 +800,14 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) - static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) - { - dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); -- d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id); -+ qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id); - d->guest_slots[slot_id].active = 0; - } - - static void qxl_reset_memslots(PCIQXLDevice *d) - { - dprint(d, 1, "%s:\n", __FUNCTION__); -- d->ssd.worker->reset_memslots(d->ssd.worker); -+ qemu_spice_reset_memslots(&d->ssd); - memset(&d->guest_slots, 0, sizeof(d->guest_slots)); - } - -@@ -815,7 +815,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) - { - dprint(d, 1, "%s:\n", __FUNCTION__); - d->mode = QXL_MODE_UNDEFINED; -- d->ssd.worker->destroy_surfaces(d->ssd.worker); -+ qemu_spice_destroy_surfaces(&d->ssd); - memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); - } - -@@ -869,7 +869,7 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) - - qxl->mode = QXL_MODE_NATIVE; - qxl->cmdflags = 0; -- qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface); -+ qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface); - - /* for local rendering */ - qxl_render_resize(qxl); -@@ -884,7 +884,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d) - dprint(d, 1, "%s\n", __FUNCTION__); - - d->mode = QXL_MODE_UNDEFINED; -- d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0); -+ qemu_spice_destroy_primary_surface(&d->ssd, 0); - } - - static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) -@@ -956,15 +956,15 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - case QXL_IO_UPDATE_AREA: - { - QXLRect update = d->ram->update_area; -- d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface, -- &update, NULL, 0, 0); -+ qemu_spice_update_area(&d->ssd, d->ram->update_surface, -+ &update, NULL, 0, 0); - break; - } - case QXL_IO_NOTIFY_CMD: -- d->ssd.worker->wakeup(d->ssd.worker); -+ qemu_spice_wakeup(&d->ssd); - break; - case QXL_IO_NOTIFY_CURSOR: -- d->ssd.worker->wakeup(d->ssd.worker); -+ qemu_spice_wakeup(&d->ssd); - break; - case QXL_IO_UPDATE_IRQ: - qxl_set_irq(d); -@@ -978,7 +978,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - break; - } - d->oom_running = 1; -- d->ssd.worker->oom(d->ssd.worker); -+ qemu_spice_oom(&d->ssd); - d->oom_running = 0; - break; - case QXL_IO_SET_MODE: -@@ -1016,10 +1016,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - qxl_destroy_primary(d); - break; - case QXL_IO_DESTROY_SURFACE_WAIT: -- d->ssd.worker->destroy_surface_wait(d->ssd.worker, val); -+ qemu_spice_destroy_surface_wait(&d->ssd, val); - break; - case QXL_IO_DESTROY_ALL_SURFACES: -- d->ssd.worker->destroy_surfaces(d->ssd.worker); -+ qemu_spice_destroy_surfaces(&d->ssd); - break; - default: - fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); -@@ -1424,7 +1424,7 @@ static int qxl_post_load(void *opaque, int version) - cmds[out].cmd.type = QXL_CMD_CURSOR; - cmds[out].group_id = MEMSLOT_GROUP_GUEST; - out++; -- d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out); -+ qemu_spice_loadvm_commands(&d->ssd, cmds, out); - qemu_free(cmds); - - break; -diff --git a/ui/spice-display.c b/ui/spice-display.c -index feeee73..1e6a38f 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -62,6 +62,89 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) - dest->right = MAX(dest->right, r->right); - } - -+ -+void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, -+ struct QXLRect *area, struct QXLRect *dirty_rects, -+ uint32_t num_dirty_rects, -+ uint32_t clear_dirty_region) -+{ -+ ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects, -+ num_dirty_rects, clear_dirty_region); -+} -+ -+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot) -+{ -+ ssd->worker->add_memslot(ssd->worker, memslot); -+} -+ -+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) -+{ -+ ssd->worker->del_memslot(ssd->worker, gid, sid); -+} -+ -+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, -+ QXLDevSurfaceCreate *surface) -+{ -+ ssd->worker->create_primary_surface(ssd->worker, id, surface); -+} -+ -+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id) -+{ -+ ssd->worker->destroy_primary_surface(ssd->worker, id); -+} -+ -+void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id) -+{ -+ ssd->worker->destroy_surface_wait(ssd->worker, id); -+} -+ -+void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, -+ struct QXLCommandExt *ext, uint32_t count) -+{ -+ ssd->worker->loadvm_commands(ssd->worker, ext, count); -+} -+ -+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->wakeup(ssd->worker); -+} -+ -+void qemu_spice_oom(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->oom(ssd->worker); -+} -+ -+void qemu_spice_start(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->start(ssd->worker); -+} -+ -+void qemu_spice_stop(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->stop(ssd->worker); -+} -+ -+void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->reset_memslots(ssd->worker); -+} -+ -+void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->destroy_surfaces(ssd->worker); -+} -+ -+void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->reset_image_cache(ssd->worker); -+} -+ -+void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd) -+{ -+ ssd->worker->reset_cursor(ssd->worker); -+} -+ -+ - static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - { - SimpleSpiceUpdate *update; -@@ -161,7 +244,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) - memset(&memslot, 0, sizeof(memslot)); - memslot.slot_group_id = MEMSLOT_GROUP_HOST; - memslot.virt_end = ~0; -- ssd->worker->add_memslot(ssd->worker, &memslot); -+ qemu_spice_add_memslot(ssd, &memslot); - } - - void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) -@@ -181,14 +264,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) - surface.mem = (intptr_t)ssd->buf; - surface.group_id = MEMSLOT_GROUP_HOST; - -- ssd->worker->create_primary_surface(ssd->worker, 0, &surface); -+ qemu_spice_create_primary_surface(ssd, 0, &surface); - } - - void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) - { - dprint(1, "%s:\n", __FUNCTION__); - -- ssd->worker->destroy_primary_surface(ssd->worker, 0); -+ qemu_spice_destroy_primary_surface(ssd, 0); - } - - void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) -@@ -196,9 +279,9 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) - SimpleSpiceDisplay *ssd = opaque; - - if (running) { -- ssd->worker->start(ssd->worker); -+ qemu_spice_start(ssd); - } else { -- ssd->worker->stop(ssd->worker); -+ qemu_spice_stop(ssd); - } - ssd->running = running; - } -@@ -267,7 +350,7 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) - - if (ssd->notify) { - ssd->notify = 0; -- ssd->worker->wakeup(ssd->worker); -+ qemu_spice_wakeup(ssd); - dprint(2, "%s: notify\n", __FUNCTION__); - } - } -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 2f95f68..5b06b11 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -80,3 +80,25 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - int x, int y, int w, int h); - void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); - void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); -+ -+void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, -+ struct QXLRect *area, struct QXLRect *dirty_rects, -+ uint32_t num_dirty_rects, -+ uint32_t clear_dirty_region); -+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot); -+void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, -+ uint32_t sid); -+void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, -+ QXLDevSurfaceCreate *surface); -+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id); -+void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id); -+void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, -+ struct QXLCommandExt *ext, uint32_t count); -+void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); -+void qemu_spice_oom(SimpleSpiceDisplay *ssd); -+void qemu_spice_start(SimpleSpiceDisplay *ssd); -+void qemu_spice_stop(SimpleSpiceDisplay *ssd); -+void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd); -+void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd); -+void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd); -+void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd); --- -1.7.5.1 - diff --git a/0014-spice-qxl-move-worker-wrappers.patch b/0014-spice-qxl-move-worker-wrappers.patch new file mode 100644 index 0000000..ef804d6 --- /dev/null +++ b/0014-spice-qxl-move-worker-wrappers.patch @@ -0,0 +1,294 @@ +>From 60257c766e7a39134a9db9f4d1111f2b9fea2f86 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 29 Jun 2011 10:07:52 +0200 +Subject: [PATCH 14/28] spice/qxl: move worker wrappers + +Move the wrapper functions which are used by qxl only to qxl.c. +Rename them from qemu_spice_* to qxl_spice_*. Also pass in a +qxl state pointer instead of a SimpleSpiceDisplay pointer. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 4 +- + hw/qxl.c | 67 ++++++++++++++++++++++++++++++++++++++++++++------- + hw/qxl.h | 13 ++++++++++ + ui/spice-display.c | 46 ----------------------------------- + ui/spice-display.h | 12 --------- + 5 files changed, 72 insertions(+), 70 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index bef5f14..60b822d 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl) + update.bottom = qxl->guest_primary.surface.height; + + memset(dirty, 0, sizeof(dirty)); +- qemu_spice_update_area(&qxl->ssd, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1); ++ qxl_spice_update_area(qxl, 0, &update, ++ dirty, ARRAY_SIZE(dirty), 1); + + for (i = 0; i < ARRAY_SIZE(dirty); i++) { + if (qemu_spice_rect_is_empty(dirty+i)) { +diff --git a/hw/qxl.c b/hw/qxl.c +index 2127fa3..803a364 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -125,6 +125,53 @@ static void qxl_reset_memslots(PCIQXLDevice *d); + static void qxl_reset_surfaces(PCIQXLDevice *d); + static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + ++ ++void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, ++ struct QXLRect *area, struct QXLRect *dirty_rects, ++ uint32_t num_dirty_rects, ++ uint32_t clear_dirty_region) ++{ ++ qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects, ++ num_dirty_rects, clear_dirty_region); ++} ++ ++void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id) ++{ ++ qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); ++} ++ ++void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, ++ uint32_t count) ++{ ++ qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count); ++} ++ ++void qxl_spice_oom(PCIQXLDevice *qxl) ++{ ++ qxl->ssd.worker->oom(qxl->ssd.worker); ++} ++ ++void qxl_spice_reset_memslots(PCIQXLDevice *qxl) ++{ ++ qxl->ssd.worker->reset_memslots(qxl->ssd.worker); ++} ++ ++void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl) ++{ ++ qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); ++} ++ ++void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) ++{ ++ qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); ++} ++ ++void qxl_spice_reset_cursor(PCIQXLDevice *qxl) ++{ ++ qxl->ssd.worker->reset_cursor(qxl->ssd.worker); ++} ++ ++ + static inline uint32_t msb_mask(uint32_t val) + { + uint32_t mask; +@@ -684,8 +731,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + dprint(d, 1, "%s: start%s\n", __FUNCTION__, + loadvm ? " (loadvm)" : ""); + +- qemu_spice_reset_cursor(&d->ssd); +- qemu_spice_reset_image_cache(&d->ssd); ++ qxl_spice_reset_cursor(d); ++ qxl_spice_reset_image_cache(d); + qxl_reset_surfaces(d); + qxl_reset_memslots(d); + +@@ -807,7 +854,7 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) + static void qxl_reset_memslots(PCIQXLDevice *d) + { + dprint(d, 1, "%s:\n", __FUNCTION__); +- qemu_spice_reset_memslots(&d->ssd); ++ qxl_spice_reset_memslots(d); + memset(&d->guest_slots, 0, sizeof(d->guest_slots)); + } + +@@ -815,7 +862,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + { + dprint(d, 1, "%s:\n", __FUNCTION__); + d->mode = QXL_MODE_UNDEFINED; +- qemu_spice_destroy_surfaces(&d->ssd); ++ qxl_spice_destroy_surfaces(d); + memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); + } + +@@ -956,8 +1003,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + case QXL_IO_UPDATE_AREA: + { + QXLRect update = d->ram->update_area; +- qemu_spice_update_area(&d->ssd, d->ram->update_surface, +- &update, NULL, 0, 0); ++ qxl_spice_update_area(d, d->ram->update_surface, ++ &update, NULL, 0, 0); + break; + } + case QXL_IO_NOTIFY_CMD: +@@ -978,7 +1025,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + break; + } + d->oom_running = 1; +- qemu_spice_oom(&d->ssd); ++ qxl_spice_oom(d); + d->oom_running = 0; + break; + case QXL_IO_SET_MODE: +@@ -1016,10 +1063,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + qxl_destroy_primary(d); + break; + case QXL_IO_DESTROY_SURFACE_WAIT: +- qemu_spice_destroy_surface_wait(&d->ssd, val); ++ qxl_spice_destroy_surface_wait(d, val); + break; + case QXL_IO_DESTROY_ALL_SURFACES: +- qemu_spice_destroy_surfaces(&d->ssd); ++ qxl_spice_destroy_surfaces(d); + break; + default: + fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); +@@ -1419,7 +1466,7 @@ static int qxl_post_load(void *opaque, int version) + cmds[out].cmd.type = QXL_CMD_CURSOR; + cmds[out].group_id = MEMSLOT_GROUP_GUEST; + out++; +- qemu_spice_loadvm_commands(&d->ssd, cmds, out); ++ qxl_spice_loadvm_commands(d, cmds, out); + qemu_free(cmds); + + break; +diff --git a/hw/qxl.h b/hw/qxl.h +index f6c450d..e62b9d0 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -98,6 +98,19 @@ typedef struct PCIQXLDevice { + /* qxl.c */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); + ++void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, ++ struct QXLRect *area, struct QXLRect *dirty_rects, ++ uint32_t num_dirty_rects, ++ uint32_t clear_dirty_region); ++void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id); ++void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, ++ uint32_t count); ++void qxl_spice_oom(PCIQXLDevice *qxl); ++void qxl_spice_reset_memslots(PCIQXLDevice *qxl); ++void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl); ++void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); ++void qxl_spice_reset_cursor(PCIQXLDevice *qxl); ++ + /* qxl-logger.c */ + void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); + void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 93e25bf..af10ae8 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -63,15 +63,6 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) + } + + +-void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, +- struct QXLRect *area, struct QXLRect *dirty_rects, +- uint32_t num_dirty_rects, +- uint32_t clear_dirty_region) +-{ +- ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects, +- num_dirty_rects, clear_dirty_region); +-} +- + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot) + { + ssd->worker->add_memslot(ssd->worker, memslot); +@@ -93,27 +84,11 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id) + ssd->worker->destroy_primary_surface(ssd->worker, id); + } + +-void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id) +-{ +- ssd->worker->destroy_surface_wait(ssd->worker, id); +-} +- +-void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, +- struct QXLCommandExt *ext, uint32_t count) +-{ +- ssd->worker->loadvm_commands(ssd->worker, ext, count); +-} +- + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) + { + ssd->worker->wakeup(ssd->worker); + } + +-void qemu_spice_oom(SimpleSpiceDisplay *ssd) +-{ +- ssd->worker->oom(ssd->worker); +-} +- + void qemu_spice_start(SimpleSpiceDisplay *ssd) + { + ssd->worker->start(ssd->worker); +@@ -124,27 +99,6 @@ void qemu_spice_stop(SimpleSpiceDisplay *ssd) + ssd->worker->stop(ssd->worker); + } + +-void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd) +-{ +- ssd->worker->reset_memslots(ssd->worker); +-} +- +-void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd) +-{ +- ssd->worker->destroy_surfaces(ssd->worker); +-} +- +-void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd) +-{ +- ssd->worker->reset_image_cache(ssd->worker); +-} +- +-void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd) +-{ +- ssd->worker->reset_cursor(ssd->worker); +-} +- +- + static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { + SimpleSpiceUpdate *update; +diff --git a/ui/spice-display.h b/ui/spice-display.h +index eb7a573..abe99c7 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -82,24 +82,12 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); + void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); + +-void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, +- struct QXLRect *area, struct QXLRect *dirty_rects, +- uint32_t num_dirty_rects, +- uint32_t clear_dirty_region); + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot); + void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, + uint32_t sid); + void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + QXLDevSurfaceCreate *surface); + void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id); +-void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id); +-void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, +- struct QXLCommandExt *ext, uint32_t count); + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); +-void qemu_spice_oom(SimpleSpiceDisplay *ssd); + void qemu_spice_start(SimpleSpiceDisplay *ssd); + void qemu_spice_stop(SimpleSpiceDisplay *ssd); +-void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd); +-void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd); +-void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd); +-void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd); +-- +1.7.5.1 + diff --git a/0015-qxl-fix-surface-tracking-locking.patch b/0015-qxl-fix-surface-tracking-locking.patch new file mode 100644 index 0000000..c5bd1ee --- /dev/null +++ b/0015-qxl-fix-surface-tracking-locking.patch @@ -0,0 +1,92 @@ +>From b2b956cfda5fb144d9faa10b7c5894833feb7d30 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 29 Jun 2011 10:24:05 +0200 +Subject: [PATCH 15/28] qxl: fix surface tracking & locking + +Surface tracking needs proper locking since it is used from vcpu and spice +worker threads, add it. Also reset the surface counter when zapping all +surfaces. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 13 ++++++++++++- + hw/qxl.h | 2 ++ + 2 files changed, 14 insertions(+), 1 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 803a364..416bd48 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -137,7 +137,12 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + + void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id) + { ++ qemu_mutex_lock(&qxl->track_lock); ++ PANIC_ON(id >= NUM_SURFACES); + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); ++ qxl->guest_surfaces.cmds[id] = 0; ++ qxl->guest_surfaces.count--; ++ qemu_mutex_unlock(&qxl->track_lock); + } + + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, +@@ -158,7 +163,11 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl) + + void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl) + { ++ qemu_mutex_lock(&qxl->track_lock); + qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); ++ memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); ++ qxl->guest_surfaces.count = 0; ++ qemu_mutex_unlock(&qxl->track_lock); + } + + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) +@@ -317,6 +326,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); + uint32_t id = le32_to_cpu(cmd->surface_id); + PANIC_ON(id >= NUM_SURFACES); ++ qemu_mutex_lock(&qxl->track_lock); + if (cmd->type == QXL_SURFACE_CMD_CREATE) { + qxl->guest_surfaces.cmds[id] = ext->cmd.data; + qxl->guest_surfaces.count++; +@@ -327,6 +337,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + qxl->guest_surfaces.cmds[id] = 0; + qxl->guest_surfaces.count--; + } ++ qemu_mutex_unlock(&qxl->track_lock); + break; + } + case QXL_CMD_CURSOR: +@@ -863,7 +874,6 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + dprint(d, 1, "%s:\n", __FUNCTION__); + d->mode = QXL_MODE_UNDEFINED; + qxl_spice_destroy_surfaces(d); +- memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); + } + + /* called from spice server thread context only */ +@@ -1283,6 +1293,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) + qxl->generation = 1; + qxl->num_memslots = NUM_MEMSLOTS; + qxl->num_surfaces = NUM_SURFACES; ++ qemu_mutex_init(&qxl->track_lock); + + switch (qxl->revision) { + case 1: /* spice 0.4 -- qxl-1 */ +diff --git a/hw/qxl.h b/hw/qxl.h +index e62b9d0..5d0e85e 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -55,6 +55,8 @@ typedef struct PCIQXLDevice { + } guest_surfaces; + QXLPHYSICAL guest_cursor; + ++ QemuMutex track_lock; ++ + /* thread signaling */ + pthread_t main; + int pipe[2]; +-- +1.7.5.1 + diff --git a/0015-spice-add-qemu_spice_display_init_common.patch b/0015-spice-add-qemu_spice_display_init_common.patch deleted file mode 100644 index 23a1fe2..0000000 --- a/0015-spice-add-qemu_spice_display_init_common.patch +++ /dev/null @@ -1,84 +0,0 @@ ->From 1de5cd33d8c1ffa35b5bcdf703d4b097284edda0 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Jun 2011 10:42:25 +0200 -Subject: [PATCH 15/25] spice: add qemu_spice_display_init_common - -Factor out SimpleSpiceDisplay initialization into -qemu_spice_display_init_common() and call it from -both qxl.c (for vga mode) and spice-display.c - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 7 +------ - ui/spice-display.c | 17 +++++++++++------ - ui/spice-display.h | 1 + - 3 files changed, 13 insertions(+), 12 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 5deb776..2127fa3 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1315,12 +1315,7 @@ static int qxl_init_primary(PCIDevice *dev) - - vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, - qxl_hw_screen_dump, qxl_hw_text_update, qxl); -- qxl->ssd.ds = vga->ds; -- qemu_mutex_init(&qxl->ssd.lock); -- qxl->ssd.mouse_x = -1; -- qxl->ssd.mouse_y = -1; -- qxl->ssd.bufsize = (16 * 1024 * 1024); -- qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize); -+ qemu_spice_display_init_common(&qxl->ssd, vga->ds); - - qxl0 = qxl; - register_displaychangelistener(vga->ds, &display_listener); -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 1e6a38f..93e25bf 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -286,6 +286,16 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) - ssd->running = running; - } - -+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) -+{ -+ ssd->ds = ds; -+ qemu_mutex_init(&ssd->lock); -+ ssd->mouse_x = -1; -+ ssd->mouse_y = -1; -+ ssd->bufsize = (16 * 1024 * 1024); -+ ssd->buf = qemu_malloc(ssd->bufsize); -+} -+ - /* display listener callbacks */ - - void qemu_spice_display_update(SimpleSpiceDisplay *ssd, -@@ -499,12 +509,7 @@ static DisplayChangeListener display_listener = { - void qemu_spice_display_init(DisplayState *ds) - { - assert(sdpy.ds == NULL); -- sdpy.ds = ds; -- qemu_mutex_init(&sdpy.lock); -- sdpy.mouse_x = -1; -- sdpy.mouse_y = -1; -- sdpy.bufsize = (16 * 1024 * 1024); -- sdpy.buf = qemu_malloc(sdpy.bufsize); -+ qemu_spice_display_init_common(&sdpy, ds); - register_displaychangelistener(ds, &display_listener); - - sdpy.qxl.base.sif = &dpy_interface.base; -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 5b06b11..eb7a573 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -75,6 +75,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); - void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); - void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); - void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason); -+void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds); - - void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - int x, int y, int w, int h); --- -1.7.5.1 - diff --git a/0016-qxl-add-io_port_to_string.patch b/0016-qxl-add-io_port_to_string.patch new file mode 100644 index 0000000..a47328c --- /dev/null +++ b/0016-qxl-add-io_port_to_string.patch @@ -0,0 +1,71 @@ +>From 31c995f6ee18ff2e2b45dbdcf1d57f777d1e0ef9 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 17 Jun 2011 14:42:09 +0200 +Subject: [PATCH 16/28] qxl: add io_port_to_string + +Signed-off-by: Alon Levy +--- + hw/qxl.c | 40 +++++++++++++++++++++++++++++++++++++++- + 1 files changed, 39 insertions(+), 1 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 416bd48..6e66021 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -409,6 +409,43 @@ static const char *qxl_mode_to_string(int mode) + return "INVALID"; + } + ++static const char *io_port_to_string(uint32_t io_port) ++{ ++ if (io_port >= QXL_IO_RANGE_SIZE) { ++ return "out of range"; ++ } ++ static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = { ++ [QXL_IO_NOTIFY_CMD] = "QXL_IO_NOTIFY_CMD", ++ [QXL_IO_NOTIFY_CURSOR] = "QXL_IO_NOTIFY_CURSOR", ++ [QXL_IO_UPDATE_AREA] = "QXL_IO_UPDATE_AREA", ++ [QXL_IO_UPDATE_IRQ] = "QXL_IO_UPDATE_IRQ", ++ [QXL_IO_NOTIFY_OOM] = "QXL_IO_NOTIFY_OOM", ++ [QXL_IO_RESET] = "QXL_IO_RESET", ++ [QXL_IO_SET_MODE] = "QXL_IO_SET_MODE", ++ [QXL_IO_LOG] = "QXL_IO_LOG", ++ [QXL_IO_MEMSLOT_ADD] = "QXL_IO_MEMSLOT_ADD", ++ [QXL_IO_MEMSLOT_DEL] = "QXL_IO_MEMSLOT_DEL", ++ [QXL_IO_DETACH_PRIMARY] = "QXL_IO_DETACH_PRIMARY", ++ [QXL_IO_ATTACH_PRIMARY] = "QXL_IO_ATTACH_PRIMARY", ++ [QXL_IO_CREATE_PRIMARY] = "QXL_IO_CREATE_PRIMARY", ++ [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY", ++ [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT", ++ [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES", ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC", ++ [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC", ++ [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC", ++ [QXL_IO_DESTROY_PRIMARY_ASYNC] = "QXL_IO_DESTROY_PRIMARY_ASYNC", ++ [QXL_IO_DESTROY_SURFACE_ASYNC] = "QXL_IO_DESTROY_SURFACE_ASYNC", ++ [QXL_IO_DESTROY_ALL_SURFACES_ASYNC] ++ = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", ++ [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", ++ [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", ++#endif ++ }; ++ return io_port_to_string[io_port]; ++} ++ + /* called from spice server thread context only */ + static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + { +@@ -1005,7 +1042,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + 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); ++ dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", ++ __func__, io_port, io_port_to_string(io_port)); + return; + } + +-- +1.7.5.1 + diff --git a/0016-spice-qxl-move-worker-wrappers.patch b/0016-spice-qxl-move-worker-wrappers.patch deleted file mode 100644 index 55b7bf5..0000000 --- a/0016-spice-qxl-move-worker-wrappers.patch +++ /dev/null @@ -1,294 +0,0 @@ ->From b1fef6eecf09404114ca016aa090cffa183d40f1 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 29 Jun 2011 10:07:52 +0200 -Subject: [PATCH 16/25] spice/qxl: move worker wrappers - -Move the wrapper functions which are used by qxl only to qxl.c. -Rename them from qemu_spice_* to qxl_spice_*. Also pass in a -qxl state pointer instead of a SimpleSpiceDisplay pointer. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 4 +- - hw/qxl.c | 67 ++++++++++++++++++++++++++++++++++++++++++++------- - hw/qxl.h | 13 ++++++++++ - ui/spice-display.c | 46 ----------------------------------- - ui/spice-display.h | 12 --------- - 5 files changed, 72 insertions(+), 70 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index bef5f14..60b822d 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -124,8 +124,8 @@ void qxl_render_update(PCIQXLDevice *qxl) - update.bottom = qxl->guest_primary.surface.height; - - memset(dirty, 0, sizeof(dirty)); -- qemu_spice_update_area(&qxl->ssd, 0, &update, -- dirty, ARRAY_SIZE(dirty), 1); -+ qxl_spice_update_area(qxl, 0, &update, -+ dirty, ARRAY_SIZE(dirty), 1); - - for (i = 0; i < ARRAY_SIZE(dirty); i++) { - if (qemu_spice_rect_is_empty(dirty+i)) { -diff --git a/hw/qxl.c b/hw/qxl.c -index 2127fa3..803a364 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -125,6 +125,53 @@ static void qxl_reset_memslots(PCIQXLDevice *d); - static void qxl_reset_surfaces(PCIQXLDevice *d); - static void qxl_ring_set_dirty(PCIQXLDevice *qxl); - -+ -+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, -+ struct QXLRect *area, struct QXLRect *dirty_rects, -+ uint32_t num_dirty_rects, -+ uint32_t clear_dirty_region) -+{ -+ qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects, -+ num_dirty_rects, clear_dirty_region); -+} -+ -+void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id) -+{ -+ qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); -+} -+ -+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, -+ uint32_t count) -+{ -+ qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count); -+} -+ -+void qxl_spice_oom(PCIQXLDevice *qxl) -+{ -+ qxl->ssd.worker->oom(qxl->ssd.worker); -+} -+ -+void qxl_spice_reset_memslots(PCIQXLDevice *qxl) -+{ -+ qxl->ssd.worker->reset_memslots(qxl->ssd.worker); -+} -+ -+void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl) -+{ -+ qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); -+} -+ -+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) -+{ -+ qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); -+} -+ -+void qxl_spice_reset_cursor(PCIQXLDevice *qxl) -+{ -+ qxl->ssd.worker->reset_cursor(qxl->ssd.worker); -+} -+ -+ - static inline uint32_t msb_mask(uint32_t val) - { - uint32_t mask; -@@ -684,8 +731,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) - dprint(d, 1, "%s: start%s\n", __FUNCTION__, - loadvm ? " (loadvm)" : ""); - -- qemu_spice_reset_cursor(&d->ssd); -- qemu_spice_reset_image_cache(&d->ssd); -+ qxl_spice_reset_cursor(d); -+ qxl_spice_reset_image_cache(d); - qxl_reset_surfaces(d); - qxl_reset_memslots(d); - -@@ -807,7 +854,7 @@ static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) - static void qxl_reset_memslots(PCIQXLDevice *d) - { - dprint(d, 1, "%s:\n", __FUNCTION__); -- qemu_spice_reset_memslots(&d->ssd); -+ qxl_spice_reset_memslots(d); - memset(&d->guest_slots, 0, sizeof(d->guest_slots)); - } - -@@ -815,7 +862,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) - { - dprint(d, 1, "%s:\n", __FUNCTION__); - d->mode = QXL_MODE_UNDEFINED; -- qemu_spice_destroy_surfaces(&d->ssd); -+ qxl_spice_destroy_surfaces(d); - memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); - } - -@@ -956,8 +1003,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - case QXL_IO_UPDATE_AREA: - { - QXLRect update = d->ram->update_area; -- qemu_spice_update_area(&d->ssd, d->ram->update_surface, -- &update, NULL, 0, 0); -+ qxl_spice_update_area(d, d->ram->update_surface, -+ &update, NULL, 0, 0); - break; - } - case QXL_IO_NOTIFY_CMD: -@@ -978,7 +1025,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - break; - } - d->oom_running = 1; -- qemu_spice_oom(&d->ssd); -+ qxl_spice_oom(d); - d->oom_running = 0; - break; - case QXL_IO_SET_MODE: -@@ -1016,10 +1063,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - qxl_destroy_primary(d); - break; - case QXL_IO_DESTROY_SURFACE_WAIT: -- qemu_spice_destroy_surface_wait(&d->ssd, val); -+ qxl_spice_destroy_surface_wait(d, val); - break; - case QXL_IO_DESTROY_ALL_SURFACES: -- qemu_spice_destroy_surfaces(&d->ssd); -+ qxl_spice_destroy_surfaces(d); - break; - default: - fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); -@@ -1419,7 +1466,7 @@ static int qxl_post_load(void *opaque, int version) - cmds[out].cmd.type = QXL_CMD_CURSOR; - cmds[out].group_id = MEMSLOT_GROUP_GUEST; - out++; -- qemu_spice_loadvm_commands(&d->ssd, cmds, out); -+ qxl_spice_loadvm_commands(d, cmds, out); - qemu_free(cmds); - - break; -diff --git a/hw/qxl.h b/hw/qxl.h -index f6c450d..e62b9d0 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -98,6 +98,19 @@ typedef struct PCIQXLDevice { - /* qxl.c */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); - -+void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, -+ struct QXLRect *area, struct QXLRect *dirty_rects, -+ uint32_t num_dirty_rects, -+ uint32_t clear_dirty_region); -+void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id); -+void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, -+ uint32_t count); -+void qxl_spice_oom(PCIQXLDevice *qxl); -+void qxl_spice_reset_memslots(PCIQXLDevice *qxl); -+void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl); -+void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); -+void qxl_spice_reset_cursor(PCIQXLDevice *qxl); -+ - /* qxl-logger.c */ - void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); - void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 93e25bf..af10ae8 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -63,15 +63,6 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) - } - - --void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, -- struct QXLRect *area, struct QXLRect *dirty_rects, -- uint32_t num_dirty_rects, -- uint32_t clear_dirty_region) --{ -- ssd->worker->update_area(ssd->worker, surface_id, area, dirty_rects, -- num_dirty_rects, clear_dirty_region); --} -- - void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot) - { - ssd->worker->add_memslot(ssd->worker, memslot); -@@ -93,27 +84,11 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id) - ssd->worker->destroy_primary_surface(ssd->worker, id); - } - --void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id) --{ -- ssd->worker->destroy_surface_wait(ssd->worker, id); --} -- --void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, -- struct QXLCommandExt *ext, uint32_t count) --{ -- ssd->worker->loadvm_commands(ssd->worker, ext, count); --} -- - void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) - { - ssd->worker->wakeup(ssd->worker); - } - --void qemu_spice_oom(SimpleSpiceDisplay *ssd) --{ -- ssd->worker->oom(ssd->worker); --} -- - void qemu_spice_start(SimpleSpiceDisplay *ssd) - { - ssd->worker->start(ssd->worker); -@@ -124,27 +99,6 @@ void qemu_spice_stop(SimpleSpiceDisplay *ssd) - ssd->worker->stop(ssd->worker); - } - --void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd) --{ -- ssd->worker->reset_memslots(ssd->worker); --} -- --void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd) --{ -- ssd->worker->destroy_surfaces(ssd->worker); --} -- --void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd) --{ -- ssd->worker->reset_image_cache(ssd->worker); --} -- --void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd) --{ -- ssd->worker->reset_cursor(ssd->worker); --} -- -- - static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - { - SimpleSpiceUpdate *update; -diff --git a/ui/spice-display.h b/ui/spice-display.h -index eb7a573..abe99c7 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -82,24 +82,12 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); - void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); - --void qemu_spice_update_area(SimpleSpiceDisplay *ssd, uint32_t surface_id, -- struct QXLRect *area, struct QXLRect *dirty_rects, -- uint32_t num_dirty_rects, -- uint32_t clear_dirty_region); - void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot); - void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, - uint32_t sid); - void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - QXLDevSurfaceCreate *surface); - void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id); --void qemu_spice_destroy_surface_wait(SimpleSpiceDisplay *ssd, uint32_t id); --void qemu_spice_loadvm_commands(SimpleSpiceDisplay *ssd, -- struct QXLCommandExt *ext, uint32_t count); - void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); --void qemu_spice_oom(SimpleSpiceDisplay *ssd); - void qemu_spice_start(SimpleSpiceDisplay *ssd); - void qemu_spice_stop(SimpleSpiceDisplay *ssd); --void qemu_spice_reset_memslots(SimpleSpiceDisplay *ssd); --void qemu_spice_destroy_surfaces(SimpleSpiceDisplay *ssd); --void qemu_spice_reset_image_cache(SimpleSpiceDisplay *ssd); --void qemu_spice_reset_cursor(SimpleSpiceDisplay *ssd); --- -1.7.5.1 - diff --git a/0017-qxl-error-handling-fixes-and-cleanups.patch b/0017-qxl-error-handling-fixes-and-cleanups.patch new file mode 100644 index 0000000..39a81b7 --- /dev/null +++ b/0017-qxl-error-handling-fixes-and-cleanups.patch @@ -0,0 +1,110 @@ +>From 4b61f7ca2ed63deb1d35c17150b53a1661f395f7 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Jun 2011 10:41:36 +0200 +Subject: [PATCH 17/28] qxl: error handling fixes and cleanups. + +Add qxl_guest_bug() function which is supposed to be called in case +sanity checks of guest requests fail. It raises an error IRQ and +logs a message in case guest debugging is enabled. + +Make PANIC_ON() abort instead of exit. That macro should be used +for qemu bugs only, any guest-triggerable stuff should use the new +qxl_guest_bug() function instead. + +Convert a few easy cases from PANIC_ON() to qxl_guest_bug() to +show intended usage. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 34 ++++++++++++++++++++++++++++++---- + hw/qxl.h | 3 ++- + 2 files changed, 32 insertions(+), 5 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 6e66021..28c8b5d 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -125,6 +125,16 @@ static void qxl_reset_memslots(PCIQXLDevice *d); + static void qxl_reset_surfaces(PCIQXLDevice *d); + static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + ++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg) ++{ ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ qxl_send_events(qxl, QXL_INTERRUPT_ERROR); ++#endif ++ if (qxl->guestdebug) { ++ fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg); ++ } ++} ++ + + void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, +@@ -1091,22 +1101,38 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + qxl_hard_reset(d, 0); + break; + case QXL_IO_MEMSLOT_ADD: +- PANIC_ON(val >= NUM_MEMSLOTS); +- PANIC_ON(d->guest_slots[val].active); ++ if (val >= NUM_MEMSLOTS) { ++ qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range"); ++ break; ++ } ++ if (d->guest_slots[val].active) { ++ qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active"); ++ break; ++ } + d->guest_slots[val].slot = d->ram->mem_slot; + qxl_add_memslot(d, val, 0); + break; + case QXL_IO_MEMSLOT_DEL: ++ if (val >= NUM_MEMSLOTS) { ++ qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range"); ++ break; ++ } + qxl_del_memslot(d, val); + break; + case QXL_IO_CREATE_PRIMARY: +- PANIC_ON(val != 0); ++ if (val != 0) { ++ qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0"); ++ break; ++ } + dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n"); + d->guest_primary.surface = d->ram->create_surface; + qxl_create_guest_primary(d, 0); + break; + case QXL_IO_DESTROY_PRIMARY: +- PANIC_ON(val != 0); ++ if (val != 0) { ++ qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0"); ++ break; ++ } + dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode)); + qxl_destroy_primary(d); + break; +diff --git a/hw/qxl.h b/hw/qxl.h +index 5d0e85e..5db9aae 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -86,7 +86,7 @@ typedef struct PCIQXLDevice { + + #define PANIC_ON(x) if ((x)) { \ + printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \ +- exit(-1); \ ++ abort(); \ + } + + #define dprint(_qxl, _level, _fmt, ...) \ +@@ -99,6 +99,7 @@ typedef struct PCIQXLDevice { + + /* qxl.c */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); ++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg); + + void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, +-- +1.7.5.1 + diff --git a/0017-qxl-fix-surface-tracking-locking.patch b/0017-qxl-fix-surface-tracking-locking.patch deleted file mode 100644 index c525dc7..0000000 --- a/0017-qxl-fix-surface-tracking-locking.patch +++ /dev/null @@ -1,92 +0,0 @@ ->From fc1bf5a4be15e71f87fd73f79356a5a1df5aa724 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 29 Jun 2011 10:24:05 +0200 -Subject: [PATCH 17/25] qxl: fix surface tracking & locking - -Surface tracking needs proper locking since it is used from vcpu and spice -worker threads, add it. Also reset the surface counter when zapping all -surfaces. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 13 ++++++++++++- - hw/qxl.h | 2 ++ - 2 files changed, 14 insertions(+), 1 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 803a364..416bd48 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -137,7 +137,12 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - - void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id) - { -+ qemu_mutex_lock(&qxl->track_lock); -+ PANIC_ON(id >= NUM_SURFACES); - qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); -+ qxl->guest_surfaces.cmds[id] = 0; -+ qxl->guest_surfaces.count--; -+ qemu_mutex_unlock(&qxl->track_lock); - } - - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, -@@ -158,7 +163,11 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl) - - void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl) - { -+ qemu_mutex_lock(&qxl->track_lock); - qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); -+ memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); -+ qxl->guest_surfaces.count = 0; -+ qemu_mutex_unlock(&qxl->track_lock); - } - - void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) -@@ -317,6 +326,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) - QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); - uint32_t id = le32_to_cpu(cmd->surface_id); - PANIC_ON(id >= NUM_SURFACES); -+ qemu_mutex_lock(&qxl->track_lock); - if (cmd->type == QXL_SURFACE_CMD_CREATE) { - qxl->guest_surfaces.cmds[id] = ext->cmd.data; - qxl->guest_surfaces.count++; -@@ -327,6 +337,7 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) - qxl->guest_surfaces.cmds[id] = 0; - qxl->guest_surfaces.count--; - } -+ qemu_mutex_unlock(&qxl->track_lock); - break; - } - case QXL_CMD_CURSOR: -@@ -863,7 +874,6 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) - dprint(d, 1, "%s:\n", __FUNCTION__); - d->mode = QXL_MODE_UNDEFINED; - qxl_spice_destroy_surfaces(d); -- memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); - } - - /* called from spice server thread context only */ -@@ -1283,6 +1293,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) - qxl->generation = 1; - qxl->num_memslots = NUM_MEMSLOTS; - qxl->num_surfaces = NUM_SURFACES; -+ qemu_mutex_init(&qxl->track_lock); - - switch (qxl->revision) { - case 1: /* spice 0.4 -- qxl-1 */ -diff --git a/hw/qxl.h b/hw/qxl.h -index e62b9d0..5d0e85e 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -55,6 +55,8 @@ typedef struct PCIQXLDevice { - } guest_surfaces; - QXLPHYSICAL guest_cursor; - -+ QemuMutex track_lock; -+ - /* thread signaling */ - pthread_t main; - int pipe[2]; --- -1.7.5.1 - diff --git a/0018-qxl-add-io_port_to_string.patch b/0018-qxl-add-io_port_to_string.patch deleted file mode 100644 index 96a5238..0000000 --- a/0018-qxl-add-io_port_to_string.patch +++ /dev/null @@ -1,71 +0,0 @@ ->From cb29c060e51d2afcd9ba6ed6a115442473381d5a Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 17 Jun 2011 14:42:09 +0200 -Subject: [PATCH 18/25] qxl: add io_port_to_string - -Signed-off-by: Alon Levy ---- - hw/qxl.c | 40 +++++++++++++++++++++++++++++++++++++++- - 1 files changed, 39 insertions(+), 1 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 416bd48..6e66021 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -409,6 +409,43 @@ static const char *qxl_mode_to_string(int mode) - return "INVALID"; - } - -+static const char *io_port_to_string(uint32_t io_port) -+{ -+ if (io_port >= QXL_IO_RANGE_SIZE) { -+ return "out of range"; -+ } -+ static const char *io_port_to_string[QXL_IO_RANGE_SIZE + 1] = { -+ [QXL_IO_NOTIFY_CMD] = "QXL_IO_NOTIFY_CMD", -+ [QXL_IO_NOTIFY_CURSOR] = "QXL_IO_NOTIFY_CURSOR", -+ [QXL_IO_UPDATE_AREA] = "QXL_IO_UPDATE_AREA", -+ [QXL_IO_UPDATE_IRQ] = "QXL_IO_UPDATE_IRQ", -+ [QXL_IO_NOTIFY_OOM] = "QXL_IO_NOTIFY_OOM", -+ [QXL_IO_RESET] = "QXL_IO_RESET", -+ [QXL_IO_SET_MODE] = "QXL_IO_SET_MODE", -+ [QXL_IO_LOG] = "QXL_IO_LOG", -+ [QXL_IO_MEMSLOT_ADD] = "QXL_IO_MEMSLOT_ADD", -+ [QXL_IO_MEMSLOT_DEL] = "QXL_IO_MEMSLOT_DEL", -+ [QXL_IO_DETACH_PRIMARY] = "QXL_IO_DETACH_PRIMARY", -+ [QXL_IO_ATTACH_PRIMARY] = "QXL_IO_ATTACH_PRIMARY", -+ [QXL_IO_CREATE_PRIMARY] = "QXL_IO_CREATE_PRIMARY", -+ [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY", -+ [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT", -+ [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES", -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC", -+ [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC", -+ [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC", -+ [QXL_IO_DESTROY_PRIMARY_ASYNC] = "QXL_IO_DESTROY_PRIMARY_ASYNC", -+ [QXL_IO_DESTROY_SURFACE_ASYNC] = "QXL_IO_DESTROY_SURFACE_ASYNC", -+ [QXL_IO_DESTROY_ALL_SURFACES_ASYNC] -+ = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", -+ [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", -+ [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", -+#endif -+ }; -+ return io_port_to_string[io_port]; -+} -+ - /* called from spice server thread context only */ - static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) - { -@@ -1005,7 +1042,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - 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); -+ dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", -+ __func__, io_port, io_port_to_string(io_port)); - return; - } - --- -1.7.5.1 - diff --git a/0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch b/0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch new file mode 100644 index 0000000..b7b311f --- /dev/null +++ b/0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch @@ -0,0 +1,52 @@ +>From 5c0219c6cef769a5748705d489376ea618486a17 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 6 Jul 2011 13:40:29 +0200 +Subject: [PATCH 18/28] qxl: make qxl_guest_bug take variable arguments + +Signed-off-by: Alon Levy +--- + hw/qxl.c | 9 +++++++-- + hw/qxl.h | 2 +- + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 28c8b5d..c50eaf9 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -125,13 +125,18 @@ static void qxl_reset_memslots(PCIQXLDevice *d); + static void qxl_reset_surfaces(PCIQXLDevice *d); + static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + +-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg) ++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + { + #if SPICE_INTERFACE_QXL_MINOR >= 1 + qxl_send_events(qxl, QXL_INTERRUPT_ERROR); + #endif + if (qxl->guestdebug) { +- fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg); ++ va_list ap; ++ va_start(ap, msg); ++ fprintf(stderr, "qxl-%d: guest bug: ", qxl->id); ++ vfprintf(stderr, msg, ap); ++ fprintf(stderr, "\n"); ++ va_end(ap); + } + } + +diff --git a/hw/qxl.h b/hw/qxl.h +index 5db9aae..32ca5a0 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -99,7 +99,7 @@ typedef struct PCIQXLDevice { + + /* qxl.c */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); +-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg); ++void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...); + + void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, +-- +1.7.5.1 + diff --git a/0019-qxl-error-handling-fixes-and-cleanups.patch b/0019-qxl-error-handling-fixes-and-cleanups.patch deleted file mode 100644 index c030308..0000000 --- a/0019-qxl-error-handling-fixes-and-cleanups.patch +++ /dev/null @@ -1,110 +0,0 @@ ->From 9e85acc84ed9dbaed1bb7abe83e1b2fe61905706 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Jun 2011 10:41:36 +0200 -Subject: [PATCH 19/25] qxl: error handling fixes and cleanups. - -Add qxl_guest_bug() function which is supposed to be called in case -sanity checks of guest requests fail. It raises an error IRQ and -logs a message in case guest debugging is enabled. - -Make PANIC_ON() abort instead of exit. That macro should be used -for qemu bugs only, any guest-triggerable stuff should use the new -qxl_guest_bug() function instead. - -Convert a few easy cases from PANIC_ON() to qxl_guest_bug() to -show intended usage. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 34 ++++++++++++++++++++++++++++++---- - hw/qxl.h | 3 ++- - 2 files changed, 32 insertions(+), 5 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 6e66021..28c8b5d 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -125,6 +125,16 @@ static void qxl_reset_memslots(PCIQXLDevice *d); - static void qxl_reset_surfaces(PCIQXLDevice *d); - static void qxl_ring_set_dirty(PCIQXLDevice *qxl); - -+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg) -+{ -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ qxl_send_events(qxl, QXL_INTERRUPT_ERROR); -+#endif -+ if (qxl->guestdebug) { -+ fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg); -+ } -+} -+ - - void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, -@@ -1091,22 +1101,38 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - qxl_hard_reset(d, 0); - break; - case QXL_IO_MEMSLOT_ADD: -- PANIC_ON(val >= NUM_MEMSLOTS); -- PANIC_ON(d->guest_slots[val].active); -+ if (val >= NUM_MEMSLOTS) { -+ qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: val out of range"); -+ break; -+ } -+ if (d->guest_slots[val].active) { -+ qxl_guest_bug(d, "QXL_IO_MEMSLOT_ADD: memory slot already active"); -+ break; -+ } - d->guest_slots[val].slot = d->ram->mem_slot; - qxl_add_memslot(d, val, 0); - break; - case QXL_IO_MEMSLOT_DEL: -+ if (val >= NUM_MEMSLOTS) { -+ qxl_guest_bug(d, "QXL_IO_MEMSLOT_DEL: val out of range"); -+ break; -+ } - qxl_del_memslot(d, val); - break; - case QXL_IO_CREATE_PRIMARY: -- PANIC_ON(val != 0); -+ if (val != 0) { -+ qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0"); -+ break; -+ } - dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n"); - d->guest_primary.surface = d->ram->create_surface; - qxl_create_guest_primary(d, 0); - break; - case QXL_IO_DESTROY_PRIMARY: -- PANIC_ON(val != 0); -+ if (val != 0) { -+ qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0"); -+ break; -+ } - dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode)); - qxl_destroy_primary(d); - break; -diff --git a/hw/qxl.h b/hw/qxl.h -index 5d0e85e..5db9aae 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -86,7 +86,7 @@ typedef struct PCIQXLDevice { - - #define PANIC_ON(x) if ((x)) { \ - printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \ -- exit(-1); \ -+ abort(); \ - } - - #define dprint(_qxl, _level, _fmt, ...) \ -@@ -99,6 +99,7 @@ typedef struct PCIQXLDevice { - - /* qxl.c */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); -+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg); - - void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, --- -1.7.5.1 - diff --git a/0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch b/0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch new file mode 100644 index 0000000..258a7c3 --- /dev/null +++ b/0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch @@ -0,0 +1,31 @@ +>From e8f481961a5fd3ad92a55dbabcccf09b037d86c9 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 29 Jun 2011 11:53:21 +0200 +Subject: [PATCH 19/28] qxl: only disallow specific io's in vga mode + +Since the driver is still in operation even after moving to UNDEFINED, i.e. +by destroying primary in any way. + +Signed-off-by: Alon Levy +--- + hw/qxl.c | 3 ++- + 1 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index c50eaf9..23e3240 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1055,8 +1055,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + case QXL_IO_LOG: + break; + default: +- if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT) ++ if (d->mode != QXL_MODE_VGA) { + break; ++ } + dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", + __func__, io_port, io_port_to_string(io_port)); + return; +-- +1.7.5.1 + diff --git a/0020-qxl-async-io-support-using-new-spice-api.patch b/0020-qxl-async-io-support-using-new-spice-api.patch new file mode 100644 index 0000000..68ed72c --- /dev/null +++ b/0020-qxl-async-io-support-using-new-spice-api.patch @@ -0,0 +1,659 @@ +>From a1950cb3afb36a78df3ac9a545d99baf7cc93ca2 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Thu, 23 Jun 2011 20:02:18 +0200 +Subject: [PATCH 20/28] qxl: async io support using new spice api + +Some of the QXL port i/o commands are waiting for the spice server to +complete certain actions. Add async versions for these commands, so we +don't block the vcpu while the spice server processses the command. +Instead the qxl device will raise an IRQ when done. + +The async command processing relies on an added QXLInterface::async_complete +and added QXLWorker::*_async additions, in spice server qxl >= 3.1 + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Alon Levy +--- + hw/qxl-render.c | 2 +- + hw/qxl.c | 240 ++++++++++++++++++++++++++++++++++++++++++++-------- + hw/qxl.h | 16 +++- + ui/spice-display.c | 47 ++++++++-- + ui/spice-display.h | 23 +++++- + 5 files changed, 274 insertions(+), 54 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 60b822d..643ff2d 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -125,7 +125,7 @@ void qxl_render_update(PCIQXLDevice *qxl) + + memset(dirty, 0, sizeof(dirty)); + qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1); ++ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); + + for (i = 0; i < ARRAY_SIZE(dirty); i++) { + if (qemu_spice_rect_is_empty(dirty+i)) { +diff --git a/hw/qxl.c b/hw/qxl.c +index 23e3240..d3109e4 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -120,7 +120,7 @@ static QXLMode qxl_modes[] = { + static PCIQXLDevice *qxl0; + + static void qxl_send_events(PCIQXLDevice *d, uint32_t events); +-static void qxl_destroy_primary(PCIQXLDevice *d); ++static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async); + static void qxl_reset_memslots(PCIQXLDevice *d); + static void qxl_reset_surfaces(PCIQXLDevice *d); + static void qxl_ring_set_dirty(PCIQXLDevice *qxl); +@@ -144,22 +144,47 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, + uint32_t num_dirty_rects, +- uint32_t clear_dirty_region) ++ uint32_t clear_dirty_region, ++ qxl_async_io async) + { +- qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects, +- num_dirty_rects, clear_dirty_region); ++ if (async == QXL_SYNC) { ++ qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, ++ dirty_rects, num_dirty_rects, clear_dirty_region); ++ } else { ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, ++ clear_dirty_region, 0); ++#else ++ abort(); ++#endif ++ } + } + +-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id) ++static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, ++ uint32_t id) + { + qemu_mutex_lock(&qxl->track_lock); +- PANIC_ON(id >= NUM_SURFACES); +- qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl->guest_surfaces.cmds[id] = 0; + qxl->guest_surfaces.count--; + qemu_mutex_unlock(&qxl->track_lock); + } + ++static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, ++ qxl_async_io async) ++{ ++ if (async) { ++#if SPICE_INTERFACE_QXL_MINOR < 1 ++ abort(); ++#else ++ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, ++ (uint64_t)id); ++#endif ++ } else { ++ qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); ++ qxl_spice_destroy_surface_wait_complete(qxl, id); ++ } ++} ++ + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count) + { +@@ -176,15 +201,28 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl) + qxl->ssd.worker->reset_memslots(qxl->ssd.worker); + } + +-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl) ++static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + { + qemu_mutex_lock(&qxl->track_lock); +- qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); + memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); + qxl->guest_surfaces.count = 0; + qemu_mutex_unlock(&qxl->track_lock); + } + ++static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) ++{ ++ if (async) { ++#if SPICE_INTERFACE_QXL_MINOR < 1 ++ abort(); ++#else ++ spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); ++#endif ++ } else { ++ qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); ++ qxl_spice_destroy_surfaces_complete(qxl); ++ } ++} ++ + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) + { + qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); +@@ -689,6 +727,38 @@ static int interface_flush_resources(QXLInstance *sin) + return ret; + } + ++static void qxl_create_guest_primary_complete(PCIQXLDevice *d); ++ ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ ++/* called from spice server thread context only */ ++static void interface_async_complete(QXLInstance *sin, uint64_t cookie) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ uint32_t current_async; ++ ++ qemu_mutex_lock(&qxl->async_lock); ++ current_async = qxl->current_async; ++ qxl->current_async = QXL_UNDEFINED_IO; ++ qemu_mutex_unlock(&qxl->async_lock); ++ ++ dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); ++ switch (current_async) { ++ case QXL_IO_CREATE_PRIMARY_ASYNC: ++ qxl_create_guest_primary_complete(qxl); ++ break; ++ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC: ++ qxl_spice_destroy_surfaces_complete(qxl); ++ break; ++ case QXL_IO_DESTROY_SURFACE_ASYNC: ++ qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie); ++ break; ++ } ++ qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); ++} ++ ++#endif ++ + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -708,6 +778,9 @@ static const QXLInterface qxl_interface = { + .req_cursor_notification = interface_req_cursor_notification, + .notify_update = interface_notify_update, + .flush_resources = interface_flush_resources, ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ .async_complete = interface_async_complete, ++#endif + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +@@ -727,7 +800,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) + return; + } + dprint(d, 1, "%s\n", __FUNCTION__); +- qxl_destroy_primary(d); ++ qxl_destroy_primary(d, QXL_SYNC); + } + + static void qxl_set_irq(PCIQXLDevice *d) +@@ -824,13 +897,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + + if (qxl->mode != QXL_MODE_VGA) { + dprint(qxl, 1, "%s\n", __FUNCTION__); +- qxl_destroy_primary(qxl); ++ qxl_destroy_primary(qxl, QXL_SYNC); + qxl_soft_reset(qxl); + } + vga_ioport_write(opaque, addr, val); + } + +-static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) ++static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, ++ qxl_async_io async) + { + static const int regions[] = { + QXL_RAM_RANGE_INDEX, +@@ -900,7 +974,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) + __FUNCTION__, memslot.slot_id, + memslot.virt_start, memslot.virt_end); + +- qemu_spice_add_memslot(&d->ssd, &memslot); ++ qemu_spice_add_memslot(&d->ssd, &memslot, async); + d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; + d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; + d->guest_slots[slot_id].delta = delta; +@@ -925,7 +999,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + { + dprint(d, 1, "%s:\n", __FUNCTION__); + d->mode = QXL_MODE_UNDEFINED; +- qxl_spice_destroy_surfaces(d); ++ qxl_spice_destroy_surfaces(d, QXL_SYNC); + } + + /* called from spice server thread context only */ +@@ -950,7 +1024,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + } + } + +-static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) ++static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl) ++{ ++ /* for local rendering */ ++ qxl_render_resize(qxl); ++} ++ ++static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, ++ qxl_async_io async) + { + QXLDevSurfaceCreate surface; + QXLSurfaceCreate *sc = &qxl->guest_primary.surface; +@@ -978,22 +1059,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) + + qxl->mode = QXL_MODE_NATIVE; + qxl->cmdflags = 0; +- qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface); ++ qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async); + +- /* for local rendering */ +- qxl_render_resize(qxl); ++ if (async == QXL_SYNC) { ++ qxl_create_guest_primary_complete(qxl); ++ } + } + +-static void qxl_destroy_primary(PCIQXLDevice *d) ++/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or ++ * done (in QXL_SYNC case), 0 otherwise. */ ++static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) + { + if (d->mode == QXL_MODE_UNDEFINED) { +- return; ++ return 0; + } + + dprint(d, 1, "%s\n", __FUNCTION__); + + d->mode = QXL_MODE_UNDEFINED; +- qemu_spice_destroy_primary_surface(&d->ssd, 0); ++ qemu_spice_destroy_primary_surface(&d->ssd, 0, async); ++ return 1; + } + + static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) +@@ -1023,10 +1108,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) + } + + d->guest_slots[0].slot = slot; +- qxl_add_memslot(d, 0, devmem); ++ qxl_add_memslot(d, 0, devmem, QXL_SYNC); + + d->guest_primary.surface = surface; +- qxl_create_guest_primary(d, 0); ++ qxl_create_guest_primary(d, 0, QXL_SYNC); + + d->mode = QXL_MODE_COMPAT; + d->cmdflags = QXL_COMMAND_FLAG_COMPAT; +@@ -1044,6 +1129,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + { + PCIQXLDevice *d = opaque; + uint32_t io_port = addr - d->io_base; ++ qxl_async_io async = QXL_SYNC; ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ uint32_t orig_io_port = io_port; ++#endif + + switch (io_port) { + case QXL_IO_RESET: +@@ -1053,6 +1142,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + case QXL_IO_CREATE_PRIMARY: + case QXL_IO_UPDATE_IRQ: + case QXL_IO_LOG: ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ case QXL_IO_MEMSLOT_ADD_ASYNC: ++ case QXL_IO_CREATE_PRIMARY_ASYNC: ++#endif + break; + default: + if (d->mode != QXL_MODE_VGA) { +@@ -1060,15 +1153,61 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + } + dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", + __func__, io_port, io_port_to_string(io_port)); ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ /* 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); ++ } ++#endif + return; + } + ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ /* we change the io_port to avoid ifdeffery in the main switch */ ++ orig_io_port = io_port; ++ switch (io_port) { ++ case QXL_IO_UPDATE_AREA_ASYNC: ++ io_port = QXL_IO_UPDATE_AREA; ++ goto async_common; ++ case QXL_IO_MEMSLOT_ADD_ASYNC: ++ io_port = QXL_IO_MEMSLOT_ADD; ++ goto async_common; ++ case QXL_IO_CREATE_PRIMARY_ASYNC: ++ io_port = QXL_IO_CREATE_PRIMARY; ++ goto async_common; ++ case QXL_IO_DESTROY_PRIMARY_ASYNC: ++ io_port = QXL_IO_DESTROY_PRIMARY; ++ goto async_common; ++ case QXL_IO_DESTROY_SURFACE_ASYNC: ++ io_port = QXL_IO_DESTROY_SURFACE_WAIT; ++ goto async_common; ++ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC: ++ io_port = QXL_IO_DESTROY_ALL_SURFACES; ++async_common: ++ async = QXL_ASYNC; ++ qemu_mutex_lock(&d->async_lock); ++ if (d->current_async != QXL_UNDEFINED_IO) { ++ qxl_guest_bug(d, "%d async started before last (%d) complete", ++ io_port, d->current_async); ++ qemu_mutex_unlock(&d->async_lock); ++ return; ++ } ++ d->current_async = orig_io_port; ++ qemu_mutex_unlock(&d->async_lock); ++ dprint(d, 2, "start async %d (%d)\n", io_port, val); ++ break; ++ default: ++ break; ++ } ++#endif ++ + switch (io_port) { + case QXL_IO_UPDATE_AREA: + { + QXLRect update = d->ram->update_area; + qxl_spice_update_area(d, d->ram->update_surface, +- &update, NULL, 0, 0); ++ &update, NULL, 0, 0, async); + break; + } + case QXL_IO_NOTIFY_CMD: +@@ -1116,7 +1255,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + break; + } + d->guest_slots[val].slot = d->ram->mem_slot; +- qxl_add_memslot(d, val, 0); ++ qxl_add_memslot(d, val, 0, async); + break; + case QXL_IO_MEMSLOT_DEL: + if (val >= NUM_MEMSLOTS) { +@@ -1127,31 +1266,56 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + break; + case QXL_IO_CREATE_PRIMARY: + if (val != 0) { +- qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0"); +- break; ++ qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0", ++ async); ++ goto cancel_async; + } +- dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n"); ++ dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async); + d->guest_primary.surface = d->ram->create_surface; +- qxl_create_guest_primary(d, 0); ++ qxl_create_guest_primary(d, 0, async); + break; + case QXL_IO_DESTROY_PRIMARY: + if (val != 0) { +- qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0"); +- break; ++ qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0", ++ async); ++ goto cancel_async; ++ } ++ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async, ++ qxl_mode_to_string(d->mode)); ++ if (!qxl_destroy_primary(d, async)) { ++ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n", ++ qxl_mode_to_string(d->mode)); ++ goto cancel_async; + } +- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode)); +- qxl_destroy_primary(d); + break; + case QXL_IO_DESTROY_SURFACE_WAIT: +- qxl_spice_destroy_surface_wait(d, val); ++ if (val >= NUM_SURFACES) { ++ qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):" ++ "%d >= NUM_SURFACES", async, val); ++ goto cancel_async; ++ } ++ qxl_spice_destroy_surface_wait(d, val, async); + break; + case QXL_IO_DESTROY_ALL_SURFACES: +- qxl_spice_destroy_surfaces(d); ++ d->mode = QXL_MODE_UNDEFINED; ++ qxl_spice_destroy_surfaces(d, async); + break; + default: + fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); + abort(); + } ++ return; ++cancel_async: ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ if (async) { ++ qxl_send_events(d, QXL_INTERRUPT_IO_CMD); ++ qemu_mutex_lock(&d->async_lock); ++ d->current_async = QXL_UNDEFINED_IO; ++ qemu_mutex_unlock(&d->async_lock); ++ } ++#else ++ return; ++#endif + } + + static uint32_t ioport_read(void *opaque, uint32_t addr) +@@ -1364,6 +1528,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + qxl->num_memslots = NUM_MEMSLOTS; + qxl->num_surfaces = NUM_SURFACES; + qemu_mutex_init(&qxl->track_lock); ++ qemu_mutex_init(&qxl->async_lock); ++ qxl->current_async = QXL_UNDEFINED_IO; + + switch (qxl->revision) { + case 1: /* spice 0.4 -- qxl-1 */ +@@ -1528,9 +1694,9 @@ static int qxl_post_load(void *opaque, int version) + if (!d->guest_slots[i].active) { + continue; + } +- qxl_add_memslot(d, i, 0); ++ qxl_add_memslot(d, i, 0, QXL_SYNC); + } +- qxl_create_guest_primary(d, 1); ++ qxl_create_guest_primary(d, 1, QXL_SYNC); + + /* replay surface-create and cursor-set commands */ + cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); +diff --git a/hw/qxl.h b/hw/qxl.h +index 32ca5a0..1046205 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -15,6 +15,8 @@ enum qxl_mode { + QXL_MODE_NATIVE, + }; + ++#define QXL_UNDEFINED_IO UINT32_MAX ++ + typedef struct PCIQXLDevice { + PCIDevice pci; + SimpleSpiceDisplay ssd; +@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice { + int32_t num_memslots; + int32_t num_surfaces; + ++ uint32_t current_async; ++ QemuMutex async_lock; ++ + struct guest_slots { + QXLMemSlot slot; + void *ptr; +@@ -104,13 +109,12 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...); + void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, + uint32_t num_dirty_rects, +- uint32_t clear_dirty_region); +-void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id); ++ uint32_t clear_dirty_region, ++ qxl_async_io async); + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count); + void qxl_spice_oom(PCIQXLDevice *qxl); + void qxl_spice_reset_memslots(PCIQXLDevice *qxl); +-void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl); + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); + void qxl_spice_reset_cursor(PCIQXLDevice *qxl); + +@@ -122,3 +126,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); + void qxl_render_resize(PCIQXLDevice *qxl); + void qxl_render_update(PCIQXLDevice *qxl); + void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id, ++ struct QXLRect *area, ++ uint32_t clear_dirty_region, ++ int is_vga); ++#endif +diff --git a/ui/spice-display.c b/ui/spice-display.c +index af10ae8..683d454 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -62,10 +62,18 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) + dest->right = MAX(dest->right, r->right); + } + +- +-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot) +-{ +- ssd->worker->add_memslot(ssd->worker, memslot); ++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, ++ qxl_async_io async) ++{ ++ if (async != QXL_SYNC) { ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); ++#else ++ abort(); ++#endif ++ } else { ++ ssd->worker->add_memslot(ssd->worker, memslot); ++ } + } + + void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) +@@ -74,14 +82,33 @@ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) + } + + void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, +- QXLDevSurfaceCreate *surface) +-{ +- ssd->worker->create_primary_surface(ssd->worker, id, surface); ++ QXLDevSurfaceCreate *surface, ++ qxl_async_io async) ++{ ++ if (async != QXL_SYNC) { ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); ++#else ++ abort(); ++#endif ++ } else { ++ ssd->worker->create_primary_surface(ssd->worker, id, surface); ++ } + } + +-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id) ++ ++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, ++ uint32_t id, qxl_async_io async) + { +- ssd->worker->destroy_primary_surface(ssd->worker, id); ++ if (async != QXL_SYNC) { ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); ++#else ++ abort(); ++#endif ++ } else { ++ ssd->worker->destroy_primary_surface(ssd->worker, id); ++ } + } + + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) +@@ -198,7 +225,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) + memset(&memslot, 0, sizeof(memslot)); + memslot.slot_group_id = MEMSLOT_GROUP_HOST; + memslot.virt_end = ~0; +- qemu_spice_add_memslot(ssd, &memslot); ++ qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC); + } + + void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) +@@ -218,14 +245,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + surface.mem = (intptr_t)ssd->buf; + surface.group_id = MEMSLOT_GROUP_HOST; + +- qemu_spice_create_primary_surface(ssd, 0, &surface); ++ qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); + } + + void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) + { + dprint(1, "%s:\n", __FUNCTION__); + +- qemu_spice_destroy_primary_surface(ssd, 0); ++ qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); + } + + void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) +diff --git a/ui/spice-display.h b/ui/spice-display.h +index abe99c7..1388641 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -33,6 +33,20 @@ + + #define NUM_SURFACES 1024 + ++/* ++ * Internal enum to differenciate between options for ++ * io calls that have a sync (old) version and an _async (new) ++ * version: ++ * QXL_SYNC: use the old version ++ * QXL_ASYNC: use the new version and make sure there are no two ++ * happening at the same time. This is used for guest initiated ++ * calls ++ */ ++typedef enum qxl_async_io { ++ QXL_SYNC, ++ QXL_ASYNC, ++} qxl_async_io; ++ + typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; + typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; + +@@ -82,12 +96,15 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); + void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); + +-void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot); ++void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, ++ qxl_async_io async); + void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, + uint32_t sid); + void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, +- QXLDevSurfaceCreate *surface); +-void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id); ++ QXLDevSurfaceCreate *surface, ++ qxl_async_io async); ++void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, ++ uint32_t id, qxl_async_io async); + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); + void qemu_spice_start(SimpleSpiceDisplay *ssd); + void qemu_spice_stop(SimpleSpiceDisplay *ssd); +-- +1.7.5.1 + diff --git a/0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch b/0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch deleted file mode 100644 index e9f4866..0000000 --- a/0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch +++ /dev/null @@ -1,52 +0,0 @@ ->From beffb6d82668c7f8bcead447422529532cc0b4e7 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 6 Jul 2011 13:40:29 +0200 -Subject: [PATCH 20/25] qxl: make qxl_guest_bug take variable arguments - -Signed-off-by: Alon Levy ---- - hw/qxl.c | 9 +++++++-- - hw/qxl.h | 2 +- - 2 files changed, 8 insertions(+), 3 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 28c8b5d..c50eaf9 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -125,13 +125,18 @@ static void qxl_reset_memslots(PCIQXLDevice *d); - static void qxl_reset_surfaces(PCIQXLDevice *d); - static void qxl_ring_set_dirty(PCIQXLDevice *qxl); - --void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg) -+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) - { - #if SPICE_INTERFACE_QXL_MINOR >= 1 - qxl_send_events(qxl, QXL_INTERRUPT_ERROR); - #endif - if (qxl->guestdebug) { -- fprintf(stderr, "qxl-%d: guest bug: %s\n", qxl->id, msg); -+ va_list ap; -+ va_start(ap, msg); -+ fprintf(stderr, "qxl-%d: guest bug: ", qxl->id); -+ vfprintf(stderr, msg, ap); -+ fprintf(stderr, "\n"); -+ va_end(ap); - } - } - -diff --git a/hw/qxl.h b/hw/qxl.h -index 5db9aae..32ca5a0 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -99,7 +99,7 @@ typedef struct PCIQXLDevice { - - /* qxl.c */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); --void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg); -+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...); - - void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, --- -1.7.5.1 - diff --git a/0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch b/0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch new file mode 100644 index 0000000..41b88a3 --- /dev/null +++ b/0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch @@ -0,0 +1,77 @@ +>From fed782e33714e6a44bca9a8c3ab8b017393e8089 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 5 Jun 2011 11:01:48 +0300 +Subject: [PATCH 21/28] qxl: add QXL_IO_FLUSH_{SURFACES,RELEASE} for guest + S3&S4 support + +Add two new IOs. + QXL_IO_FLUSH_SURFACES - equivalent to update area for all surfaces, used + to reduce vmexits from NumSurfaces to 1 on guest S3, S4 and resolution change (windows + driver implementation is such that this is done on each of those occasions). + QXL_IO_FLUSH_RELEASE - used to ensure anything on last_release is put on the release ring + for the client to free. + +Signed-off-by: Yonit Halperin +Signed-off-by: Alon Levy +--- + hw/qxl.c | 30 ++++++++++++++++++++++++++++++ + 1 files changed, 30 insertions(+), 0 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index d3109e4..847a9b8 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -185,6 +185,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + } + } + ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) ++{ ++ spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); ++} ++#endif ++ + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count) + { +@@ -1184,6 +1191,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) + goto async_common; + case QXL_IO_DESTROY_ALL_SURFACES_ASYNC: + io_port = QXL_IO_DESTROY_ALL_SURFACES; ++ goto async_common; ++ case QXL_IO_FLUSH_SURFACES_ASYNC: + async_common: + async = QXL_ASYNC; + qemu_mutex_lock(&d->async_lock); +@@ -1296,6 +1305,27 @@ async_common: + } + qxl_spice_destroy_surface_wait(d, val, async); + break; ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ case QXL_IO_FLUSH_RELEASE: { ++ QXLReleaseRing *ring = &d->ram->release_ring; ++ if (ring->prod - ring->cons + 1 == ring->num_items) { ++ fprintf(stderr, ++ "ERROR: no flush, full release ring [p%d,%dc]\n", ++ ring->prod, ring->cons); ++ } ++ qxl_push_free_res(d, 1 /* flush */); ++ dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n", ++ qxl_mode_to_string(d->mode), d->guest_surfaces.count, ++ d->num_free_res, d->last_release); ++ break; ++ } ++ case QXL_IO_FLUSH_SURFACES_ASYNC: ++ dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n", ++ val, qxl_mode_to_string(d->mode), d->guest_surfaces.count, ++ d->num_free_res); ++ qxl_spice_flush_surfaces_async(d); ++ break; ++#endif + case QXL_IO_DESTROY_ALL_SURFACES: + d->mode = QXL_MODE_UNDEFINED; + qxl_spice_destroy_surfaces(d, async); +-- +1.7.5.1 + diff --git a/0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch b/0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch deleted file mode 100644 index 3a1041b..0000000 --- a/0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch +++ /dev/null @@ -1,31 +0,0 @@ ->From 4eb9272a4185cf47a4a4e9cb59a95cfd9939e86c Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 29 Jun 2011 11:53:21 +0200 -Subject: [PATCH 21/25] qxl: only disallow specific io's in vga mode - -Since the driver is still in operation even after moving to UNDEFINED, i.e. -by destroying primary in any way. - -Signed-off-by: Alon Levy ---- - hw/qxl.c | 3 ++- - 1 files changed, 2 insertions(+), 1 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index c50eaf9..23e3240 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1055,8 +1055,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - case QXL_IO_LOG: - break; - default: -- if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT) -+ if (d->mode != QXL_MODE_VGA) { - break; -+ } - dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", - __func__, io_port, io_port_to_string(io_port)); - return; --- -1.7.5.1 - diff --git a/0022-qxl-async-io-support-using-new-spice-api.patch b/0022-qxl-async-io-support-using-new-spice-api.patch deleted file mode 100644 index 74ca328..0000000 --- a/0022-qxl-async-io-support-using-new-spice-api.patch +++ /dev/null @@ -1,659 +0,0 @@ ->From b25a2a169340f70b29d47d0598df1ac525a87bf9 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Thu, 23 Jun 2011 20:02:18 +0200 -Subject: [PATCH 22/25] qxl: async io support using new spice api - -Some of the QXL port i/o commands are waiting for the spice server to -complete certain actions. Add async versions for these commands, so we -don't block the vcpu while the spice server processses the command. -Instead the qxl device will raise an IRQ when done. - -The async command processing relies on an added QXLInterface::async_complete -and added QXLWorker::*_async additions, in spice server qxl >= 3.1 - -Signed-off-by: Gerd Hoffmann -Signed-off-by: Alon Levy ---- - hw/qxl-render.c | 2 +- - hw/qxl.c | 240 ++++++++++++++++++++++++++++++++++++++++++++-------- - hw/qxl.h | 16 +++- - ui/spice-display.c | 47 ++++++++-- - ui/spice-display.h | 23 +++++- - 5 files changed, 274 insertions(+), 54 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 60b822d..643ff2d 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -125,7 +125,7 @@ void qxl_render_update(PCIQXLDevice *qxl) - - memset(dirty, 0, sizeof(dirty)); - qxl_spice_update_area(qxl, 0, &update, -- dirty, ARRAY_SIZE(dirty), 1); -+ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); - - for (i = 0; i < ARRAY_SIZE(dirty); i++) { - if (qemu_spice_rect_is_empty(dirty+i)) { -diff --git a/hw/qxl.c b/hw/qxl.c -index 23e3240..d3109e4 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -120,7 +120,7 @@ static QXLMode qxl_modes[] = { - static PCIQXLDevice *qxl0; - - static void qxl_send_events(PCIQXLDevice *d, uint32_t events); --static void qxl_destroy_primary(PCIQXLDevice *d); -+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async); - static void qxl_reset_memslots(PCIQXLDevice *d); - static void qxl_reset_surfaces(PCIQXLDevice *d); - static void qxl_ring_set_dirty(PCIQXLDevice *qxl); -@@ -144,22 +144,47 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) - void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, - uint32_t num_dirty_rects, -- uint32_t clear_dirty_region) -+ uint32_t clear_dirty_region, -+ qxl_async_io async) - { -- qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, dirty_rects, -- num_dirty_rects, clear_dirty_region); -+ if (async == QXL_SYNC) { -+ qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, -+ dirty_rects, num_dirty_rects, clear_dirty_region); -+ } else { -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, -+ clear_dirty_region, 0); -+#else -+ abort(); -+#endif -+ } - } - --void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id) -+static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, -+ uint32_t id) - { - qemu_mutex_lock(&qxl->track_lock); -- PANIC_ON(id >= NUM_SURFACES); -- qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); - qxl->guest_surfaces.cmds[id] = 0; - qxl->guest_surfaces.count--; - qemu_mutex_unlock(&qxl->track_lock); - } - -+static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, -+ qxl_async_io async) -+{ -+ if (async) { -+#if SPICE_INTERFACE_QXL_MINOR < 1 -+ abort(); -+#else -+ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, -+ (uint64_t)id); -+#endif -+ } else { -+ qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); -+ qxl_spice_destroy_surface_wait_complete(qxl, id); -+ } -+} -+ - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, - uint32_t count) - { -@@ -176,15 +201,28 @@ void qxl_spice_reset_memslots(PCIQXLDevice *qxl) - qxl->ssd.worker->reset_memslots(qxl->ssd.worker); - } - --void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl) -+static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) - { - qemu_mutex_lock(&qxl->track_lock); -- qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); - memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); - qxl->guest_surfaces.count = 0; - qemu_mutex_unlock(&qxl->track_lock); - } - -+static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) -+{ -+ if (async) { -+#if SPICE_INTERFACE_QXL_MINOR < 1 -+ abort(); -+#else -+ spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); -+#endif -+ } else { -+ qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); -+ qxl_spice_destroy_surfaces_complete(qxl); -+ } -+} -+ - void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) - { - qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); -@@ -689,6 +727,38 @@ static int interface_flush_resources(QXLInstance *sin) - return ret; - } - -+static void qxl_create_guest_primary_complete(PCIQXLDevice *d); -+ -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ -+/* called from spice server thread context only */ -+static void interface_async_complete(QXLInstance *sin, uint64_t cookie) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ uint32_t current_async; -+ -+ qemu_mutex_lock(&qxl->async_lock); -+ current_async = qxl->current_async; -+ qxl->current_async = QXL_UNDEFINED_IO; -+ qemu_mutex_unlock(&qxl->async_lock); -+ -+ dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); -+ switch (current_async) { -+ case QXL_IO_CREATE_PRIMARY_ASYNC: -+ qxl_create_guest_primary_complete(qxl); -+ break; -+ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC: -+ qxl_spice_destroy_surfaces_complete(qxl); -+ break; -+ case QXL_IO_DESTROY_SURFACE_ASYNC: -+ qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie); -+ break; -+ } -+ qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); -+} -+ -+#endif -+ - static const QXLInterface qxl_interface = { - .base.type = SPICE_INTERFACE_QXL, - .base.description = "qxl gpu", -@@ -708,6 +778,9 @@ static const QXLInterface qxl_interface = { - .req_cursor_notification = interface_req_cursor_notification, - .notify_update = interface_notify_update, - .flush_resources = interface_flush_resources, -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ .async_complete = interface_async_complete, -+#endif - }; - - static void qxl_enter_vga_mode(PCIQXLDevice *d) -@@ -727,7 +800,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) - return; - } - dprint(d, 1, "%s\n", __FUNCTION__); -- qxl_destroy_primary(d); -+ qxl_destroy_primary(d, QXL_SYNC); - } - - static void qxl_set_irq(PCIQXLDevice *d) -@@ -824,13 +897,14 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) - - if (qxl->mode != QXL_MODE_VGA) { - dprint(qxl, 1, "%s\n", __FUNCTION__); -- qxl_destroy_primary(qxl); -+ qxl_destroy_primary(qxl, QXL_SYNC); - qxl_soft_reset(qxl); - } - vga_ioport_write(opaque, addr, val); - } - --static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) -+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, -+ qxl_async_io async) - { - static const int regions[] = { - QXL_RAM_RANGE_INDEX, -@@ -900,7 +974,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) - __FUNCTION__, memslot.slot_id, - memslot.virt_start, memslot.virt_end); - -- qemu_spice_add_memslot(&d->ssd, &memslot); -+ qemu_spice_add_memslot(&d->ssd, &memslot, async); - d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; - d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; - d->guest_slots[slot_id].delta = delta; -@@ -925,7 +999,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) - { - dprint(d, 1, "%s:\n", __FUNCTION__); - d->mode = QXL_MODE_UNDEFINED; -- qxl_spice_destroy_surfaces(d); -+ qxl_spice_destroy_surfaces(d, QXL_SYNC); - } - - /* called from spice server thread context only */ -@@ -950,7 +1024,14 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) - } - } - --static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) -+static void qxl_create_guest_primary_complete(PCIQXLDevice *qxl) -+{ -+ /* for local rendering */ -+ qxl_render_resize(qxl); -+} -+ -+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, -+ qxl_async_io async) - { - QXLDevSurfaceCreate surface; - QXLSurfaceCreate *sc = &qxl->guest_primary.surface; -@@ -978,22 +1059,26 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) - - qxl->mode = QXL_MODE_NATIVE; - qxl->cmdflags = 0; -- qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface); -+ qemu_spice_create_primary_surface(&qxl->ssd, 0, &surface, async); - -- /* for local rendering */ -- qxl_render_resize(qxl); -+ if (async == QXL_SYNC) { -+ qxl_create_guest_primary_complete(qxl); -+ } - } - --static void qxl_destroy_primary(PCIQXLDevice *d) -+/* return 1 if surface destoy was initiated (in QXL_ASYNC case) or -+ * done (in QXL_SYNC case), 0 otherwise. */ -+static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) - { - if (d->mode == QXL_MODE_UNDEFINED) { -- return; -+ return 0; - } - - dprint(d, 1, "%s\n", __FUNCTION__); - - d->mode = QXL_MODE_UNDEFINED; -- qemu_spice_destroy_primary_surface(&d->ssd, 0); -+ qemu_spice_destroy_primary_surface(&d->ssd, 0, async); -+ return 1; - } - - static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) -@@ -1023,10 +1108,10 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) - } - - d->guest_slots[0].slot = slot; -- qxl_add_memslot(d, 0, devmem); -+ qxl_add_memslot(d, 0, devmem, QXL_SYNC); - - d->guest_primary.surface = surface; -- qxl_create_guest_primary(d, 0); -+ qxl_create_guest_primary(d, 0, QXL_SYNC); - - d->mode = QXL_MODE_COMPAT; - d->cmdflags = QXL_COMMAND_FLAG_COMPAT; -@@ -1044,6 +1129,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - { - PCIQXLDevice *d = opaque; - uint32_t io_port = addr - d->io_base; -+ qxl_async_io async = QXL_SYNC; -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ uint32_t orig_io_port = io_port; -+#endif - - switch (io_port) { - case QXL_IO_RESET: -@@ -1053,6 +1142,10 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - case QXL_IO_CREATE_PRIMARY: - case QXL_IO_UPDATE_IRQ: - case QXL_IO_LOG: -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ case QXL_IO_MEMSLOT_ADD_ASYNC: -+ case QXL_IO_CREATE_PRIMARY_ASYNC: -+#endif - break; - default: - if (d->mode != QXL_MODE_VGA) { -@@ -1060,15 +1153,61 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - } - dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", - __func__, io_port, io_port_to_string(io_port)); -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ /* 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); -+ } -+#endif - return; - } - -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ /* we change the io_port to avoid ifdeffery in the main switch */ -+ orig_io_port = io_port; -+ switch (io_port) { -+ case QXL_IO_UPDATE_AREA_ASYNC: -+ io_port = QXL_IO_UPDATE_AREA; -+ goto async_common; -+ case QXL_IO_MEMSLOT_ADD_ASYNC: -+ io_port = QXL_IO_MEMSLOT_ADD; -+ goto async_common; -+ case QXL_IO_CREATE_PRIMARY_ASYNC: -+ io_port = QXL_IO_CREATE_PRIMARY; -+ goto async_common; -+ case QXL_IO_DESTROY_PRIMARY_ASYNC: -+ io_port = QXL_IO_DESTROY_PRIMARY; -+ goto async_common; -+ case QXL_IO_DESTROY_SURFACE_ASYNC: -+ io_port = QXL_IO_DESTROY_SURFACE_WAIT; -+ goto async_common; -+ case QXL_IO_DESTROY_ALL_SURFACES_ASYNC: -+ io_port = QXL_IO_DESTROY_ALL_SURFACES; -+async_common: -+ async = QXL_ASYNC; -+ qemu_mutex_lock(&d->async_lock); -+ if (d->current_async != QXL_UNDEFINED_IO) { -+ qxl_guest_bug(d, "%d async started before last (%d) complete", -+ io_port, d->current_async); -+ qemu_mutex_unlock(&d->async_lock); -+ return; -+ } -+ d->current_async = orig_io_port; -+ qemu_mutex_unlock(&d->async_lock); -+ dprint(d, 2, "start async %d (%d)\n", io_port, val); -+ break; -+ default: -+ break; -+ } -+#endif -+ - switch (io_port) { - case QXL_IO_UPDATE_AREA: - { - QXLRect update = d->ram->update_area; - qxl_spice_update_area(d, d->ram->update_surface, -- &update, NULL, 0, 0); -+ &update, NULL, 0, 0, async); - break; - } - case QXL_IO_NOTIFY_CMD: -@@ -1116,7 +1255,7 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - break; - } - d->guest_slots[val].slot = d->ram->mem_slot; -- qxl_add_memslot(d, val, 0); -+ qxl_add_memslot(d, val, 0, async); - break; - case QXL_IO_MEMSLOT_DEL: - if (val >= NUM_MEMSLOTS) { -@@ -1127,31 +1266,56 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - break; - case QXL_IO_CREATE_PRIMARY: - if (val != 0) { -- qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY: val != 0"); -- break; -+ qxl_guest_bug(d, "QXL_IO_CREATE_PRIMARY (async=%d): val != 0", -+ async); -+ goto cancel_async; - } -- dprint(d, 1, "QXL_IO_CREATE_PRIMARY\n"); -+ dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async); - d->guest_primary.surface = d->ram->create_surface; -- qxl_create_guest_primary(d, 0); -+ qxl_create_guest_primary(d, 0, async); - break; - case QXL_IO_DESTROY_PRIMARY: - if (val != 0) { -- qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY: val != 0"); -- break; -+ qxl_guest_bug(d, "QXL_IO_DESTROY_PRIMARY (async=%d): val != 0", -+ async); -+ goto cancel_async; -+ } -+ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async, -+ qxl_mode_to_string(d->mode)); -+ if (!qxl_destroy_primary(d, async)) { -+ dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n", -+ qxl_mode_to_string(d->mode)); -+ goto cancel_async; - } -- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (%s)\n", qxl_mode_to_string(d->mode)); -- qxl_destroy_primary(d); - break; - case QXL_IO_DESTROY_SURFACE_WAIT: -- qxl_spice_destroy_surface_wait(d, val); -+ if (val >= NUM_SURFACES) { -+ qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):" -+ "%d >= NUM_SURFACES", async, val); -+ goto cancel_async; -+ } -+ qxl_spice_destroy_surface_wait(d, val, async); - break; - case QXL_IO_DESTROY_ALL_SURFACES: -- qxl_spice_destroy_surfaces(d); -+ d->mode = QXL_MODE_UNDEFINED; -+ qxl_spice_destroy_surfaces(d, async); - break; - default: - fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); - abort(); - } -+ return; -+cancel_async: -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ if (async) { -+ qxl_send_events(d, QXL_INTERRUPT_IO_CMD); -+ qemu_mutex_lock(&d->async_lock); -+ d->current_async = QXL_UNDEFINED_IO; -+ qemu_mutex_unlock(&d->async_lock); -+ } -+#else -+ return; -+#endif - } - - static uint32_t ioport_read(void *opaque, uint32_t addr) -@@ -1364,6 +1528,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) - qxl->num_memslots = NUM_MEMSLOTS; - qxl->num_surfaces = NUM_SURFACES; - qemu_mutex_init(&qxl->track_lock); -+ qemu_mutex_init(&qxl->async_lock); -+ qxl->current_async = QXL_UNDEFINED_IO; - - switch (qxl->revision) { - case 1: /* spice 0.4 -- qxl-1 */ -@@ -1528,9 +1694,9 @@ static int qxl_post_load(void *opaque, int version) - if (!d->guest_slots[i].active) { - continue; - } -- qxl_add_memslot(d, i, 0); -+ qxl_add_memslot(d, i, 0, QXL_SYNC); - } -- qxl_create_guest_primary(d, 1); -+ qxl_create_guest_primary(d, 1, QXL_SYNC); - - /* replay surface-create and cursor-set commands */ - cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); -diff --git a/hw/qxl.h b/hw/qxl.h -index 32ca5a0..1046205 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -15,6 +15,8 @@ enum qxl_mode { - QXL_MODE_NATIVE, - }; - -+#define QXL_UNDEFINED_IO UINT32_MAX -+ - typedef struct PCIQXLDevice { - PCIDevice pci; - SimpleSpiceDisplay ssd; -@@ -30,6 +32,9 @@ typedef struct PCIQXLDevice { - int32_t num_memslots; - int32_t num_surfaces; - -+ uint32_t current_async; -+ QemuMutex async_lock; -+ - struct guest_slots { - QXLMemSlot slot; - void *ptr; -@@ -104,13 +109,12 @@ void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...); - void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, - uint32_t num_dirty_rects, -- uint32_t clear_dirty_region); --void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id); -+ uint32_t clear_dirty_region, -+ qxl_async_io async); - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, - uint32_t count); - void qxl_spice_oom(PCIQXLDevice *qxl); - void qxl_spice_reset_memslots(PCIQXLDevice *qxl); --void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl); - void qxl_spice_reset_image_cache(PCIQXLDevice *qxl); - void qxl_spice_reset_cursor(PCIQXLDevice *qxl); - -@@ -122,3 +126,9 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); - void qxl_render_resize(PCIQXLDevice *qxl); - void qxl_render_update(PCIQXLDevice *qxl); - void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id, -+ struct QXLRect *area, -+ uint32_t clear_dirty_region, -+ int is_vga); -+#endif -diff --git a/ui/spice-display.c b/ui/spice-display.c -index af10ae8..683d454 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -62,10 +62,18 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) - dest->right = MAX(dest->right, r->right); - } - -- --void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot) --{ -- ssd->worker->add_memslot(ssd->worker, memslot); -+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, -+ qxl_async_io async) -+{ -+ if (async != QXL_SYNC) { -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); -+#else -+ abort(); -+#endif -+ } else { -+ ssd->worker->add_memslot(ssd->worker, memslot); -+ } - } - - void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) -@@ -74,14 +82,33 @@ void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) - } - - void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, -- QXLDevSurfaceCreate *surface) --{ -- ssd->worker->create_primary_surface(ssd->worker, id, surface); -+ QXLDevSurfaceCreate *surface, -+ qxl_async_io async) -+{ -+ if (async != QXL_SYNC) { -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); -+#else -+ abort(); -+#endif -+ } else { -+ ssd->worker->create_primary_surface(ssd->worker, id, surface); -+ } - } - --void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id) -+ -+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, -+ uint32_t id, qxl_async_io async) - { -- ssd->worker->destroy_primary_surface(ssd->worker, id); -+ if (async != QXL_SYNC) { -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); -+#else -+ abort(); -+#endif -+ } else { -+ ssd->worker->destroy_primary_surface(ssd->worker, id); -+ } - } - - void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) -@@ -198,7 +225,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) - memset(&memslot, 0, sizeof(memslot)); - memslot.slot_group_id = MEMSLOT_GROUP_HOST; - memslot.virt_end = ~0; -- qemu_spice_add_memslot(ssd, &memslot); -+ qemu_spice_add_memslot(ssd, &memslot, QXL_SYNC); - } - - void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) -@@ -218,14 +245,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) - surface.mem = (intptr_t)ssd->buf; - surface.group_id = MEMSLOT_GROUP_HOST; - -- qemu_spice_create_primary_surface(ssd, 0, &surface); -+ qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); - } - - void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) - { - dprint(1, "%s:\n", __FUNCTION__); - -- qemu_spice_destroy_primary_surface(ssd, 0); -+ qemu_spice_destroy_primary_surface(ssd, 0, QXL_SYNC); - } - - void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) -diff --git a/ui/spice-display.h b/ui/spice-display.h -index abe99c7..1388641 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -33,6 +33,20 @@ - - #define NUM_SURFACES 1024 - -+/* -+ * Internal enum to differenciate between options for -+ * io calls that have a sync (old) version and an _async (new) -+ * version: -+ * QXL_SYNC: use the old version -+ * QXL_ASYNC: use the new version and make sure there are no two -+ * happening at the same time. This is used for guest initiated -+ * calls -+ */ -+typedef enum qxl_async_io { -+ QXL_SYNC, -+ QXL_ASYNC, -+} qxl_async_io; -+ - typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; - typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; - -@@ -82,12 +96,15 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); - void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); - --void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot); -+void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, -+ qxl_async_io async); - void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, - uint32_t sid); - void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, -- QXLDevSurfaceCreate *surface); --void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id); -+ QXLDevSurfaceCreate *surface, -+ qxl_async_io async); -+void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, -+ uint32_t id, qxl_async_io async); - void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); - void qemu_spice_start(SimpleSpiceDisplay *ssd); - void qemu_spice_stop(SimpleSpiceDisplay *ssd); --- -1.7.5.1 - diff --git a/0022-qxl-bump-pci-rev.patch b/0022-qxl-bump-pci-rev.patch new file mode 100644 index 0000000..17ebfc1 --- /dev/null +++ b/0022-qxl-bump-pci-rev.patch @@ -0,0 +1,90 @@ +>From 81c99528614b45f2b8407418f7e2b5742559ac19 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 29 Jun 2011 15:51:24 +0200 +Subject: [PATCH 22/28] qxl: bump pci rev + +Inform guest drivers about the new features I/O commands we have +now (async commands, S3 support) if building with newer spice, i.e. +if SPICE_INTERFACE_QXL_MINOR >= 1. + +sneaked in some 81+ column line spliting. + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Alon Levy +--- + hw/qxl.c | 25 ++++++++++++++++++------- + hw/qxl.h | 6 ++++++ + 2 files changed, 24 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 847a9b8..b684608 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1566,9 +1566,14 @@ static int qxl_init_common(PCIQXLDevice *qxl) + pci_device_rev = QXL_REVISION_STABLE_V04; + break; + case 2: /* spice 0.6 -- qxl-2 */ +- default: + pci_device_rev = QXL_REVISION_STABLE_V06; + break; ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++ case 3: /* qxl-3 */ ++#endif ++ default: ++ pci_device_rev = QXL_DEFAULT_REVISION; ++ break; + } + + pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); +@@ -1830,9 +1835,12 @@ static PCIDeviceInfo qxl_info_primary = { + .device_id = QXL_DEVICE_ID_STABLE, + .class_id = PCI_CLASS_DISPLAY_VGA, + .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("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, ++ QXL_DEFAULT_REVISION), + DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), +@@ -1851,9 +1859,12 @@ static PCIDeviceInfo qxl_info_secondary = { + .device_id = QXL_DEVICE_ID_STABLE, + .class_id = PCI_CLASS_DISPLAY_OTHER, + .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("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, ++ QXL_DEFAULT_REVISION), + 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 1046205..4bcf7e1 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -102,6 +102,12 @@ typedef struct PCIQXLDevice { + } \ + } while (0) + ++#if SPICE_INTERFACE_QXL_MINOR >= 1 ++#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 ++#else ++#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06 ++#endif ++ + /* qxl.c */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); + void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...); +-- +1.7.5.1 + diff --git a/0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch b/0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch deleted file mode 100644 index ab900ef..0000000 --- a/0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch +++ /dev/null @@ -1,77 +0,0 @@ ->From b751be42f3da5666bd11d5a0acb20f225d9a4eb9 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Sun, 5 Jun 2011 11:01:48 +0300 -Subject: [PATCH 23/25] qxl: add QXL_IO_FLUSH_{SURFACES,RELEASE} for guest - S3&S4 support - -Add two new IOs. - QXL_IO_FLUSH_SURFACES - equivalent to update area for all surfaces, used - to reduce vmexits from NumSurfaces to 1 on guest S3, S4 and resolution change (windows - driver implementation is such that this is done on each of those occasions). - QXL_IO_FLUSH_RELEASE - used to ensure anything on last_release is put on the release ring - for the client to free. - -Signed-off-by: Yonit Halperin -Signed-off-by: Alon Levy ---- - hw/qxl.c | 30 ++++++++++++++++++++++++++++++ - 1 files changed, 30 insertions(+), 0 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index d3109e4..847a9b8 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -185,6 +185,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - } - } - -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) -+{ -+ spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); -+} -+#endif -+ - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, - uint32_t count) - { -@@ -1184,6 +1191,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) - goto async_common; - case QXL_IO_DESTROY_ALL_SURFACES_ASYNC: - io_port = QXL_IO_DESTROY_ALL_SURFACES; -+ goto async_common; -+ case QXL_IO_FLUSH_SURFACES_ASYNC: - async_common: - async = QXL_ASYNC; - qemu_mutex_lock(&d->async_lock); -@@ -1296,6 +1305,27 @@ async_common: - } - qxl_spice_destroy_surface_wait(d, val, async); - break; -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ case QXL_IO_FLUSH_RELEASE: { -+ QXLReleaseRing *ring = &d->ram->release_ring; -+ if (ring->prod - ring->cons + 1 == ring->num_items) { -+ fprintf(stderr, -+ "ERROR: no flush, full release ring [p%d,%dc]\n", -+ ring->prod, ring->cons); -+ } -+ qxl_push_free_res(d, 1 /* flush */); -+ dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n", -+ qxl_mode_to_string(d->mode), d->guest_surfaces.count, -+ d->num_free_res, d->last_release); -+ break; -+ } -+ case QXL_IO_FLUSH_SURFACES_ASYNC: -+ dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC (%d) (%s, s#=%d, res#=%d)\n", -+ val, qxl_mode_to_string(d->mode), d->guest_surfaces.count, -+ d->num_free_res); -+ qxl_spice_flush_surfaces_async(d); -+ break; -+#endif - case QXL_IO_DESTROY_ALL_SURFACES: - d->mode = QXL_MODE_UNDEFINED; - qxl_spice_destroy_surfaces(d, async); --- -1.7.5.1 - diff --git a/0023-virtio-serial-bus-replay-guest_open-on-migration.patch b/0023-virtio-serial-bus-replay-guest_open-on-migration.patch new file mode 100644 index 0000000..5abb114 --- /dev/null +++ b/0023-virtio-serial-bus-replay-guest_open-on-migration.patch @@ -0,0 +1,50 @@ +>From ab57ac80b3e681a61ed34c84c36df673e6f9be33 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Thu, 28 Jul 2011 15:08:48 +0300 +Subject: [PATCH 23/28] virtio-serial-bus: replay guest_open on migration + +When migrating a host with with a spice agent running the mouse becomes +non operational after the migration. This is rhbz #725965. + +The problem is that after migration spice doesn't know the guest agent is open. +Spice is just a char dev here. And a chardev cannot query it's device, the +device has to let the chardev know when it is open. Right now after migration +the chardev which is recreated is in it's default state, which assumes the +guest is disconnected. + +Char devices carry no information across migration, but the virtio-serial does +already carry the guest_connected state. This patch passes that bit to the +chardev. + +Signed-off-by: Alon Levy +--- + hw/virtio-serial-bus.c | 6 ++++++ + 1 files changed, 6 insertions(+), 0 deletions(-) + +diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c +index c5eb931..4a6d932 100644 +--- a/hw/virtio-serial-bus.c ++++ b/hw/virtio-serial-bus.c +@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) + for (i = 0; i < nr_active_ports; i++) { + uint32_t id; + bool host_connected; ++ VirtIOSerialPortInfo *info; + + id = qemu_get_be32(f); + port = find_port_by_id(s, id); +@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) + } + + port->guest_connected = qemu_get_byte(f); ++ info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); ++ if (port->guest_connected && info->guest_open) { ++ /* replay guest open */ ++ info->guest_open(port); ++ } + host_connected = qemu_get_byte(f); + if (host_connected != port->host_connected) { + /* +-- +1.7.5.1 + diff --git a/0024-qemu-char-make-qemu_chr_event-public.patch b/0024-qemu-char-make-qemu_chr_event-public.patch new file mode 100644 index 0000000..2294597 --- /dev/null +++ b/0024-qemu-char-make-qemu_chr_event-public.patch @@ -0,0 +1,42 @@ +>From c86147be45fe6cc38efa932f9587774d626a881b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 11 Aug 2011 12:16:11 +0200 +Subject: [PATCH 24/28] qemu-char: make qemu_chr_event public + +Make qemu_chr_event public so that it can be used by chardev code +which lives outside of qemu-char.c + +Signed-off-by: Hans de Goede +--- + qemu-char.c | 2 +- + qemu-char.h | 1 + + 2 files changed, 2 insertions(+), 1 deletions(-) + +diff --git a/qemu-char.c b/qemu-char.c +index 8d39500..5d5a6d5 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -119,7 +119,7 @@ static void char_write_unblocked(void *opaque) + chr->chr_write_unblocked(chr->handler_opaque); + } + +-static void qemu_chr_event(CharDriverState *s, int event) ++void qemu_chr_event(CharDriverState *s, int event) + { + /* Keep track if the char device is open */ + switch (event) { +diff --git a/qemu-char.h b/qemu-char.h +index 68e7b5b..77ad62d 100644 +--- a/qemu-char.h ++++ b/qemu-char.h +@@ -107,6 +107,7 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg); + void qemu_chr_generic_open(CharDriverState *s); + int qemu_chr_can_read(CharDriverState *s); + void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len); ++void qemu_chr_event(CharDriverState *s, int event); + int qemu_chr_get_msgfd(CharDriverState *s); + void qemu_chr_accept_input(CharDriverState *s); + int qemu_chr_add_client(CharDriverState *s, int fd); +-- +1.7.5.1 + diff --git a/0024-qxl-bump-pci-rev.patch b/0024-qxl-bump-pci-rev.patch deleted file mode 100644 index b301840..0000000 --- a/0024-qxl-bump-pci-rev.patch +++ /dev/null @@ -1,90 +0,0 @@ ->From 37779d77dff7cb73d333a6440cadd1db0638516b Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 29 Jun 2011 15:51:24 +0200 -Subject: [PATCH 24/25] qxl: bump pci rev - -Inform guest drivers about the new features I/O commands we have -now (async commands, S3 support) if building with newer spice, i.e. -if SPICE_INTERFACE_QXL_MINOR >= 1. - -sneaked in some 81+ column line spliting. - -Signed-off-by: Gerd Hoffmann -Signed-off-by: Alon Levy ---- - hw/qxl.c | 25 ++++++++++++++++++------- - hw/qxl.h | 6 ++++++ - 2 files changed, 24 insertions(+), 7 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 847a9b8..b684608 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1566,9 +1566,14 @@ static int qxl_init_common(PCIQXLDevice *qxl) - pci_device_rev = QXL_REVISION_STABLE_V04; - break; - case 2: /* spice 0.6 -- qxl-2 */ -- default: - pci_device_rev = QXL_REVISION_STABLE_V06; - break; -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+ case 3: /* qxl-3 */ -+#endif -+ default: -+ pci_device_rev = QXL_DEFAULT_REVISION; -+ break; - } - - pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); -@@ -1830,9 +1835,12 @@ static PCIDeviceInfo qxl_info_primary = { - .device_id = QXL_DEVICE_ID_STABLE, - .class_id = PCI_CLASS_DISPLAY_VGA, - .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("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, -+ QXL_DEFAULT_REVISION), - DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), - DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), - DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), -@@ -1851,9 +1859,12 @@ static PCIDeviceInfo qxl_info_secondary = { - .device_id = QXL_DEVICE_ID_STABLE, - .class_id = PCI_CLASS_DISPLAY_OTHER, - .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("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, -+ QXL_DEFAULT_REVISION), - 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 1046205..4bcf7e1 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -102,6 +102,12 @@ typedef struct PCIQXLDevice { - } \ - } while (0) - -+#if SPICE_INTERFACE_QXL_MINOR >= 1 -+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 -+#else -+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06 -+#endif -+ - /* qxl.c */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); - void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...); --- -1.7.5.1 - diff --git a/0025-spice-qemu-char-Generate-chardev-open-close-events.patch b/0025-spice-qemu-char-Generate-chardev-open-close-events.patch new file mode 100644 index 0000000..7b4b41b --- /dev/null +++ b/0025-spice-qemu-char-Generate-chardev-open-close-events.patch @@ -0,0 +1,79 @@ +>From d98187ff877341b5db5ca7f9d50b238d5936052b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 21 Jul 2011 15:36:40 +0200 +Subject: [PATCH 25/28] spice-qemu-char: Generate chardev open/close events + +Define a state callback and make that generate chardev open/close events when +called by the spice-server. + +Note that for all but the newest spice-server versions (which have a fix for +this) the code ignores these events for a spicevmc with a subtype of vdagent, +this subtype specific knowledge is undesirable, but unavoidable for now, see: +http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html + +Signed-off-by: Hans de Goede +--- + spice-qemu-char.c | 35 ++++++++++++++++++++++++++++++++++- + 1 files changed, 34 insertions(+), 1 deletions(-) + +diff --git a/spice-qemu-char.c b/spice-qemu-char.c +index 2b8aec4..d55e74a 100644 +--- a/spice-qemu-char.c ++++ b/spice-qemu-char.c +@@ -89,11 +89,39 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + return bytes; + } + ++static void vmc_state(SpiceCharDeviceInstance *sin, int connected) ++{ ++ SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); ++ ++#if SPICE_SERVER_VERSION < 0x000901 ++ /* ++ * spice-server calls the state callback for the agent channel when the ++ * spice client connects / disconnects. Given that not the client but ++ * the server is doing the parsing of the messages this is wrong as the ++ * server is still listening. Worse, this causes the parser in the server ++ * to go out of sync, so we ignore state calls for subtype vdagent ++ * spicevmc chardevs. For the full story see: ++ * http://lists.freedesktop.org/archives/spice-devel/2011-July/004837.html ++ */ ++ if (strcmp(sin->subtype, "vdagent") == 0) { ++ return; ++ } ++#endif ++ ++ if ((scd->chr->opened && connected) || ++ (!scd->chr->opened && !connected)) { ++ return; ++ } ++ ++ qemu_chr_event(scd->chr, connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED); ++} ++ + static SpiceCharDeviceInterface vmc_interface = { + .base.type = SPICE_INTERFACE_CHAR_DEVICE, + .base.description = "spice virtual channel char device", + .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, + .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, ++ .state = vmc_state, + .write = vmc_write, + .read = vmc_read, + }; +@@ -222,7 +250,12 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) + chr->chr_guest_close = spice_chr_guest_close; + s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s); + +- qemu_chr_generic_open(chr); ++#if SPICE_SERVER_VERSION < 0x000901 ++ /* See comment in vmc_state() */ ++ if (strcmp(subtype, "vdagent") == 0) { ++ qemu_chr_generic_open(chr); ++ } ++#endif + + *_chr = chr; + return 0; +-- +1.7.5.1 + diff --git a/0025-virtio-serial-bus-replay-guest_open-on-migration.patch b/0025-virtio-serial-bus-replay-guest_open-on-migration.patch deleted file mode 100644 index 84f8a72..0000000 --- a/0025-virtio-serial-bus-replay-guest_open-on-migration.patch +++ /dev/null @@ -1,50 +0,0 @@ ->From a1f7b1a638423f74a7a8e3e141f760777dcbd1ab Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Thu, 28 Jul 2011 15:08:48 +0300 -Subject: [PATCH 25/25] virtio-serial-bus: replay guest_open on migration - -When migrating a host with with a spice agent running the mouse becomes -non operational after the migration. This is rhbz #725965. - -The problem is that after migration spice doesn't know the guest agent is open. -Spice is just a char dev here. And a chardev cannot query it's device, the -device has to let the chardev know when it is open. Right now after migration -the chardev which is recreated is in it's default state, which assumes the -guest is disconnected. - -Char devices carry no information across migration, but the virtio-serial does -already carry the guest_connected state. This patch passes that bit to the -chardev. - -Signed-off-by: Alon Levy ---- - hw/virtio-serial-bus.c | 6 ++++++ - 1 files changed, 6 insertions(+), 0 deletions(-) - -diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c -index c5eb931..4a6d932 100644 ---- a/hw/virtio-serial-bus.c -+++ b/hw/virtio-serial-bus.c -@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) - for (i = 0; i < nr_active_ports; i++) { - uint32_t id; - bool host_connected; -+ VirtIOSerialPortInfo *info; - - id = qemu_get_be32(f); - port = find_port_by_id(s, id); -@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) - } - - port->guest_connected = qemu_get_byte(f); -+ info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); -+ if (port->guest_connected && info->guest_open) { -+ /* replay guest open */ -+ info->guest_open(port); -+ } - host_connected = qemu_get_byte(f); - if (host_connected != port->host_connected) { - /* --- -1.7.5.1 - diff --git a/0026-usb-redir-Call-qemu_chr_guest_open-close.patch b/0026-usb-redir-Call-qemu_chr_guest_open-close.patch new file mode 100644 index 0000000..8bb4dbf --- /dev/null +++ b/0026-usb-redir-Call-qemu_chr_guest_open-close.patch @@ -0,0 +1,37 @@ +>From c8a865625b713ffc1cff6ff97fc3e4c01aeeb0f7 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 21 Jul 2011 16:28:06 +0200 +Subject: [PATCH 26/28] usb-redir: Call qemu_chr_guest_open/close + +To let the chardev now we're ready start receiving data. This is necessary +with the spicevmc chardev to get it registered with the spice-server. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 6932beb..9ce2c8b 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -839,6 +839,8 @@ static int usbredir_initfn(USBDevice *udev) + /* We'll do the attach once we receive the speed from the usb-host */ + udev->auto_attach = 0; + ++ /* Let the other side know we are ready */ ++ qemu_chr_guest_open(dev->cs); + qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); + + return 0; +@@ -861,6 +863,7 @@ static void usbredir_handle_destroy(USBDevice *udev) + { + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + ++ qemu_chr_guest_close(dev->cs); + qemu_chr_close(dev->cs); + /* Note must be done after qemu_chr_close, as that causes a close event */ + qemu_bh_delete(dev->open_close_bh); +-- +1.7.5.1 + diff --git a/0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch b/0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch new file mode 100644 index 0000000..baf9f81 --- /dev/null +++ b/0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch @@ -0,0 +1,88 @@ +>From a6fba82709859fc91e676ce53079eb250bb55750 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 4 Aug 2011 14:41:07 +0200 +Subject: [PATCH 27/28] usb-redir: Device disconnect + re-connect robustness + fixes + +These fixes mainly target the other side sending some (error status) +packets after a disconnect packet. In some cases these would get queued +up and then reported to the controller when a new device gets connected. + +* Fully reset device state on disconnect +* Don't allow a connect message when already connected +* Ignore iso and interrupt status messages when disconnected + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 22 +++++++++++++++++++++- + 1 files changed, 21 insertions(+), 1 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 9ce2c8b..6d8f986 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -905,6 +905,11 @@ static void usbredir_device_connect(void *priv, + { + USBRedirDevice *dev = priv; + ++ if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { ++ ERROR("Received device connect while already connected\n"); ++ return; ++ } ++ + switch (device_connect->speed) { + case usb_redir_speed_low: + DPRINTF("attaching low speed device\n"); +@@ -933,19 +938,26 @@ static void usbredir_device_connect(void *priv, + static void usbredir_device_disconnect(void *priv) + { + USBRedirDevice *dev = priv; ++ int i; + + /* Stop any pending attaches */ + qemu_del_timer(dev->attach_timer); + + if (dev->dev.attached) { + usb_device_detach(&dev->dev); +- usbredir_cleanup_device_queues(dev); + /* + * Delay next usb device attach to give the guest a chance to see + * see the detach / attach in case of quick close / open succession + */ + dev->next_attach_time = qemu_get_clock_ms(vm_clock) + 200; + } ++ ++ /* Reset state so that the next dev connected starts with a clean slate */ ++ usbredir_cleanup_device_queues(dev); ++ memset(dev->endpoint, 0, sizeof(dev->endpoint)); ++ for (i = 0; i < MAX_ENDPOINTS; i++) { ++ QTAILQ_INIT(&dev->endpoint[i].bufpq); ++ } + } + + static void usbredir_interface_info(void *priv, +@@ -1037,6 +1049,10 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, + DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, + ep, id); + ++ if (!dev->dev.attached) { ++ return; ++ } ++ + dev->endpoint[EP2I(ep)].iso_error = iso_stream_status->status; + if (iso_stream_status->status == usb_redir_stall) { + DPRINTF("iso stream stopped by peer ep %02X\n", ep); +@@ -1054,6 +1070,10 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, + DPRINTF("interrupt recv status %d ep %02X id %u\n", + interrupt_receiving_status->status, ep, id); + ++ if (!dev->dev.attached) { ++ return; ++ } ++ + dev->endpoint[EP2I(ep)].interrupt_error = + interrupt_receiving_status->status; + if (interrupt_receiving_status->status == usb_redir_stall) { +-- +1.7.5.1 + diff --git a/0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch b/0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch new file mode 100644 index 0000000..18e5064 --- /dev/null +++ b/0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch @@ -0,0 +1,32 @@ +>From 7e49ff036892fade86c7734118ee0c6da5cbad09 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 11 Aug 2011 12:11:16 +0200 +Subject: [PATCH 28/28] usb-redir: Don't try to write to the chardev after a + close event + +Sicne we handle close async in a bh, do_write and thus write can get +called after receiving a close event. This patch adds a check to +the usb-redir write callback to not do a qemu_chr_write on a closed +chardev. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 6d8f986..732ddab 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -226,7 +226,7 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + USBRedirDevice *dev = priv; + int r; + +- if (dev->cs->write_blocked) { ++ if (!dev->cs->opened || dev->cs->write_blocked) { + return 0; + } + +-- +1.7.5.1 + diff --git a/qemu.spec b/qemu.spec index 5896356..ec75e78 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,9 +1,7 @@ -%define githead 0af4922 - Summary: QEMU is a FAST! processor emulator Name: qemu Version: 0.15.0 -Release: 0.3.20110804%githead%{?dist} +Release: 1%{?dist} # Epoch because we pushed a qemu-1.0 package Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -19,11 +17,7 @@ URL: http://www.qemu.org/ %define _smp_mflags %{nil} %endif -# Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz -# The source for this package was pulled from upstream's git. Use the -# following commands to generate the tarball: -# git archive --format=tar --prefix=qemu-kvm-0.15.0/ 0af4922 | gzip > qemu-kvm-0.15.0-0af4922.tar.gz -Source0: qemu-kvm-%{version}-%{githead}.tar.gz +Source0: http://downloads.sourceforge.net/sourceforge/kvm/qemu-kvm-%{version}.tar.gz Source1: qemu.init @@ -52,23 +46,23 @@ Patch08: 0008-virtio-console-Enable-port-throttling-when-chardev-i.patch Patch09: 0009-spice-qemu-char.c-add-throttling.patch Patch10: 0010-spice-qemu-char.c-remove-intermediate-buffer.patch Patch11: 0011-usb-redir-Add-flow-control-support.patch -Patch12: 0012-usb-redir-Call-qemu_chr_guest_open-close.patch -Patch13: 0013-spice-qemu-char-Generate-chardev-open-close-events.patch -Patch14: 0014-spice-add-worker-wrapper-functions.patch -Patch15: 0015-spice-add-qemu_spice_display_init_common.patch -Patch16: 0016-spice-qxl-move-worker-wrappers.patch -Patch17: 0017-qxl-fix-surface-tracking-locking.patch -Patch18: 0018-qxl-add-io_port_to_string.patch -Patch19: 0019-qxl-error-handling-fixes-and-cleanups.patch -Patch20: 0020-qxl-make-qxl_guest_bug-take-variable-arguments.patch -Patch21: 0021-qxl-only-disallow-specific-io-s-in-vga-mode.patch -Patch22: 0022-qxl-async-io-support-using-new-spice-api.patch -Patch23: 0023-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch -Patch24: 0024-qxl-bump-pci-rev.patch -Patch25: 0025-virtio-serial-bus-replay-guest_open-on-migration.patch - -# Fix for default accelerator in non-KVM builds -Patch100: qemu-kvm-default-accelerator.patch +Patch12: 0012-spice-add-worker-wrapper-functions.patch +Patch13: 0013-spice-add-qemu_spice_display_init_common.patch +Patch14: 0014-spice-qxl-move-worker-wrappers.patch +Patch15: 0015-qxl-fix-surface-tracking-locking.patch +Patch16: 0016-qxl-add-io_port_to_string.patch +Patch17: 0017-qxl-error-handling-fixes-and-cleanups.patch +Patch18: 0018-qxl-make-qxl_guest_bug-take-variable-arguments.patch +Patch19: 0019-qxl-only-disallow-specific-io-s-in-vga-mode.patch +Patch20: 0020-qxl-async-io-support-using-new-spice-api.patch +Patch21: 0021-qxl-add-QXL_IO_FLUSH_-SURFACES-RELEASE-for-guest-S3-.patch +Patch22: 0022-qxl-bump-pci-rev.patch +Patch23: 0023-virtio-serial-bus-replay-guest_open-on-migration.patch +Patch24: 0024-qemu-char-make-qemu_chr_event-public.patch +Patch25: 0025-spice-qemu-char-Generate-chardev-open-close-events.patch +Patch26: 0026-usb-redir-Call-qemu_chr_guest_open-close.patch +Patch27: 0027-usb-redir-Device-disconnect-re-connect-robustness-fi.patch +Patch28: 0028-usb-redir-Don-t-try-to-write-to-the-chardev-after-a-.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel @@ -267,8 +261,9 @@ such as kvm_stat. %patch23 -p1 %patch24 -p1 %patch25 -p1 - -%patch100 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 %build # By default we build everything, but allow x86 to build a minimal version @@ -579,6 +574,9 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Sun Aug 14 2011 Justin M. Forbes - 2:0.15.0-1 +- Update to 0.15.0 stable release. + * Thu Aug 04 2011 Justin M. Forbes - 2:0.15.0-0.3.201108040af4922 - Update to 0.15.0-rc1 as we prepare for 0.15.0 release diff --git a/sources b/sources index 48c748a..250f8be 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -a6d16b7d6acfa94300586eda5e7c19a3 qemu-kvm-0.15.0-0af4922.tar.gz +b45b0deebba4ce47dcaaab3807f6ed47 qemu-kvm-0.15.0.tar.gz