From e8aa2d95ea2015ce95d712543c78e09a0130be3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Jun 2019 18:39:10 +0200 Subject: hw/block/pflash: Simplify trace_pflash_io_read/write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reviewed-by: Stephen Checkoway Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-3-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 5 +++-- hw/block/pflash_cfi02.c | 6 ++---- hw/block/trace-events | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) (limited to 'hw') 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" -- cgit v1.2.3 From c1474acd5d284d69d1543713ef00b90b9712619f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 26 Jun 2019 18:40:09 +0200 Subject: hw/block/pflash: Simplify trace_pflash_data_read/write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use a field width format to have a single function to log the different width accesses. Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-4-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi01.c | 6 ++---- hw/block/pflash_cfi02.c | 6 ++---- hw/block/trace-events | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) (limited to 'hw') 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 -- cgit v1.2.3 From 6536987fd6aa52adbb6c128db1952e7c62f5c82b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 1 May 2019 18:15:35 +0200 Subject: hw/block/pflash_cfi02: Fix debug format string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always compile the debug code to prevent format string to bitrot. Delete dead code. Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch, use PRIx32] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'hw') 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; -- cgit v1.2.3 From aeaf6c20dbcfed5c459d9f6b39cb5fa2187f0b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 5 May 2019 22:42:08 +0200 Subject: hw/block/pflash_cfi02: Add an enum to define the write cycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No change in functionality is intended with this commit. Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'hw') 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: -- cgit v1.2.3 From 1d311e738b223452bbfb8ce10cc3327db7bca3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 1 May 2019 18:14:25 +0200 Subject: hw/block/pflash_cfi02: Add helpers to manipulate the status bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'hw') 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)); -- cgit v1.2.3 From 7f7bdcaff5ad88a79257d6b28f95d0491b7f9002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 5 May 2019 23:04:48 +0200 Subject: hw/block/pflash_cfi02: Simplify a statement using fall through MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'hw') 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; } -- cgit v1.2.3 From c3d25271b2117a1416f5818d9d2b399b4e1e77b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 5 May 2019 23:14:29 +0200 Subject: hw/block/pflash_cfi02: Use the ldst API in pflash_write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The load/store API eases code review. Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) (limited to 'hw') 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 -- cgit v1.2.3 From 3e4bcf89b7acea62e248ee048c1c67767be88f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 5 May 2019 23:21:19 +0200 Subject: hw/block/pflash_cfi02: Use the ldst API in pflash_read() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The load/store API eases code review. Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch, simplified tracing] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) (limited to 'hw') 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; -- cgit v1.2.3 From 06e8b8e3e1bb5f2d189197b050b23d9da3955a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 5 May 2019 23:24:51 +0200 Subject: hw/block/pflash_cfi02: Extract the pflash_data_read() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the code block in a new function, remove a goto statement. Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch, remove the XXX tracing comment] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'hw') 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; -- cgit v1.2.3 From aff498cf30363788c8a248ec961829488d37f65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 1 May 2019 18:15:56 +0200 Subject: hw/block/pflash_cfi02: Unify the MemoryRegionOps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-3-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch to ease review] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 60 +++++++++++++------------------------------------ 1 file changed, 15 insertions(+), 45 deletions(-) (limited to 'hw') 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; -- cgit v1.2.3 From 6682bc1ee431dc6198b85ac71d537104cfc57fed Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:17 -0400 Subject: hw/block/pflash_cfi02: Fix command address comparison MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-4-stephen.checkoway@oberlin.edu> Acked-by: Thomas Huth Acked-by: Alistair Francis Acked-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'hw') 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); -- cgit v1.2.3 From 1eb27d692ead211ff19667c5447fe9701c9fd992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 18 May 2019 14:45:35 +0200 Subject: hw/block/pflash_cfi02: Remove pointless local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can directly use pfl->total_len, remove the local 'chip_len' variable. Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'hw') 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; -- cgit v1.2.3 From 9ac45b886ac36937ff0969d63c5b819b4efaa337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 18 May 2019 20:21:28 +0200 Subject: hw/block/pflash_cfi02: Document the current CFI values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stephen Checkoway Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Acked-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'hw') 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; } -- cgit v1.2.3 From d6874c8391f733d86f0ae85cc564109d7f01691d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 18 May 2019 20:00:36 +0200 Subject: hw/block/pflash_cfi02: Hold the PRI table offset in a variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-17-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'hw') 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[] = { -- cgit v1.2.3 From c2c1bf44a9b7f620b0565d17e33e7c5a04a5c51a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 18 May 2019 20:23:31 +0200 Subject: hw/block/pflash_cfi02: Document 'Page Mode' operations are not supported MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Extracted from bigger patch] Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'hw') 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[] = { -- cgit v1.2.3 From 64659053557a6a19bb00bb226e9b4d8f78cead7b Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:19 -0400 Subject: hw/block/pflash_cfi02: Implement nonuniform sector sizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-6-stephen.checkoway@oberlin.edu> Acked-by: Thomas Huth Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Rebased, add assert() on pri_offset] Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 141 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 114 insertions(+), 27 deletions(-) (limited to 'hw') 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), -- cgit v1.2.3 From 102f0f79a51cfc289f7ad19a10be654925faeff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 18 May 2019 20:57:02 +0200 Subject: hw/block/pflash_cfi02: Extract pflash_regions_count() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the pflash_regions_count() function, the code will be easier to review. Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-20-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'hw') 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]; -- cgit v1.2.3 From 8a508e7064bbe7d434a93f3284e6d93881c68a44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 27 Jun 2019 15:44:24 +0200 Subject: hw/block/pflash_cfi02: Split if() condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the if() condition check and arrange the indentation to ease the review of the next patches. No logical change. Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-21-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'hw') 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; -- cgit v1.2.3 From 46fb7809b5520e2cb77bdc86270b0c393e4b1210 Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:20 -0400 Subject: hw/block/pflash_cfi02: Fix CFI in autoselect mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-7-stephen.checkoway@oberlin.edu> Tested-by: Philippe Mathieu-Daudé Acked-by: Thomas Huth Acked-by: Alistair Francis Acked-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'hw') 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: -- cgit v1.2.3 From a97910423975b9fee1dbcdc1a2488804d4092c36 Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:21 -0400 Subject: hw/block/pflash_cfi02: Fix reset command not ignored during erase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-8-stephen.checkoway@oberlin.edu> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Tested-by: Philippe Mathieu-Daudé Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'hw') 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; -- cgit v1.2.3 From a50547aca54c0e55122c32c077cab747147a6b30 Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:22 -0400 Subject: hw/block/pflash_cfi02: Implement multi-sector erase MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-9-stephen.checkoway@oberlin.edu> Acked-by: Thomas Huth Acked-by: Philippe Mathieu-Daudé [PMD: Rebased] Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 94 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 18 deletions(-) (limited to 'hw') 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 */ -- cgit v1.2.3 From ddb6f2254871c7c686561c4b41d52e2f0413f9a1 Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:23 -0400 Subject: hw/block/pflash_cfi02: Implement erase suspend/resume MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-10-stephen.checkoway@oberlin.edu> Acked-by: Thomas Huth Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé [PMD: Rebased] Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 154 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 140 insertions(+), 14 deletions(-) (limited to 'hw') 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) -- cgit v1.2.3 From 80f2c625cbd67447a750c0c6c5d377dfa65d4d7d Mon Sep 17 00:00:00 2001 From: Stephen Checkoway Date: Fri, 26 Apr 2019 12:26:24 -0400 Subject: hw/block/pflash_cfi02: Use chip erase time specified in the CFI table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Message-Id: <20190426162624.55977-11-stephen.checkoway@oberlin.edu> Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'hw') 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 */ -- cgit v1.2.3 From b03499371785cd9a0d8157ec8bd1c19a2bf8b5c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 18 May 2019 21:22:03 +0200 Subject: hw/block/pflash_cfi02: Document commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-28-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) (limited to 'hw') diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index b2d37c33bb..83084b9d72 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 -- cgit v1.2.3 From 3ae0343db69c379beb5750b4ed70794bbed51b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 27 Jun 2019 19:45:08 +0200 Subject: hw/block/pflash_cfi02: Reduce I/O accesses to 16-bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parallel NOR flashes are limited to 16-bit bus accesses. Remove the 32-bit dead code. Reviewed-by: Alistair Francis Message-Id: <20190627202719.17739-29-philmd@redhat.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/block/pflash_cfi02.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 83084b9d72..5392290c72 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, -- cgit v1.2.3