All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality
@ 2019-06-27 20:26 Philippe Mathieu-Daudé
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 01/28] tests/pflash-cfi02: Add test for supported CFI commands Philippe Mathieu-Daudé
                   ` (27 more replies)
  0 siblings, 28 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Hi,

This series is based on Stephen Checkoway work (v4):
https://lists.gnu.org/archive/html/qemu-devel/2019-04/msg04595.html

Stephen work is a great improvement of the actual code, however
while reviewing his patches, I found them quite dense, so I started
to split each logical change to be able to digest his series.

Sfephen implemented the 'interleaving' feature in way I am not yet
confident it is in the project best interest. The relevant thread
started here:
https://lists.gnu.org/archive/html/qemu-devel/2019-06/msg05395.html

However meanwhile we will discuss his interleaving implementation,
I don't want to block the rest of his work, so I took that patch
of (and rebased his work).

I'm spamming all the maintainers of the boards using
pflash_cfi02_register(). This series is not 'block' related, it is
a classical 'device' model series.
Help reviewing is appreciated :)

I am still looking for real-world code stressing this flash model.

Regards,

Phil.

Philippe Mathieu-Daudé (20):
  hw/block/pflash: Simplify trace_pflash_io_read/write()
  hw/block/pflash: Simplify trace_pflash_data_read/write()
  hw/block/pflash_cfi02: Fix debug format string
  hw/block/pflash_cfi02: Add an enum to define the write cycles
  hw/block/pflash_cfi02: Add helpers to manipulate the status bits
  hw/block/pflash_cfi02: Simplify a statement using fall through
  hw/block/pflash_cfi02: Use the ldst API in pflash_write()
  hw/block/pflash_cfi02: Use the ldst API in pflash_read()
  hw/block/pflash_cfi02: Extract the pflash_data_read() function
  hw/block/pflash_cfi02: Unify the MemoryRegionOps
  tests/pflash-cfi02: Refactor to support testing multiple
    configurations
  hw/block/pflash_cfi02: Remove pointless local variable
  hw/block/pflash_cfi02: Document the current CFI values
  hw/block/pflash_cfi02: Hold the PRI table offset in a variable
  hw/block/pflash_cfi02: Document 'Page Mode' operations are not
    supported
  hw/block/pflash_cfi02: Extract pflash_regions_count()
  hw/block/pflash_cfi02: Split if() condition
  hw/block/pflash_cfi02: Reduce single byte/word write delay
  hw/block/pflash_cfi02: Document commands
  hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit

Stephen Checkoway (8):
  tests/pflash-cfi02: Add test for supported CFI commands
  hw/block/pflash_cfi02: Fix command address comparison
  hw/block/pflash_cfi02: Implement nonuniform sector sizes
  hw/block/pflash_cfi02: Fix CFI in autoselect mode
  hw/block/pflash_cfi02: Fix reset command not ignored during erase
  hw/block/pflash_cfi02: Implement multi-sector erase
  hw/block/pflash_cfi02: Implement erase suspend/resume
  hw/block/pflash_cfi02: Use chip erase time specified in the CFI table

 hw/block/pflash_cfi01.c   |  11 +-
 hw/block/pflash_cfi02.c   | 703 ++++++++++++++++++++++++++------------
 hw/block/trace-events     |  10 +-
 tests/Makefile.include    |   2 +
 tests/pflash-cfi02-test.c | 681 ++++++++++++++++++++++++++++++++++++
 5 files changed, 1173 insertions(+), 234 deletions(-)
 create mode 100644 tests/pflash-cfi02-test.c

-- 
2.20.1



^ permalink raw reply	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 01/28] tests/pflash-cfi02: Add test for supported CFI commands
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write() Philippe Mathieu-Daudé
                   ` (26 subsequent siblings)
  27 siblings, 0 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

Test the AMD command set for parallel flash chips. This test uses an
ARM musicpal board with a pflash drive to test the following list of
currently-supported commands.
- Autoselect
- CFI
- Sector erase
- Chip erase
- Program
- Unlock bypass
- Reset

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-2-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: reworded the patch subject, g_assert_cmpint -> cmphex]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 tests/Makefile.include    |   2 +
 tests/pflash-cfi02-test.c | 225 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 227 insertions(+)
 create mode 100644 tests/pflash-cfi02-test.c

diff --git a/tests/Makefile.include b/tests/Makefile.include
index db750dd6d0..d02132fb94 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -260,6 +260,7 @@ check-qtest-arm-y += tests/m25p80-test$(EXESUF)
 check-qtest-arm-y += tests/test-arm-mptimer$(EXESUF)
 check-qtest-arm-y += tests/boot-serial-test$(EXESUF)
 check-qtest-arm-y += tests/hexloader-test$(EXESUF)
+check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF)
 
 check-qtest-aarch64-y = tests/numa-test$(EXESUF)
 check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF)
@@ -767,6 +768,7 @@ tests/device-introspect-test$(EXESUF): tests/device-introspect-test.o
 tests/rtc-test$(EXESUF): tests/rtc-test.o
 tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/hexloader-test$(EXESUF): tests/hexloader-test.o
+tests/pflash-cfi02$(EXESUF): tests/pflash-cfi02-test.o
 tests/endianness-test$(EXESUF): tests/endianness-test.o
 tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
 tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
new file mode 100644
index 0000000000..e7e16a8dd8
--- /dev/null
+++ b/tests/pflash-cfi02-test.c
@@ -0,0 +1,225 @@
+/*
+ * QTest testcase for parallel flash with AMD command set
+ *
+ * Copyright (c) 2019 Stephen Checkoway
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "libqtest.h"
+
+/*
+ * To test the pflash_cfi02 device, we run QEMU with the musicpal machine with
+ * a pflash drive. This enables us to test some flash configurations, but not
+ * all. In particular, we're limited to a 16-bit wide flash device.
+ */
+
+#define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
+#define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
+
+#define FLASH_WIDTH 2
+#define CFI_ADDR (FLASH_WIDTH * 0x55)
+#define UNLOCK0_ADDR (FLASH_WIDTH * 0x5555)
+#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AAA)
+
+#define CFI_CMD 0x98
+#define UNLOCK0_CMD 0xAA
+#define UNLOCK1_CMD 0x55
+#define AUTOSELECT_CMD 0x90
+#define RESET_CMD 0xF0
+#define PROGRAM_CMD 0xA0
+#define SECTOR_ERASE_CMD 0x30
+#define CHIP_ERASE_CMD 0x10
+#define UNLOCK_BYPASS_CMD 0x20
+#define UNLOCK_BYPASS_RESET_CMD 0x00
+
+static char image_path[] = "/tmp/qtest.XXXXXX";
+
+static inline void flash_write(uint64_t byte_addr, uint16_t data)
+{
+    qtest_writew(global_qtest, BASE_ADDR + byte_addr, data);
+}
+
+static inline uint16_t flash_read(uint64_t byte_addr)
+{
+    return qtest_readw(global_qtest, BASE_ADDR + byte_addr);
+}
+
+static void unlock(void)
+{
+    flash_write(UNLOCK0_ADDR, UNLOCK0_CMD);
+    flash_write(UNLOCK1_ADDR, UNLOCK1_CMD);
+}
+
+static void reset(void)
+{
+    flash_write(0, RESET_CMD);
+}
+
+static void sector_erase(uint64_t byte_addr)
+{
+    unlock();
+    flash_write(UNLOCK0_ADDR, 0x80);
+    unlock();
+    flash_write(byte_addr, SECTOR_ERASE_CMD);
+}
+
+static void wait_for_completion(uint64_t byte_addr)
+{
+    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
+    if ((flash_read(byte_addr) & 0x40) ^ (flash_read(byte_addr) & 0x40)) {
+        /* Wait for erase or program to finish. */
+        clock_step_next();
+        /* Ensure that DQ6 has stopped toggling. */
+        g_assert_cmphex(flash_read(byte_addr), ==, flash_read(byte_addr));
+    }
+}
+
+static void bypass_program(uint64_t byte_addr, uint16_t data)
+{
+    flash_write(UNLOCK0_ADDR, PROGRAM_CMD);
+    flash_write(byte_addr, data);
+    /*
+     * Data isn't valid until DQ6 stops toggling. We don't model this as
+     * writes are immediate, but if this changes in the future, we can wait
+     * until the program is complete.
+     */
+    wait_for_completion(byte_addr);
+}
+
+static void program(uint64_t byte_addr, uint16_t data)
+{
+    unlock();
+    bypass_program(byte_addr, data);
+}
+
+static void chip_erase(void)
+{
+    unlock();
+    flash_write(UNLOCK0_ADDR, 0x80);
+    unlock();
+    flash_write(UNLOCK0_ADDR, SECTOR_ERASE_CMD);
+}
+
+static void test_flash(void)
+{
+    global_qtest = qtest_initf("-M musicpal,accel=qtest "
+                               "-drive if=pflash,file=%s,format=raw,copy-on-read",
+                               image_path);
+    /* Check the IDs. */
+    unlock();
+    flash_write(UNLOCK0_ADDR, AUTOSELECT_CMD);
+    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
+    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
+    reset();
+
+    /* Check the erase blocks. */
+    flash_write(CFI_ADDR, CFI_CMD);
+    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x10), ==, 'Q');
+    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x11), ==, 'R');
+    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x12), ==, 'Y');
+    /* Num erase regions. */
+    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x2C), >=, 1);
+    uint32_t nb_sectors = flash_read(FLASH_WIDTH * 0x2D) +
+                          (flash_read(FLASH_WIDTH * 0x2E) << 8) + 1;
+    uint32_t sector_len = (flash_read(FLASH_WIDTH * 0x2F) << 8) +
+                          (flash_read(FLASH_WIDTH * 0x30) << 16);
+    reset();
+
+    /* Erase and program sector. */
+    for (uint32_t i = 0; i < nb_sectors; ++i) {
+        uint64_t byte_addr = i * sector_len;
+        sector_erase(byte_addr);
+        /* Read toggle. */
+        uint16_t status0 = flash_read(byte_addr);
+        /* DQ7 is 0 during an erase. */
+        g_assert_cmphex(status0 & 0x80, ==, 0);
+        uint16_t status1 = flash_read(byte_addr);
+        /* DQ6 toggles during an erase. */
+        g_assert_cmphex(status0 & 0x40, !=, status1 & 0x40);
+        /* Wait for erase to complete. */
+        clock_step_next();
+        /* Ensure DQ6 has stopped toggling. */
+        g_assert_cmphex(flash_read(byte_addr), ==, flash_read(byte_addr));
+        /* Now the data should be valid. */
+        g_assert_cmphex(flash_read(byte_addr), ==, 0xFFFF);
+
+        /* Program a bit pattern. */
+        program(byte_addr, 0x5555);
+        g_assert_cmphex(flash_read(byte_addr), ==, 0x5555);
+        program(byte_addr, 0xAA55);
+        g_assert_cmphex(flash_read(byte_addr), ==, 0x0055);
+    }
+
+    /* Erase the chip. */
+    chip_erase();
+    /* Read toggle. */
+    uint16_t status0 = flash_read(0);
+    /* DQ7 is 0 during an erase. */
+    g_assert_cmphex(status0 & 0x80, ==, 0);
+    uint16_t status1 = flash_read(0);
+    /* DQ6 toggles during an erase. */
+    g_assert_cmphex(status0 & 0x40, !=, status1 & 0x40);
+    /* Wait for erase to complete. */
+    clock_step_next();
+    /* Ensure DQ6 has stopped toggling. */
+    g_assert_cmphex(flash_read(0), ==, flash_read(0));
+    /* Now the data should be valid. */
+    g_assert_cmphex(flash_read(0), ==, 0xFFFF);
+
+    /* Unlock bypass */
+    unlock();
+    flash_write(UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
+    bypass_program(0, 0x0123);
+    bypass_program(2, 0x4567);
+    bypass_program(4, 0x89AB);
+    /*
+     * Test that bypass programming, unlike normal programming can use any
+     * address for the PROGRAM_CMD.
+     */
+    flash_write(6, PROGRAM_CMD);
+    flash_write(6, 0xCDEF);
+    wait_for_completion(6);
+    flash_write(0, UNLOCK_BYPASS_RESET_CMD);
+    bypass_program(8, 0x55AA); /* Should fail. */
+    g_assert_cmphex(flash_read(0), ==, 0x0123);
+    g_assert_cmphex(flash_read(2), ==, 0x4567);
+    g_assert_cmphex(flash_read(4), ==, 0x89AB);
+    g_assert_cmphex(flash_read(6), ==, 0xCDEF);
+    g_assert_cmphex(flash_read(8), ==, 0xFFFF);
+
+    qtest_quit(global_qtest);
+}
+
+static void cleanup(void *opaque)
+{
+    unlink(image_path);
+}
+
+int main(int argc, char **argv)
+{
+    int fd = mkstemp(image_path);
+    if (fd == -1) {
+        g_printerr("Failed to create temporary file %s: %s\n", image_path,
+                   strerror(errno));
+        exit(EXIT_FAILURE);
+    }
+    if (ftruncate(fd, 8 * 1024 * 1024) < 0) {
+        int error_code = errno;
+        close(fd);
+        unlink(image_path);
+        g_printerr("Failed to truncate file %s to 8 MB: %s\n", image_path,
+                   strerror(error_code));
+        exit(EXIT_FAILURE);
+    }
+    close(fd);
+
+    qtest_add_abrt_handler(cleanup, NULL);
+    g_test_init(&argc, &argv, NULL);
+    qtest_add_func("pflash-cfi02", test_flash);
+    int result = g_test_run();
+    cleanup(NULL);
+    return result;
+}
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write()
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 01/28] tests/pflash-cfi02: Add test for supported CFI commands Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-27 21:49   ` Stephen Checkoway
  2019-06-28 15:52   ` Alistair Francis
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 03/28] hw/block/pflash: Simplify trace_pflash_data_read/write() Philippe Mathieu-Daudé
                   ` (25 subsequent siblings)
  27 siblings, 2 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Call the read() trace function after the value is set, so we can
log the returned value.
Rename the I/O trace functions with '_io_' in their name.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi01.c | 5 +++--
 hw/block/pflash_cfi02.c | 6 ++----
 hw/block/trace-events   | 4 ++--
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 35080d915f..74fc1bc2da 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -288,7 +288,6 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
     uint32_t ret;
 
     ret = -1;
-    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
     switch (pfl->cmd) {
     default:
         /* This should never happen : reset state & treat it as a read */
@@ -391,6 +390,8 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
 
         break;
     }
+    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
+
     return ret;
 }
 
@@ -453,7 +454,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
 
     cmd = value;
 
-    trace_pflash_write(offset, value, width, pfl->wcycle);
+    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     if (!pfl->wcycle) {
         /* Set the device in I/O access mode */
         memory_region_rom_device_set_romd(&pfl->mem, false);
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index eb106f4996..f05cd507b3 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -145,7 +145,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
     uint8_t *p;
 
     ret = -1;
-    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
     /* 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) {
@@ -241,6 +240,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
         }
         break;
     }
+    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
 
     return ret;
 }
@@ -267,6 +267,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
     uint8_t *p;
     uint8_t cmd;
 
+    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     cmd = value;
     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
 #if 0
@@ -275,11 +276,8 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
 #endif
         goto reset_flash;
     }
-    trace_pflash_write(offset, value, width, pfl->wcycle);
     offset &= pfl->chip_len - 1;
 
-    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
-            offset, value, width);
     boff = offset & (pfl->sector_len - 1);
     if (pfl->width == 2)
         boff = boff >> 1;
diff --git a/hw/block/trace-events b/hw/block/trace-events
index 97a17838ed..f637fe918e 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -7,9 +7,9 @@ fdc_ioport_write(uint8_t reg, uint8_t value) "write reg 0x%02x val 0x%02x"
 # pflash_cfi02.c
 # pflash_cfi01.c
 pflash_reset(void) "reset"
-pflash_read(uint64_t offset, uint8_t cmd, int width, uint8_t wcycle) "offset:0x%04"PRIx64" cmd:0x%02x width:%d wcycle:%u"
-pflash_write(uint64_t offset, uint32_t value, int width, uint8_t wcycle) "offset:0x%04"PRIx64" value:0x%03x width:%d wcycle:%u"
 pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
+pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
+pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
 pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
 pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
 pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 03/28] hw/block/pflash: Simplify trace_pflash_data_read/write()
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 01/28] tests/pflash-cfi02: Add test for supported CFI commands Philippe Mathieu-Daudé
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write() Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-28 15:54   ` Alistair Francis
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 04/28] hw/block/pflash_cfi02: Fix debug format string Philippe Mathieu-Daudé
                   ` (24 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Use a field width format to have a single function to log
the different width accesses.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi01.c | 6 ++----
 hw/block/pflash_cfi02.c | 6 ++----
 hw/block/trace-events   | 6 ++----
 3 files changed, 6 insertions(+), 12 deletions(-)

diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 74fc1bc2da..db4a246b22 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -248,7 +248,6 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
     switch (width) {
     case 1:
         ret = p[offset];
-        trace_pflash_data_read8(offset, ret);
         break;
     case 2:
         if (be) {
@@ -258,7 +257,6 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
             ret = p[offset];
             ret |= p[offset + 1] << 8;
         }
-        trace_pflash_data_read16(offset, ret);
         break;
     case 4:
         if (be) {
@@ -272,12 +270,12 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
             ret |= p[offset + 2] << 16;
             ret |= p[offset + 3] << 24;
         }
-        trace_pflash_data_read32(offset, ret);
         break;
     default:
         DPRINTF("BUG in %s\n", __func__);
         abort();
     }
+    trace_pflash_data_read(offset, width << 1, ret);
     return ret;
 }
 
@@ -415,7 +413,7 @@ static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
 {
     uint8_t *p = pfl->storage;
 
-    trace_pflash_data_write(offset, value, width, pfl->counter);
+    trace_pflash_data_write(offset, width << 1, value, pfl->counter);
     switch (width) {
     case 1:
         p[offset] = value;
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index f05cd507b3..6cdfc85264 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -172,7 +172,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
         switch (width) {
         case 1:
             ret = p[offset];
-            trace_pflash_data_read8(offset, ret);
             break;
         case 2:
             if (be) {
@@ -182,7 +181,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
                 ret = p[offset];
                 ret |= p[offset + 1] << 8;
             }
-            trace_pflash_data_read16(offset, ret);
             break;
         case 4:
             if (be) {
@@ -196,9 +194,9 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
                 ret |= p[offset + 2] << 16;
                 ret |= p[offset + 3] << 24;
             }
-            trace_pflash_data_read32(offset, ret);
             break;
         }
+        trace_pflash_data_read(offset, width << 1, ret);
         break;
     case 0x90:
         /* flash ID read */
@@ -343,7 +341,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
             /* We need another unlock sequence */
             goto check_unlock0;
         case 0xA0:
-            trace_pflash_data_write(offset, value, width, 0);
+            trace_pflash_data_write(offset, width << 1, value, 0);
             p = pfl->storage;
             if (!pfl->ro) {
                 switch (width) {
diff --git a/hw/block/trace-events b/hw/block/trace-events
index f637fe918e..13d1b21dd4 100644
--- a/hw/block/trace-events
+++ b/hw/block/trace-events
@@ -10,10 +10,8 @@ pflash_reset(void) "reset"
 pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
 pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
 pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
-pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
-pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
-pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
-pflash_data_write(uint64_t offset, uint32_t value, int width, uint64_t counter) "data offset:0x%04"PRIx64" value:0x%08x width:%d counter:0x%016"PRIx64
+pflash_data_read(uint64_t offset, int width, uint32_t value) "data offset:0x%04"PRIx64" value:0x%0*x"
+pflash_data_write(uint64_t offset, int width, uint32_t value, uint64_t counter) "data offset:0x%04"PRIx64" value:0x%0*x counter:0x%016"PRIx64
 pflash_manufacturer_id(uint16_t id) "Read Manufacturer ID: 0x%04x"
 pflash_device_id(uint16_t id) "Read Device ID: 0x%04x"
 pflash_device_info(uint64_t offset) "Read Device Information offset:0x%04"PRIx64
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 04/28] hw/block/pflash_cfi02: Fix debug format string
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (2 preceding siblings ...)
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 03/28] hw/block/pflash: Simplify trace_pflash_data_read/write() Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-28 15:55   ` Alistair Francis
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 05/28] hw/block/pflash_cfi02: Add an enum to define the write cycles Philippe Mathieu-Daudé
                   ` (23 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Always compile the debug code to prevent format string to bitrot.
Delete dead code.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch, use PRIx32]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 6cdfc85264..43796e551a 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -47,15 +47,13 @@
 #include "hw/sysbus.h"
 #include "trace.h"
 
-//#define PFLASH_DEBUG
-#ifdef PFLASH_DEBUG
+#define PFLASH_DEBUG false
 #define DPRINTF(fmt, ...)                                  \
 do {                                                       \
-    fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__);       \
+    if (PFLASH_DEBUG) {                                    \
+        fprintf(stderr, "PFLASH: " fmt, ## __VA_ARGS__);   \
+    }                                                      \
 } while (0)
-#else
-#define DPRINTF(fmt, ...) do { } while (0)
-#endif
 
 #define PFLASH_LAZY_ROMD_THRESHOLD 42
 
@@ -218,14 +216,14 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
         default:
             goto flash_read;
         }
-        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
+        DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx32 "\n", __func__, boff, ret);
         break;
     case 0xA0:
     case 0x10:
     case 0x30:
         /* Status register read */
         ret = pfl->status;
-        DPRINTF("%s: status %x\n", __func__, ret);
+        DPRINTF("%s: status %" PRIx32 "\n", __func__, ret);
         /* Toggle bit 6 */
         pfl->status ^= 0x40;
         break;
@@ -268,10 +266,6 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
     trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     cmd = value;
     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-#if 0
-        DPRINTF("%s: flash reset asked (%02x %02x)\n",
-                __func__, pfl->cmd, cmd);
-#endif
         goto reset_flash;
     }
     offset &= pfl->chip_len - 1;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 05/28] hw/block/pflash_cfi02: Add an enum to define the write cycles
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (3 preceding siblings ...)
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 04/28] hw/block/pflash_cfi02: Fix debug format string Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-28 15:56   ` Alistair Francis
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 06/28] hw/block/pflash_cfi02: Add helpers to manipulate the status bits Philippe Mathieu-Daudé
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

No change in functionality is intended with this commit.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 43796e551a..303d225f23 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -57,6 +57,11 @@ do {                                                       \
 
 #define PFLASH_LAZY_ROMD_THRESHOLD 42
 
+/* Special write cycles for CFI queries. */
+enum {
+    WCYCLE_CFI              = 7,
+};
+
 struct PFlashCFI02 {
     /*< private >*/
     SysBusDevice parent_obj;
@@ -286,7 +291,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
         if (boff == 0x55 && cmd == 0x98) {
         enter_CFI_mode:
             /* Enter CFI query mode */
-            pfl->wcycle = 7;
+            pfl->wcycle = WCYCLE_CFI;
             pfl->cmd = 0x98;
             return;
         }
@@ -458,7 +463,8 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
             goto reset_flash;
         }
         break;
-    case 7: /* Special value for CFI queries */
+    /* Special values for CFI queries */
+    case WCYCLE_CFI:
         DPRINTF("%s: invalid write in CFI query mode\n", __func__);
         goto reset_flash;
     default:
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 06/28] hw/block/pflash_cfi02: Add helpers to manipulate the status bits
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (4 preceding siblings ...)
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 05/28] hw/block/pflash_cfi02: Add an enum to define the write cycles Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-28 16:00   ` Alistair Francis
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 07/28] hw/block/pflash_cfi02: Simplify a statement using fall through Philippe Mathieu-Daudé
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Pull out all of the code to modify the status into simple helper
functions. Status handling becomes more complex once multiple
chips are interleaved to produce a single device.

No change in functionality is intended with this commit.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 40 ++++++++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 303d225f23..e9eea0ec08 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -101,6 +101,31 @@ struct PFlashCFI02 {
     void *storage;
 };
 
+/*
+ * Toggle status bit DQ7.
+ */
+static inline void toggle_dq7(PFlashCFI02 *pfl)
+{
+    pfl->status ^= 0x80;
+}
+
+/*
+ * Set status bit DQ7 to bit 7 of value.
+ */
+static inline void set_dq7(PFlashCFI02 *pfl, uint8_t value)
+{
+    pfl->status &= 0x7F;
+    pfl->status |= value & 0x80;
+}
+
+/*
+ * Toggle status bit DQ6.
+ */
+static inline void toggle_dq6(PFlashCFI02 *pfl)
+{
+    pfl->status ^= 0x40;
+}
+
 /*
  * Set up replicated mappings of the same region.
  */
@@ -130,7 +155,7 @@ static void pflash_timer (void *opaque)
 
     trace_pflash_timer_expired(pfl->cmd);
     /* Reset flash */
-    pfl->status ^= 0x80;
+    toggle_dq7(pfl);
     if (pfl->bypass) {
         pfl->wcycle = 2;
     } else {
@@ -229,8 +254,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
         /* Status register read */
         ret = pfl->status;
         DPRINTF("%s: status %" PRIx32 "\n", __func__, ret);
-        /* Toggle bit 6 */
-        pfl->status ^= 0x40;
+        toggle_dq6(pfl);
         break;
     case 0x98:
         /* CFI query mode */
@@ -374,7 +398,11 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
                     break;
                 }
             }
-            pfl->status = 0x00 | ~(value & 0x80);
+            /*
+             * While programming, status bit DQ7 should hold the opposite
+             * value from how it was programmed.
+             */
+            set_dq7(pfl, ~value);
             /* Let's pretend write is immediate */
             if (pfl->bypass)
                 goto do_bypass;
@@ -422,7 +450,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
                 memset(pfl->storage, 0xFF, pfl->chip_len);
                 pflash_update(pfl, 0, pfl->chip_len);
             }
-            pfl->status = 0x00;
+            set_dq7(pfl, 0x00);
             /* Let's wait 5 seconds before chip erase is done */
             timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
                       (NANOSECONDS_PER_SECOND * 5));
@@ -437,7 +465,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
                 memset(p + offset, 0xFF, pfl->sector_len);
                 pflash_update(pfl, offset, pfl->sector_len);
             }
-            pfl->status = 0x00;
+            set_dq7(pfl, 0x00);
             /* Let's wait 1/2 second before sector erase is done */
             timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
                       (NANOSECONDS_PER_SECOND / 2));
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 07/28] hw/block/pflash_cfi02: Simplify a statement using fall through
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (5 preceding siblings ...)
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 06/28] hw/block/pflash_cfi02: Add helpers to manipulate the status bits Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-28 16:01   ` Alistair Francis
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 08/28] hw/block/pflash_cfi02: Use the ldst API in pflash_write() Philippe Mathieu-Daudé
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index e9eea0ec08..9e8c28af8f 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -239,10 +239,10 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
         case 0x0E:
         case 0x0F:
             ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
