From 366ba84f40f9b5b4b9ed05ea469a4a9ef419f96c Mon Sep 17 00:00:00 2001
From: Yonit Halperin <yhalperi@redhat.com>
Date: Tue, 21 Feb 2012 11:31:45 +0100
Subject: [PATCH 3/4] qxl: set only off-screen surfaces dirty instead of the
 whole vram

RH-Author: Yonit Halperin <yhalperi@redhat.com>
Message-id: <1329823906-8716-2-git-send-email-yhalperi@redhat.com>
Patchwork-id: 37449
O-Subject: [RHEL 6.3 qemu-kvm PACTH 1/2] qxl: set only off-screen surfaces dirty instead of the whole vram
Bugzilla: 790083
RH-Acked-by: Alon Levy <alevy@redhat.com>
RH-Acked-by: Hans de Goede <hdegoede@redhat.com>
RH-Acked-by: Uri Lublin <uril@redhat.com>

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.

upstream: http://patchwork.ozlabs.org/patch/141279/

Signed-off-by: Yonit Halperin <yhalperi@redhat.com>
---
 hw/qxl.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 51 insertions(+), 10 deletions(-)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/qxl.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/hw/qxl.c b/hw/qxl.c
index 3d9ddd7..cdb2a3c 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1013,7 +1013,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
     qxl_spice_destroy_surfaces(d, QXL_SYNC);
 }
 
-/* called from spice server thread context only */
+/* can be called also from spice server thread context */
 void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
 {
     uint64_t phys   = le64_to_cpu(pqxl);
@@ -1504,6 +1504,53 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
     }
 }
 
+static void qxl_dirty_surfaces(PCIQXLDevice *qxl)
+{
+    ram_addr_t surface0_addr;
+    int i;
+    intptr_t vram_base;
+    ram_addr_t vram_addr;
+
+    if (qxl->mode != QXL_MODE_NATIVE) {
+        return;
+    }
+    surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
+    /* dirty the primary surface */
+    qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
+
+    vram_addr = qxl->vram_offset;
+    vram_base = (intptr_t)qemu_get_ram_ptr(qxl->vram_offset);
+
+    /* dirty the off-screen surfaces */
+    for (i = 0; i < NUM_SURFACES; i++) {
+        QXLSurfaceCmd *cmd;
+        intptr_t surface_addr, 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_addr = (intptr_t)qxl_phys2virt(qxl,
+                                               cmd->u.surface_create.data,
+                                               MEMSLOT_GROUP_GUEST);
+        surface_size = cmd->u.surface_create.height *
+                       abs(cmd->u.surface_create.stride);
+        surface_offset = surface_addr - vram_base;
+        surface_offset &= TARGET_PAGE_MASK;
+
+        dprint(qxl, 3, "%s: dirty surface %d, addr1 %p, offset %p, size %d\n",
+               __func__, i, (void *)surface_addr, (void *)surface_offset,
+               surface_size);
+        qxl_set_dirty(vram_addr + surface_offset,
+                      vram_addr + surface_offset + surface_size);
+
+    }
+}
+
 static void qxl_vm_change_state_handler(void *opaque, int running,
                                         RunState state)
 {
@@ -1517,15 +1564,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 */
-        ram_addr_t vram_addr = qxl->vram_offset;
-        ram_addr_t surface0_addr = qxl->vga.vram_offset + qxl->shadow_rom.draw_area_offset;
-        qxl_set_dirty(vram_addr, vram_addr + qxl->vram_size);
-        qxl_set_dirty(surface0_addr, surface0_addr + qxl->shadow_rom.surface0_area_size);
+    } else {
+        /* make sure surfaces are saved before migration */
+        qxl_dirty_surfaces(qxl);
     }
 }
 
-- 
1.7.7.6

