diff options
author | Namyoon Woo <namyoon@chromium.org> | 2019-03-26 15:19:24 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-12 14:50:00 -0700 |
commit | a256570f5fbe9605500f66aaf1b2484c09229d96 (patch) | |
tree | f312586b08b59d01bc911213d26e2c59bd0f61b6 /util | |
parent | 985924cb008d94e811a1adf15a311e41ca9992e6 (diff) | |
download | chrome-ec-a256570f5fbe9605500f66aaf1b2484c09229d96.tar.gz |
stm32mon: retry on damaged ACK, NACK or timeout
BUG=b:112837404
BRANCH=None
TEST=manually ran stm32mon or flash_ec on scarlet and DragonTalon.
1. stm32mon via Servo V4 type-C at 57600 bps on scarlet.
$ ./util/flash_ec --board scarlet --image ${IMG} \
--bitbang_rate 57600 --verbose
2. stm32mon via Servo V4 type-C at 9600 bps on scarlet.
which tends to fail for NACK or timeout.
$ ./util/flash_ec --board scarlet --image ${IMG} \
--bitbang_rate 9600 --verbose
3. flash_ec via Servo Micro on scarlet
$ ./util/flash_ec --board scarlet --image ${IMG} --verbose
4. flash_ec on DragonTalon via Servo V2 and Servo Micro
respectively.
$ ./util/flash_ec --board hatch_fp --image ${IMG} --verbose
Full log can be found at http://gpaste/5439133910564864
Change-Id: I3c8e8c81d9d12475f5722eaacc932dc1244625d5
Signed-off-by: Namyoon Woo <namyoon@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1540496
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Reviewed-by: Matthew Blecker <matthewb@chromium.org>
Diffstat (limited to 'util')
-rw-r--r-- | util/stm32mon.c | 379 |
1 files changed, 253 insertions, 126 deletions
diff --git a/util/stm32mon.c b/util/stm32mon.c index 601a53238e..05788b9189 100644 --- a/util/stm32mon.c +++ b/util/stm32mon.c @@ -20,6 +20,7 @@ #define _BSD_SOURCE /* Older glibc */ #include <arpa/inet.h> +#include <compile_time_macros.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> @@ -63,9 +64,10 @@ #define CMD_RP 0x82 /* Enables the read protection */ #define CMD_RU 0x92 /* Disables the read protection */ -#define RESP_NACK 0x1f -#define RESP_ACK 0x79 -#define RESP_BUSY 0x76 +#define RESP_NACK 0x1f +#define RESP_ACK 0x79 /* 0b 0111 1001 */ +#define RESP_BUSY 0x76 +#define RESP_DAMAGED_ACK 0xBC /* 0b 1011 1100, 1 bit shifted REST_ACK */ /* SPI Start of Frame */ #define SOF 0x5A @@ -204,6 +206,8 @@ struct stm32_def { #define DEFAULT_BAUDRATE B38400 #define PAGE_SIZE 256 #define INVALID_I2C_ADAPTER -1 +#define MAX_ACK_RETRY_COUNT (EXT_ERASE_TIMEOUT / DEFAULT_TIMEOUT) +#define MAX_RETRY_COUNT 3 enum interface_mode { MODE_SERIAL, @@ -227,6 +231,20 @@ const char *serial_port = "/dev/ttyUSB1"; const char *input_filename; const char *output_filename; uint32_t offset = 0x08000000, length = 0; +int retry_on_damaged_ack; + +/* STM32MON function return values */ +enum { + STM32_SUCCESS = 0, + STM32_EIO = -1, /* IO error */ + STM32_EINVAL = -2, /* Got a faulty response from device */ + STM32_ETIMEDOUT = -3, /* Device didn't respond in a time window. */ + STM32_ENOMEM = -4, /* Failed to allocate memory. */ + STM32_ENACK = -5, /* Got NACK. */ + STM32_EDACK = -6, /* Got a damanged ACK. */ +}; +BUILD_ASSERT(STM32_SUCCESS == 0); +#define IS_STM32_ERROR(res) ((res) < STM32_SUCCESS) /* optional command flags */ enum { @@ -257,6 +275,29 @@ static void discard_input(int); /* On user request save all data exchange with the target in this log file. */ static FILE *log_file; +/* Statistic data structure for response kind. */ +struct { + const char * const event_name; + uint32_t event_count; +} stat_resp[] = { + { "RESP_ACK", 0 }, + { "RESP_NACK", 0 }, + { "RESP_BUSY", 0 }, + { "RESP_DAMAGED_ACK", 0 }, + { "JUNK", 0 }, +}; + +enum { + RESP_ACK_IDX = 0, + RESP_NACK_IDX, + RESP_BUSY_IDX, + RESP_DAMAGED_ACK_IDX, + JUNK_IDX, + MAX_EVENT_IDX +}; + +BUILD_ASSERT(ARRAY_SIZE(stat_resp) == MAX_EVENT_IDX); + /* * Print data into the log file, in hex, 16 bytes per line, prefix the first * line with the value supplied by the caller (usually 'r' or 'w' for @@ -305,6 +346,7 @@ static ssize_t write_wrapper(int fd, const void *buf, size_t count) return rv; } + int open_serial(const char *port, int cr50_mode) { int fd, res; @@ -472,39 +514,62 @@ int wait_for_ack(int fd) uint8_t resp; int res; time_t deadline = time(NULL) + DEFAULT_TIMEOUT; - uint8_t ack = RESP_ACK; + const uint8_t ack = RESP_ACK; while (time(NULL) < deadline) { res = read_wrapper(fd, &resp, 1); if ((res < 0) && (errno != EAGAIN)) { perror("Failed to read answer"); - return -EIO; + return STM32_EIO; } - if (res == 1) { - if (resp == RESP_ACK) { - if (mode == MODE_SPI) /* Ack the ACK */ - if (write_wrapper(fd, &ack, 1) != 1) - return -EIO; - return 0; - } else if (resp == RESP_NACK) { - fprintf(stderr, "NACK\n"); - if (mode == MODE_SPI) /* Ack the NACK */ - if (write_wrapper(fd, &ack, 1) != 1) - return -EIO; - discard_input(fd); - return -EINVAL; - } else if (resp == RESP_BUSY) { - /* I2C Boot protocol 1.1 */ - deadline = time(NULL) + DEFAULT_TIMEOUT; - } else { - if (mode == MODE_SERIAL) - fprintf(stderr, "Receive junk: %02x\n", - resp); + + if (res != 1) + continue; + + switch (resp) { + case RESP_ACK: + stat_resp[RESP_ACK_IDX].event_count++; + if (mode == MODE_SPI) /* Ack the ACK */ + if (write_wrapper(fd, &ack, 1) != 1) + return STM32_EIO; + return STM32_SUCCESS; + + case RESP_NACK: + stat_resp[RESP_NACK_IDX].event_count++; + fprintf(stderr, "NACK\n"); + if (mode == MODE_SPI) /* Ack the NACK */ + if (write_wrapper(fd, &ack, 1) != 1) + return STM32_EIO; + discard_input(fd); + return STM32_ENACK; + + case RESP_BUSY: + stat_resp[RESP_BUSY_IDX].event_count++; + /* I2C Boot protocol 1.1 */ + deadline = time(NULL) + DEFAULT_TIMEOUT; + break; + + case RESP_DAMAGED_ACK: + if (retry_on_damaged_ack) { + /* It is a damaged ACK. However, device is + * likely to believe it sent ACK, so let's not + * treat it as junk. + */ + stat_resp[RESP_DAMAGED_ACK_IDX].event_count++; + fprintf(stderr, "DAMAGED_ACK\n"); + return STM32_EDACK; } + + /* Do not break so that it can be handled as junk */ + default: + stat_resp[JUNK_IDX].event_count++; + if (mode == MODE_SERIAL) + fprintf(stderr, "Receive junk: %02x\n", resp); + break; } } fprintf(stderr, "Timeout\n"); - return -ETIMEDOUT; + return STM32_ETIMEDOUT; } int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, @@ -516,19 +581,23 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, uint8_t cmd_frame[] = { SOF, cmd, 0xff ^ cmd }; /* XOR checksum */ /* only the SPI mode needs the Start Of Frame byte */ int cmd_off = mode == MODE_SPI ? 0 : 1; + int count_damaged_ack = 0; /* Send the command index */ res = write_wrapper(fd, cmd_frame + cmd_off, sizeof(cmd_frame) - cmd_off); if (res <= 0) { perror("Failed to write command frame"); - return -1; + return STM32_EIO; } /* Wait for the ACK */ - if (wait_for_ack(fd) < 0) { + res = wait_for_ack(fd); + if (res == STM32_EDACK) { + ++count_damaged_ack; + } else if (IS_STM32_ERROR(res)) { fprintf(stderr, "Failed to get command 0x%02x ACK\n", cmd); - return -1; + return res; } /* Send the command payloads */ @@ -540,7 +609,7 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, if (data == NULL) { fprintf(stderr, "Failed to allocate memory for load %d\n", c); - return -ENOMEM; + return STM32_ENOMEM; } memcpy(data, p->data, size); for (i = 0; i < size; i++) @@ -555,35 +624,36 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, if (res < 0) { perror("Failed to write command payload"); free(data); - return -1; + return STM32_EIO; } size -= res; data_ptr += res; } + free(data); /* Wait for the ACK */ res = wait_for_ack(fd); - if (res < 0) { - if (res != -ETIMEDOUT) + if (res == STM32_EDACK) { + ++count_damaged_ack; + } else if (IS_STM32_ERROR(res)) { + if (res != STM32_ETIMEDOUT) fprintf(stderr, "payload %d ACK failed for CMD%02x\n", c, cmd); - free(data); return res; } - free(data); } /* Read the answer payload */ if (resp) { if (mode == MODE_SPI) /* ignore dummy byte */ if (read_wrapper(fd, resp, 1) < 0) - return -1; + return STM32_EIO; while ((resp_size > 0) && (res = read_wrapper(fd, resp, resp_size))) { if (res < 0) { perror("Failed to read payload"); - return -1; + return STM32_EIO; } readcnt += res; resp += res; @@ -592,17 +662,48 @@ int send_command(int fd, uint8_t cmd, payload_t *loads, int cnt, /* Wait for the ACK */ if (ack_requested) { - if (wait_for_ack(fd) < 0) { + res = wait_for_ack(fd); + if (res == STM32_EDACK) { + ++count_damaged_ack; + } else if (IS_STM32_ERROR(res)) { fprintf(stderr, - "Failed to get response to command 0x%02x ACK\n", - cmd); - return -1; + "Failed to get response to command" + " 0x%02x ACK\n", cmd); + return res; } } } + + if (count_damaged_ack) + return STM32_EDACK; + return readcnt; } +int send_command_retry(int fd, uint8_t cmd, payload_t *loads, + int cnt, uint8_t *resp, int resp_size, int ack_requested) +{ + int res; + int retries = MAX_RETRY_COUNT; + + do { + int ack_tries = MAX_ACK_RETRY_COUNT; + + res = send_command(fd, cmd, loads, cnt, resp, resp_size, + ack_requested); + + while (res == STM32_ETIMEDOUT && ack_tries--) { + if (cmd == CMD_WRITEMEM) { + /* send garbage byte */ + write_wrapper(fd, loads->data, 1); + } + res = wait_for_ack(fd); + } + } while ((res == STM32_ENACK || res == STM32_EDACK) && retries--); + + return res; +} + struct stm32_def *command_get_id(int fd) { int res; @@ -637,7 +738,7 @@ int init_monitor(int fd) /* Skip in i2c mode */ if (mode == MODE_I2C) - return 0; + return STM32_SUCCESS; printf("Waiting for the monitor startup ..."); fflush(stdout); @@ -647,23 +748,23 @@ int init_monitor(int fd) res = write_wrapper(fd, &init, 1); if (res <= 0) { perror("Failed to write command"); - return -1; + return STM32_EIO; } /* Wait for the ACK */ res = wait_for_ack(fd); - if (res == 0) + if (res == STM32_SUCCESS) break; - if (res == -EINVAL) { + if (res == STM32_ENACK) { /* we got NACK'ed, the loader might be already started * let's ping it to check */ if (command_get_id(fd)) { printf("Monitor already started.\n"); - return 0; + return STM32_SUCCESS; } } - if (res < 0 && res != -ETIMEDOUT) - return -1; + if (IS_STM32_ERROR(res) && res != STM32_ETIMEDOUT) + return res; fflush(stdout); } printf("Done.\n"); @@ -671,7 +772,7 @@ int init_monitor(int fd) /* read trailing chars */ discard_input(fd); - return 0; + return STM32_SUCCESS; } int command_get_commands(int fd, struct stm32_def *chip) @@ -688,7 +789,7 @@ int command_get_commands(int fd, struct stm32_def *chip) if (cmds[0] > sizeof(cmds) - 2) { fprintf(stderr, "invalid GET answer (%02x...)\n", cmds[0]); - return -1; + return STM32_EINVAL; } printf("Bootloader v%d.%d, commands : ", cmds[1] >> 4, cmds[1] & 0xf); @@ -705,11 +806,11 @@ int command_get_commands(int fd, struct stm32_def *chip) erase = command_erase_i2c; printf("\n"); - return 0; + return STM32_SUCCESS; } fprintf(stderr, "Cannot get bootloader command list.\n"); - return -1; + return STM32_EINVAL; } static int use_progressbar; @@ -729,6 +830,7 @@ static void draw_spinner(uint32_t remaining, uint32_t size) printf("\r%c%3d%%", wheel[windex++], percent); windex %= sizeof(wheel); } + fflush(stdout); } int command_read_mem(int fd, uint32_t address, uint32_t size, uint8_t *buffer) @@ -743,18 +845,21 @@ int command_read_mem(int fd, uint32_t address, uint32_t size, uint8_t *buffer) }; while (remaining) { - cnt = (remaining > PAGE_SIZE) ? PAGE_SIZE - 1 : remaining - 1; + uint32_t bytes = MIN(remaining, PAGE_SIZE); + + cnt = (uint8_t) (bytes - 1); addr_be = htonl(address); draw_spinner(remaining, size); - fflush(stdout); - res = send_command(fd, CMD_READMEM, loads, 2, buffer, cnt + 1, - 0); - if (res < 0) - return -EIO; - buffer += cnt + 1; - address += cnt + 1; - remaining -= cnt + 1; + + res = send_command_retry(fd, CMD_READMEM, loads, 2, buffer, + bytes, 0); + if (IS_STM32_ERROR(res)) + return STM32_EIO; + + buffer += bytes; + address += bytes; + remaining -= bytes; } return size; @@ -774,7 +879,7 @@ int command_write_mem(int fd, uint32_t address, uint32_t size, uint8_t *buffer) }; while (remaining) { - cnt = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining; + cnt = MIN(remaining, PAGE_SIZE); /* skip empty blocks to save time */ for (i = 0; i < cnt && buffer[i] == 0xff; i++) ; @@ -785,11 +890,11 @@ int command_write_mem(int fd, uint32_t address, uint32_t size, uint8_t *buffer) memcpy(outbuf + 1, buffer, cnt); draw_spinner(remaining, size); - fflush(stdout); - res = send_command(fd, CMD_WRITEMEM, loads, 2, + + res = send_command_retry(fd, CMD_WRITEMEM, loads, 2, NULL, 0, 1); - if (res < 0) - return -EIO; + if (IS_STM32_ERROR(res)) + return STM32_EIO; } buffer += cnt; address += cnt; @@ -805,7 +910,6 @@ int command_ext_erase(int fd, uint16_t count, uint16_t start) uint16_t count_be = htons(count); payload_t load = { 2, (uint8_t *)&count_be }; uint16_t *pages = NULL; - int retries = EXT_ERASE_TIMEOUT / DEFAULT_TIMEOUT; if (count < 0xfff0) { int i; @@ -813,7 +917,7 @@ int command_ext_erase(int fd, uint16_t count, uint16_t start) load.size = 2 * (count + 1); pages = malloc(load.size); if (!pages) - return -ENOMEM; + return STM32_ENOMEM; load.data = (uint8_t *)pages; pages[0] = htons(count - 1); for (i = 0; i < count; i++) @@ -821,11 +925,8 @@ int command_ext_erase(int fd, uint16_t count, uint16_t start) } printf("Erasing...\n"); - res = send_command(fd, CMD_EXTERASE, &load, 1, NULL, 0, 1); - /* Erase can take long time (e.g. 13s+ on STM32H7) */ - while ((res == -ETIMEDOUT) && --retries) - res = wait_for_ack(fd); - if (res >= 0) + res = send_command_retry(fd, CMD_EXTERASE, &load, 1, NULL, 0, 1); + if (!IS_STM32_ERROR(res)) printf("Flash erased.\n"); if (pages) @@ -857,20 +958,19 @@ int command_erase_i2c(int fd, uint16_t count, uint16_t start) load[1].size = 2 * count; pages = malloc(load[1].size); if (!pages) - return -ENOMEM; + return STM32_ENOMEM; load[1].data = (uint8_t *)pages; count_be = htons(count - 1); for (i = 0; i < count; i++) pages[i] = htons(start + i); - } else { - load_cnt = 1; } - erase_cmd = (boot_loader_version == 0x10 ? CMD_EXTERASE : - CMD_NO_STRETCH_ERASE); - res = send_command(fd, erase_cmd, load, load_cnt, - NULL, 0, 1); - if (res >= 0) + erase_cmd = (boot_loader_version == 0x10) ? CMD_EXTERASE : + CMD_NO_STRETCH_ERASE; + + printf("Erasing...\n"); + res = send_command(fd, erase_cmd, load, load_cnt, NULL, 0, 1); + if (!IS_STM32_ERROR(res)) printf("Flash erased.\n"); if (pages) @@ -892,15 +992,16 @@ int command_erase(int fd, uint16_t count, uint16_t start) load.size = count + 1; pages = malloc(load.size); if (!pages) - return -ENOMEM; + return STM32_ENOMEM; load.data = (uint8_t *)pages; pages[0] = count - 1; for (i = 0; i < count; i++) pages[i+1] = start + i; } + printf("Erasing...\n"); res = send_command(fd, CMD_ERASE, &load, 1, NULL, 0, 1); - if (res >= 0) + if (!IS_STM32_ERROR(res)) printf("Flash erased.\n"); if (pages) @@ -911,7 +1012,7 @@ int command_erase(int fd, uint16_t count, uint16_t start) int command_read_unprotect(int fd) { int res; - int retries = EXT_ERASE_TIMEOUT / DEFAULT_TIMEOUT; + int retries = MAX_RETRY_COUNT; printf("Unprotecting flash read...\n"); @@ -922,9 +1023,9 @@ int command_read_unprotect(int fd) */ do { res = wait_for_ack(fd); - } while ((res == -ETIMEDOUT) && --retries); + } while ((res == STM32_ETIMEDOUT) && --retries); - if (res < 0) { + if (IS_STM32_ERROR(res)) { fprintf(stderr, "Failed to get read-protect ACK\n"); return res; } @@ -939,10 +1040,10 @@ int command_read_unprotect(int fd) usleep(MAX_DELAY_REBOOT); if (init_monitor(fd) < 0) { fprintf(stderr, "Cannot recover after RU reset\n"); - return -EIO; + return STM32_EIO; } - return 0; + return STM32_SUCCESS; } int command_write_unprotect(int fd) @@ -950,13 +1051,13 @@ int command_write_unprotect(int fd) int res; res = send_command(fd, CMD_WU, NULL, 0, NULL, 0, 1); - if (res < 0) - return -EIO; + if (IS_STM32_ERROR(res)) + return STM32_EIO; /* Wait for the ACK */ if (wait_for_ack(fd) < 0) { fprintf(stderr, "Failed to get write-protect ACK\n"); - return -EINVAL; + return STM32_EINVAL; } printf("Flash write unprotected.\n"); @@ -969,10 +1070,10 @@ int command_write_unprotect(int fd) usleep(MAX_DELAY_REBOOT); if (init_monitor(fd) < 0) { fprintf(stderr, "Cannot recover after WP reset\n"); - return -EIO; + return STM32_EIO; } - return 0; + return STM32_SUCCESS; } int command_go(int fd, uint32_t address) @@ -982,8 +1083,8 @@ int command_go(int fd, uint32_t address) payload_t load = { 4, (uint8_t *)&addr_be }; res = send_command(fd, CMD_GO, &load, 1, NULL, 0, 1); - if (res < 0) - return -EIO; + if (IS_STM32_ERROR(res)) + return STM32_EIO; #if 0 /* this ACK should exist according to the documentation ... */ /* Wait for the ACK */ @@ -994,7 +1095,7 @@ int command_go(int fd, uint32_t address) #endif printf("Program started at 0x%08x.\n", address); - return 0; + return STM32_SUCCESS; } /* @@ -1031,13 +1132,13 @@ int read_device_signature_register(int fd, const struct stm32_def *chip, if (!otp.addr) { fprintf(stderr, "No otp_area.addr specified for given chip.\n"); - return -EINVAL; + return STM32_EINVAL; } if (addr <= otp_end_addr) { fprintf(stderr, "Attempting to read from invalid address: " "%08X\n", addr); - return -EINVAL; + return STM32_EINVAL; } /* @@ -1052,14 +1153,14 @@ int read_device_signature_register(int fd, const struct stm32_def *chip, fprintf(stderr, "Requested register 0x%08X is outside read range.\n", addr); - return -EINVAL; + return STM32_EINVAL; } buffer = malloc(read_size_bytes); if (!buffer) { fprintf(stderr, "Cannot allocate %" PRIu32 " bytes\n", read_size_bytes); - return -ENOMEM; + return STM32_ENOMEM; } res = command_read_mem(fd, otp_end_addr, read_size_bytes, buffer); @@ -1071,7 +1172,7 @@ int read_device_signature_register(int fd, const struct stm32_def *chip, read_size_bytes, otp_end_addr); free(buffer); - return (res < 0) ? res : 0; + return IS_STM32_ERROR(res) ? res : STM32_SUCCESS; } /* Return zero on success, a negative error value on failures. */ @@ -1082,13 +1183,13 @@ int read_flash_size_register(int fd, struct stm32_def *chip, uint32_t flash_size_addr = chip->device_signature.flash_size_addr; if (!flash_size_addr) - return -EINVAL; + return STM32_EINVAL; res = read_device_signature_register(fd, chip, flash_size_addr, sizeof(*flash_size_kbytes), (uint8_t *)flash_size_kbytes); - if (!res) + if (!IS_STM32_ERROR(res)) printf("Flash size: %" PRIu16 " KB\n", *flash_size_kbytes); else fprintf(stderr, @@ -1108,12 +1209,12 @@ int read_unique_device_id_register(int fd, struct stm32_def *chip, chip->device_signature.unique_device_id_addr; if (!unique_device_id_addr) - return -EINVAL; + return STM32_EINVAL; res = read_device_signature_register(fd, chip, unique_device_id_addr, STM32_UNIQUE_ID_SIZE_BYTES, device_id); - if (!res) { + if (!IS_STM32_ERROR(res)) { printf("Unique Device ID: 0x"); for (i = STM32_UNIQUE_ID_SIZE_BYTES - 1; i >= 0; i--) printf("%02X", device_id[i]); @@ -1136,13 +1237,13 @@ int read_package_data_register(int fd, struct stm32_def *chip, uint32_t package_data_addr = chip->device_signature.package_data_addr; if (!package_data_addr) - return -EINVAL; + return STM32_EINVAL; res = read_device_signature_register(fd, chip, package_data_addr, sizeof(*package_data), (uint8_t *)package_data); - if (!res) + if (!IS_STM32_ERROR(res)) printf("Package data register: %04X\n", *package_data); else fprintf(stderr, @@ -1165,14 +1266,14 @@ int read_flash(int fd, struct stm32_def *chip, const char *filename, buffer = malloc(size); if (!buffer) { fprintf(stderr, "Cannot allocate %d bytes\n", size); - return -ENOMEM; + return STM32_ENOMEM; } hnd = fopen(filename, "w"); if (!hnd) { fprintf(stderr, "Cannot open file %s for writing\n", filename); free(buffer); - return -EIO; + return STM32_EIO; } printf("Reading %d bytes at 0x%08x\n", size, offset); @@ -1185,7 +1286,7 @@ int read_flash(int fd, struct stm32_def *chip, const char *filename, fclose(hnd); free(buffer); - return (res < 0) ? res : 0; + return IS_STM32_ERROR(res) ? res : STM32_SUCCESS; } /* Return zero on success, a negative error value on failures. */ @@ -1199,7 +1300,7 @@ int write_flash(int fd, struct stm32_def *chip, const char *filename, if (!buffer) { fprintf(stderr, "Cannot allocate %d bytes\n", size); - return -ENOMEM; + return STM32_ENOMEM; } if (!strncmp(filename, "-", sizeof("-"))) @@ -1209,16 +1310,15 @@ int write_flash(int fd, struct stm32_def *chip, const char *filename, if (!hnd) { fprintf(stderr, "Cannot open file %s for reading\n", filename); free(buffer); - return -EIO; + return STM32_EIO; } res = fread(buffer, 1, size, hnd); + fclose(hnd); if (res <= 0) { fprintf(stderr, "Cannot read %s\n", filename); free(buffer); - fclose(hnd); - return -EIO; + return STM32_EIO; } - fclose(hnd); /* faster write: skip empty trailing space */ while (res && buffer[res - 1] == 0xff) @@ -1231,12 +1331,12 @@ int write_flash(int fd, struct stm32_def *chip, const char *filename, if (written != res) { fprintf(stderr, "Error writing to flash\n"); free(buffer); - return -EIO; + return STM32_EIO; } - printf("\rDone.\n"); + printf("\r %d bytes written.\n", written); free(buffer); - return 0; + return STM32_SUCCESS; } static const struct option longopts[] = { @@ -1397,11 +1497,25 @@ int parse_parameters(int argc, char **argv) return flags; } +static void display_stat_response(void) +{ + uint32_t total_events = MAX_EVENT_IDX; + uint32_t idx; + + printf("--\n"); + for (idx = 0; idx < total_events; ++idx) { + printf("%-18s %d\n", stat_resp[idx].event_name, + stat_resp[idx].event_count); + } + printf("--\n"); +} + int main(int argc, char **argv) { int ser; struct stm32_def *chip; - int ret = 1; + int ret = STM32_EIO; + int res; int flags; uint16_t flash_size_kbytes = 0; uint8_t unique_device_id[STM32_UNIQUE_ID_SIZE_BYTES] = { 0 }; @@ -1410,6 +1524,8 @@ int main(int argc, char **argv) /* Parse command line options */ flags = parse_parameters(argc, argv); + retry_on_damaged_ack = !!(flags & FLAG_CR50_MODE); + switch (mode) { case MODE_SPI: ser = open_spi(spi_adapter); @@ -1437,7 +1553,8 @@ int main(int argc, char **argv) * have the same chip ID, but different flash sizes based on the * package. */ - if (!read_flash_size_register(ser, chip, &flash_size_kbytes)) + res = read_flash_size_register(ser, chip, &flash_size_kbytes); + if (!IS_STM32_ERROR(res)) chip->flash_size = flash_size_kbytes * KBYTES_TO_BYTES; /* @@ -1468,25 +1585,25 @@ int main(int argc, char **argv) for (i = 0; i < page_count; i += 128) { int count = MIN(128, page_count - i); ret = erase(ser, count, i); - if (ret) + if (IS_STM32_ERROR(ret)) goto terminate; } } else { ret = erase(ser, 0xFFFF, 0); - if (ret) + if (IS_STM32_ERROR(ret)) goto terminate; } } if (input_filename) { ret = read_flash(ser, chip, input_filename, offset, length); - if (ret) + if (IS_STM32_ERROR(ret)) goto terminate; } if (output_filename) { ret = write_flash(ser, chip, output_filename, offset); - if (ret) + if (IS_STM32_ERROR(ret)) goto terminate; } @@ -1495,12 +1612,22 @@ int main(int argc, char **argv) command_go(ser, offset); /* Normal exit */ - ret = 0; + ret = STM32_SUCCESS; terminate: if (log_file) fclose(log_file); /* Close serial port */ close(ser); - return ret; + + if (retry_on_damaged_ack) + display_stat_response(); + + if (IS_STM32_ERROR(ret)) { + fprintf(stderr, "Failed: %d\n", ret); + return 1; + } + + printf("Done.\n"); + return 0; } |