static int epb_access(struct qib_devdata *dd, int sdnum, int claim) { u16 acc; u64 accval; int owned = 0; u64 oct_sel = 0; switch (sdnum) { case IB_7220_SERDES: acc = kr_ibsd_epb_access_ctrl; break; case PCIE_SERDES0: case PCIE_SERDES1: acc = kr_pciesd_epb_access_ctrl; oct_sel = (2 << (sdnum - PCIE_SERDES0)); break; default: return 0; } qib_read_kreg32(dd, kr_scratch); udelay(15); accval = qib_read_kreg32(dd, acc); owned = !!(accval & EPB_ACC_GNT); if (claim < 0) { u64 pollval; u64 newval = 0; qib_write_kreg(dd, acc, newval); pollval = qib_read_kreg32(dd, acc); udelay(5); pollval = qib_read_kreg32(dd, acc); if (pollval & EPB_ACC_GNT) owned = -1; } else if (claim > 0) { u64 pollval; u64 newval = EPB_ACC_REQ | oct_sel; qib_write_kreg(dd, acc, newval); pollval = qib_read_kreg32(dd, acc); udelay(5); pollval = qib_read_kreg32(dd, acc); if (!(pollval & EPB_ACC_GNT)) owned = -1; } return owned; }
/* * Lemma to deal with race condition of write..read to epb regs */ static int epb_trans(struct qib_devdata *dd, u16 reg, u64 i_val, u64 *o_vp) { int tries; u64 transval; qib_write_kreg(dd, reg, i_val); /* Throw away first read, as RDY bit may be stale */ transval = qib_read_kreg64(dd, reg); for (tries = EPB_TRANS_TRIES; tries; --tries) { transval = qib_read_kreg32(dd, reg); if (transval & EPB_TRANS_RDY) break; udelay(5); } if (transval & EPB_TRANS_ERR) return -1; if (tries > 0 && o_vp) *o_vp = transval; return tries; }
void qib_sd7220_clr_ibpar(struct qib_devdata *dd) { int ret; /* clear, then re-enable parity errs */ ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, UC_PAR_CLR_D, UC_PAR_CLR_M); if (ret < 0) { qib_dev_err(dd, "Failed clearing IBSerDes Parity err\n"); goto bail; } ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0, UC_PAR_CLR_M); qib_read_kreg32(dd, kr_scratch); udelay(4); qib_write_kreg(dd, kr_hwerrclear, QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); qib_read_kreg32(dd, kr_scratch); bail: return; }
/* * query, claim, release ownership of the EPB (External Parallel Bus) * for a specified SERDES. * the "claim" parameter is >0 to claim, <0 to release, 0 to query. * Returns <0 for errors, >0 if we had ownership, else 0. */ static int epb_access(struct qib_devdata *dd, int sdnum, int claim) { u16 acc; u64 accval; int owned = 0; u64 oct_sel = 0; switch (sdnum) { case IB_7220_SERDES: /* * The IB SERDES "ownership" is fairly simple. A single each * request/grant. */ acc = kr_ibsd_epb_access_ctrl; break; case PCIE_SERDES0: case PCIE_SERDES1: /* PCIe SERDES has two "octants", need to select which */ acc = kr_pciesd_epb_access_ctrl; oct_sel = (2 << (sdnum - PCIE_SERDES0)); break; default: return 0; } /* Make sure any outstanding transaction was seen */ qib_read_kreg32(dd, kr_scratch); udelay(15); accval = qib_read_kreg32(dd, acc); owned = !!(accval & EPB_ACC_GNT); if (claim < 0) { /* Need to release */ u64 pollval; /* * The only writeable bits are the request and CS. * Both should be clear */ u64 newval = 0; qib_write_kreg(dd, acc, newval); /* First read after write is not trustworthy */ pollval = qib_read_kreg32(dd, acc); udelay(5); pollval = qib_read_kreg32(dd, acc); if (pollval & EPB_ACC_GNT) owned = -1; } else if (claim > 0) { /* Need to claim */ u64 pollval; u64 newval = EPB_ACC_REQ | oct_sel; qib_write_kreg(dd, acc, newval); /* First read after write is not trustworthy */ pollval = qib_read_kreg32(dd, acc); udelay(5); pollval = qib_read_kreg32(dd, acc); if (!(pollval & EPB_ACC_GNT)) owned = -1; } return owned; }
/* * Localize the stuff that should be done to change IB uC reset * returns <0 for errors. */ static int qib_ibsd_reset(struct qib_devdata *dd, int assert_rst) { u64 rst_val; int ret = 0; unsigned long flags; rst_val = qib_read_kreg64(dd, kr_ibserdesctrl); if (assert_rst) { /* * Vendor recommends "interrupting" uC before reset, to * minimize possible glitches. */ spin_lock_irqsave(&dd->cspec->sdepb_lock, flags); epb_access(dd, IB_7220_SERDES, 1); rst_val |= 1ULL; /* Squelch possible parity error from _asserting_ reset */ qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask & ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); qib_write_kreg(dd, kr_ibserdesctrl, rst_val); /* flush write, delay to ensure it took effect */ qib_read_kreg32(dd, kr_scratch); udelay(2); /* once it's reset, can remove interrupt */ epb_access(dd, IB_7220_SERDES, -1); spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); } else { /* * Before we de-assert reset, we need to deal with * possible glitch on the Parity-error line. * Suppress it around the reset, both in chip-level * hwerrmask and in IB uC control reg. uC will allow * it again during startup. */ u64 val; rst_val &= ~(1ULL); qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask & ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); ret = qib_resync_ibepb(dd); if (ret < 0) qib_dev_err(dd, "unable to re-sync IB EPB\n"); /* set uC control regs to suppress parity errs */ ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG5, 1, 1); if (ret < 0) goto bail; /* IB uC code past Version 1.32.17 allow suppression of wdog */ ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80, 0x80); if (ret < 0) { qib_dev_err(dd, "Failed to set WDOG disable\n"); goto bail; } qib_write_kreg(dd, kr_ibserdesctrl, rst_val); /* flush write, delay for startup */ qib_read_kreg32(dd, kr_scratch); udelay(1); /* clear, then re-enable parity errs */ qib_sd7220_clr_ibpar(dd); val = qib_read_kreg64(dd, kr_hwerrstatus); if (val & QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR) { qib_dev_err(dd, "IBUC Parity still set after RST\n"); dd->cspec->hwerrmask &= ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR; } qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask); } bail: return ret; }
static int qib_ibsd_reset(struct qib_devdata *dd, int assert_rst) { u64 rst_val; int ret = 0; unsigned long flags; rst_val = qib_read_kreg64(dd, kr_ibserdesctrl); if (assert_rst) { spin_lock_irqsave(&dd->cspec->sdepb_lock, flags); epb_access(dd, IB_7220_SERDES, 1); rst_val |= 1ULL; qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask & ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); qib_write_kreg(dd, kr_ibserdesctrl, rst_val); qib_read_kreg32(dd, kr_scratch); udelay(2); epb_access(dd, IB_7220_SERDES, -1); spin_unlock_irqrestore(&dd->cspec->sdepb_lock, flags); } else { u64 val; rst_val &= ~(1ULL); qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask & ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR); ret = qib_resync_ibepb(dd); if (ret < 0) qib_dev_err(dd, "unable to re-sync IB EPB\n"); ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG5, 1, 1); if (ret < 0) goto bail; ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES, IB_MPREG6, 0x80, 0x80); if (ret < 0) { qib_dev_err(dd, "Failed to set WDOG disable\n"); goto bail; } qib_write_kreg(dd, kr_ibserdesctrl, rst_val); qib_read_kreg32(dd, kr_scratch); udelay(1); qib_sd7220_clr_ibpar(dd); val = qib_read_kreg64(dd, kr_hwerrstatus); if (val & QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR) { qib_dev_err(dd, "IBUC Parity still set after RST\n"); dd->cspec->hwerrmask &= ~QLOGIC_IB_HWE_IB_UC_MEMORYPARITYERR; } qib_write_kreg(dd, kr_hwerrmask, dd->cspec->hwerrmask); } bail: return ret; }