Merge remote-tracking branch 'goog/upstream-master' into merge
* goog/upstream-master:
Add retry functionality to all read/write device operations
Bug: 77998542
Change-Id: Id355d32acbc698173f72af4744e70b21117b4172
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,6 +56,56 @@
#endif
+/* Citadel might take up to 100ms to wake up */
+#define RETRY_COUNT 25
+#define RETRY_WAIT_TIME_US 5000
+
+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, 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(RETRY_WAIT_TIME_US);
+ continue;
+ }
+
+ 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(RETRY_WAIT_TIME_US);
+ continue;
+ }
+
+ 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)
@@ -63,40 +113,22 @@
uint8_t buf[6];
uint32_t command = CMD_ID(app_id) | CMD_IS_READ | CMD_TRANSPORT;
- uint16_t retries = 10;
- while (retries--) {
- int err = dev->ops.read(dev->ctx, command, buf, sizeof(buf));
-
- if (err == 0) {
- /* The read operation is successful */
- *status = *(uint32_t *)buf;
- *ulen = *(uint16_t *)(buf + 4);
-
- return 0;
- }
-
- 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);
- continue;
- }
-
- /* Citadel driver returned an error */
- NLOGE("Failed to read device status: %d", err);
+ 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 @@
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 @@
/* 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 @@
*/
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 @@
/* 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;
}