ipath_driver.c

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

C
1,993
字号
			ret = -ENODEV;			break;		}	} while (1);	return ret;}void ipath_set_ib_lstate(struct ipath_devdata *dd, int which){	static const char *what[4] = {		[0] = "DOWN",		[INFINIPATH_IBCC_LINKCMD_INIT] = "INIT",		[INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED",		[INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE"	};	ipath_cdbg(SMA, "Trying to move unit %u to %s, current ltstate "		   "is %s\n", dd->ipath_unit,		   what[(which >> INFINIPATH_IBCC_LINKCMD_SHIFT) &			INFINIPATH_IBCC_LINKCMD_MASK],		   ipath_ibcstatus_str[			   (ipath_read_kreg64			    (dd, dd->ipath_kregs->kr_ibcstatus) >>			    INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &			   INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]);	ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,			 dd->ipath_ibcctrl | which);}/** * ipath_read_kreg64_port - read a device's per-port 64-bit kernel register * @dd: the infinipath device * @regno: the register number to read * @port: the port containing the register * * Registers that vary with the chip implementation constants (port) * use this routine. */u64 ipath_read_kreg64_port(const struct ipath_devdata *dd, ipath_kreg regno,			   unsigned port){	u16 where;	if (port < dd->ipath_portcnt &&	    (regno == dd->ipath_kregs->kr_rcvhdraddr ||	     regno == dd->ipath_kregs->kr_rcvhdrtailaddr))		where = regno + port;	else		where = -1;	return ipath_read_kreg64(dd, where);}/** * ipath_write_kreg_port - write a device's per-port 64-bit kernel register * @dd: the infinipath device * @regno: the register number to write * @port: the port containing the register * @value: the value to write * * Registers that vary with the chip implementation constants (port) * use this routine. */void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,			  unsigned port, u64 value){	u16 where;	if (port < dd->ipath_portcnt &&	    (regno == dd->ipath_kregs->kr_rcvhdraddr ||	     regno == dd->ipath_kregs->kr_rcvhdrtailaddr))		where = regno + port;	else		where = -1;	ipath_write_kreg(dd, where, value);}/** * ipath_shutdown_device - shut down a device * @dd: the infinipath device * * This is called to make the device quiet when we are about to * unload the driver, and also when the device is administratively * disabled.   It does not free any data structures. * Everything it does has to be setup again by ipath_init_chip(dd,1) */void ipath_shutdown_device(struct ipath_devdata *dd){	u64 val;	ipath_dbg("Shutting down the device\n");	dd->ipath_flags |= IPATH_LINKUNK;	dd->ipath_flags &= ~(IPATH_INITTED | IPATH_LINKDOWN |			     IPATH_LINKINIT | IPATH_LINKARMED |			     IPATH_LINKACTIVE);	*dd->ipath_statusp &= ~(IPATH_STATUS_IB_CONF |				IPATH_STATUS_IB_READY);	/* mask interrupts, but not errors */	ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);	dd->ipath_rcvctrl = 0;	ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,			 dd->ipath_rcvctrl);	/*	 * gracefully stop all sends allowing any in progress to trickle out	 * first.	 */	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, 0ULL);	/* flush it */	val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);	/*	 * enough for anything that's going to trickle out to have actually	 * done so.	 */	udelay(5);	/*	 * abort any armed or launched PIO buffers that didn't go. (self	 * clearing).  Will cause any packet currently being transmitted to	 * go out with an EBP, and may also cause a short packet error on	 * the receiver.	 */	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,			 INFINIPATH_S_ABORT);	ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE <<			    INFINIPATH_IBCC_LINKINITCMD_SHIFT);	/*	 * we are shutting down, so tell the layered driver.  We don't do	 * this on just a link state change, much like ethernet, a cable	 * unplug, etc. doesn't change driver state	 */	ipath_layer_intr(dd, IPATH_LAYER_INT_IF_DOWN);	/* disable IBC */	dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,			 dd->ipath_control);	/*	 * clear SerdesEnable and turn the leds off; do this here because	 * we are unloading, so don't count on interrupts to move along	 * Turn the LEDs off explictly for the same reason.	 */	dd->ipath_f_quiet_serdes(dd);	dd->ipath_f_setextled(dd, 0, 0);	if (dd->ipath_stats_timer_active) {		del_timer_sync(&dd->ipath_stats_timer);		dd->ipath_stats_timer_active = 0;	}	/*	 * clear all interrupts and errors, so that the next time the driver	 * is loaded or device is enabled, we know that whatever is set	 * happened while we were unloaded	 */	ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear,			 ~0ULL & ~INFINIPATH_HWE_MEMBISTFAILED);	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL);	ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);}/** * ipath_free_pddata - free a port's allocated data * @dd: the infinipath device * @port: the port * @freehdrq: free the port data structure if true * * when closing, free up any allocated data for a port, if the * reference count goes to zero * Note: this also optionally frees the portdata itself! * Any changes here have to be matched up with the reinit case * of ipath_init_chip(), which calls this routine on reinit after reset. */void ipath_free_pddata(struct ipath_devdata *dd, u32 port, int freehdrq){	struct ipath_portdata *pd = dd->ipath_pd[port];	if (!pd)		return;	if (freehdrq)		/*		 * only clear and free portdata if we are going to also		 * release the hdrq, otherwise we leak the hdrq on each		 * open/close cycle		 */		dd->ipath_pd[port] = NULL;	if (freehdrq && pd->port_rcvhdrq) {		ipath_cdbg(VERBOSE, "free closed port %d rcvhdrq @ %p "			   "(size=%lu)\n", pd->port_port, pd->port_rcvhdrq,			   (unsigned long) pd->port_rcvhdrq_size);		dma_free_coherent(&dd->pcidev->dev, pd->port_rcvhdrq_size,				  pd->port_rcvhdrq, pd->port_rcvhdrq_phys);		pd->port_rcvhdrq = NULL;	}	if (port && pd->port_rcvegrbuf) {		/* always free this */		if (pd->port_rcvegrbuf) {			unsigned e;			for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) {				void *base = pd->port_rcvegrbuf[e];				size_t size = pd->port_rcvegrbuf_size;				ipath_cdbg(VERBOSE, "egrbuf free(%p, %lu), "					   "chunk %u/%u\n", base,					   (unsigned long) size,					   e, pd->port_rcvegrbuf_chunks);				dma_free_coherent(					&dd->pcidev->dev, size, base,					pd->port_rcvegrbuf_phys[e]);			}			vfree(pd->port_rcvegrbuf);			pd->port_rcvegrbuf = NULL;			vfree(pd->port_rcvegrbuf_phys);			pd->port_rcvegrbuf_phys = NULL;		}		pd->port_rcvegrbuf_chunks = 0;	} else if (port == 0 && dd->ipath_port0_skbs) {		unsigned e;		struct sk_buff **skbs = dd->ipath_port0_skbs;		dd->ipath_port0_skbs = NULL;		ipath_cdbg(VERBOSE, "free closed port %d ipath_port0_skbs "			   "@ %p\n", pd->port_port, skbs);		for (e = 0; e < dd->ipath_rcvegrcnt; e++)			if (skbs[e])				dev_kfree_skb(skbs[e]);		vfree(skbs);	}	if (freehdrq) {		kfree(pd->port_tid_pg_list);		kfree(pd);	}}static int __init infinipath_init(void){	int ret;	ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ipath_core_version);	/*	 * These must be called before the driver is registered with	 * the PCI subsystem.	 */	idr_init(&unit_table);	if (!idr_pre_get(&unit_table, GFP_KERNEL)) {		ret = -ENOMEM;		goto bail;	}	ret = pci_register_driver(&ipath_driver);	if (ret < 0) {		printk(KERN_ERR IPATH_DRV_NAME		       ": Unable to register driver: error %d\n", -ret);		goto bail_unit;	}	ret = ipath_driver_create_group(&ipath_driver.driver);	if (ret < 0) {		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create driver "		       "sysfs entries: error %d\n", -ret);		goto bail_pci;	}	ret = ipath_init_ipathfs();	if (ret < 0) {		printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "		       "ipathfs: error %d\n", -ret);		goto bail_group;	}	goto bail;bail_group:	ipath_driver_remove_group(&ipath_driver.driver);bail_pci:	pci_unregister_driver(&ipath_driver);bail_unit:	idr_destroy(&unit_table);bail:	return ret;}static void cleanup_device(struct ipath_devdata *dd){	int port;	ipath_shutdown_device(dd);	if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {		/* can't do anything more with chip; needs re-init */		*dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;		if (dd->ipath_kregbase) {			/*			 * if we haven't already cleaned up before these are			 * to ensure any register reads/writes "fail" until			 * re-init			 */			dd->ipath_kregbase = NULL;			dd->ipath_kregvirt = NULL;			dd->ipath_uregbase = 0;			dd->ipath_sregbase = 0;			dd->ipath_cregbase = 0;			dd->ipath_kregsize = 0;		}		ipath_disable_wc(dd);	}	if (dd->ipath_pioavailregs_dma) {		dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,				  (void *) dd->ipath_pioavailregs_dma,				  dd->ipath_pioavailregs_phys);		dd->ipath_pioavailregs_dma = NULL;	}	if (dd->ipath_pageshadow) {		struct page **tmpp = dd->ipath_pageshadow;		int i, cnt = 0;		ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "			   "locked\n");		for (port = 0; port < dd->ipath_cfgports; port++) {			int port_tidbase = port * dd->ipath_rcvtidcnt;			int maxtid = port_tidbase + dd->ipath_rcvtidcnt;			for (i = port_tidbase; i < maxtid; i++) {				if (!tmpp[i])					continue;				ipath_release_user_pages(&tmpp[i], 1);				tmpp[i] = NULL;				cnt++;			}		}		if (cnt) {			ipath_stats.sps_pageunlocks += cnt;			ipath_cdbg(VERBOSE, "There were still %u expTID "				   "entries locked\n", cnt);		}		if (ipath_stats.sps_pagelocks ||		    ipath_stats.sps_pageunlocks)			ipath_cdbg(VERBOSE, "%llu pages locked, %llu "				   "unlocked via ipath_m{un}lock\n",				   (unsigned long long)				   ipath_stats.sps_pagelocks,				   (unsigned long long)				   ipath_stats.sps_pageunlocks);		ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",			   dd->ipath_pageshadow);		vfree(dd->ipath_pageshadow);		dd->ipath_pageshadow = NULL;	}	/*	 * free any resources still in use (usually just kernel ports)	 * at unload	 */	for (port = 0; port < dd->ipath_cfgports; port++)		ipath_free_pddata(dd, port, 1);	kfree(dd->ipath_pd);	/*	 * debuggability, in case some cleanup path tries to use it	 * after this	 */	dd->ipath_pd = NULL;}static void __exit infinipath_cleanup(void){	struct ipath_devdata *dd, *tmp;	unsigned long flags;	ipath_exit_ipathfs();	ipath_driver_remove_group(&ipath_driver.driver);	spin_lock_irqsave(&ipath_devs_lock, flags);	/*	 * turn off rcv, send, and interrupts for all ports, all drivers	 * should also hard reset the chip here?	 * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs	 * for all versions of the driver, if they were allocated	 */	list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {		spin_unlock_irqrestore(&ipath_devs_lock, flags);		if (dd->ipath_kregbase)			cleanup_device(dd);		if (dd->pcidev) {			if (dd->pcidev->irq) {				ipath_cdbg(VERBOSE,					   "unit %u free_irq of irq %x\n",					   dd->ipath_unit, dd->pcidev->irq);				free_irq(dd->pcidev->irq, dd);			} else				ipath_dbg("irq is 0, not doing free_irq "					  "for unit %u\n", dd->ipath_unit);			/*			 * we check for NULL here, because it's outside			 * the kregbase check, and we need to call it			 * after the free_irq.  Thus it's possible that			 * the function pointers were never initialized.			 */			if (dd->ipath_f_cleanup)				/* clean up chip-specific stuff */				dd->ipath_f_cleanup(dd);			dd->pcidev = NULL;		}		spin_lock_irqsave(&ipath_devs_lock, flags);	}	spin_unlock_irqrestore(&ipath_devs_lock, flags);	ipath_cdbg(VERBOSE, "Unregistering pci driver\n");	pci_unregister_driver(&ipath_driver);	idr_destroy(&unit_table);}/** * ipath_reset_device - reset the chip if possible * @unit: the device to reset * * Whether or not reset is successful, we attempt to re-initialize the chip * (that is, much like a driver unload/reload).  We clear the INITTED flag * so that the various entry points will fail until we reinitialize.  For * now, we only allow this if no user ports are open that use chip resources */int ipath_reset_device(int unit){	int ret, i;	struct ipath_devdata *dd = ipath_lookup(unit);	if (!dd) {		ret = -ENODEV;		goto bail;	}	dev_info(&dd->pcidev->dev, "Reset on unit %u requested\n", unit);	if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) {		dev_info(&dd->pcidev->dev, "Invalid unit number %u or "			 "not initialized or not present\n", unit);		ret = -ENXIO;		goto bail;	}	if (dd->ipath_pd)		for (i = 1; i < dd->ipath_cfgports; i++) {			if (dd->ipath_pd[i] && dd->ipath_pd[i]->port_cnt) {				ipath_dbg("unit %u port %d is in use "					  "(PID %u cmd %s), can't reset\n",					  unit, i,					  dd->ipath_pd[i]->port_pid,					  dd->ipath_pd[i]->port_comm);				ret = -EBUSY;				goto bail;			}		}	dd->ipath_flags &= ~IPATH_INITTED;	ret = dd->ipath_f_reset(dd);	if (ret != 1)		ipath_dbg("reset was not successful\n");	ipath_dbg("Trying to reinitialize unit %u after reset attempt\n",		  unit);	ret = ipath_init_chip(dd, 1);	if (ret)		ipath_dev_err(dd, "Reinitialize unit %u after "			      "reset failed with %d\n", unit, ret);	else		dev_info(&dd->pcidev->dev, "Reinitialized unit %u after "			 "resetting\n", unit);bail:	return ret;}module_init(infinipath_init);module_exit(infinipath_cleanup);

⌨️ 快捷键说明

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