From 45328ea12498e857262ae571710d01cb38302a9f Mon Sep 17 00:00:00 2001 From: Gareth McMullin Date: Thu, 26 Mar 2015 22:20:47 -0700 Subject: [PATCH] Add buffering support for flash drivers. Some devices can get a significant boost in performance by writing to flash memories one page at a time. Generic function to do this are provided at the target layer and may be used by flash drivers. --- src/include/target.h | 9 ++++++++ src/target.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/include/target.h b/src/include/target.h index f49bc58..96b5506 100644 --- a/src/include/target.h +++ b/src/include/target.h @@ -133,6 +133,12 @@ struct target_flash { struct target_flash *next; int align; uint8_t erased; + + /* For buffered flash */ + size_t buf_size; + flash_write_func write_buf; + uint32_t buf_addr; + void *buf; }; struct target_s { @@ -215,6 +221,9 @@ void target_add_commands(target *t, const struct command_s *cmds, const char *na void target_add_ram(target *t, uint32_t start, uint32_t len); void target_add_flash(target *t, struct target_flash *f); const char *target_mem_map(target *t); +int target_flash_write_buffered(struct target_flash *f, + uint32_t dest, const void *src, size_t len); +int target_flash_done_buffered(struct target_flash *f); static inline uint32_t target_mem_read32(target *t, uint32_t addr) { diff --git a/src/target.c b/src/target.c index 3ab59bc..266c23e 100644 --- a/src/target.c +++ b/src/target.c @@ -57,6 +57,8 @@ void target_list_free(void) } while (target_list->flash) { void * next = target_list->flash->next; + if (target_list->flash->buf) + free(target_list->flash->buf); free(target_list->flash); target_list->flash = next; } @@ -216,3 +218,51 @@ int target_flash_done(target *t) return 0; } +int target_flash_write_buffered(struct target_flash *f, + uint32_t dest, const void *src, size_t len) +{ + int ret = 0; + + if (f->buf == NULL) { + /* Allocate flash sector buffer */ + f->buf = malloc(f->buf_size); + f->buf_addr = -1; + } + while (len) { + uint32_t offset = dest % f->buf_size; + uint32_t base = dest - offset; + if (base != f->buf_addr) { + if (f->buf_addr != (uint32_t)-1) { + /* Write sector to flash if valid */ + ret |= f->write_buf(f, f->buf_addr, + f->buf, f->buf_size); + } + /* Setup buffer for a new sector */ + f->buf_addr = base; + memset(f->buf, f->erased, f->buf_size); + } + /* Copy chunk into sector buffer */ + size_t sectlen = MIN(f->buf_size - offset, len); + memcpy(f->buf + offset, src, sectlen); + dest += sectlen; + src += sectlen; + len -= sectlen; + } + return ret; +} + +int target_flash_done_buffered(struct target_flash *f) +{ + int ret = 0; + if ((f->buf != NULL) &&(f->buf_addr != (uint32_t)-1)) { + /* Write sector to flash if valid */ + ret = f->write_buf(f, f->buf_addr, f->buf, f->buf_size); + f->buf_addr = -1; + free(f->buf); + f->buf = NULL; + } + + return ret; +} + +