ipath_init_chip.c

来自「linux 内核源代码」· C语言 代码 · 共 1,018 行 · 第 1/3 页

C
1,018
字号
			  dd->ipath_piosize4k, dd->ipath_pio4kbase,			  dd->ipath_4kalign);	}	else ipath_dbg("%u 2k piobufs @ %p\n",		       dd->ipath_piobcnt2k, dd->ipath_pio2kbase);	spin_lock_init(&dd->ipath_tid_lock);	spin_lock_init(&dd->ipath_gpio_lock);	spin_lock_init(&dd->ipath_eep_st_lock);	sema_init(&dd->ipath_eep_sem, 1);done:	*pdp = pd;	return ret;}/** * init_chip_reset - re-initialize after a reset, or enable * @dd: the infinipath device * @pdp: output for port data * * sanity check at least some of the values after reset, and * ensure no receive or transmit (explictly, in case reset * failed */static int init_chip_reset(struct ipath_devdata *dd,			   struct ipath_portdata **pdp){	u32 rtmp;	*pdp = dd->ipath_pd[0];	/* ensure chip does no sends or receives while we re-initialize */	dd->ipath_control = dd->ipath_sendctrl = dd->ipath_rcvctrl = 0U;	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, 0);	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0);	ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0);	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_portcnt);	if (dd->ipath_portcnt != rtmp)		dev_info(&dd->pcidev->dev, "portcnt was %u before "			 "reset, now %u, using original\n",			 dd->ipath_portcnt, rtmp);	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);	if (rtmp != dd->ipath_rcvtidcnt)		dev_info(&dd->pcidev->dev, "tidcnt was %u before "			 "reset, now %u, using original\n",			 dd->ipath_rcvtidcnt, rtmp);	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidbase);	if (rtmp != dd->ipath_rcvtidbase)		dev_info(&dd->pcidev->dev, "tidbase was %u before "			 "reset, now %u, using original\n",			 dd->ipath_rcvtidbase, rtmp);	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrcnt);	if (rtmp != dd->ipath_rcvegrcnt)		dev_info(&dd->pcidev->dev, "egrcnt was %u before "			 "reset, now %u, using original\n",			 dd->ipath_rcvegrcnt, rtmp);	rtmp = ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvegrbase);	if (rtmp != dd->ipath_rcvegrbase)		dev_info(&dd->pcidev->dev, "egrbase was %u before "			 "reset, now %u, using original\n",			 dd->ipath_rcvegrbase, rtmp);	return 0;}static int init_pioavailregs(struct ipath_devdata *dd){	int ret;	dd->ipath_pioavailregs_dma = dma_alloc_coherent(		&dd->pcidev->dev, PAGE_SIZE, &dd->ipath_pioavailregs_phys,		GFP_KERNEL);	if (!dd->ipath_pioavailregs_dma) {		ipath_dev_err(dd, "failed to allocate PIOavail reg area "			      "in memory\n");		ret = -ENOMEM;		goto done;	}	/*	 * we really want L2 cache aligned, but for current CPUs of	 * interest, they are the same.	 */	dd->ipath_statusp = (u64 *)		((char *)dd->ipath_pioavailregs_dma +		 ((2 * L1_CACHE_BYTES +		   dd->ipath_pioavregs * sizeof(u64)) & ~L1_CACHE_BYTES));	/* copy the current value now that it's really allocated */	*dd->ipath_statusp = dd->_ipath_status;	/*	 * setup buffer to hold freeze msg, accessible to apps,	 * following statusp	 */	dd->ipath_freezemsg = (char *)&dd->ipath_statusp[1];	/* and its length */	dd->ipath_freezelen = L1_CACHE_BYTES - sizeof(dd->ipath_statusp[0]);	ret = 0;done:	return ret;}/** * init_shadow_tids - allocate the shadow TID array * @dd: the infinipath device * * allocate the shadow TID array, so we can ipath_munlock previous * entries.  It may make more sense to move the pageshadow to the * port data structure, so we only allocate memory for ports actually * in use, since we at 8k per port, now. */static void init_shadow_tids(struct ipath_devdata *dd){	struct page **pages;	dma_addr_t *addrs;	pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *			sizeof(struct page *));	if (!pages) {		ipath_dev_err(dd, "failed to allocate shadow page * "			      "array, no expected sends!\n");		dd->ipath_pageshadow = NULL;		return;	}	addrs = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *			sizeof(dma_addr_t));	if (!addrs) {		ipath_dev_err(dd, "failed to allocate shadow dma handle "			      "array, no expected sends!\n");		vfree(dd->ipath_pageshadow);		dd->ipath_pageshadow = NULL;		return;	}	memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt *	       sizeof(struct page *));	dd->ipath_pageshadow = pages;	dd->ipath_physshadow = addrs;}static void enable_chip(struct ipath_devdata *dd,			struct ipath_portdata *pd, int reinit){	u32 val;	int i;	if (!reinit)		init_waitqueue_head(&ipath_state_wait);	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,			 dd->ipath_rcvctrl);	/* Enable PIO send, and update of PIOavail regs to memory. */	dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE |		INFINIPATH_S_PIOBUFAVAILUPD;	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,			 dd->ipath_sendctrl);	/*	 * enable port 0 receive, and receive interrupt.  other ports	 * done as user opens and inits them.	 */	dd->ipath_rcvctrl = INFINIPATH_R_TAILUPD |		(1ULL << INFINIPATH_R_PORTENABLE_SHIFT) |		(1ULL << INFINIPATH_R_INTRAVAIL_SHIFT);	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,			 dd->ipath_rcvctrl);	/*	 * now ready for use.  this should be cleared whenever we	 * detect a reset, or initiate one.	 */	dd->ipath_flags |= IPATH_INITTED;	/*	 * init our shadow copies of head from tail values, and write	 * head values to match.	 */	val = ipath_read_ureg32(dd, ur_rcvegrindextail, 0);	(void)ipath_write_ureg(dd, ur_rcvegrindexhead, val, 0);	dd->ipath_port0head = ipath_read_ureg32(dd, ur_rcvhdrtail, 0);	/* Initialize so we interrupt on next packet received */	(void)ipath_write_ureg(dd, ur_rcvhdrhead,			       dd->ipath_rhdrhead_intr_off |			       dd->ipath_port0head, 0);	/*	 * by now pioavail updates to memory should have occurred, so	 * copy them into our working/shadow registers; this is in	 * case something went wrong with abort, but mostly to get the	 * initial values of the generation bit correct.	 */	for (i = 0; i < dd->ipath_pioavregs; i++) {		__le64 val;		/*		 * Chip Errata bug 6641; even and odd qwords>3 are swapped.		 */		if (i > 3) {			if (i & 1)				val = dd->ipath_pioavailregs_dma[i - 1];			else				val = dd->ipath_pioavailregs_dma[i + 1];		}		else			val = dd->ipath_pioavailregs_dma[i];		dd->ipath_pioavailshadow[i] = le64_to_cpu(val);	}	/* can get counters, stats, etc. */	dd->ipath_flags |= IPATH_PRESENT;}static int init_housekeeping(struct ipath_devdata *dd,			     struct ipath_portdata **pdp, int reinit){	char boardn[32];	int ret = 0;	/*	 * have to clear shadow copies of registers at init that are	 * not otherwise set here, or all kinds of bizarre things	 * happen with driver on chip reset	 */	dd->ipath_rcvhdrsize = 0;	/*	 * Don't clear ipath_flags as 8bit mode was set before	 * entering this func. However, we do set the linkstate to	 * unknown, so we can watch for a transition.	 * PRESENT is set because we want register reads to work,	 * and the kernel infrastructure saw it in config space;	 * We clear it if we have failures.	 */	dd->ipath_flags |= IPATH_LINKUNK | IPATH_PRESENT;	dd->ipath_flags &= ~(IPATH_LINKACTIVE | IPATH_LINKARMED |			     IPATH_LINKDOWN | IPATH_LINKINIT);	ipath_cdbg(VERBOSE, "Try to read spc chip revision\n");	dd->ipath_revision =		ipath_read_kreg64(dd, dd->ipath_kregs->kr_revision);	/*	 * set up fundamental info we need to use the chip; we assume	 * if the revision reg and these regs are OK, we don't need to	 * special case the rest	 */	dd->ipath_sregbase =		ipath_read_kreg32(dd, dd->ipath_kregs->kr_sendregbase);	dd->ipath_cregbase =		ipath_read_kreg32(dd, dd->ipath_kregs->kr_counterregbase);	dd->ipath_uregbase =		ipath_read_kreg32(dd, dd->ipath_kregs->kr_userregbase);	ipath_cdbg(VERBOSE, "ipath_kregbase %p, sendbase %x usrbase %x, "		   "cntrbase %x\n", dd->ipath_kregbase, dd->ipath_sregbase,		   dd->ipath_uregbase, dd->ipath_cregbase);	if ((dd->ipath_revision & 0xffffffff) == 0xffffffff	    || (dd->ipath_sregbase & 0xffffffff) == 0xffffffff	    || (dd->ipath_cregbase & 0xffffffff) == 0xffffffff	    || (dd->ipath_uregbase & 0xffffffff) == 0xffffffff) {		ipath_dev_err(dd, "Register read failures from chip, "			      "giving up initialization\n");		dd->ipath_flags &= ~IPATH_PRESENT;		ret = -ENODEV;		goto done;	}	/* clear diagctrl register, in case diags were running and crashed */	ipath_write_kreg (dd, dd->ipath_kregs->kr_hwdiagctrl, 0);	/* clear the initial reset flag, in case first driver load */	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,			 INFINIPATH_E_RESET);	if (reinit)		ret = init_chip_reset(dd, pdp);	else		ret = init_chip_first(dd, pdp);	if (ret)		goto done;	ipath_cdbg(VERBOSE, "Revision %llx (PCI %x), %u ports, %u tids, "		   "%u egrtids\n", (unsigned long long) dd->ipath_revision,		   dd->ipath_pcirev, dd->ipath_portcnt, dd->ipath_rcvtidcnt,		   dd->ipath_rcvegrcnt);	if (((dd->ipath_revision >> INFINIPATH_R_SOFTWARE_SHIFT) &	     INFINIPATH_R_SOFTWARE_MASK) != IPATH_CHIP_SWVERSION) {		ipath_dev_err(dd, "Driver only handles version %d, "			      "chip swversion is %d (%llx), failng\n",			      IPATH_CHIP_SWVERSION,			      (int)(dd->ipath_revision >>				    INFINIPATH_R_SOFTWARE_SHIFT) &			      INFINIPATH_R_SOFTWARE_MASK,			      (unsigned long long) dd->ipath_revision);		ret = -ENOSYS;		goto done;	}	dd->ipath_majrev = (u8) ((dd->ipath_revision >>				  INFINIPATH_R_CHIPREVMAJOR_SHIFT) &				 INFINIPATH_R_CHIPREVMAJOR_MASK);	dd->ipath_minrev = (u8) ((dd->ipath_revision >>				  INFINIPATH_R_CHIPREVMINOR_SHIFT) &				 INFINIPATH_R_CHIPREVMINOR_MASK);	dd->ipath_boardrev = (u8) ((dd->ipath_revision >>				    INFINIPATH_R_BOARDID_SHIFT) &				   INFINIPATH_R_BOARDID_MASK);	ret = dd->ipath_f_get_boardname(dd, boardn, sizeof boardn);	snprintf(dd->ipath_boardversion, sizeof(dd->ipath_boardversion),		 "ChipABI %u.%u, %s, InfiniPath%u %u.%u, PCI %u, "		 "SW Compat %u\n",		 IPATH_CHIP_VERS_MAJ, IPATH_CHIP_VERS_MIN, boardn,		 (unsigned)(dd->ipath_revision >> INFINIPATH_R_ARCH_SHIFT) &		 INFINIPATH_R_ARCH_MASK,		 dd->ipath_majrev, dd->ipath_minrev, dd->ipath_pcirev,		 (unsigned)(dd->ipath_revision >>			    INFINIPATH_R_SOFTWARE_SHIFT) &		 INFINIPATH_R_SOFTWARE_MASK);	ipath_dbg("%s", dd->ipath_boardversion);done:	return ret;}/** * ipath_init_chip - do the actual initialization sequence on the chip * @dd: the infinipath device * @reinit: reinitializing, so don't allocate new memory *

⌨️ 快捷键说明

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