All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH linux dev-4.7 0/4] Add FSI interrupt support for hub
@ 2017-04-07 13:52 Christopher Bostic
  2017-04-07 13:52 ` [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal Christopher Bostic
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Christopher Bostic @ 2017-04-07 13:52 UTC (permalink / raw)
  To: joel; +Cc: Christopher Bostic, openbmc

Allow interrupt processing of client devices behind hub master.
Manage enable/disable of IRQ enables along the IRQ path including
primary slave Si1s, SRSIS; hub master MSIEP, MMODE i-poll; hub slave
Si1s.

Christopher Bostic (4):
  drivers/fsi: Change interrupt handler device traversal.
  drivers/fsi: Look for Hub sourced IRQs
  drivers/fsi: Scan for hub link IRQ sources
  drivers/fsi: Set IRQ masks along hub path


-- 
1.8.2.2

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal.
  2017-04-07 13:52 [PATCH linux dev-4.7 0/4] Add FSI interrupt support for hub Christopher Bostic
@ 2017-04-07 13:52 ` Christopher Bostic
  2017-04-10 20:03   ` Eddie James
  2017-04-07 13:52 ` [PATCH linux dev-4.7 2/4] drivers/fsi: Look for Hub sourced IRQs Christopher Bostic
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Christopher Bostic @ 2017-04-07 13:52 UTC (permalink / raw)
  To: joel; +Cc: Christopher Bostic, openbmc

Traverse the slave device list and master slave list using the
kernel utility device_for_each_child instead of using internally
managed linked lists.

Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
---
 drivers/fsi/fsi-core.c | 34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 3d382e6..36dde94 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -778,22 +778,32 @@ static void fsi_master_unscan(struct fsi_master *master)
 	master->slave_list = false;
 }
 
-static void fsi_master_irq(struct fsi_master *master, int link, uint32_t si1s)
+static int __fsi_dev_irq(struct device *dev, void *data)
 {
-	struct fsi_slave *slave;
-	struct fsi_device *fsi_dev;
-
-	if (list_empty(&master->my_slaves))
-		return;
+	uint32_t *si1s = data;
+	struct fsi_device *fsi_dev = to_fsi_dev(dev);
 
-	slave = list_first_entry(&master->my_slaves, struct fsi_slave,
-				list_link);
+	if (!fsi_dev || !si1s) {
+		dev_dbg(dev, "Invalid input: %p %p\n", fsi_dev, si1s);
+		return -EINVAL;
+	}
 
-	list_for_each_entry(fsi_dev, &slave->my_engines, link) {
-		if (si1s & (0x80000000 >> fsi_dev->si1s_bit) &&
-		    fsi_dev->irq_handler)
-			fsi_dev->irq_handler(0, &fsi_dev->dev);
+	if (*si1s & (0x80000000 >> fsi_dev->si1s_bit) && fsi_dev->irq_handler) {
+		fsi_dev->irq_handler(0, &fsi_dev->dev);
+		return 1;
 	}
+
+	return 0;
+}
+
+static int __fsi_slave_irq(struct device *dev, void *data)
+{
+	return device_for_each_child(dev, data, __fsi_dev_irq);
+}
+
+static void fsi_master_irq(struct fsi_master *master, int link, uint32_t si1s)
+{
+	device_for_each_child(master->dev, &si1s, __fsi_slave_irq);
 }
 
 static int fsi_master_ipoll(void *data)
-- 
1.8.2.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH linux dev-4.7 2/4] drivers/fsi: Look for Hub sourced IRQs
  2017-04-07 13:52 [PATCH linux dev-4.7 0/4] Add FSI interrupt support for hub Christopher Bostic
  2017-04-07 13:52 ` [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal Christopher Bostic
@ 2017-04-07 13:52 ` Christopher Bostic
  2017-04-10 20:05   ` Eddie James
  2017-04-07 13:52 ` [PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources Christopher Bostic
  2017-04-07 13:52 ` [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path Christopher Bostic
  3 siblings, 1 reply; 10+ messages in thread
From: Christopher Bostic @ 2017-04-07 13:52 UTC (permalink / raw)
  To: joel; +Cc: Christopher Bostic, openbmc

In addition to looking for local device IRQs on the slave also
check if the IRQ came from a hub source in the interrupt handler.

Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
---
 drivers/fsi/fsi-core.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 36dde94..45e1171 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -98,6 +98,11 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
 #define FSI_SI1S		0x1C	/* R: IRQ status */
 
 /*
+ * SI1S, SI1M fields
+ */
+#define FSI_SI1_HUB_SRC		0x00100000	/* hub IRQ source */
+
+/*
  * SMODE fields
  */
 #define	FSI_SMODE_WSC		0x80000000	/* Warm start done */
@@ -793,6 +798,13 @@ static int __fsi_dev_irq(struct device *dev, void *data)
 		return 1;
 	}
 
+	if (!(*si1s & FSI_SI1_HUB_SRC)) {
+		dev_dbg(dev, "IRQ not from a hub source\n");
+		return 0;
+	}
+
+	/* TODO: handle hub sourced IRQ */
+
 	return 0;
 }
 
-- 
1.8.2.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources
  2017-04-07 13:52 [PATCH linux dev-4.7 0/4] Add FSI interrupt support for hub Christopher Bostic
  2017-04-07 13:52 ` [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal Christopher Bostic
  2017-04-07 13:52 ` [PATCH linux dev-4.7 2/4] drivers/fsi: Look for Hub sourced IRQs Christopher Bostic
@ 2017-04-07 13:52 ` Christopher Bostic
  2017-04-10 20:08   ` Eddie James
  2017-04-07 13:52 ` [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path Christopher Bostic
  3 siblings, 1 reply; 10+ messages in thread
From: Christopher Bostic @ 2017-04-07 13:52 UTC (permalink / raw)
  To: joel; +Cc: Christopher Bostic, openbmc

Look for the hub link that may have sourced the IRQ being handled.
Clear out hub link interrupting conditions that are latched in
hardware after FSI client handler has been dispatched.

Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
---
 drivers/fsi/fsi-core.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 124 insertions(+), 5 deletions(-)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 45e1171..72f3a35 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -96,6 +96,10 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
 #define	FSI_SMODE		0x0	/* R/W: Mode register */
 #define FSI_SI1M		0x18	/* R/W: IRQ mask */
 #define FSI_SI1S		0x1C	/* R: IRQ status */
+#define FSI_SRSIC0		0x68	/* R/W: Remote IRQ condition 0 */
+#define FSI_SRSIC1		0x6C	/* R/W: Remote IRQ condition 1 */
+#define FSI_SRSIM0		0x70	/* R/W: Remote IRQ mask 0 */
+#define FSI_SRSIS0		0x78	/* R: Remote IRQ status 0 */
 
 /*
  * SI1S, SI1M fields
@@ -116,6 +120,13 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
 #define	FSI_SMODE_LBCRR_SHIFT	8		/* Clk ratio shift */
 #define	FSI_SMODE_LBCRR_MASK	0xf		/* Clk ratio mask */
 
+/*
+ * SRSIS, SRSIM, SRSIC fields
+ */
+#define	FSI_SRSIX_IRQ1_MASK	0x00aaaaaa	/* SI1 IRQ sources */
+#define	FSI_SRSIX_BITS_PER_LINK	8
+
+
 /* FSI endpoint-device support */
 int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
 		size_t size)
@@ -584,6 +595,21 @@ static struct bin_attribute fsi_slave_raw_attr = {
 	.write = fsi_slave_sysfs_raw_write,
 };
 
+static int fsi_slave_irq_clear(struct fsi_slave *slave)
+{
+	uint32_t clear = ~0;
+	int rc;
+
+	rc = fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC0, &clear,
+				sizeof(clear));
+	if (rc) {
+		dev_dbg(&slave->dev, "Failed on write to SRSIC0\n");
+		return rc;
+	}
+	return fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC1, &clear,
+				sizeof(clear));
+}
+
 static int fsi_slave_init(struct fsi_master *master,
 		int link, uint8_t slave_id)
 {
@@ -649,8 +675,11 @@ static int fsi_slave_init(struct fsi_master *master,
 		dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
 
 	list_add(&slave->list_link, &master->my_slaves);
-	fsi_slave_scan(slave);
-	return 0;
+	rc = fsi_slave_scan(slave);
+	if (rc)
+		return rc;
+
+	return fsi_slave_irq_clear(slave);
 }
 
 /* FSI master support */
@@ -783,10 +812,62 @@ static void fsi_master_unscan(struct fsi_master *master)
 	master->slave_list = false;
 }
 
