⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipath_iba6110.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	config1 = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig1);	ipath_cdbg(VERBOSE, "Initial serdes status is 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));	/* force reset on */	val |= INFINIPATH_SERDC0_RESET_PLL		/* | INFINIPATH_SERDC0_RESET_MASK */		;	ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);	udelay(15);		/* need pll reset set at least for a bit */	if (val & INFINIPATH_SERDC0_RESET_PLL) {		u64 val2 = val &= ~INFINIPATH_SERDC0_RESET_PLL;		/* set lane resets, and tx idle, during pll reset */		val2 |= INFINIPATH_SERDC0_RESET_MASK |			INFINIPATH_SERDC0_TXIDLE;		ipath_cdbg(VERBOSE, "Clearing serdes PLL reset (writing "			   "%llx)\n", (unsigned long long) val2);		ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,				 val2);		/*		 * be sure chip saw it		 */		val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);		/*		 * need pll reset clear at least 11 usec before lane		 * resets cleared; give it a few more		 */		udelay(15);		val = val2;	/* for check below */	}	if (val & (INFINIPATH_SERDC0_RESET_PLL |		   INFINIPATH_SERDC0_RESET_MASK |		   INFINIPATH_SERDC0_TXIDLE)) {		val &= ~(INFINIPATH_SERDC0_RESET_PLL |			 INFINIPATH_SERDC0_RESET_MASK |			 INFINIPATH_SERDC0_TXIDLE);		/* clear them */		ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0,				 val);	}	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);		/*		 * we use address 3		 */		val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;		change = 1;	}	if (val & INFINIPATH_XGXS_RESET) {		/* normally true after boot */		val &= ~INFINIPATH_XGXS_RESET;		change = 1;	}	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;		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, "After setup: serdes status is 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;		/* for now, say we always succeeded */}/** * ipath_ht_quiet_serdes - set serdes to txidle * @dd: the infinipath device * driver is being unloaded */static void ipath_ht_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);}/** * ipath_pe_put_tid - write a TID in chip * @dd: the infinipath device * @tidptr: pointer to the expected TID (in chip) to udpate * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing * * This exists as a separate routine to allow for special locking etc. * It's used for both the full cleanup on exit, as well as the normal * setup and teardown. */static void ipath_ht_put_tid(struct ipath_devdata *dd,			     u64 __iomem *tidptr, u32 type,			     unsigned long pa){	if (!dd->ipath_kregbase)		return;	if (pa != dd->ipath_tidinvalid) {		if (unlikely((pa & ~INFINIPATH_RT_ADDR_MASK))) {			dev_info(&dd->pcidev->dev,				 "physaddr %lx has more than "				 "40 bits, using only 40!!!\n", pa);			pa &= INFINIPATH_RT_ADDR_MASK;		}		if (type == RCVHQ_RCV_TYPE_EAGER)			pa |= dd->ipath_tidtemplate;		else {			/* in words (fixed, full page).  */			u64 lenvalid = PAGE_SIZE >> 2;			lenvalid <<= INFINIPATH_RT_BUFSIZE_SHIFT;			pa |= lenvalid | INFINIPATH_RT_VALID;		}	}	writeq(pa, tidptr);}/** * ipath_ht_clear_tid - clear all TID entries for a port, expected and eager * @dd: the infinipath device * @port: the port * * Used from ipath_close(), and at chip initialization. */static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port){	u64 __iomem *tidbase;	int i;	if (!dd->ipath_kregbase)		return;	ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);	/*	 * need to invalidate all of the expected TID entries for this	 * port, so we don't have valid entries that might somehow get	 * used (early in next use of this port, or through some bug)	 */	tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +				   dd->ipath_rcvtidbase +				   port * dd->ipath_rcvtidcnt *				   sizeof(*tidbase));	for (i = 0; i < dd->ipath_rcvtidcnt; i++)		ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,				 dd->ipath_tidinvalid);	tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +				   dd->ipath_rcvegrbase +				   port * dd->ipath_rcvegrcnt *				   sizeof(*tidbase));	for (i = 0; i < dd->ipath_rcvegrcnt; i++)		ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,				 dd->ipath_tidinvalid);}/** * ipath_ht_tidtemplate - setup constants for TID updates * @dd: the infinipath device * * We setup stuff that we use a lot, to avoid calculating each time */static void ipath_ht_tidtemplate(struct ipath_devdata *dd){	dd->ipath_tidtemplate = dd->ipath_ibmaxlen >> 2;	dd->ipath_tidtemplate <<= INFINIPATH_RT_BUFSIZE_SHIFT;	dd->ipath_tidtemplate |= INFINIPATH_RT_VALID;	/*	 * work around chip errata bug 7358, by marking invalid tids	 * as having max length	 */	dd->ipath_tidinvalid = (-1LL & INFINIPATH_RT_BUFSIZE_MASK) <<		INFINIPATH_RT_BUFSIZE_SHIFT;}static int ipath_ht_early_init(struct ipath_devdata *dd){	u32 __iomem *piobuf;	u32 pioincr, val32;	int i;	/*	 * one cache line; long IB headers will spill over into received	 * buffer	 */	dd->ipath_rcvhdrentsize = 16;	dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;	/*	 * For HT, we allocate a somewhat overly large eager buffer,	 * such that we can guarantee that we can receive the largest	 * packet that we can send out.  To truly support a 4KB MTU,	 * we need to bump this to a large value.  To date, other than	 * testing, we have never encountered an HCA that can really	 * send 4KB MTU packets, so we do not handle that (we'll get	 * errors interrupts if we ever see one).	 */	dd->ipath_rcvegrbufsize = dd->ipath_piosize2k;	/*	 * the min() check here is currently a nop, but it may not	 * always be, depending on just how we do ipath_rcvegrbufsize	 */	dd->ipath_ibmaxlen = min(dd->ipath_piosize2k,				 dd->ipath_rcvegrbufsize);	dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;	ipath_ht_tidtemplate(dd);	/*	 * zero all the TID entries at startup.  We do this for sanity,	 * in case of a previous driver crash of some kind, and also	 * because the chip powers up with these memories in an unknown	 * state.  Use portcnt, not cfgports, since this is for the	 * full chip, not for current (possibly different) configuration	 * value.	 * Chip Errata bug 6447	 */	for (val32 = 0; val32 < dd->ipath_portcnt; val32++)		ipath_ht_clear_tids(dd, val32);	/*	 * write the pbc of each buffer, to be sure it's initialized, then	 * cancel all the buffers, and also abort any packets that might	 * have been in flight for some reason (the latter is for driver	 * unload/reload, but isn't a bad idea at first init).	PIO send	 * isn't enabled at this point, so there is no danger of sending	 * these out on the wire.	 * Chip Errata bug 6610	 */	piobuf = (u32 __iomem *) (((char __iomem *)(dd->ipath_kregbase)) +				  dd->ipath_piobufbase);	pioincr = dd->ipath_palign / sizeof(*piobuf);	for (i = 0; i < dd->ipath_piobcnt2k; i++) {		/*		 * reasonable word count, just to init pbc		 */		writel(16, piobuf);		piobuf += pioincr;	}	ipath_get_eeprom_info(dd);	if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&		dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {		/*		 * Later production QHT7040 has same changes as QHT7140, so		 * can use GPIO interrupts.  They have serial #'s starting		 * with 128, rather than 112.		 */		if (dd->ipath_serial[0] == '1' &&		    dd->ipath_serial[1] == '2' &&		    dd->ipath_serial[2] == '8')			dd->ipath_flags |= IPATH_GPIO_INTR;		else {			ipath_dev_err(dd, "Unsupported InfiniPath board "				"(serial number %.16s)!\n",				dd->ipath_serial);			return 1;		}	}	if (dd->ipath_minrev >= 4) {		/* Rev4+ reports extra errors via internal GPIO pins */		dd->ipath_flags |= IPATH_GPIO_ERRINTRS;		dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK;		ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,				 dd->ipath_gpio_mask);	}	return 0;}static int ipath_ht_txe_recover(struct ipath_devdata *dd){	int cnt = ++ipath_stats.sps_txeparity;	if (cnt >= IPATH_MAX_PARITY_ATTEMPTS)  {		if (cnt == IPATH_MAX_PARITY_ATTEMPTS)			ipath_dev_err(dd,				"Too many attempts to recover from "				"TXE parity, giving up\n");		return 0;	}	dev_info(&dd->pcidev->dev,		"Recovering from TXE PIO parity error\n");	return 1;}/** * ipath_init_ht_get_base_info - set chip-specific flags for user code * @dd: the infinipath device * @kbase: ipath_base_info pointer * * We set the PCIE flag because the lower bandwidth on PCIe vs * HyperTransport can affect some user packet algorithms. */static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase){	struct ipath_base_info *kinfo = kbase;	kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |		IPATH_RUNTIME_PIO_REGSWAPPED;	if (pd->port_dd->ipath_minrev < 4)		kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY;	return 0;}static void ipath_ht_free_irq(struct ipath_devdata *dd){	free_irq(dd->ipath_irq, dd);	ht_destroy_irq(dd->ipath_irq);	dd->ipath_irq = 0;	dd->ipath_intconfig = 0;}/** * ipath_init_iba6110_funcs - set up the chip-specific function pointers * @dd: the infinipath device * * This is global, and is called directly at init to set up the * chip-specific function pointers for later use. */void ipath_init_iba6110_funcs(struct ipath_devdata *dd){	dd->ipath_f_intrsetup = ipath_ht_intconfig;	dd->ipath_f_bus = ipath_setup_ht_config;	dd->ipath_f_reset = ipath_setup_ht_reset;	dd->ipath_f_get_boardname = ipath_ht_boardname;	dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors;	dd->ipath_f_early_init = ipath_ht_early_init;	dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors;	dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes;	dd->ipath_f_bringup_serdes = ipath_ht_bringup_serdes;	dd->ipath_f_clear_tids = ipath_ht_clear_tids;	dd->ipath_f_put_tid = ipath_ht_put_tid;	dd->ipath_f_cleanup = ipath_setup_ht_cleanup;	dd->ipath_f_setextled = ipath_setup_ht_setextled;	dd->ipath_f_get_base_info = ipath_ht_get_base_info;	dd->ipath_f_free_irq = ipath_ht_free_irq;	/*	 * initialize chip-specific variables	 */	dd->ipath_f_tidtemplate = ipath_ht_tidtemplate;	/*	 * setup the register offsets, since they are different for each	 * chip	 */	dd->ipath_kregs = &ipath_ht_kregs;	dd->ipath_cregs = &ipath_ht_cregs;	/*	 * do very early init that is needed before ipath_f_bus is	 * called	 */	ipath_init_ht_variables(dd);}

⌨️ 快捷键说明

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