Skip to contentSkip to conversation

cfi02: Optimize consecutive write accesses

RFC PATCH In review Jan Kiszka 1 participant 1 message Apr 13, 2008

lore
Share & tools
lore

Jan Kiszka

author
#0 lore raw

RFC PATCH 3/4 cfi02: Optimize consecutive write accesses

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

---
 hw/pflash_cfi02.c |   22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)
hw/pflash_cfi02.c +15 -7
Index: 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;