From patchwork Tue Jun 23 04:25:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Herrenschmidt X-Patchwork-Id: 487504 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id F1CE7140157 for ; Tue, 23 Jun 2015 14:27:10 +1000 (AEST) Received: from ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id D39BB1A0FA9 for ; Tue, 23 Jun 2015 14:27:10 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from gate.crashing.org (gate.crashing.org [63.228.1.57]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 0E0201A0F71 for ; Tue, 23 Jun 2015 14:26:25 +1000 (AEST) Received: from pasglop.ozlabs.ibm.com (localhost.localdomain [127.0.0.1]) by gate.crashing.org (8.14.1/8.13.8) with ESMTP id t5N4Q2mQ029011; Mon, 22 Jun 2015 23:26:11 -0500 From: Benjamin Herrenschmidt To: skiboot@lists.ozlabs.org Date: Tue, 23 Jun 2015 14:25:57 +1000 Message-Id: <1435033560-9180-7-git-send-email-benh@kernel.crashing.org> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1435033560-9180-1-git-send-email-benh@kernel.crashing.org> References: <1435033560-9180-1-git-send-email-benh@kernel.crashing.org> Subject: [Skiboot] [PATCH 07/10] fsi-master: Refactor the driver X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" 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 --- hw/fsi-master.c | 240 ++++++++++++++++++++++++++++++++------------------------ include/chip.h | 4 + 2 files changed, 141 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); + + } } diff --git a/include/chip.h b/include/chip.h index 9cecace..470ba64 100644 --- a/include/chip.h +++ b/include/chip.h @@ -79,6 +79,7 @@ struct dt_node; struct centaur_chip; +struct mfsi; /* Chip type */ enum proc_chip_type { @@ -161,6 +162,9 @@ struct proc_chip { /* Used by hw/psi.c */ struct psi *psi; + + /* Used by hw/fsi-master.c */ + struct mfsi *fsi_masters; }; extern uint32_t pir_to_chip_id(uint32_t pir);