ipath_pe800.c

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

C
1,254
字号
	else		ipath_dev_err(dd, "Can't find PCI Express "			      "capability!\n");	return 0;}static void ipath_init_pe_variables(void){	/*	 * bits for selecting i2c direction and values,	 * used for I2C serial flash	 */	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;	/* variables for sanity checking interrupt and errors */	infinipath_hwe_bitsextant =		(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<		 INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |		(INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<		 INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |		INFINIPATH_HWE_PCIE1PLLFAILED |		INFINIPATH_HWE_PCIE0PLLFAILED |		INFINIPATH_HWE_PCIEPOISONEDTLP |		INFINIPATH_HWE_PCIECPLTIMEOUT |		INFINIPATH_HWE_PCIEBUSPARITYXTLH |		INFINIPATH_HWE_PCIEBUSPARITYXADM |		INFINIPATH_HWE_PCIEBUSPARITYRADM |		INFINIPATH_HWE_MEMBISTFAILED |		INFINIPATH_HWE_COREPLL_FBSLIP |		INFINIPATH_HWE_COREPLL_RFSLIP |		INFINIPATH_HWE_SERDESPLLFAILED |		INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |		INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;	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_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;	infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;}/* setup the MSI stuff again after a reset.  I'd like to just call * pci_enable_msi() and request_irq() again, but when I do that, * the MSI enable bit doesn't get set in the command word, and * we switch to to a different interrupt vector, which is confusing, * so I instead just do it all inline.  Perhaps somehow can tie this * into the PCIe hotplug support at some point * Note, because I'm doing it all here, I don't call pci_disable_msi() * or free_irq() at the start of ipath_setup_pe_reset(). */static int ipath_reinit_msi(struct ipath_devdata *dd){	int pos;	u16 control;	int ret;	if (!dd->ipath_msi_lo) {		dev_info(&dd->pcidev->dev, "Can't restore MSI config, "			 "initial setup failed?\n");		ret = 0;		goto bail;	}	if (!(pos = pci_find_capability(dd->pcidev, PCI_CAP_ID_MSI))) {		ipath_dev_err(dd, "Can't find MSI capability, "			      "can't restore MSI settings\n");		ret = 0;		goto bail;	}	ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",		   dd->ipath_msi_lo, pos + PCI_MSI_ADDRESS_LO);	pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_LO,			       dd->ipath_msi_lo);	ipath_cdbg(VERBOSE, "Writing msi_lo 0x%x to config offset 0x%x\n",		   dd->ipath_msi_hi, pos + PCI_MSI_ADDRESS_HI);	pci_write_config_dword(dd->pcidev, pos + PCI_MSI_ADDRESS_HI,			       dd->ipath_msi_hi);	pci_read_config_word(dd->pcidev, pos + PCI_MSI_FLAGS, &control);	if (!(control & PCI_MSI_FLAGS_ENABLE)) {		ipath_cdbg(VERBOSE, "MSI control at off %x was %x, "			   "setting MSI enable (%x)\n", pos + PCI_MSI_FLAGS,			   control, control | PCI_MSI_FLAGS_ENABLE);		control |= PCI_MSI_FLAGS_ENABLE;		pci_write_config_word(dd->pcidev, pos + PCI_MSI_FLAGS,				      control);	}	/* now rewrite the data (vector) info */	pci_write_config_word(dd->pcidev, pos +			      ((control & PCI_MSI_FLAGS_64BIT) ? 12 : 8),			      dd->ipath_msi_data);	/* we restore the cachelinesize also, although it doesn't really	 * matter */	pci_write_config_byte(dd->pcidev, PCI_CACHE_LINE_SIZE,			      dd->ipath_pci_cacheline);	/* and now set the pci master bit again */	pci_set_master(dd->pcidev);	ret = 1;bail:	return ret;}/* This routine sleeps, so it can only be called from user context, not * from interrupt context.  If we need interrupt context, we can split * it into two routines.*/static int ipath_setup_pe_reset(struct ipath_devdata *dd){	u64 val;	int i;	int ret;	/* Use ERROR so it shows up in logs, etc. */	ipath_dev_err(dd, "Resetting PE-800 unit %u\n",		      dd->ipath_unit);	/* keep chip from being accessed in a few places */	dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT);	val = dd->ipath_control | INFINIPATH_C_RESET;	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, val);	mb();	for (i = 1; i <= 5; i++) {		int r;		/* allow MBIST, etc. to complete; longer on each retry.		 * We sometimes get machine checks from bus timeout if no		 * response, so for now, make it *really* long.		 */		msleep(1000 + (1 + i) * 2000);		if ((r =		     pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,					    dd->ipath_pcibar0)))			ipath_dev_err(dd, "rewrite of BAR0 failed: %d\n",				      r);		if ((r =		     pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_1,					    dd->ipath_pcibar1)))			ipath_dev_err(dd, "rewrite of BAR1 failed: %d\n",				      r);		/* now re-enable memory access */		if ((r = pci_enable_device(dd->pcidev)))			ipath_dev_err(dd, "pci_enable_device failed after "				      "reset: %d\n", r);		/* whether it worked or not, mark as present, again */		dd->ipath_flags |= IPATH_PRESENT;		val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);		if (val == dd->ipath_revision) {			ipath_cdbg(VERBOSE, "Got matching revision "				   "register %llx on try %d\n",				   (unsigned long long) val, i);			ret = ipath_reinit_msi(dd);			goto bail;		}		/* Probably getting -1 back */		ipath_dbg("Didn't get expected revision register, "			  "got %llx, try %d\n", (unsigned long long) val,			  i + 1);	}	ret = 0; /* failed */bail:	return ret;}/** * ipath_pe_put_tid - write a TID in chip * @dd: the infinipath device * @tidptr: pointer to the expected TID (in chip) to udpate * @tidtype: 0 for eager, 1 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_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,			     u32 type, unsigned long pa){	u32 __iomem *tidp32 = (u32 __iomem *)tidptr;	unsigned long flags = 0; /* keep gcc quiet */	if (pa != dd->ipath_tidinvalid) {		if (pa & ((1U << 11) - 1)) {			dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "				 "not 4KB aligned!\n", pa);			return;		}		pa >>= 11;		/* paranoia check */		if (pa & (7<<29))			ipath_dev_err(dd,				      "BUG: Physical page address 0x%lx "				      "has bits set in 31-29\n", pa);		if (type == 0)			pa |= dd->ipath_tidtemplate;		else /* for now, always full 4KB page */			pa |= 2 << 29;	}	/* workaround chip bug 9437 by writing each TID twice	 * and holding a spinlock around the writes, so they don't	 * intermix with other TID (eager or expected) writes	 * Unfortunately, this call can be done from interrupt level	 * for the port 0 eager TIDs, so we have to use irqsave	 */	spin_lock_irqsave(&dd->ipath_tid_lock, flags);	ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);	if (dd->ipath_kregbase)		writel(pa, tidp32);	ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xdeadbeef);	mmiowb();	spin_unlock_irqrestore(&dd->ipath_tid_lock, flags);}/** * ipath_pe_clear_tid - clear all TID entries for a port, expected and eager * @dd: the infinipath device * @port: the port * * clear all TID entries for a port, expected and eager. * Used from ipath_close().  On PE800, TIDs are only 32 bits, * not 64, but they are still on 64 bit boundaries, so tidbase * is declared as u64 * for the pointer math, even though we write 32 bits */static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port){	u64 __iomem *tidbase;	unsigned long tidinv;	int i;	if (!dd->ipath_kregbase)		return;	ipath_cdbg(VERBOSE, "Invalidate TIDs for port %u\n", port);	tidinv = dd->ipath_tidinvalid;	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_pe_put_tid(dd, &tidbase[i], 0, tidinv);	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_pe_put_tid(dd, &tidbase[i], 1, tidinv);}/** * ipath_pe_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_pe_tidtemplate(struct ipath_devdata *dd){	u32 egrsize = dd->ipath_rcvegrbufsize;	/* For now, we always allocate 4KB buffers (at init) so we can	 * receive max size packets.  We may want a module parameter to	 * specify 2KB or 4KB and/or make be per port instead of per device	 * for those who want to reduce memory footprint.  Note that the	 * ipath_rcvhdrentsize size must be large enough to hold the largest	 * IB header (currently 96 bytes) that we expect to handle (plus of	 * course the 2 dwords of RHF).	 */	if (egrsize == 2048)		dd->ipath_tidtemplate = 1U << 29;	else if (egrsize == 4096)		dd->ipath_tidtemplate = 2U << 29;	else {		egrsize = 4096;		dev_info(&dd->pcidev->dev, "BUG: unsupported egrbufsize "			 "%u, using %u\n", dd->ipath_rcvegrbufsize,			 egrsize);		dd->ipath_tidtemplate = 2U << 29;	}	dd->ipath_tidinvalid = 0;}static int ipath_pe_early_init(struct ipath_devdata *dd){	dd->ipath_flags |= IPATH_4BYTE_TID;	/*	 * For openib, we need to be able to handle an IB header of 96 bytes	 * or 24 dwords.  HT-400 has arbitrary sized receive buffers, so we	 * made them the same size as the PIO buffers.  The PE-800 does not	 * handle arbitrary size buffers, so we need the header large enough	 * to handle largest IB header, but still have room for a 2KB MTU	 * standard IB packet.	 */	dd->ipath_rcvhdrentsize = 24;	dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;	/* For HT-400, 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 larger value.  We'll do this when I get around to	 * testing 4KB sends on the PE-800, which I have not yet done.	 */	dd->ipath_rcvegrbufsize = 2048;	/*	 * 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_rcvhdrentsize << 2));	dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;	/*	 * For PE-800, we can request a receive interrupt for 1 or	 * more packets from current offset.  For now, we set this	 * up for a single packet, to match the HT-400 behavior.	 */	dd->ipath_rhdrhead_intr_off = 1ULL<<32;	ipath_get_eeprom_info(dd);	return 0;}int __attribute__((weak)) ipath_unordered_wc(void){	return 0;}/** * ipath_init_pe_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 algorithims. */static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase){	struct ipath_base_info *kinfo = kbase;	if (ipath_unordered_wc()) {		kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER;		ipath_cdbg(PROC, "Intel processor, forcing WC order\n");	}	else		ipath_cdbg(PROC, "Not Intel processor, WC ordered\n");	kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;	return 0;}/** * ipath_init_pe800_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_pe800_funcs(struct ipath_devdata *dd){	dd->ipath_f_intrsetup = ipath_pe_intconfig;	dd->ipath_f_bus = ipath_setup_pe_config;	dd->ipath_f_reset = ipath_setup_pe_reset;	dd->ipath_f_get_boardname = ipath_pe_boardname;	dd->ipath_f_init_hwerrors = ipath_pe_init_hwerrors;	dd->ipath_f_early_init = ipath_pe_early_init;	dd->ipath_f_handle_hwerrors = ipath_pe_handle_hwerrors;	dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;	dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;	dd->ipath_f_clear_tids = ipath_pe_clear_tids;	dd->ipath_f_put_tid = ipath_pe_put_tid;	dd->ipath_f_cleanup = ipath_setup_pe_cleanup;	dd->ipath_f_setextled = ipath_setup_pe_setextled;	dd->ipath_f_get_base_info = ipath_pe_get_base_info;	/* initialize chip-specific variables */	dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;	/*	 * setup the register offsets, since they are different for each	 * chip	 */	dd->ipath_kregs = &ipath_pe_kregs;	dd->ipath_cregs = &ipath_pe_cregs;	ipath_init_pe_variables();}

⌨️ 快捷键说明

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