+/* TODO: Add support for hub links 4-7 */
+static int next_hublink_source(struct fsi_slave *slave, uint32_t srsis)
+{
+	int index;
+
+	if (!slave)
+		return -EINVAL;
+
+	if (!(srsis & FSI_SRSIX_IRQ1_MASK)) {
+		dev_dbg(&slave->dev, "Unexpected IRQ source SRSIS:0x%08x\n",
+			srsis);
+		return -EINVAL;
+	}
+
+	/*
+	 * TODO: add a fair scheduler to ensure we don't favor lower
+	 * hublink IRQ sources over others
+	 */
+	index = __clz(srsis);
+	dev_dbg(&slave->dev, "SRSIS:0x%08x index:%d\n", srsis, index);
+	return index / FSI_SRSIX_BITS_PER_LINK;
+}
+
+static int __fsi_dev_irq(struct device *dev, void *data);
+
+static int __fsi_hub_slave_irq(struct device *dev, void *data)
+{
+	int rc;
+	struct fsi_slave *hub_slave = to_fsi_slave(dev);
+	uint32_t si1s;
+
+	if (!hub_slave) {
+		dev_dbg(dev, "Could not find hub slave\n");
+		return -ENODEV;
+	}
+
+	rc = fsi_slave_read(hub_slave, FSI_SLAVE_BASE + FSI_SI1S, &si1s,
+			sizeof(si1s));
+	if (rc) {
+		dev_dbg(dev, "Fail on read of hub slave si1s\n");
+		return rc;
+	}
+
+	if (!si1s)
+		return 0;
+
+	return device_for_each_child(dev, &si1s, __fsi_dev_irq);
+}
+
 static int __fsi_dev_irq(struct device *dev, void *data)
 {
-	uint32_t *si1s = data;
+	uint32_t *si1s = data, srsis;
 	struct fsi_device *fsi_dev = to_fsi_dev(dev);
+	struct fsi_slave *slave;
+	struct fsi_master_hub *hub;
+	int rc, hublink;
 
 	if (!fsi_dev || !si1s) {
 		dev_dbg(dev, "Invalid input: %p %p\n", fsi_dev, si1s);
@@ -803,9 +884,47 @@ static int __fsi_dev_irq(struct device *dev, void *data)
 		return 0;
 	}
 
-	/* TODO: handle hub sourced IRQ */
+	hub = dev_get_drvdata(dev);
+	if (!hub) {
+		dev_dbg(dev, "Not a hub device\n");
+		return 0;
+	}
 
-	return 0;
+	/* Scan the hub links for the source of IRQ */
+	slave = to_fsi_slave(dev->parent);
+	if (!slave) {
+		dev_dbg(dev, "Could not retrieve device's slave\n");
+		return -ENODEV;
+	}
+
+	rc = fsi_slave_read(slave, FSI_SLAVE_BASE + FSI_SRSIS0, &srsis,
+			sizeof(srsis));
+	if (rc) {
+		dev_dbg(&slave->dev, "Failed to read SRSIS0\n");
+		return rc;
+	}
+	if (srsis) {
+		hublink = next_hublink_source(slave, srsis);
+
+		if (!hub->master.dev)
+			return 0;
+
+		device_for_each_child(dev, &hublink, __fsi_hub_slave_irq);
+
+		/* Clear out the interrupting condition */
+		srsis = 0xff000000 >> (hublink * FSI_SRSIX_BITS_PER_LINK);
+		rc =  fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC0,
+					&srsis, sizeof(srsis));
+		if (rc) {
+			dev_dbg(&slave->dev, "Failed to clear out SRSIC\n");
+			return rc;
+		}
+	} else {
+		dev_dbg(&slave->dev, "SI1S HUB src but no SRSIS0 bits!\n");
+		return -EINVAL;
+	}
+
+	return 1;
 }
 
 static int __fsi_slave_irq(struct device *dev, void *data)
-- 
1.8.2.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path
  2017-04-07 13:52 [PATCH linux dev-4.7 0/4] Add FSI interrupt support for hub Christopher Bostic
                   ` (2 preceding siblings ...)
  2017-04-07 13:52 ` [PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources Christopher Bostic
@ 2017-04-07 13:52 ` Christopher Bostic
  2017-04-10 20:32   ` Eddie James
  3 siblings, 1 reply; 10+ messages in thread
From: Christopher Bostic @ 2017-04-07 13:52 UTC (permalink / raw)
  To: joel; +Cc: Christopher Bostic, openbmc

Enable/disable client engine IRQ masks including those along
the hub path to a particular engine. This includes slave
MMODE i-poll, Si1M, SRSIM, and hub master MSIEP.

Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
---
 drivers/fsi/fsi-core.c   | 142 ++++++++++++++++++++++++++++++++++++++++++++---
 drivers/fsi/fsi-master.h |   4 ++
 2 files changed, 139 insertions(+), 7 deletions(-)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index 72f3a35..5ee6bc1 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -1086,17 +1086,140 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv)
 }
 EXPORT_SYMBOL_GPL(fsi_driver_unregister);
 
