📄 ipath_iba6110.c
字号:
INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"), INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),};#define TXE_PIO_PARITY ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF | \ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC) \ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)#define RXE_EAGER_PARITY (INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID \ << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)static int ipath_ht_txe_recover(struct ipath_devdata *);/** * ipath_ht_handle_hwerrors - display hardware errors. * @dd: the infinipath device * @msg: the output buffer * @msgl: the size of the output buffer * * Use same msg buffer as regular errors to avoid excessive stack * use. Most hardware errors are catastrophic, but for right now, * we'll print them and continue. We reuse the same message buffer as * ipath_handle_errors() to avoid excessive stack usage. */static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg, size_t msgl){ ipath_err_t hwerrs; u32 bits, ctrl; int isfatal = 0; char bitsmsg[64]; int log_idx; hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus); if (!hwerrs) { ipath_cdbg(VERBOSE, "Called but no hardware errors set\n"); /* * better than printing cofusing messages * This seems to be related to clearing the crc error, or * the pll error during init. */ goto bail; } else if (hwerrs == -1LL) { ipath_dev_err(dd, "Read of hardware error status failed " "(all bits set); ignoring\n"); goto bail; } 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, * it's a parity error we may recover from, * or it's occurred within the last 5 seconds */ if ((hwerrs & ~(dd->ipath_lasthwerror | TXE_PIO_PARITY | RXE_EAGER_PARITY)) || (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) && !ipath_diag_inuse) { /* * 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_ht_txe_recover(dd)) hwerrs &= ~TXE_PIO_PARITY; if (hwerrs & RXE_EAGER_PARITY) ipath_dev_err(dd, "RXE parity, Eager TID error is not " "recoverable\n"); if (!hwerrs) { ipath_dbg("Clearing freezemode on ignored or " "recovered hardware error\n"); ipath_clear_freeze(dd); } } *msg = '\0'; /* * may someday want to decode into which bits are which * functional area for parity errors, etc. */ if (hwerrs & (infinipath_hwe_htcmemparityerr_mask << INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT)) { bits = (u32) ((hwerrs >> INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) & INFINIPATH_HWE_HTCMEMPARITYERR_MASK); snprintf(bitsmsg, sizeof bitsmsg, "[HTC Parity Errs %x] ", bits); strlcat(msg, bitsmsg, msgl); } ipath_format_hwerrors(hwerrs, ipath_6110_hwerror_msgs, sizeof(ipath_6110_hwerror_msgs) / sizeof(ipath_6110_hwerror_msgs[0]), msg, msgl); if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS)) hwerr_crcbits(dd, hwerrs, msg, msgl); 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_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED; ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask, dd->ipath_hwerrmask); }#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \ INFINIPATH_HWE_COREPLL_RFSLIP | \ INFINIPATH_HWE_HTBPLL_FBSLIP | \ INFINIPATH_HWE_HTBPLL_RFSLIP | \ INFINIPATH_HWE_HTAPLL_FBSLIP | \ INFINIPATH_HWE_HTAPLL_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 (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_ht_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; } *dd->ipath_statusp &= ~IPATH_STATUS_IB_READY; /* mark as having had error */ *dd->ipath_statusp |= IPATH_STATUS_HWERROR; /* * mark as not usable, at a minimum until driver * is reloaded, probably until reboot, since no * other reset is possible. */ dd->ipath_flags &= ~IPATH_INITTED; } else *msg = 0; /* recovered from all of them */ if (*msg) ipath_dev_err(dd, "%s hardware error\n", msg); if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) /* * for status file; if no trailing brace is copied, * we'll know it was truncated. */ snprintf(dd->ipath_freezemsg, dd->ipath_freezelen, "{%s}", msg);bail:;}/** * ipath_ht_boardname - fill in the board name * @dd: the infinipath device * @name: the output buffer * @namelen: the size of the output buffer * * fill in the board name, based on the board revision register */static int ipath_ht_boardname(struct ipath_devdata *dd, char *name, size_t namelen){ char *n = NULL; u8 boardrev = dd->ipath_boardrev; int ret = 0; switch (boardrev) { case 5: /* * original production board; two production levels, with * different serial number ranges. See ipath_ht_early_init() for * case where we enable IPATH_GPIO_INTR for later serial # range. * Original 112* serial number is no longer supported. */ n = "InfiniPath_QHT7040"; break; case 7: /* small form factor production board */ n = "InfiniPath_QHT7140"; break; default: /* don't know, just print the number */ ipath_dev_err(dd, "Don't yet know about board " "with ID %u\n", boardrev); snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u", boardrev); ret = 1; break; } if (n) snprintf(name, namelen, "%s", n); if (ret) { ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name); goto bail; } if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 4)) { /* * This version of the driver only supports Rev 3.2 - 3.4 */ ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n", dd->ipath_majrev, dd->ipath_minrev); ret = 1; goto bail; } /* * pkt/word counters are 32 bit, and therefore wrap fast enough * that we snapshot them from a timer, and maintain 64 bit shadow * copies */ dd->ipath_flags |= IPATH_32BITCOUNTERS; dd->ipath_flags |= IPATH_GPIO_INTR; if (dd->ipath_htspeed != 800) ipath_dev_err(dd, "Incorrectly configured for HT @ %uMHz\n", dd->ipath_htspeed); ret = 0;bail: return ret;}static void ipath_check_htlink(struct ipath_devdata *dd){ u8 linkerr, link_off, i; for (i = 0; i < 2; i++) { link_off = dd->ipath_ht_slave_off + i * 4 + 0xd; if (pci_read_config_byte(dd->pcidev, link_off, &linkerr)) dev_info(&dd->pcidev->dev, "Couldn't read " "linkerror%d of HT slave/primary block\n", i); else if (linkerr & 0xf0) { ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, " "clearing\n", linkerr >> 4, i); /* * writing the linkerr bits that are set should * clear them */ if (pci_write_config_byte(dd->pcidev, link_off, linkerr)) ipath_dbg("Failed write to clear HT " "linkerror%d\n", i); if (pci_read_config_byte(dd->pcidev, link_off, &linkerr)) dev_info(&dd->pcidev->dev, "Couldn't reread linkerror%d of " "HT slave/primary block\n", i); else if (linkerr & 0xf0) dev_info(&dd->pcidev->dev, "HT linkerror%d bits 0x%x " "couldn't be cleared\n", i, linkerr >> 4); } }}static int ipath_setup_ht_reset(struct ipath_devdata *dd){ ipath_dbg("No reset possible for this InfiniPath hardware\n"); return 0;}#define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */#define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses *//* * Bits 13-15 of command==0 is slave/primary block. Clear any HT CRC * errors. We only bother to do this at load time, because it's OK if * it happened before we were loaded (first time after boot/reset), * but any time after that, it's fatal anyway. Also need to not check * for for upper byte errors if we are in 8 bit mode, so figure out * our width. For now, at least, also complain if it's 8 bit. */static void slave_or_pri_blk(struct ipath_devdata *dd, struct pci_dev *pdev, int pos, u8 cap_type){ u8 linkwidth = 0, linkerr, link_a_b_off, link_off; u16 linkctrl = 0; int i; dd->ipath_ht_slave_off = pos; /* command word, master_host bit */ /* master host || slave */ if ((cap_type >> 2) & 1) link_a_b_off = 4; else link_a_b_off = 0; ipath_cdbg(VERBOSE, "HT%u (Link %c) connected to processor\n", link_a_b_off ? 1 : 0, link_a_b_off ? 'B' : 'A'); link_a_b_off += pos; /* * check both link control registers; clear both HT CRC sets if * necessary. */ for (i = 0; i < 2; i++) { link_off = pos + i * 4 + 0x4; if (pci_read_config_word(pdev, link_off, &linkctrl)) ipath_dev_err(dd, "Couldn't read HT link control%d " "register\n", i); else if (linkctrl & (0xf << 8)) { ipath_cdbg(VERBOSE, "Clear linkctrl%d CRC Error " "bits %x\n", i, linkctrl & (0xf << 8)); /* * now write them back to clear the error. */ pci_write_config_byte(pdev, link_off, linkctrl & (0xf << 8)); } } /* * As with HT CRC bits, same for protocol errors that might occur * during boot. */ for (i = 0; i < 2; i++) { link_off = pos + i * 4 + 0xd; if (pci_read_config_byte(pdev, link_off, &linkerr)) dev_info(&pdev->dev, "Couldn't read linkerror%d " "of HT slave/primary block\n", i); else if (linkerr & 0xf0) { ipath_cdbg(VERBOSE, "HT linkerr%d bits 0x%x set, " "clearing\n", linkerr >> 4, i); /* * writing the linkerr bits that are set will clear * them */ if (pci_write_config_byte (pdev, link_off, linkerr)) ipath_dbg("Failed write to clear HT " "linkerror%d\n", i); if (pci_read_config_byte(pdev, link_off, &linkerr)) dev_info(&pdev->dev, "Couldn't reread " "linkerror%d of HT slave/primary " "block\n", i); else if (linkerr & 0xf0) dev_info(&pdev->dev, "HT linkerror%d bits " "0x%x couldn't be cleared\n", i, linkerr >> 4); } } /* * this is just for our link to the host, not devices connected * through tunnel. */ if (pci_read_config_byte(pdev, link_a_b_off + 7, &linkwidth)) ipath_dev_err(dd, "Couldn't read HT link width " "config register\n"); else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -