summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2016-04-30 15:48:48 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-05-02 17:35:46 -0700
commit3b1c3ba36febf50fa3be0e9b68e40be8e413e04d (patch)
tree5d31471600194d539b3e1b4df785e7cf055d79c2
parentacaec8810146196b432e3fcc3f6b8ba0161ff747 (diff)
downloadchrome-ec-3b1c3ba36febf50fa3be0e9b68e40be8e413e04d.tar.gz
usb_updater: retransmit upgrade blocks if target does not reply
When the target is running upgrade protocol version 2, it is capable of processing multiple transfer attempts of the same block. This patch allows timeouts when expecting the target acknowledges. If the acknowledge does not arrive in time, the host reports the timeout on the console and retransmits the same block to the target. BRANCH=none BUG=chrome-os-partner:52856 TEST=it is now possible to successfully upgrade cr50 on Kevin in one go: $ ./extra/usb_updater/usb_updater build/cr50/ec.bin read 0x80000 bytes from build/cr50/ec.bin open_device 18d1:5014 found interface 4 endpoint 5, chunk_len 64 READY ------- erase Target running protocol version 2 Updating at offset 0x00004000 sending 0x29620/0x3c000 bytes Timeout! Timeout! Timeout! Timeout! ------- update complete reboot bye Change-Id: Ib1c3179cb3a02c0ae6e5e949476553ae28b6a295 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/341583 Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-rw-r--r--extra/usb_updater/usb_updater.c75
1 files changed, 50 insertions, 25 deletions
diff --git a/extra/usb_updater/usb_updater.c b/extra/usb_updater/usb_updater.c
index 808c042e87..1b071b46e6 100644
--- a/extra/usb_updater/usb_updater.c
+++ b/extra/usb_updater/usb_updater.c
@@ -39,6 +39,7 @@ struct usb_endpoint {
};
/* Globals */
+static uint32_t protocol_version;
static char *progname;
static char *short_opts = ":d:h";
static const struct option long_opts[] = {
@@ -323,6 +324,48 @@ struct startup_resp {
uint32_t version;
};
+static int transfer_block(struct usb_endpoint *uep, struct update_pdu *updu,
+ uint8_t *transfer_data_ptr, size_t payload_size)
+{
+ size_t transfer_size;
+ uint32_t reply;
+ int actual;
+ int r;
+
+ /* First send the header. */
+ xfer(uep, updu, sizeof(*updu), NULL, 0);
+
+ /* Now send the block, chunk by chunk. */
+ for (transfer_size = 0; transfer_size < payload_size;) {
+ int chunk_size;
+
+ chunk_size = MIN(uep->chunk_len, payload_size - transfer_size);
+ xfer(uep, transfer_data_ptr, chunk_size, NULL, 0);
+ transfer_data_ptr += chunk_size;
+ transfer_size += chunk_size;
+ }
+
+ /* Now get the reply. */
+ r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80,
+ (void *) &reply, sizeof(reply),
+ &actual, 1000);
+ if (r) {
+ if ((r == -7) && (protocol_version >= 2)) {
+ fprintf(stderr, "Timeout!\n");
+ return r;
+ }
+ USB_ERROR("libusb_bulk_transfer", r);
+ shut_down(uep);
+ }
+
+ if (reply) {
+ fprintf(stderr, "error: status %#08x\n", be32toh(reply));
+ exit(1);
+ }
+
+ return 0;
+}
+
static void transfer_and_reboot(struct usb_endpoint *uep,
uint8_t *data, uint32_t data_len)
{
@@ -333,7 +376,6 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
struct update_pdu updu;
struct startup_resp first_resp;
int rxed_size;
- uint32_t protocol_version;
/* Send start/erase request */
printf("erase\n");
@@ -369,14 +411,11 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
data_len--;
printf("sending 0x%x/0x%x bytes\n", data_len, CONFIG_RW_SIZE);
-
while (data_len) {
size_t payload_size;
SHA_CTX ctx;
uint8_t digest[SHA_DIGEST_LENGTH];
-
- uint8_t *transfer_data_ptr;
- size_t transfer_size;
+ int max_retries;
/* prepare the header to prepend to the block. */
payload_size = MIN(data_len, SIGNED_TRANSFER_SIZE);
@@ -396,29 +435,15 @@ static void transfer_and_reboot(struct usb_endpoint *uep,
memcpy(&updu.cmd.block_digest, digest,
sizeof(updu.cmd.block_digest));
- /* Now send the header. */
- xfer(uep, &updu, sizeof(updu), NULL, 0);
- /* Now send the block, chunk by chunk. */
- transfer_data_ptr = data_ptr;
- for (transfer_size = 0; transfer_size < payload_size;) {
- int chunk_size;
-
- chunk_size = MIN(uep->chunk_len,
- payload_size - transfer_size);
- xfer(uep, transfer_data_ptr, chunk_size,
- NULL, 0);
- transfer_data_ptr += chunk_size;
- transfer_size += chunk_size;
- }
+ for (max_retries = 10; max_retries; max_retries--)
+ if (!transfer_block(uep, &updu, data_ptr, payload_size))
+ break;
- /* Now get the reply. */
- xfer(uep, NULL, 0, &reply, sizeof(reply));
- if (reply) {
- fprintf(stderr, "error: status %#08x remaining %#08x\n",
- be32toh(reply), data_len);
+ if (!max_retries) {
+ fprintf(stderr, "Failed to trasfer block, %d to go\n",
+ data_len);
exit(1);
}
-
data_len -= payload_size;
data_ptr += payload_size;
next_offset += payload_size;