From: David B. <dbr...@us...> - 2009-12-18 10:33:47
|
This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "Main OpenOCD repository". The branch, master has been updated via e40f6380638ed3f7780b78ceb1411f8b7059a073 (commit) via ef4fbd36d491b1c89cb13d43f6c03e26fd0d8a7d (commit) via b8b4bb0745b63e03eec745ce0eb97bfa6e0792a1 (commit) from 3616b93eee128b0c12fa0d453fbe6ced998e482f (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit e40f6380638ed3f7780b78ceb1411f8b7059a073 Author: David Brownell <dbr...@us...> Date: Fri Dec 18 01:33:19 2009 -0800 stellaris: update bulk flash writes Try to right-size the SRAM buffers, by not: - using them for very small writes - giving up when a large buffer isn't available - allocating buffers much larger than their data Also don't: - bother loading the code unless we allocate the writebuffer too - be so verbose with messaging: * be more concise * reduce importance (e.g. DEBUG not WARNING) * remove duplication The minimum buffer size is something of a guess. It's eight times smaller than before, almost the same size as the code being downloaded. It probably deserves some tuning. Also, note an erratum affecting flash protection on some chips; and narrow many over-wide lines affected by the above changes. Signed-off-by: David Brownell <dbr...@us...> diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c index 4183cba..51fe677 100644 --- a/src/flash/nor/stellaris.c +++ b/src/flash/nor/stellaris.c @@ -748,6 +748,8 @@ static int stellaris_protect(struct flash_bank *bank, int set, int first, int la /* Write commit command */ /* REVISIT safety check, since this cannot be undone * except by the "Recover a locked device" procedure. + * REVISIT DustDevil-A0 parts have an erratum making FMPPE commits + * inadvisable ... it makes future mass erase operations fail. */ LOG_WARNING("Flash protection cannot be removed once commited, commit is NOT executed !"); /* target_write_u32(target, FLASH_FMC, FMC_WRKEY | FMC_COMT); */ @@ -823,37 +825,47 @@ static int stellaris_write_block(struct flash_bank *bank, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; + /* power of two, and multiple of word size */ + static const unsigned buf_min = 32; + + /* for small buffers it's faster not to download an algorithm */ + if (wcount < buf_min) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "", bank, buffer, offset, wcount); /* flash write code */ if (target_alloc_working_area(target, sizeof(stellaris_write_code), &write_algorithm) != ERROR_OK) { - LOG_WARNING("no working area available, can't do block memory writes"); + LOG_DEBUG("no working area for block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; }; - target_write_buffer(target, write_algorithm->address, - sizeof(stellaris_write_code), - (uint8_t *) stellaris_write_code); + /* plus a buffer big enough for this data */ + if (wcount < buffer_size) { + buffer_size = wcount; + buffer_size += buf_min - 1; + buffer_size &= ~(buf_min - 1); + } /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { - LOG_DEBUG("called target_alloc_working_area(target=%p buffer_size=%08" PRIx32 " source=%p)", - target, buffer_size, source); buffer_size /= 2; - if (buffer_size <= 256) + if (buffer_size <= buf_min) { - /* if we already allocated the writing code, but failed to get a buffer, free the algorithm */ - if (write_algorithm) - target_free_working_area(target, write_algorithm); - - LOG_WARNING("no large enough working area available, can't do block memory writes"); + target_free_working_area(target, write_algorithm); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)", + target_name(target), (unsigned) buffer_size); }; + retval = target_write_buffer(target, write_algorithm->address, + sizeof(stellaris_write_code), + (uint8_t *) stellaris_write_code); + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; @@ -870,11 +882,20 @@ static int stellaris_write_block(struct flash_bank *bank, buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, 4*thisrun_count); - LOG_INFO("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count)); - LOG_DEBUG("Algorithm flash write %" PRIi32 " words to 0x%" PRIx32 ", %" PRIi32 " remaining", thisrun_count, address, (wcount - thisrun_count)); - if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params, write_algorithm->address, write_algorithm->address + sizeof(stellaris_write_code)-10, 10000, &armv7m_info)) != ERROR_OK) + LOG_DEBUG("Algorithm flash write %u words to 0x%" PRIx32 + ", %u remaining", + (unsigned) thisrun_count, address, + (unsigned) (wcount - thisrun_count)); + retval = target_run_algorithm(target, 0, NULL, 3, reg_params, + write_algorithm->address, + write_algorithm->address + + sizeof(stellaris_write_code) - 10, + 10000, &armv7m_info); + if (retval != ERROR_OK) { - LOG_ERROR("error executing stellaris flash write algorithm"); + LOG_ERROR("error %d executing stellaris " + "flash write algorithm", + retval); retval = ERROR_FLASH_OPERATION_FAILED; break; } @@ -884,6 +905,10 @@ static int stellaris_write_block(struct flash_bank *bank, wcount -= thisrun_count; } + /* REVISIT we could speed up writing multi-section images by + * not freeing the initialized write_algorithm this way. + */ + target_free_working_area(target, write_algorithm); target_free_working_area(target, source); @@ -942,13 +967,13 @@ static int stellaris_write(struct flash_bank *bank, uint8_t *buffer, uint32_t of if (words_remaining > 0) { /* try using a block write */ - if ((retval = stellaris_write_block(bank, buffer, offset, words_remaining)) != ERROR_OK) + retval = stellaris_write_block(bank, buffer, offset, + words_remaining); + if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - /* if block write failed (no sufficient working area), - * we use normal (slow) single dword accesses */ - LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); + LOG_DEBUG("writing flash word-at-a-time"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { commit ef4fbd36d491b1c89cb13d43f6c03e26fd0d8a7d Author: Dean Glazeski <dn...@gm...> Date: Thu Dec 17 21:02:40 2009 -0600 NAND write data page refactoring. Refactored the write page raw function into two new functions for writing data to a NAND device and then another function to finish up a write to a NAND device. This includes some new updates to introduce more error checking to existing code. [dbr...@us...: fix fault handling, whitespace] Signed-off-by: David Brownell <dbr...@us...> diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index 1056696..50d8249 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -675,7 +675,9 @@ static int nand_write_plain(struct nand_device *nand, uint32_t address, uint8_t } #endif -int nand_write_page(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) +int nand_write_page(struct nand_device *nand, uint32_t page, + uint8_t *data, uint32_t data_size, + uint8_t *oob, uint32_t oob_size) { uint32_t block; @@ -808,66 +810,41 @@ int nand_read_page_raw(struct nand_device *nand, uint32_t page, return ERROR_OK; } -int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) +int nand_write_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) { - uint32_t i; - int retval; - uint8_t status; + int retval = ERROR_NAND_NO_BUFFER; - retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); - if (ERROR_OK != retval) - return retval; + if (nand->controller->write_block_data != NULL) + retval = (nand->controller->write_block_data)(nand, data, size); - if (data) - { - if (nand->controller->write_block_data != NULL) - (nand->controller->write_block_data)(nand, data, data_size); - else - { - for (i = 0; i < data_size;) - { - if (nand->device->options & NAND_BUSWIDTH_16) - { - uint16_t data_buf = le_to_h_u16(data); - nand->controller->write_data(nand, data_buf); - data += 2; - i += 2; - } - else - { - nand->controller->write_data(nand, *data); - data += 1; - i += 1; - } - } - } - } + if (ERROR_NAND_NO_BUFFER == retval) { + bool is16bit = nand->device->options & NAND_BUSWIDTH_16; + uint32_t incr = is16bit ? 2 : 1; + uint16_t write_data; + uint32_t i; - if (oob) - { - if (nand->controller->write_block_data != NULL) - (nand->controller->write_block_data)(nand, oob, oob_size); - else - { - for (i = 0; i < oob_size;) - { - if (nand->device->options & NAND_BUSWIDTH_16) - { - uint16_t oob_buf = le_to_h_u16(data); - nand->controller->write_data(nand, oob_buf); - oob += 2; - i += 2; - } - else - { - nand->controller->write_data(nand, *oob); - oob += 1; - i += 1; - } - } + for (i = 0; i < size; i += incr) { + if (is16bit) + write_data = le_to_h_u16(data); + else + write_data = *data; + + retval = nand->controller->write_data(nand, write_data); + if (ERROR_OK != retval) + break; + + data += incr; } } + return retval; +} + +int nand_write_finish(struct nand_device *nand) +{ + int retval; + uint8_t status; + nand->controller->command(nand, NAND_CMD_PAGEPROG); retval = nand->controller->nand_ready ? @@ -876,18 +853,47 @@ int nand_write_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, if (!retval) return ERROR_NAND_OPERATION_TIMEOUT; - if ((retval = nand_read_status(nand, &status)) != ERROR_OK) - { + retval = nand_read_status(nand, &status); + if (ERROR_OK != retval) { LOG_ERROR("couldn't read status"); return ERROR_NAND_OPERATION_FAILED; } - if (status & NAND_STATUS_FAIL) - { - LOG_ERROR("write operation didn't pass, status: 0x%2.2x", status); + if (status & NAND_STATUS_FAIL) { + LOG_ERROR("write operation didn't pass, status: 0x%2.2x", + status); return ERROR_NAND_OPERATION_FAILED; } return ERROR_OK; } +int nand_write_page_raw(struct nand_device *nand, uint32_t page, + uint8_t *data, uint32_t data_size, + uint8_t *oob, uint32_t oob_size) +{ + int retval; + + retval = nand_page_command(nand, page, NAND_CMD_SEQIN, !data); + if (ERROR_OK != retval) + return retval; + + if (data) { + retval = nand_write_data_page(nand, data, data_size); + if (ERROR_OK != retval) { + LOG_ERROR("Unable to write data to NAND device"); + return retval; + } + } + + if (oob) { + retval = nand_write_data_page(nand, oob, oob_size); + if (ERROR_OK != retval) { + LOG_ERROR("Unable to write OOB data to NAND device"); + return retval; + } + } + + return nand_write_finish(nand); +} + diff --git a/src/flash/nand/core.h b/src/flash/nand/core.h index 990114a..d2d1571 100644 --- a/src/flash/nand/core.h +++ b/src/flash/nand/core.h @@ -212,6 +212,10 @@ int nand_page_command(struct nand_device *nand, uint32_t page, uint8_t cmd, bool oob_only); int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); +int nand_write_data_page(struct nand_device *nand, + uint8_t *data, uint32_t size); + +int nand_write_finish(struct nand_device *nand); int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); commit b8b4bb0745b63e03eec745ce0eb97bfa6e0792a1 Author: Dean Glazeski <dn...@gm...> Date: Thu Dec 17 21:02:39 2009 -0600 NAND read data page refactor. Added a new function to encapsulate reading a page of data from a NAND device using either the read_block_data function of a NAND controller or to use direct reading of data from the NAND device. This also adds some performance enhancements and uses the read_data function if the read_block_data function fails safely (because it can't allocate a buffer in the working area). [dbr...@us...: fix fault handling, whitespace] Signed-off-by: David Brownell <dbr...@us...> diff --git a/src/flash/nand/core.c b/src/flash/nand/core.c index d52cf5d..1056696 100644 --- a/src/flash/nand/core.c +++ b/src/flash/nand/core.c @@ -768,11 +768,31 @@ int nand_page_command(struct nand_device *nand, uint32_t page, return ERROR_OK; } +int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size) +{ + int retval = ERROR_NAND_NO_BUFFER; + + if (nand->controller->read_block_data != NULL) + retval = (nand->controller->read_block_data)(nand, data, size); + + if (ERROR_NAND_NO_BUFFER == retval) { + uint32_t i; + int incr = (nand->device->options & NAND_BUSWIDTH_16) ? 2 : 1; + + retval = ERROR_OK; + for (i = 0; retval == ERROR_OK && i < size; i += incr) { + retval = nand->controller->read_data(nand, data); + data += incr; + } + } + + return retval; +} + int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size) { - uint32_t i; int retval; retval = nand_page_command(nand, page, NAND_CMD_READ0, !data); @@ -780,52 +800,10 @@ int nand_read_page_raw(struct nand_device *nand, uint32_t page, return retval; if (data) - { - if (nand->controller->read_block_data != NULL) - (nand->controller->read_block_data)(nand, data, data_size); - else - { - for (i = 0; i < data_size;) - { - if (nand->device->options & NAND_BUSWIDTH_16) - { - nand->controller->read_data(nand, data); - data += 2; - i += 2; - } - else - { - nand->controller->read_data(nand, data); - data += 1; - i += 1; - } - } - } - } + nand_read_data_page(nand, data, data_size); if (oob) - { - if (nand->controller->read_block_data != NULL) - (nand->controller->read_block_data)(nand, oob, oob_size); - else - { - for (i = 0; i < oob_size;) - { - if (nand->device->options & NAND_BUSWIDTH_16) - { - nand->controller->read_data(nand, oob); - oob += 2; - i += 2; - } - else - { - nand->controller->read_data(nand, oob); - oob += 1; - i += 1; - } - } - } - } + nand_read_data_page(nand, oob, oob_size); return ERROR_OK; } diff --git a/src/flash/nand/core.h b/src/flash/nand/core.h index b8dc01c..990114a 100644 --- a/src/flash/nand/core.h +++ b/src/flash/nand/core.h @@ -211,6 +211,8 @@ struct nand_device *get_nand_device_by_num(int num); int nand_page_command(struct nand_device *nand, uint32_t page, uint8_t cmd, bool oob_only); +int nand_read_data_page(struct nand_device *nand, uint8_t *data, uint32_t size); + int nand_read_page_raw(struct nand_device *nand, uint32_t page, uint8_t *data, uint32_t data_size, uint8_t *oob, uint32_t oob_size); int nand_write_page_raw(struct nand_device *nand, uint32_t page, ----------------------------------------------------------------------- Summary of changes: src/flash/nand/core.c | 192 +++++++++++++++++++++------------------------ src/flash/nand/core.h | 6 ++ src/flash/nor/stellaris.c | 65 +++++++++++----- 3 files changed, 139 insertions(+), 124 deletions(-) hooks/post-receive -- Main OpenOCD repository |