+static uint32_t link_to_srsim_mask(int link)
+{
+	return ((0x80000000 >> 6) >> FSI_SRSIX_BITS_PER_LINK*link);
+}
+
+static uint32_t link_to_msiep_mask(int link)
+{
+	return (0xf0000000 >> (FSI_MSIEP_BITS_PER_LINK*link));
+}
+
+static int set_si1m(struct fsi_slave *slave, uint32_t mask, int on)
+{
+	int rc;
+	uint32_t si1m;
+
+	rc = fsi_slave_read(slave, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+			sizeof(si1m));
+	if (rc) {
+		dev_dbg(&slave->dev, "Failed to read SI1M\n");
+		return rc;
+	}
+
+	if (on)
+		si1m |= mask;
+	else
+		si1m &= ~mask;
+
+	return fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+			sizeof(si1m));
+}
+
+static int set_upstream_irq_masks(struct fsi_master *master,
+				struct fsi_slave *slave, int on)
+{
+	struct fsi_slave *upstream_slave;
+	struct fsi_master *upstream_master;
+	uint32_t mask, si1m;
+	int rc;
+
+	if (!master->idx)
+		return 0;
+
+	upstream_slave = to_fsi_slave(slave->master->dev->parent);
+	if (!upstream_slave) {
+		dev_dbg(&slave->dev, "No upstream slave found\n");
+		return -ENODEV;
+	}
+
+	rc = fsi_slave_read(upstream_slave, FSI_SLAVE_BASE + FSI_SRSIM0, &si1m,
+			sizeof(si1m));
+	if (rc) {
+		dev_dbg(&slave->dev, "Failed to read SRSIM0\n");
+		return rc;
+	}
+
+	mask = link_to_srsim_mask(slave->link);
+	if (on)
+		si1m |= mask;
+	else
+		si1m &= ~mask;
+	rc = fsi_slave_write(upstream_slave, FSI_SLAVE_BASE + FSI_SRSIM0, &si1m,
+			sizeof(si1m));
+	if (rc) {
+		dev_dbg(&slave->dev, "Failed to write SRSIM0\n");
+		return rc;
+	}
+
+	upstream_master = upstream_slave->master;
+	if (!upstream_master) {
+		dev_dbg(&upstream_slave->dev, "Cannot find master\n");
+		return -ENODEV;
+	}
+
+	rc = upstream_master->read(upstream_master, 0, 0,
+				FSI_HUB_CONTROL + FSI_MSIEP0, &si1m,
+				sizeof(si1m));
+	if (rc) {
+		dev_dbg(&upstream_slave->dev,
+			"Could not read master's MSIEP\n");
+		return rc;
+	}
+
+	/* TODO: merge this into above on/off check */
+	mask = link_to_msiep_mask(slave->link);
+	if (on) {
+		upstream_master->ipoll |= FSI_SI1_HUB_SRC;
+		si1m |= mask;
+	} else {
+		upstream_master->ipoll &= ~FSI_SI1_HUB_SRC;
+		si1m &= ~mask;
+	}
+
+	rc = upstream_master->write(upstream_master, 0, 0,
+				FSI_HUB_CONTROL + FSI_MSIEP0, &si1m,
+				sizeof(si1m));
+	if (rc) {
+		dev_dbg(&upstream_slave->dev,
+			"Failed to write to master's MSIEP\n");
+		return rc;
+	}
+	si1m = 0xd0040410;
+	rc = upstream_master->write(upstream_master, 0, 0,
+				FSI_HUB_CONTROL + FSI_MMODE, &si1m,
+				sizeof(si1m));
+	if (rc) {
+		dev_dbg(&upstream_slave->dev,
+			"Failed to set hub I POLL\n");
+	}
+
+	si1m = FSI_SI1_HUB_SRC;
+	rc = upstream_master->write(upstream_master, 0, 0,
+				FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+				sizeof(si1m));
+	if (rc) {
+		dev_dbg(&upstream_slave->dev,
+			"Failed to set hub mask in SI1M\n");
+	}
+
+	return set_si1m(upstream_slave, FSI_SI1_HUB_SRC, on);
+}
+
 int fsi_enable_irq(struct fsi_device *dev)
 {
 	int rc;
 	u32 si1m;
 	u32 bit = 0x80000000 >> dev->si1s_bit;
 	struct fsi_master *master = dev->slave->master;
+	struct fsi_slave *slave = dev->slave;
+	int link = slave->link;
 
 	if (!dev->irq_handler)
 		return -EINVAL;
 
-	rc = master->read(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+	rc = master->read(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
 			sizeof(u32));
 	if (rc) {
 		dev_err(master->dev, "couldn't read si1m:%d\n", rc);
@@ -1104,7 +1227,7 @@ int fsi_enable_irq(struct fsi_device *dev)
 	}
 
 	si1m |= bit;
-	rc = master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+	rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
 			sizeof(u32));
 	if (rc) {
 		dev_err(master->dev, "couldn't write si1m:%d\n", rc);
@@ -1112,7 +1235,7 @@ int fsi_enable_irq(struct fsi_device *dev)
 	}
 
 	master->ipoll |= bit;
-	return 0;
+	return set_upstream_irq_masks(master, slave, 1);
 }
 EXPORT_SYMBOL_GPL(fsi_enable_irq);
 
@@ -1122,23 +1245,28 @@ void fsi_disable_irq(struct fsi_device *dev)
 	u32 si1m;
 	u32 bits = ~(0x80000000 >> dev->si1s_bit);
 	struct fsi_master *master = dev->slave->master;
+	struct fsi_slave *slave = dev->slave;
+	int link = dev->slave->link;
 
-	master->ipoll &= bits;
+	master->ipoll &= ~bits;
 
-	rc = master->read(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+	rc = master->read(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
 			sizeof(u32));
 	if (rc) {
 		dev_err(master->dev, "couldn't read si1m:%d\n", rc);
 		return;
 	}
 
-	si1m &= bits;
-	rc = master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
+	si1m &= ~bits;
+	rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
 			sizeof(u32));
 	if (rc) {
 		dev_err(master->dev, "couldn't write si1m:%d\n", rc);
 		return;
 	}
