[PATCH linux dev-4.10 4/7] drivers/fsi: Set IRQ masks along hub path

Christopher Bostic cbostic at linux.vnet.ibm.com
Wed May 10 07:38:59 AEST 2017


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

Signed-off-by: Christopher Bostic <cbostic at linux.vnet.ibm.com>
---
 drivers/fsi/fsi-core.c       | 145 +++++++++++++++++++++++++++++++++++++++++--
 drivers/fsi/fsi-master-hub.c |   6 +-
 2 files changed, 144 insertions(+), 7 deletions(-)

diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
index d29af9a..d6ea95b 100644
--- a/drivers/fsi/fsi-core.c
+++ b/drivers/fsi/fsi-core.c
@@ -56,6 +56,8 @@
 #define FSI_SI1S		0x1C	/* R  : IRQ status */
 #define FSI_SRSIC0		0x68	/* R/W: Hub IRQ condition 0 */
 #define FSI_SRSIC1		0x6C	/* R/W: Hub IRQ condition 1 */
+#define FSI_SRSIM0		0x70	/* R/W: Hub IRQ mask 0 */
+#define FSI_SRSIS0		0x78	/* R: Hub IRQ status 0 */
 #define FSI_LLMODE		0x100	/* R/W: Link layer mode register */
 
 /*
@@ -72,6 +74,13 @@
 #define FSI_SMODE_LBCRR_SHIFT	8		/* Clk ratio shift */
 #define FSI_SMODE_LBCRR_MASK	0xf		/* Clk ratio mask */
 
+#define FSI_SI1S_HUB_SRC	0x00100000
+
+/*
+ * SRSIM, SRSIS, SRSIC fields
+ */
+#define FSI_SRSIX_BITS_PER_LINK	8
+
 /*
  * LLMODE fields
  */
@@ -79,6 +88,12 @@
 
 #define FSI_SLAVE_SIZE_23b		0x800000
 
+/* Master control regs */
+#define	FSI_HUB_CONTROL		0x3400
+#define FSI_MMODE		0x0		/* R/W: mode */
+#define FSI_MSIEP0		0x30		/* R/W: Slave IRQ enable */
+#define FSI_MSIEP_BITS_PER_LINK	4
+
 static DEFINE_IDA(master_ida);
 
 struct fsi_slave {
@@ -807,7 +822,7 @@ static int __fsi_dev_irq(struct device *dev, void *data)
 		dev_dbg(dev, "IRQ handler exit: %d\n", rc);
 	}
 
-	return 0;
+	return 1;
 }
 
 static int __fsi_slave_irq(struct device *dev, void *data)
@@ -993,17 +1008,129 @@ 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 fsi_write_mask(struct fsi_master *master, struct fsi_slave *slave,
+			uint32_t offset, uint32_t mask, int on)
+{
+	int rc;
+	uint32_t val;
+
+	if (!slave && !master)
+		return -EINVAL;
+
+	if (slave)
+		rc = fsi_slave_read(slave, FSI_SLAVE_BASE + offset, &val,
+				sizeof(val));
+	else
+		rc = master->read(master, 0, 0, offset, &val, sizeof(val));
+
+	if (rc) {
+		dev_dbg(&slave->dev, "Failed to read offset %04x\n",
+			offset);
+		return rc;
+	}
+	val = be32_to_cpu(val);
+
+	if (on)
+		val |= mask;
+	else
+		val &= ~mask;
+
+	val = cpu_to_be32(val);
+	if (slave)
+		rc = fsi_slave_write(slave, FSI_SLAVE_BASE + offset, &val,
+				sizeof(val));
+	else
+		rc = master->write(master, 0, 0, offset, &val, sizeof(val));
+
+	return rc;
+}
+
+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;
+	}
+
+	mask = link_to_srsim_mask(slave->link);
+	rc = fsi_write_mask(NULL, upstream_slave, FSI_SRSIM0, mask, on);
+	if (rc)
+		return rc;
+
+	upstream_master = upstream_slave->master;
+	if (!upstream_master) {
+		dev_dbg(&upstream_slave->dev, "Cannot find master\n");
+		return -ENODEV;
+	}
+
+	mask = link_to_msiep_mask(slave->link);
+
+	/*
+	 * TODO: Remove these HUB control references by creating a new master
+	 * method master->write_control(msiep)
+	 */
+	rc = fsi_write_mask(upstream_master, NULL, FSI_HUB_CONTROL + FSI_MSIEP0,
+			mask, on);
+
+	mask = FSI_SI1S_HUB_SRC;
+	if (on)
+		upstream_master->ipoll |= mask;
+	else
+		upstream_master->ipoll &= mask;
+
+	if (rc)
+		return rc;
+
+	si1m = be32_to_cpu(0xd0040410);
+
+	/*
+	 * TODO: Remove the HUB control reference by creating a new master
+	 * method master->write_control(mmode)
+	 */
+	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 i-poll\n");
+	}
+
+	return fsi_write_mask(NULL, upstream_slave, FSI_SI1M, mask, on);
+}
+
 int fsi_enable_irq(struct fsi_device *dev)
 {
 	int rc;
 	uint32_t si1m;
 	uint32_t 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(uint32_t));
 	if (rc) {
 		dev_err(&master->dev, "Coudn't read si1m:%d\n", rc);
@@ -1011,7 +1138,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(uint32_t));
 	if (rc) {
 		dev_err(&master->dev, "Coudn't write si1m:%d\n", rc);
@@ -1019,20 +1146,23 @@ int fsi_enable_irq(struct fsi_device *dev)
 	}
 
 	master->ipoll |= bit;
-	return 0;
+	return set_upstream_irq_masks(master, slave, 1);
 }
 EXPORT_SYMBOL(fsi_enable_irq);
 
+
 void fsi_disable_irq(struct fsi_device *dev)
 {
 	int rc;
 	uint32_t si1m;
 	uint32_t bits = ~(0x80000000 >> dev->si1s_bit);
 	struct fsi_master *master = dev->slave->master;
+	struct fsi_slave *slave = dev->slave;
+	int link = slave->link;
 
 	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(uint32_t));
 	if (rc) {
 		dev_err(&master->dev, "Couldn't read si1m:%d\n", rc);
@@ -1040,12 +1170,15 @@ void fsi_disable_irq(struct fsi_device *dev)
 	}
 
 	si1m &= bits;
-	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(uint32_t));
 	if (rc) {
 		dev_err(&master->dev, "Coudn't write si1m:%d\n", rc);
 		return;
 	}
+
+	if (!master->ipoll)
+		set_upstream_irq_masks(master, slave, 0);
 }
 EXPORT_SYMBOL(fsi_disable_irq);
 
diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c
index aebaa6b..48944b6 100644
--- a/drivers/fsi/fsi-master-hub.c
+++ b/drivers/fsi/fsi-master-hub.c
@@ -59,7 +59,11 @@
 #define FSI_MMODE_CRS1SHFT	8		/* Clk rate selection 1 shift */
 #define FSI_MMODE_CRS1MASK	0x3ff		/* Clk rate selection 1 mask */
 
-/* MRESB: Reset brindge */
+/* MSIEP: Per slave interrupt enable */
+#define FSI_MSIEP0		0x30		/* R/W: Slave IRQ enable */
+#define FSI_MSIEP_BITS_PER_LINK 4
+
+/* MRESB: Reset bridge */
 #define FSI_MRESB_RST_GEN	0x80000000	/* General reset */
 #define FSI_MRESB_RST_ERR	0x40000000	/* Error Reset */
 
-- 
1.8.2.2



More information about the openbmc mailing list