-            if (ret == (uint8_t)-1) {
-                goto flash_read;
+            if (ret != (uint8_t)-1) {
+                break;
             }
-            break;
+            /* Fall through to data read. */
         default:
             goto flash_read;
         }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 08/28] hw/block/pflash_cfi02: Use the ldst API in pflash_write()
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (6 preceding siblings ...)
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 07/28] hw/block/pflash_cfi02: Simplify a statement using fall through Philippe Mathieu-Daudé
@ 2019-06-27 20:26 ` Philippe Mathieu-Daudé
  2019-06-28 16:03   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 09/28] hw/block/pflash_cfi02: Use the ldst API in pflash_read() Philippe Mathieu-Daudé
                   ` (19 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:26 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

The load/store API eases code review.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 38 ++++++++------------------------------
 1 file changed, 8 insertions(+), 30 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 9e8c28af8f..ae38ed0bae 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -365,38 +365,16 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
             goto check_unlock0;
         case 0xA0:
             trace_pflash_data_write(offset, width << 1, value, 0);
-            p = pfl->storage;
             if (!pfl->ro) {
-                switch (width) {
-                case 1:
-                    p[offset] &= value;
-                    pflash_update(pfl, offset, 1);
-                    break;
-                case 2:
-                    if (be) {
-                        p[offset] &= value >> 8;
-                        p[offset + 1] &= value;
-                    } else {
-                        p[offset] &= value;
-                        p[offset + 1] &= value >> 8;
-                    }
-                    pflash_update(pfl, offset, 2);
-                    break;
-                case 4:
-                    if (be) {
-                        p[offset] &= value >> 24;
-                        p[offset + 1] &= value >> 16;
-                        p[offset + 2] &= value >> 8;
-                        p[offset + 3] &= value;
-                    } else {
-                        p[offset] &= value;
-                        p[offset + 1] &= value >> 8;
-                        p[offset + 2] &= value >> 16;
-                        p[offset + 3] &= value >> 24;
-                    }
-                    pflash_update(pfl, offset, 4);
-                    break;
+                p = (uint8_t *)pfl->storage + offset;
+                if (pfl->be) {
+                    uint64_t current = ldn_be_p(p, width);
+                    stn_be_p(p, width, current & value);
+                } else {
+                    uint64_t current = ldn_le_p(p, width);
+                    stn_le_p(p, width, current & value);
                 }
+                pflash_update(pfl, offset, width);
             }
             /*
              * While programming, status bit DQ7 should hold the opposite
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 09/28] hw/block/pflash_cfi02: Use the ldst API in pflash_read()
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (7 preceding siblings ...)
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 08/28] hw/block/pflash_cfi02: Use the ldst API in pflash_write() Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:03   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 10/28] hw/block/pflash_cfi02: Extract the pflash_data_read() function Philippe Mathieu-Daudé
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

The load/store API eases code review.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch, simplified tracing]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 32 +++++---------------------------
 1 file changed, 5 insertions(+), 27 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index ae38ed0bae..49afecb921 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -196,33 +196,11 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
     case 0x00:
     flash_read:
         /* Flash area read */
-        p = pfl->storage;
-        switch (width) {
-        case 1:
-            ret = p[offset];
-            break;
-        case 2:
-            if (be) {
-                ret = p[offset] << 8;
-                ret |= p[offset + 1];
-            } else {
-                ret = p[offset];
-                ret |= p[offset + 1] << 8;
-            }
-            break;
-        case 4:
-            if (be) {
-                ret = p[offset] << 24;
-                ret |= p[offset + 1] << 16;
-                ret |= p[offset + 2] << 8;
-                ret |= p[offset + 3];
-            } else {
-                ret = p[offset];
-                ret |= p[offset + 1] << 8;
-                ret |= p[offset + 2] << 16;
-                ret |= p[offset + 3] << 24;
-            }
-            break;
+        p = (uint8_t *)pfl->storage + offset;
+        if (pfl->be) {
+            ret = ldn_be_p(p, width);
+        } else {
+            ret = ldn_le_p(p, width);
         }
         trace_pflash_data_read(offset, width << 1, ret);
         break;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 10/28] hw/block/pflash_cfi02: Extract the pflash_data_read() function
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (8 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 09/28] hw/block/pflash_cfi02: Use the ldst API in pflash_read() Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:17   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 11/28] hw/block/pflash_cfi02: Unify the MemoryRegionOps Philippe Mathieu-Daudé
                   ` (17 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Extract the code block in a new function, remove a goto statement.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch, remove the XXX tracing comment]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 49afecb921..c079a63880 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -165,12 +165,23 @@ static void pflash_timer (void *opaque)
     pfl->cmd = 0;
 }
 
+/*
+ * Read data from flash.
+ */
+static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
+                                 unsigned int width)
+{
+    uint8_t *p = (uint8_t *)pfl->storage + offset;
+    uint64_t ret = pfl->be ? ldn_be_p(p, width) : ldn_le_p(p, width);
+    trace_pflash_data_read(offset, width << 1, ret);
+    return ret;
+}
+
 static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
                             int width, int be)
 {
     hwaddr boff;
     uint32_t ret;
-    uint8_t *p;
 
     ret = -1;
     /* Lazy reset to ROMD mode after a certain amount of read accesses */
@@ -194,15 +205,8 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
     case 0x80:
         /* We accept reads during second unlock sequence... */
     case 0x00:
-    flash_read:
         /* Flash area read */
-        p = (uint8_t *)pfl->storage + offset;
-        if (pfl->be) {
-            ret = ldn_be_p(p, width);
-        } else {
-            ret = ldn_le_p(p, width);
-        }
-        trace_pflash_data_read(offset, width << 1, ret);
+        ret = pflash_data_read(pfl, offset, width);
         break;
     case 0x90:
         /* flash ID read */
@@ -222,7 +226,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
             }
             /* Fall through to data read. */
         default:
-            goto flash_read;
+            ret = pflash_data_read(pfl, offset, width);
         }
         DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx32 "\n", __func__, boff, ret);
         break;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 11/28] hw/block/pflash_cfi02: Unify the MemoryRegionOps
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (9 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 10/28] hw/block/pflash_cfi02: Extract the pflash_data_read() function Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:25   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 12/28] hw/block/pflash_cfi02: Fix command address comparison Philippe Mathieu-Daudé
                   ` (16 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

The pflash_read()/pflash_write() can check the device endianess
via the pfl->be variable, so remove the 'int be' argument.

Since the big/little MemoryRegionOps are now identical, it is
pointless to declare them both. Unify them.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
[PMD: Extracted from bigger patch to ease review]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 60 +++++++++++------------------------------
 1 file changed, 15 insertions(+), 45 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index c079a63880..e64dc69c6c 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -177,11 +177,11 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
     return ret;
 }
 
-static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
-                            int width, int be)
+static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
 {
+    PFlashCFI02 *pfl = opaque;
     hwaddr boff;
-    uint32_t ret;
+    uint64_t ret;
 
     ret = -1;
     /* Lazy reset to ROMD mode after a certain amount of read accesses */
@@ -228,14 +228,14 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
         default:
             ret = pflash_data_read(pfl, offset, width);
         }
-        DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx32 "\n", __func__, boff, ret);
+        DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx64 "\n", __func__, boff, ret);
         break;
     case 0xA0:
     case 0x10:
     case 0x30:
         /* Status register read */
         ret = pfl->status;
-        DPRINTF("%s: status %" PRIx32 "\n", __func__, ret);
+        DPRINTF("%s: status %" PRIx64 "\n", __func__, ret);
         toggle_dq6(pfl);
         break;
     case 0x98:
@@ -253,8 +253,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
 }
 
 /* update flash content on disk */
-static void pflash_update(PFlashCFI02 *pfl, int offset,
-                          int size)
+static void pflash_update(PFlashCFI02 *pfl, int offset, int size)
 {
     int offset_end;
     if (pfl->blk) {
@@ -267,9 +266,10 @@ static void pflash_update(PFlashCFI02 *pfl, int offset,
     }
 }
 
-static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
-                         uint32_t value, int width, int be)
+static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
+                         unsigned int width)
 {
+    PFlashCFI02 *pfl = opaque;
     hwaddr boff;
     uint8_t *p;
     uint8_t cmd;
@@ -477,39 +477,9 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
     pfl->cmd = 0;
 }
 
-static uint64_t pflash_be_readfn(void *opaque, hwaddr addr, unsigned size)
-{
-    return pflash_read(opaque, addr, size, 1);
-}
-
-static void pflash_be_writefn(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    pflash_write(opaque, addr, value, size, 1);
-}
-
-static uint64_t pflash_le_readfn(void *opaque, hwaddr addr, unsigned size)
-{
-    return pflash_read(opaque, addr, size, 0);
-}
-
-static void pflash_le_writefn(void *opaque, hwaddr addr,
-                              uint64_t value, unsigned size)
-{
-    pflash_write(opaque, addr, value, size, 0);
-}
-
-static const MemoryRegionOps pflash_cfi02_ops_be = {
-    .read = pflash_be_readfn,
-    .write = pflash_be_writefn,
-    .valid.min_access_size = 1,
-    .valid.max_access_size = 4,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const MemoryRegionOps pflash_cfi02_ops_le = {
-    .read = pflash_le_readfn,
-    .write = pflash_le_writefn,
+static const MemoryRegionOps pflash_cfi02_ops = {
+    .read = pflash_read,
+    .write = pflash_write,
     .valid.min_access_size = 1,
     .valid.max_access_size = 4,
     .endianness = DEVICE_NATIVE_ENDIAN,
@@ -537,9 +507,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 
     chip_len = pfl->sector_len * pfl->nb_blocs;
 
-    memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), pfl->be ?
-                                  &pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
-                                  pfl, pfl->name, chip_len, &local_err);
+    memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
+                                  &pflash_cfi02_ops, pfl, pfl->name,
+                                  chip_len, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 12/28] hw/block/pflash_cfi02: Fix command address comparison
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (10 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 11/28] hw/block/pflash_cfi02: Unify the MemoryRegionOps Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:28   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 13/28] tests/pflash-cfi02: Refactor to support testing multiple configurations Philippe Mathieu-Daudé
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

Most AMD commands only examine 11 bits of the address. This masks the
addresses used in the comparison to 11 bits. The exceptions are word or
sector addresses which use offset directly rather than the shifted
offset, boff.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20190426162624.55977-4-stephen.checkoway@oberlin.edu>
[PMD: Prepend 'hw/' in patch subject]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c   |  8 +++++++-
 tests/pflash-cfi02-test.c | 12 ++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index e64dc69c6c..4be3837be5 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -281,11 +281,13 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     }
     offset &= pfl->chip_len - 1;
 
-    boff = offset & (pfl->sector_len - 1);
+    boff = offset;
     if (pfl->width == 2)
         boff = boff >> 1;
     else if (pfl->width == 4)
         boff = boff >> 2;
+    /* Only the least-significant 11 bits are used in most cases. */
+    boff &= 0x7FF;
     switch (pfl->wcycle) {
     case 0:
         /* Set the device in I/O access mode if required */
@@ -538,6 +540,10 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
         }
     }
 
+    /* Only 11 bits are used in the comparison. */
+    pfl->unlock_addr0 &= 0x7FF;
+    pfl->unlock_addr1 &= 0x7FF;
+
     pflash_setup_mappings(pfl);
     pfl->rom_mode = 1;
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index e7e16a8dd8..e090b2e3a0 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -21,8 +21,8 @@
 
 #define FLASH_WIDTH 2
 #define CFI_ADDR (FLASH_WIDTH * 0x55)
-#define UNLOCK0_ADDR (FLASH_WIDTH * 0x5555)
-#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AAA)
+#define UNLOCK0_ADDR (FLASH_WIDTH * 0x555)
+#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AA)
 
 #define CFI_CMD 0x98
 #define UNLOCK0_CMD 0xAA
@@ -190,6 +190,14 @@ static void test_flash(void)
     g_assert_cmphex(flash_read(6), ==, 0xCDEF);
     g_assert_cmphex(flash_read(8), ==, 0xFFFF);
 
