diff options
author | Anatol Pomazau <anatol@google.com> | 2018-03-28 13:09:47 -0700 |
---|---|---|
committer | Anatol Pomazau <anatol@google.com> | 2018-04-04 10:10:27 -0700 |
commit | 0ee610c481f78a08209bd6f6d3b39d42cf5c1ac3 (patch) | |
tree | e05225b5bc8b2ec7a9c01b9ec5faea28f2a6d6cd /libnos_transport | |
parent | 2fdba9b8f5840c59cd48f98d378dd85d82102840 (diff) | |
download | generic-0ee610c481f78a08209bd6f6d3b39d42cf5c1ac3.tar.gz |
Add retry functionality to all read/write device operations
Test: harness tests passed 80 times
Bug: 73959155
Change-Id: I9a664e9584eb7ee04f0f94bbcee7763b0e3a19bb
Diffstat (limited to 'libnos_transport')
-rw-r--r-- | libnos_transport/transport.c | 78 |
1 files changed, 55 insertions, 23 deletions
diff --git a/libnos_transport/transport.c b/libnos_transport/transport.c index 140d257..6f09be0 100644 --- a/libnos_transport/transport.c +++ b/libnos_transport/transport.c @@ -56,47 +56,79 @@ extern int usleep (uint32_t usec); #endif -/* status is non-zero on error */ -static int get_status(const struct nos_device *dev, - uint8_t app_id, uint32_t *status, uint16_t *ulen) -{ - uint8_t buf[6]; - uint32_t command = CMD_ID(app_id) | CMD_IS_READ | CMD_TRANSPORT; +/* Citadel might take up to 100ms to wake up */ +#define RETRY_COUNT 25 +#define RETRY_WAIT_TIME_US 5000 - uint16_t retries = 10; +static int nos_device_read(const struct nos_device *dev, uint32_t command, + uint8_t *buf, uint32_t len) { + int retries = RETRY_COUNT; while (retries--) { - int err = dev->ops.read(dev->ctx, command, buf, sizeof(buf)); + int err = dev->ops.read(dev->ctx, command, buf, len); - if (err == 0) { - /* The read operation is successful */ - *status = *(uint32_t *)buf; - *ulen = *(uint16_t *)(buf + 4); + if (err == -EAGAIN) { + /* Linux driver returns EAGAIN error if Citadel chip is asleep. + * Give to the chip a little bit of time to awake and retry reading + * status again. */ + usleep(RETRY_WAIT_TIME_US); + continue; + } - return 0; + if (err) { + NLOGE("Failed to read: %s", strerror(-err)); } + return -err; + } + + return ETIMEDOUT; +} + +static int nos_device_write(const struct nos_device *dev, uint32_t command, + uint8_t *buf, uint32_t len) { + int retries = RETRY_COUNT; + while (retries--) { + int err = dev->ops.write(dev->ctx, command, buf, len); if (err == -EAGAIN) { /* Linux driver returns EAGAIN error if Citadel chip is asleep. * Give to the chip a little bit of time to awake and retry reading * status again. */ - usleep(5000); + usleep(RETRY_WAIT_TIME_US); continue; } - /* Citadel driver returned an error */ - NLOGE("Failed to read device status: %d", err); + if (err) { + NLOGE("Failed to write: %s", strerror(-err)); + } + return -err; + } + + return ETIMEDOUT; +} + +/* status is non-zero on error */ +static int get_status(const struct nos_device *dev, + uint8_t app_id, uint32_t *status, uint16_t *ulen) +{ + uint8_t buf[6]; + uint32_t command = CMD_ID(app_id) | CMD_IS_READ | CMD_TRANSPORT; + + if (0 != nos_device_read(dev, command, buf, sizeof(buf))) { + NLOGE("Failed to read device status"); return -1; } - NLOGE("Failed to read device status"); - return -1; + /* The read operation is successful */ + *status = *(uint32_t *)buf; + *ulen = *(uint16_t *)(buf + 4); + return 0; } static int clear_status(const struct nos_device *dev, uint8_t app_id) { uint32_t command = CMD_ID(app_id) | CMD_TRANSPORT; - if (0 != dev->ops.write(dev->ctx, command, 0, 0)) { + if (0 != nos_device_write(dev, command, 0, 0)) { NLOGE("Failed to clear device status"); return -1; } @@ -161,7 +193,7 @@ uint32_t nos_call_application(const struct nos_device *dev, NLOGV("Write command 0x%08x, bytes 0x%x", command, ulen); - if (0 != dev->ops.write(dev->ctx, command, buf, ulen)) { + if (0 != nos_device_write(dev, command, buf, ulen)) { NLOGE("Failed to send datagram to device"); return APP_ERROR_IO; } @@ -187,7 +219,7 @@ uint32_t nos_call_application(const struct nos_device *dev, /* Now tell the app to do whatever */ command = CMD_ID(app_id) | CMD_PARAM(params); NLOGV("Write command 0x%08x", command); - if (0 != dev->ops.write(dev->ctx, command, 0, 0)) { + if (0 != nos_device_write(dev, command, 0, 0)) { NLOGE("Failed to send command datagram to device"); return APP_ERROR_IO; } @@ -222,7 +254,7 @@ reply: */ gimme = MIN(left, MAX_DEVICE_TRANSFER); NLOGV("Read command 0x%08x, bytes 0x%x", command, gimme); - if (0 != dev->ops.read(dev->ctx, command, buf, gimme)) { + if (0 != nos_device_read(dev, command, buf, gimme)) { NLOGE("Failed to receive datagram from device"); return APP_ERROR_IO; } @@ -238,7 +270,7 @@ reply: /* Clear the reply manually for the next caller */ command = CMD_ID(app_id) | CMD_TRANSPORT; - if (0 != dev->ops.write(dev->ctx, command, 0, 0)) { + if (0 != nos_device_write(dev, command, 0, 0)) { NLOGE("Failed to clear the reply"); return APP_ERROR_IO; } |