qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC][PATCH 3/4] cfi02: Optimize consecutive write accesses


From: Jan Kiszka
Subject: [Qemu-devel] [RFC][PATCH 3/4] cfi02: Optimize consecutive write accesses
Date: Sun, 13 Apr 2008 12:11:21 +0200
User-agent: Thunderbird 2.0.0.12 (X11/20080226)

The MusicPal emulation supports, of course, also updating the virtual
flash (online or via the emergency procedure [1]). But this procedure
turned out to take ages even on high-end hosts. Running oprofile on QEMU
revealed the bottleneck: before and after each write access, the cfi02
emulation switches the access mode of the flash between read/write and
read-only. For this purpose, cpu_register_physical_memory() is invoked
which is a fairly heavy-weighted function, surely not written to be
called in a tight loop.

Therefore, this patch optimizes the chip un-/locking by invoking
cpu_register_physical_memory() lazily: the chip memory remains
read/writable as long as no read access takes place. Flash update
algorithms like the one of the MusicPal will now be able to write larger
chunks without the overhead of access mode changes (e.g. the MusicPal
writes one sector and only then verifies its content). On the MusicPal,
this speeds up firmware updates significantly. I never ran it without
optimization, it would have taken hours, but now it is done within a few
minutes on a Core 2.

[1] http://www.mydssd.de/musicpal/doku.php?id=my_musicpal:firmware

Signed-off-by: Jan Kiszka <address@hidden>
---
 hw/pflash_cfi02.c |   22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

Index: b/hw/pflash_cfi02.c
===================================================================
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -70,6 +70,7 @@ struct pflash_t {
     QEMUTimer *timer;
     ram_addr_t off;
     int fl_mem;
+    int rom_mode;
     void *storage;
 };
 
@@ -80,6 +81,7 @@ static void pflash_register_memory(pflas
 
     if (rom_mode)
         phys_offset |= pfl->off | IO_MEM_ROMD;
+    pfl->rom_mode = rom_mode;
 
     for (i = 0; i < pfl->mappings; i++)
         cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
@@ -110,7 +112,13 @@ static uint32_t pflash_read (pflash_t *p
 
     DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
     ret = -1;
-    offset -= pfl->base;
+    if (pfl->rom_mode) {
+        offset -= (uint32_t)(long)pfl->storage;
+        /* Lazy reset of to ROMD mode */
+        if (pfl->wcycle == 0)
+            pflash_register_memory(pfl, 1);
+    } else
+        offset -= pfl->base;
     offset &= pfl->chip_len - 1;
     boff = offset & 0xFF;
     if (pfl->width == 2)
@@ -224,8 +232,6 @@ static void pflash_write (pflash_t *pfl,
     uint8_t *p;
     uint8_t cmd;
 
-    /* WARNING: when the memory area is in ROMD mode, the offset is a
-       ram offset, not a physical address */
     cmd = value;
     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
 #if 0
@@ -236,7 +242,9 @@ static void pflash_write (pflash_t *pfl,
     }
     DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
             offset, value, width, pfl->wcycle);
-    if (pfl->wcycle == 0)
+    /* WARNING: when the memory area is in ROMD mode, the offset is a
+       ram offset, not a physical address */
+    if (pfl->rom_mode)
         offset -= (uint32_t)(long)pfl->storage;
     else
         offset -= pfl->base;
@@ -251,8 +259,9 @@ static void pflash_write (pflash_t *pfl,
         boff = boff >> 2;
     switch (pfl->wcycle) {
     case 0:
-        /* Set the device in I/O access mode */
-        pflash_register_memory(pfl, 0);
+        /* Set the device in I/O access mode if required */
+        if (pfl->rom_mode)
+            pflash_register_memory(pfl, 0);
         /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {
@@ -439,7 +448,6 @@ static void pflash_write (pflash_t *pfl,
 
     /* Reset flash */
  reset_flash:
-    pflash_register_memory(pfl, 1);
     pfl->bypass = 0;
     pfl->wcycle = 0;
     pfl->cmd = 0;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]