+
+	if (!master->ipoll)
+		set_upstream_irq_masks(master, slave, 0);
 }
 
 struct bus_type fsi_bus_type = {
diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
index 54723a7..7c9c3fa 100644
--- a/drivers/fsi/fsi-master.h
+++ b/drivers/fsi/fsi-master.h
@@ -27,6 +27,7 @@
 #define FSI_MLEVP0		0x18		/* R: plug detect */
 #define FSI_MSENP0		0x18		/* S: Set enable */
 #define FSI_MCENP0		0x20		/* C: Clear enable */
+#define FSI_MSIEP0		0x30		/* R/W: Slave IRQ enable */
 #define FSI_MAEB		0x70		/* R: Error address */
 #define FSI_MVER		0x74		/* R: master version/type */
 #define FSI_MRESP0		0xd0		/* W: Port reset */
@@ -47,6 +48,9 @@
 #define FSI_MMODE_CRS1SHFT	8		/* Clk rate selection 1 shift */
 #define FSI_MMODE_CRS1MASK	0x3ff		/* Clk rate selection 1 mask */
 
+/* MSIEP: Slave interrupt enable */
+#define FSI_MSIEP_BITS_PER_LINK	4
+
 /* MRESB: Reset brindge */
 #define FSI_MRESB_RST_GEN	0x80000000	/* General reset */
 #define FSI_MRESB_RST_ERR	0x40000000	/* Error Reset */
-- 
1.8.2.2

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal.
  2017-04-07 13:52 ` [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal Christopher Bostic
@ 2017-04-10 20:03   ` Eddie James
  0 siblings, 0 replies; 10+ messages in thread
From: Eddie James @ 2017-04-10 20:03 UTC (permalink / raw)
  To: Christopher Bostic, joel; +Cc: openbmc



On 04/07/2017 08:52 AM, Christopher Bostic wrote:
> Traverse the slave device list and master slave list using the
> kernel utility device_for_each_child instead of using internally
> managed linked lists.
>
> Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
> ---
>   drivers/fsi/fsi-core.c | 34 ++++++++++++++++++++++------------
>   1 file changed, 22 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index 3d382e6..36dde94 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -778,22 +778,32 @@ static void fsi_master_unscan(struct fsi_master *master)
>   	master->slave_list = false;
>   }
>
> -static void fsi_master_irq(struct fsi_master *master, int link, uint32_t si1s)
> +static int __fsi_dev_irq(struct device *dev, void *data)
>   {
> -	struct fsi_slave *slave;
> -	struct fsi_device *fsi_dev;
> -
> -	if (list_empty(&master->my_slaves))
> -		return;
> +	uint32_t *si1s = data;
> +	struct fsi_device *fsi_dev = to_fsi_dev(dev);
>
> -	slave = list_first_entry(&master->my_slaves, struct fsi_slave,
> -				list_link);
> +	if (!fsi_dev || !si1s) {
> +		dev_dbg(dev, "Invalid input: %p %p\n", fsi_dev, si1s);
> +		return -EINVAL;
> +	}
>
> -	list_for_each_entry(fsi_dev, &slave->my_engines, link) {
> -		if (si1s & (0x80000000 >> fsi_dev->si1s_bit) &&
> -		    fsi_dev->irq_handler)
> -			fsi_dev->irq_handler(0, &fsi_dev->dev);
> +	if (*si1s & (0x80000000 >> fsi_dev->si1s_bit) && fsi_dev->irq_handler) {
> +		fsi_dev->irq_handler(0, &fsi_dev->dev);
> +		return 1;
>   	}
> +
> +	return 0;
> +}
> +
> +static int __fsi_slave_irq(struct device *dev, void *data)
> +{
> +	return device_for_each_child(dev, data, __fsi_dev_irq);
> +}
> +
> +static void fsi_master_irq(struct fsi_master *master, int link, uint32_t si1s)
> +{
> +	device_for_each_child(master->dev, &si1s, __fsi_slave_irq);
>   }
>
>   static int fsi_master_ipoll(void *data)

Looks fine.

Acked-by: Eddie James <eajames@linux.vnet.ibm.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH linux dev-4.7 2/4] drivers/fsi: Look for Hub sourced IRQs
  2017-04-07 13:52 ` [PATCH linux dev-4.7 2/4] drivers/fsi: Look for Hub sourced IRQs Christopher Bostic
@ 2017-04-10 20:05   ` Eddie James
  0 siblings, 0 replies; 10+ messages in thread
From: Eddie James @ 2017-04-10 20:05 UTC (permalink / raw)
  To: Christopher Bostic, joel; +Cc: openbmc



On 04/07/2017 08:52 AM, Christopher Bostic wrote:
> In addition to looking for local device IRQs on the slave also
> check if the IRQ came from a hub source in the interrupt handler.
>
> Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
> ---
>   drivers/fsi/fsi-core.c | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index 36dde94..45e1171 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -98,6 +98,11 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
>   #define FSI_SI1S		0x1C	/* R: IRQ status */
>
>   /*
> + * SI1S, SI1M fields
> + */
> +#define FSI_SI1_HUB_SRC		0x00100000	/* hub IRQ source */
> +
> +/*
>    * SMODE fields
>    */
>   #define	FSI_SMODE_WSC		0x80000000	/* Warm start done */
> @@ -793,6 +798,13 @@ static int __fsi_dev_irq(struct device *dev, void *data)
>   		return 1;
>   	}
>
> +	if (!(*si1s & FSI_SI1_HUB_SRC)) {
> +		dev_dbg(dev, "IRQ not from a hub source\n");
> +		return 0;
> +	}
> +
> +	/* TODO: handle hub sourced IRQ */
> +
>   	return 0;
>   }
>

Acked-by: Eddie James <eajames@linux.vnet.ibm.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources
  2017-04-07 13:52 ` [PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources Christopher Bostic
@ 2017-04-10 20:08   ` Eddie James
  0 siblings, 0 replies; 10+ messages in thread
From: Eddie James @ 2017-04-10 20:08 UTC (permalink / raw)
  To: Christopher Bostic, joel; +Cc: openbmc



