From 56753ff0811d17d4d309dd73d669f7ba33a144ee Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 19 Apr 2012 17:28:17 +0200 Subject: [PATCH] Add a couple of backported QXL/Spice bugfixes - Add spice volume control patches --- ...frindex-writes-leave-a-valid-frindex.patch | 36 + ...check-in-qxl_phys2virt-is-off-by-one.patch | 30 + ...-mouse-events-only-to-running-guests.patch | 45 ++ 0403-qxl-fix-warnings-on-32bit.patch | 45 ++ ...-render-stuff-when-the-vm-is-stopped.patch | 56 ++ ...-screen-surfaces-dirty-instead-of-th.patch | 97 +++ ...imary-surface-is-saved-on-migration-.patch | 30 + ...upport-to-add_client-monitor-command.patch | 139 ++++ ...v6-channel-address-in-monitor-events.patch | 83 ++ 0409-qxl-drop-vram-bar-minimum-size.patch | 30 + ...l-move-ram-size-init-to-new-function.patch | 97 +++ ...dd-user-friendly-bar-size-properties.patch | 63 ++ ...l-fix-spice-sdl-no-cursor-regression.patch | 93 +++ ...move-NULL-check-g_malloc0-can-t-fail.patch | 29 + ...l_spice_update_area_async-definition.patch | 34 + 0415-qxl-require-spice-0.8.2.patch | 358 +++++++++ 0416-qxl-remove-flipped.patch | 145 ++++ 0417-qxl-introduce-QXLCookie.patch | 264 ++++++ 0418-qxl-make-qxl_render_update-async.patch | 360 +++++++++ ...ce-use-error_report-to-report-errors.patch | 102 +++ ...ls-channel-option-is-used-without-TL.patch | 44 + ...ndle-upright-and-non-shared-surfaces.patch | 77 ++ 0422-spice-set-spice-uuid-and-name.patch | 39 + ...x-client_migrate_info-error-handling.patch | 35 + ...-init_pipe_signaling-exit-on-failure.patch | 49 ++ 0425-qxl-switch-qxl.c-to-trace-events.patch | 753 ++++++++++++++++++ 0426-qxl-qxl_render.c-add-trace-events.patch | 95 +++ ...compilation-failures-on-32-bit-hosts.patch | 80 ++ 0428-spice-fix-broken-initialization.patch | 67 ++ ....c-Fix-compilation-warnings-on-32-bi.patch | 56 ++ ...-use-uintptr_t-when-casting-qxl-phys.patch | 78 ++ 0431-qxl-add-optinal-64bit-vram-bar.patch | 185 +++++ ...default-values-of-vram-_size_mb-to-1.patch | 35 + ...roken-vnc-spice-since-commit-f934493.patch | 30 + ...assert-on-guest-create_guest_primary.patch | 36 + 0501-audio-add-VOICE_VOLUME-ctl.patch | 68 ++ ...y-volume-effect-if-backend-has-VOICE.patch | 99 +++ 0503-hw-ac97-remove-USE_MIXER-code.patch | 170 ++++ ...c97-the-volume-mask-is-not-only-0x1f.patch | 28 + ...-ac97-add-support-for-volume-control.patch | 134 ++++ ...spice-add-support-for-volume-control.patch | 84 ++ ...-Do-not-use-pa_simple-PulseAudio-API.patch | 573 +++++++++++++ ...gure-pa_simple-is-not-needed-anymore.patch | 31 + ...lling-volume-with-PulseAudio-backend.patch | 134 ++++ qemu.spec | 105 ++- 45 files changed, 5219 insertions(+), 2 deletions(-) create mode 100644 0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch create mode 100644 0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch create mode 100644 0402-input-send-kbd-mouse-events-only-to-running-guests.patch create mode 100644 0403-qxl-fix-warnings-on-32bit.patch create mode 100644 0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch create mode 100644 0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch create mode 100644 0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch create mode 100644 0407-Add-SPICE-support-to-add_client-monitor-command.patch create mode 100644 0408-spice-support-ipv6-channel-address-in-monitor-events.patch create mode 100644 0409-qxl-drop-vram-bar-minimum-size.patch create mode 100644 0410-qxl-move-ram-size-init-to-new-function.patch create mode 100644 0411-qxl-add-user-friendly-bar-size-properties.patch create mode 100644 0412-qxl-fix-spice-sdl-no-cursor-regression.patch create mode 100644 0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch create mode 100644 0414-qxl-drop-qxl_spice_update_area_async-definition.patch create mode 100644 0415-qxl-require-spice-0.8.2.patch create mode 100644 0416-qxl-remove-flipped.patch create mode 100644 0417-qxl-introduce-QXLCookie.patch create mode 100644 0418-qxl-make-qxl_render_update-async.patch create mode 100644 0419-spice-use-error_report-to-report-errors.patch create mode 100644 0420-Error-out-when-tls-channel-option-is-used-without-TL.patch create mode 100644 0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch create mode 100644 0422-spice-set-spice-uuid-and-name.patch create mode 100644 0423-monitor-fix-client_migrate_info-error-handling.patch create mode 100644 0424-qxl-init_pipe_signaling-exit-on-failure.patch create mode 100644 0425-qxl-switch-qxl.c-to-trace-events.patch create mode 100644 0426-qxl-qxl_render.c-add-trace-events.patch create mode 100644 0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch create mode 100644 0428-spice-fix-broken-initialization.patch create mode 100644 0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch create mode 100644 0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch create mode 100644 0431-qxl-add-optinal-64bit-vram-bar.patch create mode 100644 0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch create mode 100644 0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch create mode 100644 0434-qxl-don-t-assert-on-guest-create_guest_primary.patch create mode 100644 0501-audio-add-VOICE_VOLUME-ctl.patch create mode 100644 0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch create mode 100644 0503-hw-ac97-remove-USE_MIXER-code.patch create mode 100644 0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch create mode 100644 0505-hw-ac97-add-support-for-volume-control.patch create mode 100644 0506-audio-spice-add-support-for-volume-control.patch create mode 100644 0507-Do-not-use-pa_simple-PulseAudio-API.patch create mode 100644 0508-configure-pa_simple-is-not-needed-anymore.patch create mode 100644 0509-Allow-controlling-volume-with-PulseAudio-backend.patch diff --git a/0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch b/0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch new file mode 100644 index 0000000..af7a55c --- /dev/null +++ b/0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch @@ -0,0 +1,36 @@ +From 4c245e5ecbc7d5c30c8e8bb4bfcd18c79fafddfe Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 3 Apr 2012 14:04:31 +0200 +Subject: [PATCH 147/181] usb-ehci: Ensure frindex writes leave a valid + frindex value + +frindex is a 14 bits counter, so bits 31-14 should always be 0, and +after the commit titled "usb-ehci: frindex always is a 14 bits counter" +we rely on frindex always being a multiple of 8. I've not seen this in +practice, but theoretically a guest can write a value >= 0x4000 or a value +which is not a multiple of 8 value to frindex, this patch ensures that +things will still work when that happens. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index ff69587..16e6053 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1081,6 +1081,10 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + val &= USBINTR_MASK; + break; + ++ case FRINDEX: ++ val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */ ++ break; ++ + case CONFIGFLAG: + val &= 0x1; + if (val) { +-- +1.7.10 + diff --git a/0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch b/0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch new file mode 100644 index 0000000..df4ed85 --- /dev/null +++ b/0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch @@ -0,0 +1,30 @@ +From 8858b6d0dac346d9f841cfa84f57cb03bffdf050 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 4 Nov 2011 10:34:24 +0100 +Subject: [PATCH 401/434] qxl: Slot sanity check in qxl_phys2virt() is off by + one, fix + +Spotted by Coverity. + +Signed-off-by: Markus Armbruster +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 41500e9..e0f9d4a 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1020,7 +1020,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + case MEMSLOT_GROUP_HOST: + return (void*)offset; + case MEMSLOT_GROUP_GUEST: +- PANIC_ON(slot > NUM_MEMSLOTS); ++ PANIC_ON(slot >= NUM_MEMSLOTS); + PANIC_ON(!qxl->guest_slots[slot].active); + PANIC_ON(offset < qxl->guest_slots[slot].delta); + offset -= qxl->guest_slots[slot].delta; +-- +1.7.10 + diff --git a/0402-input-send-kbd-mouse-events-only-to-running-guests.patch b/0402-input-send-kbd-mouse-events-only-to-running-guests.patch new file mode 100644 index 0000000..ba35d9b --- /dev/null +++ b/0402-input-send-kbd-mouse-events-only-to-running-guests.patch @@ -0,0 +1,45 @@ +From f87b93c3944652f90e2c0010da6ee8c182382369 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 15 Feb 2012 09:15:37 +0100 +Subject: [PATCH 402/434] input: send kbd+mouse events only to running guests. + +Trying to interact with a stopped guest will queue up the events, +then send them all at once when the guest continues running, with +a high chance to have them cause unwanted actions. + +Avoid that by only injecting the input events only when the guest +is in running state. + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Anthony Liguori +--- + input.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/input.c b/input.c +index 9ade63f..b48408d 100644 +--- a/input.c ++++ b/input.c +@@ -130,6 +130,9 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) + + void kbd_put_keycode(int keycode) + { ++ if (!runstate_is_running()) { ++ return; ++ } + if (qemu_put_kbd_event) { + qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); + } +@@ -151,6 +154,9 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) + void *mouse_event_opaque; + int width, height; + ++ if (!runstate_is_running()) { ++ return; ++ } + if (QTAILQ_EMPTY(&mouse_handlers)) { + return; + } +-- +1.7.10 + diff --git a/0403-qxl-fix-warnings-on-32bit.patch b/0403-qxl-fix-warnings-on-32bit.patch new file mode 100644 index 0000000..c358780 --- /dev/null +++ b/0403-qxl-fix-warnings-on-32bit.patch @@ -0,0 +1,45 @@ +From 3b36dd31d54b24e02493fdd86269ba5286086c98 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 8 Feb 2012 15:58:35 +0100 +Subject: [PATCH 403/434] qxl: fix warnings on 32bit + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index e0f9d4a..4fd5e4e 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -628,7 +628,7 @@ static void interface_release_resource(QXLInstance *sin, + + if (ext.group_id == MEMSLOT_GROUP_HOST) { + /* host group -> vga mode update request */ +- qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); ++ qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id); + return; + } + +@@ -751,7 +751,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&qxl->async_lock); + +- dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); ++ dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", ++ current_async, cookie); + switch (current_async) { + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); +@@ -1018,7 +1019,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + + switch (group_id) { + case MEMSLOT_GROUP_HOST: +- return (void*)offset; ++ return (void *)(intptr_t)offset; + case MEMSLOT_GROUP_GUEST: + PANIC_ON(slot >= NUM_MEMSLOTS); + PANIC_ON(!qxl->guest_slots[slot].active); +-- +1.7.10 + diff --git a/0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch b/0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch new file mode 100644 index 0000000..24722a4 --- /dev/null +++ b/0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch @@ -0,0 +1,56 @@ +From 29fdb0f3a401e5590e465a0cc37d82383f3d5f07 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 15 Feb 2012 14:04:44 +0100 +Subject: [PATCH 404/434] qxl: don't render stuff when the vm is stopped. + +This patch fixes the local qxl renderer to not kick spice-server +in case the vm is stopped. First it is largely pointless because +we ask spice-server to process all not-yet processed commands when +the vm is stopped, so there isn't much do do anyway. Second we +avoid triggering an assert in spice-server. + +The patch makes sure we still honor redraw requests, even if we don't +ask spice-server for updates. This is needed to handle displaysurface +changes with a stopped vm correctly. + +With this patch applied it is possible to take screen shots (via +screendump monitor command) from a qxl gpu even in case the guest +is stopped. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 2c51ba9..a7891b2 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -121,19 +121,17 @@ void qxl_render_update(PCIQXLDevice *qxl) + dpy_resize(vga->ds); + } + +- if (!qxl->guest_primary.commands) { +- return; +- } +- qxl->guest_primary.commands = 0; +- + update.left = 0; + update.right = qxl->guest_primary.surface.width; + update.top = 0; + update.bottom = qxl->guest_primary.surface.height; + + memset(dirty, 0, sizeof(dirty)); +- qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); ++ if (runstate_is_running() && qxl->guest_primary.commands) { ++ qxl->guest_primary.commands = 0; ++ qxl_spice_update_area(qxl, 0, &update, ++ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); ++ } + if (redraw) { + memset(dirty, 0, sizeof(dirty)); + dirty[0] = update; +-- +1.7.10 + diff --git a/0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch b/0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch new file mode 100644 index 0000000..8c642a0 --- /dev/null +++ b/0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch @@ -0,0 +1,97 @@ +From 0386bf2be16745ce87f35ce65153ef4e11f93b22 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 15 Feb 2012 11:22:15 +0200 +Subject: [PATCH 405/434] qxl: set only off-screen surfaces dirty instead of + the whole vram + +We used to assure the guest surfaces were saved before migration by +setting the whole vram dirty. This patch sets dirty only the areas +that are actually used in the vram. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 44 insertions(+), 9 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 4fd5e4e..3d9b1b3 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1010,7 +1010,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + qxl_spice_destroy_surfaces(d, QXL_SYNC); + } + +-/* called from spice server thread context only */ ++/* can be also called from spice server thread context */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + { + uint64_t phys = le64_to_cpu(pqxl); +@@ -1469,6 +1469,46 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) + } + } + ++static void qxl_dirty_surfaces(PCIQXLDevice *qxl) ++{ ++ intptr_t vram_start; ++ int i; ++ ++ if (qxl->mode != QXL_MODE_NATIVE) { ++ return; ++ } ++ ++ /* dirty the primary surface */ ++ qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, ++ qxl->shadow_rom.surface0_area_size); ++ ++ vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); ++ ++ /* dirty the off-screen surfaces */ ++ for (i = 0; i < NUM_SURFACES; i++) { ++ QXLSurfaceCmd *cmd; ++ intptr_t surface_offset; ++ int surface_size; ++ ++ if (qxl->guest_surfaces.cmds[i] == 0) { ++ continue; ++ } ++ ++ cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], ++ MEMSLOT_GROUP_GUEST); ++ assert(cmd->type == QXL_SURFACE_CMD_CREATE); ++ surface_offset = (intptr_t)qxl_phys2virt(qxl, ++ cmd->u.surface_create.data, ++ MEMSLOT_GROUP_GUEST); ++ surface_offset -= vram_start; ++ surface_size = cmd->u.surface_create.height * ++ abs(cmd->u.surface_create.stride); ++ dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, ++ i, (int)surface_offset, surface_size); ++ qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); ++ } ++} ++ + static void qxl_vm_change_state_handler(void *opaque, int running, + RunState state) + { +@@ -1482,14 +1522,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running, + * called + */ + qxl_update_irq(qxl); +- } else if (qxl->mode == QXL_MODE_NATIVE) { +- /* dirty all vram (which holds surfaces) and devram (primary surface) +- * to make sure they are saved */ +- /* FIXME #1: should go out during "live" stage */ +- /* FIXME #2: we only need to save the areas which are actually used */ +- qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size); +- qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, +- qxl->shadow_rom.surface0_area_size); ++ } else { ++ /* make sure surfaces are saved before migration */ ++ qxl_dirty_surfaces(qxl); + } + } + +-- +1.7.10 + diff --git a/0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch b/0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch new file mode 100644 index 0000000..b07d4b6 --- /dev/null +++ b/0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch @@ -0,0 +1,30 @@ +From ba922e5e6a5687f13def623e36bfb834ece2defc Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 15 Feb 2012 11:22:16 +0200 +Subject: [PATCH 406/434] qxl: make sure primary surface is saved on migration + also in compat mode + +RHBZ #790083 + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 3d9b1b3..b910337 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1474,7 +1474,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + intptr_t vram_start; + int i; + +- if (qxl->mode != QXL_MODE_NATIVE) { ++ if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { + return; + } + +-- +1.7.10 + diff --git a/0407-Add-SPICE-support-to-add_client-monitor-command.patch b/0407-Add-SPICE-support-to-add_client-monitor-command.patch new file mode 100644 index 0000000..1ba56e5 --- /dev/null +++ b/0407-Add-SPICE-support-to-add_client-monitor-command.patch @@ -0,0 +1,139 @@ +From 9ada192cfea65a92a765c6a2f6b56a08f1b865df Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Mon, 13 Feb 2012 13:43:08 +0000 +Subject: [PATCH 407/434] Add SPICE support to add_client monitor command + +With the acceptance of some new APIs to libspice-server.so it +is possible to add support for SPICE to the 'add_client' +monitor command, bringing parity with VNC. Since SPICE can +use TLS or plain connections, the command also gains a new +'tls' parameter to specify whether TLS should be attempted +on the injected client sockets. + +This new feature is only enabled if building against a +libspice-server >= 0.10.1 + +* qmp-commands.hx: Add 'tls' parameter & missing doc for + 'skipauth' parameter +* monitor.c: Wire up SPICE for 'add_client' command +* ui/qemu-spice.h, ui/spice-core.c: Add qemu_spice_display_add_client + API to wire up from monitor + +[1] http://cgit.freedesktop.org/spice/spice/commit/server/spice.h?id=d55b68b6b44f2499278fa860fb47ff22f5011faa + http://cgit.freedesktop.org/spice/spice/commit/server/spice.h?id=bd07dde530d9504e1cfe7ed5837fc00c26f36716 + +Changes in v3: + - Added 'optional' flag to new parameters documented + - Added no-op impl of qemu_spice_display_add_client when + SPICE is disabled during build + +Signed-off-by: Daniel P. Berrange +Signed-off-by: Gerd Hoffmann +--- + monitor.c | 9 +++++++-- + qmp-commands.hx | 6 ++++-- + ui/qemu-spice.h | 7 +++++++ + ui/spice-core.c | 13 +++++++++++++ + 4 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/monitor.c b/monitor.c +index a82fda3..3c23aa4 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -998,13 +998,18 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d + CharDriverState *s; + + if (strcmp(protocol, "spice") == 0) { ++ int fd = monitor_get_fd(mon, fdname); ++ int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); ++ int tls = qdict_get_try_bool(qdict, "tls", 0); + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } +- qerror_report(QERR_ADD_CLIENT_FAILED); +- return -1; ++ if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { ++ close(fd); ++ } ++ return 0; + #ifdef CONFIG_VNC + } else if (strcmp(protocol, "vnc") == 0) { + int fd = monitor_get_fd(mon, fdname); +diff --git a/qmp-commands.hx b/qmp-commands.hx +index 97975a5..122b10d 100644 +--- a/qmp-commands.hx ++++ b/qmp-commands.hx +@@ -909,8 +909,8 @@ EQMP + + { + .name = "add_client", +- .args_type = "protocol:s,fdname:s,skipauth:b?", +- .params = "protocol fdname skipauth", ++ .args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?", ++ .params = "protocol fdname skipauth tls", + .help = "add a graphics client", + .user_print = monitor_user_noop, + .mhandler.cmd_new = add_graphics_client, +@@ -926,6 +926,8 @@ Arguments: + + - "protocol": protocol name (json-string) + - "fdname": file descriptor name (json-string) ++- "skipauth": whether to skip authentication (json-bool, optional) ++- "tls": whether to perform TLS (json-bool, optional) + + Example: + +diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h +index c35b29c..680206a 100644 +--- a/ui/qemu-spice.h ++++ b/ui/qemu-spice.h +@@ -33,6 +33,7 @@ void qemu_spice_init(void); + void qemu_spice_input_init(void); + void qemu_spice_audio_init(void); + void qemu_spice_display_init(DisplayState *ds); ++int qemu_spice_display_add_client(int csock, int skipauth, int tls); + int qemu_spice_add_interface(SpiceBaseInstance *sin); + int qemu_spice_set_passwd(const char *passwd, + bool fail_if_connected, bool disconnect_if_connected); +@@ -68,6 +69,12 @@ static inline int qemu_spice_migrate_info(const char *h, int p, int t, + return -1; + } + ++static inline int qemu_spice_display_add_client(int csock, int skipauth, ++ int tls) ++{ ++ return -1; ++} ++ + #endif /* CONFIG_SPICE */ + + #endif /* QEMU_SPICE_H */ +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 5639c6f..d98863e 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -747,6 +747,19 @@ int qemu_spice_set_pw_expire(time_t expires) + return qemu_spice_set_ticket(false, false); + } + ++int qemu_spice_display_add_client(int csock, int skipauth, int tls) ++{ ++#if SPICE_SERVER_VERSION >= 0x000a01 ++ if (tls) { ++ return spice_server_add_ssl_client(spice_server, csock, skipauth); ++ } else { ++ return spice_server_add_client(spice_server, csock, skipauth); ++ } ++#else ++ return -1; ++#endif ++} ++ + static void spice_register_config(void) + { + qemu_add_opts(&qemu_spice_opts); +-- +1.7.10 + diff --git a/0408-spice-support-ipv6-channel-address-in-monitor-events.patch b/0408-spice-support-ipv6-channel-address-in-monitor-events.patch new file mode 100644 index 0000000..4709e09 --- /dev/null +++ b/0408-spice-support-ipv6-channel-address-in-monitor-events.patch @@ -0,0 +1,83 @@ +From 6594551ebe427cae4298b038be02ddc9c335219f Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 8 Feb 2012 15:40:15 +0200 +Subject: [PATCH 408/434] spice: support ipv6 channel address in monitor + events and in spice info + +RHBZ #788444 + +CC: Gerd Hoffmann + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 37 ++++++++++++++++++++++++++++++++----- + 1 file changed, 32 insertions(+), 5 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index d98863e..27216e9 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -220,10 +220,23 @@ static void channel_event(int event, SpiceChannelEventInfo *info) + } + + client = qdict_new(); +- add_addr_info(client, &info->paddr, info->plen); +- + server = qdict_new(); +- add_addr_info(server, &info->laddr, info->llen); ++ ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { ++ add_addr_info(client, (struct sockaddr *)&info->paddr_ext, ++ info->plen_ext); ++ add_addr_info(server, (struct sockaddr *)&info->laddr_ext, ++ info->llen_ext); ++ } else { ++ fprintf(stderr, "spice: %s, extended address is expected\n", ++ __func__); ++#endif ++ add_addr_info(client, &info->paddr, info->plen); ++ add_addr_info(server, &info->laddr, info->llen); ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ } ++#endif + + if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { + qdict_put(server, "auth", qstring_from_str(auth)); +@@ -376,16 +389,30 @@ static SpiceChannelList *qmp_query_spice_channels(void) + QTAILQ_FOREACH(item, &channel_list, link) { + SpiceChannelList *chan; + char host[NI_MAXHOST], port[NI_MAXSERV]; ++ struct sockaddr *paddr; ++ socklen_t plen; + + chan = g_malloc0(sizeof(*chan)); + chan->value = g_malloc0(sizeof(*chan->value)); + +- getnameinfo(&item->info->paddr, item->info->plen, ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { ++ paddr = (struct sockaddr *)&item->info->paddr_ext; ++ plen = item->info->plen_ext; ++ } else { ++#endif ++ paddr = &item->info->paddr; ++ plen = item->info->plen; ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ } ++#endif ++ ++ getnameinfo(paddr, plen, + host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV); + chan->value->host = g_strdup(host); + chan->value->port = g_strdup(port); +- chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family)); ++ chan->value->family = g_strdup(inet_strfamily(paddr->sa_family)); + + chan->value->connection_id = item->info->connection_id; + chan->value->channel_type = item->info->type; +-- +1.7.10 + diff --git a/0409-qxl-drop-vram-bar-minimum-size.patch b/0409-qxl-drop-vram-bar-minimum-size.patch new file mode 100644 index 0000000..f7a740d --- /dev/null +++ b/0409-qxl-drop-vram-bar-minimum-size.patch @@ -0,0 +1,30 @@ +From f7656005900f3c07450303afa66151b6a1bb9599 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Feb 2012 14:40:01 +0100 +Subject: [PATCH 409/434] qxl: drop vram bar minimum size + +There is no reason to require a minimum size of 16 MB for the vram. +Lower the limit to 4096 (one page). Make it disapper completely would +break guests. +--- + hw/qxl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index b910337..d71c94d 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1595,8 +1595,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_qxl_rom(qxl); + init_qxl_ram(qxl); + +- if (qxl->vram_size < 16 * 1024 * 1024) { +- qxl->vram_size = 16 * 1024 * 1024; ++ if (qxl->vram_size < 4096) { ++ qxl->vram_size = 4096; + } + if (qxl->revision == 1) { + qxl->vram_size = 4096; +-- +1.7.10 + diff --git a/0410-qxl-move-ram-size-init-to-new-function.patch b/0410-qxl-move-ram-size-init-to-new-function.patch new file mode 100644 index 0000000..97b12cf --- /dev/null +++ b/0410-qxl-move-ram-size-init-to-new-function.patch @@ -0,0 +1,97 @@ +From 619c68418809149d56025e5b4e7a9828eef90ea8 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Feb 2012 15:02:40 +0100 +Subject: [PATCH 410/434] qxl: move ram size init to new function + +Factor memory bar sizing bits out to a separate function. + +Signed-off-by: Gerd Hoffmann + +Conflicts: + + hw/qxl.c +--- + hw/qxl.c | 41 ++++++++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 19 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index d71c94d..df8efbc 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1557,6 +1557,25 @@ static DisplayChangeListener display_listener = { + .dpy_refresh = display_refresh, + }; + ++static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) ++{ ++ /* vga ram (bar 0) */ ++ if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { ++ qxl->vga.vram_size = ram_min_mb * 1024 * 1024; ++ } ++ ++ /* vram (surfaces, bar 1) */ ++ if (qxl->vram_size < 4096) { ++ qxl->vram_size = 4096; ++ } ++ if (qxl->revision == 1) { ++ qxl->vram_size = 4096; ++ } ++ ++ qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); ++ qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); ++} ++ + static int qxl_init_common(PCIQXLDevice *qxl) + { + uint8_t* config = qxl->pci.config; +@@ -1595,13 +1614,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_qxl_rom(qxl); + init_qxl_ram(qxl); + +- if (qxl->vram_size < 4096) { +- qxl->vram_size = 4096; +- } +- if (qxl->revision == 1) { +- qxl->vram_size = 4096; +- } +- qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); + memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram", + qxl->vram_size); + +@@ -1644,15 +1656,11 @@ static int qxl_init_primary(PCIDevice *dev) + { + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); + VGACommonState *vga = &qxl->vga; +- ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + PortioList *qxl_vga_port_list = g_new(PortioList, 1); + + qxl->id = 0; +- +- if (ram_size < 32 * 1024 * 1024) { +- ram_size = 32 * 1024 * 1024; +- } +- vga_common_init(vga, ram_size); ++ qxl_init_ramsize(qxl, 32); ++ vga_common_init(vga, qxl->vga.vram_size); + vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false); + portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); + portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); +@@ -1671,14 +1679,9 @@ static int qxl_init_secondary(PCIDevice *dev) + { + static int device_id = 1; + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); +- ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + + qxl->id = device_id++; +- +- if (ram_size < 16 * 1024 * 1024) { +- ram_size = 16 * 1024 * 1024; +- } +- qxl->vga.vram_size = ram_size; ++ qxl_init_ramsize(qxl, 16); + memory_region_init_ram(&qxl->vga.vram, &qxl->pci.qdev, "qxl.vgavram", + qxl->vga.vram_size); + qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); +-- +1.7.10 + diff --git a/0411-qxl-add-user-friendly-bar-size-properties.patch b/0411-qxl-add-user-friendly-bar-size-properties.patch new file mode 100644 index 0000000..30fae99 --- /dev/null +++ b/0411-qxl-add-user-friendly-bar-size-properties.patch @@ -0,0 +1,63 @@ +From eff66c7db18e9a3ef0b6ce5deb9a49b61090d809 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Feb 2012 15:03:24 +0100 +Subject: [PATCH 411/434] qxl: add user-friendly bar size properties + +Add two properties to specify bar sizes in megabytes instead of bytes, +which is alot more user-friendly. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 8 ++++++++ + hw/qxl.h | 4 ++++ + 2 files changed, 12 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index df8efbc..c8839c3 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1560,11 +1560,17 @@ static DisplayChangeListener display_listener = { + static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) + { + /* vga ram (bar 0) */ ++ if (qxl->ram_size_mb != -1) { ++ qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024; ++ } + if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { + qxl->vga.vram_size = ram_min_mb * 1024 * 1024; + } + + /* vram (surfaces, bar 1) */ ++ if (qxl->vram_size_mb != -1) { ++ qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; ++ } + if (qxl->vram_size < 4096) { + qxl->vram_size = 4096; + } +@@ -1863,6 +1869,8 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), ++ DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), ++ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/qxl.h b/hw/qxl.h +index 766aa6d..d062991 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -89,6 +89,10 @@ typedef struct PCIQXLDevice { + + /* io bar */ + MemoryRegion io_bar; ++ ++ /* user-friendly properties (in megabytes) */ ++ uint32_t ram_size_mb; ++ uint32_t vram_size_mb; + } PCIQXLDevice; + + #define PANIC_ON(x) if ((x)) { \ +-- +1.7.10 + diff --git a/0412-qxl-fix-spice-sdl-no-cursor-regression.patch b/0412-qxl-fix-spice-sdl-no-cursor-regression.patch new file mode 100644 index 0000000..6c4a6d7 --- /dev/null +++ b/0412-qxl-fix-spice-sdl-no-cursor-regression.patch @@ -0,0 +1,93 @@ +From 1cae61c4d4fe994e5158d63d5f4fe9b52a7b8211 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:25 +0200 +Subject: [PATCH 412/434] qxl: fix spice+sdl no cursor regression +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +regression introduced by 075360945860ad9bdd491921954b383bf762b0e5, + +v2: lock around qemu_spice_cursor_refresh_unlocked + +Reported-by: Fabiano FidĂȘncio +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 4 ++++ + ui/spice-display.c | 23 ++++++++++++++--------- + ui/spice-display.h | 1 + + 3 files changed, 19 insertions(+), 9 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index c8839c3..17f2576 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1548,6 +1548,10 @@ static void display_refresh(struct DisplayState *ds) + { + if (qxl0->mode == QXL_MODE_VGA) { + qemu_spice_display_refresh(&qxl0->ssd); ++ } else { ++ qemu_mutex_lock(&qxl0->ssd.lock); ++ qemu_spice_cursor_refresh_unlocked(&qxl0->ssd); ++ qemu_mutex_unlock(&qxl0->ssd.lock); + } + } + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 6c302a3..c6e61d8 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -317,16 +317,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + ssd->notify++; + } + +-void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) ++void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) + { +- dprint(3, "%s:\n", __FUNCTION__); +- vga_hw_update(); +- +- qemu_mutex_lock(&ssd->lock); +- if (ssd->update == NULL) { +- ssd->update = qemu_spice_create_update(ssd); +- ssd->notify++; +- } + if (ssd->cursor) { + ssd->ds->cursor_define(ssd->cursor); + cursor_put(ssd->cursor); +@@ -337,6 +329,19 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + ssd->mouse_x = -1; + ssd->mouse_y = -1; + } ++} ++ ++void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) ++{ ++ dprint(3, "%s:\n", __func__); ++ vga_hw_update(); ++ ++ qemu_mutex_lock(&ssd->lock); ++ if (ssd->update == NULL) { ++ ssd->update = qemu_spice_create_update(ssd); ++ ssd->notify++; ++ } ++ qemu_spice_cursor_refresh_unlocked(ssd); + qemu_mutex_unlock(&ssd->lock); + + if (ssd->notify) { +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 5e52df9..a23bfc8 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -97,6 +97,7 @@ 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_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd); + + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async); +-- +1.7.10 + diff --git a/0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch b/0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch new file mode 100644 index 0000000..8eddcc9 --- /dev/null +++ b/0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch @@ -0,0 +1,29 @@ +From 4888e60d646b0f8cdfe4180bacc90857d3d2a5dd Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:26 +0200 +Subject: [PATCH 413/434] sdl: remove NULL check, g_malloc0 can't fail + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + ui/sdl.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/ui/sdl.c b/ui/sdl.c +index 8cafc44..6844c83 100644 +--- a/ui/sdl.c ++++ b/ui/sdl.c +@@ -167,10 +167,6 @@ static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf) + static DisplaySurface* sdl_create_displaysurface(int width, int height) + { + DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface)); +- if (surface == NULL) { +- fprintf(stderr, "sdl_create_displaysurface: malloc failed\n"); +- exit(1); +- } + + surface->width = width; + surface->height = height; +-- +1.7.10 + diff --git a/0414-qxl-drop-qxl_spice_update_area_async-definition.patch b/0414-qxl-drop-qxl_spice_update_area_async-definition.patch new file mode 100644 index 0000000..0edba27 --- /dev/null +++ b/0414-qxl-drop-qxl_spice_update_area_async-definition.patch @@ -0,0 +1,34 @@ +From 813c46edf4f3f69347353749755e040bc5fbd597 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:27 +0200 +Subject: [PATCH 414/434] qxl: drop qxl_spice_update_area_async definition + +It was never used. Introduced in +5ff4e36c804157bd84af43c139f8cd3a59722db9 +qxl: async io support using new spice api + +But not used even then. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/hw/qxl.h b/hw/qxl.h +index d062991..a615eca 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -138,9 +138,3 @@ 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 +-- +1.7.10 + diff --git a/0415-qxl-require-spice-0.8.2.patch b/0415-qxl-require-spice-0.8.2.patch new file mode 100644 index 0000000..e00a42e --- /dev/null +++ b/0415-qxl-require-spice-0.8.2.patch @@ -0,0 +1,358 @@ +From e07eeb01819b40b839cc12b2eb658f48f13a5ff0 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:28 +0200 +Subject: [PATCH 415/434] qxl: require spice >= 0.8.2 + +drop all ifdefs on SPICE_INTERFACE_QXL_MINOR >= 1 as a result, +any check for SPICE_SERVER_VERSION that is now always satisfied, +and SPICE_INTERFACE_CORE_MINOR >= 3 tests, because +0.8.2 has SPICE_INTERFACE_QXL_MINOR == 1 and +SPICE_INTERFACE_CORE_MINOR == 3. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + configure | 2 +- + hw/qxl.c | 40 ---------------------------------------- + hw/qxl.h | 4 ---- + ui/spice-core.c | 17 ----------------- + ui/spice-display.c | 12 ------------ + 5 files changed, 1 insertion(+), 74 deletions(-) + +diff --git a/configure b/configure +index a4848a4..b03172c 100755 +--- a/configure ++++ b/configure +@@ -2501,7 +2501,7 @@ int main(void) { spice_server_new(); return 0; } + EOF + spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null) + spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null) +- if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \ ++ if $pkg_config --atleast-version=0.8.2 spice-server >/dev/null 2>&1 && \ + compile_prog "$spice_cflags" "$spice_libs" ; then + spice="yes" + libs_softmmu="$libs_softmmu $spice_libs" +diff --git a/hw/qxl.c b/hw/qxl.c +index 17f2576..0be9859 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -125,9 +125,7 @@ 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) { + va_list ap; + va_start(ap, msg); +@@ -149,12 +147,8 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + 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 + } + } + +@@ -171,24 +165,18 @@ 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); + } + } + +-#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) +@@ -217,11 +205,7 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + 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); +@@ -493,7 +477,6 @@ static const char *io_port_to_string(uint32_t io_port) + [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", +@@ -503,7 +486,6 @@ static const char *io_port_to_string(uint32_t io_port) + = "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]; + } +@@ -738,8 +720,6 @@ static int interface_flush_resources(QXLInstance *sin) + + 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) + { +@@ -767,8 +747,6 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); + } + +-#endif +- + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -788,9 +766,7 @@ 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) +@@ -1140,9 +1116,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + PCIQXLDevice *d = opaque; + uint32_t io_port = addr; + 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: +@@ -1152,10 +1126,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + 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) { +@@ -1163,17 +1135,14 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + } + 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) { +@@ -1212,7 +1181,6 @@ async_common: + default: + break; + } +-#endif + + switch (io_port) { + case QXL_IO_UPDATE_AREA: +@@ -1304,7 +1272,6 @@ 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) { +@@ -1325,7 +1292,6 @@ async_common: + 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); +@@ -1336,16 +1302,12 @@ async_common: + } + 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 uint64_t ioport_read(void *opaque, target_phys_addr_t addr, +@@ -1607,9 +1569,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) + case 2: /* spice 0.6 -- qxl-2 */ + 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; +diff --git a/hw/qxl.h b/hw/qxl.h +index a615eca..9288e46 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -108,11 +108,7 @@ 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); +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 27216e9..2c815f1 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -139,8 +139,6 @@ static void watch_remove(SpiceWatch *watch) + g_free(watch); + } + +-#if SPICE_INTERFACE_CORE_MINOR >= 3 +- + typedef struct ChannelList ChannelList; + struct ChannelList { + SpiceChannelEventInfo *info; +@@ -257,15 +255,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info) + } + } + +-#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */ +- +-static QList *channel_list_get(void) +-{ +- return NULL; +-} +- +-#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */ +- + static SpiceCoreInterface core_interface = { + .base.type = SPICE_INTERFACE_CORE, + .base.description = "qemu core services", +@@ -281,9 +270,7 @@ static SpiceCoreInterface core_interface = { + .watch_update_mask = watch_update_mask, + .watch_remove = watch_remove, + +-#if SPICE_INTERFACE_CORE_MINOR >= 3 + .channel_event = channel_event, +-#endif + }; + + #ifdef SPICE_INTERFACE_MIGRATION +@@ -490,7 +477,6 @@ static void migration_state_notifier(Notifier *notifier, void *data) + spice_server_migrate_start(spice_server); + #endif + } else if (migration_has_finished(s)) { +-#if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */ + #ifndef SPICE_INTERFACE_MIGRATION + spice_server_migrate_switch(spice_server); + #else +@@ -498,7 +484,6 @@ static void migration_state_notifier(Notifier *notifier, void *data) + } else if (migration_has_failed(s)) { + spice_server_migrate_end(spice_server, false); + #endif +-#endif + } + } + +@@ -659,11 +644,9 @@ void qemu_spice_init(void) + spice_server_set_noauth(spice_server); + } + +-#if SPICE_SERVER_VERSION >= 0x000801 + if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) { + spice_server_set_agent_copypaste(spice_server, false); + } +-#endif + + compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ; + str = qemu_opt_get(opts, "image-compression"); +diff --git a/ui/spice-display.c b/ui/spice-display.c +index c6e61d8..ad76bae 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -64,11 +64,7 @@ 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); + } +@@ -84,11 +80,7 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + 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); + } +@@ -99,11 +91,7 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async) + { + 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); + } +-- +1.7.10 + diff --git a/0416-qxl-remove-flipped.patch b/0416-qxl-remove-flipped.patch new file mode 100644 index 0000000..3820b9b --- /dev/null +++ b/0416-qxl-remove-flipped.patch @@ -0,0 +1,145 @@ +From f9344933bcc1425cf1e8142dc2f8321522dc00af Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:29 +0200 +Subject: [PATCH 416/434] qxl: remove flipped + +Tested on linux and windows guests. For negative stride, qxl_flip copies +directly to vga->ds->surface->data, for positive it's reallocated to +share qxl->guest_primary.data + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 66 +++++++++++++++++++++++++------------------------------ + hw/qxl.h | 2 +- + 2 files changed, 31 insertions(+), 37 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index a7891b2..5811d74 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -23,10 +23,21 @@ + + static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) + { +- uint8_t *src = qxl->guest_primary.data; +- uint8_t *dst = qxl->guest_primary.flipped; ++ uint8_t *src; ++ uint8_t *dst = qxl->vga.ds->surface->data; + int len, i; + ++ if (qxl->guest_primary.qxl_stride > 0) { ++ return; ++ } ++ if (!qxl->guest_primary.data) { ++ dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); ++ qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); ++ } ++ dprint(qxl, 1, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, ++ qxl->guest_primary.qxl_stride, ++ rect->left, rect->right, rect->top, rect->bottom); ++ src = qxl->guest_primary.data; + src += (qxl->guest_primary.surface.height - rect->top - 1) * + qxl->guest_primary.abs_stride; + dst += rect->top * qxl->guest_primary.abs_stride; +@@ -75,52 +86,38 @@ void qxl_render_update(PCIQXLDevice *qxl) + { + VGACommonState *vga = &qxl->vga; + QXLRect dirty[32], update; +- void *ptr; + int i, redraw = 0; +- +- if (!is_buffer_shared(vga->ds->surface)) { +- dprint(qxl, 1, "%s: restoring shared displaysurface\n", __func__); +- qxl->guest_primary.resized++; +- qxl->guest_primary.commands++; +- redraw = 1; +- } ++ DisplaySurface *surface = vga->ds->surface; + + if (qxl->guest_primary.resized) { + qxl->guest_primary.resized = 0; + +- if (qxl->guest_primary.flipped) { +- g_free(qxl->guest_primary.flipped); +- qxl->guest_primary.flipped = NULL; +- } +- qemu_free_displaysurface(vga->ds); +- + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); +- if (qxl->guest_primary.qxl_stride < 0) { +- /* spice surface is upside down -> need extra buffer to flip */ +- qxl->guest_primary.flipped = +- g_malloc(qxl->guest_primary.surface.width * +- qxl->guest_primary.abs_stride); +- ptr = qxl->guest_primary.flipped; +- } else { +- ptr = qxl->guest_primary.data; +- } +- dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n", ++ dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", + __FUNCTION__, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.qxl_stride, + qxl->guest_primary.bytes_pp, +- qxl->guest_primary.bits_pp, +- qxl->guest_primary.flipped ? "yes" : "no"); +- vga->ds->surface = ++ qxl->guest_primary.bits_pp); ++ } ++ if (surface->width != qxl->guest_primary.surface.width || ++ surface->height != qxl->guest_primary.surface.height) { ++ dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", ++ __func__); ++ if (qxl->guest_primary.qxl_stride > 0) { ++ qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.bits_pp, + qxl->guest_primary.abs_stride, +- ptr); +- dpy_resize(vga->ds); ++ qxl->guest_primary.data); ++ } else { ++ qemu_resize_displaysurface(vga->ds, ++ qxl->guest_primary.surface.width, ++ qxl->guest_primary.surface.height); ++ } + } +- + update.left = 0; + update.right = qxl->guest_primary.surface.width; + update.top = 0; +@@ -136,14 +133,11 @@ void qxl_render_update(PCIQXLDevice *qxl) + memset(dirty, 0, sizeof(dirty)); + dirty[0] = update; + } +- + for (i = 0; i < ARRAY_SIZE(dirty); i++) { + if (qemu_spice_rect_is_empty(dirty+i)) { + break; + } +- if (qxl->guest_primary.flipped) { +- qxl_flip(qxl, dirty+i); +- } ++ qxl_flip(qxl, dirty+i); + dpy_update(vga->ds, + dirty[i].left, dirty[i].top, + dirty[i].right - dirty[i].left, +diff --git a/hw/qxl.h b/hw/qxl.h +index 9288e46..53a3ace 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -52,7 +52,7 @@ typedef struct PCIQXLDevice { + uint32_t abs_stride; + uint32_t bits_pp; + uint32_t bytes_pp; +- uint8_t *data, *flipped; ++ uint8_t *data; + } guest_primary; + + struct surfaces { +-- +1.7.10 + diff --git a/0417-qxl-introduce-QXLCookie.patch b/0417-qxl-introduce-QXLCookie.patch new file mode 100644 index 0000000..1eeff47 --- /dev/null +++ b/0417-qxl-introduce-QXLCookie.patch @@ -0,0 +1,264 @@ +From bbe362cd6a386d98a94ac791f1263671bd79b754 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:30 +0200 +Subject: [PATCH 417/434] qxl: introduce QXLCookie + +Will be used in the next patch. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 2 +- + hw/qxl.c | 61 ++++++++++++++++++++++++++++++++++++++++------------ + hw/qxl.h | 2 +- + ui/spice-display.c | 22 ++++++++++++++++--- + ui/spice-display.h | 14 ++++++++++++ + 5 files changed, 82 insertions(+), 19 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 5811d74..4c22166 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -127,7 +127,7 @@ void qxl_render_update(PCIQXLDevice *qxl) + if (runstate_is_running() && qxl->guest_primary.commands) { + qxl->guest_primary.commands = 0; + qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); ++ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL); + } + if (redraw) { + memset(dirty, 0, sizeof(dirty)); +diff --git a/hw/qxl.c b/hw/qxl.c +index 0be9859..e6e65d9 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -141,14 +141,15 @@ 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_async_io async) ++ qxl_async_io async, struct QXLCookie *cookie) + { + if (async == QXL_SYNC) { + qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, + dirty_rects, num_dirty_rects, clear_dirty_region); + } else { ++ assert(cookie != NULL); + spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, +- clear_dirty_region, 0); ++ clear_dirty_region, (uint64_t)cookie); + } + } + +@@ -164,9 +165,13 @@ static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, + static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + qxl_async_io async) + { ++ QXLCookie *cookie; ++ + if (async) { +- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, +- (uint64_t)id); ++ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_SURFACE_ASYNC); ++ cookie->u.surface_id = id; ++ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl_spice_destroy_surface_wait_complete(qxl, id); +@@ -175,7 +180,9 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + + static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + { +- spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); ++ spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_FLUSH_SURFACES_ASYNC)); + } + + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, +@@ -205,7 +212,9 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + { + if (async) { +- spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); ++ spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); + } else { + qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); + qxl_spice_destroy_surfaces_complete(qxl); +@@ -721,9 +730,8 @@ static int interface_flush_resources(QXLInstance *sin) + static void qxl_create_guest_primary_complete(PCIQXLDevice *d); + + /* called from spice server thread context only */ +-static void interface_async_complete(QXLInstance *sin, uint64_t cookie) ++static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + { +- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + uint32_t current_async; + + qemu_mutex_lock(&qxl->async_lock); +@@ -731,8 +739,16 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&qxl->async_lock); + +- dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", +- current_async, cookie); ++ dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); ++ if (!cookie) { ++ fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); ++ return; ++ } ++ if (cookie && current_async != cookie->io) { ++ fprintf(stderr, ++ "qxl: %s: error: current_async = %d != %ld = cookie->io\n", ++ __func__, current_async, cookie->io); ++ } + switch (current_async) { + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); +@@ -741,12 +757,29 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl_spice_destroy_surfaces_complete(qxl); + break; + case QXL_IO_DESTROY_SURFACE_ASYNC: +- qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie); ++ qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); + break; + } + qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); + } + ++/* called from spice server thread context only */ ++static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ QXLCookie *cookie = (QXLCookie *)cookie_token; ++ ++ switch (cookie->type) { ++ case QXL_COOKIE_TYPE_IO: ++ interface_async_complete_io(qxl, cookie); ++ break; ++ default: ++ fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", ++ __func__, cookie->type); ++ } ++ g_free(cookie); ++} ++ + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -1057,9 +1090,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) + if (d->mode == QXL_MODE_UNDEFINED) { + return 0; + } +- + dprint(d, 1, "%s\n", __FUNCTION__); +- + d->mode = QXL_MODE_UNDEFINED; + qemu_spice_destroy_primary_surface(&d->ssd, 0, async); + qxl_spice_reset_cursor(d); +@@ -1187,7 +1218,9 @@ async_common: + { + QXLRect update = d->ram->update_area; + qxl_spice_update_area(d, d->ram->update_surface, +- &update, NULL, 0, 0, async); ++ &update, NULL, 0, 0, async, ++ qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_UPDATE_AREA_ASYNC)); + break; + } + case QXL_IO_NOTIFY_CMD: +diff --git a/hw/qxl.h b/hw/qxl.h +index 53a3ace..1443925 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -118,7 +118,7 @@ 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_async_io async); ++ qxl_async_io async, QXLCookie *cookie); + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count); + void qxl_spice_oom(PCIQXLDevice *qxl); +diff --git a/ui/spice-display.c b/ui/spice-display.c +index ad76bae..ab266ae 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -60,11 +60,23 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) + dest->right = MAX(dest->right, r->right); + } + ++QXLCookie *qxl_cookie_new(int type, uint64_t io) ++{ ++ QXLCookie *cookie; ++ ++ cookie = g_malloc0(sizeof(*cookie)); ++ cookie->type = type; ++ cookie->io = io; ++ return cookie; ++} ++ + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async) + { + if (async != QXL_SYNC) { +- spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); ++ spice_qxl_add_memslot_async(&ssd->qxl, memslot, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_MEMSLOT_ADD_ASYNC)); + } else { + ssd->worker->add_memslot(ssd->worker, memslot); + } +@@ -80,7 +92,9 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + qxl_async_io async) + { + if (async != QXL_SYNC) { +- spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); ++ spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_CREATE_PRIMARY_ASYNC)); + } else { + ssd->worker->create_primary_surface(ssd->worker, id, surface); + } +@@ -91,7 +105,9 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async) + { + if (async != QXL_SYNC) { +- spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); ++ spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_PRIMARY_ASYNC)); + } else { + ssd->worker->destroy_primary_surface(ssd->worker, id); + } +diff --git a/ui/spice-display.h b/ui/spice-display.h +index a23bfc8..8a010cb 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -48,6 +48,20 @@ typedef enum qxl_async_io { + QXL_ASYNC, + } qxl_async_io; + ++enum { ++ QXL_COOKIE_TYPE_IO, ++}; ++ ++typedef struct QXLCookie { ++ int type; ++ uint64_t io; ++ union { ++ uint32_t surface_id; ++ } u; ++} QXLCookie; ++ ++QXLCookie *qxl_cookie_new(int type, uint64_t io); ++ + typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; + typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; + +-- +1.7.10 + diff --git a/0418-qxl-make-qxl_render_update-async.patch b/0418-qxl-make-qxl_render_update-async.patch new file mode 100644 index 0000000..c569d73 --- /dev/null +++ b/0418-qxl-make-qxl_render_update-async.patch @@ -0,0 +1,360 @@ +From c26805e29312fee136008a57c70a2f5f140ba706 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:31 +0200 +Subject: [PATCH 418/434] qxl: make qxl_render_update async + +RHBZ# 747011 + +Removes the last user of QXL_SYNC when using update drivers that use the +_ASYNC io ports. + +The last user is qxl_render_update, it is called both by qxl_hw_update +which is the vga_hw_update_ptr passed to graphic_console_init, and by +qxl_hw_screen_dump. + +At the same time the QXLRect area being passed to the red_worker thread +is passed as a copy, as part of the QXLCookie. + +The implementation uses interface_update_area_complete with a bh to make +sure dpy_update and qxl_flip are called from the io thread, otherwise +the vga->ds->surface.data can change under our feet. + +With this patch sdl+spice works fine. But spice by itself doesn't +produce the expected screendumps unless repeated a few times, due to +ppm_save being called before update_area (rendering done in spice server +thread) having a chance to complete. Fixed by next patch, but see commit +message for problem introduced by it. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 96 +++++++++++++++++++++++++++++++++++++--------------- + hw/qxl.c | 69 ++++++++++++++++++++++++++++++++++--- + hw/qxl.h | 10 ++++++ + ui/spice-display.h | 6 ++++ + 4 files changed, 150 insertions(+), 31 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 4c22166..4857838 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -82,17 +82,25 @@ void qxl_render_resize(PCIQXLDevice *qxl) + } + } + +-void qxl_render_update(PCIQXLDevice *qxl) ++static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area) ++{ ++ area->left = 0; ++ area->right = qxl->guest_primary.surface.width; ++ area->top = 0; ++ area->bottom = qxl->guest_primary.surface.height; ++} ++ ++static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + { + VGACommonState *vga = &qxl->vga; +- QXLRect dirty[32], update; +- int i, redraw = 0; ++ int i; + DisplaySurface *surface = vga->ds->surface; + + if (qxl->guest_primary.resized) { + qxl->guest_primary.resized = 0; +- + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); ++ qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); ++ qxl->num_dirty_rects = 1; + dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", + __FUNCTION__, + qxl->guest_primary.surface.width, +@@ -103,9 +111,9 @@ void qxl_render_update(PCIQXLDevice *qxl) + } + if (surface->width != qxl->guest_primary.surface.width || + surface->height != qxl->guest_primary.surface.height) { +- dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", +- __func__); + if (qxl->guest_primary.qxl_stride > 0) { ++ dprint(qxl, 1, "%s: using guest_primary for displaysurface\n", ++ __func__); + qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, +@@ -113,36 +121,70 @@ void qxl_render_update(PCIQXLDevice *qxl) + qxl->guest_primary.abs_stride, + qxl->guest_primary.data); + } else { ++ dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", ++ __func__); + qemu_resize_displaysurface(vga->ds, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); + } + } +- update.left = 0; +- update.right = qxl->guest_primary.surface.width; +- update.top = 0; +- update.bottom = qxl->guest_primary.surface.height; +- +- memset(dirty, 0, sizeof(dirty)); +- if (runstate_is_running() && qxl->guest_primary.commands) { +- qxl->guest_primary.commands = 0; +- qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL); +- } +- if (redraw) { +- memset(dirty, 0, sizeof(dirty)); +- dirty[0] = update; +- } +- for (i = 0; i < ARRAY_SIZE(dirty); i++) { +- if (qemu_spice_rect_is_empty(dirty+i)) { ++ for (i = 0; i < qxl->num_dirty_rects; i++) { ++ if (qemu_spice_rect_is_empty(qxl->dirty+i)) { + break; + } +- qxl_flip(qxl, dirty+i); ++ qxl_flip(qxl, qxl->dirty+i); + dpy_update(vga->ds, +- dirty[i].left, dirty[i].top, +- dirty[i].right - dirty[i].left, +- dirty[i].bottom - dirty[i].top); ++ qxl->dirty[i].left, qxl->dirty[i].top, ++ qxl->dirty[i].right - qxl->dirty[i].left, ++ qxl->dirty[i].bottom - qxl->dirty[i].top); ++ } ++ qxl->num_dirty_rects = 0; ++} ++ ++/* ++ * use ssd.lock to protect render_update_cookie_num. ++ * qxl_render_update is called by io thread or vcpu thread, and the completion ++ * callbacks are called by spice_server thread, defering to bh called from the ++ * io thread. ++ */ ++void qxl_render_update(PCIQXLDevice *qxl) ++{ ++ QXLCookie *cookie; ++ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ ++ if (!runstate_is_running() || !qxl->guest_primary.commands) { ++ qxl_render_update_area_unlocked(qxl); ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ return; + } ++ ++ qxl->guest_primary.commands = 0; ++ qxl->render_update_cookie_num++; ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, ++ 0); ++ qxl_set_rect_to_surface(qxl, &cookie->u.render.area); ++ qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL, ++ 0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie); ++} ++ ++void qxl_render_update_area_bh(void *opaque) ++{ ++ PCIQXLDevice *qxl = opaque; ++ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ qxl_render_update_area_unlocked(qxl); ++ qemu_mutex_unlock(&qxl->ssd.lock); ++} ++ ++void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie) ++{ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ qemu_bh_schedule(qxl->update_area_bh); ++ qxl->render_update_cookie_num--; ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ g_free(cookie); + } + + static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor) +diff --git a/hw/qxl.c b/hw/qxl.c +index e6e65d9..73be115 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -750,6 +750,11 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + __func__, current_async, cookie->io); + } + switch (current_async) { ++ case QXL_IO_MEMSLOT_ADD_ASYNC: ++ case QXL_IO_DESTROY_PRIMARY_ASYNC: ++ case QXL_IO_UPDATE_AREA_ASYNC: ++ case QXL_IO_FLUSH_SURFACES_ASYNC: ++ break; + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); + break; +@@ -759,11 +764,54 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + case QXL_IO_DESTROY_SURFACE_ASYNC: + qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); + break; ++ default: ++ fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__, ++ current_async); + } + qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); + } + + /* called from spice server thread context only */ ++static void interface_update_area_complete(QXLInstance *sin, ++ uint32_t surface_id, ++ QXLRect *dirty, uint32_t num_updated_rects) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ int i; ++ int qxl_i; ++ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ if (surface_id != 0 || !qxl->render_update_cookie_num) { ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ return; ++ } ++ if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { ++ /* ++ * overflow - treat this as a full update. Not expected to be common. ++ */ ++ dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); ++ qxl->guest_primary.resized = 1; ++ } ++ if (qxl->guest_primary.resized) { ++ /* ++ * Don't bother copying or scheduling the bh since we will flip ++ * the whole area anyway on completion of the update_area async call ++ */ ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ return; ++ } ++ qxl_i = qxl->num_dirty_rects; ++ for (i = 0; i < num_updated_rects; i++) { ++ qxl->dirty[qxl_i++] = dirty[i]; ++ } ++ qxl->num_dirty_rects += num_updated_rects; ++ dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", ++ __func__, qxl->num_dirty_rects); ++ qemu_bh_schedule(qxl->update_area_bh); ++ qemu_mutex_unlock(&qxl->ssd.lock); ++} ++ ++/* called from spice server thread context only */ + static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); +@@ -772,12 +820,16 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + switch (cookie->type) { + case QXL_COOKIE_TYPE_IO: + interface_async_complete_io(qxl, cookie); ++ g_free(cookie); ++ break; ++ case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: ++ qxl_render_update_area_done(qxl, cookie); + break; + default: + fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", + __func__, cookie->type); ++ g_free(cookie); + } +- g_free(cookie); + } + + static const QXLInterface qxl_interface = { +@@ -800,6 +852,7 @@ static const QXLInterface qxl_interface = { + .notify_update = interface_notify_update, + .flush_resources = interface_flush_resources, + .async_complete = interface_async_complete, ++ .update_area_complete = interface_update_area_complete, + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +@@ -1216,11 +1269,17 @@ async_common: + switch (io_port) { + case QXL_IO_UPDATE_AREA: + { ++ QXLCookie *cookie = NULL; + QXLRect update = d->ram->update_area; ++ ++ if (async == QXL_ASYNC) { ++ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_UPDATE_AREA_ASYNC); ++ cookie->u.area = update; ++ } + qxl_spice_update_area(d, d->ram->update_surface, +- &update, NULL, 0, 0, async, +- qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_UPDATE_AREA_ASYNC)); ++ cookie ? &cookie->u.area : &update, ++ NULL, 0, 0, async, cookie); + break; + } + case QXL_IO_NOTIFY_CMD: +@@ -1652,6 +1711,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_pipe_signaling(qxl); + qxl_reset_state(qxl); + ++ qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl); ++ + return 0; + } + +diff --git a/hw/qxl.h b/hw/qxl.h +index 1443925..86e415b 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -18,6 +18,8 @@ enum qxl_mode { + + #define QXL_UNDEFINED_IO UINT32_MAX + ++#define QXL_NUM_DIRTY_RECTS 64 ++ + typedef struct PCIQXLDevice { + PCIDevice pci; + SimpleSpiceDisplay ssd; +@@ -93,6 +95,12 @@ typedef struct PCIQXLDevice { + /* user-friendly properties (in megabytes) */ + uint32_t ram_size_mb; + uint32_t vram_size_mb; ++ ++ /* qxl_render_update state */ ++ int render_update_cookie_num; ++ int num_dirty_rects; ++ QXLRect dirty[QXL_NUM_DIRTY_RECTS]; ++ QEMUBH *update_area_bh; + } PCIQXLDevice; + + #define PANIC_ON(x) if ((x)) { \ +@@ -134,3 +142,5 @@ 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); ++void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie); ++void qxl_render_update_area_bh(void *opaque); +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 8a010cb..12e50b6 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -50,6 +50,7 @@ typedef enum qxl_async_io { + + enum { + QXL_COOKIE_TYPE_IO, ++ QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, + }; + + typedef struct QXLCookie { +@@ -57,6 +58,11 @@ typedef struct QXLCookie { + uint64_t io; + union { + uint32_t surface_id; ++ QXLRect area; ++ struct { ++ QXLRect area; ++ int redraw; ++ } render; + } u; + } QXLCookie; + +-- +1.7.10 + diff --git a/0419-spice-use-error_report-to-report-errors.patch b/0419-spice-use-error_report-to-report-errors.patch new file mode 100644 index 0000000..ac7464a --- /dev/null +++ b/0419-spice-use-error_report-to-report-errors.patch @@ -0,0 +1,102 @@ +From 2b973a5ea22635211cbde2e559cc6e6355ca8205 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Fri, 24 Feb 2012 18:13:12 +0100 +Subject: [PATCH 419/434] spice: use error_report to report errors + +Error message reporting during spice startup wasn't consistent, it was done +with fprintf(stderr, "") but sometimes the message didn't have a trailing +\n. Using error_report make the intent of the message clearer and deal +with the final \n for us. + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 2c815f1..8503f03 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -227,8 +227,8 @@ static void channel_event(int event, SpiceChannelEventInfo *info) + add_addr_info(server, (struct sockaddr *)&info->laddr_ext, + info->llen_ext); + } else { +- fprintf(stderr, "spice: %s, extended address is expected\n", +- __func__); ++ error_report("spice: %s, extended address is expected", ++ __func__); + #endif + add_addr_info(client, &info->paddr, info->plen); + add_addr_info(server, &info->laddr, info->llen); +@@ -333,7 +333,7 @@ static int parse_name(const char *string, const char *optname, + if (value != -1) { + return value; + } +- fprintf(stderr, "spice: invalid %s: %s\n", optname, string); ++ error_report("spice: invalid %s: %s", optname, string); + exit(1); + } + +@@ -525,7 +525,7 @@ static int add_channel(const char *name, const char *value, void *opaque) + rc = spice_server_set_channel_security(spice_server, value, security); + } + if (rc != 0) { +- fprintf(stderr, "spice: failed to set channel security for %s\n", value); ++ error_report("spice: failed to set channel security for %s", value); + exit(1); + } + return 0; +@@ -553,15 +553,15 @@ void qemu_spice_init(void) + port = qemu_opt_get_number(opts, "port", 0); + tls_port = qemu_opt_get_number(opts, "tls-port", 0); + if (!port && !tls_port) { +- fprintf(stderr, "neither port nor tls-port specified for spice."); ++ error_report("neither port nor tls-port specified for spice"); + exit(1); + } + if (port < 0 || port > 65535) { +- fprintf(stderr, "spice port is out of range"); ++ error_report("spice port is out of range"); + exit(1); + } + if (tls_port < 0 || tls_port > 65535) { +- fprintf(stderr, "spice tls-port is out of range"); ++ error_report("spice tls-port is out of range"); + exit(1); + } + password = qemu_opt_get(opts, "password"); +@@ -631,11 +631,11 @@ void qemu_spice_init(void) + #if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */ + if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 || + spice_server_set_sasl(spice_server, 1) == -1) { +- fprintf(stderr, "spice: failed to enable sasl\n"); ++ error_report("spice: failed to enable sasl"); + exit(1); + } + #else +- fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n"); ++ error_report("spice: sasl is not available (spice >= 0.9 required)"); + exit(1); + #endif + } +@@ -683,7 +683,7 @@ void qemu_spice_init(void) + qemu_opt_foreach(opts, add_channel, NULL, 0); + + if (0 != spice_server_init(spice_server, &core_interface)) { +- fprintf(stderr, "failed to initialize spice server"); ++ error_report("failed to initialize spice server"); + exit(1); + }; + using_spice = 1; +@@ -708,7 +708,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) + { + if (!spice_server) { + if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) { +- fprintf(stderr, "Oops: spice configured but not active\n"); ++ error_report("Oops: spice configured but not active"); + exit(1); + } + /* +-- +1.7.10 + diff --git a/0420-Error-out-when-tls-channel-option-is-used-without-TL.patch b/0420-Error-out-when-tls-channel-option-is-used-without-TL.patch new file mode 100644 index 0000000..3c73fc3 --- /dev/null +++ b/0420-Error-out-when-tls-channel-option-is-used-without-TL.patch @@ -0,0 +1,44 @@ +From d01f59d652b8ac906ecd129afa338f56b2aaef90 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Fri, 24 Feb 2012 18:28:32 +0100 +Subject: [PATCH 420/434] Error out when tls-channel option is used without + TLS + +It's currently possible to setup spice channels using TLS when +no TLS port has been specified (ie TLS is disabled). This cannot +work, so better to error out in such a situation. + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 8503f03..98356b0 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -511,6 +511,12 @@ static int add_channel(const char *name, const char *value, void *opaque) + int rc; + + if (strcmp(name, "tls-channel") == 0) { ++ int *tls_port = opaque; ++ if (!*tls_port) { ++ error_report("spice: tried to setup tls-channel" ++ " without specifying a TLS port"); ++ exit(1); ++ } + security = SPICE_CHANNEL_SECURITY_SSL; + } + if (strcmp(name, "plaintext-channel") == 0) { +@@ -680,7 +686,7 @@ void qemu_spice_init(void) + spice_server_set_playback_compression + (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1)); + +- qemu_opt_foreach(opts, add_channel, NULL, 0); ++ qemu_opt_foreach(opts, add_channel, &tls_port, 0); + + if (0 != spice_server_init(spice_server, &core_interface)) { + error_report("failed to initialize spice server"); +-- +1.7.10 + diff --git a/0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch b/0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch new file mode 100644 index 0000000..d5b0eb1 --- /dev/null +++ b/0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch @@ -0,0 +1,77 @@ +From 7027fa0d3be22f48a51420a45aff13bec54fef1e Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 27 Feb 2012 11:05:09 +0100 +Subject: [PATCH 421/434] qxl: properly handle upright and non-shared surfaces + +Although qxl creates a shared displaysurface when the qxl surface is +upright and doesn't need to be flipped there is no guarantee that the +surface doesn't become unshared for some reason. Rename qxl_flip to +qxl_blit and fix it to handle both flip and non-flip cases. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 4857838..2e10e93 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -21,25 +21,31 @@ + + #include "qxl.h" + +-static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) ++static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) + { + uint8_t *src; + uint8_t *dst = qxl->vga.ds->surface->data; + int len, i; + +- if (qxl->guest_primary.qxl_stride > 0) { ++ if (is_buffer_shared(qxl->vga.ds->surface)) { + return; + } + if (!qxl->guest_primary.data) { + dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); + } +- dprint(qxl, 1, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, ++ dprint(qxl, 2, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, + qxl->guest_primary.qxl_stride, + rect->left, rect->right, rect->top, rect->bottom); + src = qxl->guest_primary.data; +- src += (qxl->guest_primary.surface.height - rect->top - 1) * +- qxl->guest_primary.abs_stride; ++ if (qxl->guest_primary.qxl_stride < 0) { ++ /* qxl surface is upside down, walk src scanlines ++ * in reverse order to flip it */ ++ src += (qxl->guest_primary.surface.height - rect->top - 1) * ++ qxl->guest_primary.abs_stride; ++ } else { ++ src += rect->top * qxl->guest_primary.abs_stride; ++ } + dst += rect->top * qxl->guest_primary.abs_stride; + src += rect->left * qxl->guest_primary.bytes_pp; + dst += rect->left * qxl->guest_primary.bytes_pp; +@@ -48,7 +54,7 @@ static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) + for (i = rect->top; i < rect->bottom; i++) { + memcpy(dst, src, len); + dst += qxl->guest_primary.abs_stride; +- src -= qxl->guest_primary.abs_stride; ++ src += qxl->guest_primary.qxl_stride; + } + } + +@@ -132,7 +138,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + if (qemu_spice_rect_is_empty(qxl->dirty+i)) { + break; + } +- qxl_flip(qxl, qxl->dirty+i); ++ qxl_blit(qxl, qxl->dirty+i); + dpy_update(vga->ds, + qxl->dirty[i].left, qxl->dirty[i].top, + qxl->dirty[i].right - qxl->dirty[i].left, +-- +1.7.10 + diff --git a/0422-spice-set-spice-uuid-and-name.patch b/0422-spice-set-spice-uuid-and-name.patch new file mode 100644 index 0000000..bba1015 --- /dev/null +++ b/0422-spice-set-spice-uuid-and-name.patch @@ -0,0 +1,39 @@ +From 544cfc4a2c730aca346df7215a0dd83280f864d5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 5 Mar 2012 18:22:26 +0100 +Subject: [PATCH 422/434] spice: set spice uuid and name + +This allows a Spice client to identify a VM + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 98356b0..4ad0a67 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -19,6 +19,7 @@ + #include + + #include ++#include "sysemu.h" + + #include "qemu-common.h" + #include "qemu-spice.h" +@@ -688,6 +689,11 @@ void qemu_spice_init(void) + + qemu_opt_foreach(opts, add_channel, &tls_port, 0); + ++#if SPICE_SERVER_VERSION >= 0x000a02 /* 0.10.2 */ ++ spice_server_set_name(spice_server, qemu_name); ++ spice_server_set_uuid(spice_server, qemu_uuid); ++#endif ++ + if (0 != spice_server_init(spice_server, &core_interface)) { + error_report("failed to initialize spice server"); + exit(1); +-- +1.7.10 + diff --git a/0423-monitor-fix-client_migrate_info-error-handling.patch b/0423-monitor-fix-client_migrate_info-error-handling.patch new file mode 100644 index 0000000..b691cf5 --- /dev/null +++ b/0423-monitor-fix-client_migrate_info-error-handling.patch @@ -0,0 +1,35 @@ +From 63f3e6ee49e0a88bbd7915d81962c9046205c411 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Sun, 18 Mar 2012 09:42:39 +0200 +Subject: [PATCH 423/434] monitor: fix client_migrate_info error handling + +Report QERR_MISSING_PARAMETER when port is missing. Otherwise +QERR_UNDEFINED_ERROR will occur. + +rhbz #795652 + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + monitor.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/monitor.c b/monitor.c +index 3c23aa4..76739d7 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -1046,6 +1046,11 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, + return -1; + } + ++ if (port == -1 && tls_port == -1) { ++ qerror_report(QERR_MISSING_PARAMETER, "port/tls-port"); ++ return -1; ++ } ++ + ret = qemu_spice_migrate_info(hostname, port, tls_port, subject, + cb, opaque); + if (ret != 0) { +-- +1.7.10 + diff --git a/0424-qxl-init_pipe_signaling-exit-on-failure.patch b/0424-qxl-init_pipe_signaling-exit-on-failure.patch new file mode 100644 index 0000000..3de1920 --- /dev/null +++ b/0424-qxl-init_pipe_signaling-exit-on-failure.patch @@ -0,0 +1,49 @@ +From d3e6c37f68e7e4573a47b0540f626a2add0d05e4 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 18 Mar 2012 13:46:13 +0100 +Subject: [PATCH 424/434] qxl: init_pipe_signaling: exit on failure + +If pipe creation fails, exit, don't log and continue. Fix indentation at +the same time. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 73be115..9ad5807 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1453,16 +1453,17 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) + + static void init_pipe_signaling(PCIQXLDevice *d) + { +- if (pipe(d->pipe) < 0) { +- dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__); +- return; +- } +- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); +- fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); +- fcntl(d->pipe[0], F_SETOWN, getpid()); +- +- qemu_thread_get_self(&d->main); +- qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); ++ if (pipe(d->pipe) < 0) { ++ fprintf(stderr, "%s:%s: qxl pipe creation failed\n", ++ __FILE__, __func__); ++ exit(1); ++ } ++ fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); ++ fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); ++ fcntl(d->pipe[0], F_SETOWN, getpid()); ++ ++ qemu_thread_get_self(&d->main); ++ qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); + } + + /* graphics console */ +-- +1.7.10 + diff --git a/0425-qxl-switch-qxl.c-to-trace-events.patch b/0425-qxl-switch-qxl.c-to-trace-events.patch new file mode 100644 index 0000000..e60bd4c --- /dev/null +++ b/0425-qxl-switch-qxl.c-to-trace-events.patch @@ -0,0 +1,753 @@ +From 29304ce6b6863b544f1ad8535a927dfc8864354c Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 18 Mar 2012 13:46:14 +0100 +Subject: [PATCH 425/434] qxl: switch qxl.c to trace-events + +dprint is still used for qxl_init_common one time prints. + +also switched parts of spice-display.c over, mainly all the callbacks to +spice server. + +All qxl device trace events start with the qxl device id. + +Signed-off-by: Alon Levy +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Gerd Hoffmann + +Conflicts: + + trace-events +--- + hw/qxl.c | 141 +++++++++++++++++++++++++--------------------------- + trace-events | 59 ++++++++++++++++++++++ + ui/spice-display.c | 14 +++++- + 3 files changed, 140 insertions(+), 74 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 9ad5807..813873a 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -23,6 +23,7 @@ + #include "qemu-queue.h" + #include "monitor.h" + #include "sysemu.h" ++#include "trace.h" + + #include "qxl.h" + +@@ -143,6 +144,10 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + uint32_t clear_dirty_region, + qxl_async_io async, struct QXLCookie *cookie) + { ++ trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right, ++ area->top, area->bottom); ++ trace_qxl_spice_update_area_rest(qxl->id, 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); +@@ -156,6 +161,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, + uint32_t id) + { ++ trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id); + qemu_mutex_lock(&qxl->track_lock); + qxl->guest_surfaces.cmds[id] = 0; + qxl->guest_surfaces.count--; +@@ -167,6 +173,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + { + QXLCookie *cookie; + ++ trace_qxl_spice_destroy_surface_wait(qxl->id, id, async); + if (async) { + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_DESTROY_SURFACE_ASYNC); +@@ -174,12 +181,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); +- qxl_spice_destroy_surface_wait_complete(qxl, id); + } + } + + static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count, ++ qxl->num_free_res); + spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_FLUSH_SURFACES_ASYNC)); +@@ -188,21 +196,25 @@ static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count) + { ++ trace_qxl_spice_loadvm_commands(qxl->id, ext, count); + qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count); + } + + void qxl_spice_oom(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_oom(qxl->id); + qxl->ssd.worker->oom(qxl->ssd.worker); + } + + void qxl_spice_reset_memslots(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_reset_memslots(qxl->id); + qxl->ssd.worker->reset_memslots(qxl->ssd.worker); + } + + static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_destroy_surfaces_complete(qxl->id); + qemu_mutex_lock(&qxl->track_lock); + memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); + qxl->guest_surfaces.count = 0; +@@ -211,6 +223,7 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + + static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + { ++ trace_qxl_spice_destroy_surfaces(qxl->id, async); + if (async) { + spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -223,11 +236,13 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_reset_image_cache(qxl->id); + qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); + } + + void qxl_spice_reset_cursor(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_reset_cursor(qxl->id); + qxl->ssd.worker->reset_cursor(qxl->ssd.worker); + qemu_mutex_lock(&qxl->track_lock); + qxl->guest_cursor = 0; +@@ -412,7 +427,7 @@ static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + +- dprint(qxl, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_interface_attach_worker(qxl->id); + qxl->ssd.worker = qxl_worker; + } + +@@ -420,7 +435,7 @@ static void interface_set_compression_level(QXLInstance *sin, int level) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + +- dprint(qxl, 1, "%s: %d\n", __FUNCTION__, level); ++ trace_qxl_interface_set_compression_level(qxl->id, level); + qxl->shadow_rom.compression_level = cpu_to_le32(level); + qxl->rom->compression_level = cpu_to_le32(level); + qxl_rom_set_dirty(qxl); +@@ -430,6 +445,7 @@ static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + ++ trace_qxl_interface_set_mm_time(qxl->id, mm_time); + qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); + qxl->rom->mm_clock = cpu_to_le32(mm_time); + qxl_rom_set_dirty(qxl); +@@ -439,7 +455,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + +- dprint(qxl, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_interface_get_init_info(qxl->id); + info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; + info->memslot_id_bits = MEMSLOT_SLOT_BITS; + info->num_memslots = NUM_MEMSLOTS; +@@ -508,9 +524,10 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + QXLCommand *cmd; + int notify, ret; + ++ trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode)); ++ + switch (qxl->mode) { + case QXL_MODE_VGA: +- dprint(qxl, 2, "%s: vga\n", __FUNCTION__); + ret = false; + qemu_mutex_lock(&qxl->ssd.lock); + if (qxl->ssd.update != NULL) { +@@ -521,19 +538,18 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + } + qemu_mutex_unlock(&qxl->ssd.lock); + if (ret) { +- dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); ++ trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); + qxl_log_command(qxl, "vga", ext); + } + return ret; + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + case QXL_MODE_UNDEFINED: +- dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); + ring = &qxl->ram->cmd_ring; + if (SPICE_RING_IS_EMPTY(ring)) { + return false; + } +- dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); ++ trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); + SPICE_RING_CONS_ITEM(ring, cmd); + ext->cmd = *cmd; + ext->group_id = MEMSLOT_GROUP_GUEST; +@@ -558,6 +574,7 @@ static int interface_req_cmd_notification(QXLInstance *sin) + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int wait = 1; + ++ trace_qxl_ring_command_req_notification(qxl->id); + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: +@@ -595,10 +612,11 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush) + } + + SPICE_RING_PUSH(ring, notify); +- dprint(d, 2, "free: push %d items, notify %s, ring %d/%d [%d,%d]\n", +- d->num_free_res, notify ? "yes" : "no", +- ring->prod - ring->cons, ring->num_items, +- ring->prod, ring->cons); ++ trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode), ++ d->guest_surfaces.count, d->num_free_res, ++ d->last_release, notify ? "yes" : "no"); ++ trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons, ++ ring->num_items, ring->prod, ring->cons); + if (notify) { + qxl_send_events(d, QXL_INTERRUPT_DISPLAY); + } +@@ -645,7 +663,7 @@ static void interface_release_resource(QXLInstance *sin, + } + qxl->last_release = ext.info; + qxl->num_free_res++; +- dprint(qxl, 3, "%4d\r", qxl->num_free_res); ++ trace_qxl_ring_res_put(qxl->id, qxl->num_free_res); + qxl_push_free_res(qxl, 0); + } + +@@ -657,6 +675,8 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * + QXLCommand *cmd; + int notify; + ++ trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode)); ++ + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: +@@ -680,6 +700,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * + if (qxl->id == 0) { + qxl_render_cursor(qxl, ext); + } ++ trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode)); + return true; + default: + return false; +@@ -692,6 +713,7 @@ static int interface_req_cursor_notification(QXLInstance *sin) + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int wait = 1; + ++ trace_qxl_ring_cursor_req_notification(qxl->id); + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: +@@ -719,7 +741,6 @@ static int interface_flush_resources(QXLInstance *sin) + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int ret; + +- dprint(qxl, 1, "free: guest flush (have %d)\n", qxl->num_free_res); + ret = qxl->num_free_res; + if (ret) { + qxl_push_free_res(qxl, 1); +@@ -739,7 +760,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + qxl->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&qxl->async_lock); + +- dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); ++ trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie); + if (!cookie) { + fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); + return; +@@ -785,11 +806,15 @@ static void interface_update_area_complete(QXLInstance *sin, + qemu_mutex_unlock(&qxl->ssd.lock); + return; + } ++ trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left, ++ dirty->right, dirty->top, dirty->bottom); ++ trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects); + if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { + /* + * overflow - treat this as a full update. Not expected to be common. + */ +- dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); ++ trace_qxl_interface_update_area_complete_overflow(qxl->id, ++ QXL_NUM_DIRTY_RECTS); + qxl->guest_primary.resized = 1; + } + if (qxl->guest_primary.resized) { +@@ -805,8 +830,8 @@ static void interface_update_area_complete(QXLInstance *sin, + qxl->dirty[qxl_i++] = dirty[i]; + } + qxl->num_dirty_rects += num_updated_rects; +- dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", +- __func__, qxl->num_dirty_rects); ++ trace_qxl_interface_update_area_complete_schedule_bh(qxl->id, ++ qxl->num_dirty_rects); + qemu_bh_schedule(qxl->update_area_bh); + qemu_mutex_unlock(&qxl->ssd.lock); + } +@@ -860,7 +885,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) + if (d->mode == QXL_MODE_VGA) { + return; + } +- dprint(d, 1, "%s\n", __FUNCTION__); ++ trace_qxl_enter_vga_mode(d->id); + qemu_spice_create_host_primary(&d->ssd); + d->mode = QXL_MODE_VGA; + memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); +@@ -871,7 +896,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) + if (d->mode != QXL_MODE_VGA) { + return; + } +- dprint(d, 1, "%s\n", __FUNCTION__); ++ trace_qxl_exit_vga_mode(d->id); + qxl_destroy_primary(d, QXL_SYNC); + } + +@@ -908,7 +933,7 @@ static void qxl_reset_state(PCIQXLDevice *d) + + static void qxl_soft_reset(PCIQXLDevice *d) + { +- dprint(d, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_soft_reset(d->id); + qxl_check_state(d); + + if (d->id == 0) { +@@ -920,8 +945,7 @@ static void qxl_soft_reset(PCIQXLDevice *d) + + static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + { +- dprint(d, 1, "%s: start%s\n", __FUNCTION__, +- loadvm ? " (loadvm)" : ""); ++ trace_qxl_hard_reset(d->id, loadvm); + + qxl_spice_reset_cursor(d); + qxl_spice_reset_image_cache(d); +@@ -936,13 +960,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + } + qemu_spice_create_host_memslot(&d->ssd); + qxl_soft_reset(d); +- +- dprint(d, 1, "%s: done\n", __FUNCTION__); + } + + static void qxl_reset_handler(DeviceState *dev) + { + PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev); ++ + qxl_hard_reset(d, 0); + } + +@@ -951,8 +974,8 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + VGACommonState *vga = opaque; + PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga); + ++ trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val); + if (qxl->mode != QXL_MODE_VGA) { +- dprint(qxl, 1, "%s\n", __FUNCTION__); + qxl_destroy_primary(qxl, QXL_SYNC); + qxl_soft_reset(qxl); + } +@@ -992,9 +1015,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start); + guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end); + +- dprint(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n", +- __FUNCTION__, slot_id, +- guest_start, guest_end); ++ trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end); + + PANIC_ON(slot_id >= NUM_MEMSLOTS); + PANIC_ON(guest_start > guest_end); +@@ -1040,10 +1061,6 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + memslot.generation = d->rom->slot_generation = 0; + qxl_rom_set_dirty(d); + +- dprint(d, 1, "%s: slot %d: host virt 0x%lx - 0x%lx\n", +- __FUNCTION__, memslot.slot_id, +- memslot.virt_start, memslot.virt_end); +- + 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; +@@ -1053,21 +1070,19 @@ 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); + 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__); + qxl_spice_reset_memslots(d); + memset(&d->guest_slots, 0, sizeof(d->guest_slots)); + } + + static void qxl_reset_surfaces(PCIQXLDevice *d) + { +- dprint(d, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_reset_surfaces(d->id); + d->mode = QXL_MODE_UNDEFINED; + qxl_spice_destroy_surfaces(d, QXL_SYNC); + } +@@ -1109,9 +1124,6 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, + assert(qxl->mode != QXL_MODE_NATIVE); + qxl_exit_vga_mode(qxl); + +- dprint(qxl, 1, "%s: %dx%d\n", __FUNCTION__, +- le32_to_cpu(sc->width), le32_to_cpu(sc->height)); +- + surface.format = le32_to_cpu(sc->format); + surface.height = le32_to_cpu(sc->height); + surface.mem = le64_to_cpu(sc->mem); +@@ -1120,6 +1132,10 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, + surface.width = le32_to_cpu(sc->width); + surface.type = le32_to_cpu(sc->type); + surface.flags = le32_to_cpu(sc->flags); ++ trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem, ++ sc->format, sc->position); ++ trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type, ++ sc->flags); + + surface.mouse_mode = true; + surface.group_id = MEMSLOT_GROUP_GUEST; +@@ -1143,7 +1159,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) + if (d->mode == QXL_MODE_UNDEFINED) { + return 0; + } +- dprint(d, 1, "%s\n", __FUNCTION__); ++ trace_qxl_destroy_primary(d->id); + d->mode = QXL_MODE_UNDEFINED; + qemu_spice_destroy_primary_surface(&d->ssd, 0, async); + qxl_spice_reset_cursor(d); +@@ -1170,8 +1186,8 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) + .mem = devmem + d->shadow_rom.draw_area_offset, + }; + +- dprint(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%" PRIx64 " ]\n", +- __func__, modenr, mode->x_res, mode->y_res, mode->bits, devmem); ++ trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits, ++ devmem); + if (!loadvm) { + qxl_hard_reset(d, 0); + } +@@ -1217,8 +1233,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + 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)); ++ trace_qxl_io_unexpected_vga_mode(d->id, ++ io_port, io_port_to_string(io_port)); + /* be nice to buggy guest drivers */ + if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && + io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { +@@ -1260,11 +1276,12 @@ async_common: + } + d->current_async = orig_io_port; + qemu_mutex_unlock(&d->async_lock); +- dprint(d, 2, "start async %d (%"PRId64")\n", io_port, val); + break; + default: + break; + } ++ trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size, ++ async); + + switch (io_port) { + case QXL_IO_UPDATE_AREA: +@@ -1300,7 +1317,6 @@ async_common: + d->oom_running = 0; + break; + case QXL_IO_SET_MODE: +- dprint(d, 1, "QXL_SET_MODE %d\n", (int)val); + qxl_set_mode(d, val, 0); + break; + case QXL_IO_LOG: +@@ -1310,7 +1326,6 @@ async_common: + } + break; + case QXL_IO_RESET: +- dprint(d, 1, "QXL_IO_RESET\n"); + qxl_hard_reset(d, 0); + break; + case QXL_IO_MEMSLOT_ADD: +@@ -1338,7 +1353,6 @@ async_common: + async); + goto cancel_async; + } +- 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, async); + break; +@@ -1348,11 +1362,9 @@ async_common: + 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)); ++ trace_qxl_io_destroy_primary_ignored(d->id, ++ qxl_mode_to_string(d->mode)); + goto cancel_async; + } + break; +@@ -1372,16 +1384,9 @@ async_common: + 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" +- " (%"PRId64") (%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; + case QXL_IO_DESTROY_ALL_SURFACES: +@@ -1407,7 +1412,7 @@ static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, + { + PCIQXLDevice *d = opaque; + +- dprint(d, 1, "%s: unexpected\n", __FUNCTION__); ++ trace_qxl_io_read_unexpected(d->id); + return 0xff; + } + +@@ -1558,8 +1563,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + surface_offset -= vram_start; + surface_size = cmd->u.surface_create.height * + abs(cmd->u.surface_create.stride); +- dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, +- i, (int)surface_offset, surface_size); ++ trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size); + qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); + } + } +@@ -1759,7 +1763,7 @@ static void qxl_pre_save(void *opaque) + PCIQXLDevice* d = opaque; + uint8_t *ram_start = d->vga.vram_ptr; + +- dprint(d, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_pre_save(d->id); + if (d->last_release == NULL) { + d->last_release_offset = 0; + } else { +@@ -1772,10 +1776,9 @@ static int qxl_pre_load(void *opaque) + { + PCIQXLDevice* d = opaque; + +- dprint(d, 1, "%s: start\n", __FUNCTION__); ++ trace_qxl_pre_load(d->id); + qxl_hard_reset(d, 1); + qxl_exit_vga_mode(d); +- dprint(d, 1, "%s: done\n", __FUNCTION__); + return 0; + } + +@@ -1787,7 +1790,6 @@ static void qxl_create_memslots(PCIQXLDevice *d) + if (!d->guest_slots[i].active) { + continue; + } +- dprint(d, 1, "%s: restoring guest slot %d\n", __func__, i); + qxl_add_memslot(d, i, 0, QXL_SYNC); + } + } +@@ -1799,8 +1801,6 @@ static int qxl_post_load(void *opaque, int version) + QXLCommandExt *cmds; + int in, out, newmode; + +- dprint(d, 1, "%s: start\n", __FUNCTION__); +- + assert(d->last_release_offset < d->vga.vram_size); + if (d->last_release_offset == 0) { + d->last_release = NULL; +@@ -1810,8 +1810,7 @@ static int qxl_post_load(void *opaque, int version) + + d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset); + +- dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__, +- qxl_mode_to_string(d->mode)); ++ trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode)); + newmode = d->mode; + d->mode = QXL_MODE_UNDEFINED; + +@@ -1853,8 +1852,6 @@ static int qxl_post_load(void *opaque, int version) + qxl_set_mode(d, d->shadow_rom.mode, 1); + break; + } +- dprint(d, 1, "%s: done\n", __FUNCTION__); +- + return 0; + } + +diff --git a/trace-events b/trace-events +index 962caca..0bc290f 100644 +--- a/trace-events ++++ b/trace-events +@@ -631,3 +631,62 @@ win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=% + win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x" + win_helper_done(uint32_t tl) "tl=%d" + win_helper_retry(uint32_t tl) "tl=%d" ++ ++# hw/qxl.c ++disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d" ++disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" ++qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %dx%d mem=%lx %d,%d" ++qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d" ++qxl_destroy_primary(int qid) "%d" ++qxl_enter_vga_mode(int qid) "%d" ++qxl_exit_vga_mode(int qid) "%d" ++qxl_hard_reset(int qid, int64_t loadvm) "%d loadvm=%"PRId64"" ++qxl_interface_async_complete_io(int qid, uint32_t current_async, void *cookie) "%d current=%d cookie=%p" ++qxl_interface_attach_worker(int qid) "%d" ++qxl_interface_get_init_info(int qid) "%d" ++qxl_interface_set_compression_level(int qid, int64_t level) "%d %"PRId64 ++qxl_interface_update_area_complete(int qid, uint32_t surface_id, uint32_t dirty_left, uint32_t dirty_right, uint32_t dirty_top, uint32_t dirty_bottom) "%d surface=%d [%d,%d,%d,%d]" ++qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d #=%d" ++qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" ++qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" ++qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" ++qxl_io_read_unexpected(int qid) "%d" ++qxl_io_unexpected_vga_mode(int qid, uint32_t io_port, const char *desc) "%d 0x%x (%s)" ++qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" ++qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 ++qxl_post_load(int qid, const char *mode) "%d %s" ++qxl_pre_load(int qid) "%d" ++qxl_pre_save(int qid) "%d" ++qxl_reset_surfaces(int qid) "%d" ++qxl_ring_command_check(int qid, const char *mode) "%d %s" ++qxl_ring_command_get(int qid, const char *mode) "%d %s" ++qxl_ring_command_req_notification(int qid) "%d" ++qxl_ring_cursor_check(int qid, const char *mode) "%d %s" ++qxl_ring_cursor_get(int qid, const char *mode) "%d %s" ++qxl_ring_cursor_req_notification(int qid) "%d" ++qxl_ring_res_push(int qid, const char *mode, uint32_t surface_count, uint32_t free_res, void *last_release, const char *notify) "%d %s s#=%d res#=%d last=%p notify=%s" ++qxl_ring_res_push_rest(int qid, uint32_t ring_has, uint32_t ring_size, uint32_t prod, uint32_t cons) "%d ring %d/%d [%d,%d]" ++qxl_ring_res_put(int qid, uint32_t free_res) "%d #res=%d" ++qxl_set_mode(int qid, int modenr, uint32_t x_res, uint32_t y_res, uint32_t bits, uint64_t devmem) "%d mode=%d [ x=%d y=%d @ bpp=%d devmem=0x%" PRIx64 " ]" ++qxl_soft_reset(int qid) "%d" ++qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d" ++qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u" ++qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int async) "%d sid=%u surface=%p async=%d" ++qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d" ++qemu_spice_wakeup(uint32_t qid) "%d" ++qemu_spice_start(uint32_t qid) "%d" ++qemu_spice_stop(uint32_t qid) "%d" ++qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d" ++qxl_spice_destroy_surfaces_complete(int qid) "%d" ++qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" ++qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" ++qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" ++qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" ++qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" ++qxl_spice_oom(int qid) "%d" ++qxl_spice_reset_cursor(int qid) "%d" ++qxl_spice_reset_image_cache(int qid) "%d" ++qxl_spice_reset_memslots(int qid) "%d" ++qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" ++qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" ++qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" +diff --git a/ui/spice-display.c b/ui/spice-display.c +index ab266ae..28d6d4a 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -22,6 +22,7 @@ + #include "monitor.h" + #include "console.h" + #include "sysemu.h" ++#include "trace.h" + + #include "spice-display.h" + +@@ -73,6 +74,10 @@ QXLCookie *qxl_cookie_new(int type, uint64_t io) + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async) + { ++ trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id, ++ memslot->virt_start, memslot->virt_end, ++ async); ++ + if (async != QXL_SYNC) { + spice_qxl_add_memslot_async(&ssd->qxl, memslot, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -84,6 +89,7 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + + void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) + { ++ trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid); + ssd->worker->del_memslot(ssd->worker, gid, sid); + } + +@@ -91,6 +97,7 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + QXLDevSurfaceCreate *surface, + qxl_async_io async) + { ++ trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); + if (async != QXL_SYNC) { + spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -100,10 +107,10 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + } + } + +- + void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async) + { ++ trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); + if (async != QXL_SYNC) { + spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -115,16 +122,19 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) + { ++ trace_qemu_spice_wakeup(ssd->qxl.id); + ssd->worker->wakeup(ssd->worker); + } + + void qemu_spice_start(SimpleSpiceDisplay *ssd) + { ++ trace_qemu_spice_start(ssd->qxl.id); + ssd->worker->start(ssd->worker); + } + + void qemu_spice_stop(SimpleSpiceDisplay *ssd) + { ++ trace_qemu_spice_stop(ssd->qxl.id); + ssd->worker->stop(ssd->worker); + } + +@@ -142,7 +152,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + return NULL; + }; + +- dprint(2, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__, ++ trace_qemu_spice_create_update( + ssd->dirty.left, ssd->dirty.right, + ssd->dirty.top, ssd->dirty.bottom); + +-- +1.7.10 + diff --git a/0426-qxl-qxl_render.c-add-trace-events.patch b/0426-qxl-qxl_render.c-add-trace-events.patch new file mode 100644 index 0000000..90c4069 --- /dev/null +++ b/0426-qxl-qxl_render.c-add-trace-events.patch @@ -0,0 +1,95 @@ +From 6b3e0d7afd011b8d40207fe45f6518937df1d99e Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 18 Mar 2012 13:46:15 +0100 +Subject: [PATCH 426/434] qxl/qxl_render.c: add trace events + +Signed-off-by: Alon Levy +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Gerd Hoffmann + +Cherry-pick: Added missing include "trace.h" +--- + hw/qxl-render.c | 14 +++++--------- + trace-events | 7 +++++++ + 2 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 2e10e93..835dc5e 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -20,6 +20,7 @@ + */ + + #include "qxl.h" ++#include "trace.h" + + static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) + { +@@ -31,11 +32,10 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) + return; + } + if (!qxl->guest_primary.data) { +- dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); ++ trace_qxl_render_blit_guest_primary_initialized(); + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); + } +- dprint(qxl, 2, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, +- qxl->guest_primary.qxl_stride, ++ trace_qxl_render_blit(qxl->guest_primary.qxl_stride, + rect->left, rect->right, rect->top, rect->bottom); + src = qxl->guest_primary.data; + if (qxl->guest_primary.qxl_stride < 0) { +@@ -107,8 +107,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); + qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); + qxl->num_dirty_rects = 1; +- dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", +- __FUNCTION__, ++ trace_qxl_render_guest_primary_resized( + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.qxl_stride, +@@ -118,8 +117,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + if (surface->width != qxl->guest_primary.surface.width || + surface->height != qxl->guest_primary.surface.height) { + if (qxl->guest_primary.qxl_stride > 0) { +- dprint(qxl, 1, "%s: using guest_primary for displaysurface\n", +- __func__); + qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, +@@ -127,8 +124,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.abs_stride, + qxl->guest_primary.data); + } else { +- dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", +- __func__); + qemu_resize_displaysurface(vga->ds, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); +@@ -187,6 +182,7 @@ void qxl_render_update_area_bh(void *opaque) + void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie) + { + qemu_mutex_lock(&qxl->ssd.lock); ++ trace_qxl_render_update_area_done(cookie); + qemu_bh_schedule(qxl->update_area_bh); + qxl->render_update_cookie_num--; + qemu_mutex_unlock(&qxl->ssd.lock); +diff --git a/trace-events b/trace-events +index 0bc290f..6050d92 100644 +--- a/trace-events ++++ b/trace-events +@@ -690,3 +690,10 @@ qxl_spice_reset_memslots(int qid) "%d" + qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" + qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" + qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" ++qxl_vga_ioport_while_not_in_vga_mode(int qid) "%d (int qid, reset to VGA mode because of VGA io)" ++ ++# hw/qxl-render.c ++qxl_render_blit_guest_primary_initialized(void) "" ++qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]" ++qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d" ++qxl_render_update_area_done(void *cookie) "%p" +-- +1.7.10 + diff --git a/0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch b/0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch new file mode 100644 index 0000000..b723016 --- /dev/null +++ b/0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch @@ -0,0 +1,80 @@ +From 1ca7f74b31de28e9170e404ce2b932e311e4d2d0 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 16 Mar 2012 13:50:04 +0000 +Subject: [PATCH 427/434] hw/qxl.c: Fix compilation failures on 32 bit hosts + +Fix compilation failures on 32 bit hosts (cast from pointer to +integer of different size; %ld expects 'long int' not uint64_t). + +Reported-by: Steve Langasek +Signed-off-by: Peter Maydell +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 813873a..bcdf274 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -154,7 +154,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + } else { + assert(cookie != NULL); + spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, +- clear_dirty_region, (uint64_t)cookie); ++ clear_dirty_region, (uintptr_t)cookie); + } + } + +@@ -178,7 +178,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_DESTROY_SURFACE_ASYNC); + cookie->u.surface_id = id; +- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); ++ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + } +@@ -189,8 +189,8 @@ static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count, + qxl->num_free_res); + spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_FLUSH_SURFACES_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_FLUSH_SURFACES_ASYNC)); + } + + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, +@@ -226,8 +226,8 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + trace_qxl_spice_destroy_surfaces(qxl->id, async); + if (async) { + spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); + } else { + qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); + qxl_spice_destroy_surfaces_complete(qxl); +@@ -767,7 +767,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + } + if (cookie && current_async != cookie->io) { + fprintf(stderr, +- "qxl: %s: error: current_async = %d != %ld = cookie->io\n", ++ "qxl: %s: error: current_async = %d != %" PRId64 " = cookie->io\n", + __func__, current_async, cookie->io); + } + switch (current_async) { +@@ -840,7 +840,7 @@ static void interface_update_area_complete(QXLInstance *sin, + static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); +- QXLCookie *cookie = (QXLCookie *)cookie_token; ++ QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; + + switch (cookie->type) { + case QXL_COOKIE_TYPE_IO: +-- +1.7.10 + diff --git a/0428-spice-fix-broken-initialization.patch b/0428-spice-fix-broken-initialization.patch new file mode 100644 index 0000000..6559660 --- /dev/null +++ b/0428-spice-fix-broken-initialization.patch @@ -0,0 +1,67 @@ +From 9f7bc0be9a5c353d076bb42b3bfdf77d8709063f Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 14 Mar 2012 20:33:37 +0200 +Subject: [PATCH 428/434] spice: fix broken initialization + +Commit 1b71f7c14fab6f00c2680d4489fbee7baf796e4f moved MODULE_INIT_QOM to +way before MODULE_INIT_MACHINE, thereby breaking assumptions made in +spice-core.c which registered both a type initializer and a machine +intializer. + +This fix removes the type registration, and replaces it with calling +qemu_spice_init in vl.c after command line parsing (second pass) is +done, and after timers are armed, required by spice server. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann + +Conflicts: + + ui/spice-core.c +--- + ui/spice-core.c | 8 +------- + vl.c | 5 +++++ + 2 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 4ad0a67..a468524 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -554,7 +554,7 @@ void qemu_spice_init(void) + + qemu_thread_get_self(&me); + +- if (!opts) { ++ if (!opts) { + return; + } + port = qemu_opt_get_number(opts, "port", 0); +@@ -787,9 +787,3 @@ static void spice_register_config(void) + qemu_add_opts(&qemu_spice_opts); + } + machine_init(spice_register_config); +- +-static void spice_initialize(void) +-{ +- qemu_spice_init(); +-} +-device_init(spice_initialize); +diff --git a/vl.c b/vl.c +index fdefa86..d33eb03 100644 +--- a/vl.c ++++ b/vl.c +@@ -3271,6 +3271,11 @@ int main(int argc, char **argv, char **envp) + exit(1); + } + ++#ifdef CONFIG_SPICE ++ /* spice needs the timers to be initialized by this point */ ++ qemu_spice_init(); ++#endif ++ + if (icount_option && (kvm_enabled() || xen_enabled())) { + fprintf(stderr, "-icount is not allowed with kvm or xen\n"); + exit(1); +-- +1.7.10 + diff --git a/0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch b/0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch new file mode 100644 index 0000000..27fb514 --- /dev/null +++ b/0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch @@ -0,0 +1,56 @@ +From 2b4d2ccd83280b22d2fea0801e11af5a944a135d Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Wed, 7 Mar 2012 13:36:48 +0000 +Subject: [PATCH 429/434] ui/spice-display.c: Fix compilation warnings on 32 + bit hosts + +Fix compilation failures ("cast from pointer to integer of +different size [-Werror=pointer-to-int-cast]") by using +uintptr_t instead. + +Signed-off-by: Peter Maydell +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 28d6d4a..6d7563f 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -80,8 +80,8 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + + if (async != QXL_SYNC) { + spice_qxl_add_memslot_async(&ssd->qxl, memslot, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_MEMSLOT_ADD_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_MEMSLOT_ADD_ASYNC)); + } else { + ssd->worker->add_memslot(ssd->worker, memslot); + } +@@ -100,8 +100,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); + if (async != QXL_SYNC) { + spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_CREATE_PRIMARY_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_CREATE_PRIMARY_ASYNC)); + } else { + ssd->worker->create_primary_surface(ssd->worker, id, surface); + } +@@ -113,8 +113,8 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); + if (async != QXL_SYNC) { + spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_DESTROY_PRIMARY_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_PRIMARY_ASYNC)); + } else { + ssd->worker->destroy_primary_surface(ssd->worker, id); + } +-- +1.7.10 + diff --git a/0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch b/0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch new file mode 100644 index 0000000..bdfc59e --- /dev/null +++ b/0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch @@ -0,0 +1,78 @@ +From 626eb7b96445815945600895a411ee14c10b9056 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 21 Mar 2012 18:17:18 +0200 +Subject: [PATCH 430/434] ui/spice-display: use uintptr_t when casting qxl + physical addresses + +The current intptr_t casts are a problem when the address's highest +bit is 1, and it is cast to a intptr_t and then to uint64_t, such +as at: + surface.mem = (intptr_t)ssd->buf; + +This causes the sign bit to be extended which causes a wrong address to +be passed on to spice, which then complains when it gets the wrong +slot_id number, since the slot_id is taken from the higher bits. + +The assertion happens early - during the first primary surface creation. + +This fixes running "-vga qxl -spice" with 32 bit compiled +qemu-system-i386. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 6d7563f..cb8a7ad 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -168,7 +168,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + drawable->bbox = ssd->dirty; + drawable->clip.type = SPICE_CLIP_TYPE_NONE; + drawable->effect = QXL_EFFECT_OPAQUE; +- drawable->release_info.id = (intptr_t)update; ++ drawable->release_info.id = (uintptr_t)update; + drawable->type = QXL_DRAW_COPY; + drawable->surfaces_dest[0] = -1; + drawable->surfaces_dest[1] = -1; +@@ -179,7 +179,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + + time_space.tv_nsec / 1000 / 1000; + + drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; +- drawable->u.copy.src_bitmap = (intptr_t)image; ++ drawable->u.copy.src_bitmap = (uintptr_t)image; + drawable->u.copy.src_area.right = bw; + drawable->u.copy.src_area.bottom = bh; + +@@ -189,7 +189,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + image->bitmap.stride = bw * 4; + image->descriptor.width = image->bitmap.x = bw; + image->descriptor.height = image->bitmap.y = bh; +- image->bitmap.data = (intptr_t)(update->bitmap); ++ image->bitmap.data = (uintptr_t)(update->bitmap); + image->bitmap.palette = 0; + image->bitmap.format = SPICE_BITMAP_FMT_32BIT; + +@@ -210,7 +210,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + } + + cmd->type = QXL_CMD_DRAW; +- cmd->data = (intptr_t)drawable; ++ cmd->data = (uintptr_t)drawable; + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + return update; +@@ -254,7 +254,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + surface.mouse_mode = true; + surface.flags = 0; + surface.type = 0; +- surface.mem = (intptr_t)ssd->buf; ++ surface.mem = (uintptr_t)ssd->buf; + surface.group_id = MEMSLOT_GROUP_HOST; + + qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); +-- +1.7.10 + diff --git a/0431-qxl-add-optinal-64bit-vram-bar.patch b/0431-qxl-add-optinal-64bit-vram-bar.patch new file mode 100644 index 0000000..f686f01 --- /dev/null +++ b/0431-qxl-add-optinal-64bit-vram-bar.patch @@ -0,0 +1,185 @@ +From f1e729a041efbd2d562e8202407e927745210bbd Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 14 Oct 2011 18:05:48 +0200 +Subject: [PATCH 431/434] qxl: add optinal 64bit vram bar + +This patch adds an 64bit pci bar for vram. It is turned off by default. +It can be enabled by setting the size of the 64bit bar to be larger than +the 32bit bar. Both 32bit and 64bit bar refer to the same memory. Only +the first part of the memory is available via 32bit bar. + +The intention is to allow large vram sizes for 64bit guests, by allowing +the vram bar being mapped above 4G, so we don't have to squeeze it into +the pci I/O window below 4G. + +With vram_size_mb=16 and vram64_size_mb=256 it looks like this: + +00:02.0 VGA compatible controller: Red Hat, Inc. Device 0100 (rev 02) (prog-if 00 [VGA controller]) + Subsystem: Red Hat, Inc Device 1100 + Physical Slot: 2 + Flags: fast devsel, IRQ 10 + Memory at f8000000 (32-bit, non-prefetchable) [size=64M] + Memory at fc000000 (32-bit, non-prefetchable) [size=16M] + Memory at fd020000 (32-bit, non-prefetchable) [size=8K] + I/O ports at c5a0 [size=32] + Memory at ffe0000000 (64-bit, prefetchable) [size=256M] + Expansion ROM at fd000000 [disabled] [size=64K] + +[ mapping above 4G needs patched seabios: + http://www.kraxel.org/cgit/seabios/commit/?h=pci64 ] + +Conflicts: + + hw/qxl.c +--- + hw/qxl.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- + hw/qxl.h | 7 +++++++ + 2 files changed, 51 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index bcdf274..18f3759 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1002,6 +1002,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + static const int regions[] = { + QXL_RAM_RANGE_INDEX, + QXL_VRAM_RANGE_INDEX, ++ QXL_VRAM64_RANGE_INDEX, + }; + uint64_t guest_start; + uint64_t guest_end; +@@ -1046,6 +1047,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram); + break; + case QXL_VRAM_RANGE_INDEX: ++ case 4 /* vram 64bit */: + virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar); + break; + default: +@@ -1630,18 +1632,28 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) + qxl->vga.vram_size = ram_min_mb * 1024 * 1024; + } + +- /* vram (surfaces, bar 1) */ ++ /* vram32 (surfaces, 32bit, bar 1) */ ++ if (qxl->vram32_size_mb != -1) { ++ qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024; ++ } ++ if (qxl->vram32_size < 4096) { ++ qxl->vram32_size = 4096; ++ } ++ ++ /* vram (surfaces, 64bit, bar 4+5) */ + if (qxl->vram_size_mb != -1) { + qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; + } +- if (qxl->vram_size < 4096) { +- qxl->vram_size = 4096; ++ if (qxl->vram_size < qxl->vram32_size) { ++ qxl->vram_size = qxl->vram32_size; + } ++ + if (qxl->revision == 1) { ++ qxl->vram32_size = 4096; + qxl->vram_size = 4096; + } +- + qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); ++ qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1); + qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); + } + +@@ -1683,6 +1695,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + + memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram", + qxl->vram_size); ++ memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, ++ 0, qxl->vram32_size); + + io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); + if (qxl->revision == 1) { +@@ -1706,7 +1720,29 @@ static int qxl_init_common(PCIQXLDevice *qxl) + PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram); + + pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, +- PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar); ++ PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar); ++ ++ if (qxl->vram32_size < qxl->vram_size) { ++ /* ++ * Make the 64bit vram bar show up only in case it is ++ * configured to be larger than the 32bit vram bar. ++ */ ++ pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX, ++ PCI_BASE_ADDRESS_SPACE_MEMORY | ++ PCI_BASE_ADDRESS_MEM_TYPE_64 | ++ PCI_BASE_ADDRESS_MEM_PREFETCH, ++ &qxl->vram_bar); ++ } ++ ++ /* print pci bar details */ ++ dprint(qxl, 1, "ram/%s: %d MB [region 0]\n", ++ qxl->id == 0 ? "pri" : "sec", ++ qxl->vga.vram_size / (1024*1024)); ++ dprint(qxl, 1, "vram/32: %d MB [region 1]\n", ++ qxl->vram32_size / (1024*1024)); ++ dprint(qxl, 1, "vram/64: %d MB %s\n", ++ qxl->vram_size / (1024*1024), ++ qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]"); + + qxl->ssd.qxl.base.sif = &qxl_interface.base; + qxl->ssd.qxl.id = qxl->id; +@@ -1918,7 +1954,7 @@ static VMStateDescription qxl_vmstate = { + static Property qxl_properties[] = { + DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, + 64 * 1024 * 1024), +- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, ++ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size, + 64 * 1024 * 1024), + DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, + QXL_DEFAULT_REVISION), +@@ -1926,7 +1962,8 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), +- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), ++ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), ++ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/qxl.h b/hw/qxl.h +index 86e415b..11a0db3 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -16,6 +16,10 @@ enum qxl_mode { + QXL_MODE_NATIVE, + }; + ++#ifndef QXL_VRAM64_RANGE_INDEX ++#define QXL_VRAM64_RANGE_INDEX 4 ++#endif ++ + #define QXL_UNDEFINED_IO UINT32_MAX + + #define QXL_NUM_DIRTY_RECTS 64 +@@ -88,6 +92,8 @@ typedef struct PCIQXLDevice { + /* vram pci bar */ + uint32_t vram_size; + MemoryRegion vram_bar; ++ uint32_t vram32_size; ++ MemoryRegion vram32_bar; + + /* io bar */ + MemoryRegion io_bar; +@@ -95,6 +101,7 @@ typedef struct PCIQXLDevice { + /* user-friendly properties (in megabytes) */ + uint32_t ram_size_mb; + uint32_t vram_size_mb; ++ uint32_t vram32_size_mb; + + /* qxl_render_update state */ + int render_update_cookie_num; +-- +1.7.10 + diff --git a/0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch b/0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch new file mode 100644 index 0000000..3972342 --- /dev/null +++ b/0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch @@ -0,0 +1,35 @@ +From c18b8163ec4ebec3a7f99865038fa1ad36b2add2 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Thu, 29 Mar 2012 22:24:38 +0200 +Subject: [PATCH 432/434] qxl: set default values of vram*_size_mb to -1 + +The addition of those values caused a regression where not specifying +any value for the vram bar size would result in a 4096 _byte_ surface +area. This is ok for the windows driver but causes the X driver to be +unusable. Also, it's a regression. This patch returns the default +behavior of having a 64 megabyte vram BAR. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 18f3759..2135fde 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1962,8 +1962,8 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), +- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), +- DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), ++ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), ++ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), + DEFINE_PROP_END_OF_LIST(), + }; + +-- +1.7.10 + diff --git a/0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch b/0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch new file mode 100644 index 0000000..16e821e --- /dev/null +++ b/0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch @@ -0,0 +1,30 @@ +From 68fc3d666b28d14c5023c1f2115cd3a51389f838 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 18 Apr 2012 12:24:28 +0300 +Subject: [PATCH 433/434] qxl-render: fix broken vnc+spice since commit + f934493 + +Notify any listeners such as vnc that the displaysurface has been +changed, otherwise they will segfault when first accessing the freed old +displaysurface data. + +Signed-off-by: Alon Levy +--- + hw/qxl-render.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 835dc5e..180b8f9 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -127,6 +127,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qemu_resize_displaysurface(vga->ds, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); ++ dpy_resize(vga->ds); + } + } + for (i = 0; i < qxl->num_dirty_rects; i++) { +-- +1.7.10 + diff --git a/0434-qxl-don-t-assert-on-guest-create_guest_primary.patch b/0434-qxl-don-t-assert-on-guest-create_guest_primary.patch new file mode 100644 index 0000000..f98970f --- /dev/null +++ b/0434-qxl-don-t-assert-on-guest-create_guest_primary.patch @@ -0,0 +1,36 @@ +From f9f547a6646d72204d88a79960191a0285774c23 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 18 Apr 2012 14:00:06 +0300 +Subject: [PATCH 434/434] qxl: don't assert on guest create_guest_primary + +initiate the implicit destroy ourselves. + +Signed-off-by: Alon Levy +--- + hw/qxl.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 2135fde..29c8873 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1123,7 +1123,15 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, + QXLDevSurfaceCreate surface; + QXLSurfaceCreate *sc = &qxl->guest_primary.surface; + +- assert(qxl->mode != QXL_MODE_NATIVE); ++ if (qxl->mode == QXL_MODE_NATIVE) { ++ /* ++ * allow a create without a destroy. This could be used ++ * later for an atomic "change primary" but right now just ++ * destroy the primary for the guest. Note that this uses ++ * the ability to have multiple concurrent async commands. ++ */ ++ qxl_destroy_primary(qxl, async); ++ } + qxl_exit_vga_mode(qxl); + + surface.format = le32_to_cpu(sc->format); +-- +1.7.10 + diff --git a/0501-audio-add-VOICE_VOLUME-ctl.patch b/0501-audio-add-VOICE_VOLUME-ctl.patch new file mode 100644 index 0000000..b981b77 --- /dev/null +++ b/0501-audio-add-VOICE_VOLUME-ctl.patch @@ -0,0 +1,68 @@ +From be81272bafb948278e5e5739ef975cd7bbf0ee0c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:35 +0200 +Subject: [PATCH 501/509] audio: add VOICE_VOLUME ctl + +Add a new PCM control operation to update the stream volume on the +audio backend. The argument given is a SWVoiceOut/SWVoiceIn. + +v4: +- verified other backends didn't fail/assert on this new control + they randomly return 0 or -1, but we ignore return value. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/audio.c | 12 ++++++++++++ + audio/audio_int.h | 1 + + 2 files changed, 13 insertions(+) + +diff --git a/audio/audio.c b/audio/audio.c +index 50d0d71..2ae9b2f 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -2050,17 +2050,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) + void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) + { + if (sw) { ++ HWVoiceOut *hw = sw->hw; ++ + sw->vol.mute = mute; + sw->vol.l = nominal_volume.l * lvol / 255; + sw->vol.r = nominal_volume.r * rvol / 255; ++ ++ if (hw->pcm_ops->ctl_out) { ++ hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); ++ } + } + } + + void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) + { + if (sw) { ++ HWVoiceIn *hw = sw->hw; ++ + sw->vol.mute = mute; + sw->vol.l = nominal_volume.l * lvol / 255; + sw->vol.r = nominal_volume.r * rvol / 255; ++ ++ if (hw->pcm_ops->ctl_in) { ++ hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); ++ } + } + } +diff --git a/audio/audio_int.h b/audio/audio_int.h +index 2003f8b..117f95e 100644 +--- a/audio/audio_int.h ++++ b/audio/audio_int.h +@@ -231,6 +231,7 @@ void audio_run (const char *msg); + + #define VOICE_ENABLE 1 + #define VOICE_DISABLE 2 ++#define VOICE_VOLUME 3 + + static inline int audio_ring_dist (int dst, int src, int len) + { +-- +1.7.10 + diff --git a/0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch b/0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch new file mode 100644 index 0000000..656989d --- /dev/null +++ b/0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch @@ -0,0 +1,99 @@ +From eaa3b2d4cc2ac17b2aaf0d6387d3991b9d08c56e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:36 +0200 +Subject: [PATCH 502/509] audio: don't apply volume effect if backend has + VOICE_VOLUME_CAP + +If the audio backend is capable of volume control, don't apply +software volume (mixeng_volume ()), but instead, rely on backend +volume control. This will allow guest to have full range volume +control. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/audio.c | 9 +++++++-- + audio/audio_int.h | 5 +++++ + audio/audio_template.h | 2 ++ + 3 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/audio/audio.c b/audio/audio.c +index 2ae9b2f..0fe95a7 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -954,7 +954,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) + total += isamp; + } + +- mixeng_volume (sw->buf, ret, &sw->vol); ++ if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { ++ mixeng_volume (sw->buf, ret, &sw->vol); ++ } + + sw->clip (buf, sw->buf, ret); + sw->total_hw_samples_acquired += total; +@@ -1038,7 +1040,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) + swlim = audio_MIN (swlim, samples); + if (swlim) { + sw->conv (sw->buf, buf, swlim); +- mixeng_volume (sw->buf, swlim, &sw->vol); ++ ++ if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { ++ mixeng_volume (sw->buf, swlim, &sw->vol); ++ } + } + + while (swlim) { +diff --git a/audio/audio_int.h b/audio/audio_int.h +index 117f95e..b9b0676 100644 +--- a/audio/audio_int.h ++++ b/audio/audio_int.h +@@ -82,6 +82,7 @@ typedef struct HWVoiceOut { + int samples; + QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; + QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; ++ int ctl_caps; + struct audio_pcm_ops *pcm_ops; + QLIST_ENTRY (HWVoiceOut) entries; + } HWVoiceOut; +@@ -101,6 +102,7 @@ typedef struct HWVoiceIn { + + int samples; + QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; ++ int ctl_caps; + struct audio_pcm_ops *pcm_ops; + QLIST_ENTRY (HWVoiceIn) entries; + } HWVoiceIn; +@@ -150,6 +152,7 @@ struct audio_driver { + int max_voices_in; + int voice_size_out; + int voice_size_in; ++ int ctl_caps; + }; + + struct audio_pcm_ops { +@@ -233,6 +236,8 @@ void audio_run (const char *msg); + #define VOICE_DISABLE 2 + #define VOICE_VOLUME 3 + ++#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) ++ + static inline int audio_ring_dist (int dst, int src, int len) + { + return (dst >= src) ? (dst - src) : (len - src + dst); +diff --git a/audio/audio_template.h b/audio/audio_template.h +index e62a713..519432a 100644 +--- a/audio/audio_template.h ++++ b/audio/audio_template.h +@@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) + } + + hw->pcm_ops = drv->pcm_ops; ++ hw->ctl_caps = drv->ctl_caps; ++ + QLIST_INIT (&hw->sw_head); + #ifdef DAC + QLIST_INIT (&hw->cap_head); +-- +1.7.10 + diff --git a/0503-hw-ac97-remove-USE_MIXER-code.patch b/0503-hw-ac97-remove-USE_MIXER-code.patch new file mode 100644 index 0000000..763773a --- /dev/null +++ b/0503-hw-ac97-remove-USE_MIXER-code.patch @@ -0,0 +1,170 @@ +From e27e5ceeee3d8cb55ba0749446b49ccc6ec5b96d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:37 +0200 +Subject: [PATCH 503/509] hw/ac97: remove USE_MIXER code + +That code doesn't compile. The interesting bits for volume control are +going to be rewritten in the following patch. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + hw/ac97.c | 121 ------------------------------------------------------------- + 1 file changed, 121 deletions(-) + +diff --git a/hw/ac97.c b/hw/ac97.c +index 0dbba3b..cd893c3 100644 +--- a/hw/ac97.c ++++ b/hw/ac97.c +@@ -434,99 +434,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) + AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + } + +-#ifdef USE_MIXER +-static void set_volume (AC97LinkState *s, int index, +- audmixerctl_t mt, uint32_t val) +-{ +- int mute = (val >> MUTE_SHIFT) & 1; +- uint8_t rvol = VOL_MASK - (val & VOL_MASK); +- uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); +- rvol = 255 * rvol / VOL_MASK; +- lvol = 255 * lvol / VOL_MASK; +- +-#ifdef SOFT_VOLUME +- if (index == AC97_Master_Volume_Mute) { +- AUD_set_volume_out (s->voice_po, mute, lvol, rvol); +- } +- else { +- AUD_set_volume (mt, &mute, &lvol, &rvol); +- } +-#else +- AUD_set_volume (mt, &mute, &lvol, &rvol); +-#endif +- +- rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); +- lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); +- mixer_store (s, index, val); +-} +- +-static audrecsource_t ac97_to_aud_record_source (uint8_t i) +-{ +- switch (i) { +- case REC_MIC: +- return AUD_REC_MIC; +- +- case REC_CD: +- return AUD_REC_CD; +- +- case REC_VIDEO: +- return AUD_REC_VIDEO; +- +- case REC_AUX: +- return AUD_REC_AUX; +- +- case REC_LINE_IN: +- return AUD_REC_LINE_IN; +- +- case REC_PHONE: +- return AUD_REC_PHONE; +- +- default: +- dolog ("Unknown record source %d, using MIC\n", i); +- return AUD_REC_MIC; +- } +-} +- +-static uint8_t aud_to_ac97_record_source (audrecsource_t rs) +-{ +- switch (rs) { +- case AUD_REC_MIC: +- return REC_MIC; +- +- case AUD_REC_CD: +- return REC_CD; +- +- case AUD_REC_VIDEO: +- return REC_VIDEO; +- +- case AUD_REC_AUX: +- return REC_AUX; +- +- case AUD_REC_LINE_IN: +- return REC_LINE_IN; +- +- case AUD_REC_PHONE: +- return REC_PHONE; +- +- default: +- dolog ("Unknown audio recording source %d using MIC\n", rs); +- return REC_MIC; +- } +-} +- +-static void record_select (AC97LinkState *s, uint32_t val) +-{ +- uint8_t rs = val & REC_MASK; +- uint8_t ls = (val >> 8) & REC_MASK; +- audrecsource_t ars = ac97_to_aud_record_source (rs); +- audrecsource_t als = ac97_to_aud_record_source (ls); +- AUD_set_record_source (&als, &ars); +- rs = aud_to_ac97_record_source (ars); +- ls = aud_to_ac97_record_source (als); +- mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +-} +-#endif +- + static void mixer_reset (AC97LinkState *s) + { + uint8_t active[LAST_INDEX]; +@@ -561,12 +468,6 @@ static void mixer_reset (AC97LinkState *s) + mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); + mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + +-#ifdef USE_MIXER +- record_select (s, 0); +- set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); +- set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM , 0x8808); +- set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); +-#endif + reset_voices (s, active); + } + +@@ -625,20 +526,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) + val |= mixer_load (s, index) & 0xf; + mixer_store (s, index, val); + break; +-#ifdef USE_MIXER +- case AC97_Master_Volume_Mute: +- set_volume (s, index, AUD_MIXER_VOLUME, val); +- break; +- case AC97_PCM_Out_Volume_Mute: +- set_volume (s, index, AUD_MIXER_PCM, val); +- break; +- case AC97_Line_In_Volume_Mute: +- set_volume (s, index, AUD_MIXER_LINE_IN, val); +- break; +- case AC97_Record_Select: +- record_select (s, val); +- break; +-#endif + case AC97_Vendor_ID1: + case AC97_Vendor_ID2: + dolog ("Attempt to write vendor ID to %#x\n", val); +@@ -1191,14 +1078,6 @@ static int ac97_post_load (void *opaque, int version_id) + uint8_t active[LAST_INDEX]; + AC97LinkState *s = opaque; + +-#ifdef USE_MIXER +- record_select (s, mixer_load (s, AC97_Record_Select)); +-#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) +- V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); +- V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); +- V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); +-#undef V_ +-#endif + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); + active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); + active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); +-- +1.7.10 + diff --git a/0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch b/0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch new file mode 100644 index 0000000..015f995 --- /dev/null +++ b/0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch @@ -0,0 +1,28 @@ +From c0bcb346459445db2895fb56c78ab71e592c0c90 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:38 +0200 +Subject: [PATCH 504/509] hw/ac97: the volume mask is not only 0x1f + +It's a case by case (see Table 66. AC ?97 Baseline Audio Register Map) + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + hw/ac97.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/ac97.c b/hw/ac97.c +index cd893c3..aa1babf 100644 +--- a/hw/ac97.c ++++ b/hw/ac97.c +@@ -115,7 +115,6 @@ enum { + #define EACS_VRA 1 + #define EACS_VRM 8 + +-#define VOL_MASK 0x1f + #define MUTE_SHIFT 15 + + #define REC_MASK 7 +-- +1.7.10 + diff --git a/0505-hw-ac97-add-support-for-volume-control.patch b/0505-hw-ac97-add-support-for-volume-control.patch new file mode 100644 index 0000000..551ae8e --- /dev/null +++ b/0505-hw-ac97-add-support-for-volume-control.patch @@ -0,0 +1,134 @@ +From 41d13bd2047a3a3ae8f451ff4aaf0585231ba1c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:39 +0200 +Subject: [PATCH 505/509] hw/ac97: add support for volume control + +Combine output volume with Master and PCM registers values. +Use default values in mixer_reset (). +Set volume on post-load to update backend values. + +v4,v5: +- fix some code style + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + hw/ac97.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/hw/ac97.c b/hw/ac97.c +index aa1babf..dd4917b 100644 +--- a/hw/ac97.c ++++ b/hw/ac97.c +@@ -433,6 +433,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) + AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + } + ++static void get_volume (uint16_t vol, uint16_t mask, int inverse, ++ int *mute, uint8_t *lvol, uint8_t *rvol) ++{ ++ *mute = (vol >> MUTE_SHIFT) & 1; ++ *rvol = (255 * (vol & mask)) / mask; ++ *lvol = (255 * ((vol >> 8) & mask)) / mask; ++ ++ if (inverse) { ++ *rvol = 255 - *rvol; ++ *lvol = 255 - *lvol; ++ } ++} ++ ++static void update_combined_volume_out (AC97LinkState *s) ++{ ++ uint8_t lvol, rvol, plvol, prvol; ++ int mute, pmute; ++ ++ get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, ++ &mute, &lvol, &rvol); ++ /* FIXME: should be 1f according to spec */ ++ get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, ++ &pmute, &plvol, &prvol); ++ ++ mute = mute | pmute; ++ lvol = (lvol * plvol) / 255; ++ rvol = (rvol * prvol) / 255; ++ ++ AUD_set_volume_out (s->voice_po, mute, lvol, rvol); ++} ++ ++static void update_volume_in (AC97LinkState *s) ++{ ++ uint8_t lvol, rvol; ++ int mute; ++ ++ get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, ++ &mute, &lvol, &rvol); ++ ++ AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); ++} ++ ++static void set_volume (AC97LinkState *s, int index, uint32_t val) ++{ ++ mixer_store (s, index, val); ++ if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { ++ update_combined_volume_out (s); ++ } else if (index == AC97_Record_Gain_Mute) { ++ update_volume_in (s); ++ } ++} ++ ++static void record_select (AC97LinkState *s, uint32_t val) ++{ ++ uint8_t rs = val & REC_MASK; ++ uint8_t ls = (val >> 8) & REC_MASK; ++ mixer_store (s, AC97_Record_Select, rs | (ls << 8)); ++} ++ + static void mixer_reset (AC97LinkState *s) + { + uint8_t active[LAST_INDEX]; +@@ -467,6 +526,11 @@ static void mixer_reset (AC97LinkState *s) + mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); + mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + ++ record_select (s, 0); ++ set_volume (s, AC97_Master_Volume_Mute, 0x8000); ++ set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); ++ set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); ++ + reset_voices (s, active); + } + +@@ -525,6 +589,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) + val |= mixer_load (s, index) & 0xf; + mixer_store (s, index, val); + break; ++ case AC97_PCM_Out_Volume_Mute: ++ case AC97_Master_Volume_Mute: ++ case AC97_Record_Gain_Mute: ++ case AC97_Line_In_Volume_Mute: ++ set_volume (s, index, val); ++ break; ++ case AC97_Record_Select: ++ record_select (s, val); ++ break; + case AC97_Vendor_ID1: + case AC97_Vendor_ID2: + dolog ("Attempt to write vendor ID to %#x\n", val); +@@ -1077,6 +1150,14 @@ static int ac97_post_load (void *opaque, int version_id) + uint8_t active[LAST_INDEX]; + AC97LinkState *s = opaque; + ++ record_select (s, mixer_load (s, AC97_Record_Select)); ++ set_volume (s, AC97_Master_Volume_Mute, ++ mixer_load (s, AC97_Master_Volume_Mute)); ++ set_volume (s, AC97_PCM_Out_Volume_Mute, ++ mixer_load (s, AC97_PCM_Out_Volume_Mute)); ++ set_volume (s, AC97_Line_In_Volume_Mute, ++ mixer_load (s, AC97_Line_In_Volume_Mute)); ++ + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); + active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); + active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); +-- +1.7.10 + diff --git a/0506-audio-spice-add-support-for-volume-control.patch b/0506-audio-spice-add-support-for-volume-control.patch new file mode 100644 index 0000000..e713e87 --- /dev/null +++ b/0506-audio-spice-add-support-for-volume-control.patch @@ -0,0 +1,84 @@ +From a9f796f670f3c34c3b5874026b61bbe4d782be2e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:40 +0200 +Subject: [PATCH 506/509] audio/spice: add support for volume control + +Use Spice server volume control API when available. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/spiceaudio.c | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c +index f972110..6f15591 100644 +--- a/audio/spiceaudio.c ++++ b/audio/spiceaudio.c +@@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) + } + spice_server_playback_stop (&out->sin); + break; ++ case VOICE_VOLUME: ++ { ++#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) ++ SWVoiceOut *sw; ++ va_list ap; ++ uint16_t vol[2]; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceOut *); ++ va_end (ap); ++ ++ vol[0] = sw->vol.l / ((1ULL << 16) + 1); ++ vol[1] = sw->vol.r / ((1ULL << 16) + 1); ++ spice_server_playback_set_volume (&out->sin, 2, vol); ++ spice_server_playback_set_mute (&out->sin, sw->vol.mute); ++#endif ++ break; ++ } + } ++ + return 0; + } + +@@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) + in->active = 0; + spice_server_record_stop (&in->sin); + break; ++ case VOICE_VOLUME: ++ { ++#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) ++ SWVoiceIn *sw; ++ va_list ap; ++ uint16_t vol[2]; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceIn *); ++ va_end (ap); ++ ++ vol[0] = sw->vol.l / ((1ULL << 16) + 1); ++ vol[1] = sw->vol.r / ((1ULL << 16) + 1); ++ spice_server_record_set_volume (&in->sin, 2, vol); ++ spice_server_record_set_mute (&in->sin, sw->vol.mute); ++#endif ++ break; ++ } + } ++ + return 0; + } + +@@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = { + .max_voices_in = 1, + .voice_size_out = sizeof (SpiceVoiceOut), + .voice_size_in = sizeof (SpiceVoiceIn), ++#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) ++ .ctl_caps = VOICE_VOLUME_CAP ++#endif + }; + + void qemu_spice_audio_init (void) +-- +1.7.10 + diff --git a/0507-Do-not-use-pa_simple-PulseAudio-API.patch b/0507-Do-not-use-pa_simple-PulseAudio-API.patch new file mode 100644 index 0000000..28f7df7 --- /dev/null +++ b/0507-Do-not-use-pa_simple-PulseAudio-API.patch @@ -0,0 +1,573 @@ +From 5c8ce128ec78d17a8a0f49115dc07726a3d3f0c1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:41 +0200 +Subject: [PATCH 507/509] Do not use pa_simple PulseAudio API + +Unfortunately, pa_simple is a limited API which doesn't let us +retrieve the associated pa_stream. It is needed to control the volume +of the stream. + +In v4: +- add missing braces + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/paaudio.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 339 insertions(+), 38 deletions(-) + +diff --git a/audio/paaudio.c b/audio/paaudio.c +index d1f3912..6f50c1c 100644 +--- a/audio/paaudio.c ++++ b/audio/paaudio.c +@@ -2,8 +2,7 @@ + #include "qemu-common.h" + #include "audio.h" + +-#include +-#include ++#include + + #define AUDIO_CAP "pulseaudio" + #include "audio_int.h" +@@ -15,7 +14,7 @@ typedef struct { + int live; + int decr; + int rpos; +- pa_simple *s; ++ pa_stream *stream; + void *pcm_buf; + struct audio_pt pt; + } PAVoiceOut; +@@ -26,17 +25,23 @@ typedef struct { + int dead; + int incr; + int wpos; +- pa_simple *s; ++ pa_stream *stream; + void *pcm_buf; + struct audio_pt pt; ++ const void *read_data; ++ size_t read_index, read_length; + } PAVoiceIn; + +-static struct { ++typedef struct { + int samples; + char *server; + char *sink; + char *source; +-} conf = { ++ pa_threaded_mainloop *mainloop; ++ pa_context *context; ++} paaudio; ++ ++static paaudio glob_paaudio = { + .samples = 4096, + }; + +@@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) + AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); + } + ++#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ ++ do { \ ++ if (!(expression)) { \ ++ if (rerror) { \ ++ *(rerror) = pa_context_errno ((c)->context); \ ++ } \ ++ goto label; \ ++ } \ ++ } while (0); ++ ++#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ ++ do { \ ++ if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ ++ !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ ++ if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ ++ ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ ++ if (rerror) { \ ++ *(rerror) = pa_context_errno ((c)->context); \ ++ } \ ++ } else { \ ++ if (rerror) { \ ++ *(rerror) = PA_ERR_BADSTATE; \ ++ } \ ++ } \ ++ goto label; \ ++ } \ ++ } while (0); ++ ++static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ ++ while (length > 0) { ++ size_t l; ++ ++ while (!p->read_data) { ++ int r; ++ ++ r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); ++ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); ++ ++ if (!p->read_data) { ++ pa_threaded_mainloop_wait (g->mainloop); ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ } else { ++ p->read_index = 0; ++ } ++ } ++ ++ l = p->read_length < length ? p->read_length : length; ++ memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); ++ ++ data = (uint8_t *) data + l; ++ length -= l; ++ ++ p->read_index += l; ++ p->read_length -= l; ++ ++ if (!p->read_length) { ++ int r; ++ ++ r = pa_stream_drop (p->stream); ++ p->read_data = NULL; ++ p->read_length = 0; ++ p->read_index = 0; ++ ++ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); ++ } ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return 0; ++ ++unlock_and_fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return -1; ++} ++ ++static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ ++ while (length > 0) { ++ size_t l; ++ int r; ++ ++ while (!(l = pa_stream_writable_size (p->stream))) { ++ pa_threaded_mainloop_wait (g->mainloop); ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ } ++ ++ CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail); ++ ++ if (l > length) { ++ l = length; ++ } ++ ++ r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); ++ CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail); ++ ++ data = (const uint8_t *) data + l; ++ length -= l; ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return 0; ++ ++unlock_and_fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return -1; ++} ++ + static void *qpa_thread_out (void *arg) + { + PAVoiceOut *pa = arg; +@@ -77,7 +202,7 @@ static void *qpa_thread_out (void *arg) + } + } + +- decr = to_mix = audio_MIN (pa->live, conf.samples >> 2); ++ decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2); + rpos = pa->rpos; + + if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { +@@ -91,8 +216,8 @@ static void *qpa_thread_out (void *arg) + + hw->clip (pa->pcm_buf, src, chunk); + +- if (pa_simple_write (pa->s, pa->pcm_buf, +- chunk << hw->info.shift, &error) < 0) { ++ if (qpa_simple_write (pa, pa->pcm_buf, ++ chunk << hw->info.shift, &error) < 0) { + qpa_logerr (error, "pa_simple_write failed\n"); + return NULL; + } +@@ -169,7 +294,7 @@ static void *qpa_thread_in (void *arg) + } + } + +- incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2); ++ incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2); + wpos = pa->wpos; + + if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { +@@ -181,8 +306,8 @@ static void *qpa_thread_in (void *arg) + int chunk = audio_MIN (to_grab, hw->samples - wpos); + void *buf = advance (pa->pcm_buf, wpos); + +- if (pa_simple_read (pa->s, buf, +- chunk << hw->info.shift, &error) < 0) { ++ if (qpa_simple_read (pa, buf, ++ chunk << hw->info.shift, &error) < 0) { + qpa_logerr (error, "pa_simple_read failed\n"); + return NULL; + } +@@ -283,6 +408,109 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) + } + } + ++static void context_state_cb (pa_context *c, void *userdata) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ switch (pa_context_get_state(c)) { ++ case PA_CONTEXT_READY: ++ case PA_CONTEXT_TERMINATED: ++ case PA_CONTEXT_FAILED: ++ pa_threaded_mainloop_signal (g->mainloop, 0); ++ break; ++ ++ case PA_CONTEXT_UNCONNECTED: ++ case PA_CONTEXT_CONNECTING: ++ case PA_CONTEXT_AUTHORIZING: ++ case PA_CONTEXT_SETTING_NAME: ++ break; ++ } ++} ++ ++static void stream_state_cb (pa_stream *s, void * userdata) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ switch (pa_stream_get_state (s)) { ++ ++ case PA_STREAM_READY: ++ case PA_STREAM_FAILED: ++ case PA_STREAM_TERMINATED: ++ pa_threaded_mainloop_signal (g->mainloop, 0); ++ break; ++ ++ case PA_STREAM_UNCONNECTED: ++ case PA_STREAM_CREATING: ++ break; ++ } ++} ++ ++static void stream_request_cb (pa_stream *s, size_t length, void *userdata) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ pa_threaded_mainloop_signal (g->mainloop, 0); ++} ++ ++static pa_stream *qpa_simple_new ( ++ const char *server, ++ const char *name, ++ pa_stream_direction_t dir, ++ const char *dev, ++ const char *stream_name, ++ const pa_sample_spec *ss, ++ const pa_channel_map *map, ++ const pa_buffer_attr *attr, ++ int *rerror) ++{ ++ paaudio *g = &glob_paaudio; ++ int r; ++ pa_stream *stream; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ stream = pa_stream_new (g->context, name, ss, map); ++ if (!stream) { ++ goto fail; ++ } ++ ++ pa_stream_set_state_callback (stream, stream_state_cb, g); ++ pa_stream_set_read_callback (stream, stream_request_cb, g); ++ pa_stream_set_write_callback (stream, stream_request_cb, g); ++ ++ if (dir == PA_STREAM_PLAYBACK) { ++ r = pa_stream_connect_playback (stream, dev, attr, ++ PA_STREAM_INTERPOLATE_TIMING ++ |PA_STREAM_ADJUST_LATENCY ++ |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); ++ } else { ++ r = pa_stream_connect_record (stream, dev, attr, ++ PA_STREAM_INTERPOLATE_TIMING ++ |PA_STREAM_ADJUST_LATENCY ++ |PA_STREAM_AUTO_TIMING_UPDATE); ++ } ++ ++ if (r < 0) { ++ goto fail; ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ ++ return stream; ++ ++fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++ ++ if (stream) { ++ pa_stream_unref (stream); ++ } ++ ++ qpa_logerr (pa_context_errno (g->context), ++ "stream_new() failed\n"); ++ ++ return NULL; ++} ++ + static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) + { + int error; +@@ -306,24 +534,24 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) + + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); + +- pa->s = pa_simple_new ( +- conf.server, ++ pa->stream = qpa_simple_new ( ++ glob_paaudio.server, + "qemu", + PA_STREAM_PLAYBACK, +- conf.sink, ++ glob_paaudio.sink, + "pcm.playback", + &ss, + NULL, /* channel map */ + &ba, /* buffering attributes */ + &error + ); +- if (!pa->s) { ++ if (!pa->stream) { + qpa_logerr (error, "pa_simple_new for playback failed\n"); + goto fail1; + } + + audio_pcm_init_info (&hw->info, &obt_as); +- hw->samples = conf.samples; ++ hw->samples = glob_paaudio.samples; + pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + pa->rpos = hw->rpos; + if (!pa->pcm_buf) { +@@ -342,8 +570,10 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) + g_free (pa->pcm_buf); + pa->pcm_buf = NULL; + fail2: +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; ++ } + fail1: + return -1; + } +@@ -361,24 +591,24 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as) + + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); + +- pa->s = pa_simple_new ( +- conf.server, ++ pa->stream = qpa_simple_new ( ++ glob_paaudio.server, + "qemu", + PA_STREAM_RECORD, +- conf.source, ++ glob_paaudio.source, + "pcm.capture", + &ss, + NULL, /* channel map */ + NULL, /* buffering attributes */ + &error + ); +- if (!pa->s) { ++ if (!pa->stream) { + qpa_logerr (error, "pa_simple_new for capture failed\n"); + goto fail1; + } + + audio_pcm_init_info (&hw->info, &obt_as); +- hw->samples = conf.samples; ++ hw->samples = glob_paaudio.samples; + pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + pa->wpos = hw->wpos; + if (!pa->pcm_buf) { +@@ -397,8 +627,10 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as) + g_free (pa->pcm_buf); + pa->pcm_buf = NULL; + fail2: +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; ++ } + fail1: + return -1; + } +@@ -413,9 +645,9 @@ static void qpa_fini_out (HWVoiceOut *hw) + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + +- if (pa->s) { +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; + } + + audio_pt_fini (&pa->pt, AUDIO_FUNC); +@@ -433,9 +665,9 @@ static void qpa_fini_in (HWVoiceIn *hw) + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + +- if (pa->s) { +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; + } + + audio_pt_fini (&pa->pt, AUDIO_FUNC); +@@ -460,37 +692,106 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) + /* common */ + static void *qpa_audio_init (void) + { +- return &conf; ++ paaudio *g = &glob_paaudio; ++ ++ g->mainloop = pa_threaded_mainloop_new (); ++ if (!g->mainloop) { ++ goto fail; ++ } ++ ++ g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server); ++ if (!g->context) { ++ goto fail; ++ } ++ ++ pa_context_set_state_callback (g->context, context_state_cb, g); ++ ++ if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) { ++ qpa_logerr (pa_context_errno (g->context), ++ "pa_context_connect() failed\n"); ++ goto fail; ++ } ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ if (pa_threaded_mainloop_start (g->mainloop) < 0) { ++ goto unlock_and_fail; ++ } ++ ++ for (;;) { ++ pa_context_state_t state; ++ ++ state = pa_context_get_state (g->context); ++ ++ if (state == PA_CONTEXT_READY) { ++ break; ++ } ++ ++ if (!PA_CONTEXT_IS_GOOD (state)) { ++ qpa_logerr (pa_context_errno (g->context), ++ "Wrong context state\n"); ++ goto unlock_and_fail; ++ } ++ ++ /* Wait until the context is ready */ ++ pa_threaded_mainloop_wait (g->mainloop); ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ ++ return &glob_paaudio; ++ ++unlock_and_fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++fail: ++ AUD_log (AUDIO_CAP, "Failed to initialize PA context"); ++ return NULL; + } + + static void qpa_audio_fini (void *opaque) + { +- (void) opaque; ++ paaudio *g = opaque; ++ ++ if (g->mainloop) { ++ pa_threaded_mainloop_stop (g->mainloop); ++ } ++ ++ if (g->context) { ++ pa_context_disconnect (g->context); ++ pa_context_unref (g->context); ++ g->context = NULL; ++ } ++ ++ if (g->mainloop) { ++ pa_threaded_mainloop_free (g->mainloop); ++ } ++ ++ g->mainloop = NULL; + } + + struct audio_option qpa_options[] = { + { + .name = "SAMPLES", + .tag = AUD_OPT_INT, +- .valp = &conf.samples, ++ .valp = &glob_paaudio.samples, + .descr = "buffer size in samples" + }, + { + .name = "SERVER", + .tag = AUD_OPT_STR, +- .valp = &conf.server, ++ .valp = &glob_paaudio.server, + .descr = "server address" + }, + { + .name = "SINK", + .tag = AUD_OPT_STR, +- .valp = &conf.sink, ++ .valp = &glob_paaudio.sink, + .descr = "sink device name" + }, + { + .name = "SOURCE", + .tag = AUD_OPT_STR, +- .valp = &conf.source, ++ .valp = &glob_paaudio.source, + .descr = "source device name" + }, + { /* End of list */ } +-- +1.7.10 + diff --git a/0508-configure-pa_simple-is-not-needed-anymore.patch b/0508-configure-pa_simple-is-not-needed-anymore.patch new file mode 100644 index 0000000..14e8766 --- /dev/null +++ b/0508-configure-pa_simple-is-not-needed-anymore.patch @@ -0,0 +1,31 @@ +From 1b4ee5ccd426102b9ea415a8ce563bf96d7aa1f4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:42 +0200 +Subject: [PATCH 508/509] configure: pa_simple is not needed anymore + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + configure | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index b03172c..4559836 100755 +--- a/configure ++++ b/configure +@@ -1791,9 +1791,9 @@ for drv in $audio_drv_list; do + ;; + + pa) +- audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ +- "pa_simple *s = 0; pa_simple_free(s); return 0;" +- libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" ++ audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ ++ "pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" ++ libs_softmmu="-lpulse $libs_softmmu" + audio_pt_int="yes" + ;; + +-- +1.7.10 + diff --git a/0509-Allow-controlling-volume-with-PulseAudio-backend.patch b/0509-Allow-controlling-volume-with-PulseAudio-backend.patch new file mode 100644 index 0000000..acc8ded --- /dev/null +++ b/0509-Allow-controlling-volume-with-PulseAudio-backend.patch @@ -0,0 +1,134 @@ +From 4b09edbfdaad4536617bbb53ccadfe531156ed56 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:43 +0200 +Subject: [PATCH 509/509] Allow controlling volume with PulseAudio backend + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/paaudio.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 94 insertions(+), 5 deletions(-) + +diff --git a/audio/paaudio.c b/audio/paaudio.c +index 6f50c1c..e6708d0 100644 +--- a/audio/paaudio.c ++++ b/audio/paaudio.c +@@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw) + + static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) + { +- (void) hw; +- (void) cmd; ++ PAVoiceOut *pa = (PAVoiceOut *) hw; ++ pa_operation *op; ++ pa_cvolume v; ++ paaudio *g = &glob_paaudio; ++ ++ pa_cvolume_init (&v); ++ ++ switch (cmd) { ++ case VOICE_VOLUME: ++ { ++ SWVoiceOut *sw; ++ va_list ap; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceOut *); ++ va_end (ap); ++ ++ v.channels = 2; ++ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; ++ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ op = pa_context_set_sink_input_volume (g->context, ++ pa_stream_get_index (pa->stream), ++ &v, NULL, NULL); ++ if (!op) ++ qpa_logerr (pa_context_errno (g->context), ++ "set_sink_input_volume() failed\n"); ++ else ++ pa_operation_unref (op); ++ ++ op = pa_context_set_sink_input_mute (g->context, ++ pa_stream_get_index (pa->stream), ++ sw->vol.mute, NULL, NULL); ++ if (!op) { ++ qpa_logerr (pa_context_errno (g->context), ++ "set_sink_input_mute() failed\n"); ++ } else { ++ pa_operation_unref (op); ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ } ++ } + return 0; + } + + static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) + { +- (void) hw; +- (void) cmd; ++ PAVoiceIn *pa = (PAVoiceIn *) hw; ++ pa_operation *op; ++ pa_cvolume v; ++ paaudio *g = &glob_paaudio; ++ ++ pa_cvolume_init (&v); ++ ++ switch (cmd) { ++ case VOICE_VOLUME: ++ { ++ SWVoiceIn *sw; ++ va_list ap; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceIn *); ++ va_end (ap); ++ ++ v.channels = 2; ++ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; ++ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ /* FIXME: use the upcoming "set_source_output_{volume,mute}" */ ++ op = pa_context_set_source_volume_by_index (g->context, ++ pa_stream_get_device_index (pa->stream), ++ &v, NULL, NULL); ++ if (!op) { ++ qpa_logerr (pa_context_errno (g->context), ++ "set_source_volume() failed\n"); ++ } else { ++ pa_operation_unref(op); ++ } ++ ++ op = pa_context_set_source_mute_by_index (g->context, ++ pa_stream_get_index (pa->stream), ++ sw->vol.mute, NULL, NULL); ++ if (!op) { ++ qpa_logerr (pa_context_errno (g->context), ++ "set_source_mute() failed\n"); ++ } else { ++ pa_operation_unref (op); ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ } ++ } + return 0; + } + +@@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = { + .max_voices_out = INT_MAX, + .max_voices_in = INT_MAX, + .voice_size_out = sizeof (PAVoiceOut), +- .voice_size_in = sizeof (PAVoiceIn) ++ .voice_size_in = sizeof (PAVoiceIn), ++ .ctl_caps = VOICE_VOLUME_CAP + }; +-- +1.7.10 + diff --git a/qemu.spec b/qemu.spec index f76c8be..3752fa8 100644 --- a/qemu.spec +++ b/qemu.spec @@ -38,7 +38,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 1.0 -Release: 14%{?dist} +Release: 15%{?dist} # Epoch because we pushed a qemu-1.0 package Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -104,7 +104,7 @@ Patch25: 0025-rbd-always-set-out-parameter-in-qemu_rbd_snap_list.patch Patch26: 0026-e1000-bounds-packet-size-against-buffer-size.patch Patch27: virtio-blk_refuse_SG_IO_requests_with_scsi_off.patch -# USB Redirect patches should go upstream soon! +# USB-redir patches all upstream for 1.1 except for the chardev flowcontrol set Patch101: 0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch Patch102: 0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch Patch103: 0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch @@ -151,6 +151,7 @@ Patch143: 0143-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch Patch144: 0144-usb-redir-An-interface-count-of-0-is-a-valid-value.patch Patch145: 0145-usb-redir-Reset-device-address-and-speed-on-disconne.patch Patch146: 0146-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch +Patch147: 0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch # General bug fixes Patch201: Fix_save-restore_of_in-kernel_i8259.patch @@ -160,6 +161,53 @@ Patch202: qemu-virtio-9p-noatime.patch Patch301: enable_architectural_PMU_cpuid_leaf.patch Patch302: qemu_virtio-scsi_support.patch +# QXL fixes backports, all are upstream for 1.1 +Patch401: 0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch +Patch402: 0402-input-send-kbd-mouse-events-only-to-running-guests.patch +Patch403: 0403-qxl-fix-warnings-on-32bit.patch +Patch404: 0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch +Patch405: 0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch +Patch406: 0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch +Patch407: 0407-Add-SPICE-support-to-add_client-monitor-command.patch +Patch408: 0408-spice-support-ipv6-channel-address-in-monitor-events.patch +Patch409: 0409-qxl-drop-vram-bar-minimum-size.patch +Patch410: 0410-qxl-move-ram-size-init-to-new-function.patch +Patch411: 0411-qxl-add-user-friendly-bar-size-properties.patch +Patch412: 0412-qxl-fix-spice-sdl-no-cursor-regression.patch +Patch413: 0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch +Patch414: 0414-qxl-drop-qxl_spice_update_area_async-definition.patch +Patch415: 0415-qxl-require-spice-0.8.2.patch +Patch416: 0416-qxl-remove-flipped.patch +Patch417: 0417-qxl-introduce-QXLCookie.patch +Patch418: 0418-qxl-make-qxl_render_update-async.patch +Patch419: 0419-spice-use-error_report-to-report-errors.patch +Patch420: 0420-Error-out-when-tls-channel-option-is-used-without-TL.patch +Patch421: 0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch +Patch422: 0422-spice-set-spice-uuid-and-name.patch +Patch423: 0423-monitor-fix-client_migrate_info-error-handling.patch +Patch424: 0424-qxl-init_pipe_signaling-exit-on-failure.patch +Patch425: 0425-qxl-switch-qxl.c-to-trace-events.patch +Patch426: 0426-qxl-qxl_render.c-add-trace-events.patch +Patch427: 0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch +Patch428: 0428-spice-fix-broken-initialization.patch +Patch429: 0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch +Patch430: 0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch +Patch431: 0431-qxl-add-optinal-64bit-vram-bar.patch +Patch432: 0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch +Patch433: 0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch +Patch434: 0434-qxl-don-t-assert-on-guest-create_guest_primary.patch + +# Spice volume control backports, all are upstream for 1.1 +Patch501: 0501-audio-add-VOICE_VOLUME-ctl.patch +Patch502: 0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch +Patch503: 0503-hw-ac97-remove-USE_MIXER-code.patch +Patch504: 0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch +Patch505: 0505-hw-ac97-add-support-for-volume-control.patch +Patch506: 0506-audio-spice-add-support-for-volume-control.patch +Patch507: 0507-Do-not-use-pa_simple-PulseAudio-API.patch +Patch508: 0508-configure-pa_simple-is-not-needed-anymore.patch +Patch509: 0509-Allow-controlling-volume-with-PulseAudio-backend.patch + BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel BuildRequires: libaio-devel @@ -478,6 +526,7 @@ such as kvm_stat. %patch144 -p1 %patch145 -p1 %patch146 -p1 +%patch147 -p1 %patch201 -p1 %patch202 -p1 @@ -485,6 +534,52 @@ such as kvm_stat. %patch301 -p1 %patch302 -p1 +%patch401 -p1 +%patch402 -p1 +%patch403 -p1 +%patch404 -p1 +%patch405 -p1 +%patch406 -p1 +%patch407 -p1 +%patch408 -p1 +%patch409 -p1 +%patch410 -p1 +%patch411 -p1 +%patch412 -p1 +%patch413 -p1 +%patch414 -p1 +%patch415 -p1 +%patch416 -p1 +%patch417 -p1 +%patch418 -p1 +%patch419 -p1 +%patch420 -p1 +%patch421 -p1 +%patch422 -p1 +%patch423 -p1 +%patch424 -p1 +%patch425 -p1 +%patch426 -p1 +%patch427 -p1 +%patch428 -p1 +%patch429 -p1 +%patch430 -p1 +%patch431 -p1 +%patch432 -p1 +%patch433 -p1 +%patch434 -p1 + +%patch501 -p1 +%patch502 -p1 +%patch503 -p1 +%patch504 -p1 +%patch505 -p1 +%patch506 -p1 +%patch507 -p1 +%patch508 -p1 +%patch509 -p1 + + %build # By default we build everything, but allow x86 to build a minimal version # with only similar arch target support @@ -524,6 +619,7 @@ sed -i.debug 's/"-g $CFLAGS"/"$CFLAGS"/g' configure --extra-ldflags="$extraldflags -pie -Wl,-z,relro -Wl,-z,now" \ --extra-cflags="%{optflags} -fPIE -DPIE" \ --enable-spice \ + --enable-mixemu \ %if %{without rbd} --disable-rbd \ %endif @@ -561,6 +657,7 @@ make clean --disable-xen \ %ifarch %{ix86} x86_64 --enable-spice \ + --enable-mixemu \ %endif %if %{without rbd} --disable-rbd \ @@ -912,6 +1009,10 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Thu Apr 19 2012 Hans de Goede - 2:1.0-15 +- Add a couple of backported QXL/Spice bugfixes +- Add spice volume control patches + * Fri Apr 6 2012 Paolo Bonzini - 2:1.0-12 - Add back PPC and SPARC user emulators - Update binfmt rules from upstream