+    /* Test ignored high order bits of address. */
+    flash_write(FLASH_WIDTH * 0x5555, UNLOCK0_CMD);
+    flash_write(FLASH_WIDTH * 0x2AAA, UNLOCK1_CMD);
+    flash_write(FLASH_WIDTH * 0x5555, AUTOSELECT_CMD);
+    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
+    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
+    reset();
+
     qtest_quit(global_qtest);
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 13/28] tests/pflash-cfi02: Refactor to support testing multiple configurations
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (11 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 12/28] hw/block/pflash_cfi02: Fix command address comparison Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:41   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 14/28] hw/block/pflash_cfi02: Remove pointless local variable Philippe Mathieu-Daudé
                   ` (14 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Introduce the FlashConfig structure, to be able to run the same set
of tests on different flash models/configurations.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 tests/pflash-cfi02-test.c | 386 +++++++++++++++++++++++++++-----------
 1 file changed, 277 insertions(+), 109 deletions(-)

diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index e090b2e3a0..b00f5ca2e7 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -17,12 +17,18 @@
  */
 
 #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
+#define FLASH_SIZE (8 * 1024 * 1024)
 #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
 
-#define FLASH_WIDTH 2
-#define CFI_ADDR (FLASH_WIDTH * 0x55)
-#define UNLOCK0_ADDR (FLASH_WIDTH * 0x555)
-#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AA)
+/* Use a newtype to keep flash addresses separate from byte addresses. */
+typedef struct {
+    uint64_t addr;
+} faddr;
+#define FLASH_ADDR(x) ((faddr) { .addr = (x) })
+
+#define CFI_ADDR FLASH_ADDR(0x55)
+#define UNLOCK0_ADDR FLASH_ADDR(0x555)
+#define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
 
 #define CFI_CMD 0x98
 #define UNLOCK0_CMD 0xAA
@@ -35,170 +41,313 @@
 #define UNLOCK_BYPASS_CMD 0x20
 #define UNLOCK_BYPASS_RESET_CMD 0x00
 
+typedef struct {
+    int bank_width;
+
+    QTestState *qtest;
+} FlashConfig;
+
 static char image_path[] = "/tmp/qtest.XXXXXX";
 
-static inline void flash_write(uint64_t byte_addr, uint16_t data)
+/*
+ * The pflash implementation allows some parameters to be unspecified. We want
+ * to test those configurations but we also need to know the real values in
+ * our testing code. So after we launch qemu, we'll need a new FlashConfig
+ * with the correct values filled in.
+ */
+static FlashConfig expand_config_defaults(const FlashConfig *c)
 {
-    qtest_writew(global_qtest, BASE_ADDR + byte_addr, data);
+    FlashConfig ret = *c;
+
+    if (ret.bank_width == 0) {
+        ret.bank_width = 2;
+    }
+
+    /* XXX: Limitations of test harness. */
+    assert(ret.bank_width == 2);
+    return ret;
 }
 
-static inline uint16_t flash_read(uint64_t byte_addr)
+/*
+ * Return a bit mask suitable for extracting the least significant
+ * status/query response from an interleaved response.
+ */
+static inline uint64_t device_mask(const FlashConfig *c)
 {
-    return qtest_readw(global_qtest, BASE_ADDR + byte_addr);
+    return (uint64_t)-1;
 }
 
-static void unlock(void)
+/*
+ * Return a bit mask exactly as long as the bank_width.
+ */
+static inline uint64_t bank_mask(const FlashConfig *c)
 {
-    flash_write(UNLOCK0_ADDR, UNLOCK0_CMD);
-    flash_write(UNLOCK1_ADDR, UNLOCK1_CMD);
+    if (c->bank_width == 8) {
+        return (uint64_t)-1;
+    }
+    return (1ULL << (c->bank_width * 8)) - 1ULL;
 }
 
-static void reset(void)
+static inline void flash_write(const FlashConfig *c, uint64_t byte_addr,
+                               uint64_t data)
 {
-    flash_write(0, RESET_CMD);
-}
-
-static void sector_erase(uint64_t byte_addr)
-{
-    unlock();
-    flash_write(UNLOCK0_ADDR, 0x80);
-    unlock();
-    flash_write(byte_addr, SECTOR_ERASE_CMD);
-}
-
-static void wait_for_completion(uint64_t byte_addr)
-{
-    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
-    if ((flash_read(byte_addr) & 0x40) ^ (flash_read(byte_addr) & 0x40)) {
-        /* Wait for erase or program to finish. */
-        clock_step_next();
-        /* Ensure that DQ6 has stopped toggling. */
-        g_assert_cmphex(flash_read(byte_addr), ==, flash_read(byte_addr));
+    /* Sanity check our tests. */
+    assert((data & ~bank_mask(c)) == 0);
+    uint64_t addr = BASE_ADDR + byte_addr;
+    switch (c->bank_width) {
+    case 1:
+        qtest_writeb(c->qtest, addr, data);
+        break;
+    case 2:
+        qtest_writew(c->qtest, addr, data);
+        break;
+    case 4:
+        qtest_writel(c->qtest, addr, data);
+        break;
+    case 8:
+        qtest_writeq(c->qtest, addr, data);
+        break;
+    default:
+        abort();
     }
 }
 
-static void bypass_program(uint64_t byte_addr, uint16_t data)
+static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr)
 {
-    flash_write(UNLOCK0_ADDR, PROGRAM_CMD);
-    flash_write(byte_addr, data);
+    uint64_t addr = BASE_ADDR + byte_addr;
+    switch (c->bank_width) {
+    case 1:
+        return qtest_readb(c->qtest, addr);
+    case 2:
+        return qtest_readw(c->qtest, addr);
+    case 4:
+        return qtest_readl(c->qtest, addr);
+    case 8:
+        return qtest_readq(c->qtest, addr);
+    default:
+        abort();
+    }
+}
+
+/*
+ * Convert a flash address expressed in the maximum width of the device as a
+ * byte address.
+ */
+static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr)
+{
+    /*
+     * Command addresses are always given as addresses in the maximum
+     * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
+     * uses addresses 0xAAA and 0x555 to unlock because the least significant
+     * bit is ignored. (0x555 rather than 0x554 is traditional.)
+     *
+     * In general we need to multiply by the maximum device width.
+     */
+    return flash_addr.addr * c->bank_width;
+}
+
+/*
+ * Return the command value or expected status replicated across all devices.
+ */
+static inline uint64_t replicate(const FlashConfig *c, uint64_t data)
+{
+    /* Sanity check our tests. */
+    assert((data & ~device_mask(c)) == 0);
+    return data;
+}
+
+static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr,
+                             uint8_t cmd)
+{
+    flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd));
+}
+
+static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr)
+{
+    return flash_read(c, as_byte_addr(c, query_addr));
+}
+
+static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr)
+{
+    return flash_query(c, query_addr) & device_mask(c);
+}
+
+static void unlock(const FlashConfig *c)
+{
+    flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD);
+    flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD);
+}
+
+static void reset(const FlashConfig *c)
+{
+    flash_cmd(c, FLASH_ADDR(0), RESET_CMD);
+}
+
+static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
+{
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, 0x80);
+    unlock(c);
+    flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
+}
+
+static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr)
+{
+    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
+    const uint64_t dq6 = replicate(c, 0x40);
+    if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) {
+        /* Wait for erase or program to finish. */
+        qtest_clock_step_next(c->qtest);
+        /* Ensure that DQ6 has stopped toggling. */
+        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+    }
+}
+
+static void bypass_program(const FlashConfig *c, uint64_t byte_addr,
+                           uint16_t data)
+{
+    flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD);
+    flash_write(c, byte_addr, data);
     /*
      * Data isn't valid until DQ6 stops toggling. We don't model this as
      * writes are immediate, but if this changes in the future, we can wait
      * until the program is complete.
      */
-    wait_for_completion(byte_addr);
+    wait_for_completion(c, byte_addr);
 }
 
-static void program(uint64_t byte_addr, uint16_t data)
+static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
 {
-    unlock();
-    bypass_program(byte_addr, data);
+    unlock(c);
+    bypass_program(c, byte_addr, data);
 }
 
-static void chip_erase(void)
+static void chip_erase(const FlashConfig *c)
 {
-    unlock();
-    flash_write(UNLOCK0_ADDR, 0x80);
-    unlock();
-    flash_write(UNLOCK0_ADDR, SECTOR_ERASE_CMD);
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, 0x80);
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
 }
 
-static void test_flash(void)
+static void test_flash(const void *opaque)
 {
-    global_qtest = qtest_initf("-M musicpal,accel=qtest "
-                               "-drive if=pflash,file=%s,format=raw,copy-on-read",
-                               image_path);
+    const FlashConfig *config = opaque;
+    QTestState *qtest;
+    qtest = qtest_initf("-M musicpal,accel=qtest"
+                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
+                        image_path);
+    FlashConfig explicit_config = expand_config_defaults(config);
+    explicit_config.qtest = qtest;
+    const FlashConfig *c = &explicit_config;
+
     /* Check the IDs. */
-    unlock();
-    flash_write(UNLOCK0_ADDR, AUTOSELECT_CMD);
-    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
-    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
-    reset();
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+    if (c->bank_width >= 2) {
+        /*
+         * XXX: The ID returned by the musicpal flash chip is 16 bits which
+         * wouldn't happen with an 8-bit device. It would probably be best to
+         * prohibit addresses larger than the device width in pflash_cfi02.c,
+         * but then we couldn't test smaller device widths at all.
+         */
+        g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==,
+                        replicate(c, 0x236D));
+    }
+    reset(c);
 
     /* Check the erase blocks. */
-    flash_write(CFI_ADDR, CFI_CMD);
-    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x10), ==, 'Q');
-    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x11), ==, 'R');
-    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x12), ==, 'Y');
-    /* Num erase regions. */
-    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x2C), >=, 1);
-    uint32_t nb_sectors = flash_read(FLASH_WIDTH * 0x2D) +
-                          (flash_read(FLASH_WIDTH * 0x2E) << 8) + 1;
-    uint32_t sector_len = (flash_read(FLASH_WIDTH * 0x2F) << 8) +
-                          (flash_read(FLASH_WIDTH * 0x30) << 16);
-    reset();
+    flash_cmd(c, CFI_ADDR, CFI_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
 
+    /* Num erase regions. */
+    g_assert_cmphex(flash_query_1(c, FLASH_ADDR(0x2C)), >=, 1);
+
+    uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(0x2D)) +
+                          (flash_query_1(c, FLASH_ADDR(0x2E)) << 8) + 1;
+    uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(0x2F)) << 8) +
+                          (flash_query_1(c, FLASH_ADDR(0x30)) << 16);
+    reset(c);
+
+    const uint64_t dq7 = replicate(c, 0x80);
+    const uint64_t dq6 = replicate(c, 0x40);
     /* Erase and program sector. */
     for (uint32_t i = 0; i < nb_sectors; ++i) {
         uint64_t byte_addr = i * sector_len;
-        sector_erase(byte_addr);
+        sector_erase(c, byte_addr);
         /* Read toggle. */
-        uint16_t status0 = flash_read(byte_addr);
+        uint64_t status0 = flash_read(c, byte_addr);
         /* DQ7 is 0 during an erase. */
-        g_assert_cmphex(status0 & 0x80, ==, 0);
-        uint16_t status1 = flash_read(byte_addr);
+        g_assert_cmphex(status0 & dq7, ==, 0);
+        uint64_t status1 = flash_read(c, byte_addr);
         /* DQ6 toggles during an erase. */
-        g_assert_cmphex(status0 & 0x40, !=, status1 & 0x40);
+        g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
         /* Wait for erase to complete. */
-        clock_step_next();
+        qtest_clock_step_next(c->qtest);
         /* Ensure DQ6 has stopped toggling. */
-        g_assert_cmphex(flash_read(byte_addr), ==, flash_read(byte_addr));
+        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
         /* Now the data should be valid. */
-        g_assert_cmphex(flash_read(byte_addr), ==, 0xFFFF);
+        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
 
         /* Program a bit pattern. */
-        program(byte_addr, 0x5555);
-        g_assert_cmphex(flash_read(byte_addr), ==, 0x5555);
-        program(byte_addr, 0xAA55);
-        g_assert_cmphex(flash_read(byte_addr), ==, 0x0055);
+        program(c, byte_addr, 0x55);
+        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
+        program(c, byte_addr, 0xA5);
+        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
     }
 
     /* Erase the chip. */
-    chip_erase();
+    chip_erase(c);
     /* Read toggle. */
-    uint16_t status0 = flash_read(0);
+    uint64_t status0 = flash_read(c, 0);
     /* DQ7 is 0 during an erase. */
-    g_assert_cmphex(status0 & 0x80, ==, 0);
-    uint16_t status1 = flash_read(0);
+    g_assert_cmphex(status0 & dq7, ==, 0);
+    uint64_t status1 = flash_read(c, 0);
     /* DQ6 toggles during an erase. */
-    g_assert_cmphex(status0 & 0x40, !=, status1 & 0x40);
+    g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
     /* Wait for erase to complete. */
-    clock_step_next();
+    qtest_clock_step_next(c->qtest);
     /* Ensure DQ6 has stopped toggling. */
-    g_assert_cmphex(flash_read(0), ==, flash_read(0));
+    g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
     /* Now the data should be valid. */
-    g_assert_cmphex(flash_read(0), ==, 0xFFFF);
+
+    for (uint32_t i = 0; i < nb_sectors; ++i) {
+        uint64_t byte_addr = i * sector_len;
+        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+    }
 
     /* Unlock bypass */
-    unlock();
-    flash_write(UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
-    bypass_program(0, 0x0123);
-    bypass_program(2, 0x4567);
-    bypass_program(4, 0x89AB);
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
+    bypass_program(c, 0 * c->bank_width, 0x01);
+    bypass_program(c, 1 * c->bank_width, 0x23);
+    bypass_program(c, 2 * c->bank_width, 0x45);
     /*
      * Test that bypass programming, unlike normal programming can use any
      * address for the PROGRAM_CMD.
      */
-    flash_write(6, PROGRAM_CMD);
-    flash_write(6, 0xCDEF);
-    wait_for_completion(6);
-    flash_write(0, UNLOCK_BYPASS_RESET_CMD);
-    bypass_program(8, 0x55AA); /* Should fail. */
-    g_assert_cmphex(flash_read(0), ==, 0x0123);
-    g_assert_cmphex(flash_read(2), ==, 0x4567);
-    g_assert_cmphex(flash_read(4), ==, 0x89AB);
-    g_assert_cmphex(flash_read(6), ==, 0xCDEF);
-    g_assert_cmphex(flash_read(8), ==, 0xFFFF);
+    flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD);
+    flash_write(c, 3 * c->bank_width, 0x67);
+    wait_for_completion(c, 3 * c->bank_width);
+    flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD);
+    bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */
+    g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01);
+    g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23);
+    g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45);
+    g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67);
+    g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c));
 
     /* Test ignored high order bits of address. */
-    flash_write(FLASH_WIDTH * 0x5555, UNLOCK0_CMD);
-    flash_write(FLASH_WIDTH * 0x2AAA, UNLOCK1_CMD);
-    flash_write(FLASH_WIDTH * 0x5555, AUTOSELECT_CMD);
-    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
-    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
-    reset();
+    flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD);
+    flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD);
+    flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD);
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+    reset(c);
 
-    qtest_quit(global_qtest);
+    qtest_quit(qtest);
 }
 
 static void cleanup(void *opaque)
@@ -206,6 +355,17 @@ static void cleanup(void *opaque)
     unlink(image_path);
 }
 
+/*
+ * XXX: Tests are limited to bank_width = 2 for now because that's what
+ * hw/arm/musicpal.c has.
+ */
+static const FlashConfig configuration[] = {
+    /* One x16 device. */
+    {
+        .bank_width = 2,
+    },
+};
+
 int main(int argc, char **argv)
 {
     int fd = mkstemp(image_path);
@@ -214,19 +374,27 @@ int main(int argc, char **argv)
                    strerror(errno));
         exit(EXIT_FAILURE);
     }
-    if (ftruncate(fd, 8 * 1024 * 1024) < 0) {
+    if (ftruncate(fd, FLASH_SIZE) < 0) {
         int error_code = errno;
         close(fd);
         unlink(image_path);
-        g_printerr("Failed to truncate file %s to 8 MB: %s\n", image_path,
-                   strerror(error_code));
+        g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
+                   FLASH_SIZE, strerror(error_code));
         exit(EXIT_FAILURE);
     }
     close(fd);
 
     qtest_add_abrt_handler(cleanup, NULL);
     g_test_init(&argc, &argv, NULL);
-    qtest_add_func("pflash-cfi02", test_flash);
+
+    size_t nb_configurations = sizeof configuration / sizeof configuration[0];
+    for (size_t i = 0; i < nb_configurations; ++i) {
+        const FlashConfig *config = &configuration[i];
+        char *path = g_strdup_printf("pflash-cfi02/%d",
+                                     config->bank_width);
+        qtest_add_data_func(path, config, test_flash);
+        g_free(path);
+    }
     int result = g_test_run();
     cleanup(NULL);
     return result;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 14/28] hw/block/pflash_cfi02: Remove pointless local variable
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (12 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 13/28] tests/pflash-cfi02: Refactor to support testing multiple configurations Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:32   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 15/28] hw/block/pflash_cfi02: Document the current CFI values Philippe Mathieu-Daudé
                   ` (13 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

We can directly use pfl->total_len, remove the local 'chip_len'
variable.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 4be3837be5..1a794fa83c 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -409,7 +409,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             /* Chip erase */
             DPRINTF("%s: start chip erase\n", __func__);
             if (!pfl->ro) {
-                memset(pfl->storage, 0xFF, pfl->chip_len);
+                memset(pfl->storage, 0xff, pfl->chip_len);
                 pflash_update(pfl, 0, pfl->chip_len);
             }
             set_dq7(pfl, 0x00);
@@ -490,7 +490,6 @@ static const MemoryRegionOps pflash_cfi02_ops = {
 static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 {
     PFlashCFI02 *pfl = PFLASH_CFI02(dev);
-    uint32_t chip_len;
     int ret;
     Error *local_err = NULL;
 
@@ -507,18 +506,17 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    chip_len = pfl->sector_len * pfl->nb_blocs;
+    pfl->chip_len = pfl->sector_len * pfl->nb_blocs;
 
     memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
                                   &pflash_cfi02_ops, pfl, pfl->name,
-                                  chip_len, &local_err);
+                                  pfl->chip_len, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
         return;
     }
 
     pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
-    pfl->chip_len = chip_len;
 
     if (pfl->blk) {
         uint64_t perm;
@@ -533,8 +531,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     }
 
     if (pfl->blk) {
-        if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, chip_len,
-                                         errp)) {
+        if (!blk_check_size_and_read_all(pfl->blk, pfl->storage,
+                                         pfl->chip_len, errp)) {
             vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
             return;
         }
@@ -594,7 +592,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     /* Max timeout for chip erase */
     pfl->cfi_table[0x26] = 0x0D;
     /* Device size */
-    pfl->cfi_table[0x27] = ctz32(chip_len);
+    pfl->cfi_table[0x27] = ctz32(pfl->chip_len);
     /* Flash device interface (8 & 16 bits) */
     pfl->cfi_table[0x28] = 0x02;
     pfl->cfi_table[0x29] = 0x00;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 15/28] hw/block/pflash_cfi02: Document the current CFI values
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (13 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 14/28] hw/block/pflash_cfi02: Remove pointless local variable Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:33   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 16/28] hw/block/pflash_cfi02: Hold the PRI table offset in a variable Philippe Mathieu-Daudé
                   ` (12 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 1a794fa83c..f1bac480f5 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -550,6 +550,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->wcycle = 0;
     pfl->cmd = 0;
     pfl->status = 0;
+
     /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
     /* Standard "QRY" string */
     pfl->cfi_table[0x10] = 'Q';
@@ -575,7 +576,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->cfi_table[0x1D] = 0x00;
     /* Vpp max (no Vpp pin) */
     pfl->cfi_table[0x1E] = 0x00;
-    /* Reserved */
+    /* Timeout per single byte/word write (128 ms) */
     pfl->cfi_table[0x1F] = 0x07;
     /* Timeout for min size buffer write (NA) */
     pfl->cfi_table[0x20] = 0x00;
@@ -614,17 +615,25 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->cfi_table[0x32] = 'R';
     pfl->cfi_table[0x33] = 'I';
 
+    /* Extended version 1.0 */
     pfl->cfi_table[0x34] = '1';
     pfl->cfi_table[0x35] = '0';
 
+    /* Address sensitive unlock required. */
     pfl->cfi_table[0x36] = 0x00;
+    /* Erase suspend not supported. */
     pfl->cfi_table[0x37] = 0x00;
+    /* Sector protect not supported. */
     pfl->cfi_table[0x38] = 0x00;
+    /* Temporary sector unprotect not supported. */
     pfl->cfi_table[0x39] = 0x00;
 
+    /* Sector protect/unprotect scheme. */
     pfl->cfi_table[0x3a] = 0x00;
 
+    /* Simultaneous operation not supported. */
     pfl->cfi_table[0x3b] = 0x00;
+    /* Burst mode not supported. */
     pfl->cfi_table[0x3c] = 0x00;
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 16/28] hw/block/pflash_cfi02: Hold the PRI table offset in a variable
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (14 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 15/28] hw/block/pflash_cfi02: Document the current CFI values Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:34   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 17/28] hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported Philippe Mathieu-Daudé
                   ` (11 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Manufacturers are allowed to move the PRI table, this is why the
offset is queryable via fixed offsets 0x15/0x16.
Add a variable to hold the offset, so it will be easier to later
move the PRI table.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index f1bac480f5..23d05a6308 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -552,6 +552,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->status = 0;
 
     /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
+    const uint16_t pri_ofs = 0x31;
     /* Standard "QRY" string */
     pfl->cfi_table[0x10] = 'Q';
     pfl->cfi_table[0x11] = 'R';
@@ -560,8 +561,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->cfi_table[0x13] = 0x02;
     pfl->cfi_table[0x14] = 0x00;
     /* Primary extended table address */
-    pfl->cfi_table[0x15] = 0x31;
-    pfl->cfi_table[0x16] = 0x00;
+    pfl->cfi_table[0x15] = pri_ofs;
+    pfl->cfi_table[0x16] = pri_ofs >> 8;
     /* Alternate command set (none) */
     pfl->cfi_table[0x17] = 0x00;
     pfl->cfi_table[0x18] = 0x00;
@@ -609,32 +610,34 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
     pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
     pfl->cfi_table[0x30] = pfl->sector_len >> 16;
+    assert(0x30 < pri_ofs);
 
     /* Extended */
-    pfl->cfi_table[0x31] = 'P';
-    pfl->cfi_table[0x32] = 'R';
-    pfl->cfi_table[0x33] = 'I';
+    pfl->cfi_table[0x00 + pri_ofs] = 'P';
+    pfl->cfi_table[0x01 + pri_ofs] = 'R';
+    pfl->cfi_table[0x02 + pri_ofs] = 'I';
 
     /* Extended version 1.0 */
-    pfl->cfi_table[0x34] = '1';
-    pfl->cfi_table[0x35] = '0';
+    pfl->cfi_table[0x03 + pri_ofs] = '1';
+    pfl->cfi_table[0x04 + pri_ofs] = '0';
 
     /* Address sensitive unlock required. */
-    pfl->cfi_table[0x36] = 0x00;
+    pfl->cfi_table[0x05 + pri_ofs] = 0x00;
     /* Erase suspend not supported. */
-    pfl->cfi_table[0x37] = 0x00;
+    pfl->cfi_table[0x06 + pri_ofs] = 0x00;
     /* Sector protect not supported. */
-    pfl->cfi_table[0x38] = 0x00;
+    pfl->cfi_table[0x07 + pri_ofs] = 0x00;
     /* Temporary sector unprotect not supported. */
-    pfl->cfi_table[0x39] = 0x00;
+    pfl->cfi_table[0x08 + pri_ofs] = 0x00;
 
     /* Sector protect/unprotect scheme. */
-    pfl->cfi_table[0x3a] = 0x00;
+    pfl->cfi_table[0x09 + pri_ofs] = 0x00;
 
     /* Simultaneous operation not supported. */
-    pfl->cfi_table[0x3b] = 0x00;
+    pfl->cfi_table[0x0a + pri_ofs] = 0x00;
     /* Burst mode not supported. */
-    pfl->cfi_table[0x3c] = 0x00;
+    pfl->cfi_table[0x0b + pri_ofs] = 0x00;
+    assert(0x0b + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
 }
 
 static Property pflash_cfi02_properties[] = {
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 17/28] hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (15 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 16/28] hw/block/pflash_cfi02: Hold the PRI table offset in a variable Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:35   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 18/28] hw/block/pflash_cfi02: Implement nonuniform sector sizes Philippe Mathieu-Daudé
                   ` (10 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

The 'page mode' feature entry was implicitly set as zero
(not supported). Document it exists, so we won't discard
it if we squeeze the CFI table.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 23d05a6308..01d9c5d75a 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -637,7 +637,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->cfi_table[0x0a + pri_ofs] = 0x00;
     /* Burst mode not supported. */
     pfl->cfi_table[0x0b + pri_ofs] = 0x00;
-    assert(0x0b + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
+    /* Page mode not supported. */
+    pfl->cfi_table[0x0c + pri_ofs] = 0x00;
+    assert(0x0c + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
 }
 
 static Property pflash_cfi02_properties[] = {
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 18/28] hw/block/pflash_cfi02: Implement nonuniform sector sizes
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (16 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 17/28] hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 17:28   ` Philippe Mathieu-Daudé
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 19/28] hw/block/pflash_cfi02: Extract pflash_regions_count() Philippe Mathieu-Daudé
                   ` (9 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

Some flash chips support sectors of different sizes. For example, the
AMD AM29LV160DT has 31 64 kB sectors, one 32 kB sector, two 8 kB
sectors, and a 16 kB sector, in that order. The AM29LV160DB has those in
the reverse order.

The `num-blocks` and `sector-length` properties work exactly as they did
before: a flash device with uniform sector lengths. To get non-uniform
sector lengths for up to four regions, the following properties may be
set
- region 0. `num-blocks0` and `sector-length0`;
- region 1. `num-blocks1` and `sector-length1`;
- region 2. `num-blocks2` and `sector-length2`; and
- region 3. `num-blocks3` and `sector-length3`.

If the uniform and nonuniform properties are set, then both must specify
a flash device with the same total size. It would be better to disallow
both being set, or make `num-blocks0` and `sector-length0` alias
`num-blocks` and `sector-length`, but that would make testing currently
impossible.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
[PMD: Rebased, add assert() on pri_offset]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c   | 141 +++++++++++++++++++++++++++-------
 tests/pflash-cfi02-test.c | 155 ++++++++++++++++++++++++++++----------
 2 files changed, 231 insertions(+), 65 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 01d9c5d75a..1f096ec185 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -29,7 +29,6 @@
  * - CFI queries
  *
  * It does not support flash interleaving.
- * It does not implement boot blocs with reduced size
  * It does not implement software data protection as found in many real chips
  * It does not implement erase suspend/resume commands
  * It does not implement multiple sectors erase
@@ -57,6 +56,13 @@ do {                                                       \
 
 #define PFLASH_LAZY_ROMD_THRESHOLD 42
 
+/*
+ * The size of the cfi_table indirectly depends on this and the start of the
+ * PRI table directly depends on it. 4 is the maximum size (and also what
+ * seems common) without changing the PRT table address.
+ */
+#define PFLASH_MAX_ERASE_REGIONS 4
+
 /* Special write cycles for CFI queries. */
 enum {
     WCYCLE_CFI              = 7,
@@ -68,8 +74,10 @@ struct PFlashCFI02 {
     /*< public >*/
 
     BlockBackend *blk;
-    uint32_t sector_len;
-    uint32_t nb_blocs;
+    uint32_t uniform_nb_blocs;
+    uint32_t uniform_sector_len;
+    uint32_t nb_blocs[PFLASH_MAX_ERASE_REGIONS];
+    uint32_t sector_len[PFLASH_MAX_ERASE_REGIONS];
     uint32_t chip_len;
     uint8_t mappings;
     uint8_t width;
@@ -86,7 +94,7 @@ struct PFlashCFI02 {
     uint16_t ident3;
     uint16_t unlock_addr0;
     uint16_t unlock_addr1;
-    uint8_t cfi_table[0x52];
+    uint8_t cfi_table[0x4d];
     QEMUTimer timer;
     /* The device replicates the flash memory across its memory space.  Emulate
      * that by having a container (.mem) filled with an array of aliases
@@ -177,6 +185,25 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
     return ret;
 }
 
+/*
+ * offset should be a byte offset of the QEMU device and _not_ a device
+ * offset.
+ */
+static uint32_t pflash_sector_len(PFlashCFI02 *pfl, hwaddr offset)
+{
+    assert(offset < pfl->chip_len);
+    int nb_regions = pfl->cfi_table[0x2C];
+    hwaddr addr = 0;
+    for (int i = 0; i < nb_regions; ++i) {
+        uint64_t region_size = (uint64_t)pfl->nb_blocs[i] * pfl->sector_len[i];
+        if (addr <= offset && offset < addr + region_size) {
+            return pfl->sector_len[i];
+        }
+        addr += region_size;
+    }
+    abort();
+}
+
 static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
 {
     PFlashCFI02 *pfl = opaque;
@@ -191,10 +218,11 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
     }
     offset &= pfl->chip_len - 1;
     boff = offset & 0xFF;
-    if (pfl->width == 2)
+    if (pfl->width == 2) {
         boff = boff >> 1;
-    else if (pfl->width == 4)
+    } else if (pfl->width == 4) {
         boff = boff >> 2;
+    }
     switch (pfl->cmd) {
     default:
         /* This should never happen : reset state & treat it as a read*/
@@ -273,6 +301,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     hwaddr boff;
     uint8_t *p;
     uint8_t cmd;
+    uint32_t sector_len;
 
     trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     cmd = value;
@@ -282,10 +311,11 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     offset &= pfl->chip_len - 1;
 
     boff = offset;
-    if (pfl->width == 2)
+    if (pfl->width == 2) {
         boff = boff >> 1;
-    else if (pfl->width == 4)
+    } else if (pfl->width == 4) {
         boff = boff >> 2;
+    }
     /* Only the least-significant 11 bits are used in most cases. */
     boff &= 0x7FF;
     switch (pfl->wcycle) {
@@ -420,12 +450,14 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         case 0x30:
             /* Sector erase */
             p = pfl->storage;
-            offset &= ~(pfl->sector_len - 1);
-            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
-                    offset);
+            sector_len = pflash_sector_len(pfl, offset);
+            offset &= ~(sector_len - 1);
+            DPRINTF("%s: start sector erase at %0*" PRIx64 "-%0*" PRIx64 "\n",
+                    __func__, pfl->width * 2, offset,
+                    pfl->width * 2, offset + sector_len - 1);
             if (!pfl->ro) {
-                memset(p + offset, 0xFF, pfl->sector_len);
-                pflash_update(pfl, offset, pfl->sector_len);
+                memset(p + offset, 0xff, sector_len);
+                pflash_update(pfl, offset, sector_len);
             }
             set_dq7(pfl, 0x00);
             /* Let's wait 1/2 second before sector erase is done */
@@ -493,11 +525,11 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     int ret;
     Error *local_err = NULL;
 
-    if (pfl->sector_len == 0) {
+    if (pfl->uniform_sector_len == 0 && pfl->sector_len[0] == 0) {
         error_setg(errp, "attribute \"sector-length\" not specified or zero.");
         return;
     }
-    if (pfl->nb_blocs == 0) {
+    if (pfl->uniform_nb_blocs == 0 && pfl->nb_blocs[0] == 0) {
         error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
         return;
     }
@@ -506,7 +538,51 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    pfl->chip_len = pfl->sector_len * pfl->nb_blocs;
+    int nb_regions;
+    pfl->chip_len = 0;
+    for (nb_regions = 0; nb_regions < PFLASH_MAX_ERASE_REGIONS; ++nb_regions) {
+        if (pfl->nb_blocs[nb_regions] == 0) {
+            break;
+        }
+        uint64_t sector_len_per_device = pfl->sector_len[nb_regions];
+
+        /*
+         * The size of each flash sector must be a power of 2 and it must be
+         * aligned at the same power of 2.
+         */
+        if (sector_len_per_device & 0xff ||
+            sector_len_per_device >= (1 << 24) ||
+            !is_power_of_2(sector_len_per_device))
+        {
+            error_setg(errp, "unsupported configuration: "
+                       "sector length[%d] per device = %" PRIx64 ".",
+                       nb_regions, sector_len_per_device);
+            return;
+        }
+        if (pfl->chip_len & (sector_len_per_device - 1)) {
+            error_setg(errp, "unsupported configuration: "
+                       "flash region %d not correctly aligned.",
+                       nb_regions);
+            return;
+        }
+
+        pfl->chip_len += (uint64_t)pfl->sector_len[nb_regions] *
+                          pfl->nb_blocs[nb_regions];
+    }
+
+    uint64_t uniform_len = (uint64_t)pfl->uniform_nb_blocs *
+                           pfl->uniform_sector_len;
+    if (nb_regions == 0) {
+        nb_regions = 1;
+        pfl->nb_blocs[0] = pfl->uniform_nb_blocs;
+        pfl->sector_len[0] = pfl->uniform_sector_len;
+        pfl->chip_len = uniform_len;
+    } else if (uniform_len != 0 && uniform_len != pfl->chip_len) {
+        error_setg(errp, "\"num-blocks\"*\"sector-length\" "
+                   "different from \"num-blocks0\"*\'sector-length0\" + ... + "
+                   "\"num-blocks3\"*\"sector-length3\"");
+        return;
+    }
 
     memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
                                   &pflash_cfi02_ops, pfl, pfl->name,
@@ -552,7 +628,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->status = 0;
 
     /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
-    const uint16_t pri_ofs = 0x31;
+    const uint16_t pri_ofs = 0x40;
     /* Standard "QRY" string */
     pfl->cfi_table[0x10] = 'Q';
     pfl->cfi_table[0x11] = 'R';
@@ -603,14 +679,17 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     //    pfl->cfi_table[0x2A] = 0x05;
     pfl->cfi_table[0x2A] = 0x00;
     pfl->cfi_table[0x2B] = 0x00;
-    /* Number of erase block regions (uniform) */
-    pfl->cfi_table[0x2C] = 0x01;
-    /* Erase block region 1 */
-    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
-    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
-    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
-    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
-    assert(0x30 < pri_ofs);
+    /* Number of erase block regions */
+    pfl->cfi_table[0x2c] = nb_regions;
+    /* Erase block regions */
+    for (int i = 0; i < nb_regions; ++i) {
+        uint32_t sector_len_per_device = pfl->sector_len[i];
+        pfl->cfi_table[0x2d + 4 * i] = pfl->nb_blocs[i] - 1;
+        pfl->cfi_table[0x2e + 4 * i] = (pfl->nb_blocs[i] - 1) >> 8;
+        pfl->cfi_table[0x2f + 4 * i] = sector_len_per_device >> 8;
+        pfl->cfi_table[0x30 + 4 * i] = sector_len_per_device >> 16;
+    }
+    assert(0x2c + 4 * nb_regions < pri_ofs);
 
     /* Extended */
     pfl->cfi_table[0x00 + pri_ofs] = 'P';
@@ -644,8 +723,16 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 
 static Property pflash_cfi02_properties[] = {
     DEFINE_PROP_DRIVE("drive", PFlashCFI02, blk),
-    DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, nb_blocs, 0),
-    DEFINE_PROP_UINT32("sector-length", PFlashCFI02, sector_len, 0),
+    DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, uniform_nb_blocs, 0),
+    DEFINE_PROP_UINT32("sector-length", PFlashCFI02, uniform_sector_len, 0),
+    DEFINE_PROP_UINT32("num-blocks0", PFlashCFI02, nb_blocs[0], 0),
+    DEFINE_PROP_UINT32("sector-length0", PFlashCFI02, sector_len[0], 0),
+    DEFINE_PROP_UINT32("num-blocks1", PFlashCFI02, nb_blocs[1], 0),
+    DEFINE_PROP_UINT32("sector-length1", PFlashCFI02, sector_len[1], 0),
+    DEFINE_PROP_UINT32("num-blocks2", PFlashCFI02, nb_blocs[2], 0),
+    DEFINE_PROP_UINT32("sector-length2", PFlashCFI02, sector_len[2], 0),
+    DEFINE_PROP_UINT32("num-blocks3", PFlashCFI02, nb_blocs[3], 0),
+    DEFINE_PROP_UINT32("sector-length3", PFlashCFI02, sector_len[3], 0),
     DEFINE_PROP_UINT8("width", PFlashCFI02, width, 0),
     DEFINE_PROP_UINT8("mappings", PFlashCFI02, mappings, 0),
     DEFINE_PROP_UINT8("big-endian", PFlashCFI02, be, 0),
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index b00f5ca2e7..1659eaebce 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -17,9 +17,11 @@
  */
 
 #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
-#define FLASH_SIZE (8 * 1024 * 1024)
 #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
 
+#define UNIFORM_FLASH_SIZE (8 * 1024 * 1024)
+#define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024)
+
 /* Use a newtype to keep flash addresses separate from byte addresses. */
 typedef struct {
     uint64_t addr;
@@ -44,6 +46,10 @@ typedef struct {
 typedef struct {
     int bank_width;
 
+    /* Nonuniform block size. */
+    int nb_blocs[4];
+    int sector_len[4];
+
     QTestState *qtest;
 } FlashConfig;
 
@@ -62,6 +68,10 @@ static FlashConfig expand_config_defaults(const FlashConfig *c)
     if (ret.bank_width == 0) {
         ret.bank_width = 2;
     }
+    if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) {
+        ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE;
+        ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE;
+    }
 
     /* XXX: Limitations of test harness. */
     assert(ret.bank_width == 2);
@@ -230,13 +240,41 @@ static void chip_erase(const FlashConfig *c)
     flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
 }
 
-static void test_flash(const void *opaque)
+/*
+ * Test flash commands with a variety of device geometry.
+ */
+static void test_geometry(const void *opaque)
 {
     const FlashConfig *config = opaque;
     QTestState *qtest;
     qtest = qtest_initf("-M musicpal,accel=qtest"
-                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
-                        image_path);
+                        " -drive if=pflash,file=%s,format=raw,copy-on-read"
+                        /* Device geometry properties. */
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks0,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length0,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks1,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length1,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks2,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length2,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=num-blocks3,value=%d"
+                        " -global driver=cfi.pflash02,"
+                        "property=sector-length3,value=%d",
+                        image_path,
+                        config->nb_blocs[0],
+                        config->sector_len[0],
+                        config->nb_blocs[1],
+                        config->sector_len[1],
+                        config->nb_blocs[2],
+                        config->sector_len[2],
+                        config->nb_blocs[3],
+                        config->sector_len[3]);
     FlashConfig explicit_config = expand_config_defaults(config);
     explicit_config.qtest = qtest;
     const FlashConfig *c = &explicit_config;
@@ -264,39 +302,56 @@ static void test_flash(const void *opaque)
     g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
 
     /* Num erase regions. */
-    g_assert_cmphex(flash_query_1(c, FLASH_ADDR(0x2C)), >=, 1);
+    int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C));
+    g_assert_cmphex(nb_erase_regions, ==,
+                    !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] +
+                    !!c->nb_blocs[3]);
+
+    /* Check device length. */
+    uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
+    g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
 
-    uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(0x2D)) +
-                          (flash_query_1(c, FLASH_ADDR(0x2E)) << 8) + 1;
-    uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(0x2F)) << 8) +
-                          (flash_query_1(c, FLASH_ADDR(0x30)) << 16);
     reset(c);
 
     const uint64_t dq7 = replicate(c, 0x80);
     const uint64_t dq6 = replicate(c, 0x40);
-    /* Erase and program sector. */
-    for (uint32_t i = 0; i < nb_sectors; ++i) {
-        uint64_t byte_addr = i * sector_len;
-        sector_erase(c, byte_addr);
-        /* Read toggle. */
-        uint64_t status0 = flash_read(c, byte_addr);
-        /* DQ7 is 0 during an erase. */
-        g_assert_cmphex(status0 & dq7, ==, 0);
-        uint64_t status1 = flash_read(c, byte_addr);
-        /* DQ6 toggles during an erase. */
-        g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
-        /* Wait for erase to complete. */
-        qtest_clock_step_next(c->qtest);
-        /* Ensure DQ6 has stopped toggling. */
-        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
-        /* Now the data should be valid. */
-        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+    uint64_t byte_addr = 0;
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        uint64_t base = 0x2D + 4 * region;
+        flash_cmd(c, CFI_ADDR, CFI_CMD);
+        uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) +
+                              (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1;
+        uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) +
+                              (flash_query_1(c, FLASH_ADDR(base + 3)) << 16);
+        g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]);
+        g_assert_cmphex(sector_len, ==, c->sector_len[region]);
+        reset(c);
 
-        /* Program a bit pattern. */
-        program(c, byte_addr, 0x55);
-        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
-        program(c, byte_addr, 0xA5);
-        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
+        /* Erase and program sector. */
+        for (uint32_t i = 0; i < nb_sectors; ++i) {
+            sector_erase(c, byte_addr);
+            /* Read toggle. */
+            uint64_t status0 = flash_read(c, byte_addr);
+            /* DQ7 is 0 during an erase. */
+            g_assert_cmphex(status0 & dq7, ==, 0);
+            uint64_t status1 = flash_read(c, byte_addr);
+            /* DQ6 toggles during an erase. */
+            g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
+            /* Wait for erase to complete. */
+            qtest_clock_step_next(c->qtest);
+            /* Ensure DQ6 has stopped toggling. */
+            g_assert_cmphex(flash_read(c, byte_addr), ==,
+                            flash_read(c, byte_addr));
+            /* Now the data should be valid. */
+            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+
+            /* Program a bit pattern. */
+            program(c, byte_addr, 0x55);
+            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
+            program(c, byte_addr, 0xA5);
+            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
+            byte_addr += sector_len;
+        }
     }
 
     /* Erase the chip. */
@@ -314,9 +369,11 @@ static void test_flash(const void *opaque)
     g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
     /* Now the data should be valid. */
 
-    for (uint32_t i = 0; i < nb_sectors; ++i) {
-        uint64_t byte_addr = i * sector_len;
-        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) {
+            uint64_t byte_addr = i * c->sector_len[region];
+            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+        }
     }
 
     /* Unlock bypass */
@@ -364,6 +421,18 @@ static const FlashConfig configuration[] = {
     {
         .bank_width = 2,
     },
+    /* Nonuniform sectors (top boot). */
+    {
+        .bank_width = 2,
+        .nb_blocs = { 127, 1, 2, 1 },
+        .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 },
+    },
+    /* Nonuniform sectors (bottom boot). */
+    {
+        .bank_width = 2,
+        .nb_blocs = { 1, 2, 1, 127 },
+        .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 },
+    },
 };
 
 int main(int argc, char **argv)
@@ -374,12 +443,12 @@ int main(int argc, char **argv)
                    strerror(errno));
         exit(EXIT_FAILURE);
     }
-    if (ftruncate(fd, FLASH_SIZE) < 0) {
+    if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) {
         int error_code = errno;
         close(fd);
         unlink(image_path);
         g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
-                   FLASH_SIZE, strerror(error_code));
+                   UNIFORM_FLASH_SIZE, strerror(error_code));
         exit(EXIT_FAILURE);
     }
     close(fd);
@@ -390,9 +459,19 @@ int main(int argc, char **argv)
     size_t nb_configurations = sizeof configuration / sizeof configuration[0];
     for (size_t i = 0; i < nb_configurations; ++i) {
         const FlashConfig *config = &configuration[i];
-        char *path = g_strdup_printf("pflash-cfi02/%d",
+        char *path = g_strdup_printf("pflash-cfi02"
+                                     "/geometry/%dx%x-%dx%x-%dx%x-%dx%x"
+                                     "/%d",
+                                     config->nb_blocs[0],
+                                     config->sector_len[0],
+                                     config->nb_blocs[1],
+                                     config->sector_len[1],
+                                     config->nb_blocs[2],
+                                     config->sector_len[2],
+                                     config->nb_blocs[3],
+                                     config->sector_len[3],
                                      config->bank_width);
-        qtest_add_data_func(path, config, test_flash);
+        qtest_add_data_func(path, config, test_geometry);
         g_free(path);
     }
     int result = g_test_run();
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 19/28] hw/block/pflash_cfi02: Extract pflash_regions_count()
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (17 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 18/28] hw/block/pflash_cfi02: Implement nonuniform sector sizes Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 16:43   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 20/28] hw/block/pflash_cfi02: Split if() condition Philippe Mathieu-Daudé
                   ` (8 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Extract the pflash_regions_count() function, the code will be
easier to review.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 1f096ec185..a0d3bd60dc 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -157,6 +157,11 @@ static void pflash_register_memory(PFlashCFI02 *pfl, int rom_mode)
     pfl->rom_mode = rom_mode;
 }
 
