[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