linux-gbmc: support retry for ENXIO error
In rare cases, i2c-ast2600.c will return ENXIO error during sending of
MCTP packets in i2c multi-master mode. Here we supported limited retry
for ENXIO error.
Tested:
Still pass with nvmesensor single-worker-mode:
https://paste.googleplex.com/5948322238169088
Fusion-Link:
https://fusion2.corp.google.com/69214948-c3c6-3e47-8fab-32e83ffb9835
Google-Bug-Id: 286397121
Change-Id: Ib2ebbfaa6dba25c4571ca2afa714d01cf7e5e726
Signed-off-by: Jinliang Wang <jinliangw@google.com>
diff --git a/recipes-kernel/linux/files/0001-mctp-i2c-add-MCTP-retry-mechanism.patch b/recipes-kernel/linux/files/0001-mctp-i2c-add-MCTP-retry-mechanism.patch
index 2a6db1d..ae4d838 100644
--- a/recipes-kernel/linux/files/0001-mctp-i2c-add-MCTP-retry-mechanism.patch
+++ b/recipes-kernel/linux/files/0001-mctp-i2c-add-MCTP-retry-mechanism.patch
@@ -1,4 +1,4 @@
-From 5be710bf888d8ed9f10d12cd5db5faf8b3fd65e4 Mon Sep 17 00:00:00 2001
+From 9e2ff138c053f809c1d994d4d013ef8c35bddc89 Mon Sep 17 00:00:00 2001
From: Jinliang Wang <jinliangw@google.com>
Date: Mon, 22 Apr 2024 15:50:24 -0700
Subject: [PATCH] mctp-i2c: add MCTP retry mechanism
@@ -17,41 +17,49 @@
Google-Bug-Id: 286397121
Signed-off-by: Jinliang Wang <jinliangw@google.com>
---
- drivers/net/mctp/mctp-i2c.c | 32 ++++++++++++++++++++++++++++++--
+ drivers/net/mctp/mctp-i2c.c | 40 +++++++++++++++++++++++++++++++++++--
include/uapi/linux/i2c.h | 2 ++
- 2 files changed, 32 insertions(+), 2 deletions(-)
+ 2 files changed, 40 insertions(+), 2 deletions(-)
diff --git a/drivers/net/mctp/mctp-i2c.c b/drivers/net/mctp/mctp-i2c.c
-index baf7afac7857..1d8296b0c0c2 100644
+index baf7afac7857..820e6f61b7f9 100644
--- a/drivers/net/mctp/mctp-i2c.c
+++ b/drivers/net/mctp/mctp-i2c.c
-@@ -435,6 +435,34 @@ static void mctp_i2c_unlock_reset(struct mctp_i2c_dev *midev)
+@@ -435,6 +435,42 @@ static void mctp_i2c_unlock_reset(struct mctp_i2c_dev *midev)
i2c_unlock_bus(midev->adapter, I2C_LOCK_SEGMENT);
}
+#define RETRY_TIME_MS 2000
+#define RETRY_INVERVAL_MS 20
+#define RETRY_CNT (RETRY_TIME_MS / RETRY_INVERVAL_MS)
++#define ENXIO_RETRY_LIMIT 5
+
+static int mctp_i2c_transfer_with_retry(struct i2c_adapter *adap,
+ struct i2c_msg *msg)
+{
+ int rc = 0;
-+ int retry = 0;
++ int retry = 0; /* General retry count */
++ int enxio_retry = 0; /* Special retry count for ENXIO error */
+ msg->flags = I2C_M_IS_MCTP;
+ while (retry < RETRY_CNT) {
+ retry++;
+ rc = __i2c_transfer(adap, msg, 1);
-+ if (rc == -EBUSY || rc == -EAGAIN || rc == -EPROTO) {
++ if (rc == -ENXIO) {
++ enxio_retry++;
++ if (enxio_retry >= ENXIO_RETRY_LIMIT) {
++ /* Jump out if we accumulate enough ENXIO error */
++ break;
++ }
++ } else if (rc == -EBUSY || rc == -EAGAIN || rc == -EPROTO) {
+ if (retry >= (RETRY_CNT - 1)) {
-+ /* set last retry flag */
++ /* Set last retry flag so i2c driver layer may perform necessary recovery */
+ msg->flags |= I2C_M_LAST_RETRY;
+ }
-+ msleep_interruptible(RETRY_INVERVAL_MS);
-+ /* continue to retry */
+ } else {
+ break;
+ }
++ msleep_interruptible(RETRY_INVERVAL_MS);
++ /* Continue to retry */
+ }
+
+ return rc;
@@ -60,7 +68,7 @@
static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
{
struct net_device_stats *stats = &midev->ndev->stats;
-@@ -478,7 +506,7 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
+@@ -478,7 +514,7 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
/* no flow: full lock & unlock */
mctp_i2c_lock_nest(midev);
mctp_i2c_device_select(midev->client, midev);
@@ -69,7 +77,7 @@
mctp_i2c_unlock_nest(midev);
break;
-@@ -492,7 +520,7 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
+@@ -492,7 +528,7 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)
case MCTP_I2C_TX_FLOW_EXISTING:
/* existing flow: we already have the lock; just tx */