aboutsummaryrefslogtreecommitdiff
path: root/hw/fsi-master.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-06-23 14:25:57 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-07-06 17:06:54 +1000
commit194bbe6f0038899a8468c1d11f3bec6489d95f44 (patch)
treeb4de8b3a1555a3c823bd93bf8c7650dc3590600c /hw/fsi-master.c
parentf9e92f3714a85aa2ea1681cfb52879e30c5c6618 (diff)
downloadskiboot-194bbe6f0038899a8468c1d11f3bec6489d95f44.zip
skiboot-194bbe6f0038899a8468c1d11f3bec6489d95f44.tar.gz
skiboot-194bbe6f0038899a8468c1d11f3bec6489d95f44.tar.bz2
fsi-master: Refactor the driver
Move the various base addresses etc... in a per-instance struct mfsi which simplifies the code and will make it easier to add subsequent error handling improvements. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/fsi-master.c')
-rw-r--r--hw/fsi-master.c240
1 files changed, 137 insertions, 103 deletions
diff --git a/hw/fsi-master.c b/hw/fsi-master.c
index b8e5d6b..f2efd01 100644
--- a/hw/fsi-master.c
+++ b/hw/fsi-master.c
@@ -64,64 +64,75 @@
#define hMFSI_OPB_REG_BASE 0x03400
#define MFSI_OPB_PORT_STRIDE 0x08000
-
+struct mfsi {
+ uint32_t chip_id;
+ uint32_t unit;
+ uint32_t xscom_base;
+ uint32_t port_base;
+ uint32_t reg_base;
+ uint32_t err_bits;
+};
+
+#define mfsi_log(__lev, __m, __fmt, ...) \
+ prlog(__lev, "MFSI %x:%x: " __fmt, __m->chip_id, __m->unit, ##__VA_ARGS__)
/*
* Use a global FSI lock for now. Beware of re-entrancy
* if we ever add support for normal chip XSCOM via FSI, in
* which case we'll probably have to consider either per chip
* lock (which can have AB->BA deadlock issues) or a re-entrant
- * global lock
+ * global lock or something else. ...
*/
static struct lock fsi_lock = LOCK_UNLOCKED;
-static uint32_t mfsi_valid_err;
/*
* OPB accessors
*/
-#define MFSI_OPB_MAX_TRIES 120
+/* We try up to 1.2ms for an OPB access */
+#define MFSI_OPB_MAX_TRIES 1200
-static int64_t mfsi_pib2opb_reset(uint32_t chip, uint32_t xscom_base)
+static int64_t mfsi_pib2opb_reset(struct mfsi *mfsi)
{
uint64_t stat;
int64_t rc;
- rc = xscom_write(chip, xscom_base + PIB2OPB_REG_RESET, (1ul << 63));
+ rc = xscom_write(mfsi->chip_id,
+ mfsi->xscom_base + PIB2OPB_REG_RESET, (1ul << 63));
if (rc) {
- prerror("MFSI: XSCOM error %lld resetting PIB2OPB\n", rc);
+ mfsi_log(PR_ERR, mfsi, "XSCOM error %lld resetting PIB2OPB\n", rc);
return rc;
}
- rc = xscom_write(chip, xscom_base + PIB2OPB_REG_STAT, (1ul << 63));
+ rc = xscom_write(mfsi->chip_id,
+ mfsi->xscom_base + PIB2OPB_REG_STAT, (1ul << 63));
if (rc) {
- prerror("MFSI: XSCOM error %lld resetting status\n", rc);
+ mfsi_log(PR_ERR, mfsi, "XSCOM error %lld resetting status\n", rc);
return rc;
}
- rc = xscom_read(chip, xscom_base + PIB2OPB_REG_STAT, &stat);
+ rc = xscom_read(mfsi->chip_id,
+ mfsi->xscom_base + PIB2OPB_REG_STAT, &stat);
if (rc) {
- prerror("MFSI: XSCOM error %lld reading status\n", rc);
+ mfsi_log(PR_ERR, mfsi, "XSCOM error %lld reading status\n", rc);
return rc;
}
return 0;
}
-static int64_t mfsi_handle_opb_error(uint32_t chip, uint32_t xscom_base,
- uint32_t stat, uint32_t err_bits)
+static int64_t mfsi_handle_opb_error(struct mfsi *mfsi, uint32_t stat)
{
- prerror("MFSI: Error status=0x%08x (raw=0x%08x) !\n",
- stat & err_bits, stat);
+ mfsi_log(PR_ERR, mfsi, "MFSI: Error status=0x%08x (raw=0x%08x)\n",
+ stat & mfsi->err_bits, stat);
/* For now, just reset the PIB2OPB on error. We should collect more
* info and look at the remote errors in the target as well but that
* will be for another day.
*/
- mfsi_pib2opb_reset(chip, xscom_base);
+ mfsi_pib2opb_reset(mfsi);
return OPAL_HARDWARE;
}
-static int64_t mfsi_opb_poll(uint32_t chip, uint32_t xscom_base,
- uint32_t *read_data, uint32_t err_bits)
+static int64_t mfsi_opb_poll(struct mfsi *mfsi, uint32_t *read_data)
{
unsigned long retries = MFSI_OPB_MAX_TRIES;
uint64_t sval;
@@ -131,13 +142,13 @@ static int64_t mfsi_opb_poll(uint32_t chip, uint32_t xscom_base,
/* We try again every 10us for a bit more than 1ms */
for (;;) {
/* Read OPB status register */
- rc = xscom_read(chip, xscom_base + PIB2OPB_REG_STAT, &sval);
+ rc = xscom_read(mfsi->chip_id, mfsi->xscom_base + PIB2OPB_REG_STAT, &sval);
if (rc) {
/* Do something here ? */
- prerror("MFSI: XSCOM error %lld read OPB STAT\n", rc);
+ mfsi_log(PR_ERR, mfsi, "XSCOM error %lld read OPB STAT\n", rc);
return rc;
}
- prlog(PR_INSANE, " STAT=0x%16llx...\n", sval);
+ mfsi_log(PR_INSANE, mfsi, " STAT=0x%16llx...\n", sval);
stat = sval >> 32;
@@ -146,21 +157,22 @@ static int64_t mfsi_opb_poll(uint32_t chip, uint32_t xscom_base,
break;
if (retries-- == 0) {
/* XXX What should we do here ? reset it ? */
- prerror("MFSI: OPB POLL timeout !\n");
+ mfsi_log(PR_ERR, mfsi, "OPB POLL timeout !\n");
return OPAL_HARDWARE;
}
- time_wait_us(10);
+ time_wait_us(1);
}
/* Did we have an error ? */
- if (stat & err_bits)
- return mfsi_handle_opb_error(chip, xscom_base, stat, err_bits);
+ if (stat & mfsi->err_bits)
+ return mfsi_handle_opb_error(mfsi, stat);
if (read_data) {
if (!(stat & OPB_STAT_READ_VALID)) {
- prerror("MFSI: Read successful but no data !\n");
+ mfsi_log(PR_ERR, mfsi, "Read successful but no data !\n");
+
/* What do do here ? can it actually happen ? */
- sval |= 0xffffffff;
+ sval = 0xffffffff;
}
*read_data = sval & 0xffffffff;
}
@@ -168,135 +180,142 @@ static int64_t mfsi_opb_poll(uint32_t chip, uint32_t xscom_base,
return OPAL_SUCCESS;
}
-static int64_t mfsi_opb_read(uint32_t chip, uint32_t xscom_base,
- uint32_t addr, uint32_t *data,
- uint32_t err_bits)
+static int64_t mfsi_opb_read(struct mfsi *mfsi, uint32_t opb_addr, uint32_t *data)
{
uint64_t opb_cmd = OPB_CMD_READ | OPB_CMD_32BIT;
int64_t rc;
- if (addr > 0x00ffffff)
+ if (opb_addr > 0x00ffffff)
return OPAL_PARAMETER;
- opb_cmd |= addr;
+ opb_cmd |= opb_addr;
opb_cmd <<= 32;
- prlog(PR_INSANE, "MFSI_OPB_READ: Writing 0x%16llx to XSCOM %x\n",
- opb_cmd, xscom_base);
+ mfsi_log(PR_INSANE, mfsi, "MFSI_OPB_READ: Writing 0x%16llx to XSCOM %x\n",
+ opb_cmd, mfsi->xscom_base);
- rc = xscom_write(chip, xscom_base + PIB2OPB_REG_CMD, opb_cmd);
+ rc = xscom_write(mfsi->chip_id, mfsi->xscom_base + PIB2OPB_REG_CMD, opb_cmd);
if (rc) {
- prerror("MFSI: XSCOM error %lld writing OPB CMD\n", rc);
+ mfsi_log(PR_ERR, mfsi, "XSCOM error %lld writing OPB CMD\n", rc);
return rc;
}
- return mfsi_opb_poll(chip, xscom_base, data, err_bits);
+ return mfsi_opb_poll(mfsi, data);
}
-static int64_t mfsi_opb_write(uint32_t chip, uint32_t xscom_base,
- uint32_t addr, uint32_t data,
- uint32_t err_bits)
+static int64_t mfsi_opb_write(struct mfsi *mfsi, uint32_t opb_addr, uint32_t data)
{
uint64_t opb_cmd = OPB_CMD_WRITE | OPB_CMD_32BIT;
int64_t rc;
- if (addr > 0x00ffffff)
+ if (opb_addr > 0x00ffffff)
return OPAL_PARAMETER;
- opb_cmd |= addr;
+ opb_cmd |= opb_addr;
opb_cmd <<= 32;
opb_cmd |= data;
- prlog(PR_INSANE, "MFSI_OPB_WRITE: Writing 0x%16llx to XSCOM %x\n",
- opb_cmd, xscom_base);
+ mfsi_log(PR_INSANE, mfsi, "MFSI_OPB_WRITE: Writing 0x%16llx to XSCOM %x\n",
+ opb_cmd, mfsi->xscom_base);
- rc = xscom_write(chip, xscom_base + PIB2OPB_REG_CMD, opb_cmd);
+ rc = xscom_write(mfsi->chip_id, mfsi->xscom_base + PIB2OPB_REG_CMD, opb_cmd);
if (rc) {
- prerror("MFSI: XSCOM error %lld writing OPB CMD\n", rc);
+ mfsi_log(PR_ERR, mfsi, "XSCOM error %lld writing OPB CMD\n", rc);
return rc;
}
- return mfsi_opb_poll(chip, xscom_base, NULL, err_bits);
+ return mfsi_opb_poll(mfsi, NULL);
}
-static int64_t mfsi_get_addrs(uint32_t mfsi, uint32_t port,
- uint32_t *xscom_base, uint32_t *port_base,
- uint32_t *reg_base, uint32_t *err_bits)
+static struct mfsi *mfsi_get(uint32_t chip_id, uint32_t unit)
{
- if (port > 7)
- return OPAL_PARAMETER;
-
- /* We hard code everything for now */
- switch(mfsi) {
- case MFSI_cMFSI0:
- *xscom_base = PIB2OPB_MFSI0_ADDR;
- *port_base = cMFSI_OPB_PORT_BASE + port * MFSI_OPB_PORT_STRIDE;
- *reg_base = cMFSI_OPB_REG_BASE;
- *err_bits = OPB_STAT_ERR_BASE | OPB_STAT_ERR_CMFSI;
- break;
- case MFSI_cMFSI1:
- *xscom_base = PIB2OPB_MFSI1_ADDR;
- *port_base = cMFSI_OPB_PORT_BASE + port * MFSI_OPB_PORT_STRIDE;
- *reg_base = cMFSI_OPB_REG_BASE;
- *err_bits = OPB_STAT_ERR_BASE | OPB_STAT_ERR_CMFSI;
- break;
- case MFSI_hMFSI0:
- *xscom_base = PIB2OPB_MFSI0_ADDR;
- *port_base = hMFSI_OPB_PORT_BASE + port * MFSI_OPB_PORT_STRIDE;
- *reg_base = hMFSI_OPB_REG_BASE;
- *err_bits = OPB_STAT_ERR_BASE | OPB_STAT_ERR_HMFSI;
- break;
- default:
- return OPAL_PARAMETER;
- }
- *err_bits = *err_bits & mfsi_valid_err;
-
- return OPAL_SUCCESS;
+ struct proc_chip *chip = get_chip(chip_id);
+ struct mfsi *mfsi;
+
+ if (!chip || unit > MFSI_hMFSI0)
+ return NULL;
+ mfsi = &chip->fsi_masters[unit];
+ if (mfsi->xscom_base == 0)
+ return NULL;
+ return mfsi;
}
-int64_t mfsi_read(uint32_t chip, uint32_t mfsi, uint32_t port,
+int64_t mfsi_read(uint32_t chip, uint32_t unit, uint32_t port,
uint32_t fsi_addr, uint32_t *data)
{
+ struct mfsi *mfsi = mfsi_get(chip, unit);
+ uint32_t port_addr;
int64_t rc;
- uint32_t xscom, port_addr, reg, err_bits;
- rc = mfsi_get_addrs(mfsi, port, &xscom, &port_addr, &reg, &err_bits);
- if (rc)
- return rc;
+ if (!mfsi)
+ return OPAL_PARAMETER;
+
lock(&fsi_lock);
- rc = mfsi_opb_read(chip, xscom, port_addr + fsi_addr, data, err_bits);
- /* XXX Handle FSI level errors here, maybe reset port */
+
+ /* Calculate port address */
+ port_addr = mfsi->port_base + port * MFSI_OPB_PORT_STRIDE;
+ port_addr += fsi_addr;
+
+ /* Perform OPB access */
+ rc = mfsi_opb_read(mfsi, port_addr, data);
+
+ /* XXX Handle FSI level errors here */
+
unlock(&fsi_lock);
return rc;
}
-int64_t mfsi_write(uint32_t chip, uint32_t mfsi, uint32_t port,
+int64_t mfsi_write(uint32_t chip, uint32_t unit, uint32_t port,
uint32_t fsi_addr, uint32_t data)
{
+ struct mfsi *mfsi = mfsi_get(chip, unit);
+ uint32_t port_addr;
int64_t rc;
- uint32_t xscom, port_addr, reg, err_bits;
- rc = mfsi_get_addrs(mfsi, port, &xscom, &port_addr, &reg, &err_bits);
- if (rc)
- return rc;
lock(&fsi_lock);
- rc = mfsi_opb_write(chip, xscom, port_addr + fsi_addr, data, err_bits);
- /* XXX Handle FSI level errors here, maybe reset port */
+
+ /* Calculate port address */
+ port_addr = mfsi->port_base + port * MFSI_OPB_PORT_STRIDE;
+ port_addr += fsi_addr;
+
+ /* Perform OPB access */
+ rc = mfsi_opb_write(mfsi, port_addr, data);
+
+ /* XXX Handle FSI level errors here */
+
unlock(&fsi_lock);
return rc;
}
-void mfsi_init(void)
+static void mfsi_add(struct proc_chip *chip, struct mfsi *mfsi, uint32_t unit)
{
- struct proc_chip *chip;
-
- /* For now assume all chips are the same DD... might need
- * fixing.
- */
- chip = next_chip(NULL);
- assert(chip);
- mfsi_valid_err = OPB_STAT_ERR_BASE | OPB_STAT_ERR_CMFSI | OPB_STAT_ERR_HMFSI;
+ mfsi->chip_id = chip->id;
+ mfsi->unit = unit;
+ /* We hard code everything for now */
+ switch(unit) {
+ case MFSI_cMFSI0:
+ mfsi->xscom_base = PIB2OPB_MFSI0_ADDR;
+ mfsi->port_base = cMFSI_OPB_PORT_BASE;
+ mfsi->reg_base = cMFSI_OPB_REG_BASE;
+ mfsi->err_bits = OPB_STAT_ERR_BASE | OPB_STAT_ERR_CMFSI;
+ break;
+ case MFSI_cMFSI1:
+ mfsi->xscom_base = PIB2OPB_MFSI1_ADDR;
+ mfsi->port_base = cMFSI_OPB_PORT_BASE;
+ mfsi->reg_base = cMFSI_OPB_REG_BASE;
+ mfsi->err_bits = OPB_STAT_ERR_BASE | OPB_STAT_ERR_CMFSI;
+ break;
+ case MFSI_hMFSI0:
+ mfsi->xscom_base = PIB2OPB_MFSI0_ADDR;
+ mfsi->port_base = hMFSI_OPB_PORT_BASE;
+ mfsi->reg_base = hMFSI_OPB_REG_BASE;
+ mfsi->err_bits = OPB_STAT_ERR_BASE | OPB_STAT_ERR_HMFSI;
+ break;
+ default:
+ /* ??? */
+ return;
+ }
/* Hardware Bug HW222712 on Murano DD1.0 causes the
* any_error bit to be un-clearable so we just
@@ -310,6 +329,21 @@ void mfsi_init(void)
/* 16: cMFSI any-master-error */
/* 24: hMFSI any-master-error */
- mfsi_valid_err &= 0xFFFF7F7F;
+ mfsi->err_bits &= 0xFFFF7F7F;
+
+ mfsi_log(PR_INFO, mfsi, "Initialized\n");
+}
+
+void mfsi_init(void)
+{
+ struct proc_chip *chip;
+
+ for_each_chip(chip) {
+ chip->fsi_masters = zalloc(sizeof(struct mfsi) * 3);
+ mfsi_add(chip, &chip->fsi_masters[MFSI_cMFSI0], MFSI_cMFSI0);
+ mfsi_add(chip, &chip->fsi_masters[MFSI_hMFSI0], MFSI_hMFSI0);
+ mfsi_add(chip, &chip->fsi_masters[MFSI_cMFSI1], MFSI_cMFSI1);
+
+ }
}