Skip to contentSkip to conversation

hw/pflash_cfi02: Fix lazy reset of ROMD mode

PATCH Applied Jordan Justen 4 participants 10 messages Apr 3, 2011 – Apr 27, 2011 1 message not in the archive

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 hw/pflash_cfi02: Fix lazy reset of ROMD mode

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hw/pflash_cfi02.c +1 -1
index 30c8aa4..370c5ee 100644
@@ -112,7 +112,7 @@ 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) {
+    if (!pfl->rom_mode) {
         /* Lazy reset of to ROMD mode */
         if (pfl->wcycle == 0)
             pflash_register_memory(pfl, 1);
Signature · 1 line
1.7.1
#1 lore raw
Quoted 9 lines · Jordan Justen

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Thanks, applied.

Quoted 18 lines
hw/pflash_cfi02.c +1 -1
index 30c8aa4..370c5ee 100644
@@ -112,7 +112,7 @@ 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) {
+    if (!pfl->rom_mode) {
         /* Lazy reset of to ROMD mode */
         if (pfl->wcycle == 0)
             pflash_register_memory(pfl, 1);
Signature · 1 line
1.7.1
Signature · 2 lines
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
[email protected]                 http://www.aurel32.net
#2 lore raw
In reply to Jordan Justen
Quoted 15 lines · Jordan Justen

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hw/pflash_cfi02.c +0 -0
index 30c8aa4..370c5ee 100644

hw/pflash_cfi02.c static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, · line 118

Quoted 8 lines
hw/pflash_cfi02.c +1 -1
@@ -112,7 +112,7 @@ 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) {
+    if (!pfl->rom_mode) {
         /* Lazy reset of to ROMD mode */
         if (pfl->wcycle == 0)
             pflash_register_memory(pfl, 1);

Indeed, that block looks weird to its author today as well. But inverting the logic completely defeats the purpose of lazy mode switching (will likely file a patch to remove the block). We should instead switch back using the timer.

So the question is: Did you actually see a problem that the flash was stuck in write mode, or did you just stumble over this strange code? In the former case, please explain the sequence or provide a trace.

Thanks,
Jan

#3 lore raw

PATCH 1/1 pflash: Restore & fix lazy ROMD switching

Quoted 17 lines · Jan Kiszka
Quoted 16 lines · Jordan Justen

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hw/pflash_cfi02.c +0 -0
index 30c8aa4..370c5ee 100644
@@ -112,7 +112,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
 
Quoted 12 lines

hw/pflash_cfi02.c static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, · line 118

Quoted 7 lines
hw/pflash_cfi02.c +1 -1
     DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
     ret = -1;
-    if (pfl->rom_mode) {
+    if (!pfl->rom_mode) {
         /* Lazy reset of to ROMD mode */
         if (pfl->wcycle == 0)
             pflash_register_memory(pfl, 1);

Indeed, that block looks weird to its author today as well. But inverting the logic completely defeats the purpose of lazy mode switching (will likely file a patch to remove the block). We should instead switch back using the timer.

That was wishful thinking. We were actually lacking a switch-back on read, something that the old twisted logic was papering over. Patch below should resolve that more gracefully, at least it does so here.

Jan

------8<------

Commit 5145b3d1cc revealed a bug in the lazy ROMD switch-back logic, but resolved it by breaking that feature. This approach addresses the issue by switching back to ROMD after a certain amount of read accesses without further unlock sequences.

---
 hw/pflash_cfi02.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
hw/pflash_cfi02.c +8 -4
index 370c5ee..14bbc34 100644
@@ -50,6 +50,8 @@ do {                                               \
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+#define PFLASH_LAZY_ROMD_THRESHOLD 42
+
 struct pflash_t {
     BlockDriverState *bs;
     target_phys_addr_t base;
@@ -70,6 +72,7 @@ struct pflash_t {
     ram_addr_t off;
     int fl_mem;
     int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
     void *storage;
 };
 
@@ -112,10 +115,10 @@ 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);
+    /* Lazy reset to ROMD mode after a certain amount of read accesses */
+    if (!pfl->rom_mode && pfl->wcycle == 0 &&
+        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
+        pflash_register_memory(pfl, 1);
     }
     offset &= pfl->chip_len - 1;
     boff = offset & 0xFF;
@@ -254,6 +257,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
         /* Set the device in I/O access mode if required */
         if (pfl->rom_mode)
             pflash_register_memory(pfl, 0);
+        pfl->read_counter = 0;
         /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {
Signature · 1 line
1.7.1
#4 lore raw

Re: [Qemu-devel] [PATCH] pflash: Restore & fix lazy ROMD switching

Quoted 4 lines · Jan Kiszka

Commit 5145b3d1cc revealed a bug in the lazy ROMD switch-back logic, but resolved it by breaking that feature. This approach addresses the issue by switching back to ROMD after a certain amount of read accesses without further unlock sequences.

Without this change, the code will stay in flash mode until a single read occurs. The code sequence you are wanting to support using will issue a read before trying to unlock again?

Actually, I suppose it will want to verify the written data before moving on, so this does make sense.

Is the overhead of switching the modes significant enough to justify the lazy switch-back? (If so, maybe I'll look at this for cfi01 too.)

Thanks,

-Jordan

#5 lore raw

Re: [Qemu-devel] [PATCH] pflash: Restore & fix lazy ROMD switching

Quoted 6 lines · Jordan Justen
Quoted 4 lines · Jan Kiszka

Commit 5145b3d1cc revealed a bug in the lazy ROMD switch-back logic, but resolved it by breaking that feature. This approach addresses the issue by switching back to ROMD after a certain amount of read accesses without further unlock sequences.

Quoted 6 lines

Without this change, the code will stay in flash mode until a single read occurs. The code sequence you are wanting to support using will issue a read before trying to unlock again?

Actually, I suppose it will want to verify the written data before moving on, so this does make sense.

Precisely. The drivers (e.g. Linux) compare two successive reads for bit flips. In their absence, the result was written. The guest I'm optimizing for does 5 reads per write.

Quoted 3 lines

Is the overhead of switching the modes significant enough to justify the lazy switch-back? (If so, maybe I'll look at this for cfi01 too.)

As we call into cpu_register_physical_memory, the overhead is tremendous, an order of magnitude IIRC, which will sum up to huge delays when reflashing a complete multi-MB firmware image e.g.

Jan

#6 lore raw

Re: [Qemu-devel] [PATCH] pflash: Restore & fix lazy ROMD switching

In reply to Jan Kiszka
Quoted 86 lines · Jan Kiszka
Quoted 17 lines · Jan Kiszka
Quoted 16 lines · Jordan Justen

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hw/pflash_cfi02.c +0 -0
index 30c8aa4..370c5ee 100644
@@ -112,7 +112,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
 
Quoted 12 lines

hw/pflash_cfi02.c static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, · line 118

Quoted 7 lines
hw/pflash_cfi02.c +1 -1
     DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
     ret = -1;
-    if (pfl->rom_mode) {
+    if (!pfl->rom_mode) {
         /* Lazy reset of to ROMD mode */
         if (pfl->wcycle == 0)
             pflash_register_memory(pfl, 1);

Indeed, that block looks weird to its author today as well. But inverting the logic completely defeats the purpose of lazy mode switching (will likely file a patch to remove the block). We should instead switch back using the timer.

That was wishful thinking. We were actually lacking a switch-back on read, something that the old twisted logic was papering over. Patch below should resolve that more gracefully, at least it does so here.

Jan

------8<------

Commit 5145b3d1cc revealed a bug in the lazy ROMD switch-back logic, but resolved it by breaking that feature. This approach addresses the issue by switching back to ROMD after a certain amount of read accesses without further unlock sequences.

---
 hw/pflash_cfi02.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
hw/pflash_cfi02.c +7 -4
index 370c5ee..14bbc34 100644
@@ -50,6 +50,8 @@ do {                                               \
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+#define PFLASH_LAZY_ROMD_THRESHOLD 42
+
 struct pflash_t {
     BlockDriverState *bs;
     target_phys_addr_t base;
@@ -70,6 +72,7 @@ struct pflash_t {
     ram_addr_t off;
     int fl_mem;
     int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
     void *storage;
 };
 
@@ -112,10 +115,10 @@ 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);
+    /* Lazy reset to ROMD mode after a certain amount of read accesses */
+    if (!pfl->rom_mode && pfl->wcycle == 0 &&
+        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
+        pflash_register_memory(pfl, 1);
     }
     offset &= pfl->chip_len - 1;
     boff = offset & 0xFF;

hw/pflash_cfi02.c static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, · line 263

Quoted 7 lines
hw/pflash_cfi02.c +1 -0
@@ -254,6 +257,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
         /* Set the device in I/O access mode if required */
         if (pfl->rom_mode)
             pflash_register_memory(pfl, 0);
+        pfl->read_counter = 0;
         /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {

Please apply unless concerns remain.

Jan

#7 lore raw

Re: [Qemu-devel] [PATCH] pflash: Restore & fix lazy ROMD switching

Quoted 88 lines · Jan Kiszka
Quoted 87 lines · Jan Kiszka
Quoted 17 lines · Jan Kiszka
Quoted 16 lines · Jordan Justen

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
hw/pflash_cfi02.c +0 -0
index 30c8aa4..370c5ee 100644
@@ -112,7 +112,7 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
 
Quoted 12 lines

hw/pflash_cfi02.c static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset, · line 118

Quoted 7 lines
hw/pflash_cfi02.c +1 -1
     DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
     ret = -1;
-    if (pfl->rom_mode) {
+    if (!pfl->rom_mode) {
         /* Lazy reset of to ROMD mode */
         if (pfl->wcycle == 0)
             pflash_register_memory(pfl, 1);

Indeed, that block looks weird to its author today as well. But inverting the logic completely defeats the purpose of lazy mode switching (will likely file a patch to remove the block). We should instead switch back using the timer.

That was wishful thinking. We were actually lacking a switch-back on read, something that the old twisted logic was papering over. Patch below should resolve that more gracefully, at least it does so here.

Jan

------8<------

Commit 5145b3d1cc revealed a bug in the lazy ROMD switch-back logic, but resolved it by breaking that feature. This approach addresses the issue by switching back to ROMD after a certain amount of read accesses without further unlock sequences.

---
 hw/pflash_cfi02.c |   12 ++++++++----
 1 files changed, 8 insertions(+), 4 deletions(-)
hw/pflash_cfi02.c +7 -4
index 370c5ee..14bbc34 100644
@@ -50,6 +50,8 @@ do {                                               \
 #define DPRINTF(fmt, ...) do { } while (0)
 #endif
 
+#define PFLASH_LAZY_ROMD_THRESHOLD 42
+
 struct pflash_t {
     BlockDriverState *bs;
     target_phys_addr_t base;
@@ -70,6 +72,7 @@ struct pflash_t {
     ram_addr_t off;
     int fl_mem;
     int rom_mode;
+    int read_counter; /* used for lazy switch-back to rom mode */
     void *storage;
 };
 
@@ -112,10 +115,10 @@ 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);
+    /* Lazy reset to ROMD mode after a certain amount of read accesses */
+    if (!pfl->rom_mode && pfl->wcycle == 0 &&
+        ++pfl->read_counter > PFLASH_LAZY_ROMD_THRESHOLD) {
+        pflash_register_memory(pfl, 1);
     }
     offset &= pfl->chip_len - 1;
     boff = offset & 0xFF;
@@ -254,6 +257,7 @@ static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
         /* Set the device in I/O access mode if required */
Quoted 9 lines

hw/pflash_cfi02.c static void pflash_write (pflash_t *pfl, target_phys_addr_t offset, · line 263

Quoted 6 lines
hw/pflash_cfi02.c +1 -0
         if (pfl->rom_mode)
             pflash_register_memory(pfl, 0);
+        pfl->read_counter = 0;
         /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {

Please apply unless concerns remain.

Done.

Signature · 2 lines
Aurelien Jarno                          GPG: 1024D/F1BCDB73
[email protected]                 http://www.aurel32.net
#8 lore raw
In reply to Jan Kiszka
Quoted 3 lines · Jan Kiszka

Indeed, that block looks weird to its author today as well. But inverting the logic completely defeats the purpose of lazy mode switching (will likely file a patch to remove the block).

Looking at the 2nd parameter to the call, and the pflash_register_memory code, it seems it only makes sense with the !pfl->rom_mode.

I thought that the goal was to allow multiple write operations before exiting to rom mode, but that a read will return it to rom mode. In that case, this change seemed to fix it.

Quoted 6 lines

We should
instead switch back using the timer.

So the question is: Did you actually see a problem that the flash was stuck in write mode, or did you just stumble over this strange code? In the former case, please explain the sequence or provide a trace.

I had enabled the debug trace messages and was probing the flash from the efi shell on x86-64. I found that I would always see the debug messages for reads, after I started writing to the flash.

This change allowed the flash to go back to a rom mode where the debug prints would then disappear for subsequent reads.

-Jordan

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw

PATCH 1/1 hw/pflash_cfi02: Fix lazy reset of ROMD mode

Is this a 'trivial patch,' or does hw/pflash_cfi02 have an active maintainer?

Thanks,

-Jordan

---------- Forwarded message ----------
From: Jordan Justen <[email protected]>
Date: Sun, Apr 3, 2011 at 13:16
Subject: [Qemu-devel] [PATCH] hw/pflash_cfi02: Fix lazy reset of ROMD mode
To: [email protected]
Cc: Jordan Justen <[email protected]>

When checking pfl->rom_mode for when to lazily reenter ROMD mode, the value was check was the opposite of what it should have been. This prevent the part from returning to ROMD mode after a write was made to the CFI rom region.

---
 hw/pflash_cfi02.c |    2 +-

 1 files changed, 1 insertions(+), 1 deletions(-)
hw/pflash_cfi02.c +0 -0
index 30c8aa4..370c5ee 100644
@@ -112,7 +112,7 @@ 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) {
+    if (!pfl->rom_mode) {
        /* Lazy reset of to ROMD mode */
        if (pfl->wcycle == 0) pflash_register_memory(pfl, 1);
--
1.7.1