On 04/07/2017 08:52 AM, Christopher Bostic wrote:
> Look for the hub link that may have sourced the IRQ being handled.
> Clear out hub link interrupting conditions that are latched in
> hardware after FSI client handler has been dispatched.
>
> Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
> ---
>   drivers/fsi/fsi-core.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 124 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index 45e1171..72f3a35 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -96,6 +96,10 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
>   #define	FSI_SMODE		0x0	/* R/W: Mode register */
>   #define FSI_SI1M		0x18	/* R/W: IRQ mask */
>   #define FSI_SI1S		0x1C	/* R: IRQ status */
> +#define FSI_SRSIC0		0x68	/* R/W: Remote IRQ condition 0 */
> +#define FSI_SRSIC1		0x6C	/* R/W: Remote IRQ condition 1 */
> +#define FSI_SRSIM0		0x70	/* R/W: Remote IRQ mask 0 */
> +#define FSI_SRSIS0		0x78	/* R: Remote IRQ status 0 */
>
>   /*
>    * SI1S, SI1M fields
> @@ -116,6 +120,13 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
>   #define	FSI_SMODE_LBCRR_SHIFT	8		/* Clk ratio shift */
>   #define	FSI_SMODE_LBCRR_MASK	0xf		/* Clk ratio mask */
>
> +/*
> + * SRSIS, SRSIM, SRSIC fields
> + */
> +#define	FSI_SRSIX_IRQ1_MASK	0x00aaaaaa	/* SI1 IRQ sources */
> +#define	FSI_SRSIX_BITS_PER_LINK	8
> +
> +
>   /* FSI endpoint-device support */
>   int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
>   		size_t size)
> @@ -584,6 +595,21 @@ static struct bin_attribute fsi_slave_raw_attr = {
>   	.write = fsi_slave_sysfs_raw_write,
>   };
>
> +static int fsi_slave_irq_clear(struct fsi_slave *slave)
> +{
> +	uint32_t clear = ~0;
> +	int rc;
> +
> +	rc = fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC0, &clear,
> +				sizeof(clear));
> +	if (rc) {
> +		dev_dbg(&slave->dev, "Failed on write to SRSIC0\n");
> +		return rc;
> +	}
> +	return fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC1, &clear,
> +				sizeof(clear));
> +}
> +
>   static int fsi_slave_init(struct fsi_master *master,
>   		int link, uint8_t slave_id)
>   {
> @@ -649,8 +675,11 @@ static int fsi_slave_init(struct fsi_master *master,
>   		dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
>
>   	list_add(&slave->list_link, &master->my_slaves);
> -	fsi_slave_scan(slave);
> -	return 0;
> +	rc = fsi_slave_scan(slave);
> +	if (rc)
> +		return rc;
> +
> +	return fsi_slave_irq_clear(slave);
>   }
>
>   /* FSI master support */
> @@ -783,10 +812,62 @@ static void fsi_master_unscan(struct fsi_master *master)
>   	master->slave_list = false;
>   }
>
> +/* TODO: Add support for hub links 4-7 */
> +static int next_hublink_source(struct fsi_slave *slave, uint32_t srsis)
> +{
> +	int index;
> +
> +	if (!slave)
> +		return -EINVAL;
> +
> +	if (!(srsis & FSI_SRSIX_IRQ1_MASK)) {
> +		dev_dbg(&slave->dev, "Unexpected IRQ source SRSIS:0x%08x\n",
> +			srsis);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * TODO: add a fair scheduler to ensure we don't favor lower
> +	 * hublink IRQ sources over others
> +	 */
> +	index = __clz(srsis);
> +	dev_dbg(&slave->dev, "SRSIS:0x%08x index:%d\n", srsis, index);
> +	return index / FSI_SRSIX_BITS_PER_LINK;
> +}
> +
> +static int __fsi_dev_irq(struct device *dev, void *data);
> +
> +static int __fsi_hub_slave_irq(struct device *dev, void *data)
> +{
> +	int rc;
> +	struct fsi_slave *hub_slave = to_fsi_slave(dev);
> +	uint32_t si1s;
> +
> +	if (!hub_slave) {
> +		dev_dbg(dev, "Could not find hub slave\n");
> +		return -ENODEV;
> +	}
> +
> +	rc = fsi_slave_read(hub_slave, FSI_SLAVE_BASE + FSI_SI1S, &si1s,
> +			sizeof(si1s));
> +	if (rc) {
> +		dev_dbg(dev, "Fail on read of hub slave si1s\n");
> +		return rc;
> +	}
> +
> +	if (!si1s)
> +		return 0;
> +
> +	return device_for_each_child(dev, &si1s, __fsi_dev_irq);
> +}
> +
>   static int __fsi_dev_irq(struct device *dev, void *data)
>   {
> -	uint32_t *si1s = data;
> +	uint32_t *si1s = data, srsis;
>   	struct fsi_device *fsi_dev = to_fsi_dev(dev);
> +	struct fsi_slave *slave;
> +	struct fsi_master_hub *hub;
> +	int rc, hublink;
>
>   	if (!fsi_dev || !si1s) {
>   		dev_dbg(dev, "Invalid input: %p %p\n", fsi_dev, si1s);
> @@ -803,9 +884,47 @@ static int __fsi_dev_irq(struct device *dev, void *data)
>   		return 0;
>   	}
>
> -	/* TODO: handle hub sourced IRQ */
> +	hub = dev_get_drvdata(dev);
> +	if (!hub) {
> +		dev_dbg(dev, "Not a hub device\n");
> +		return 0;
> +	}
>
> -	return 0;
> +	/* Scan the hub links for the source of IRQ */
> +	slave = to_fsi_slave(dev->parent);
> +	if (!slave) {
> +		dev_dbg(dev, "Could not retrieve device's slave\n");
> +		return -ENODEV;
> +	}
> +
> +	rc = fsi_slave_read(slave, FSI_SLAVE_BASE + FSI_SRSIS0, &srsis,
> +			sizeof(srsis));
> +	if (rc) {
> +		dev_dbg(&slave->dev, "Failed to read SRSIS0\n");
> +		return rc;
> +	}
> +	if (srsis) {
> +		hublink = next_hublink_source(slave, srsis);
> +
> +		if (!hub->master.dev)
> +			return 0;
> +
> +		device_for_each_child(dev, &hublink, __fsi_hub_slave_irq);
> +
> +		/* Clear out the interrupting condition */
> +		srsis = 0xff000000 >> (hublink * FSI_SRSIX_BITS_PER_LINK);
> +		rc =  fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC0,
> +					&srsis, sizeof(srsis));
> +		if (rc) {
> +			dev_dbg(&slave->dev, "Failed to clear out SRSIC\n");
> +			return rc;
> +		}
> +	} else {
> +		dev_dbg(&slave->dev, "SI1S HUB src but no SRSIS0 bits!\n");
> +		return -EINVAL;
> +	}
> +
> +	return 1;
>   }
>
>   static int __fsi_slave_irq(struct device *dev, void *data)

This one looks fine too.

