summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2016-04-29 16:11:28 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-05-02 17:35:44 -0700
commit42662f2214aa43982d44edd4dc12721d6f77e018 (patch)
treee1370865d7f8b0b3a6fd2f9af52147b448314544
parentc8e38a9314d10fa5984e80869d26aef334769645 (diff)
downloadchrome-ec-42662f2214aa43982d44edd4dc12721d6f77e018.tar.gz
g: recover from usb_upgrade interruptions
The usb upgrade protocol is very fragile, any error while transferring data causes the state machine on the target to lock up, and the only way to resume the upgrade is to power cycle the device. With this patch USB callbacks which happen more than 5 seconds since the previous callback would be considered a start of new transfer, thus allowing to attempt a new upgrade without the power cycle. BRANCH=none BUG=chrome-os-partner:52856 TEST=the following script allows to upgrade successfully: $ while not ./extra/usb_updater/usb_updater build/cr50/ec.bin; do sleep 6; done Change-Id: Ibe1078cf62073ce89a31416522b0d6917bc923b9 Signed-off-by: Vadim Bendebury <vbendeb@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/341572 Reviewed-by: Marius Schilder <mschilder@chromium.org> Reviewed-by: Mary Ruthven <mruthven@chromium.org>
-rw-r--r--chip/g/usb_upgrade.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/chip/g/usb_upgrade.c b/chip/g/usb_upgrade.c
index 7e86a0c035..bca76d401e 100644
--- a/chip/g/usb_upgrade.c
+++ b/chip/g/usb_upgrade.c
@@ -91,12 +91,37 @@ static uint8_t *block_buffer;
static uint32_t block_size;
static uint32_t block_index;
+/*
+ * When was last time a USB callback was called, in microseconds, free running
+ * timer.
+ */
+static uint64_t prev_activity_timestamp;
+
/* Called to deal with data from the host */
static void upgrade_out_handler(struct consumer const *consumer, size_t count)
{
struct update_pdu_header updu;
size_t resp_size;
uint32_t resp_value;
+ uint64_t delta_time;
+
+ /* How much time since the previous USB callback? */
+ delta_time = get_time().val - prev_activity_timestamp;
+ prev_activity_timestamp += delta_time;
+
+ /* If timeout exceeds 5 seconds - let's start over. */
+ if ((delta_time > 5000000) && (rx_state_ != rx_idle)) {
+ if (block_buffer) {
+ /*
+ * Previous transfer could have been aborted mid
+ * block.
+ */
+ shared_mem_release(block_buffer);
+ block_buffer = NULL;
+ }
+ rx_state_ = rx_idle;
+ CPRINTS("FW update: recovering after timeout\n");
+ }
if (rx_state_ == rx_idle) {
/* This better be the first block, of zero size. */
@@ -210,10 +235,11 @@ static void upgrade_out_handler(struct consumer const *consumer, size_t count)
*/
fw_upgrade_command_handler(block_buffer, block_index, &resp_size);
- shared_mem_release(block_buffer);
resp_value = block_buffer[0];
QUEUE_ADD_UNITS(&upgrade_to_usb, &resp_value, sizeof(resp_value));
rx_state_ = rx_outside_block;
+ shared_mem_release(block_buffer);
+ block_buffer = NULL;
}
static void upgrade_flush(struct consumer const *consumer)