ipath_ht400.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 1,604 行 · 第 1/4 页

C
1,604
字号
 */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];	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;	/*	 * 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) ||	    (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 & ~infinipath_hwe_bitsextant)		ipath_dev_err(dd, "hwerror interrupt with unknown errors "			      "%llx set\n", (unsigned long long)			      (hwerrs & ~infinipath_hwe_bitsextant));	ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);	if (ctrl & INFINIPATH_C_FREEZEMODE) {		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.			 */			if (dd->ipath_flags & IPATH_INITTED) {				ipath_dev_err(dd, "Fatal Error (freeze "					      "mode), no longer usable\n");				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 {			ipath_dbg("Clearing freezemode on ignored hardware "				  "error\n");			ctrl &= ~INFINIPATH_C_FREEZEMODE;			ipath_write_kreg(dd, dd->ipath_kregs->kr_control,					 ctrl);		}	}	*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);	}	if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK		      << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {		bits = (u32) ((hwerrs >>			       INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &			      INFINIPATH_HWE_RXEMEMPARITYERR_MASK);		snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",			 bits);		strlcat(msg, bitsmsg, msgl);	}	if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK		      << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {		bits = (u32) ((hwerrs >>			       INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &			      INFINIPATH_HWE_TXEMEMPARITYERR_MASK);		snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",			 bits);		strlcat(msg, bitsmsg, msgl);	}	if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)		strlcat(msg, "[IB2IPATH Parity]", msgl);	if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)		strlcat(msg, "[IPATH2IB Parity]", msgl);	if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR)		strlcat(msg, "[HTC Ireq Parity]", msgl);	if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR)		strlcat(msg, "[HTC Treq Parity]", msgl);	if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR)		strlcat(msg, "[HTC Tresp Parity]", msgl);	if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))		hwerr_crcbits(dd, hwerrs, msg, msgl);	if (hwerrs & INFINIPATH_HWE_HTCMISCERR5)		strlcat(msg, "[HT core Misc5]", msgl);	if (hwerrs & INFINIPATH_HWE_HTCMISCERR6)		strlcat(msg, "[HT core Misc6]", msgl);	if (hwerrs & INFINIPATH_HWE_HTCMISCERR7)		strlcat(msg, "[HT core Misc7]", msgl);	if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {		strlcat(msg, "[Memory BIST test failed, HT-400 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), HT-400 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 & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)		strlcat(msg, "[Rx Dsync]", msgl);	if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)		strlcat(msg, "[SerDes PLL]", msgl);	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;	switch (boardrev) {	case 4:		/* Ponderosa is one of the bringup boards */		n = "Ponderosa";		break;	case 5:		/*		 * HT-460 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.		 */		n = "InfiniPath_HT-460";		break;	case 6:		n = "OEM_Board_3";		break;	case 7:		/* HT-460 small form factor production board */		n = "InfiniPath_HT-465";		break;	case 8:		n = "LS/X-1";		break;	case 9:		/* Comstock bringup test board */		n = "Comstock";		break;	case 10:		n = "OEM_Board_2";		break;	case 11:		n = "InfiniPath_HT-470";		break;	case 12:		n = "OEM_Board_4";		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_HT-4xx_%u",			 boardrev);		break;	}	if (n)		snprintf(name, namelen, "%s", n);	if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {		/*		 * This version of the driver only supports the HT-400		 * Rev 3.2		 */		ipath_dev_err(dd,			      "Unsupported HT-400 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;	if (dd->ipath_htspeed != 800)		ipath_dev_err(dd,			      "Incorrectly configured for HT @ %uMHz\n",			      dd->ipath_htspeed);	if (dd->ipath_boardrev == 7 || dd->ipath_boardrev == 11 ||	    dd->ipath_boardrev == 6)		dd->ipath_flags |= IPATH_GPIO_INTR;	else		dd->ipath_flags |= IPATH_POLL_RX_INTR;	if (dd->ipath_boardrev == 8) {	/* LS/X-1 */		u64 val;		val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);		if (val & INFINIPATH_EXTS_SERDESSEL) {			/*			 * hardware disabled			 *			 * This means that the chip is hardware disabled,			 * and will not be able to bring up the link,			 * in any case.  We special case this and abort			 * early, to avoid later messages.  We also set			 * the DISABLED status bit			 */			ipath_dbg("Unit %u is hardware-disabled\n",				  dd->ipath_unit);			*dd->ipath_statusp |= IPATH_STATUS_DISABLED;			/* this value is handled differently */			ret = 2;			goto bail;		}	}	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 HT-400\n");	return 0;}#define HT_CAPABILITY_ID   0x08	/* HT capabilities not defined in kernel */#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))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?