+static size_t pflash_regions_count(PFlashCFI02 *pfl)
+{
+    return pfl->cfi_table[0x2c];
+}
+
 static void pflash_timer (void *opaque)
 {
     PFlashCFI02 *pfl = opaque;
@@ -192,9 +197,8 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
 static uint32_t pflash_sector_len(PFlashCFI02 *pfl, hwaddr offset)
 {
     assert(offset < pfl->chip_len);
-    int nb_regions = pfl->cfi_table[0x2C];
     hwaddr addr = 0;
-    for (int i = 0; i < nb_regions; ++i) {
+    for (int i = 0; i < pflash_regions_count(pfl); ++i) {
         uint64_t region_size = (uint64_t)pfl->nb_blocs[i] * pfl->sector_len[i];
         if (addr <= offset && offset < addr + region_size) {
             return pfl->sector_len[i];
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 20/28] hw/block/pflash_cfi02: Split if() condition
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (18 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 19/28] hw/block/pflash_cfi02: Extract pflash_regions_count() Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 23:06   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 21/28] hw/block/pflash_cfi02: Fix CFI in autoselect mode Philippe Mathieu-Daudé
                   ` (7 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Split the if() condition check and arrange the indentation to
ease the review of the next patches. No logical change.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index a0d3bd60dc..08b2bc83cb 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -309,8 +309,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
 
     trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     cmd = value;
-    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
-        goto reset_flash;
+    if (pfl->cmd != 0xA0) {
+        if (cmd == 0xF0) {
+            goto reset_flash;
+        }
     }
     offset &= pfl->chip_len - 1;
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 21/28] hw/block/pflash_cfi02: Fix CFI in autoselect mode
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (19 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 20/28] hw/block/pflash_cfi02: Split if() condition Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 23:08   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 22/28] hw/block/pflash_cfi02: Fix reset command not ignored during erase Philippe Mathieu-Daudé
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

After a flash device enters CFI mode from autoselect mode, the reset
command returns the device to autoselect mode. An additional reset
command is necessary to return to read array mode.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20190426162624.55977-7-stephen.checkoway@oberlin.edu>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c   | 22 ++++++++++++++++++----
 tests/pflash-cfi02-test.c | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 4 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 08b2bc83cb..13f76fa71d 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -66,6 +66,7 @@ do {                                                       \
 /* Special write cycles for CFI queries. */
 enum {
     WCYCLE_CFI              = 7,
+    WCYCLE_AUTOSELECT_CFI   = 8,
 };
 
 struct PFlashCFI02 {
@@ -311,6 +312,12 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     cmd = value;
     if (pfl->cmd != 0xA0) {
         if (cmd == 0xF0) {
+            if (pfl->wcycle == WCYCLE_AUTOSELECT_CFI) {
+                /* Return to autoselect mode. */
+                pfl->wcycle = 3;
+                pfl->cmd = 0x90;
+                return;
+            }
             goto reset_flash;
         }
     }
@@ -333,7 +340,6 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         /* We're in read mode */
     check_unlock0:
         if (boff == 0x55 && cmd == 0x98) {
-        enter_CFI_mode:
             /* Enter CFI query mode */
             pfl->wcycle = WCYCLE_CFI;
             pfl->cmd = 0x98;
@@ -410,9 +416,16 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
                 /* Unlock bypass reset */
                 goto reset_flash;
             }
-            /* We can enter CFI query mode from autoselect mode */
-            if (boff == 0x55 && cmd == 0x98)
-                goto enter_CFI_mode;
+            /*
+             * We can enter CFI query mode from autoselect mode, but we must
+             * return to autoselect mode after a reset.
+             */
+            if (boff == 0x55 && cmd == 0x98) {
+                /* Enter autoselect CFI query mode */
+                pfl->wcycle = WCYCLE_AUTOSELECT_CFI;
+                pfl->cmd = 0x98;
+                return;
+            }
             /* No break here */
         default:
             DPRINTF("%s: invalid write for command %02x\n",
@@ -493,6 +506,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         break;
     /* Special values for CFI queries */
     case WCYCLE_CFI:
+    case WCYCLE_AUTOSELECT_CFI:
         DPRINTF("%s: invalid write in CFI query mode\n", __func__);
         goto reset_flash;
     default:
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index 1659eaebce..00e2261742 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -407,6 +407,42 @@ static void test_geometry(const void *opaque)
     qtest_quit(qtest);
 }
 
+/*
+ * Test that
+ * 1. enter autoselect mode;
+ * 2. enter CFI mode; and then
+ * 3. exit CFI mode
+ * leaves the flash device in autoselect mode.
+ */
+static void test_cfi_in_autoselect(const void *opaque)
+{
+    const FlashConfig *config = opaque;
+    QTestState *qtest;
+    qtest = qtest_initf("-M musicpal,accel=qtest"
+                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
+                        image_path);
+    FlashConfig explicit_config = expand_config_defaults(config);
+    explicit_config.qtest = qtest;
+    const FlashConfig *c = &explicit_config;
+
+    /* 1. Enter autoselect. */
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+
+    /* 2. Enter CFI. */
+    flash_cmd(c, CFI_ADDR, CFI_CMD);
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
+
+    /* 3. Exit CFI. */
+    reset(c);
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+
+    qtest_quit(qtest);
+}
+
 static void cleanup(void *opaque)
 {
     unlink(image_path);
@@ -474,6 +510,9 @@ int main(int argc, char **argv)
         qtest_add_data_func(path, config, test_geometry);
         g_free(path);
     }
+
+    qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0],
+                        test_cfi_in_autoselect);
     int result = g_test_run();
     cleanup(NULL);
     return result;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 22/28] hw/block/pflash_cfi02: Fix reset command not ignored during erase
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (20 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 21/28] hw/block/pflash_cfi02: Fix CFI in autoselect mode Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 23:11   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 23/28] hw/block/pflash_cfi02: Implement multi-sector erase Philippe Mathieu-Daudé
                   ` (5 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

When the flash device is performing a chip erase, all commands are
ignored. When it is performing a sector erase, only the erase suspend
command is valid, which is currently not supported.

In particular, the reset command should not cause the device to reset to
read array mode while programming is on going.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-8-stephen.checkoway@oberlin.edu>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 13f76fa71d..39daa95833 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -311,7 +311,8 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     cmd = value;
     if (pfl->cmd != 0xA0) {
-        if (cmd == 0xF0) {
+        /* Reset does nothing during chip erase and sector erase. */
+        if (cmd == 0xF0 && pfl->cmd != 0x10 && pfl->cmd != 0x30) {
             if (pfl->wcycle == WCYCLE_AUTOSELECT_CFI) {
                 /* Return to autoselect mode. */
                 pfl->wcycle = 3;
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 23/28] hw/block/pflash_cfi02: Implement multi-sector erase
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (21 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 22/28] hw/block/pflash_cfi02: Fix reset command not ignored during erase Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 24/28] hw/block/pflash_cfi02: Implement erase suspend/resume Philippe Mathieu-Daudé
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

After two unlock cycles and a sector erase command, the AMD flash chips
start a 50 us erase time out. Any additional sector erase commands add a
sector to be erased and restart the 50 us timeout. During the timeout,
status bit DQ3 is cleared. After the time out, DQ3 is asserted during
erasure.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20190426162624.55977-9-stephen.checkoway@oberlin.edu>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c   | 94 +++++++++++++++++++++++++++++++--------
 tests/pflash-cfi02-test.c | 70 +++++++++++++++++++++++++----
 2 files changed, 137 insertions(+), 27 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 39daa95833..5874bd55ad 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -31,7 +31,6 @@
  * It does not support flash interleaving.
  * It does not implement software data protection as found in many real chips
  * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
  */
 
 #include "qemu/osdep.h"
@@ -106,6 +105,7 @@ struct PFlashCFI02 {
     MemoryRegion orig_mem;
     int rom_mode;
     int read_counter; /* used for lazy switch-back to rom mode */
+    int sectors_to_erase;
     char *name;
     void *storage;
 };
@@ -135,6 +135,22 @@ static inline void toggle_dq6(PFlashCFI02 *pfl)
     pfl->status ^= 0x40;
 }
 
+/*
+ * Turn on DQ3.
+ */
+static inline void assert_dq3(PFlashCFI02 *pfl)
+{
+    pfl->status |= 0x08;
+}
+
+/*
+ * Turn off DQ3.
+ */
+static inline void reset_dq3(PFlashCFI02 *pfl)
+{
+    pfl->status &= ~0x08;
+}
+
 /*
  * Set up replicated mappings of the same region.
  */
@@ -163,11 +179,37 @@ static size_t pflash_regions_count(PFlashCFI02 *pfl)
     return pfl->cfi_table[0x2c];
 }
 
-static void pflash_timer (void *opaque)
+static void pflash_timer(void *opaque)
 {
     PFlashCFI02 *pfl = opaque;
 
     trace_pflash_timer_expired(pfl->cmd);
+    if (pfl->cmd == 0x30) {
+        /*
+         * Sector erase. If DQ3 is 0 when the timer expires, then the 50
+         * us erase timeout has expired so we need to start the timer for the
+         * sector erase algorithm. Otherwise, the erase completed and we should
+         * go back to read array mode.
+         */
+        if ((pfl->status & 0x08) == 0) {
+            assert_dq3(pfl);
+            /*
+             * CFI address 0x21 is "Typical timeout per individual block erase
+             * 2^N ms"
+             */
+            uint64_t timeout = ((1ULL << pfl->cfi_table[0x21]) *
+                                pfl->sectors_to_erase) * 1000000;
+            timer_mod(&pfl->timer,
+                      qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
+            DPRINTF("%s: erase timeout fired; erasing %d sectors\n",
+                    __func__, pfl->sectors_to_erase);
+            return;
+        }
+        DPRINTF("%s: sector erase complete\n", __func__);
+        pfl->sectors_to_erase = 0;
+        reset_dq3(pfl);
+    }
+
     /* Reset flash */
     toggle_dq7(pfl);
     if (pfl->bypass) {
@@ -299,6 +341,24 @@ static void pflash_update(PFlashCFI02 *pfl, int offset, int size)
     }
 }
 
+static void pflash_sector_erase(PFlashCFI02 *pfl, hwaddr offset)
+{
+    uint64_t sector_len = pflash_sector_len(pfl, offset);
+    offset &= ~(sector_len - 1);
+    DPRINTF("%s: start sector erase at %0*" PRIx64 "-%0*" PRIx64 "\n",
+            __func__, pfl->width * 2, offset,
+            pfl->width * 2, offset + sector_len - 1);
+    if (!pfl->ro) {
+        uint8_t *p = pfl->storage;
+        memset(p + offset, 0xff, sector_len);
+        pflash_update(pfl, offset, sector_len);
+    }
+    set_dq7(pfl, 0x00);
+    ++pfl->sectors_to_erase;
+    /* Set (or reset) the 50 us timer for additional erase commands.  */
+    timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 50000);
+}
+
 static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
                          unsigned int width)
 {
@@ -306,7 +366,6 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     hwaddr boff;
     uint8_t *p;
     uint8_t cmd;
-    uint32_t sector_len;
 
     trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
     cmd = value;
@@ -469,20 +528,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             break;
         case 0x30:
             /* Sector erase */
-            p = pfl->storage;
-            sector_len = pflash_sector_len(pfl, offset);
-            offset &= ~(sector_len - 1);
-            DPRINTF("%s: start sector erase at %0*" PRIx64 "-%0*" PRIx64 "\n",
-                    __func__, pfl->width * 2, offset,
-                    pfl->width * 2, offset + sector_len - 1);
-            if (!pfl->ro) {
-                memset(p + offset, 0xff, sector_len);
-                pflash_update(pfl, offset, sector_len);
-            }
-            set_dq7(pfl, 0x00);
-            /* Let's wait 1/2 second before sector erase is done */
-            timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
-                      (NANOSECONDS_PER_SECOND / 2));
+            pflash_sector_erase(pfl, offset);
             break;
         default:
             DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
@@ -496,7 +542,19 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             /* Ignore writes during chip erase */
             return;
         case 0x30:
-            /* Ignore writes during sector erase */
+            /*
+             * If DQ3 is 0, additional sector erase commands can be
+             * written and anything else (other than an erase suspend) resets
+             * the device.
+             */
+            if ((pfl->status & 0x08) == 0) {
+                if (cmd == 0x30) {
+                    pflash_sector_erase(pfl, offset);
+                } else {
+                    goto reset_flash;
+                }
+            }
+            /* Ignore writes during the actual erase. */
             return;
         default:
             /* Should never happen */
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index 00e2261742..303bc87820 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -35,6 +35,7 @@ typedef struct {
 #define CFI_CMD 0x98
 #define UNLOCK0_CMD 0xAA
 #define UNLOCK1_CMD 0x55
+#define SECOND_UNLOCK_CMD 0x80
 #define AUTOSELECT_CMD 0x90
 #define RESET_CMD 0xF0
 #define PROGRAM_CMD 0xA0
@@ -196,7 +197,7 @@ static void reset(const FlashConfig *c)
 static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
 {
     unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, 0x80);
+    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
     unlock(c);
     flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
 }
@@ -235,7 +236,7 @@ static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
 static void chip_erase(const FlashConfig *c)
 {
     unlock(c);
-    flash_cmd(c, UNLOCK0_ADDR, 0x80);
+    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
     unlock(c);
     flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
 }
@@ -315,6 +316,8 @@ static void test_geometry(const void *opaque)
 
     const uint64_t dq7 = replicate(c, 0x80);
     const uint64_t dq6 = replicate(c, 0x40);
+    const uint64_t dq3 = replicate(c, 0x08);
+
     uint64_t byte_addr = 0;
     for (int region = 0; region < nb_erase_regions; ++region) {
         uint64_t base = 0x2D + 4 * region;
@@ -330,18 +333,29 @@ static void test_geometry(const void *opaque)
         /* Erase and program sector. */
         for (uint32_t i = 0; i < nb_sectors; ++i) {
             sector_erase(c, byte_addr);
-            /* Read toggle. */
+
+            /* Check that DQ3 is 0. */
+            g_assert_cmphex(flash_read(c, byte_addr) & dq3, ==, 0);
+            qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
+
+            /* Check that DQ3 is 1. */
             uint64_t status0 = flash_read(c, byte_addr);
+            g_assert_cmphex(status0 & dq3, ==, dq3);
+
             /* DQ7 is 0 during an erase. */
             g_assert_cmphex(status0 & dq7, ==, 0);
             uint64_t status1 = flash_read(c, byte_addr);
+
             /* DQ6 toggles during an erase. */
             g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
+
             /* Wait for erase to complete. */
-            qtest_clock_step_next(c->qtest);
+            wait_for_completion(c, byte_addr);
+
             /* Ensure DQ6 has stopped toggling. */
             g_assert_cmphex(flash_read(c, byte_addr), ==,
                             flash_read(c, byte_addr));
+
             /* Now the data should be valid. */
             g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
 
@@ -404,6 +418,44 @@ static void test_geometry(const void *opaque)
     g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
     reset(c);
 
+    /*
+     * Program a word on each sector, erase one or two sectors per region, and
+     * verify that all of those, and only those, are erased.
+     */
+    byte_addr = 0;
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        for (int i = 0; i < config->nb_blocs[region]; ++i) {
+            program(c, byte_addr, 0);
+            byte_addr += config->sector_len[region];
+        }
+    }
+    unlock(c);
+    flash_cmd(c, UNLOCK0_ADDR, SECOND_UNLOCK_CMD);
+    unlock(c);
+    byte_addr = 0;
+    const uint64_t erase_cmd = replicate(c, SECTOR_ERASE_CMD);
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        flash_write(c, byte_addr, erase_cmd);
+        if (c->nb_blocs[region] > 1) {
+            flash_write(c, byte_addr + c->sector_len[region], erase_cmd);
+        }
+        byte_addr += c->sector_len[region] * c->nb_blocs[region];
+    }
+
+    qtest_clock_step_next(c->qtest); /* Step over the 50 us timeout. */
+    wait_for_completion(c, 0);
+    byte_addr = 0;
+    for (int region = 0; region < nb_erase_regions; ++region) {
+        for (int i = 0; i < config->nb_blocs[region]; ++i) {
+            if (i < 2) {
+                g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
+            } else {
+                g_assert_cmphex(flash_read(c, byte_addr), ==, 0);
+            }
+            byte_addr += config->sector_len[region];
+        }
+    }
+
     qtest_quit(qtest);
 }
 
@@ -428,17 +480,17 @@ static void test_cfi_in_autoselect(const void *opaque)
     /* 1. Enter autoselect. */
     unlock(c);
     flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
 
     /* 2. Enter CFI. */
     flash_cmd(c, CFI_ADDR, CFI_CMD);
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
 
     /* 3. Exit CFI. */
     reset(c);
-    g_assert_cmpint(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
+    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
 
     qtest_quit(qtest);
 }
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 24/28] hw/block/pflash_cfi02: Implement erase suspend/resume
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (22 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 23/28] hw/block/pflash_cfi02: Implement multi-sector erase Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 25/28] hw/block/pflash_cfi02: Use chip erase time specified in the CFI table Philippe Mathieu-Daudé
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

During a sector erase (but not a chip erase), the embeded erase program
can be suspended. Once suspended, the sectors not selected for erasure
may be read and programmed. Autoselect mode is allowed during erase
suspend mode. Presumably, CFI queries are similarly allowed so this
commit allows them as well.

Since guest firmware can use status bits DQ7, DQ6, DQ3, and DQ2 to
determine the current state of sector erasure, these bits are properly
implemented.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20190426162624.55977-10-stephen.checkoway@oberlin.edu>
[PMD: Rebased]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c   | 154 ++++++++++++++++++++++++++++++++++----
 tests/pflash-cfi02-test.c | 110 +++++++++++++++++++++++++++
 2 files changed, 250 insertions(+), 14 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 5874bd55ad..a3665da3b8 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -30,7 +30,6 @@
  *
  * It does not support flash interleaving.
  * It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
  */
 
 #include "qemu/osdep.h"
@@ -38,6 +37,7 @@
 #include "hw/block/block.h"
 #include "hw/block/flash.h"
 #include "qapi/error.h"
+#include "qemu/bitmap.h"
 #include "qemu/timer.h"
 #include "sysemu/block-backend.h"
 #include "qemu/host-utils.h"
@@ -76,6 +76,7 @@ struct PFlashCFI02 {
     BlockBackend *blk;
     uint32_t uniform_nb_blocs;
     uint32_t uniform_sector_len;
+    uint32_t total_sectors;
     uint32_t nb_blocs[PFLASH_MAX_ERASE_REGIONS];
     uint32_t sector_len[PFLASH_MAX_ERASE_REGIONS];
     uint32_t chip_len;
@@ -106,6 +107,8 @@ struct PFlashCFI02 {
     int rom_mode;
     int read_counter; /* used for lazy switch-back to rom mode */
     int sectors_to_erase;
+    uint64_t erase_time_remaining;
+    unsigned long *sector_erase_map;
     char *name;
     void *storage;
 };
@@ -151,6 +154,14 @@ static inline void reset_dq3(PFlashCFI02 *pfl)
     pfl->status &= ~0x08;
 }
 
+/*
+ * Toggle status bit DQ2.
+ */
+static inline void toggle_dq2(PFlashCFI02 *pfl)
+{
+    pfl->status ^= 0x04;
+}
+
 /*
  * Set up replicated mappings of the same region.
  */
@@ -179,6 +190,29 @@ static size_t pflash_regions_count(PFlashCFI02 *pfl)
     return pfl->cfi_table[0x2c];
 }
 
+/*
+ * Returns the time it takes to erase the number of sectors scheduled for
+ * erasure based on CFI address 0x21 which is "Typical timeout per individual
+ * block erase 2^N ms."
+ */
+static uint64_t pflash_erase_time(PFlashCFI02 *pfl)
+{
+    /*
+     * If there are no sectors to erase (which can happen if all of the sectors
+     * to be erased are protected), then erase takes 100 us. Protected sectors
+     * aren't supported so this should never happen.
+     */
+    return ((1ULL << pfl->cfi_table[0x21]) * pfl->sectors_to_erase) * SCALE_US;
+}
+
+/*
+ * Returns true if the device is currently in erase suspend mode.
+ */
+static inline bool pflash_erase_suspend_mode(PFlashCFI02 *pfl)
+{
+    return pfl->erase_time_remaining > 0;
+}
+
 static void pflash_timer(void *opaque)
 {
     PFlashCFI02 *pfl = opaque;
@@ -193,12 +227,7 @@ static void pflash_timer(void *opaque)
          */
         if ((pfl->status & 0x08) == 0) {
             assert_dq3(pfl);
-            /*
-             * CFI address 0x21 is "Typical timeout per individual block erase
-             * 2^N ms"
-             */
-            uint64_t timeout = ((1ULL << pfl->cfi_table[0x21]) *
-                                pfl->sectors_to_erase) * 1000000;
+            uint64_t timeout = pflash_erase_time(pfl);
             timer_mod(&pfl->timer,
                       qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + timeout);
             DPRINTF("%s: erase timeout fired; erasing %d sectors\n",
@@ -206,6 +235,7 @@ static void pflash_timer(void *opaque)
             return;
         }
         DPRINTF("%s: sector erase complete\n", __func__);
+        bitmap_zero(pfl->sector_erase_map, pfl->total_sectors);
         pfl->sectors_to_erase = 0;
         reset_dq3(pfl);
     }
@@ -233,24 +263,44 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
     return ret;
 }
 
+typedef struct {
+    uint32_t len;
+    uint32_t num;
+} SectorInfo;
+
 /*
  * offset should be a byte offset of the QEMU device and _not_ a device
  * offset.
  */
-static uint32_t pflash_sector_len(PFlashCFI02 *pfl, hwaddr offset)
+static SectorInfo pflash_sector_info(PFlashCFI02 *pfl, hwaddr offset)
 {
     assert(offset < pfl->chip_len);
     hwaddr addr = 0;
+    uint32_t sector_num = 0;
     for (int i = 0; i < pflash_regions_count(pfl); ++i) {
         uint64_t region_size = (uint64_t)pfl->nb_blocs[i] * pfl->sector_len[i];
         if (addr <= offset && offset < addr + region_size) {
-            return pfl->sector_len[i];
+            return (SectorInfo) {
+                .len = pfl->sector_len[i],
+                .num = sector_num + (offset - addr) / pfl->sector_len[i],
+            };
         }
+        sector_num += pfl->nb_blocs[i];
         addr += region_size;
     }
     abort();
 }
 
+/*
+ * Returns true if the offset refers to a flash sector that is currently being
+ * erased.
+ */
+static bool pflash_sector_is_erasing(PFlashCFI02 *pfl, hwaddr offset)
+{
+    long sector_num = pflash_sector_info(pfl, offset).num;
+    return test_bit(sector_num, pfl->sector_erase_map);
+}
+
 static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
 {
     PFlashCFI02 *pfl = opaque;
@@ -280,6 +330,15 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
     case 0x80:
         /* We accept reads during second unlock sequence... */
     case 0x00:
+        if (pflash_erase_suspend_mode(pfl) &&
+            pflash_sector_is_erasing(pfl, offset)) {
+            /* Toggle bit 2, but not 6. */
+            toggle_dq2(pfl);
+            /* Status register read */
+            ret = pfl->status;
+            DPRINTF("%s: status %" PRIx64 "\n", __func__, ret);
+            break;
+        }
         /* Flash area read */
         ret = pflash_data_read(pfl, offset, width);
         break;
@@ -305,13 +364,16 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
         }
         DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx64 "\n", __func__, boff, ret);
         break;
-    case 0xA0:
     case 0x10:
     case 0x30:
+        /* Toggle bit 2 during erase, but not program. */
+        toggle_dq2(pfl);
+    case 0xA0:
+        /* Toggle bit 6 */
+        toggle_dq6(pfl);
         /* Status register read */
         ret = pfl->status;
         DPRINTF("%s: status %" PRIx64 "\n", __func__, ret);
-        toggle_dq6(pfl);
         break;
     case 0x98:
         /* CFI query mode */
@@ -343,7 +405,8 @@ static void pflash_update(PFlashCFI02 *pfl, int offset, int size)
 
 static void pflash_sector_erase(PFlashCFI02 *pfl, hwaddr offset)
 {
-    uint64_t sector_len = pflash_sector_len(pfl, offset);
+    SectorInfo sector_info = pflash_sector_info(pfl, offset);
+    uint64_t sector_len = sector_info.len;
     offset &= ~(sector_len - 1);
     DPRINTF("%s: start sector erase at %0*" PRIx64 "-%0*" PRIx64 "\n",
             __func__, pfl->width * 2, offset,
@@ -355,6 +418,7 @@ static void pflash_sector_erase(PFlashCFI02 *pfl, hwaddr offset)
     }
     set_dq7(pfl, 0x00);
     ++pfl->sectors_to_erase;
+    set_bit(sector_info.num, pfl->sector_erase_map);
     /* Set (or reset) the 50 us timer for additional erase commands.  */
     timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 50000);
 }
@@ -405,6 +469,25 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             pfl->cmd = 0x98;
             return;
         }
+        /* Handle erase resume in erase suspend mode, otherwise reset. */
+        if (cmd == 0x30) {
+            if (pflash_erase_suspend_mode(pfl)) {
+                /* Resume the erase. */
+                timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+                          pfl->erase_time_remaining);
+                pfl->erase_time_remaining = 0;
+                pfl->wcycle = 6;
+                pfl->cmd = 0x30;
+                set_dq7(pfl, 0x00);
+                assert_dq3(pfl);
+                return;
+            }
+            goto reset_flash;
+        }
+        /* Ignore erase suspend. */
+        if (cmd == 0xB0) {
+            return;
+        }
         if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
             DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
                     __func__, boff, cmd, pfl->unlock_addr0);
@@ -450,6 +533,14 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             /* We need another unlock sequence */
             goto check_unlock0;
         case 0xA0:
+            if (pflash_erase_suspend_mode(pfl) &&
+                pflash_sector_is_erasing(pfl, offset)) {
+                /* Ignore writes to erasing sectors. */
+                if (pfl->bypass) {
+                    goto do_bypass;
+                }
+                goto reset_flash;
+            }
             trace_pflash_data_write(offset, width << 1, value, 0);
             if (!pfl->ro) {
                 p = (uint8_t *)pfl->storage + offset;
@@ -508,6 +599,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         }
         break;
     case 5:
+        if (pflash_erase_suspend_mode(pfl)) {
+            /* Erasing is not supported in erase suspend mode. */
+            goto reset_flash;
+        }
         switch (cmd) {
         case 0x10:
             if (boff != pfl->unlock_addr0) {
@@ -542,6 +637,30 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             /* Ignore writes during chip erase */
             return;
         case 0x30:
+            if (cmd == 0xB0) {
+                /*
+                 * If erase suspend happens during the erase timeout (so DQ3 is
+                 * 0), then the device suspends erasing immediately. Set the
+                 * remaining time to be the total time to erase. Otherwise,
+                 * there is a maximum amount of time it can take to enter
+                 * suspend mode. Let's ignore that and suspend immediately and
+                 * set the remaining time to the actual time remaining on the
+                 * timer.
+                 */
+                if ((pfl->status & 0x08) == 0) {
+                    pfl->erase_time_remaining = pflash_erase_time(pfl);
+                } else {
+                    int64_t delta = timer_expire_time_ns(&pfl->timer) -
+                        qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+                    /* Make sure we have a positive time remaining. */
+                    pfl->erase_time_remaining = delta <= 0 ? 1 : delta;
+                }
+                reset_dq3(pfl);
+                timer_del(&pfl->timer);
+                pfl->wcycle = 0;
+                pfl->cmd = 0;
+                return;
+            }
             /*
              * If DQ3 is 0, additional sector erase commands can be
              * written and anything else (other than an erase suspend) resets
@@ -619,10 +738,12 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 
     int nb_regions;
     pfl->chip_len = 0;
+    pfl->total_sectors = 0;
     for (nb_regions = 0; nb_regions < PFLASH_MAX_ERASE_REGIONS; ++nb_regions) {
         if (pfl->nb_blocs[nb_regions] == 0) {
             break;
         }
+        pfl->total_sectors += pfl->nb_blocs[nb_regions];
         uint64_t sector_len_per_device = pfl->sector_len[nb_regions];
 
         /*
@@ -656,6 +777,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
         pfl->nb_blocs[0] = pfl->uniform_nb_blocs;
         pfl->sector_len[0] = pfl->uniform_sector_len;
         pfl->chip_len = uniform_len;
+        pfl->total_sectors = pfl->uniform_nb_blocs;
     } else if (uniform_len != 0 && uniform_len != pfl->chip_len) {
         error_setg(errp, "\"num-blocks\"*\"sector-length\" "
                    "different from \"num-blocks0\"*\'sector-length0\" + ... + "
@@ -697,6 +819,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->unlock_addr0 &= 0x7FF;
     pfl->unlock_addr1 &= 0x7FF;
 
+    /* Allocate memory for a bitmap for sectors being erased. */
+    pfl->sector_erase_map = bitmap_new(pfl->total_sectors);
+
     pflash_setup_mappings(pfl);
     pfl->rom_mode = 1;
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
@@ -781,8 +906,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
 
     /* Address sensitive unlock required. */
     pfl->cfi_table[0x05 + pri_ofs] = 0x00;
-    /* Erase suspend not supported. */
-    pfl->cfi_table[0x06 + pri_ofs] = 0x00;
+    /* Erase suspend to read/write. */
+    pfl->cfi_table[0x06 + pri_ofs] = 0x02;
     /* Sector protect not supported. */
     pfl->cfi_table[0x07 + pri_ofs] = 0x00;
     /* Temporary sector unprotect not supported. */
@@ -829,6 +954,7 @@ static void pflash_cfi02_unrealize(DeviceState *dev, Error **errp)
 {
     PFlashCFI02 *pfl = PFLASH_CFI02(dev);
     timer_del(&pfl->timer);
+    g_free(pfl->sector_erase_map);
 }
 
 static void pflash_cfi02_class_init(ObjectClass *klass, void *data)
diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
index 303bc87820..d3b23f4f66 100644
--- a/tests/pflash-cfi02-test.c
+++ b/tests/pflash-cfi02-test.c
@@ -43,6 +43,8 @@ typedef struct {
 #define CHIP_ERASE_CMD 0x10
 #define UNLOCK_BYPASS_CMD 0x20
 #define UNLOCK_BYPASS_RESET_CMD 0x00
+#define ERASE_SUSPEND_CMD 0xB0
+#define ERASE_RESUME_CMD SECTOR_ERASE_CMD
 
 typedef struct {
     int bank_width;
@@ -241,6 +243,16 @@ static void chip_erase(const FlashConfig *c)
     flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
 }
 
+static void erase_suspend(const FlashConfig *c)
+{
+    flash_cmd(c, FLASH_ADDR(0), ERASE_SUSPEND_CMD);
+}
+
+static void erase_resume(const FlashConfig *c)
+{
+    flash_cmd(c, FLASH_ADDR(0), ERASE_RESUME_CMD);
+}
+
 /*
  * Test flash commands with a variety of device geometry.
  */
@@ -312,11 +324,20 @@ static void test_geometry(const void *opaque)
     uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
     g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
 
+    /* Check that erase suspend to read/write is supported. */
+    uint16_t pri = flash_query_1(c, FLASH_ADDR(0x15)) +
+                   (flash_query_1(c, FLASH_ADDR(0x16)) << 8);
+    g_assert_cmpint(pri, >=, 0x2D + 4 * nb_erase_regions);
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 0)), ==, replicate(c, 'P'));
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 1)), ==, replicate(c, 'R'));
+    g_assert_cmpint(flash_query(c, FLASH_ADDR(pri + 2)), ==, replicate(c, 'I'));
+    g_assert_cmpint(flash_query_1(c, FLASH_ADDR(pri + 6)), ==, 2); /* R/W */
     reset(c);
 
     const uint64_t dq7 = replicate(c, 0x80);
     const uint64_t dq6 = replicate(c, 0x40);
     const uint64_t dq3 = replicate(c, 0x08);
+    const uint64_t dq2 = replicate(c, 0x04);
 
     uint64_t byte_addr = 0;
     for (int region = 0; region < nb_erase_regions; ++region) {
@@ -456,6 +477,95 @@ static void test_geometry(const void *opaque)
         }
     }
 
+    /* Test erase suspend/resume during erase timeout. */
+    sector_erase(c, 0);
+    /*
+     * Check that DQ 3 is 0 and DQ6 and DQ2 are toggling in the sector being
+     * erased as well as in a sector not being erased.
+     */
+    byte_addr = c->sector_len[0];
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, 0);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, 0);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+
+    /*
+     * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
+     * an erase suspended sector but that neither toggle (we should be
+     * getting data) in a sector not being erased.
+     */
+    erase_suspend(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+
+    /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
+    erase_resume(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    wait_for_completion(c, 0);
+
+    /* Repeat this process but this time suspend after the timeout. */
+    sector_erase(c, 0);
+    qtest_clock_step_next(c->qtest);
+    /*
+     * Check that DQ 3 is 1 and DQ6 and DQ2 are toggling in the sector being
+     * erased as well as in a sector not being erased.
+     */
+    byte_addr = c->sector_len[0];
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+
+    /*
+     * Check that after suspending, DQ6 does not toggle but DQ2 does toggle in
+     * an erase suspended sector but that neither toggle (we should be
+     * getting data) in a sector not being erased.
+     */
+    erase_suspend(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq6, ==, status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    g_assert_cmpint(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
+
+    /* Check that after resuming, DQ3 is 1 and DQ6 and DQ2 toggle. */
+    erase_resume(c);
+    status0 = flash_read(c, 0);
+    status1 = flash_read(c, 0);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    status0 = flash_read(c, byte_addr);
+    status1 = flash_read(c, byte_addr);
+    g_assert_cmpint(status0 & dq3, ==, dq3);
+    g_assert_cmpint(status0 & dq6, ==, ~status1 & dq6);
+    g_assert_cmpint(status0 & dq2, ==, ~status1 & dq2);
+    wait_for_completion(c, 0);
+
     qtest_quit(qtest);
 }
 
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 25/28] hw/block/pflash_cfi02: Use chip erase time specified in the CFI table
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (23 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 24/28] hw/block/pflash_cfi02: Implement erase suspend/resume Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 23:12   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 26/28] hw/block/pflash_cfi02: Reduce single byte/word write delay Philippe Mathieu-Daudé
                   ` (2 subsequent siblings)
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

From: Stephen Checkoway <stephen.checkoway@oberlin.edu>

When erasing the chip, use the typical time specified in the CFI table
rather than arbitrarily selecting 5 seconds.

Since the currently unconfigurable value set in the table is 12, this
means a chip erase takes 4096 ms so this isn't a big change in behavior.

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-11-stephen.checkoway@oberlin.edu>
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
TODO check not zero
---
 hw/block/pflash_cfi02.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index a3665da3b8..b2d37c33bb 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -617,9 +617,9 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
                 pflash_update(pfl, 0, pfl->chip_len);
             }
             set_dq7(pfl, 0x00);
-            /* Let's wait 5 seconds before chip erase is done */
+            /* Wait the time specified at CFI address 0x22. */
             timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
-                      (NANOSECONDS_PER_SECOND * 5));
+                      (1ULL << pfl->cfi_table[0x22]) * SCALE_MS);
             break;
         case 0x30:
             /* Sector erase */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 26/28] hw/block/pflash_cfi02: Reduce single byte/word write delay
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (24 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 25/28] hw/block/pflash_cfi02: Use chip erase time specified in the CFI table Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 27/28] hw/block/pflash_cfi02: Document commands Philippe Mathieu-Daudé
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 28/28] hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit Philippe Mathieu-Daudé
  27 siblings, 0 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
Message-Id: <20190426162624.55977-5-stephen.checkoway@oberlin.edu>
[PMD: Extracted from bigger patch]
Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
TODO: Why? To respect the datasheet? Which model is this?
---
 hw/block/pflash_cfi02.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index b2d37c33bb..e9519cbae8 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -857,8 +857,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
     pfl->cfi_table[0x1D] = 0x00;
     /* Vpp max (no Vpp pin) */
     pfl->cfi_table[0x1E] = 0x00;
-    /* Timeout per single byte/word write (128 ms) */
-    pfl->cfi_table[0x1F] = 0x07;
+    /* Timeout per single byte/word write (16 us) */
+    pfl->cfi_table[0x1F] = 0x04;
     /* Timeout for min size buffer write (NA) */
     pfl->cfi_table[0x20] = 0x00;
     /* Typical timeout for block erase (512 ms) */
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 27/28] hw/block/pflash_cfi02: Document commands
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (25 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 26/28] hw/block/pflash_cfi02: Reduce single byte/word write delay Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 23:13   ` Alistair Francis
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 28/28] hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit Philippe Mathieu-Daudé
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 40 +++++++++++++++++++---------------------
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index e9519cbae8..db9dc7d8fb 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -327,7 +327,7 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
         pfl->wcycle = 0;
         pfl->cmd = 0;
         /* fall through to the read code */
