[PATCH linux dev-4.7 4/4] drivers/fsi: Set IRQ masks along hub path
Christopher Bostic
cbostic at linux.vnet.ibm.com
Fri Apr 7 23:52:25 AEST 2017
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 at 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
More information about the openbmc
mailing list