diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2015-06-23 14:25:57 +1000 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-07-06 17:06:54 +1000 |
commit | 194bbe6f0038899a8468c1d11f3bec6489d95f44 (patch) | |
tree | b4de8b3a1555a3c823bd93bf8c7650dc3590600c /hw/fsi-master.c | |
parent | f9e92f3714a85aa2ea1681cfb52879e30c5c6618 (diff) | |
download | skiboot-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.c | 240 |
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, ®, &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, ®, &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); + + } } |