-    case 0x80:
+    case 0x80: /* Erase (unlock) */
         /* We accept reads during second unlock sequence... */
     case 0x00:
         if (pflash_erase_suspend_mode(pfl) &&
@@ -342,8 +342,7 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
         /* Flash area read */
         ret = pflash_data_read(pfl, offset, width);
         break;
-    case 0x90:
-        /* flash ID read */
+    case 0x90: /* flash ID read */
         switch (boff) {
         case 0x00:
         case 0x01:
@@ -364,11 +363,11 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
         }
         DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx64 "\n", __func__, boff, ret);
         break;
-    case 0x10:
-    case 0x30:
+    case 0x10: /* Chip Erase */
+    case 0x30: /* Sector Erase */
         /* Toggle bit 2 during erase, but not program. */
         toggle_dq2(pfl);
-    case 0xA0:
+    case 0xA0: /* Program */
         /* Toggle bit 6 */
         toggle_dq6(pfl);
         /* Status register read */
@@ -470,7 +469,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             return;
         }
         /* Handle erase resume in erase suspend mode, otherwise reset. */
-        if (cmd == 0x30) {
+        if (cmd == 0x30) { /* Erase Resume */
             if (pflash_erase_suspend_mode(pfl)) {
                 /* Resume the erase. */
                 timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
@@ -485,7 +484,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             goto reset_flash;
         }
         /* Ignore erase suspend. */
-        if (cmd == 0xB0) {
+        if (cmd == 0xB0) { /* Erase Suspend */
             return;
         }
         if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
@@ -516,9 +515,9 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         case 0x20:
             pfl->bypass = 1;
             goto do_bypass;
-        case 0x80:
-        case 0x90:
-        case 0xA0:
+        case 0x80: /* Erase */
+        case 0x90: /* Autoselect */
+        case 0xA0: /* Program */
             pfl->cmd = cmd;
             DPRINTF("%s: starting command %02x\n", __func__, cmd);
             break;
@@ -529,10 +528,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         break;
     case 3:
         switch (pfl->cmd) {
-        case 0x80:
+        case 0x80: /* Erase */
             /* We need another unlock sequence */
             goto check_unlock0;
-        case 0xA0:
+        case 0xA0: /* Program */
             if (pflash_erase_suspend_mode(pfl) &&
                 pflash_sector_is_erasing(pfl, offset)) {
                 /* Ignore writes to erasing sectors. */
@@ -562,7 +561,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             if (pfl->bypass)
                 goto do_bypass;
             goto reset_flash;
-        case 0x90:
+        case 0x90: /* Autoselect */
             if (pfl->bypass && cmd == 0x00) {
                 /* Unlock bypass reset */
                 goto reset_flash;
@@ -585,11 +584,11 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         }
     case 4:
         switch (pfl->cmd) {
-        case 0xA0:
+        case 0xA0: /* Program */
             /* Ignore writes while flash data write is occurring */
             /* As we suppose write is immediate, this should never happen */
             return;
-        case 0x80:
+        case 0x80: /* Erase */
             goto check_unlock1;
         default:
             /* Should never happen */
@@ -604,7 +603,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             goto reset_flash;
         }
         switch (cmd) {
-        case 0x10:
+        case 0x10: /* Chip Erase */
             if (boff != pfl->unlock_addr0) {
                 DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
                         __func__, offset);
@@ -621,8 +620,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
             timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
                       (1ULL << pfl->cfi_table[0x22]) * SCALE_MS);
             break;
-        case 0x30:
-            /* Sector erase */
+        case 0x30: /* Sector erase */
             pflash_sector_erase(pfl, offset);
             break;
         default:
@@ -633,10 +631,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
         break;
     case 6:
         switch (pfl->cmd) {
-        case 0x10:
+        case 0x10: /* Chip Erase */
             /* Ignore writes during chip erase */
             return;
-        case 0x30:
+        case 0x30: /* Sector erase */
             if (cmd == 0xB0) {
                 /*
                  * If erase suspend happens during the erase timeout (so DQ3 is
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* [Qemu-devel] [PATCH v5 28/28] hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit
  2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
                   ` (26 preceding siblings ...)
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 27/28] hw/block/pflash_cfi02: Document commands Philippe Mathieu-Daudé
@ 2019-06-27 20:27 ` Philippe Mathieu-Daudé
  2019-06-28 23:13   ` Alistair Francis
  27 siblings, 1 reply; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-27 20:27 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, John Snow, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Alex Bennée,
	Michael Walle, qemu-arm, qemu-ppc, Antony Pavlov,
	Edgar E. Iglesias, Jan Kiszka, Philippe Mathieu-Daudé,
	Aurelien Jarno, David Gibson

Parallel NOR flashes are limited to 16-bit bus accesses.
Remove the 32-bit dead code.

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 hw/block/pflash_cfi02.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index db9dc7d8fb..d1f28b02b9 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -317,8 +317,6 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
     boff = offset & 0xFF;
     if (pfl->width == 2) {
         boff = boff >> 1;
-    } else if (pfl->width == 4) {
-        boff = boff >> 2;
     }
     switch (pfl->cmd) {
     default:
@@ -449,8 +447,6 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
     boff = offset;
     if (pfl->width == 2) {
         boff = boff >> 1;
-    } else if (pfl->width == 4) {
-        boff = boff >> 2;
     }
     /* Only the least-significant 11 bits are used in most cases. */
     boff &= 0x7FF;
@@ -710,6 +706,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
 static const MemoryRegionOps pflash_cfi02_ops = {
     .read = pflash_read,
     .write = pflash_write,
+    .impl.max_access_size = 2,
     .valid.min_access_size = 1,
     .valid.max_access_size = 4,
     .endianness = DEVICE_NATIVE_ENDIAN,
-- 
2.20.1



^ permalink raw reply related	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write()
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write() Philippe Mathieu-Daudé
@ 2019-06-27 21:49   ` Stephen Checkoway
  2019-06-28 15:53     ` Alistair Francis
  2019-06-28 15:52   ` Alistair Francis
  1 sibling, 1 reply; 55+ messages in thread
From: Stephen Checkoway @ 2019-06-27 21:49 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, Markus Armbruster, Paolo Bonzini,
	Alistair Francis, Magnus Damm, qemu-devel, Max Reitz,
	Alex Bennée, Michael Walle, qemu-arm, qemu-ppc,
	Antony Pavlov, Edgar E. Iglesias, Jan Kiszka, John Snow,
	Aurelien Jarno, David Gibson

Hi Phil,

Thanks for pushing this forward! I'll try to get to the rest of these early next week.

> On Jun 27, 2019, at 16:26, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
> 
> Call the read() trace function after the value is set, so we can
> log the returned value.
> Rename the I/O trace functions with '_io_' in their name.
> 
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
> hw/block/pflash_cfi01.c | 5 +++--
> hw/block/pflash_cfi02.c | 6 ++----
> hw/block/trace-events   | 4 ++--
> 3 files changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
> index 35080d915f..74fc1bc2da 100644
> --- a/hw/block/pflash_cfi01.c
> +++ b/hw/block/pflash_cfi01.c
> @@ -288,7 +288,6 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
>     uint32_t ret;
> 
>     ret = -1;
> -    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
>     switch (pfl->cmd) {
>     default:
>         /* This should never happen : reset state & treat it as a read */
> @@ -391,6 +390,8 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
> 
>         break;
>     }
> +    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);

width * 2 might make it more clear what is going on.

> +
>     return ret;
> }
> 
> @@ -453,7 +454,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
> 
>     cmd = value;
> 
> -    trace_pflash_write(offset, value, width, pfl->wcycle);
> +    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);

Same here.

>     if (!pfl->wcycle) {
>         /* Set the device in I/O access mode */
>         memory_region_rom_device_set_romd(&pfl->mem, false);
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index eb106f4996..f05cd507b3 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -145,7 +145,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>     uint8_t *p;
> 
>     ret = -1;
> -    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
>     /* 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) {
> @@ -241,6 +240,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>         }
>         break;
>     }
> +    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);

And here.

> 
>     return ret;
> }
> @@ -267,6 +267,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>     uint8_t *p;
>     uint8_t cmd;
> 
> +    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);

And here.

>     cmd = value;
>     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
> #if 0
> @@ -275,11 +276,8 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
> #endif
>         goto reset_flash;
>     }
> -    trace_pflash_write(offset, value, width, pfl->wcycle);
>     offset &= pfl->chip_len - 1;
> 
> -    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
> -            offset, value, width);
>     boff = offset & (pfl->sector_len - 1);
>     if (pfl->width == 2)
>         boff = boff >> 1;
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 97a17838ed..f637fe918e 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -7,9 +7,9 @@ fdc_ioport_write(uint8_t reg, uint8_t value) "write reg 0x%02x val 0x%02x"
> # pflash_cfi02.c
> # pflash_cfi01.c
> pflash_reset(void) "reset"
> -pflash_read(uint64_t offset, uint8_t cmd, int width, uint8_t wcycle) "offset:0x%04"PRIx64" cmd:0x%02x width:%d wcycle:%u"
> -pflash_write(uint64_t offset, uint32_t value, int width, uint8_t wcycle) "offset:0x%04"PRIx64" value:0x%03x width:%d wcycle:%u"
> pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
> +pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
> +pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
> pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
> pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
> pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
> -- 
> 2.20.1
> 

Either way,

Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>

(And please let me know if I'm doing code review incorrectly or if that should be Reviewed-by or whatever.)

Cheers,

Steve 

-- 
Stephen Checkoway







^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write()
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write() Philippe Mathieu-Daudé
  2019-06-27 21:49   ` Stephen Checkoway
@ 2019-06-28 15:52   ` Alistair Francis
  1 sibling, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 15:52 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:38 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Call the read() trace function after the value is set, so we can
> log the returned value.
> Rename the I/O trace functions with '_io_' in their name.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi01.c | 5 +++--
>  hw/block/pflash_cfi02.c | 6 ++----
>  hw/block/trace-events   | 4 ++--
>  3 files changed, 7 insertions(+), 8 deletions(-)
>
> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
> index 35080d915f..74fc1bc2da 100644
> --- a/hw/block/pflash_cfi01.c
> +++ b/hw/block/pflash_cfi01.c
> @@ -288,7 +288,6 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
>      uint32_t ret;
>
>      ret = -1;
> -    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
>      switch (pfl->cmd) {
>      default:
>          /* This should never happen : reset state & treat it as a read */
> @@ -391,6 +390,8 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
>
>          break;
>      }
> +    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
> +
>      return ret;
>  }
>
> @@ -453,7 +454,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
>
>      cmd = value;
>
> -    trace_pflash_write(offset, value, width, pfl->wcycle);
> +    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>      if (!pfl->wcycle) {
>          /* Set the device in I/O access mode */
>          memory_region_rom_device_set_romd(&pfl->mem, false);
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index eb106f4996..f05cd507b3 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -145,7 +145,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>      uint8_t *p;
>
>      ret = -1;
> -    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
>      /* 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) {
> @@ -241,6 +240,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>          }
>          break;
>      }
> +    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
>
>      return ret;
>  }
> @@ -267,6 +267,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>      uint8_t *p;
>      uint8_t cmd;
>
> +    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>      cmd = value;
>      if (pfl->cmd != 0xA0 && cmd == 0xF0) {
>  #if 0
> @@ -275,11 +276,8 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>  #endif
>          goto reset_flash;
>      }
> -    trace_pflash_write(offset, value, width, pfl->wcycle);
>      offset &= pfl->chip_len - 1;
>
> -    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
> -            offset, value, width);
>      boff = offset & (pfl->sector_len - 1);
>      if (pfl->width == 2)
>          boff = boff >> 1;
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index 97a17838ed..f637fe918e 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -7,9 +7,9 @@ fdc_ioport_write(uint8_t reg, uint8_t value) "write reg 0x%02x val 0x%02x"
>  # pflash_cfi02.c
>  # pflash_cfi01.c
>  pflash_reset(void) "reset"
> -pflash_read(uint64_t offset, uint8_t cmd, int width, uint8_t wcycle) "offset:0x%04"PRIx64" cmd:0x%02x width:%d wcycle:%u"
> -pflash_write(uint64_t offset, uint32_t value, int width, uint8_t wcycle) "offset:0x%04"PRIx64" value:0x%03x width:%d wcycle:%u"
>  pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
> +pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
> +pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
>  pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
>  pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
>  pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write()
  2019-06-27 21:49   ` Stephen Checkoway
@ 2019-06-28 15:53     ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 15:53 UTC (permalink / raw)
  To: Stephen Checkoway
  Cc: Peter Maydell, qemu-devel@nongnu.org Developers,
	Edgar E. Iglesias, Qemu-block, John Snow, Magnus Damm,
	Markus Armbruster, Antony Pavlov, Philippe Mathieu-Daudé,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 2:50 PM Stephen Checkoway
<stephen.checkoway@oberlin.edu> wrote:
>
> Hi Phil,
>
> Thanks for pushing this forward! I'll try to get to the rest of these early next week.
>
> > On Jun 27, 2019, at 16:26, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
> >
> > Call the read() trace function after the value is set, so we can
> > log the returned value.
> > Rename the I/O trace functions with '_io_' in their name.
> >
> > Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> > ---
> > hw/block/pflash_cfi01.c | 5 +++--
> > hw/block/pflash_cfi02.c | 6 ++----
> > hw/block/trace-events   | 4 ++--
> > 3 files changed, 7 insertions(+), 8 deletions(-)
> >
> > diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
> > index 35080d915f..74fc1bc2da 100644
> > --- a/hw/block/pflash_cfi01.c
> > +++ b/hw/block/pflash_cfi01.c
> > @@ -288,7 +288,6 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
> >     uint32_t ret;
> >
> >     ret = -1;
> > -    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
> >     switch (pfl->cmd) {
> >     default:
> >         /* This should never happen : reset state & treat it as a read */
> > @@ -391,6 +390,8 @@ static uint32_t pflash_read(PFlashCFI01 *pfl, hwaddr offset,
> >
> >         break;
> >     }
> > +    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
>
> width * 2 might make it more clear what is going on.
>
> > +
> >     return ret;
> > }
> >
> > @@ -453,7 +454,7 @@ static void pflash_write(PFlashCFI01 *pfl, hwaddr offset,
> >
> >     cmd = value;
> >
> > -    trace_pflash_write(offset, value, width, pfl->wcycle);
> > +    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>
> Same here.
>
> >     if (!pfl->wcycle) {
> >         /* Set the device in I/O access mode */
> >         memory_region_rom_device_set_romd(&pfl->mem, false);
> > diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> > index eb106f4996..f05cd507b3 100644
> > --- a/hw/block/pflash_cfi02.c
> > +++ b/hw/block/pflash_cfi02.c
> > @@ -145,7 +145,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
> >     uint8_t *p;
> >
> >     ret = -1;
> > -    trace_pflash_read(offset, pfl->cmd, width, pfl->wcycle);
> >     /* 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) {
> > @@ -241,6 +240,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
> >         }
> >         break;
> >     }
> > +    trace_pflash_io_read(offset, width, width << 1, ret, pfl->cmd, pfl->wcycle);
>
> And here.
>
> >
> >     return ret;
> > }
> > @@ -267,6 +267,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
> >     uint8_t *p;
> >     uint8_t cmd;
> >
> > +    trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>
> And here.
>
> >     cmd = value;
> >     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
> > #if 0
> > @@ -275,11 +276,8 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
> > #endif
> >         goto reset_flash;
> >     }
> > -    trace_pflash_write(offset, value, width, pfl->wcycle);
> >     offset &= pfl->chip_len - 1;
> >
> > -    DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
> > -            offset, value, width);
> >     boff = offset & (pfl->sector_len - 1);
> >     if (pfl->width == 2)
> >         boff = boff >> 1;
> > diff --git a/hw/block/trace-events b/hw/block/trace-events
> > index 97a17838ed..f637fe918e 100644
> > --- a/hw/block/trace-events
> > +++ b/hw/block/trace-events
> > @@ -7,9 +7,9 @@ fdc_ioport_write(uint8_t reg, uint8_t value) "write reg 0x%02x val 0x%02x"
> > # pflash_cfi02.c
> > # pflash_cfi01.c
> > pflash_reset(void) "reset"
> > -pflash_read(uint64_t offset, uint8_t cmd, int width, uint8_t wcycle) "offset:0x%04"PRIx64" cmd:0x%02x width:%d wcycle:%u"
> > -pflash_write(uint64_t offset, uint32_t value, int width, uint8_t wcycle) "offset:0x%04"PRIx64" value:0x%03x width:%d wcycle:%u"
> > pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
> > +pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
> > +pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
> > pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
> > pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
> > pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
> > --
> > 2.20.1
> >
>
> Either way,
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
>
> (And please let me know if I'm doing code review incorrectly or if that should be Reviewed-by or whatever.)

For code review it should be Reviewed-by (or Acked-by if you are less sure).

Alistair

>
> Cheers,
>
> Steve
>
> --
> Stephen Checkoway
>
>
>
>
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 03/28] hw/block/pflash: Simplify trace_pflash_data_read/write()
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 03/28] hw/block/pflash: Simplify trace_pflash_data_read/write() Philippe Mathieu-Daudé
@ 2019-06-28 15:54   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 15:54 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:30 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Use a field width format to have a single function to log
> the different width accesses.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi01.c | 6 ++----
>  hw/block/pflash_cfi02.c | 6 ++----
>  hw/block/trace-events   | 6 ++----
>  3 files changed, 6 insertions(+), 12 deletions(-)
>
> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
> index 74fc1bc2da..db4a246b22 100644
> --- a/hw/block/pflash_cfi01.c
> +++ b/hw/block/pflash_cfi01.c
> @@ -248,7 +248,6 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
>      switch (width) {
>      case 1:
>          ret = p[offset];
> -        trace_pflash_data_read8(offset, ret);
>          break;
>      case 2:
>          if (be) {
> @@ -258,7 +257,6 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
>              ret = p[offset];
>              ret |= p[offset + 1] << 8;
>          }
> -        trace_pflash_data_read16(offset, ret);
>          break;
>      case 4:
>          if (be) {
> @@ -272,12 +270,12 @@ static uint32_t pflash_data_read(PFlashCFI01 *pfl, hwaddr offset,
>              ret |= p[offset + 2] << 16;
>              ret |= p[offset + 3] << 24;
>          }
> -        trace_pflash_data_read32(offset, ret);
>          break;
>      default:
>          DPRINTF("BUG in %s\n", __func__);
>          abort();
>      }
> +    trace_pflash_data_read(offset, width << 1, ret);
>      return ret;
>  }
>
> @@ -415,7 +413,7 @@ static inline void pflash_data_write(PFlashCFI01 *pfl, hwaddr offset,
>  {
>      uint8_t *p = pfl->storage;
>
> -    trace_pflash_data_write(offset, value, width, pfl->counter);
> +    trace_pflash_data_write(offset, width << 1, value, pfl->counter);
>      switch (width) {
>      case 1:
>          p[offset] = value;
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index f05cd507b3..6cdfc85264 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -172,7 +172,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>          switch (width) {
>          case 1:
>              ret = p[offset];
> -            trace_pflash_data_read8(offset, ret);
>              break;
>          case 2:
>              if (be) {
> @@ -182,7 +181,6 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>                  ret = p[offset];
>                  ret |= p[offset + 1] << 8;
>              }
> -            trace_pflash_data_read16(offset, ret);
>              break;
>          case 4:
>              if (be) {
> @@ -196,9 +194,9 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>                  ret |= p[offset + 2] << 16;
>                  ret |= p[offset + 3] << 24;
>              }
> -            trace_pflash_data_read32(offset, ret);
>              break;
>          }
> +        trace_pflash_data_read(offset, width << 1, ret);
>          break;
>      case 0x90:
>          /* flash ID read */
> @@ -343,7 +341,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>              /* We need another unlock sequence */
>              goto check_unlock0;
>          case 0xA0:
> -            trace_pflash_data_write(offset, value, width, 0);
> +            trace_pflash_data_write(offset, width << 1, value, 0);
>              p = pfl->storage;
>              if (!pfl->ro) {
>                  switch (width) {
> diff --git a/hw/block/trace-events b/hw/block/trace-events
> index f637fe918e..13d1b21dd4 100644
> --- a/hw/block/trace-events
> +++ b/hw/block/trace-events
> @@ -10,10 +10,8 @@ pflash_reset(void) "reset"
>  pflash_timer_expired(uint8_t cmd) "command 0x%02x done"
>  pflash_io_read(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t cmd, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x cmd:0x%02x wcycle:%u"
>  pflash_io_write(uint64_t offset, int width, int fmt_width, uint32_t value, uint8_t wcycle) "offset:0x%04"PRIx64" width:%d value:0x%0*x wcycle:%u"
> -pflash_data_read8(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%02x"
> -pflash_data_read16(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%04x"
> -pflash_data_read32(uint64_t offset, uint32_t value) "data offset:0x%04"PRIx64" value:0x%08x"
> -pflash_data_write(uint64_t offset, uint32_t value, int width, uint64_t counter) "data offset:0x%04"PRIx64" value:0x%08x width:%d counter:0x%016"PRIx64
> +pflash_data_read(uint64_t offset, int width, uint32_t value) "data offset:0x%04"PRIx64" value:0x%0*x"
> +pflash_data_write(uint64_t offset, int width, uint32_t value, uint64_t counter) "data offset:0x%04"PRIx64" value:0x%0*x counter:0x%016"PRIx64
>  pflash_manufacturer_id(uint16_t id) "Read Manufacturer ID: 0x%04x"
>  pflash_device_id(uint16_t id) "Read Device ID: 0x%04x"
>  pflash_device_info(uint64_t offset) "Read Device Information offset:0x%04"PRIx64
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 04/28] hw/block/pflash_cfi02: Fix debug format string
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 04/28] hw/block/pflash_cfi02: Fix debug format string Philippe Mathieu-Daudé
@ 2019-06-28 15:55   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 15:55 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:36 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Always compile the debug code to prevent format string to bitrot.
> Delete dead code.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch, use PRIx32]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 18 ++++++------------
>  1 file changed, 6 insertions(+), 12 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 6cdfc85264..43796e551a 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -47,15 +47,13 @@
>  #include "hw/sysbus.h"
>  #include "trace.h"
>
> -//#define PFLASH_DEBUG
> -#ifdef PFLASH_DEBUG
> +#define PFLASH_DEBUG false
>  #define DPRINTF(fmt, ...)                                  \
>  do {                                                       \
> -    fprintf(stderr, "PFLASH: " fmt , ## __VA_ARGS__);       \
> +    if (PFLASH_DEBUG) {                                    \
> +        fprintf(stderr, "PFLASH: " fmt, ## __VA_ARGS__);   \
> +    }                                                      \
>  } while (0)
> -#else
> -#define DPRINTF(fmt, ...) do { } while (0)
> -#endif
>
>  #define PFLASH_LAZY_ROMD_THRESHOLD 42
>
> @@ -218,14 +216,14 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>          default:
>              goto flash_read;
>          }
> -        DPRINTF("%s: ID " TARGET_FMT_plx " %x\n", __func__, boff, ret);
> +        DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx32 "\n", __func__, boff, ret);
>          break;
>      case 0xA0:
>      case 0x10:
>      case 0x30:
>          /* Status register read */
>          ret = pfl->status;
> -        DPRINTF("%s: status %x\n", __func__, ret);
> +        DPRINTF("%s: status %" PRIx32 "\n", __func__, ret);
>          /* Toggle bit 6 */
>          pfl->status ^= 0x40;
>          break;
> @@ -268,10 +266,6 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>      trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>      cmd = value;
>      if (pfl->cmd != 0xA0 && cmd == 0xF0) {
> -#if 0
> -        DPRINTF("%s: flash reset asked (%02x %02x)\n",
> -                __func__, pfl->cmd, cmd);
> -#endif
>          goto reset_flash;
>      }
>      offset &= pfl->chip_len - 1;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 05/28] hw/block/pflash_cfi02: Add an enum to define the write cycles
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 05/28] hw/block/pflash_cfi02: Add an enum to define the write cycles Philippe Mathieu-Daudé
@ 2019-06-28 15:56   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 15:56 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:44 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> No change in functionality is intended with this commit.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 43796e551a..303d225f23 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -57,6 +57,11 @@ do {                                                       \
>
>  #define PFLASH_LAZY_ROMD_THRESHOLD 42
>
> +/* Special write cycles for CFI queries. */
> +enum {
> +    WCYCLE_CFI              = 7,
> +};
> +
>  struct PFlashCFI02 {
>      /*< private >*/
>      SysBusDevice parent_obj;
> @@ -286,7 +291,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>          if (boff == 0x55 && cmd == 0x98) {
>          enter_CFI_mode:
>              /* Enter CFI query mode */
> -            pfl->wcycle = 7;
> +            pfl->wcycle = WCYCLE_CFI;
>              pfl->cmd = 0x98;
>              return;
>          }
> @@ -458,7 +463,8 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>              goto reset_flash;
>          }
>          break;
> -    case 7: /* Special value for CFI queries */
> +    /* Special values for CFI queries */
> +    case WCYCLE_CFI:
>          DPRINTF("%s: invalid write in CFI query mode\n", __func__);
>          goto reset_flash;
>      default:
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 06/28] hw/block/pflash_cfi02: Add helpers to manipulate the status bits
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 06/28] hw/block/pflash_cfi02: Add helpers to manipulate the status bits Philippe Mathieu-Daudé
@ 2019-06-28 16:00   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:00 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:49 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Pull out all of the code to modify the status into simple helper
> functions. Status handling becomes more complex once multiple
> chips are interleaved to produce a single device.
>
> No change in functionality is intended with this commit.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 40 ++++++++++++++++++++++++++++++++++------
>  1 file changed, 34 insertions(+), 6 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 303d225f23..e9eea0ec08 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -101,6 +101,31 @@ struct PFlashCFI02 {
>      void *storage;
>  };
>
> +/*
> + * Toggle status bit DQ7.
> + */
> +static inline void toggle_dq7(PFlashCFI02 *pfl)
> +{
> +    pfl->status ^= 0x80;
> +}
> +
> +/*
> + * Set status bit DQ7 to bit 7 of value.
> + */
> +static inline void set_dq7(PFlashCFI02 *pfl, uint8_t value)
> +{
> +    pfl->status &= 0x7F;
> +    pfl->status |= value & 0x80;
> +}
> +
> +/*
> + * Toggle status bit DQ6.
> + */
> +static inline void toggle_dq6(PFlashCFI02 *pfl)
> +{
> +    pfl->status ^= 0x40;
> +}
> +
>  /*
>   * Set up replicated mappings of the same region.
>   */
> @@ -130,7 +155,7 @@ static void pflash_timer (void *opaque)
>
>      trace_pflash_timer_expired(pfl->cmd);
>      /* Reset flash */
> -    pfl->status ^= 0x80;
> +    toggle_dq7(pfl);
>      if (pfl->bypass) {
>          pfl->wcycle = 2;
>      } else {
> @@ -229,8 +254,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>          /* Status register read */
>          ret = pfl->status;
>          DPRINTF("%s: status %" PRIx32 "\n", __func__, ret);
> -        /* Toggle bit 6 */
> -        pfl->status ^= 0x40;
> +        toggle_dq6(pfl);
>          break;
>      case 0x98:
>          /* CFI query mode */
> @@ -374,7 +398,11 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>                      break;
>                  }
>              }
> -            pfl->status = 0x00 | ~(value & 0x80);
> +            /*
> +             * While programming, status bit DQ7 should hold the opposite
> +             * value from how it was programmed.
> +             */
> +            set_dq7(pfl, ~value);
>              /* Let's pretend write is immediate */
>              if (pfl->bypass)
>                  goto do_bypass;
> @@ -422,7 +450,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>                  memset(pfl->storage, 0xFF, pfl->chip_len);
>                  pflash_update(pfl, 0, pfl->chip_len);
>              }
> -            pfl->status = 0x00;
> +            set_dq7(pfl, 0x00);
>              /* Let's wait 5 seconds before chip erase is done */
>              timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
>                        (NANOSECONDS_PER_SECOND * 5));
> @@ -437,7 +465,7 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>                  memset(p + offset, 0xFF, pfl->sector_len);
>                  pflash_update(pfl, offset, pfl->sector_len);
>              }
> -            pfl->status = 0x00;
> +            set_dq7(pfl, 0x00);
>              /* Let's wait 1/2 second before sector erase is done */
>              timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
>                        (NANOSECONDS_PER_SECOND / 2));
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 07/28] hw/block/pflash_cfi02: Simplify a statement using fall through
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 07/28] hw/block/pflash_cfi02: Simplify a statement using fall through Philippe Mathieu-Daudé
@ 2019-06-28 16:01   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:01 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:31 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index e9eea0ec08..9e8c28af8f 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -239,10 +239,10 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>          case 0x0E:
>          case 0x0F:
>              ret = boff & 0x01 ? pfl->ident3 : pfl->ident2;
> -            if (ret == (uint8_t)-1) {
> -                goto flash_read;
> +            if (ret != (uint8_t)-1) {
> +                break;
>              }
> -            break;
> +            /* Fall through to data read. */
>          default:
>              goto flash_read;
>          }
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 08/28] hw/block/pflash_cfi02: Use the ldst API in pflash_write()
  2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 08/28] hw/block/pflash_cfi02: Use the ldst API in pflash_write() Philippe Mathieu-Daudé
