📄 ipath_iba6120.c
字号:
return; } ipath_stats.sps_hwerrs++; /* Always clear the error status register, except MEMBISTFAIL, * regardless of whether we continue or stop using the chip. * We want that set so we know it failed, even across driver reload. * We'll still ignore it in the hwerrmask. We do this partly for * diagnostics, but also for support */ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, hwerrs&~INFINIPATH_HWE_MEMBISTFAILED); hwerrs &= dd->ipath_hwerrmask; /* We log some errors to EEPROM, check if we have any of those. */ for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx) if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log) ipath_inc_eeprom_err(dd, log_idx, 1); /* * make sure we get this much out, unless told to be quiet, * or it's occurred within the last 5 seconds */ if ((hwerrs & ~(dd->ipath_lasthwerror | ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) || (ipath_debug & __IPATH_VERBDBG)) dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx " "(cleared)\n", (unsigned long long) hwerrs); dd->ipath_lasthwerror |= hwerrs; if (hwerrs & ~dd->ipath_hwe_bitsextant) ipath_dev_err(dd, "hwerror interrupt with unknown errors " "%llx set\n", (unsigned long long) (hwerrs & ~dd->ipath_hwe_bitsextant)); ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control); if (ctrl & INFINIPATH_C_FREEZEMODE) { /* * parity errors in send memory are recoverable, * just cancel the send (if indicated in * sendbuffererror), * count the occurrence, unfreeze (if no other handled * hardware error bits are set), and continue. They can * occur if a processor speculative read is done to the PIO * buffer while we are sending a packet, for example. */ if ((hwerrs & TXE_PIO_PARITY) && ipath_pe_txe_recover(dd)) hwerrs &= ~TXE_PIO_PARITY; if (hwerrs) { /* * if any set that we aren't ignoring only make the * complaint once, in case it's stuck or recurring, * and we get here multiple times * Force link down, so switch knows, and * LEDs are turned off */ if (dd->ipath_flags & IPATH_INITTED) { ipath_set_linkstate(dd, IPATH_IB_LINKDOWN); ipath_setup_pe_setextled(dd, INFINIPATH_IBCS_L_STATE_DOWN, INFINIPATH_IBCS_LT_STATE_DISABLED); ipath_dev_err(dd, "Fatal Hardware Error (freeze " "mode), no longer usable, SN %.16s\n", dd->ipath_serial); isfatal = 1; } /* * Mark as having had an error for driver, and also * for /sys and status word mapped to user programs. * This marks unit as not usable, until reset */ *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; *dd->ipath_statusp |= IPATH_STATUS_HWERROR; dd->ipath_flags &= ~IPATH_INITTED; } else { static u32 freeze_cnt; freeze_cnt++; ipath_dbg("Clearing freezemode on ignored or recovered " "hardware error (%u)\n", freeze_cnt); ipath_clear_freeze(dd); } } *msg = '\0'; if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) { strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]", msgl); /* ignore from now on, so disable until driver reloaded */ *dd->ipath_statusp |= IPATH_STATUS_HWERROR; dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED; ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, dd->ipath_hwerrmask); } ipath_format_hwerrors(hwerrs, ipath_6120_hwerror_msgs, sizeof(ipath_6120_hwerror_msgs)/ sizeof(ipath_6120_hwerror_msgs[0]), msg, msgl); if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK << INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) { bits = (u32) ((hwerrs >> INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) & INFINIPATH_HWE_PCIEMEMPARITYERR_MASK); snprintf(bitsmsg, sizeof bitsmsg, "[PCIe Mem Parity Errs %x] ", bits); strlcat(msg, bitsmsg, msgl); }#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \ INFINIPATH_HWE_COREPLL_RFSLIP ) if (hwerrs & _IPATH_PLL_FAIL) { snprintf(bitsmsg, sizeof bitsmsg, "[PLL failed (%llx), InfiniPath hardware unusable]", (unsigned long long) hwerrs & _IPATH_PLL_FAIL); strlcat(msg, bitsmsg, msgl); /* ignore from now on, so disable until driver reloaded */ dd->ipath_hwerrmask &= ~(hwerrs & _IPATH_PLL_FAIL); ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, dd->ipath_hwerrmask); } if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED) { /* * If it occurs, it is left masked since the eternal * interface is unused */ dd->ipath_hwerrmask &= ~INFINIPATH_HWE_SERDESPLLFAILED; ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, dd->ipath_hwerrmask); } if (*msg) ipath_dev_err(dd, "%s hardware error\n", msg); if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) { /* * for /sys status file ; if no trailing } is copied, we'll * know it was truncated. */ snprintf(dd->ipath_freezemsg, dd->ipath_freezelen, "{%s}", msg); }}/** * ipath_pe_boardname - fill in the board name * @dd: the infinipath device * @name: the output buffer * @namelen: the size of the output buffer * * info is based on the board revision register */static int ipath_pe_boardname(struct ipath_devdata *dd, char *name, size_t namelen){ char *n = NULL; u8 boardrev = dd->ipath_boardrev; int ret; switch (boardrev) { case 0: n = "InfiniPath_Emulation"; break; case 1: n = "InfiniPath_QLE7140-Bringup"; break; case 2: n = "InfiniPath_QLE7140"; break; case 3: n = "InfiniPath_QMI7140"; break; case 4: n = "InfiniPath_QEM7140"; break; case 5: n = "InfiniPath_QMH7140"; break; case 6: n = "InfiniPath_QLE7142"; break; default: ipath_dev_err(dd, "Don't yet know about board with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u", boardrev); break; } if (n) snprintf(name, namelen, "%s", n); if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) { ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n", dd->ipath_majrev, dd->ipath_minrev); ret = 1; } else { ret = 0; if (dd->ipath_minrev >= 2) dd->ipath_f_put_tid = ipath_pe_put_tid_2; } return ret;}/** * ipath_pe_init_hwerrors - enable hardware errors * @dd: the infinipath device * * now that we have finished initializing everything that might reasonably * cause a hardware error, and cleared those errors bits as they occur, * we can enable hardware errors in the mask (potentially enabling * freeze mode), and enable hardware errors as errors (along with * everything else) in errormask */static void ipath_pe_init_hwerrors(struct ipath_devdata *dd){ ipath_err_t val; u64 extsval; extsval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); if (!(extsval & INFINIPATH_EXTS_MEMBIST_ENDTEST)) ipath_dev_err(dd, "MemBIST did not complete!\n"); if (extsval & INFINIPATH_EXTS_MEMBIST_FOUND) ipath_dbg("MemBIST corrected\n"); val = ~0ULL; /* barring bugs, all hwerrors become interrupts, */ if (!dd->ipath_boardrev) // no PLL for Emulator val &= ~INFINIPATH_HWE_SERDESPLLFAILED; if (dd->ipath_minrev < 2) { /* workaround bug 9460 in internal interface bus parity * checking. Fixed (HW bug 9490) in Rev2. */ val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM; } dd->ipath_hwerrmask = val;}/** * ipath_pe_bringup_serdes - bring up the serdes * @dd: the infinipath device */static int ipath_pe_bringup_serdes(struct ipath_devdata *dd){ u64 val, config1, prev_val; int ret = 0; ipath_dbg("Trying to bringup serdes\n"); if (ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus) & INFINIPATH_HWE_SERDESPLLFAILED) { ipath_dbg("At start, serdes PLL failed bit set " "in hwerrstatus, clearing and continuing\n"); ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, INFINIPATH_HWE_SERDESPLLFAILED); } val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1); ipath_cdbg(VERBOSE, "SerDes status config0=%llx config1=%llx, " "xgxsconfig %llx\n", (unsigned long long) val, (unsigned long long) config1, (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); /* * Force reset on, also set rxdetect enable. Must do before reading * serdesstatus at least for simulation, or some of the bits in * serdes status will come back as undefined and cause simulation * failures */ val |= INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_L1PWR_DN; ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); /* be sure chip saw it */ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); udelay(5); /* need pll reset set at least for a bit */ /* * after PLL is reset, set the per-lane Resets and TxIdle and * clear the PLL reset and rxdetect (to get falling edge). * Leave L1PWR bits set (permanently) */ val &= ~(INFINIPATH_SERDC0_RXDETECT_EN | INFINIPATH_SERDC0_RESET_PLL | INFINIPATH_SERDC0_L1PWR_DN); val |= INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE; ipath_cdbg(VERBOSE, "Clearing pll reset and setting lane resets " "and txidle (%llx)\n", (unsigned long long) val); ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); /* be sure chip saw it */ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); /* need PLL reset clear for at least 11 usec before lane * resets cleared; give it a few more to be sure */ udelay(15); val &= ~(INFINIPATH_SERDC0_RESET_MASK | INFINIPATH_SERDC0_TXIDLE); ipath_cdbg(VERBOSE, "Clearing lane resets and txidle " "(writing %llx)\n", (unsigned long long) val); ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); /* be sure chip saw it */ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch); val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig); prev_val = val; if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) & INFINIPATH_XGXS_MDIOADDR_MASK) != 3) { val &= ~(INFINIPATH_XGXS_MDIOADDR_MASK << INFINIPATH_XGXS_MDIOADDR_SHIFT); /* MDIO address 3 */ val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT; } if (val & INFINIPATH_XGXS_RESET) { val &= ~INFINIPATH_XGXS_RESET; } if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) & INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) { /* need to compensate for Tx inversion in partner */ val &= ~(INFINIPATH_XGXS_RX_POL_MASK << INFINIPATH_XGXS_RX_POL_SHIFT); val |= dd->ipath_rx_pol_inv << INFINIPATH_XGXS_RX_POL_SHIFT; } if (val != prev_val) ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val); val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0); /* clear current and de-emphasis bits */ config1 &= ~0x0ffffffff00ULL; /* set current to 20ma */ config1 |= 0x00000000000ULL; /* set de-emphasis to -5.68dB */ config1 |= 0x0cccc000000ULL; ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig1, config1); ipath_cdbg(VERBOSE, "done: SerDes status config0=%llx " "config1=%llx, sstatus=%llx xgxs=%llx\n", (unsigned long long) val, (unsigned long long) config1, (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesstatus), (unsigned long long) ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig)); if (!ipath_waitfor_mdio_cmdready(dd)) { ipath_write_kreg( dd, dd->ipath_kregs->kr_mdio, ipath_mdio_req(IPATH_MDIO_CMD_READ, 31, IPATH_MDIO_CTRL_XGXS_REG_8, 0)); if (ipath_waitfor_complete(dd, dd->ipath_kregs->kr_mdio, IPATH_MDIO_DATAVALID, &val))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -