ipath_pe800.c

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

C
1,254
字号
			       INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) &			      INFINIPATH_HWE_PCIEMEMPARITYERR_MASK);		snprintf(bitsmsg, sizeof bitsmsg,			 "[PCIe Mem 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);#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP |	\			 INFINIPATH_HWE_COREPLL_RFSLIP )	if (hwerrs & _IPATH_PLL_FAIL) {		snprintf(bitsmsg, sizeof bitsmsg,			 "[PLL failed (%llx), PE-800 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_PCIEPOISONEDTLP)		strlcat(msg, "[PCIe Poisoned TLP]", msgl);	if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT)		strlcat(msg, "[PCIe completion timeout]", msgl);	/*	 * In practice, it's unlikely wthat we'll see PCIe PLL, or bus	 * parity or memory parity error failures, because most likely we	 * won't be able to talk to the core of the chip.  Nonetheless, we	 * might see them, if they are in parts of the PCIe core that aren't	 * essential.	 */	if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED)		strlcat(msg, "[PCIePLL1]", msgl);	if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED)		strlcat(msg, "[PCIePLL0]", msgl);	if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH)		strlcat(msg, "[PCIe XTLH core parity]", msgl);	if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM)		strlcat(msg, "[PCIe ADM TX core parity]", msgl);	if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM)		strlcat(msg, "[PCIe ADM RX core parity]", msgl);	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 /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_PE-800-Bringup";		break;	case 2:		n = "InfiniPath_PE-880";		break;	case 3:		n = "InfiniPath_PE-850";		break;	case 4:		n = "InfiniPath_PE-860";		break;	default:		ipath_dev_err(dd,			      "Don't yet know about board with ID %u\n",			      boardrev);		snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u",			 boardrev);		break;	}	if (n)		snprintf(name, namelen, "%s", n);	if (dd->ipath_majrev != 4 || dd->ipath_minrev != 1) {		ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n",			      dd->ipath_majrev, dd->ipath_minrev);		ret = 1;	} else		ret = 0;	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");	val = ~0ULL;	/* barring bugs, all hwerrors become interrupts, */	if (!dd->ipath_boardrev)	// no PLL for Emulator		val &= ~INFINIPATH_HWE_SERDESPLLFAILED;	/* workaround bug 9460 in internal interface bus parity checking */	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, tmp, config1;	int ret = 0, change = 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 */	tmp = 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 */	tmp = 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);	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;		change = 1;	}	if (val & INFINIPATH_XGXS_RESET) {		val &= ~INFINIPATH_XGXS_RESET;		change = 1;	}	if (change)		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))			ipath_dbg("Never got MDIO data for XGXS "				  "status read\n");		else			ipath_cdbg(VERBOSE, "MDIO Read reg8, "				   "'bank' 31 %x\n", (u32) val);	} else		ipath_dbg("Never got MDIO cmdready for XGXS status read\n");	return ret;}/** * ipath_pe_quiet_serdes - set serdes to txidle * @dd: the infinipath device * Called when driver is being unloaded */static void ipath_pe_quiet_serdes(struct ipath_devdata *dd){	u64 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);	val |= INFINIPATH_SERDC0_TXIDLE;	ipath_dbg("Setting TxIdleEn on serdes (config0 = %llx)\n",		  (unsigned long long) val);	ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);}/* this is not yet needed on the PE800, so just return 0. */static int ipath_pe_intconfig(struct ipath_devdata *dd){	return 0;}/** * ipath_setup_pe_setextled - set the state of the two external LEDs * @dd: the infinipath device * @lst: the L state * @ltst: the LT state * These LEDs indicate the physical and logical state of IB link. * For this chip (at least with recommended board pinouts), LED1 * is Yellow (logical state) and LED2 is Green (physical state), * * Note:  We try to match the Mellanox HCA LED behavior as best * we can.  Green indicates physical link state is OK (something is * plugged in, and we can train). * Amber indicates the link is logically up (ACTIVE). * Mellanox further blinks the amber LED to indicate data packet * activity, but we have no hardware support for that, so it would * require waking up every 10-20 msecs and checking the counters * on the chip, and then turning the LED off if appropriate.  That's * visible overhead, so not something we will do. * */static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,				     u64 ltst){	u64 extctl;	/* the diags use the LED to indicate diag info, so we leave	 * the external LED alone when the diags are running */	if (ipath_diag_inuse)		return;	extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |				       INFINIPATH_EXTC_LED2PRIPORT_ON);	if (ltst & INFINIPATH_IBCS_LT_STATE_LINKUP)		extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;	if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)		extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;	dd->ipath_extctrl = extctl;	ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);}/** * ipath_setup_pe_cleanup - clean up any per-chip chip-specific stuff * @dd: the infinipath device * * This is called during driver unload. * We do the pci_disable_msi here, not in generic code, because it * isn't used for the HT-400. If we do end up needing pci_enable_msi * at some point in the future for HT-400, we'll move the call back * into the main init_one code. */static void ipath_setup_pe_cleanup(struct ipath_devdata *dd){	dd->ipath_msi_lo = 0;	/* just in case unload fails */	pci_disable_msi(dd->pcidev);}/** * ipath_setup_pe_config - setup PCIe config related stuff * @dd: the infinipath device * @pdev: the PCI device * * The pci_enable_msi() call will fail on systems with MSI quirks * such as those with AMD8131, even if the device of interest is not * attached to that device, (in the 2.6.13 - 2.6.15 kernels, at least, fixed * late in 2.6.16). * All that can be done is to edit the kernel source to remove the quirk * check until that is fixed. * We do not need to call enable_msi() for our HyperTransport chip (HT-400), * even those it uses MSI, and we want to avoid the quirk warning, so * So we call enable_msi only for the PE-800.  If we do end up needing * pci_enable_msi at some point in the future for HT-400, we'll move the * call back into the main init_one code. * We save the msi lo and hi values, so we can restore them after * chip reset (the kernel PCI infrastructure doesn't yet handle that * correctly). */static int ipath_setup_pe_config(struct ipath_devdata *dd,				 struct pci_dev *pdev){	int pos, ret;	dd->ipath_msi_lo = 0;	/* used as a flag during reset processing */	ret = pci_enable_msi(dd->pcidev);	if (ret)		ipath_dev_err(dd, "pci_enable_msi failed: %d, "			      "interrupts may not work\n", ret);	/* continue even if it fails, we may still be OK... */	if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {		u16 control;		pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,				      &dd->ipath_msi_lo);		pci_read_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,				      &dd->ipath_msi_hi);		pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,				     &control);		/* now save the data (vector) info */		pci_read_config_word(dd->pcidev,				     pos + ((control & PCI_MSI_FLAGS_64BIT)					    ? 12 : 8),				     &dd->ipath_msi_data);		ipath_cdbg(VERBOSE, "Read msi data 0x%x from config offset "			   "0x%x, control=0x%x\n", dd->ipath_msi_data,			   pos + ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),			   control);		/* we save the cachelinesize also, although it doesn't		 * really matter */		pci_read_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,				     &dd->ipath_pci_cacheline);	} else		ipath_dev_err(dd, "Can't find MSI capability, "			      "can't save MSI settings for reset\n");	if ((pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_EXP))) {		u16 linkstat;		pci_read_config_word(dd->pcidev, pos + PCI_EXP_LNKSTA,				     &linkstat);		linkstat >>= 4;		linkstat &= 0x1f;		if (linkstat != 8)			ipath_dev_err(dd, "PCIe width %u, "				      "performance reduced\n", linkstat);	}

⌨️ 快捷键说明

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