@ 2019-06-28 16:03   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:03 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:43 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> The load/store API eases code review.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 38 ++++++++------------------------------
>  1 file changed, 8 insertions(+), 30 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 9e8c28af8f..ae38ed0bae 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -365,38 +365,16 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>              goto check_unlock0;
>          case 0xA0:
>              trace_pflash_data_write(offset, width << 1, value, 0);
> -            p = pfl->storage;
>              if (!pfl->ro) {
> -                switch (width) {
> -                case 1:
> -                    p[offset] &= value;
> -                    pflash_update(pfl, offset, 1);
> -                    break;
> -                case 2:
> -                    if (be) {
> -                        p[offset] &= value >> 8;
> -                        p[offset + 1] &= value;
> -                    } else {
> -                        p[offset] &= value;
> -                        p[offset + 1] &= value >> 8;
> -                    }
> -                    pflash_update(pfl, offset, 2);
> -                    break;
> -                case 4:
> -                    if (be) {
> -                        p[offset] &= value >> 24;
> -                        p[offset + 1] &= value >> 16;
> -                        p[offset + 2] &= value >> 8;
> -                        p[offset + 3] &= value;
> -                    } else {
> -                        p[offset] &= value;
> -                        p[offset + 1] &= value >> 8;
> -                        p[offset + 2] &= value >> 16;
> -                        p[offset + 3] &= value >> 24;
> -                    }
> -                    pflash_update(pfl, offset, 4);
> -                    break;
> +                p = (uint8_t *)pfl->storage + offset;
> +                if (pfl->be) {
> +                    uint64_t current = ldn_be_p(p, width);
> +                    stn_be_p(p, width, current & value);
> +                } else {
> +                    uint64_t current = ldn_le_p(p, width);
> +                    stn_le_p(p, width, current & value);
>                  }
> +                pflash_update(pfl, offset, width);
>              }
>              /*
>               * While programming, status bit DQ7 should hold the opposite
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 09/28] hw/block/pflash_cfi02: Use the ldst API in pflash_read()
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 09/28] hw/block/pflash_cfi02: Use the ldst API in pflash_read() Philippe Mathieu-Daudé
@ 2019-06-28 16:03   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:03 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:54 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> The load/store API eases code review.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch, simplified tracing]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 32 +++++---------------------------
>  1 file changed, 5 insertions(+), 27 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index ae38ed0bae..49afecb921 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -196,33 +196,11 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>      case 0x00:
>      flash_read:
>          /* Flash area read */
> -        p = pfl->storage;
> -        switch (width) {
> -        case 1:
> -            ret = p[offset];
> -            break;
> -        case 2:
> -            if (be) {
> -                ret = p[offset] << 8;
> -                ret |= p[offset + 1];
> -            } else {
> -                ret = p[offset];
> -                ret |= p[offset + 1] << 8;
> -            }
> -            break;
> -        case 4:
> -            if (be) {
> -                ret = p[offset] << 24;
> -                ret |= p[offset + 1] << 16;
> -                ret |= p[offset + 2] << 8;
> -                ret |= p[offset + 3];
> -            } else {
> -                ret = p[offset];
> -                ret |= p[offset + 1] << 8;
> -                ret |= p[offset + 2] << 16;
> -                ret |= p[offset + 3] << 24;
> -            }
> -            break;
> +        p = (uint8_t *)pfl->storage + offset;
> +        if (pfl->be) {
> +            ret = ldn_be_p(p, width);
> +        } else {
> +            ret = ldn_le_p(p, width);
>          }
>          trace_pflash_data_read(offset, width << 1, ret);
>          break;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 10/28] hw/block/pflash_cfi02: Extract the pflash_data_read() function
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 10/28] hw/block/pflash_cfi02: Extract the pflash_data_read() function Philippe Mathieu-Daudé
@ 2019-06-28 16:17   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:17 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:46 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Extract the code block in a new function, remove a goto statement.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch, remove the XXX tracing comment]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 24 ++++++++++++++----------
>  1 file changed, 14 insertions(+), 10 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 49afecb921..c079a63880 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -165,12 +165,23 @@ static void pflash_timer (void *opaque)
>      pfl->cmd = 0;
>  }
>
> +/*
> + * Read data from flash.
> + */
> +static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
> +                                 unsigned int width)
> +{
> +    uint8_t *p = (uint8_t *)pfl->storage + offset;
> +    uint64_t ret = pfl->be ? ldn_be_p(p, width) : ldn_le_p(p, width);
> +    trace_pflash_data_read(offset, width << 1, ret);
> +    return ret;
> +}
> +
>  static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>                              int width, int be)
>  {
>      hwaddr boff;
>      uint32_t ret;
> -    uint8_t *p;
>
>      ret = -1;
>      /* Lazy reset to ROMD mode after a certain amount of read accesses */
> @@ -194,15 +205,8 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>      case 0x80:
>          /* We accept reads during second unlock sequence... */
>      case 0x00:
> -    flash_read:
>          /* Flash area read */
> -        p = (uint8_t *)pfl->storage + offset;
> -        if (pfl->be) {
> -            ret = ldn_be_p(p, width);
> -        } else {
> -            ret = ldn_le_p(p, width);
> -        }
> -        trace_pflash_data_read(offset, width << 1, ret);
> +        ret = pflash_data_read(pfl, offset, width);
>          break;
>      case 0x90:
>          /* flash ID read */
> @@ -222,7 +226,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>              }
>              /* Fall through to data read. */
>          default:
> -            goto flash_read;
> +            ret = pflash_data_read(pfl, offset, width);
>          }
>          DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx32 "\n", __func__, boff, ret);
>          break;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 11/28] hw/block/pflash_cfi02: Unify the MemoryRegionOps
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 11/28] hw/block/pflash_cfi02: Unify the MemoryRegionOps Philippe Mathieu-Daudé
@ 2019-06-28 16:25   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:25 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:37 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> The pflash_read()/pflash_write() can check the device endianess
> via the pfl->be variable, so remove the 'int be' argument.
>
> Since the big/little MemoryRegionOps are now identical, it is
> pointless to declare them both. Unify them.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> [PMD: Extracted from bigger patch to ease review]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Nice cleanup!

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 60 +++++++++++------------------------------
>  1 file changed, 15 insertions(+), 45 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index c079a63880..e64dc69c6c 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -177,11 +177,11 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
>      return ret;
>  }
>
> -static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
> -                            int width, int be)
> +static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>  {
> +    PFlashCFI02 *pfl = opaque;
>      hwaddr boff;
> -    uint32_t ret;
> +    uint64_t ret;
>
>      ret = -1;
>      /* Lazy reset to ROMD mode after a certain amount of read accesses */
> @@ -228,14 +228,14 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>          default:
>              ret = pflash_data_read(pfl, offset, width);
>          }
> -        DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx32 "\n", __func__, boff, ret);
> +        DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx64 "\n", __func__, boff, ret);
>          break;
>      case 0xA0:
>      case 0x10:
>      case 0x30:
>          /* Status register read */
>          ret = pfl->status;
> -        DPRINTF("%s: status %" PRIx32 "\n", __func__, ret);
> +        DPRINTF("%s: status %" PRIx64 "\n", __func__, ret);
>          toggle_dq6(pfl);
>          break;
>      case 0x98:
> @@ -253,8 +253,7 @@ static uint32_t pflash_read(PFlashCFI02 *pfl, hwaddr offset,
>  }
>
>  /* update flash content on disk */
> -static void pflash_update(PFlashCFI02 *pfl, int offset,
> -                          int size)
> +static void pflash_update(PFlashCFI02 *pfl, int offset, int size)
>  {
>      int offset_end;
>      if (pfl->blk) {
> @@ -267,9 +266,10 @@ static void pflash_update(PFlashCFI02 *pfl, int offset,
>      }
>  }
>
> -static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
> -                         uint32_t value, int width, int be)
> +static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
> +                         unsigned int width)
>  {
> +    PFlashCFI02 *pfl = opaque;
>      hwaddr boff;
>      uint8_t *p;
>      uint8_t cmd;
> @@ -477,39 +477,9 @@ static void pflash_write(PFlashCFI02 *pfl, hwaddr offset,
>      pfl->cmd = 0;
>  }
>
> -static uint64_t pflash_be_readfn(void *opaque, hwaddr addr, unsigned size)
> -{
> -    return pflash_read(opaque, addr, size, 1);
> -}
> -
> -static void pflash_be_writefn(void *opaque, hwaddr addr,
> -                              uint64_t value, unsigned size)
> -{
> -    pflash_write(opaque, addr, value, size, 1);
> -}
> -
> -static uint64_t pflash_le_readfn(void *opaque, hwaddr addr, unsigned size)
> -{
> -    return pflash_read(opaque, addr, size, 0);
> -}
> -
> -static void pflash_le_writefn(void *opaque, hwaddr addr,
> -                              uint64_t value, unsigned size)
> -{
> -    pflash_write(opaque, addr, value, size, 0);
> -}
> -
> -static const MemoryRegionOps pflash_cfi02_ops_be = {
> -    .read = pflash_be_readfn,
> -    .write = pflash_be_writefn,
> -    .valid.min_access_size = 1,
> -    .valid.max_access_size = 4,
> -    .endianness = DEVICE_NATIVE_ENDIAN,
> -};
> -
> -static const MemoryRegionOps pflash_cfi02_ops_le = {
> -    .read = pflash_le_readfn,
> -    .write = pflash_le_writefn,
> +static const MemoryRegionOps pflash_cfi02_ops = {
> +    .read = pflash_read,
> +    .write = pflash_write,
>      .valid.min_access_size = 1,
>      .valid.max_access_size = 4,
>      .endianness = DEVICE_NATIVE_ENDIAN,
> @@ -537,9 +507,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>
>      chip_len = pfl->sector_len * pfl->nb_blocs;
>
> -    memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl), pfl->be ?
> -                                  &pflash_cfi02_ops_be : &pflash_cfi02_ops_le,
> -                                  pfl, pfl->name, chip_len, &local_err);
> +    memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
> +                                  &pflash_cfi02_ops, pfl, pfl->name,
> +                                  chip_len, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          return;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 12/28] hw/block/pflash_cfi02: Fix command address comparison
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 12/28] hw/block/pflash_cfi02: Fix command address comparison Philippe Mathieu-Daudé
@ 2019-06-28 16:28   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:28 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:42 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> From: Stephen Checkoway <stephen.checkoway@oberlin.edu>
>
> Most AMD commands only examine 11 bits of the address. This masks the
> addresses used in the comparison to 11 bits. The exceptions are word or
> sector addresses which use offset directly rather than the shifted
> offset, boff.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Acked-by: Thomas Huth <thuth@redhat.com>
> Message-Id: <20190426162624.55977-4-stephen.checkoway@oberlin.edu>
> [PMD: Prepend 'hw/' in patch subject]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c   |  8 +++++++-
>  tests/pflash-cfi02-test.c | 12 ++++++++++--
>  2 files changed, 17 insertions(+), 3 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index e64dc69c6c..4be3837be5 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -281,11 +281,13 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>      }
>      offset &= pfl->chip_len - 1;
>
> -    boff = offset & (pfl->sector_len - 1);
> +    boff = offset;
>      if (pfl->width == 2)
>          boff = boff >> 1;
>      else if (pfl->width == 4)
>          boff = boff >> 2;
> +    /* Only the least-significant 11 bits are used in most cases. */
> +    boff &= 0x7FF;
>      switch (pfl->wcycle) {
>      case 0:
>          /* Set the device in I/O access mode if required */
> @@ -538,6 +540,10 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>          }
>      }
>
> +    /* Only 11 bits are used in the comparison. */
> +    pfl->unlock_addr0 &= 0x7FF;
> +    pfl->unlock_addr1 &= 0x7FF;
> +
>      pflash_setup_mappings(pfl);
>      pfl->rom_mode = 1;
>      sysbus_init_mmio(SYS_BUS_DEVICE(dev), &pfl->mem);
> diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
> index e7e16a8dd8..e090b2e3a0 100644
> --- a/tests/pflash-cfi02-test.c
> +++ b/tests/pflash-cfi02-test.c
> @@ -21,8 +21,8 @@
>
>  #define FLASH_WIDTH 2
>  #define CFI_ADDR (FLASH_WIDTH * 0x55)
> -#define UNLOCK0_ADDR (FLASH_WIDTH * 0x5555)
> -#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AAA)
> +#define UNLOCK0_ADDR (FLASH_WIDTH * 0x555)
> +#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AA)
>
>  #define CFI_CMD 0x98
>  #define UNLOCK0_CMD 0xAA
> @@ -190,6 +190,14 @@ static void test_flash(void)
>      g_assert_cmphex(flash_read(6), ==, 0xCDEF);
>      g_assert_cmphex(flash_read(8), ==, 0xFFFF);
>
> +    /* Test ignored high order bits of address. */
> +    flash_write(FLASH_WIDTH * 0x5555, UNLOCK0_CMD);
> +    flash_write(FLASH_WIDTH * 0x2AAA, UNLOCK1_CMD);
> +    flash_write(FLASH_WIDTH * 0x5555, AUTOSELECT_CMD);
> +    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
> +    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
> +    reset();
> +
>      qtest_quit(global_qtest);
>  }
>
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 14/28] hw/block/pflash_cfi02: Remove pointless local variable
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 14/28] hw/block/pflash_cfi02: Remove pointless local variable Philippe Mathieu-Daudé
@ 2019-06-28 16:32   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:32 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:59 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> We can directly use pfl->total_len, remove the local 'chip_len'
> variable.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 14 ++++++--------
>  1 file changed, 6 insertions(+), 8 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 4be3837be5..1a794fa83c 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -409,7 +409,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>              /* Chip erase */
>              DPRINTF("%s: start chip erase\n", __func__);
>              if (!pfl->ro) {
> -                memset(pfl->storage, 0xFF, pfl->chip_len);
> +                memset(pfl->storage, 0xff, pfl->chip_len);
>                  pflash_update(pfl, 0, pfl->chip_len);
>              }
>              set_dq7(pfl, 0x00);
> @@ -490,7 +490,6 @@ static const MemoryRegionOps pflash_cfi02_ops = {
>  static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>  {
>      PFlashCFI02 *pfl = PFLASH_CFI02(dev);
> -    uint32_t chip_len;
>      int ret;
>      Error *local_err = NULL;
>
> @@ -507,18 +506,17 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>
> -    chip_len = pfl->sector_len * pfl->nb_blocs;
> +    pfl->chip_len = pfl->sector_len * pfl->nb_blocs;
>
>      memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
>                                    &pflash_cfi02_ops, pfl, pfl->name,
> -                                  chip_len, &local_err);
> +                                  pfl->chip_len, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
>          return;
>      }
>
>      pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem);
> -    pfl->chip_len = chip_len;
>
>      if (pfl->blk) {
>          uint64_t perm;
> @@ -533,8 +531,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      }
>
>      if (pfl->blk) {
> -        if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, chip_len,
> -                                         errp)) {
> +        if (!blk_check_size_and_read_all(pfl->blk, pfl->storage,
> +                                         pfl->chip_len, errp)) {
>              vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
>              return;
>          }
> @@ -594,7 +592,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      /* Max timeout for chip erase */
>      pfl->cfi_table[0x26] = 0x0D;
>      /* Device size */
> -    pfl->cfi_table[0x27] = ctz32(chip_len);
> +    pfl->cfi_table[0x27] = ctz32(pfl->chip_len);
>      /* Flash device interface (8 & 16 bits) */
>      pfl->cfi_table[0x28] = 0x02;
>      pfl->cfi_table[0x29] = 0x00;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 15/28] hw/block/pflash_cfi02: Document the current CFI values
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 15/28] hw/block/pflash_cfi02: Document the current CFI values Philippe Mathieu-Daudé
@ 2019-06-28 16:33   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:33 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:53 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 1a794fa83c..f1bac480f5 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -550,6 +550,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->wcycle = 0;
>      pfl->cmd = 0;
>      pfl->status = 0;
> +
>      /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
>      /* Standard "QRY" string */
>      pfl->cfi_table[0x10] = 'Q';
> @@ -575,7 +576,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->cfi_table[0x1D] = 0x00;
>      /* Vpp max (no Vpp pin) */
>      pfl->cfi_table[0x1E] = 0x00;
> -    /* Reserved */
> +    /* Timeout per single byte/word write (128 ms) */
>      pfl->cfi_table[0x1F] = 0x07;
>      /* Timeout for min size buffer write (NA) */
>      pfl->cfi_table[0x20] = 0x00;
> @@ -614,17 +615,25 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->cfi_table[0x32] = 'R';
>      pfl->cfi_table[0x33] = 'I';
>
> +    /* Extended version 1.0 */
>      pfl->cfi_table[0x34] = '1';
>      pfl->cfi_table[0x35] = '0';
>
> +    /* Address sensitive unlock required. */
>      pfl->cfi_table[0x36] = 0x00;
> +    /* Erase suspend not supported. */
>      pfl->cfi_table[0x37] = 0x00;
> +    /* Sector protect not supported. */
>      pfl->cfi_table[0x38] = 0x00;
> +    /* Temporary sector unprotect not supported. */
>      pfl->cfi_table[0x39] = 0x00;
>
> +    /* Sector protect/unprotect scheme. */
>      pfl->cfi_table[0x3a] = 0x00;
>
> +    /* Simultaneous operation not supported. */
>      pfl->cfi_table[0x3b] = 0x00;
> +    /* Burst mode not supported. */
>      pfl->cfi_table[0x3c] = 0x00;
>  }
>
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 16/28] hw/block/pflash_cfi02: Hold the PRI table offset in a variable
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 16/28] hw/block/pflash_cfi02: Hold the PRI table offset in a variable Philippe Mathieu-Daudé
@ 2019-06-28 16:34   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:34 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:34 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Manufacturers are allowed to move the PRI table, this is why the
> offset is queryable via fixed offsets 0x15/0x16.
> Add a variable to hold the offset, so it will be easier to later
> move the PRI table.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 31 +++++++++++++++++--------------
>  1 file changed, 17 insertions(+), 14 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index f1bac480f5..23d05a6308 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -552,6 +552,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->status = 0;
>
>      /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
> +    const uint16_t pri_ofs = 0x31;
>      /* Standard "QRY" string */
>      pfl->cfi_table[0x10] = 'Q';
>      pfl->cfi_table[0x11] = 'R';
> @@ -560,8 +561,8 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->cfi_table[0x13] = 0x02;
>      pfl->cfi_table[0x14] = 0x00;
>      /* Primary extended table address */
> -    pfl->cfi_table[0x15] = 0x31;
> -    pfl->cfi_table[0x16] = 0x00;
> +    pfl->cfi_table[0x15] = pri_ofs;
> +    pfl->cfi_table[0x16] = pri_ofs >> 8;
>      /* Alternate command set (none) */
>      pfl->cfi_table[0x17] = 0x00;
>      pfl->cfi_table[0x18] = 0x00;
> @@ -609,32 +610,34 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
>      pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
>      pfl->cfi_table[0x30] = pfl->sector_len >> 16;
> +    assert(0x30 < pri_ofs);
>
>      /* Extended */
> -    pfl->cfi_table[0x31] = 'P';
> -    pfl->cfi_table[0x32] = 'R';
> -    pfl->cfi_table[0x33] = 'I';
> +    pfl->cfi_table[0x00 + pri_ofs] = 'P';
> +    pfl->cfi_table[0x01 + pri_ofs] = 'R';
> +    pfl->cfi_table[0x02 + pri_ofs] = 'I';
>
>      /* Extended version 1.0 */
> -    pfl->cfi_table[0x34] = '1';
> -    pfl->cfi_table[0x35] = '0';
> +    pfl->cfi_table[0x03 + pri_ofs] = '1';
> +    pfl->cfi_table[0x04 + pri_ofs] = '0';
>
>      /* Address sensitive unlock required. */
> -    pfl->cfi_table[0x36] = 0x00;
> +    pfl->cfi_table[0x05 + pri_ofs] = 0x00;
>      /* Erase suspend not supported. */
> -    pfl->cfi_table[0x37] = 0x00;
> +    pfl->cfi_table[0x06 + pri_ofs] = 0x00;
>      /* Sector protect not supported. */
> -    pfl->cfi_table[0x38] = 0x00;
> +    pfl->cfi_table[0x07 + pri_ofs] = 0x00;
>      /* Temporary sector unprotect not supported. */
> -    pfl->cfi_table[0x39] = 0x00;
> +    pfl->cfi_table[0x08 + pri_ofs] = 0x00;
>
>      /* Sector protect/unprotect scheme. */
> -    pfl->cfi_table[0x3a] = 0x00;
> +    pfl->cfi_table[0x09 + pri_ofs] = 0x00;
>
>      /* Simultaneous operation not supported. */
> -    pfl->cfi_table[0x3b] = 0x00;
> +    pfl->cfi_table[0x0a + pri_ofs] = 0x00;
>      /* Burst mode not supported. */
> -    pfl->cfi_table[0x3c] = 0x00;
> +    pfl->cfi_table[0x0b + pri_ofs] = 0x00;
> +    assert(0x0b + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
>  }
>
>  static Property pflash_cfi02_properties[] = {
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 17/28] hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 17/28] hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported Philippe Mathieu-Daudé
@ 2019-06-28 16:35   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:35 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:57 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> The 'page mode' feature entry was implicitly set as zero
> (not supported). Document it exists, so we won't discard
> it if we squeeze the CFI table.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 23d05a6308..01d9c5d75a 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -637,7 +637,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->cfi_table[0x0a + pri_ofs] = 0x00;
>      /* Burst mode not supported. */
>      pfl->cfi_table[0x0b + pri_ofs] = 0x00;
> -    assert(0x0b + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
> +    /* Page mode not supported. */
> +    pfl->cfi_table[0x0c + pri_ofs] = 0x00;
> +    assert(0x0c + pri_ofs < ARRAY_SIZE(pfl->cfi_table));
>  }
>
>  static Property pflash_cfi02_properties[] = {
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 13/28] tests/pflash-cfi02: Refactor to support testing multiple configurations
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 13/28] tests/pflash-cfi02: Refactor to support testing multiple configurations Philippe Mathieu-Daudé
@ 2019-06-28 16:41   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:41 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:50 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Introduce the FlashConfig structure, to be able to run the same set
> of tests on different flash models/configurations.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
> [PMD: Extracted from bigger patch]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  tests/pflash-cfi02-test.c | 386 +++++++++++++++++++++++++++-----------
>  1 file changed, 277 insertions(+), 109 deletions(-)
>
> diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
> index e090b2e3a0..b00f5ca2e7 100644
> --- a/tests/pflash-cfi02-test.c
> +++ b/tests/pflash-cfi02-test.c
> @@ -17,12 +17,18 @@
>   */
>
>  #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
> +#define FLASH_SIZE (8 * 1024 * 1024)
>  #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
>
> -#define FLASH_WIDTH 2
> -#define CFI_ADDR (FLASH_WIDTH * 0x55)
> -#define UNLOCK0_ADDR (FLASH_WIDTH * 0x555)
> -#define UNLOCK1_ADDR (FLASH_WIDTH * 0x2AA)
> +/* Use a newtype to keep flash addresses separate from byte addresses. */
> +typedef struct {
> +    uint64_t addr;
> +} faddr;
> +#define FLASH_ADDR(x) ((faddr) { .addr = (x) })
> +
> +#define CFI_ADDR FLASH_ADDR(0x55)
> +#define UNLOCK0_ADDR FLASH_ADDR(0x555)
> +#define UNLOCK1_ADDR FLASH_ADDR(0x2AA)
>
>  #define CFI_CMD 0x98
>  #define UNLOCK0_CMD 0xAA
> @@ -35,170 +41,313 @@
>  #define UNLOCK_BYPASS_CMD 0x20
>  #define UNLOCK_BYPASS_RESET_CMD 0x00
>
> +typedef struct {
> +    int bank_width;
> +
> +    QTestState *qtest;
> +} FlashConfig;
> +
>  static char image_path[] = "/tmp/qtest.XXXXXX";
>
> -static inline void flash_write(uint64_t byte_addr, uint16_t data)
> +/*
> + * The pflash implementation allows some parameters to be unspecified. We want
> + * to test those configurations but we also need to know the real values in
> + * our testing code. So after we launch qemu, we'll need a new FlashConfig
> + * with the correct values filled in.
> + */
> +static FlashConfig expand_config_defaults(const FlashConfig *c)
>  {
> -    qtest_writew(global_qtest, BASE_ADDR + byte_addr, data);
> +    FlashConfig ret = *c;
> +
> +    if (ret.bank_width == 0) {
> +        ret.bank_width = 2;
> +    }
> +
> +    /* XXX: Limitations of test harness. */
> +    assert(ret.bank_width == 2);
> +    return ret;
>  }
>
> -static inline uint16_t flash_read(uint64_t byte_addr)
> +/*
> + * Return a bit mask suitable for extracting the least significant
> + * status/query response from an interleaved response.
> + */
> +static inline uint64_t device_mask(const FlashConfig *c)
>  {
> -    return qtest_readw(global_qtest, BASE_ADDR + byte_addr);
> +    return (uint64_t)-1;
>  }
>
> -static void unlock(void)
> +/*
> + * Return a bit mask exactly as long as the bank_width.
> + */
> +static inline uint64_t bank_mask(const FlashConfig *c)
>  {
> -    flash_write(UNLOCK0_ADDR, UNLOCK0_CMD);
> -    flash_write(UNLOCK1_ADDR, UNLOCK1_CMD);
> +    if (c->bank_width == 8) {
> +        return (uint64_t)-1;
> +    }
> +    return (1ULL << (c->bank_width * 8)) - 1ULL;
>  }
>
> -static void reset(void)
> +static inline void flash_write(const FlashConfig *c, uint64_t byte_addr,
> +                               uint64_t data)
>  {
> -    flash_write(0, RESET_CMD);
> -}
> -
> -static void sector_erase(uint64_t byte_addr)
> -{
> -    unlock();
> -    flash_write(UNLOCK0_ADDR, 0x80);
> -    unlock();
> -    flash_write(byte_addr, SECTOR_ERASE_CMD);
> -}
> -
> -static void wait_for_completion(uint64_t byte_addr)
> -{
> -    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
> -    if ((flash_read(byte_addr) & 0x40) ^ (flash_read(byte_addr) & 0x40)) {
> -        /* Wait for erase or program to finish. */
> -        clock_step_next();
> -        /* Ensure that DQ6 has stopped toggling. */
> -        g_assert_cmphex(flash_read(byte_addr), ==, flash_read(byte_addr));
> +    /* Sanity check our tests. */
> +    assert((data & ~bank_mask(c)) == 0);
> +    uint64_t addr = BASE_ADDR + byte_addr;
> +    switch (c->bank_width) {
> +    case 1:
> +        qtest_writeb(c->qtest, addr, data);
> +        break;
> +    case 2:
> +        qtest_writew(c->qtest, addr, data);
> +        break;
> +    case 4:
> +        qtest_writel(c->qtest, addr, data);
> +        break;
> +    case 8:
> +        qtest_writeq(c->qtest, addr, data);
> +        break;
> +    default:
> +        abort();
>      }
>  }
>
> -static void bypass_program(uint64_t byte_addr, uint16_t data)
> +static inline uint64_t flash_read(const FlashConfig *c, uint64_t byte_addr)
>  {
> -    flash_write(UNLOCK0_ADDR, PROGRAM_CMD);
> -    flash_write(byte_addr, data);
> +    uint64_t addr = BASE_ADDR + byte_addr;
> +    switch (c->bank_width) {
> +    case 1:
> +        return qtest_readb(c->qtest, addr);
> +    case 2:
> +        return qtest_readw(c->qtest, addr);
> +    case 4:
> +        return qtest_readl(c->qtest, addr);
> +    case 8:
> +        return qtest_readq(c->qtest, addr);
> +    default:
> +        abort();
> +    }
> +}
> +
> +/*
> + * Convert a flash address expressed in the maximum width of the device as a
> + * byte address.
> + */
> +static inline uint64_t as_byte_addr(const FlashConfig *c, faddr flash_addr)
> +{
> +    /*
> +     * Command addresses are always given as addresses in the maximum
> +     * supported bus size for the flash chip. So an x8/x16 chip in x8 mode
> +     * uses addresses 0xAAA and 0x555 to unlock because the least significant
> +     * bit is ignored. (0x555 rather than 0x554 is traditional.)
> +     *
> +     * In general we need to multiply by the maximum device width.
> +     */
> +    return flash_addr.addr * c->bank_width;
> +}
> +
> +/*
> + * Return the command value or expected status replicated across all devices.
> + */
> +static inline uint64_t replicate(const FlashConfig *c, uint64_t data)
> +{
> +    /* Sanity check our tests. */
> +    assert((data & ~device_mask(c)) == 0);
> +    return data;
> +}
> +
> +static inline void flash_cmd(const FlashConfig *c, faddr cmd_addr,
> +                             uint8_t cmd)
> +{
> +    flash_write(c, as_byte_addr(c, cmd_addr), replicate(c, cmd));
> +}
> +
> +static inline uint64_t flash_query(const FlashConfig *c, faddr query_addr)
> +{
> +    return flash_read(c, as_byte_addr(c, query_addr));
> +}
> +
> +static inline uint64_t flash_query_1(const FlashConfig *c, faddr query_addr)
> +{
> +    return flash_query(c, query_addr) & device_mask(c);
> +}
> +
> +static void unlock(const FlashConfig *c)
> +{
> +    flash_cmd(c, UNLOCK0_ADDR, UNLOCK0_CMD);
> +    flash_cmd(c, UNLOCK1_ADDR, UNLOCK1_CMD);
> +}
> +
> +static void reset(const FlashConfig *c)
> +{
> +    flash_cmd(c, FLASH_ADDR(0), RESET_CMD);
> +}
> +
> +static void sector_erase(const FlashConfig *c, uint64_t byte_addr)
> +{
> +    unlock(c);
> +    flash_cmd(c, UNLOCK0_ADDR, 0x80);
> +    unlock(c);
> +    flash_write(c, byte_addr, replicate(c, SECTOR_ERASE_CMD));
> +}
> +
> +static void wait_for_completion(const FlashConfig *c, uint64_t byte_addr)
> +{
> +    /* If DQ6 is toggling, step the clock and ensure the toggle stops. */
> +    const uint64_t dq6 = replicate(c, 0x40);
> +    if ((flash_read(c, byte_addr) & dq6) ^ (flash_read(c, byte_addr) & dq6)) {
> +        /* Wait for erase or program to finish. */
> +        qtest_clock_step_next(c->qtest);
> +        /* Ensure that DQ6 has stopped toggling. */
> +        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
> +    }
> +}
> +
> +static void bypass_program(const FlashConfig *c, uint64_t byte_addr,
> +                           uint16_t data)
> +{
> +    flash_cmd(c, UNLOCK0_ADDR, PROGRAM_CMD);
> +    flash_write(c, byte_addr, data);
>      /*
>       * Data isn't valid until DQ6 stops toggling. We don't model this as
>       * writes are immediate, but if this changes in the future, we can wait
>       * until the program is complete.
>       */
> -    wait_for_completion(byte_addr);
> +    wait_for_completion(c, byte_addr);
>  }
>
> -static void program(uint64_t byte_addr, uint16_t data)
> +static void program(const FlashConfig *c, uint64_t byte_addr, uint16_t data)
>  {
> -    unlock();
> -    bypass_program(byte_addr, data);
> +    unlock(c);
> +    bypass_program(c, byte_addr, data);
>  }
>
> -static void chip_erase(void)
> +static void chip_erase(const FlashConfig *c)
>  {
> -    unlock();
> -    flash_write(UNLOCK0_ADDR, 0x80);
> -    unlock();
> -    flash_write(UNLOCK0_ADDR, SECTOR_ERASE_CMD);
> +    unlock(c);
> +    flash_cmd(c, UNLOCK0_ADDR, 0x80);
> +    unlock(c);
> +    flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
>  }
>
> -static void test_flash(void)
> +static void test_flash(const void *opaque)
>  {
> -    global_qtest = qtest_initf("-M musicpal,accel=qtest "
> -                               "-drive if=pflash,file=%s,format=raw,copy-on-read",
> -                               image_path);
> +    const FlashConfig *config = opaque;
> +    QTestState *qtest;
> +    qtest = qtest_initf("-M musicpal,accel=qtest"
> +                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
> +                        image_path);
> +    FlashConfig explicit_config = expand_config_defaults(config);
> +    explicit_config.qtest = qtest;
> +    const FlashConfig *c = &explicit_config;
> +
>      /* Check the IDs. */
> -    unlock();
> -    flash_write(UNLOCK0_ADDR, AUTOSELECT_CMD);
> -    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
> -    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
> -    reset();
> +    unlock(c);
> +    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
> +    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
> +    if (c->bank_width >= 2) {
> +        /*
> +         * XXX: The ID returned by the musicpal flash chip is 16 bits which
> +         * wouldn't happen with an 8-bit device. It would probably be best to
> +         * prohibit addresses larger than the device width in pflash_cfi02.c,
> +         * but then we couldn't test smaller device widths at all.
> +         */
> +        g_assert_cmphex(flash_query(c, FLASH_ADDR(1)), ==,
> +                        replicate(c, 0x236D));
> +    }
> +    reset(c);
>
>      /* Check the erase blocks. */
> -    flash_write(CFI_ADDR, CFI_CMD);
> -    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x10), ==, 'Q');
> -    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x11), ==, 'R');
> -    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x12), ==, 'Y');
> -    /* Num erase regions. */
> -    g_assert_cmphex(flash_read(FLASH_WIDTH * 0x2C), >=, 1);
> -    uint32_t nb_sectors = flash_read(FLASH_WIDTH * 0x2D) +
> -                          (flash_read(FLASH_WIDTH * 0x2E) << 8) + 1;
> -    uint32_t sector_len = (flash_read(FLASH_WIDTH * 0x2F) << 8) +
> -                          (flash_read(FLASH_WIDTH * 0x30) << 16);
> -    reset();
> +    flash_cmd(c, CFI_ADDR, CFI_CMD);
> +    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
> +    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
> +    g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
>
> +    /* Num erase regions. */
> +    g_assert_cmphex(flash_query_1(c, FLASH_ADDR(0x2C)), >=, 1);
> +
> +    uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(0x2D)) +
> +                          (flash_query_1(c, FLASH_ADDR(0x2E)) << 8) + 1;
> +    uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(0x2F)) << 8) +
> +                          (flash_query_1(c, FLASH_ADDR(0x30)) << 16);
> +    reset(c);
> +
> +    const uint64_t dq7 = replicate(c, 0x80);
> +    const uint64_t dq6 = replicate(c, 0x40);
>      /* Erase and program sector. */
>      for (uint32_t i = 0; i < nb_sectors; ++i) {
>          uint64_t byte_addr = i * sector_len;
> -        sector_erase(byte_addr);
> +        sector_erase(c, byte_addr);
>          /* Read toggle. */
> -        uint16_t status0 = flash_read(byte_addr);
> +        uint64_t status0 = flash_read(c, byte_addr);
>          /* DQ7 is 0 during an erase. */
> -        g_assert_cmphex(status0 & 0x80, ==, 0);
> -        uint16_t status1 = flash_read(byte_addr);
> +        g_assert_cmphex(status0 & dq7, ==, 0);
> +        uint64_t status1 = flash_read(c, byte_addr);
>          /* DQ6 toggles during an erase. */
> -        g_assert_cmphex(status0 & 0x40, !=, status1 & 0x40);
> +        g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
>          /* Wait for erase to complete. */
> -        clock_step_next();
> +        qtest_clock_step_next(c->qtest);
>          /* Ensure DQ6 has stopped toggling. */
> -        g_assert_cmphex(flash_read(byte_addr), ==, flash_read(byte_addr));
> +        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
>          /* Now the data should be valid. */
> -        g_assert_cmphex(flash_read(byte_addr), ==, 0xFFFF);
> +        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
>
>          /* Program a bit pattern. */
> -        program(byte_addr, 0x5555);
> -        g_assert_cmphex(flash_read(byte_addr), ==, 0x5555);
> -        program(byte_addr, 0xAA55);
> -        g_assert_cmphex(flash_read(byte_addr), ==, 0x0055);
> +        program(c, byte_addr, 0x55);
> +        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
> +        program(c, byte_addr, 0xA5);
> +        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
>      }
>
>      /* Erase the chip. */
> -    chip_erase();
> +    chip_erase(c);
>      /* Read toggle. */
> -    uint16_t status0 = flash_read(0);
> +    uint64_t status0 = flash_read(c, 0);
>      /* DQ7 is 0 during an erase. */
> -    g_assert_cmphex(status0 & 0x80, ==, 0);
> -    uint16_t status1 = flash_read(0);
> +    g_assert_cmphex(status0 & dq7, ==, 0);
> +    uint64_t status1 = flash_read(c, 0);
>      /* DQ6 toggles during an erase. */
> -    g_assert_cmphex(status0 & 0x40, !=, status1 & 0x40);
> +    g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
>      /* Wait for erase to complete. */
> -    clock_step_next();
> +    qtest_clock_step_next(c->qtest);
>      /* Ensure DQ6 has stopped toggling. */
> -    g_assert_cmphex(flash_read(0), ==, flash_read(0));
> +    g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
>      /* Now the data should be valid. */
> -    g_assert_cmphex(flash_read(0), ==, 0xFFFF);
> +
> +    for (uint32_t i = 0; i < nb_sectors; ++i) {
> +        uint64_t byte_addr = i * sector_len;
> +        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
> +    }
>
>      /* Unlock bypass */
> -    unlock();
> -    flash_write(UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
> -    bypass_program(0, 0x0123);
> -    bypass_program(2, 0x4567);
> -    bypass_program(4, 0x89AB);
> +    unlock(c);
> +    flash_cmd(c, UNLOCK0_ADDR, UNLOCK_BYPASS_CMD);
> +    bypass_program(c, 0 * c->bank_width, 0x01);
> +    bypass_program(c, 1 * c->bank_width, 0x23);
> +    bypass_program(c, 2 * c->bank_width, 0x45);
>      /*
>       * Test that bypass programming, unlike normal programming can use any
>       * address for the PROGRAM_CMD.
>       */
> -    flash_write(6, PROGRAM_CMD);
> -    flash_write(6, 0xCDEF);
> -    wait_for_completion(6);
> -    flash_write(0, UNLOCK_BYPASS_RESET_CMD);
> -    bypass_program(8, 0x55AA); /* Should fail. */
> -    g_assert_cmphex(flash_read(0), ==, 0x0123);
> -    g_assert_cmphex(flash_read(2), ==, 0x4567);
> -    g_assert_cmphex(flash_read(4), ==, 0x89AB);
> -    g_assert_cmphex(flash_read(6), ==, 0xCDEF);
> -    g_assert_cmphex(flash_read(8), ==, 0xFFFF);
> +    flash_cmd(c, FLASH_ADDR(3 * c->bank_width), PROGRAM_CMD);
> +    flash_write(c, 3 * c->bank_width, 0x67);
> +    wait_for_completion(c, 3 * c->bank_width);
> +    flash_cmd(c, FLASH_ADDR(0), UNLOCK_BYPASS_RESET_CMD);
> +    bypass_program(c, 4 * c->bank_width, 0x89); /* Should fail. */
> +    g_assert_cmphex(flash_read(c, 0 * c->bank_width), ==, 0x01);
> +    g_assert_cmphex(flash_read(c, 1 * c->bank_width), ==, 0x23);
> +    g_assert_cmphex(flash_read(c, 2 * c->bank_width), ==, 0x45);
> +    g_assert_cmphex(flash_read(c, 3 * c->bank_width), ==, 0x67);
> +    g_assert_cmphex(flash_read(c, 4 * c->bank_width), ==, bank_mask(c));
>
>      /* Test ignored high order bits of address. */
> -    flash_write(FLASH_WIDTH * 0x5555, UNLOCK0_CMD);
> -    flash_write(FLASH_WIDTH * 0x2AAA, UNLOCK1_CMD);
> -    flash_write(FLASH_WIDTH * 0x5555, AUTOSELECT_CMD);
> -    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0000), ==, 0x00BF);
> -    g_assert_cmpint(flash_read(FLASH_WIDTH * 0x0001), ==, 0x236D);
> -    reset();
> +    flash_cmd(c, FLASH_ADDR(0x5555), UNLOCK0_CMD);
> +    flash_cmd(c, FLASH_ADDR(0x2AAA), UNLOCK1_CMD);
> +    flash_cmd(c, FLASH_ADDR(0x5555), AUTOSELECT_CMD);
> +    g_assert_cmphex(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
> +    reset(c);
>
> -    qtest_quit(global_qtest);
> +    qtest_quit(qtest);
>  }
>
>  static void cleanup(void *opaque)
> @@ -206,6 +355,17 @@ static void cleanup(void *opaque)
>      unlink(image_path);
>  }
>
> +/*
> + * XXX: Tests are limited to bank_width = 2 for now because that's what
> + * hw/arm/musicpal.c has.
> + */
> +static const FlashConfig configuration[] = {
> +    /* One x16 device. */
> +    {
> +        .bank_width = 2,
> +    },
> +};
> +
>  int main(int argc, char **argv)
>  {
>      int fd = mkstemp(image_path);
> @@ -214,19 +374,27 @@ int main(int argc, char **argv)
>                     strerror(errno));
>          exit(EXIT_FAILURE);
>      }
> -    if (ftruncate(fd, 8 * 1024 * 1024) < 0) {
> +    if (ftruncate(fd, FLASH_SIZE) < 0) {
>          int error_code = errno;
>          close(fd);
>          unlink(image_path);
> -        g_printerr("Failed to truncate file %s to 8 MB: %s\n", image_path,
> -                   strerror(error_code));
> +        g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
> +                   FLASH_SIZE, strerror(error_code));
>          exit(EXIT_FAILURE);
>      }
>      close(fd);
>
>      qtest_add_abrt_handler(cleanup, NULL);
>      g_test_init(&argc, &argv, NULL);
> -    qtest_add_func("pflash-cfi02", test_flash);
> +
> +    size_t nb_configurations = sizeof configuration / sizeof configuration[0];
> +    for (size_t i = 0; i < nb_configurations; ++i) {
> +        const FlashConfig *config = &configuration[i];
> +        char *path = g_strdup_printf("pflash-cfi02/%d",
> +                                     config->bank_width);
> +        qtest_add_data_func(path, config, test_flash);
> +        g_free(path);
> +    }
>      int result = g_test_run();
>      cleanup(NULL);
>      return result;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 19/28] hw/block/pflash_cfi02: Extract pflash_regions_count()
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 19/28] hw/block/pflash_cfi02: Extract pflash_regions_count() Philippe Mathieu-Daudé
@ 2019-06-28 16:43   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 16:43 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:54 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Extract the pflash_regions_count() function, the code will be
> easier to review.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 1f096ec185..a0d3bd60dc 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -157,6 +157,11 @@ static void pflash_register_memory(PFlashCFI02 *pfl, int rom_mode)
>      pfl->rom_mode = rom_mode;
>  }
>
> +static size_t pflash_regions_count(PFlashCFI02 *pfl)
> +{
> +    return pfl->cfi_table[0x2c];
> +}
> +
>  static void pflash_timer (void *opaque)
>  {
>      PFlashCFI02 *pfl = opaque;
> @@ -192,9 +197,8 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
>  static uint32_t pflash_sector_len(PFlashCFI02 *pfl, hwaddr offset)
>  {
>      assert(offset < pfl->chip_len);
> -    int nb_regions = pfl->cfi_table[0x2C];
>      hwaddr addr = 0;
> -    for (int i = 0; i < nb_regions; ++i) {
> +    for (int i = 0; i < pflash_regions_count(pfl); ++i) {
>          uint64_t region_size = (uint64_t)pfl->nb_blocs[i] * pfl->sector_len[i];
>          if (addr <= offset && offset < addr + region_size) {
>              return pfl->sector_len[i];
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 18/28] hw/block/pflash_cfi02: Implement nonuniform sector sizes
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 18/28] hw/block/pflash_cfi02: Implement nonuniform sector sizes Philippe Mathieu-Daudé
@ 2019-06-28 17:28   ` Philippe Mathieu-Daudé
  0 siblings, 0 replies; 55+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-06-28 17:28 UTC (permalink / raw)
  To: Stephen Checkoway, qemu-devel
  Cc: Kevin Wolf, Laurent Vivier, Thomas Huth, qemu-block,
	Peter Maydell, Alex Bennée, Paolo Bonzini, Alistair Francis,
	Magnus Damm, Markus Armbruster, Max Reitz, Michael Walle,
	qemu-arm, qemu-ppc, Antony Pavlov, Edgar E. Iglesias, Jan Kiszka,
	John Snow, Aurelien Jarno, David Gibson

On 6/27/19 10:27 PM, Philippe Mathieu-Daudé wrote:
> From: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> 
> Some flash chips support sectors of different sizes. For example, the
> AMD AM29LV160DT has 31 64 kB sectors, one 32 kB sector, two 8 kB
> sectors, and a 16 kB sector, in that order. The AM29LV160DB has those in
> the reverse order.
> 
> The `num-blocks` and `sector-length` properties work exactly as they did
> before: a flash device with uniform sector lengths. To get non-uniform
> sector lengths for up to four regions, the following properties may be
> set
> - region 0. `num-blocks0` and `sector-length0`;
> - region 1. `num-blocks1` and `sector-length1`;
> - region 2. `num-blocks2` and `sector-length2`; and
> - region 3. `num-blocks3` and `sector-length3`.
> 
> If the uniform and nonuniform properties are set, then both must specify
> a flash device with the same total size. It would be better to disallow
> both being set, or make `num-blocks0` and `sector-length0` alias
> `num-blocks` and `sector-length`, but that would make testing currently
> impossible.
> 
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Acked-by: Thomas Huth <thuth@redhat.com>
> Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu>
> [PMD: Rebased, add assert() on pri_offset]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>  hw/block/pflash_cfi02.c   | 141 +++++++++++++++++++++++++++-------
>  tests/pflash-cfi02-test.c | 155 ++++++++++++++++++++++++++++----------
>  2 files changed, 231 insertions(+), 65 deletions(-)
> 
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 01d9c5d75a..1f096ec185 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -29,7 +29,6 @@
>   * - CFI queries
>   *
>   * It does not support flash interleaving.
> - * It does not implement boot blocs with reduced size
>   * It does not implement software data protection as found in many real chips
>   * It does not implement erase suspend/resume commands
>   * It does not implement multiple sectors erase
> @@ -57,6 +56,13 @@ do {                                                       \
>  
>  #define PFLASH_LAZY_ROMD_THRESHOLD 42
>  
> +/*
> + * The size of the cfi_table indirectly depends on this and the start of the
> + * PRI table directly depends on it. 4 is the maximum size (and also what
> + * seems common) without changing the PRT table address.
> + */
> +#define PFLASH_MAX_ERASE_REGIONS 4
> +
>  /* Special write cycles for CFI queries. */
>  enum {
>      WCYCLE_CFI              = 7,
> @@ -68,8 +74,10 @@ struct PFlashCFI02 {
>      /*< public >*/
>  
>      BlockBackend *blk;
> -    uint32_t sector_len;
> -    uint32_t nb_blocs;
> +    uint32_t uniform_nb_blocs;
> +    uint32_t uniform_sector_len;
> +    uint32_t nb_blocs[PFLASH_MAX_ERASE_REGIONS];
> +    uint32_t sector_len[PFLASH_MAX_ERASE_REGIONS];

I think we can drop the 'uniform' variables, and only use the indexed ones.

>      uint32_t chip_len;
>      uint8_t mappings;
>      uint8_t width;
> @@ -86,7 +94,7 @@ struct PFlashCFI02 {
>      uint16_t ident3;
>      uint16_t unlock_addr0;
>      uint16_t unlock_addr1;
> -    uint8_t cfi_table[0x52];
> +    uint8_t cfi_table[0x4d];
>      QEMUTimer timer;
>      /* The device replicates the flash memory across its memory space.  Emulate
>       * that by having a container (.mem) filled with an array of aliases
> @@ -177,6 +185,25 @@ static uint64_t pflash_data_read(PFlashCFI02 *pfl, hwaddr offset,
>      return ret;
>  }
>  
> +/*
> + * offset should be a byte offset of the QEMU device and _not_ a device
> + * offset.
> + */
> +static uint32_t pflash_sector_len(PFlashCFI02 *pfl, hwaddr offset)

Hmm I'd rather have a more generic pflash_sector_index(pfl, offset).

> +{
> +    assert(offset < pfl->chip_len);
> +    int nb_regions = pfl->cfi_table[0x2C];
> +    hwaddr addr = 0;
> +    for (int i = 0; i < nb_regions; ++i) {
> +        uint64_t region_size = (uint64_t)pfl->nb_blocs[i] * pfl->sector_len[i];
> +        if (addr <= offset && offset < addr + region_size) {
> +            return pfl->sector_len[i];
> +        }
> +        addr += region_size;
> +    }
> +    abort();
> +}
> +
>  static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>  {
>      PFlashCFI02 *pfl = opaque;
> @@ -191,10 +218,11 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>      }
>      offset &= pfl->chip_len - 1;
>      boff = offset & 0xFF;
> -    if (pfl->width == 2)
> +    if (pfl->width == 2) {
>          boff = boff >> 1;
> -    else if (pfl->width == 4)
> +    } else if (pfl->width == 4) {
>          boff = boff >> 2;
> +    }

Simple style, ok.

>      switch (pfl->cmd) {
>      default:
>          /* This should never happen : reset state & treat it as a read*/
> @@ -273,6 +301,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>      hwaddr boff;
>      uint8_t *p;
>      uint8_t cmd;
> +    uint32_t sector_len;
>  
>      trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>      cmd = value;
> @@ -282,10 +311,11 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>      offset &= pfl->chip_len - 1;
>  
>      boff = offset;
> -    if (pfl->width == 2)
> +    if (pfl->width == 2) {
>          boff = boff >> 1;
> -    else if (pfl->width == 4)
> +    } else if (pfl->width == 4) {
>          boff = boff >> 2;
> +    }

Style again.

>      /* Only the least-significant 11 bits are used in most cases. */
>      boff &= 0x7FF;
>      switch (pfl->wcycle) {
> @@ -420,12 +450,14 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          case 0x30:
>              /* Sector erase */
>              p = pfl->storage;
> -            offset &= ~(pfl->sector_len - 1);
> -            DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
> -                    offset);
> +            sector_len = pflash_sector_len(pfl, offset);
> +            offset &= ~(sector_len - 1);
> +            DPRINTF("%s: start sector erase at %0*" PRIx64 "-%0*" PRIx64 "\n",
> +                    __func__, pfl->width * 2, offset,
> +                    pfl->width * 2, offset + sector_len - 1);
>              if (!pfl->ro) {
> -                memset(p + offset, 0xFF, pfl->sector_len);
> -                pflash_update(pfl, offset, pfl->sector_len);
> +                memset(p + offset, 0xff, sector_len);
> +                pflash_update(pfl, offset, sector_len);
>              }
>              set_dq7(pfl, 0x00);
>              /* Let's wait 1/2 second before sector erase is done */
> @@ -493,11 +525,11 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      int ret;
>      Error *local_err = NULL;
>  
> -    if (pfl->sector_len == 0) {
> +    if (pfl->uniform_sector_len == 0 && pfl->sector_len[0] == 0) {
>          error_setg(errp, "attribute \"sector-length\" not specified or zero.");
>          return;
>      }
> -    if (pfl->nb_blocs == 0) {
> +    if (pfl->uniform_nb_blocs == 0 && pfl->nb_blocs[0] == 0) {
>          error_setg(errp, "attribute \"num-blocks\" not specified or zero.");
>          return;
>      }
> @@ -506,7 +538,51 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    pfl->chip_len = pfl->sector_len * pfl->nb_blocs;
> +    int nb_regions;
> +    pfl->chip_len = 0;
> +    for (nb_regions = 0; nb_regions < PFLASH_MAX_ERASE_REGIONS; ++nb_regions) {
> +        if (pfl->nb_blocs[nb_regions] == 0) {
> +            break;
> +        }
> +        uint64_t sector_len_per_device = pfl->sector_len[nb_regions];
> +
> +        /*
> +         * The size of each flash sector must be a power of 2 and it must be
> +         * aligned at the same power of 2.
> +         */
> +        if (sector_len_per_device & 0xff ||
> +            sector_len_per_device >= (1 << 24) ||
> +            !is_power_of_2(sector_len_per_device))
> +        {
> +            error_setg(errp, "unsupported configuration: "
> +                       "sector length[%d] per device = %" PRIx64 ".",
> +                       nb_regions, sector_len_per_device);
> +            return;
> +        }
> +        if (pfl->chip_len & (sector_len_per_device - 1)) {
> +            error_setg(errp, "unsupported configuration: "
> +                       "flash region %d not correctly aligned.",
> +                       nb_regions);
> +            return;
> +        }
> +
> +        pfl->chip_len += (uint64_t)pfl->sector_len[nb_regions] *
> +                          pfl->nb_blocs[nb_regions];
> +    }
> +
> +    uint64_t uniform_len = (uint64_t)pfl->uniform_nb_blocs *
> +                           pfl->uniform_sector_len;
> +    if (nb_regions == 0) {
> +        nb_regions = 1;
> +        pfl->nb_blocs[0] = pfl->uniform_nb_blocs;
> +        pfl->sector_len[0] = pfl->uniform_sector_len;
> +        pfl->chip_len = uniform_len;
> +    } else if (uniform_len != 0 && uniform_len != pfl->chip_len) {
> +        error_setg(errp, "\"num-blocks\"*\"sector-length\" "
> +                   "different from \"num-blocks0\"*\'sector-length0\" + ... + "
> +                   "\"num-blocks3\"*\"sector-length3\"");
> +        return;
> +    }
>  
>      memory_region_init_rom_device(&pfl->orig_mem, OBJECT(pfl),
>                                    &pflash_cfi02_ops, pfl, pfl->name,
> @@ -552,7 +628,7 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      pfl->status = 0;
>  
>      /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
> -    const uint16_t pri_ofs = 0x31;
> +    const uint16_t pri_ofs = 0x40;
>      /* Standard "QRY" string */
>      pfl->cfi_table[0x10] = 'Q';
>      pfl->cfi_table[0x11] = 'R';
> @@ -603,14 +679,17 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>      //    pfl->cfi_table[0x2A] = 0x05;
>      pfl->cfi_table[0x2A] = 0x00;
>      pfl->cfi_table[0x2B] = 0x00;
> -    /* Number of erase block regions (uniform) */
> -    pfl->cfi_table[0x2C] = 0x01;
> -    /* Erase block region 1 */
> -    pfl->cfi_table[0x2D] = pfl->nb_blocs - 1;
> -    pfl->cfi_table[0x2E] = (pfl->nb_blocs - 1) >> 8;
> -    pfl->cfi_table[0x2F] = pfl->sector_len >> 8;
> -    pfl->cfi_table[0x30] = pfl->sector_len >> 16;
> -    assert(0x30 < pri_ofs);
> +    /* Number of erase block regions */
> +    pfl->cfi_table[0x2c] = nb_regions;
> +    /* Erase block regions */
> +    for (int i = 0; i < nb_regions; ++i) {
> +        uint32_t sector_len_per_device = pfl->sector_len[i];
> +        pfl->cfi_table[0x2d + 4 * i] = pfl->nb_blocs[i] - 1;
> +        pfl->cfi_table[0x2e + 4 * i] = (pfl->nb_blocs[i] - 1) >> 8;
> +        pfl->cfi_table[0x2f + 4 * i] = sector_len_per_device >> 8;
> +        pfl->cfi_table[0x30 + 4 * i] = sector_len_per_device >> 16;
> +    }

OK.

> +    assert(0x2c + 4 * nb_regions < pri_ofs);
>  
>      /* Extended */
>      pfl->cfi_table[0x00 + pri_ofs] = 'P';
> @@ -644,8 +723,16 @@ static void pflash_cfi02_realize(DeviceState *dev, Error **errp)
>  
>  static Property pflash_cfi02_properties[] = {
>      DEFINE_PROP_DRIVE("drive", PFlashCFI02, blk),
> -    DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, nb_blocs, 0),
> -    DEFINE_PROP_UINT32("sector-length", PFlashCFI02, sector_len, 0),
> +    DEFINE_PROP_UINT32("num-blocks", PFlashCFI02, uniform_nb_blocs, 0),
> +    DEFINE_PROP_UINT32("sector-length", PFlashCFI02, uniform_sector_len, 0),
> +    DEFINE_PROP_UINT32("num-blocks0", PFlashCFI02, nb_blocs[0], 0),
> +    DEFINE_PROP_UINT32("sector-length0", PFlashCFI02, sector_len[0], 0),
> +    DEFINE_PROP_UINT32("num-blocks1", PFlashCFI02, nb_blocs[1], 0),
> +    DEFINE_PROP_UINT32("sector-length1", PFlashCFI02, sector_len[1], 0),
> +    DEFINE_PROP_UINT32("num-blocks2", PFlashCFI02, nb_blocs[2], 0),
> +    DEFINE_PROP_UINT32("sector-length2", PFlashCFI02, sector_len[2], 0),
> +    DEFINE_PROP_UINT32("num-blocks3", PFlashCFI02, nb_blocs[3], 0),
> +    DEFINE_PROP_UINT32("sector-length3", PFlashCFI02, sector_len[3], 0),
>      DEFINE_PROP_UINT8("width", PFlashCFI02, width, 0),
>      DEFINE_PROP_UINT8("mappings", PFlashCFI02, mappings, 0),
>      DEFINE_PROP_UINT8("big-endian", PFlashCFI02, be, 0),
> diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
> index b00f5ca2e7..1659eaebce 100644
> --- a/tests/pflash-cfi02-test.c
> +++ b/tests/pflash-cfi02-test.c
> @@ -17,9 +17,11 @@
>   */
>  
>  #define MP_FLASH_SIZE_MAX (32 * 1024 * 1024)
> -#define FLASH_SIZE (8 * 1024 * 1024)
>  #define BASE_ADDR (0x100000000ULL - MP_FLASH_SIZE_MAX)
>  
> +#define UNIFORM_FLASH_SIZE (8 * 1024 * 1024)
> +#define UNIFORM_FLASH_SECTOR_SIZE (64 * 1024)
> +
>  /* Use a newtype to keep flash addresses separate from byte addresses. */
>  typedef struct {
>      uint64_t addr;
> @@ -44,6 +46,10 @@ typedef struct {
>  typedef struct {
>      int bank_width;
>  
> +    /* Nonuniform block size. */
> +    int nb_blocs[4];
> +    int sector_len[4];
> +
>      QTestState *qtest;
>  } FlashConfig;
>  
> @@ -62,6 +68,10 @@ static FlashConfig expand_config_defaults(const FlashConfig *c)
>      if (ret.bank_width == 0) {
>          ret.bank_width = 2;
>      }
> +    if (ret.nb_blocs[0] == 0 && ret.sector_len[0] == 0) {
> +        ret.sector_len[0] = UNIFORM_FLASH_SECTOR_SIZE;
> +        ret.nb_blocs[0] = UNIFORM_FLASH_SIZE / UNIFORM_FLASH_SECTOR_SIZE;

See, here you use index=0 for the uniform config.

> +    }
>  
>      /* XXX: Limitations of test harness. */
>      assert(ret.bank_width == 2);
> @@ -230,13 +240,41 @@ static void chip_erase(const FlashConfig *c)
>      flash_cmd(c, UNLOCK0_ADDR, CHIP_ERASE_CMD);
>  }
>  
> -static void test_flash(const void *opaque)
> +/*
> + * Test flash commands with a variety of device geometry.
> + */
> +static void test_geometry(const void *opaque)
>  {
>      const FlashConfig *config = opaque;
>      QTestState *qtest;
>      qtest = qtest_initf("-M musicpal,accel=qtest"
> -                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
> -                        image_path);
> +                        " -drive if=pflash,file=%s,format=raw,copy-on-read"
> +                        /* Device geometry properties. */
> +                        " -global driver=cfi.pflash02,"
> +                        "property=num-blocks0,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=sector-length0,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=num-blocks1,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=sector-length1,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=num-blocks2,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=sector-length2,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=num-blocks3,value=%d"
> +                        " -global driver=cfi.pflash02,"
> +                        "property=sector-length3,value=%d",
> +                        image_path,
> +                        config->nb_blocs[0],
> +                        config->sector_len[0],
> +                        config->nb_blocs[1],
> +                        config->sector_len[1],
> +                        config->nb_blocs[2],
> +                        config->sector_len[2],
> +                        config->nb_blocs[3],
> +                        config->sector_len[3]);
>      FlashConfig explicit_config = expand_config_defaults(config);
>      explicit_config.qtest = qtest;
>      const FlashConfig *c = &explicit_config;
> @@ -264,39 +302,56 @@ static void test_flash(const void *opaque)
>      g_assert_cmphex(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
>  
>      /* Num erase regions. */
> -    g_assert_cmphex(flash_query_1(c, FLASH_ADDR(0x2C)), >=, 1);
> +    int nb_erase_regions = flash_query_1(c, FLASH_ADDR(0x2C));
> +    g_assert_cmphex(nb_erase_regions, ==,
> +                    !!c->nb_blocs[0] + !!c->nb_blocs[1] + !!c->nb_blocs[2] +
> +                    !!c->nb_blocs[3]);
> +
> +    /* Check device length. */
> +    uint32_t device_len = 1 << flash_query_1(c, FLASH_ADDR(0x27));
> +    g_assert_cmphex(device_len, ==, UNIFORM_FLASH_SIZE);
>  
> -    uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(0x2D)) +
> -                          (flash_query_1(c, FLASH_ADDR(0x2E)) << 8) + 1;
> -    uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(0x2F)) << 8) +
> -                          (flash_query_1(c, FLASH_ADDR(0x30)) << 16);
>      reset(c);
>  
>      const uint64_t dq7 = replicate(c, 0x80);
>      const uint64_t dq6 = replicate(c, 0x40);
> -    /* Erase and program sector. */
> -    for (uint32_t i = 0; i < nb_sectors; ++i) {
> -        uint64_t byte_addr = i * sector_len;
> -        sector_erase(c, byte_addr);
> -        /* Read toggle. */
> -        uint64_t status0 = flash_read(c, byte_addr);
> -        /* DQ7 is 0 during an erase. */
> -        g_assert_cmphex(status0 & dq7, ==, 0);
> -        uint64_t status1 = flash_read(c, byte_addr);
> -        /* DQ6 toggles during an erase. */
> -        g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
> -        /* Wait for erase to complete. */
> -        qtest_clock_step_next(c->qtest);
> -        /* Ensure DQ6 has stopped toggling. */
> -        g_assert_cmphex(flash_read(c, byte_addr), ==, flash_read(c, byte_addr));
> -        /* Now the data should be valid. */
> -        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
> +    uint64_t byte_addr = 0;
> +    for (int region = 0; region < nb_erase_regions; ++region) {
> +        uint64_t base = 0x2D + 4 * region;
> +        flash_cmd(c, CFI_ADDR, CFI_CMD);
> +        uint32_t nb_sectors = flash_query_1(c, FLASH_ADDR(base + 0)) +
> +                              (flash_query_1(c, FLASH_ADDR(base + 1)) << 8) + 1;
> +        uint32_t sector_len = (flash_query_1(c, FLASH_ADDR(base + 2)) << 8) +
> +                              (flash_query_1(c, FLASH_ADDR(base + 3)) << 16);
> +        g_assert_cmphex(nb_sectors, ==, c->nb_blocs[region]);
> +        g_assert_cmphex(sector_len, ==, c->sector_len[region]);
> +        reset(c);
>  
> -        /* Program a bit pattern. */
> -        program(c, byte_addr, 0x55);
> -        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
> -        program(c, byte_addr, 0xA5);
> -        g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
> +        /* Erase and program sector. */
> +        for (uint32_t i = 0; i < nb_sectors; ++i) {
> +            sector_erase(c, byte_addr);
> +            /* Read toggle. */
> +            uint64_t status0 = flash_read(c, byte_addr);
> +            /* DQ7 is 0 during an erase. */
> +            g_assert_cmphex(status0 & dq7, ==, 0);
> +            uint64_t status1 = flash_read(c, byte_addr);
> +            /* DQ6 toggles during an erase. */
> +            g_assert_cmphex(status0 & dq6, ==, ~status1 & dq6);
> +            /* Wait for erase to complete. */
> +            qtest_clock_step_next(c->qtest);
> +            /* Ensure DQ6 has stopped toggling. */
> +            g_assert_cmphex(flash_read(c, byte_addr), ==,
> +                            flash_read(c, byte_addr));
> +            /* Now the data should be valid. */
> +            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
> +
> +            /* Program a bit pattern. */
> +            program(c, byte_addr, 0x55);
> +            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x55);
> +            program(c, byte_addr, 0xA5);
> +            g_assert_cmphex(flash_read(c, byte_addr) & 0xFF, ==, 0x05);
> +            byte_addr += sector_len;
> +        }
>      }
>  
>      /* Erase the chip. */
> @@ -314,9 +369,11 @@ static void test_flash(const void *opaque)
>      g_assert_cmphex(flash_read(c, 0), ==, flash_read(c, 0));
>      /* Now the data should be valid. */
>  
> -    for (uint32_t i = 0; i < nb_sectors; ++i) {
> -        uint64_t byte_addr = i * sector_len;
> -        g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
> +    for (int region = 0; region < nb_erase_regions; ++region) {
> +        for (uint32_t i = 0; i < c->nb_blocs[region]; ++i) {
> +            uint64_t byte_addr = i * c->sector_len[region];
> +            g_assert_cmphex(flash_read(c, byte_addr), ==, bank_mask(c));
> +        }
>      }
>  
>      /* Unlock bypass */
> @@ -364,6 +421,18 @@ static const FlashConfig configuration[] = {
>      {
>          .bank_width = 2,
>      },
> +    /* Nonuniform sectors (top boot). */
> +    {
> +        .bank_width = 2,
> +        .nb_blocs = { 127, 1, 2, 1 },
> +        .sector_len = { 0x10000, 0x08000, 0x02000, 0x04000 },
> +    },
> +    /* Nonuniform sectors (bottom boot). */
> +    {
> +        .bank_width = 2,
> +        .nb_blocs = { 1, 2, 1, 127 },
> +        .sector_len = { 0x04000, 0x02000, 0x08000, 0x10000 },
> +    },
>  };
>  
>  int main(int argc, char **argv)
> @@ -374,12 +443,12 @@ int main(int argc, char **argv)
>                     strerror(errno));
>          exit(EXIT_FAILURE);
>      }
> -    if (ftruncate(fd, FLASH_SIZE) < 0) {
> +    if (ftruncate(fd, UNIFORM_FLASH_SIZE) < 0) {
>          int error_code = errno;
>          close(fd);
>          unlink(image_path);
>          g_printerr("Failed to truncate file %s to %u MB: %s\n", image_path,
> -                   FLASH_SIZE, strerror(error_code));
> +                   UNIFORM_FLASH_SIZE, strerror(error_code));
>          exit(EXIT_FAILURE);
>      }
>      close(fd);
> @@ -390,9 +459,19 @@ int main(int argc, char **argv)
>      size_t nb_configurations = sizeof configuration / sizeof configuration[0];
>      for (size_t i = 0; i < nb_configurations; ++i) {
>          const FlashConfig *config = &configuration[i];
> -        char *path = g_strdup_printf("pflash-cfi02/%d",
> +        char *path = g_strdup_printf("pflash-cfi02"
> +                                     "/geometry/%dx%x-%dx%x-%dx%x-%dx%x"
> +                                     "/%d",
> +                                     config->nb_blocs[0],
> +                                     config->sector_len[0],
> +                                     config->nb_blocs[1],
> +                                     config->sector_len[1],
> +                                     config->nb_blocs[2],
> +                                     config->sector_len[2],
> +                                     config->nb_blocs[3],
> +                                     config->sector_len[3],
>                                       config->bank_width);
> -        qtest_add_data_func(path, config, test_flash);
> +        qtest_add_data_func(path, config, test_geometry);
>          g_free(path);
>      }
>      int result = g_test_run();
> 


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 20/28] hw/block/pflash_cfi02: Split if() condition
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 20/28] hw/block/pflash_cfi02: Split if() condition Philippe Mathieu-Daudé
@ 2019-06-28 23:06   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 23:06 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:44 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Split the if() condition check and arrange the indentation to
> ease the review of the next patches. No logical change.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index a0d3bd60dc..08b2bc83cb 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -309,8 +309,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>
>      trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>      cmd = value;
> -    if (pfl->cmd != 0xA0 && cmd == 0xF0) {
> -        goto reset_flash;
> +    if (pfl->cmd != 0xA0) {
> +        if (cmd == 0xF0) {
> +            goto reset_flash;
> +        }
>      }
>      offset &= pfl->chip_len - 1;
>
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 21/28] hw/block/pflash_cfi02: Fix CFI in autoselect mode
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 21/28] hw/block/pflash_cfi02: Fix CFI in autoselect mode Philippe Mathieu-Daudé
@ 2019-06-28 23:08   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 23:08 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 2:09 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> From: Stephen Checkoway <stephen.checkoway@oberlin.edu>
>
> After a flash device enters CFI mode from autoselect mode, the reset
> command returns the device to autoselect mode. An additional reset
> command is necessary to return to read array mode.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Acked-by: Thomas Huth <thuth@redhat.com>
> Message-Id: <20190426162624.55977-7-stephen.checkoway@oberlin.edu>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Acked-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c   | 22 ++++++++++++++++++----
>  tests/pflash-cfi02-test.c | 39 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 57 insertions(+), 4 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 08b2bc83cb..13f76fa71d 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -66,6 +66,7 @@ do {                                                       \
>  /* Special write cycles for CFI queries. */
>  enum {
>      WCYCLE_CFI              = 7,
> +    WCYCLE_AUTOSELECT_CFI   = 8,
>  };
>
>  struct PFlashCFI02 {
> @@ -311,6 +312,12 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>      cmd = value;
>      if (pfl->cmd != 0xA0) {
>          if (cmd == 0xF0) {
> +            if (pfl->wcycle == WCYCLE_AUTOSELECT_CFI) {
> +                /* Return to autoselect mode. */
> +                pfl->wcycle = 3;
> +                pfl->cmd = 0x90;
> +                return;
> +            }
>              goto reset_flash;
>          }
>      }
> @@ -333,7 +340,6 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          /* We're in read mode */
>      check_unlock0:
>          if (boff == 0x55 && cmd == 0x98) {
> -        enter_CFI_mode:
>              /* Enter CFI query mode */
>              pfl->wcycle = WCYCLE_CFI;
>              pfl->cmd = 0x98;
> @@ -410,9 +416,16 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>                  /* Unlock bypass reset */
>                  goto reset_flash;
>              }
> -            /* We can enter CFI query mode from autoselect mode */
> -            if (boff == 0x55 && cmd == 0x98)
> -                goto enter_CFI_mode;
> +            /*
> +             * We can enter CFI query mode from autoselect mode, but we must
> +             * return to autoselect mode after a reset.
> +             */
> +            if (boff == 0x55 && cmd == 0x98) {
> +                /* Enter autoselect CFI query mode */
> +                pfl->wcycle = WCYCLE_AUTOSELECT_CFI;
> +                pfl->cmd = 0x98;
> +                return;
> +            }
>              /* No break here */
>          default:
>              DPRINTF("%s: invalid write for command %02x\n",
> @@ -493,6 +506,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          break;
>      /* Special values for CFI queries */
>      case WCYCLE_CFI:
> +    case WCYCLE_AUTOSELECT_CFI:
>          DPRINTF("%s: invalid write in CFI query mode\n", __func__);
>          goto reset_flash;
>      default:
> diff --git a/tests/pflash-cfi02-test.c b/tests/pflash-cfi02-test.c
> index 1659eaebce..00e2261742 100644
> --- a/tests/pflash-cfi02-test.c
> +++ b/tests/pflash-cfi02-test.c
> @@ -407,6 +407,42 @@ static void test_geometry(const void *opaque)
>      qtest_quit(qtest);
>  }
>
> +/*
> + * Test that
> + * 1. enter autoselect mode;
> + * 2. enter CFI mode; and then
> + * 3. exit CFI mode
> + * leaves the flash device in autoselect mode.
> + */
> +static void test_cfi_in_autoselect(const void *opaque)
> +{
> +    const FlashConfig *config = opaque;
> +    QTestState *qtest;
> +    qtest = qtest_initf("-M musicpal,accel=qtest"
> +                        " -drive if=pflash,file=%s,format=raw,copy-on-read",
> +                        image_path);
> +    FlashConfig explicit_config = expand_config_defaults(config);
> +    explicit_config.qtest = qtest;
> +    const FlashConfig *c = &explicit_config;
> +
> +    /* 1. Enter autoselect. */
> +    unlock(c);
> +    flash_cmd(c, UNLOCK0_ADDR, AUTOSELECT_CMD);
> +    g_assert_cmpint(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
> +
> +    /* 2. Enter CFI. */
> +    flash_cmd(c, CFI_ADDR, CFI_CMD);
> +    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x10)), ==, replicate(c, 'Q'));
> +    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x11)), ==, replicate(c, 'R'));
> +    g_assert_cmpint(flash_query(c, FLASH_ADDR(0x12)), ==, replicate(c, 'Y'));
> +
> +    /* 3. Exit CFI. */
> +    reset(c);
> +    g_assert_cmpint(flash_query(c, FLASH_ADDR(0)), ==, replicate(c, 0xBF));
> +
> +    qtest_quit(qtest);
> +}
> +
>  static void cleanup(void *opaque)
>  {
>      unlink(image_path);
> @@ -474,6 +510,9 @@ int main(int argc, char **argv)
>          qtest_add_data_func(path, config, test_geometry);
>          g_free(path);
>      }
> +
> +    qtest_add_data_func("pflash-cfi02/cfi-in-autoselect", &configuration[0],
> +                        test_cfi_in_autoselect);
>      int result = g_test_run();
>      cleanup(NULL);
>      return result;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 22/28] hw/block/pflash_cfi02: Fix reset command not ignored during erase
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 22/28] hw/block/pflash_cfi02: Fix reset command not ignored during erase Philippe Mathieu-Daudé
@ 2019-06-28 23:11   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 23:11 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 2:06 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> From: Stephen Checkoway <stephen.checkoway@oberlin.edu>
>
> When the flash device is performing a chip erase, all commands are
> ignored. When it is performing a sector erase, only the erase suspend
> command is valid, which is currently not supported.
>
> In particular, the reset command should not cause the device to reset to
> read array mode while programming is on going.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-8-stephen.checkoway@oberlin.edu>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index 13f76fa71d..39daa95833 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -311,7 +311,8 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>      trace_pflash_io_write(offset, width, width << 1, value, pfl->wcycle);
>      cmd = value;
>      if (pfl->cmd != 0xA0) {
> -        if (cmd == 0xF0) {
> +        /* Reset does nothing during chip erase and sector erase. */
> +        if (cmd == 0xF0 && pfl->cmd != 0x10 && pfl->cmd != 0x30) {
>              if (pfl->wcycle == WCYCLE_AUTOSELECT_CFI) {
>                  /* Return to autoselect mode. */
>                  pfl->wcycle = 3;
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 25/28] hw/block/pflash_cfi02: Use chip erase time specified in the CFI table
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 25/28] hw/block/pflash_cfi02: Use chip erase time specified in the CFI table Philippe Mathieu-Daudé
@ 2019-06-28 23:12   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 23:12 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 2:12 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> From: Stephen Checkoway <stephen.checkoway@oberlin.edu>
>
> When erasing the chip, use the typical time specified in the CFI table
> rather than arbitrarily selecting 5 seconds.
>
> Since the currently unconfigurable value set in the table is 12, this
> means a chip erase takes 4096 ms so this isn't a big change in behavior.
>
> Signed-off-by: Stephen Checkoway <stephen.checkoway@oberlin.edu>
> Message-Id: <20190426162624.55977-11-stephen.checkoway@oberlin.edu>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
> TODO check not zero
> ---
>  hw/block/pflash_cfi02.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index a3665da3b8..b2d37c33bb 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -617,9 +617,9 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>                  pflash_update(pfl, 0, pfl->chip_len);
>              }
>              set_dq7(pfl, 0x00);
> -            /* Let's wait 5 seconds before chip erase is done */
> +            /* Wait the time specified at CFI address 0x22. */
>              timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> -                      (NANOSECONDS_PER_SECOND * 5));
> +                      (1ULL << pfl->cfi_table[0x22]) * SCALE_MS);
>              break;
>          case 0x30:
>              /* Sector erase */
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 27/28] hw/block/pflash_cfi02: Document commands
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 27/28] hw/block/pflash_cfi02: Document commands Philippe Mathieu-Daudé
@ 2019-06-28 23:13   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 23:13 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:58 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 40 +++++++++++++++++++---------------------
>  1 file changed, 19 insertions(+), 21 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index e9519cbae8..db9dc7d8fb 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -327,7 +327,7 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>          pfl->wcycle = 0;
>          pfl->cmd = 0;
>          /* fall through to the read code */
> -    case 0x80:
> +    case 0x80: /* Erase (unlock) */
>          /* We accept reads during second unlock sequence... */
>      case 0x00:
>          if (pflash_erase_suspend_mode(pfl) &&
> @@ -342,8 +342,7 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>          /* Flash area read */
>          ret = pflash_data_read(pfl, offset, width);
>          break;
> -    case 0x90:
> -        /* flash ID read */
> +    case 0x90: /* flash ID read */
>          switch (boff) {
>          case 0x00:
>          case 0x01:
> @@ -364,11 +363,11 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>          }
>          DPRINTF("%s: ID " TARGET_FMT_plx " %" PRIx64 "\n", __func__, boff, ret);
>          break;
> -    case 0x10:
> -    case 0x30:
> +    case 0x10: /* Chip Erase */
> +    case 0x30: /* Sector Erase */
>          /* Toggle bit 2 during erase, but not program. */
>          toggle_dq2(pfl);
> -    case 0xA0:
> +    case 0xA0: /* Program */
>          /* Toggle bit 6 */
>          toggle_dq6(pfl);
>          /* Status register read */
> @@ -470,7 +469,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>              return;
>          }
>          /* Handle erase resume in erase suspend mode, otherwise reset. */
> -        if (cmd == 0x30) {
> +        if (cmd == 0x30) { /* Erase Resume */
>              if (pflash_erase_suspend_mode(pfl)) {
>                  /* Resume the erase. */
>                  timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
> @@ -485,7 +484,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>              goto reset_flash;
>          }
>          /* Ignore erase suspend. */
> -        if (cmd == 0xB0) {
> +        if (cmd == 0xB0) { /* Erase Suspend */
>              return;
>          }
>          if (boff != pfl->unlock_addr0 || cmd != 0xAA) {
> @@ -516,9 +515,9 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          case 0x20:
>              pfl->bypass = 1;
>              goto do_bypass;
> -        case 0x80:
> -        case 0x90:
> -        case 0xA0:
> +        case 0x80: /* Erase */
> +        case 0x90: /* Autoselect */
> +        case 0xA0: /* Program */
>              pfl->cmd = cmd;
>              DPRINTF("%s: starting command %02x\n", __func__, cmd);
>              break;
> @@ -529,10 +528,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          break;
>      case 3:
>          switch (pfl->cmd) {
> -        case 0x80:
> +        case 0x80: /* Erase */
>              /* We need another unlock sequence */
>              goto check_unlock0;
> -        case 0xA0:
> +        case 0xA0: /* Program */
>              if (pflash_erase_suspend_mode(pfl) &&
>                  pflash_sector_is_erasing(pfl, offset)) {
>                  /* Ignore writes to erasing sectors. */
> @@ -562,7 +561,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>              if (pfl->bypass)
>                  goto do_bypass;
>              goto reset_flash;
> -        case 0x90:
> +        case 0x90: /* Autoselect */
>              if (pfl->bypass && cmd == 0x00) {
>                  /* Unlock bypass reset */
>                  goto reset_flash;
> @@ -585,11 +584,11 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          }
>      case 4:
>          switch (pfl->cmd) {
> -        case 0xA0:
> +        case 0xA0: /* Program */
>              /* Ignore writes while flash data write is occurring */
>              /* As we suppose write is immediate, this should never happen */
>              return;
> -        case 0x80:
> +        case 0x80: /* Erase */
>              goto check_unlock1;
>          default:
>              /* Should never happen */
> @@ -604,7 +603,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>              goto reset_flash;
>          }
>          switch (cmd) {
> -        case 0x10:
> +        case 0x10: /* Chip Erase */
>              if (boff != pfl->unlock_addr0) {
>                  DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
>                          __func__, offset);
> @@ -621,8 +620,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>              timer_mod(&pfl->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
>                        (1ULL << pfl->cfi_table[0x22]) * SCALE_MS);
>              break;
> -        case 0x30:
> -            /* Sector erase */
> +        case 0x30: /* Sector erase */
>              pflash_sector_erase(pfl, offset);
>              break;
>          default:
> @@ -633,10 +631,10 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>          break;
>      case 6:
>          switch (pfl->cmd) {
> -        case 0x10:
> +        case 0x10: /* Chip Erase */
>              /* Ignore writes during chip erase */
>              return;
> -        case 0x30:
> +        case 0x30: /* Sector erase */
>              if (cmd == 0xB0) {
>                  /*
>                   * If erase suspend happens during the erase timeout (so DQ3 is
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: [Qemu-devel] [PATCH v5 28/28] hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit
  2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 28/28] hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit Philippe Mathieu-Daudé
@ 2019-06-28 23:13   ` Alistair Francis
  0 siblings, 0 replies; 55+ messages in thread
From: Alistair Francis @ 2019-06-28 23:13 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé
  Cc: Peter Maydell, Stephen Checkoway,
	qemu-devel@nongnu.org Developers, Edgar E. Iglesias, Qemu-block,
	John Snow, Magnus Damm, Markus Armbruster, Antony Pavlov,
	Laurent Vivier, Thomas Huth, Alistair Francis, qemu-arm,
	Jan Kiszka, Alex Bennée, David Gibson, Kevin Wolf,
	Max Reitz, Michael Walle, open list:New World, Paolo Bonzini,
	Aurelien Jarno

On Thu, Jun 27, 2019 at 1:55 PM Philippe Mathieu-Daudé
<philmd@redhat.com> wrote:
>
> Parallel NOR flashes are limited to 16-bit bus accesses.
> Remove the 32-bit dead code.
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/block/pflash_cfi02.c | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index db9dc7d8fb..d1f28b02b9 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -317,8 +317,6 @@ static uint64_t pflash_read(void *opaque, hwaddr offset, unsigned int width)
>      boff = offset & 0xFF;
>      if (pfl->width == 2) {
>          boff = boff >> 1;
> -    } else if (pfl->width == 4) {
> -        boff = boff >> 2;
>      }
>      switch (pfl->cmd) {
>      default:
> @@ -449,8 +447,6 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>      boff = offset;
>      if (pfl->width == 2) {
>          boff = boff >> 1;
> -    } else if (pfl->width == 4) {
> -        boff = boff >> 2;
>      }
>      /* Only the least-significant 11 bits are used in most cases. */
>      boff &= 0x7FF;
> @@ -710,6 +706,7 @@ static void pflash_write(void *opaque, hwaddr offset, uint64_t value,
>  static const MemoryRegionOps pflash_cfi02_ops = {
>      .read = pflash_read,
>      .write = pflash_write,
> +    .impl.max_access_size = 2,
>      .valid.min_access_size = 1,
>      .valid.max_access_size = 4,
>      .endianness = DEVICE_NATIVE_ENDIAN,
> --
> 2.20.1
>
>


^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2019-06-28 23:20 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-27 20:26 [Qemu-devel] [PATCH v5 00/28] block/pflash_cfi02: Implement missing AMD pflash functionality Philippe Mathieu-Daudé
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 01/28] tests/pflash-cfi02: Add test for supported CFI commands Philippe Mathieu-Daudé
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 02/28] hw/block/pflash: Simplify trace_pflash_io_read/write() Philippe Mathieu-Daudé
2019-06-27 21:49   ` Stephen Checkoway
2019-06-28 15:53     ` Alistair Francis
2019-06-28 15:52   ` Alistair Francis
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 03/28] hw/block/pflash: Simplify trace_pflash_data_read/write() Philippe Mathieu-Daudé
2019-06-28 15:54   ` Alistair Francis
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 04/28] hw/block/pflash_cfi02: Fix debug format string Philippe Mathieu-Daudé
2019-06-28 15:55   ` Alistair Francis
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 05/28] hw/block/pflash_cfi02: Add an enum to define the write cycles Philippe Mathieu-Daudé
2019-06-28 15:56   ` Alistair Francis
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 06/28] hw/block/pflash_cfi02: Add helpers to manipulate the status bits Philippe Mathieu-Daudé
2019-06-28 16:00   ` Alistair Francis
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 07/28] hw/block/pflash_cfi02: Simplify a statement using fall through Philippe Mathieu-Daudé
2019-06-28 16:01   ` Alistair Francis
2019-06-27 20:26 ` [Qemu-devel] [PATCH v5 08/28] hw/block/pflash_cfi02: Use the ldst API in pflash_write() Philippe Mathieu-Daudé
2019-06-28 16:03   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 09/28] hw/block/pflash_cfi02: Use the ldst API in pflash_read() Philippe Mathieu-Daudé
2019-06-28 16:03   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 10/28] hw/block/pflash_cfi02: Extract the pflash_data_read() function Philippe Mathieu-Daudé
2019-06-28 16:17   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 11/28] hw/block/pflash_cfi02: Unify the MemoryRegionOps Philippe Mathieu-Daudé
2019-06-28 16:25   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 12/28] hw/block/pflash_cfi02: Fix command address comparison Philippe Mathieu-Daudé
2019-06-28 16:28   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 13/28] tests/pflash-cfi02: Refactor to support testing multiple configurations Philippe Mathieu-Daudé
2019-06-28 16:41   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 14/28] hw/block/pflash_cfi02: Remove pointless local variable Philippe Mathieu-Daudé
2019-06-28 16:32   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 15/28] hw/block/pflash_cfi02: Document the current CFI values Philippe Mathieu-Daudé
2019-06-28 16:33   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 16/28] hw/block/pflash_cfi02: Hold the PRI table offset in a variable Philippe Mathieu-Daudé
2019-06-28 16:34   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 17/28] hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported Philippe Mathieu-Daudé
2019-06-28 16:35   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 18/28] hw/block/pflash_cfi02: Implement nonuniform sector sizes Philippe Mathieu-Daudé
2019-06-28 17:28   ` Philippe Mathieu-Daudé
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 19/28] hw/block/pflash_cfi02: Extract pflash_regions_count() Philippe Mathieu-Daudé
2019-06-28 16:43   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 20/28] hw/block/pflash_cfi02: Split if() condition Philippe Mathieu-Daudé
2019-06-28 23:06   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 21/28] hw/block/pflash_cfi02: Fix CFI in autoselect mode Philippe Mathieu-Daudé
2019-06-28 23:08   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 22/28] hw/block/pflash_cfi02: Fix reset command not ignored during erase Philippe Mathieu-Daudé
2019-06-28 23:11   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 23/28] hw/block/pflash_cfi02: Implement multi-sector erase Philippe Mathieu-Daudé
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 24/28] hw/block/pflash_cfi02: Implement erase suspend/resume Philippe Mathieu-Daudé
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 25/28] hw/block/pflash_cfi02: Use chip erase time specified in the CFI table Philippe Mathieu-Daudé
2019-06-28 23:12   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 26/28] hw/block/pflash_cfi02: Reduce single byte/word write delay Philippe Mathieu-Daudé
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 27/28] hw/block/pflash_cfi02: Document commands Philippe Mathieu-Daudé
2019-06-28 23:13   ` Alistair Francis
2019-06-27 20:27 ` [Qemu-devel] [PATCH v5 28/28] hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit Philippe Mathieu-Daudé
2019-06-28 23:13   ` Alistair Francis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.