ipath_ht400.c

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

C
1,604
字号
			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 {		u32 width;		switch (linkwidth & 7) {		case 5:			width = 4;			break;		case 4:			width = 2;			break;		case 3:			width = 32;			break;		case 1:			width = 16;			break;		case 0:		default:	/* if wrong, assume 8 bit */			width = 8;			break;		}		dd->ipath_htwidth = width;		if (linkwidth != 0x11) {			ipath_dev_err(dd, "Not configured for 16 bit HT "				      "(%x)\n", linkwidth);			if (!(linkwidth & 0xf)) {				ipath_dbg("Will ignore HT lane1 errors\n");				dd->ipath_flags |= IPATH_8BIT_IN_HT0;			}		}	}	/*	 * this is just for our link to the host, not devices connected	 * through tunnel.	 */	if (pci_read_config_byte(pdev, link_a_b_off + 0xd, &linkwidth))		ipath_dev_err(dd, "Couldn't read HT link frequency "			      "config register\n");	else {		u32 speed;		switch (linkwidth & 0xf) {		case 6:			speed = 1000;			break;		case 5:			speed = 800;			break;		case 4:			speed = 600;			break;		case 3:			speed = 500;			break;		case 2:			speed = 400;			break;		case 1:			speed = 300;			break;		default:			/*			 * assume reserved and vendor-specific are 200...			 */		case 0:			speed = 200;			break;		}		dd->ipath_htspeed = speed;	}}static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,			    int pos){	u32 int_handler_addr_lower;	u32 int_handler_addr_upper;	u64 ihandler;	u32 intvec;	/* use indirection register to get the intr handler */	pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10);	pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower);	pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11);	pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper);	ihandler = (u64) int_handler_addr_lower |		((u64) int_handler_addr_upper << 32);	/*	 * kernels with CONFIG_PCI_MSI set the vector in the irq field of	 * struct pci_device, so we use that to program the HT-400 internal	 * interrupt register (not config space) with that value. The BIOS	 * must still have done the basic MSI setup.	 */	intvec = pdev->irq;	/*	 * clear any vector bits there; normally not set but we'll overload	 * this for some debug purposes (setting the HTC debug register	 * value from software, rather than GPIOs), so it might be set on a	 * driver reload.	 */	ihandler &= ~0xff0000;	/* x86 vector goes in intrinfo[23:16] */	ihandler |= intvec << 16;	ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, "		   "interruptconfig %llx\n", int_handler_addr_lower,		   int_handler_addr_upper, intvec,		   (unsigned long long) ihandler);	/* can't program yet, so save for interrupt setup */	dd->ipath_intconfig = ihandler;	/* keep going, so we find link control stuff also */	return ihandler != 0;}/** * ipath_setup_ht_config - setup the interruptconfig register * @dd: the infinipath device * @pdev: the PCI device * * setup the interruptconfig register from the HT config info. * Also clear CRC errors in HT linkcontrol, if necessary. * This is done only for the real hardware.  It is done before * chip address space is initted, so can't touch infinipath registers */static int ipath_setup_ht_config(struct ipath_devdata *dd,				 struct pci_dev *pdev){	int pos, ret = 0;	int ihandler = 0;	/*	 * Read the capability info to find the interrupt info, and also	 * handle clearing CRC errors in linkctrl register if necessary.  We	 * do this early, before we ever enable errors or hardware errors,	 * mostly to avoid causing the chip to enter freeze mode.	 */	pos = pci_find_capability(pdev, HT_CAPABILITY_ID);	if (!pos) {		ipath_dev_err(dd, "Couldn't find HyperTransport "			      "capability; no interrupts\n");		ret = -ENODEV;		goto bail;	}	do {		u8 cap_type;		/* the HT capability type byte is 3 bytes after the		 * capability byte.		 */		if (pci_read_config_byte(pdev, pos + 3, &cap_type)) {			dev_info(&pdev->dev, "Couldn't read config "				 "command @ %d\n", pos);			continue;		}		if (!(cap_type & 0xE0))			slave_or_pri_blk(dd, pdev, pos, cap_type);		else if (cap_type == HT_INTR_DISC_CONFIG)			ihandler = set_int_handler(dd, pdev, pos);	} while ((pos = pci_find_next_capability(pdev, pos,						 HT_CAPABILITY_ID)));	if (!ihandler) {		ipath_dev_err(dd, "Couldn't find interrupt handler in "			      "config space\n");		ret = -ENODEV;	}bail:	return ret;}/** * ipath_setup_ht_cleanup - clean up any per-chip chip-specific stuff * @dd: the infinipath device * * Called during driver unload. * This is currently a nop for the HT-400, not for all chips */static void ipath_setup_ht_cleanup(struct ipath_devdata *dd){}/** * ipath_setup_ht_setextled - set the state of the two external LEDs * @dd: the infinipath device * @lst: the L state * @ltst: the LT state * * Set the state of the two external LEDs, to indicate physical and * logical state of IB link.   For this chip (at least with recommended * board pinouts), LED1 is Green (physical state), and LED2 is Yellow * (logical 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_ht_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;	/*	 * start by setting both LED control bits to off, then turn	 * on the appropriate bit(s).	 */	if (dd->ipath_boardrev == 8) { /* LS/X-1 uses different pins */		/*		 * major difference is that INFINIPATH_EXTC_LEDGBLERR_OFF		 * is inverted,  because it is normally used to indicate		 * a hardware fault at reset, if there were errors		 */		extctl = (dd->ipath_extctrl & ~INFINIPATH_EXTC_LEDGBLOK_ON)			| INFINIPATH_EXTC_LEDGBLERR_OFF;		if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)			extctl &= ~INFINIPATH_EXTC_LEDGBLERR_OFF;		if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)			extctl |= INFINIPATH_EXTC_LEDGBLOK_ON;	}	else {		extctl = dd->ipath_extctrl &			~(INFINIPATH_EXTC_LED1PRIPORT_ON |			  INFINIPATH_EXTC_LED2PRIPORT_ON);		if (ltst == INFINIPATH_IBCS_LT_STATE_LINKUP)			extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;		if (lst == INFINIPATH_IBCS_L_STATE_ACTIVE)			extctl |= INFINIPATH_EXTC_LED2PRIPORT_ON;	}	dd->ipath_extctrl = extctl;	ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);}static void ipath_init_ht_variables(void){	ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;	ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;	ipath_gpio_sda = IPATH_GPIO_SDA;	ipath_gpio_scl = IPATH_GPIO_SCL;	infinipath_i_bitsextant =		(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |		(INFINIPATH_I_RCVAVAIL_MASK <<		 INFINIPATH_I_RCVAVAIL_SHIFT) |		INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |		INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;	infinipath_e_bitsextant =		INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |		INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |		INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |		INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RUNEXPCHAR |		INFINIPATH_E_RUNSUPVL | INFINIPATH_E_REBP |		INFINIPATH_E_RIBFLOW | INFINIPATH_E_RBADVERSION |		INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |		INFINIPATH_E_RBADTID | INFINIPATH_E_RHDRLEN |		INFINIPATH_E_RHDR | INFINIPATH_E_RIBLOSTLINK |		INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SMAXPKTLEN |		INFINIPATH_E_SUNDERRUN | INFINIPATH_E_SPKTLEN |		INFINIPATH_E_SDROPPEDSMPPKT | INFINIPATH_E_SDROPPEDDATAPKT |		INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM |		INFINIPATH_E_SUNSUPVL | INFINIPATH_E_IBSTATUSCHANGED |		INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |		INFINIPATH_E_HARDWARE;	infinipath_hwe_bitsextant =		(INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<		 INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |		(INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<		 INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |		(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<		 INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |		INFINIPATH_HWE_HTCLNKABYTE0CRCERR |		INFINIPATH_HWE_HTCLNKABYTE1CRCERR |		INFINIPATH_HWE_HTCLNKBBYTE0CRCERR |		INFINIPATH_HWE_HTCLNKBBYTE1CRCERR |		INFINIPATH_HWE_HTCMISCERR4 |		INFINIPATH_HWE_HTCMISCERR5 | INFINIPATH_HWE_HTCMISCERR6 |		INFINIPATH_HWE_HTCMISCERR7 |		INFINIPATH_HWE_HTCBUSTREQPARITYERR |		INFINIPATH_HWE_HTCBUSTRESPPARITYERR |		INFINIPATH_HWE_HTCBUSIREQPARITYERR |		INFINIPATH_HWE_RXDSYNCMEMPARITYERR |		INFINIPATH_HWE_MEMBISTFAILED |		INFINIPATH_HWE_COREPLL_FBSLIP |		INFINIPATH_HWE_COREPLL_RFSLIP |		INFINIPATH_HWE_HTBPLL_FBSLIP |		INFINIPATH_HWE_HTBPLL_RFSLIP |		INFINIPATH_HWE_HTAPLL_FBSLIP |		INFINIPATH_HWE_HTAPLL_RFSLIP |		INFINIPATH_HWE_SERDESPLLFAILED |		INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |		INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;	infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;	infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;}/** * ipath_ht_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_ht_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");	ipath_check_htlink(dd);	/* barring bugs, all hwerrors become interrupts, which can */	val = -1LL;	/* don't look at crc lane1 if 8 bit */	if (dd->ipath_flags & IPATH_8BIT_IN_HT0)		val &= ~infinipath_hwe_htclnkabyte1crcerr;	/* don't look at crc lane1 if 8 bit */	if (dd->ipath_flags & IPATH_8BIT_IN_HT1)		val &= ~infinipath_hwe_htclnkbbyte1crcerr;	/*	 * disable RXDSYNCMEMPARITY because external serdes is unused,	 * and therefore the logic will never be used or initialized,	 * and uninitialized state will normally result in this error	 * being asserted.  Similarly for the external serdess pll	 * lock signal.	 */	val &= ~(INFINIPATH_HWE_SERDESPLLFAILED |		 INFINIPATH_HWE_RXDSYNCMEMPARITYERR);	/*	 * Disable MISCERR4 because of an inversion in the HT core	 * logic checking for errors that cause this bit to be set.	 * The errata can also cause the protocol error bit to be set	 * in the HT config space linkerror register(s).	 */	val &= ~INFINIPATH_HWE_HTCMISCERR4;	/*	 * PLL ignored because MDIO interface has a logic problem	 * for reads, on Comstock and Ponderosa.  BRINGUP	 */	if (dd->ipath_boardrev == 4 || dd->ipath_boardrev == 9)		val &= ~INFINIPATH_HWE_SERDESPLLFAILED;	dd->ipath_hwerrmask = val;

⌨️ 快捷键说明

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