diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2016-04-29 16:11:28 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-05-02 17:35:44 -0700 |
commit | 42662f2214aa43982d44edd4dc12721d6f77e018 (patch) | |
tree | e1370865d7f8b0b3a6fd2f9af52147b448314544 | |
parent | c8e38a9314d10fa5984e80869d26aef334769645 (diff) | |
download | chrome-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.c | 28 |
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) |