ipath_driver.c

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

C
2,286
字号
/* * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved. * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *        copyright notice, this list of conditions and the following *        disclaimer. * *      - Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the following *        disclaimer in the documentation and/or other materials *        provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */#include <linux/spinlock.h>#include <linux/idr.h>#include <linux/pci.h>#include <linux/io.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/vmalloc.h>#include "ipath_kernel.h"#include "ipath_verbs.h"#include "ipath_common.h"static void ipath_update_pio_bufs(struct ipath_devdata *);const char *ipath_get_unit_name(int unit){	static char iname[16];	snprintf(iname, sizeof iname, "infinipath%u", unit);	return iname;}#define DRIVER_LOAD_MSG "QLogic " IPATH_DRV_NAME " loaded: "#define PFX IPATH_DRV_NAME ": "/* * The size has to be longer than this string, so we can append * board/chip information to it in the init code. */const char ib_ipath_version[] = IPATH_IDSTR "\n";static struct idr unit_table;DEFINE_SPINLOCK(ipath_devs_lock);LIST_HEAD(ipath_dev_list);wait_queue_head_t ipath_state_wait;unsigned ipath_debug = __IPATH_INFO;module_param_named(debug, ipath_debug, uint, S_IWUSR | S_IRUGO);MODULE_PARM_DESC(debug, "mask for debug prints");EXPORT_SYMBOL_GPL(ipath_debug);MODULE_LICENSE("GPL");MODULE_AUTHOR("QLogic <support@pathscale.com>");MODULE_DESCRIPTION("QLogic InfiniPath driver");const char *ipath_ibcstatus_str[] = {	"Disabled",	"LinkUp",	"PollActive",	"PollQuiet",	"SleepDelay",	"SleepQuiet",	"LState6",		/* unused */	"LState7",		/* unused */	"CfgDebounce",	"CfgRcvfCfg",	"CfgWaitRmt",	"CfgIdle",	"RecovRetrain",	"LState0xD",		/* unused */	"RecovWaitRmt",	"RecovIdle",};static void __devexit ipath_remove_one(struct pci_dev *);static int __devinit ipath_init_one(struct pci_dev *,				    const struct pci_device_id *);/* Only needed for registration, nothing else needs this info */#define PCI_VENDOR_ID_PATHSCALE 0x1fc1#define PCI_DEVICE_ID_INFINIPATH_HT 0xd#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10/* Number of seconds before our card status check...  */#define STATUS_TIMEOUT 60static const struct pci_device_id ipath_pci_tbl[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },	{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },	{ 0, }};MODULE_DEVICE_TABLE(pci, ipath_pci_tbl);static struct pci_driver ipath_driver = {	.name = IPATH_DRV_NAME,	.probe = ipath_init_one,	.remove = __devexit_p(ipath_remove_one),	.id_table = ipath_pci_tbl,};static void ipath_check_status(struct work_struct *work){	struct ipath_devdata *dd = container_of(work, struct ipath_devdata,						status_work.work);	/*	 * If we don't have any interrupts, let the user know and	 * don't bother checking again.	 */	if (dd->ipath_int_counter == 0)		dev_err(&dd->pcidev->dev, "No interrupts detected.\n");}static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev,			     u32 *bar0, u32 *bar1){	int ret;	ret = pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);	if (ret)		ipath_dev_err(dd, "failed to read bar0 before enable: "			      "error %d\n", -ret);	ret = pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, bar1);	if (ret)		ipath_dev_err(dd, "failed to read bar1 before enable: "			      "error %d\n", -ret);	ipath_dbg("Read bar0 %x bar1 %x\n", *bar0, *bar1);}static void ipath_free_devdata(struct pci_dev *pdev,			       struct ipath_devdata *dd){	unsigned long flags;	pci_set_drvdata(pdev, NULL);	if (dd->ipath_unit != -1) {		spin_lock_irqsave(&ipath_devs_lock, flags);		idr_remove(&unit_table, dd->ipath_unit);		list_del(&dd->ipath_list);		spin_unlock_irqrestore(&ipath_devs_lock, flags);	}	vfree(dd);}static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev){	unsigned long flags;	struct ipath_devdata *dd;	int ret;	if (!idr_pre_get(&unit_table, GFP_KERNEL)) {		dd = ERR_PTR(-ENOMEM);		goto bail;	}	dd = vmalloc(sizeof(*dd));	if (!dd) {		dd = ERR_PTR(-ENOMEM);		goto bail;	}	memset(dd, 0, sizeof(*dd));	dd->ipath_unit = -1;	spin_lock_irqsave(&ipath_devs_lock, flags);	ret = idr_get_new(&unit_table, dd, &dd->ipath_unit);	if (ret < 0) {		printk(KERN_ERR IPATH_DRV_NAME		       ": Could not allocate unit ID: error %d\n", -ret);		ipath_free_devdata(pdev, dd);		dd = ERR_PTR(ret);		goto bail_unlock;	}	dd->pcidev = pdev;	pci_set_drvdata(pdev, dd);	INIT_DELAYED_WORK(&dd->status_work, ipath_check_status);	list_add(&dd->ipath_list, &ipath_dev_list);bail_unlock:	spin_unlock_irqrestore(&ipath_devs_lock, flags);bail:	return dd;}static inline struct ipath_devdata *__ipath_lookup(int unit){	return idr_find(&unit_table, unit);}struct ipath_devdata *ipath_lookup(int unit){	struct ipath_devdata *dd;	unsigned long flags;	spin_lock_irqsave(&ipath_devs_lock, flags);	dd = __ipath_lookup(unit);	spin_unlock_irqrestore(&ipath_devs_lock, flags);	return dd;}int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp){	int nunits, npresent, nup;	struct ipath_devdata *dd;	unsigned long flags;	u32 maxports;	nunits = npresent = nup = maxports = 0;	spin_lock_irqsave(&ipath_devs_lock, flags);	list_for_each_entry(dd, &ipath_dev_list, ipath_list) {		nunits++;		if ((dd->ipath_flags & IPATH_PRESENT) && dd->ipath_kregbase)			npresent++;		if (dd->ipath_lid &&		    !(dd->ipath_flags & (IPATH_DISABLED | IPATH_LINKDOWN					 | IPATH_LINKUNK)))			nup++;		if (dd->ipath_cfgports > maxports)			maxports = dd->ipath_cfgports;	}	spin_unlock_irqrestore(&ipath_devs_lock, flags);	if (npresentp)		*npresentp = npresent;	if (nupp)		*nupp = nup;	if (maxportsp)		*maxportsp = maxports;	return nunits;}/* * These next two routines are placeholders in case we don't have per-arch * code for controlling write combining.  If explicit control of write * combining is not available, performance will probably be awful. */int __attribute__((weak)) ipath_enable_wc(struct ipath_devdata *dd){	return -EOPNOTSUPP;}void __attribute__((weak)) ipath_disable_wc(struct ipath_devdata *dd){}/* * Perform a PIO buffer bandwidth write test, to verify proper system * configuration.  Even when all the setup calls work, occasionally * BIOS or other issues can prevent write combining from working, or * can cause other bandwidth problems to the chip. * * This test simply writes the same buffer over and over again, and * measures close to the peak bandwidth to the chip (not testing * data bandwidth to the wire).   On chips that use an address-based * trigger to send packets to the wire, this is easy.  On chips that * use a count to trigger, we want to make sure that the packet doesn't * go out on the wire, or trigger flow control checks. */static void ipath_verify_pioperf(struct ipath_devdata *dd){	u32 pbnum, cnt, lcnt;	u32 __iomem *piobuf;	u32 *addr;	u64 msecs, emsecs;	piobuf = ipath_getpiobuf(dd, &pbnum);	if (!piobuf) {		dev_info(&dd->pcidev->dev,			"No PIObufs for checking perf, skipping\n");		return;	}	/*	 * Enough to give us a reasonable test, less than piobuf size, and	 * likely multiple of store buffer length.	 */	cnt = 1024;	addr = vmalloc(cnt);	if (!addr) {		dev_info(&dd->pcidev->dev,			"Couldn't get memory for checking PIO perf,"			" skipping\n");		goto done;	}	preempt_disable();  /* we want reasonably accurate elapsed time */	msecs = 1 + jiffies_to_msecs(jiffies);	for (lcnt = 0; lcnt < 10000U; lcnt++) {		/* wait until we cross msec boundary */		if (jiffies_to_msecs(jiffies) >= msecs)			break;		udelay(1);	}	writeq(0, piobuf); /* length 0, no dwords actually sent */	ipath_flush_wc();	/*	 * this is only roughly accurate, since even with preempt we	 * still take interrupts that could take a while.   Running for	 * >= 5 msec seems to get us "close enough" to accurate values	 */	msecs = jiffies_to_msecs(jiffies);	for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) {		__iowrite32_copy(piobuf + 64, addr, cnt >> 2);		emsecs = jiffies_to_msecs(jiffies) - msecs;	}	/* 1 GiB/sec, slightly over IB SDR line rate */	if (lcnt < (emsecs * 1024U))		ipath_dev_err(dd,			"Performance problem: bandwidth to PIO buffers is "			"only %u MiB/sec\n",			lcnt / (u32) emsecs);	else		ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n",			lcnt / (u32) emsecs);	preempt_enable();	vfree(addr);done:	/* disarm piobuf, so it's available again */	ipath_disarm_piobufs(dd, pbnum, 1);}static int __devinit ipath_init_one(struct pci_dev *pdev,				    const struct pci_device_id *ent){	int ret, len, j;	struct ipath_devdata *dd;	unsigned long long addr;	u32 bar0 = 0, bar1 = 0;	dd = ipath_alloc_devdata(pdev);	if (IS_ERR(dd)) {		ret = PTR_ERR(dd);		printk(KERN_ERR IPATH_DRV_NAME		       ": Could not allocate devdata: error %d\n", -ret);		goto bail;	}	ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit);	ret = pci_enable_device(pdev);	if (ret) {		/* This can happen iff:		 *		 * We did a chip reset, and then failed to reprogram the		 * BAR, or the chip reset due to an internal error.  We then		 * unloaded the driver and reloaded it.		 *		 * Both reset cases set the BAR back to initial state.  For		 * the latter case, the AER sticky error bit at offset 0x718		 * should be set, but the Linux kernel doesn't yet know		 * about that, it appears.  If the original BAR was retained		 * in the kernel data structures, this may be OK.		 */		ipath_dev_err(dd, "enable unit %d failed: error %d\n",			      dd->ipath_unit, -ret);		goto bail_devdata;	}	addr = pci_resource_start(pdev, 0);	len = pci_resource_len(pdev, 0);	ipath_cdbg(VERBOSE, "regbase (0) %llx len %d pdev->irq %d, vend %x/%x "		   "driver_data %lx\n", addr, len, pdev->irq, ent->vendor,		   ent->device, ent->driver_data);	read_bars(dd, pdev, &bar0, &bar1);	if (!bar1 && !(bar0 & ~0xf)) {		if (addr) {			dev_info(&pdev->dev, "BAR is 0 (probable RESET), "				 "rewriting as %llx\n", addr);			ret = pci_write_config_dword(				pdev, PCI_BASE_ADDRESS_0, addr);			if (ret) {				ipath_dev_err(dd, "rewrite of BAR0 "					      "failed: err %d\n", -ret);				goto bail_disable;			}			ret = pci_write_config_dword(				pdev, PCI_BASE_ADDRESS_1, addr >> 32);			if (ret) {				ipath_dev_err(dd, "rewrite of BAR1 "					      "failed: err %d\n", -ret);				goto bail_disable;			}		} else {			ipath_dev_err(dd, "BAR is 0 (probable RESET), "				      "not usable until reboot\n");			ret = -ENODEV;			goto bail_disable;		}	}	ret = pci_request_regions(pdev, IPATH_DRV_NAME);	if (ret) {		dev_info(&pdev->dev, "pci_request_regions unit %u fails: "			 "err %d\n", dd->ipath_unit, -ret);		goto bail_disable;	}	ret = pci_set_dma_mask(pdev, DMA_64BIT_MASK);	if (ret) {		/*		 * if the 64 bit setup fails, try 32 bit.  Some systems		 * do not setup 64 bit maps on systems with 2GB or less		 * memory installed.		 */		ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);		if (ret) {			dev_info(&pdev->dev,				"Unable to set DMA mask for unit %u: %d\n",				dd->ipath_unit, ret);			goto bail_regions;		}		else {

⌨️ 快捷键说明

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