[PATCH linux dev-4.10 3/3] drivers: fsi: sbefifo: Attempt reset request during probe

Eddie James eajames at linux.vnet.ibm.com
Wed Oct 18 08:35:53 AEDT 2017


From: "Edward A. James" <eajames at us.ibm.com>

If data is found in the FIFO, the driver currently immediately fails
the probe. Instead, try a reset request and poll for it's completion for
a while (this protocol is defined in the SBE FIFO spec, though the
timeout lengths are my own invention).

Signed-off-by: Edward A. James <eajames at us.ibm.com>
---
 drivers/fsi/fsi-sbefifo.c | 53 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 42 insertions(+), 11 deletions(-)

diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
index 764d8f3..f756822 100644
--- a/drivers/fsi/fsi-sbefifo.c
+++ b/drivers/fsi/fsi-sbefifo.c
@@ -47,8 +47,10 @@
 
 #define SBEFIFO_STS		0x04
 #define   SBEFIFO_EMPTY			BIT(20)
+#define   SBEFIFO_STS_RESET_REQ		BIT(25)
 #define SBEFIFO_EOT_RAISE	0x08
 #define   SBEFIFO_EOT_MAGIC		0xffffffff
+#define SBEFIFO_REQ_RESET	0x0C
 #define SBEFIFO_EOT_ACK		0x14
 
 #define SBEFIFO_RESCHEDULE	msecs_to_jiffies(500)
@@ -831,6 +833,36 @@ static int sbefifo_unregister_child(struct device *dev, void *data)
 	return 0;
 }
 
+static int sbefifo_request_reset(struct sbefifo *sbefifo)
+{
+	int ret;
+	u32 status;
+	unsigned long start;
+	const unsigned int wait_time = 5;	/* jiffies */
+	const unsigned long timeout = msecs_to_jiffies(250);
+
+	ret = sbefifo_outw(sbefifo, SBEFIFO_UP | SBEFIFO_REQ_RESET, 1);
+	if (ret)
+		return ret;
+
+	start = jiffies;
+
+	do {
+		ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &status);
+		if (ret)
+			return ret;
+
+		if (!(status & SBEFIFO_STS_RESET_REQ))
+			return 0;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout(wait_time) > 0)
+			return -EINTR;
+	} while (time_after(start + timeout, jiffies));
+
+	return -ETIME;
+}
+
 static int sbefifo_probe(struct device *dev)
 {
 	struct fsi_device *fsi_dev = to_fsi_dev(dev);
@@ -838,7 +870,7 @@ static int sbefifo_probe(struct device *dev)
 	struct device_node *np;
 	struct platform_device *child;
 	char child_name[32];
-	u32 sts;
+	u32 up, down;
 	int ret, child_idx = 0;
 
 	dev_dbg(dev, "Found sbefifo device\n");
@@ -848,22 +880,21 @@ static int sbefifo_probe(struct device *dev)
 
 	sbefifo->fsi_dev = fsi_dev;
 
-	ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &sts);
+	ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &up);
 	if (ret)
 		return ret;
 
-	if (!(sts & SBEFIFO_EMPTY)) {
-		dev_err(dev, "Found data in upstream fifo\n");
-		return -EIO;
-	}
-
-	ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts);
+	ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &down);
 	if (ret)
 		return ret;
 
-	if (!(sts & SBEFIFO_EMPTY)) {
-		dev_err(dev, "Found data in downstream fifo\n");
-		return -EIO;
+	if (!(up & SBEFIFO_EMPTY) || !(down & SBEFIFO_EMPTY)) {
+		ret = sbefifo_request_reset(sbefifo);
+		if (ret) {
+			dev_err(dev,
+				"fifos weren't empty and failed the reset\n");
+			return ret;
+		}
 	}
 
 	spin_lock_init(&sbefifo->lock);
-- 
1.8.3.1



More information about the openbmc mailing list