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 + -
显示快捷键?