Acked-by: Eddie James <eajames@linux.vnet.ibm.com>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path
  2017-04-07 13:52 ` [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path Christopher Bostic
@ 2017-04-10 20:32   ` Eddie James
  2017-04-10 20:39     ` Christopher Bostic
  0 siblings, 1 reply; 10+ messages in thread
From: Eddie James @ 2017-04-10 20:32 UTC (permalink / raw)
  To: Christopher Bostic, joel; +Cc: openbmc



On 04/07/2017 08:52 AM, Christopher Bostic wrote:
> Enable/disable client engine IRQ masks including those along
> the hub path to a particular engine. This includes slave
> MMODE i-poll, Si1M, SRSIM, and hub master MSIEP.
>
> Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
> ---
>   drivers/fsi/fsi-core.c   | 142 ++++++++++++++++++++++++++++++++++++++++++++---
>   drivers/fsi/fsi-master.h |   4 ++
>   2 files changed, 139 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index 72f3a35..5ee6bc1 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -1086,17 +1086,140 @@ void fsi_driver_unregister(struct fsi_driver *fsi_drv)
>   }
>   EXPORT_SYMBOL_GPL(fsi_driver_unregister);
>
> +static uint32_t link_to_srsim_mask(int link)
> +{
> +	return ((0x80000000 >> 6) >> FSI_SRSIX_BITS_PER_LINK*link);
> +}
> +
> +static uint32_t link_to_msiep_mask(int link)
> +{
> +	return (0xf0000000 >> (FSI_MSIEP_BITS_PER_LINK*link));
> +}
> +
> +static int set_si1m(struct fsi_slave *slave, uint32_t mask, int on)
> +{
> +	int rc;
> +	uint32_t si1m;
> +
> +	rc = fsi_slave_read(slave, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +			sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&slave->dev, "Failed to read SI1M\n");
> +		return rc;
> +	}
> +
> +	if (on)
> +		si1m |= mask;
> +	else
> +		si1m &= ~mask;
> +
> +	return fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +			sizeof(si1m));
> +}
> +
> +static int set_upstream_irq_masks(struct fsi_master *master,
> +				struct fsi_slave *slave, int on)
> +{
> +	struct fsi_slave *upstream_slave;
> +	struct fsi_master *upstream_master;
> +	uint32_t mask, si1m;
> +	int rc;
> +
> +	if (!master->idx)
> +		return 0;
> +
> +	upstream_slave = to_fsi_slave(slave->master->dev->parent);
> +	if (!upstream_slave) {
> +		dev_dbg(&slave->dev, "No upstream slave found\n");
> +		return -ENODEV;
> +	}
> +
> +	rc = fsi_slave_read(upstream_slave, FSI_SLAVE_BASE + FSI_SRSIM0, &si1m,
> +			sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&slave->dev, "Failed to read SRSIM0\n");
> +		return rc;
> +	}
> +
> +	mask = link_to_srsim_mask(slave->link);
> +	if (on)
> +		si1m |= mask;
> +	else
> +		si1m &= ~mask;
> +	rc = fsi_slave_write(upstream_slave, FSI_SLAVE_BASE + FSI_SRSIM0, &si1m,
> +			sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&slave->dev, "Failed to write SRSIM0\n");
> +		return rc;
> +	}
> +
> +	upstream_master = upstream_slave->master;
> +	if (!upstream_master) {
> +		dev_dbg(&upstream_slave->dev, "Cannot find master\n");
> +		return -ENODEV;
> +	}
> +
> +	rc = upstream_master->read(upstream_master, 0, 0,
> +				FSI_HUB_CONTROL + FSI_MSIEP0, &si1m,
> +				sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&upstream_slave->dev,
> +			"Could not read master's MSIEP\n");
> +		return rc;
> +	}
> +
> +	/* TODO: merge this into above on/off check */
> +	mask = link_to_msiep_mask(slave->link);
> +	if (on) {
> +		upstream_master->ipoll |= FSI_SI1_HUB_SRC;
> +		si1m |= mask;
> +	} else {
> +		upstream_master->ipoll &= ~FSI_SI1_HUB_SRC;
> +		si1m &= ~mask;
> +	}
> +
> +	rc = upstream_master->write(upstream_master, 0, 0,
> +				FSI_HUB_CONTROL + FSI_MSIEP0, &si1m,
> +				sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&upstream_slave->dev,
> +			"Failed to write to master's MSIEP\n");
> +		return rc;
> +	}
> +	si1m = 0xd0040410;
> +	rc = upstream_master->write(upstream_master, 0, 0,
> +				FSI_HUB_CONTROL + FSI_MMODE, &si1m,
> +				sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&upstream_slave->dev,
> +			"Failed to set hub I POLL\n");
> +	}
> +
> +	si1m = FSI_SI1_HUB_SRC;
> +	rc = upstream_master->write(upstream_master, 0, 0,
> +				FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +				sizeof(si1m));
> +	if (rc) {
> +		dev_dbg(&upstream_slave->dev,
> +			"Failed to set hub mask in SI1M\n");
> +	}
> +
> +	return set_si1m(upstream_slave, FSI_SI1_HUB_SRC, on);
> +}
> +
>   int fsi_enable_irq(struct fsi_device *dev)
>   {
>   	int rc;
>   	u32 si1m;
>   	u32 bit = 0x80000000 >> dev->si1s_bit;
>   	struct fsi_master *master = dev->slave->master;
> +	struct fsi_slave *slave = dev->slave;
> +	int link = slave->link;
>
>   	if (!dev->irq_handler)
>   		return -EINVAL;
>
> -	rc = master->read(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +	rc = master->read(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>   			sizeof(u32));
>   	if (rc) {
>   		dev_err(master->dev, "couldn't read si1m:%d\n", rc);
> @@ -1104,7 +1227,7 @@ int fsi_enable_irq(struct fsi_device *dev)
>   	}
>
>   	si1m |= bit;
> -	rc = master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +	rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>   			sizeof(u32));
>   	if (rc) {
>   		dev_err(master->dev, "couldn't write si1m:%d\n", rc);
> @@ -1112,7 +1235,7 @@ int fsi_enable_irq(struct fsi_device *dev)
>   	}
>
>   	master->ipoll |= bit;
> -	return 0;
> +	return set_upstream_irq_masks(master, slave, 1);
>   }
>   EXPORT_SYMBOL_GPL(fsi_enable_irq);
>
> @@ -1122,23 +1245,28 @@ void fsi_disable_irq(struct fsi_device *dev)
>   	u32 si1m;
>   	u32 bits = ~(0x80000000 >> dev->si1s_bit);
>   	struct fsi_master *master = dev->slave->master;
> +	struct fsi_slave *slave = dev->slave;
> +	int link = dev->slave->link;
>
> -	master->ipoll &= bits;
> +	master->ipoll &= ~bits;

Does this work? Looks like a double bit inversion. Maybe I'm missing 
something but appears to be enabling rather than disabling the si1s bit.

>
> -	rc = master->read(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +	rc = master->read(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>   			sizeof(u32));
>   	if (rc) {
>   		dev_err(master->dev, "couldn't read si1m:%d\n", rc);
>   		return;
>   	}
>
> -	si1m &= bits;
> -	rc = master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
> +	si1m &= ~bits;

Same question here.

Other than that patch set looks good.

Thanks,
Eddie

> +	rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>   			sizeof(u32));
>   	if (rc) {
>   		dev_err(master->dev, "couldn't write si1m:%d\n", rc);
>   		return;
>   	}
> +
> +	if (!master->ipoll)
> +		set_upstream_irq_masks(master, slave, 0);
>   }
>
>   struct bus_type fsi_bus_type = {
> diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
> index 54723a7..7c9c3fa 100644
> --- a/drivers/fsi/fsi-master.h
> +++ b/drivers/fsi/fsi-master.h
> @@ -27,6 +27,7 @@
>   #define FSI_MLEVP0		0x18		/* R: plug detect */
>   #define FSI_MSENP0		0x18		/* S: Set enable */
>   #define FSI_MCENP0		0x20		/* C: Clear enable */
> +#define FSI_MSIEP0		0x30		/* R/W: Slave IRQ enable */
>   #define FSI_MAEB		0x70		/* R: Error address */
>   #define FSI_MVER		0x74		/* R: master version/type */
>   #define FSI_MRESP0		0xd0		/* W: Port reset */
> @@ -47,6 +48,9 @@
>   #define FSI_MMODE_CRS1SHFT	8		/* Clk rate selection 1 shift */
>   #define FSI_MMODE_CRS1MASK	0x3ff		/* Clk rate selection 1 mask */
>
> +/* MSIEP: Slave interrupt enable */
> +#define FSI_MSIEP_BITS_PER_LINK	4
> +
>   /* MRESB: Reset brindge */
>   #define FSI_MRESB_RST_GEN	0x80000000	/* General reset */
>   #define FSI_MRESB_RST_ERR	0x40000000	/* Error Reset */

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path
  2017-04-10 20:32   ` Eddie James
