[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 4/4] cfi02: Use timer-based ROM mode switch
From: |
Jan Kiszka |
Subject: |
[Qemu-devel] [PATCH 4/4] cfi02: Use timer-based ROM mode switch |
Date: |
Thu, 13 May 2010 16:16:48 +0200 |
Due to a bug in pflash_read, we did not switch back to ROM mode when we
should have. But simply fixing the inverted logic leaves us with slow
word-wise flash programming when the guest verifies each write via a
read.
For this reason, this patch establishes a 100 ms timer to trigger the
ROM mode switch. It also fixes the code to start this sequence from all
places that sets write cycle to 0.
Signed-off-by: Jan Kiszka <address@hidden>
---
hw/pflash_cfi02.c | 42 ++++++++++++++++++++++++++++++++----------
1 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index 6bc58b4..3d5ea9a 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -66,7 +66,8 @@ struct pflash_t {
uint16_t unlock_addr[2];
uint8_t cfi_len;
uint8_t cfi_table[0x52];
- QEMUTimer *timer;
+ QEMUTimer *cmd_timer;
+ QEMUTimer *mode_timer;
ram_addr_t off;
int fl_mem;
int rom_mode;
@@ -82,12 +83,22 @@ static void pflash_register_memory(pflash_t *pfl, int
rom_mode)
phys_offset |= pfl->off | IO_MEM_ROMD;
pfl->rom_mode = rom_mode;
+ DPRINTF("%s: rom_mode %d\n", __func__, rom_mode);
for (i = 0; i < pfl->mappings; i++)
cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
pfl->chip_len, phys_offset);
}
-static void pflash_timer (void *opaque)
+static void pflash_start_rom_mode_timer(pflash_t *pfl)
+{
+ if (!pfl->rom_mode) {
+ /* Defer switch by 100 ms */
+ qemu_mod_timer(pfl->mode_timer,
+ qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10);
+ }
+}
+
+static void pflash_cmd_timer(void *opaque)
{
pflash_t *pfl = opaque;
@@ -97,12 +108,21 @@ static void pflash_timer (void *opaque)
if (pfl->bypass) {
pfl->wcycle = 2;
} else {
- pflash_register_memory(pfl, 1);
+ pflash_start_rom_mode_timer(pfl);
pfl->wcycle = 0;
}
pfl->cmd = 0;
}
+static void pflash_mode_timer(void *opaque)
+{
+ pflash_t *pfl = opaque;
+
+ if (!pfl->rom_mode && pfl->wcycle == 0) {
+ pflash_register_memory(pfl, 1);
+ }
+}
+
static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
int width, int be)
{
@@ -112,10 +132,9 @@ static uint32_t pflash_read (pflash_t *pfl,
target_phys_addr_t offset,
DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
ret = -1;
- if (pfl->rom_mode) {
- /* Lazy reset of to ROMD mode */
- if (pfl->wcycle == 0)
- pflash_register_memory(pfl, 1);
+ if (pfl->wcycle == 0) {
+ /* Lazy switch to ROMD mode */
+ pflash_start_rom_mode_timer(pfl);
}
offset &= pfl->chip_len - 1;
boff = offset & 0xFF;
@@ -127,6 +146,7 @@ static uint32_t pflash_read (pflash_t *pfl,
target_phys_addr_t offset,
default:
/* This should never happen : reset state & treat it as a read*/
DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
+ pflash_start_rom_mode_timer(pfl);
pfl->wcycle = 0;
pfl->cmd = 0;
case 0x80:
@@ -389,7 +409,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t
offset,
pfl->status = 0x00;
pflash_update(pfl, 0, pfl->chip_len);
/* Let's wait 5 seconds before chip erase is done */
- qemu_mod_timer(pfl->timer,
+ qemu_mod_timer(pfl->cmd_timer,
qemu_get_clock(vm_clock) + (get_ticks_per_sec() *
5));
break;
case 0x30:
@@ -402,7 +422,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t
offset,
pflash_update(pfl, offset, pfl->sector_len);
pfl->status = 0x00;
/* Let's wait 1/2 second before sector erase is done */
- qemu_mod_timer(pfl->timer,
+ qemu_mod_timer(pfl->cmd_timer,
qemu_get_clock(vm_clock) + (get_ticks_per_sec() /
2));
break;
default:
@@ -440,6 +460,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t
offset,
/* Reset flash */
reset_flash:
+ pflash_start_rom_mode_timer(pfl);
pfl->bypass = 0;
pfl->wcycle = 0;
pfl->cmd = 0;
@@ -647,7 +668,8 @@ pflash_t *pflash_cfi02_register(target_phys_addr_t base,
ram_addr_t off,
#else
pfl->ro = 0;
#endif
- pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
+ pfl->cmd_timer = qemu_new_timer(vm_clock, pflash_cmd_timer, pfl);
+ pfl->mode_timer = qemu_new_timer(vm_clock, pflash_mode_timer, pfl);
pfl->sector_len = sector_len;
pfl->width = width;
pfl->wcycle = 0;
--
1.6.0.2