diff mbox

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

Message ID 20170221215032.79282-7-cbostic@linux.vnet.ibm.com
State Changes Requested, archived
Headers show

Commit Message

Christopher Bostic Feb. 21, 2017, 9:50 p.m. UTC
Define the bus error cleanup method for primary and hub links.

Signed-off-by: Christopher Bostic <cbostic@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(+)

Comments

Jeremy Kerr Feb. 22, 2017, 9:55 p.m. UTC | #1
Hi Chris,

> @@ -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;
> +

master->n_links should represent the actual number of links, rather than
reflect what's in the config table.

[besides, don't we do the / 2 during the config table parse anyway?]

>  	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;

Do we have any other bits of state to represent? If not, just use a
plain atomic_t rather than a set of flags.

Cheers,


Jeremy
Christopher Bostic Feb. 22, 2017, 10:51 p.m. UTC | #2
On 2/22/17 3:55 PM, Jeremy Kerr wrote:
> Hi Chris,
>
>> @@ -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;
>> +
> master->n_links should represent the actual number of links, rather than
> reflect what's in the config table.
>
> [besides, don't we do the / 2 during the config table parse anyway?]

Hi Jeremy,

Yes that's true, its set in scan so no need for the /2 here - will fix.


>>   	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;
> Do we have any other bits of state to represent? If not, just use a
> plain atomic_t rather than a set of flags.
No others at this point,  will change to an atomic_t

Thanks,
Chris

> Cheers,
>
>
> Jeremy
>
diff mbox

Patch

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)