aboutsummaryrefslogtreecommitdiff
path: root/hw/cirrus_vga.c
diff options
context:
space:
mode:
authoraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2008-11-24 20:21:41 +0000
committeraliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>2008-11-24 20:21:41 +0000
commit2bec46dc97571a3c34b18fe4ca198e7bfbdca41f (patch)
treea005e29d9a7346047169901ae046ebe140b9990b /hw/cirrus_vga.c
parent5832d1f2f51e1a1991c53ea98c535a619cf03001 (diff)
vga optimization (Glauber Costa)
Hypervisors like KVM perform badly while doing mmio on a loop, because it'll generate an exit on each access. This is the case with VGA, which results in very bad performance. In this patch, we map the linear frame buffer as RAM, make sure it has dirty region tracking enabled, and then just let the region to be written. Cleanups suggestions by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Signed-off-by: Glauber Costa <glommer@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5793 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/cirrus_vga.c')
-rw-r--r--hw/cirrus_vga.c65
1 files changed, 65 insertions, 0 deletions
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 01f3b6a631..e0cf458d76 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -31,6 +31,7 @@
#include "pci.h"
#include "console.h"
#include "vga_int.h"
+#include "kvm.h"
/*
* TODO:
@@ -1228,6 +1229,12 @@ static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
}
if (limit > 0) {
+ /* Thinking about changing bank base? First, drop the dirty bitmap information
+ * on the current location, otherwise we lose this pointer forever */
+ if (s->lfb_vram_mapped) {
+ target_phys_addr_t base_addr = isa_mem_base + 0xa0000 + bank_index * 0x8000;
+ cpu_physical_sync_dirty_bitmap(base_addr, base_addr + 0x8000);
+ }
s->cirrus_bank_base[bank_index] = offset;
s->cirrus_bank_limit[bank_index] = limit;
} else {
@@ -1356,6 +1363,7 @@ cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5);
break;
case 0x07: // Extended Sequencer Mode
+ cirrus_update_memory_access(s);
case 0x08: // EEPROM Control
case 0x09: // Scratch Register 0
case 0x0a: // Scratch Register 1
@@ -1528,6 +1536,7 @@ cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
s->gr[reg_index] = reg_value;
cirrus_update_bank_ptr(s, 0);
cirrus_update_bank_ptr(s, 1);
+ cirrus_update_memory_access(s);
break;
case 0x0B:
s->gr[reg_index] = reg_value;
@@ -2618,6 +2627,52 @@ static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
cirrus_linear_bitblt_writel,
};
+static void map_linear_vram(CirrusVGAState *s)
+{
+
+ if (!s->map_addr && s->lfb_addr && s->lfb_end) {
+ s->map_addr = s->lfb_addr;
+ s->map_end = s->lfb_end;
+ cpu_register_physical_memory(s->map_addr, s->map_end - s->map_addr, s->vram_offset);
+ vga_dirty_log_start((VGAState *)s);
+ }
+
+ if (!s->map_addr)
+ return;
+
+ s->lfb_vram_mapped = 0;
+
+ if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
+ && !((s->sr[0x07] & 0x01) == 0)
+ && !((s->gr[0x0B] & 0x14) == 0x14)
+ && !(s->gr[0x0B] & 0x02)) {
+
+ cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
+ (s->vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
+ cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
+ (s->vram_offset + s->cirrus_bank_base[1]) | IO_MEM_RAM);
+
+ s->lfb_vram_mapped = 1;
+ vga_dirty_log_start((VGAState *)s);
+ }
+ else {
+ cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000, s->vga_io_memory);
+ cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000, s->vga_io_memory);
+ }
+
+}
+
+static void unmap_linear_vram(CirrusVGAState *s)
+{
+ if (s->map_addr && s->lfb_addr && s->lfb_end) {
+ vga_dirty_log_stop((VGAState *)s);
+ s->map_addr = s->map_end = 0;
+ }
+
+ cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
+ s->vga_io_memory);
+}
+
/* Compute the memory access functions */
static void cirrus_update_memory_access(CirrusVGAState *s)
{
@@ -2636,11 +2691,13 @@ static void cirrus_update_memory_access(CirrusVGAState *s)
mode = s->gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
+ map_linear_vram(s);
s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
} else {
generic_io:
+ unmap_linear_vram(s);
s->cirrus_linear_write[0] = cirrus_linear_writeb;
s->cirrus_linear_write[1] = cirrus_linear_writew;
s->cirrus_linear_write[2] = cirrus_linear_writel;
@@ -3102,6 +3159,7 @@ static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_be32s(f, &s->hw_cursor_x);
qemu_get_be32s(f, &s->hw_cursor_y);
+ cirrus_update_memory_access(s);
/* force refresh */
s->graphic_mode = -1;
cirrus_update_bank_ptr(s, 0);
@@ -3261,6 +3319,13 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
s->cirrus_linear_io_addr);
cpu_register_physical_memory(addr + 0x1000000, 0x400000,
s->cirrus_linear_bitblt_io_addr);
+
+ s->map_addr = s->map_end = 0;
+ s->lfb_addr = addr & TARGET_PAGE_MASK;
+ s->lfb_end = ((addr + VGA_RAM_SIZE) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
+ /* account for overflow */
+ if (s->lfb_end < addr + VGA_RAM_SIZE)
+ s->lfb_end = addr + VGA_RAM_SIZE;
}
static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,