[PATCH linux dev-4.7 v2 6/7] drivers/fsi: Cleanup bus errors

Christopher Bostic cbostic at linux.vnet.ibm.com
Wed Feb 22 08:50:31 AEDT 2017


Define the bus error cleanup method for primary and hub links.

Signed-off-by: Christopher Bostic <cbostic at linux.vnet.ibm.com>

---

v2: Change to atomic operation when checking for nested error
    handling.

    Move slave access details out of gpio master and into the
    core.

    Only allow hub link 1 scans to cut down on scan bus errors.
---
 drivers/fsi/fsi-core.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 428675f..b660d33 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/delay.h>
+#include <linux/bitops.h>
 
 #include "fsi-master.h"
 
@@ -42,6 +43,9 @@
 
 #define FSI_PEEK_BASE			0x410
 #define	FSI_SLAVE_BASE			0x800
+#define	FSI_HUB_CONTROL			0x3400
+
+#define	FSI_SLAVE_SMODE_DFLT		0xa0ff0100
 
 #define FSI_IPOLL_PERIOD		msecs_to_jiffies(fsi_ipoll_period_ms)
 
@@ -54,6 +58,10 @@
 static const int engine_page_size = 0x400;
 static struct task_struct *master_ipoll;
 static unsigned int fsi_ipoll_period_ms = 100;
+static unsigned long fsi_state;
+
+/* state flags */
+#define	FSI_IN_ERR_CLEANUP		0
 
 static DEFINE_IDA(master_ida);
 
@@ -255,6 +263,10 @@ int hub_master_break(struct fsi_master *master, int linkno)
 	uint32_t break_offset = 0x4; /* hw workaround */
 	uint32_t addr;
 
+	/* config table lists 2 entries per hub link */
+	if (linkno >= (master->n_links / 2))
+		return -ENODEV;
+
 	command = FSI_BREAK;
 	addr = (linkno * FSI_MASTER_HUB_LINK_SIZE) + hub->base;
 	return fsi_slave_write(hub->slave, addr + break_offset, &command,
@@ -641,6 +653,28 @@ static int fsi_master_break(struct fsi_master *master, int link)
 
 void fsi_master_handle_error(struct fsi_master *master, uint32_t addr)
 {
+	uint32_t smode = FSI_SLAVE_SMODE_DFLT;
+
+	/* Avoid nested error handling */
+	if (test_and_set_bit(FSI_IN_ERR_CLEANUP, &fsi_state))
+		return;
+
+	fsi_master_break(master, 0);
+	udelay(200);
+	master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SMODE, &smode,
+			sizeof(smode));
+	smode = FSI_MRESB_RST_GEN | FSI_MRESB_RST_ERR;
+	master->write(master, 0, 0, FSI_HUB_CONTROL + FSI_MRESB0, &smode,
+			sizeof(smode));
+
+	if (addr > FSI_HUB_LINK_OFFSET) {
+		smode = FSI_BREAK;
+		master->write(master, 0, 0, 0x100004, &smode, sizeof(smode));
+		smode = FSI_SLAVE_SMODE_DFLT;
+		master->write(master, 0, 0, 0x100800, &smode, sizeof(smode));
+	}
+
+	clear_bit(FSI_IN_ERR_CLEANUP, &fsi_state);
 }
 
 static int fsi_master_scan(struct fsi_master *master)
-- 
1.8.2.2



More information about the openbmc mailing list