@ 2017-04-10 20:39     ` Christopher Bostic
  0 siblings, 0 replies; 10+ messages in thread
From: Christopher Bostic @ 2017-04-10 20:39 UTC (permalink / raw)
  To: Eddie James, joel; +Cc: openbmc



On 4/10/17 3:32 PM, Eddie James wrote:
>
>
> On 04/07/2017 08:52 AM, Christopher Bostic wrote:
>> Enable/disable client engine IRQ masks including those along
>> the hub path to a particular engine. This includes slave
>> MMODE i-poll, Si1M, SRSIM, and hub master MSIEP.
>>
>> Signed-off-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
>> ---
>>   drivers/fsi/fsi-core.c   | 142 
>> ++++++++++++++++++++++++++++++++++++++++++++---
>>   drivers/fsi/fsi-master.h |   4 ++
>>   2 files changed, 139 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
>> index 72f3a35..5ee6bc1 100644
>> --- a/drivers/fsi/fsi-core.c
>> +++ b/drivers/fsi/fsi-core.c
>> @@ -1086,17 +1086,140 @@ void fsi_driver_unregister(struct fsi_driver 
>> *fsi_drv)
>>   }
>>   EXPORT_SYMBOL_GPL(fsi_driver_unregister);
>>
>> +static uint32_t link_to_srsim_mask(int link)
>> +{
>> +    return ((0x80000000 >> 6) >> FSI_SRSIX_BITS_PER_LINK*link);
>> +}
>> +
>> +static uint32_t link_to_msiep_mask(int link)
>> +{
>> +    return (0xf0000000 >> (FSI_MSIEP_BITS_PER_LINK*link));
>> +}
>> +
>> +static int set_si1m(struct fsi_slave *slave, uint32_t mask, int on)
>> +{
>> +    int rc;
>> +    uint32_t si1m;
>> +
>> +    rc = fsi_slave_read(slave, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +            sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&slave->dev, "Failed to read SI1M\n");
>> +        return rc;
>> +    }
>> +
>> +    if (on)
>> +        si1m |= mask;
>> +    else
>> +        si1m &= ~mask;
>> +
>> +    return fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +            sizeof(si1m));
>> +}
>> +
>> +static int set_upstream_irq_masks(struct fsi_master *master,
>> +                struct fsi_slave *slave, int on)
>> +{
>> +    struct fsi_slave *upstream_slave;
>> +    struct fsi_master *upstream_master;
>> +    uint32_t mask, si1m;
>> +    int rc;
>> +
>> +    if (!master->idx)
>> +        return 0;
>> +
>> +    upstream_slave = to_fsi_slave(slave->master->dev->parent);
>> +    if (!upstream_slave) {
>> +        dev_dbg(&slave->dev, "No upstream slave found\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    rc = fsi_slave_read(upstream_slave, FSI_SLAVE_BASE + FSI_SRSIM0, 
>> &si1m,
>> +            sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&slave->dev, "Failed to read SRSIM0\n");
>> +        return rc;
>> +    }
>> +
>> +    mask = link_to_srsim_mask(slave->link);
>> +    if (on)
>> +        si1m |= mask;
>> +    else
>> +        si1m &= ~mask;
>> +    rc = fsi_slave_write(upstream_slave, FSI_SLAVE_BASE + 
>> FSI_SRSIM0, &si1m,
>> +            sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&slave->dev, "Failed to write SRSIM0\n");
>> +        return rc;
>> +    }
>> +
>> +    upstream_master = upstream_slave->master;
>> +    if (!upstream_master) {
>> +        dev_dbg(&upstream_slave->dev, "Cannot find master\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    rc = upstream_master->read(upstream_master, 0, 0,
>> +                FSI_HUB_CONTROL + FSI_MSIEP0, &si1m,
>> +                sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&upstream_slave->dev,
>> +            "Could not read master's MSIEP\n");
>> +        return rc;
>> +    }
>> +
>> +    /* TODO: merge this into above on/off check */
>> +    mask = link_to_msiep_mask(slave->link);
>> +    if (on) {
>> +        upstream_master->ipoll |= FSI_SI1_HUB_SRC;
>> +        si1m |= mask;
>> +    } else {
>> +        upstream_master->ipoll &= ~FSI_SI1_HUB_SRC;
>> +        si1m &= ~mask;
>> +    }
>> +
>> +    rc = upstream_master->write(upstream_master, 0, 0,
>> +                FSI_HUB_CONTROL + FSI_MSIEP0, &si1m,
>> +                sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&upstream_slave->dev,
>> +            "Failed to write to master's MSIEP\n");
>> +        return rc;
>> +    }
>> +    si1m = 0xd0040410;
>> +    rc = upstream_master->write(upstream_master, 0, 0,
>> +                FSI_HUB_CONTROL + FSI_MMODE, &si1m,
>> +                sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&upstream_slave->dev,
>> +            "Failed to set hub I POLL\n");
>> +    }
>> +
>> +    si1m = FSI_SI1_HUB_SRC;
>> +    rc = upstream_master->write(upstream_master, 0, 0,
>> +                FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +                sizeof(si1m));
>> +    if (rc) {
>> +        dev_dbg(&upstream_slave->dev,
>> +            "Failed to set hub mask in SI1M\n");
>> +    }
>> +
>> +    return set_si1m(upstream_slave, FSI_SI1_HUB_SRC, on);
>> +}
>> +
>>   int fsi_enable_irq(struct fsi_device *dev)
>>   {
>>       int rc;
>>       u32 si1m;
>>       u32 bit = 0x80000000 >> dev->si1s_bit;
>>       struct fsi_master *master = dev->slave->master;
>> +    struct fsi_slave *slave = dev->slave;
>> +    int link = slave->link;
>>
>>       if (!dev->irq_handler)
>>           return -EINVAL;
>>
>> -    rc = master->read(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +    rc = master->read(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, 
>> &si1m,
>>               sizeof(u32));
>>       if (rc) {
>>           dev_err(master->dev, "couldn't read si1m:%d\n", rc);
>> @@ -1104,7 +1227,7 @@ int fsi_enable_irq(struct fsi_device *dev)
>>       }
>>
>>       si1m |= bit;
>> -    rc = master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +    rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, 
>> &si1m,
>>               sizeof(u32));
>>       if (rc) {
>>           dev_err(master->dev, "couldn't write si1m:%d\n", rc);
>> @@ -1112,7 +1235,7 @@ int fsi_enable_irq(struct fsi_device *dev)
>>       }
>>
>>       master->ipoll |= bit;
>> -    return 0;
>> +    return set_upstream_irq_masks(master, slave, 1);
>>   }
>>   EXPORT_SYMBOL_GPL(fsi_enable_irq);
>>
>> @@ -1122,23 +1245,28 @@ void fsi_disable_irq(struct fsi_device *dev)
>>       u32 si1m;
>>       u32 bits = ~(0x80000000 >> dev->si1s_bit);
>>       struct fsi_master *master = dev->slave->master;
>> +    struct fsi_slave *slave = dev->slave;
>> +    int link = dev->slave->link;
>>
>> -    master->ipoll &= bits;
>> +    master->ipoll &= ~bits;
>
> Does this work? Looks like a double bit inversion. Maybe I'm missing 
> something but appears to be enabling rather than disabling the si1s bit.

Hi Eddie,
Yeah, I missed the inverting of bits when the variable is declared above.
>
>>
>> -    rc = master->read(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +    rc = master->read(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, 
>> &si1m,
>>               sizeof(u32));
>>       if (rc) {
>>           dev_err(master->dev, "couldn't read si1m:%d\n", rc);
>>           return;
>>       }
>>
>> -    si1m &= bits;
>> -    rc = master->write(master, 0, 0, FSI_SLAVE_BASE + FSI_SI1M, &si1m,
>> +    si1m &= ~bits;
>
> Same question here.
I'll remove the invert in variable declaration and will take care of it.

Thanks,
Chris
>
> Other than that patch set looks good.
>
> Thanks,
> Eddie
>
>> +    rc = master->write(master, link, 0, FSI_SLAVE_BASE + FSI_SI1M, 
>> &si1m,
>>               sizeof(u32));
>>       if (rc) {
>>           dev_err(master->dev, "couldn't write si1m:%d\n", rc);
>>           return;
>>       }
>> +
>> +    if (!master->ipoll)
>> +        set_upstream_irq_masks(master, slave, 0);
>>   }
>>
>>   struct bus_type fsi_bus_type = {
>> diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h
>> index 54723a7..7c9c3fa 100644
>> --- a/drivers/fsi/fsi-master.h
>> +++ b/drivers/fsi/fsi-master.h
>> @@ -27,6 +27,7 @@
>>   #define FSI_MLEVP0        0x18        /* R: plug detect */
>>   #define FSI_MSENP0        0x18        /* S: Set enable */
>>   #define FSI_MCENP0        0x20        /* C: Clear enable */
>> +#define FSI_MSIEP0        0x30        /* R/W: Slave IRQ enable */
>>   #define FSI_MAEB        0x70        /* R: Error address */
>>   #define FSI_MVER        0x74        /* R: master version/type */
>>   #define FSI_MRESP0        0xd0        /* W: Port reset */
>> @@ -47,6 +48,9 @@
>>   #define FSI_MMODE_CRS1SHFT    8        /* Clk rate selection 1 
>> shift */
>>   #define FSI_MMODE_CRS1MASK    0x3ff        /* Clk rate selection 1 
>> mask */
>>
>> +/* MSIEP: Slave interrupt enable */
>> +#define FSI_MSIEP_BITS_PER_LINK    4
>> +
>>   /* MRESB: Reset brindge */
>>   #define FSI_MRESB_RST_GEN    0x80000000    /* General reset */
>>   #define FSI_MRESB_RST_ERR    0x40000000    /* Error Reset */
>

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2017-04-10 20:40 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-07 13:52 [PATCH linux dev-4.7 0/4] Add FSI interrupt support for hub Christopher Bostic
2017-04-07 13:52 ` [PATCH linux dev-4.7 1/4] drivers/fsi: Change interrupt handler device traversal Christopher Bostic
2017-04-10 20:03   ` Eddie James
2017-04-07 13:52 ` [PATCH linux dev-4.7 2/4] drivers/fsi: Look for Hub sourced IRQs Christopher Bostic
2017-04-10 20:05   ` Eddie James
2017-04-07 13:52 ` [PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources Christopher Bostic
2017-04-10 20:08   ` Eddie James
2017-04-07 13:52 ` [PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path Christopher Bostic
2017-04-10 20:32   ` Eddie James
2017-04-10 20:39     ` Christopher Bostic

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.