📄 lanstreamer.c
字号:
/* * lanstreamer.c -- driver for the IBM Auto LANStreamer PCI Adapter * * Written By: Mike Sullivan, IBM Corporation * * Copyright (C) 1999 IBM Corporation * * Linux driver for IBM PCI tokenring cards based on the LanStreamer MPC * chipset. * * This driver is based on the olympic driver for IBM PCI TokenRing cards (Pit/Pit-Phy/Olympic * chipsets) written by: * 1999 Peter De Schrijver All Rights Reserved * 1999 Mike Phillips (phillim@amtrak.com) * * Base Driver Skeleton: * Written 1993-94 by Donald Becker. * * Copyright 1993 United States Government as represented by the * Director, National Security Agency. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * NO WARRANTY * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is * solely responsible for determining the appropriateness of using and * distributing the Program and assumes all risks associated with its * exercise of rights under this Agreement, including but not limited to * the risks and costs of program errors, damage to or loss of data, * programs or equipment, and unavailability or interruption of operations. * * DISCLAIMER OF LIABILITY * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * 12/10/99 - Alpha Release 0.1.0 * First release to the public * 03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing * malloc free checks, reviewed code. <alan@redhat.com> * 03/13/00 - Added spinlocks for smp * 03/08/01 - Added support for module_init() and module_exit() * 08/15/01 - Added ioctl() functionality for debugging, changed netif_*_queue * calls and other incorrectness - Kent Yoder <yoder1@us.ibm.com> * 11/05/01 - Restructured the interrupt function, added delays, reduced the * the number of TX descriptors to 1, which together can prevent * the card from locking up the box - <yoder1@us.ibm.com> * 09/27/02 - New PCI interface + bug fix. - <yoder1@us.ibm.com> * 11/13/02 - Removed free_irq calls which could cause a hang, added * netif_carrier_{on|off} - <yoder1@us.ibm.com> * * To Do: * * * If Problems do Occur * Most problems can be rectified by either closing and opening the interface * (ifconfig down and up) or rmmod and insmod'ing the driver (a bit difficult * if compiled into the kernel). *//* Change STREAMER_DEBUG to 1 to get verbose, and I mean really verbose, messages */#define STREAMER_DEBUG 0#define STREAMER_DEBUG_PACKETS 0/* Change STREAMER_NETWORK_MONITOR to receive mac frames through the arb channel. * Will also create a /proc/net/streamer_tr entry if proc_fs is compiled into the * kernel. * Intended to be used to create a ring-error reporting network module * i.e. it will give you the source address of beaconers on the ring */#define STREAMER_NETWORK_MONITOR 0/* #define CONFIG_PROC_FS *//* * Allow or disallow ioctl's for debugging */#define STREAMER_IOCTL 0#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/in.h>#include <linux/ioport.h>#include <linux/string.h>#include <linux/proc_fs.h>#include <linux/ptrace.h>#include <linux/skbuff.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/netdevice.h>#include <linux/trdevice.h>#include <linux/stddef.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/spinlock.h>#include <linux/version.h>#include <linux/bitops.h>#include <net/checksum.h>#include <asm/io.h>#include <asm/system.h>#include "lanstreamer.h"#if (BITS_PER_LONG == 64)#error broken on 64-bit: stores pointer to rx_ring->buffer in 32-bit int#endif/* I've got to put some intelligence into the version number so that Peter and I know * which version of the code somebody has got. * Version Number = a.b.c.d where a.b.c is the level of code and d is the latest author. * So 0.0.1.pds = Peter, 0.0.1.mlp = Mike * * Official releases will only have an a.b.c version number format. */static char version[] = "LanStreamer.c v0.4.0 03/08/01 - Mike Sullivan\n" " v0.5.3 11/13/02 - Kent Yoder";static struct pci_device_id streamer_pci_tbl[] = { { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_TR, PCI_ANY_ID, PCI_ANY_ID,}, {} /* terminating entry */};MODULE_DEVICE_TABLE(pci,streamer_pci_tbl);static char *open_maj_error[] = { "No error", "Lobe Media Test", "Physical Insertion", "Address Verification", "Neighbor Notification (Ring Poll)", "Request Parameters", "FDX Registration Request", "FDX Lobe Media Test", "FDX Duplicate Address Check", "Unknown stage"};static char *open_min_error[] = { "No error", "Function Failure", "Signal Lost", "Wire Fault", "Ring Speed Mismatch", "Timeout", "Ring Failure", "Ring Beaconing", "Duplicate Node Address", "Request Parameters", "Remove Received", "Reserved", "Reserved", "No Monitor Detected for RPL", "Monitor Contention failer for RPL", "FDX Protocol Error"};/* Module paramters *//* Ring Speed 0,4,16 * 0 = Autosense * 4,16 = Selected speed only, no autosense * This allows the card to be the first on the ring * and become the active monitor. * * WARNING: Some hubs will allow you to insert * at the wrong speed */static int ringspeed[STREAMER_MAX_ADAPTERS] = { 0, };module_param_array(ringspeed, int, NULL, 0);/* Packet buffer size */static int pkt_buf_sz[STREAMER_MAX_ADAPTERS] = { 0, };module_param_array(pkt_buf_sz, int, NULL, 0);/* Message Level */static int message_level[STREAMER_MAX_ADAPTERS] = { 1, };module_param_array(message_level, int, NULL, 0);#if STREAMER_IOCTLstatic int streamer_ioctl(struct net_device *, struct ifreq *, int);#endifstatic int streamer_reset(struct net_device *dev);static int streamer_open(struct net_device *dev);static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);static int streamer_close(struct net_device *dev);static void streamer_set_rx_mode(struct net_device *dev);static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs);static struct net_device_stats *streamer_get_stats(struct net_device *dev);static int streamer_set_mac_address(struct net_device *dev, void *addr);static void streamer_arb_cmd(struct net_device *dev);static int streamer_change_mtu(struct net_device *dev, int mtu);static void streamer_srb_bh(struct net_device *dev);static void streamer_asb_bh(struct net_device *dev);#if STREAMER_NETWORK_MONITOR#ifdef CONFIG_PROC_FSstatic int streamer_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data);static int sprintf_info(char *buffer, struct net_device *dev);struct streamer_private *dev_streamer=NULL;#endif#endifstatic int __devinit streamer_init_one(struct pci_dev *pdev, const struct pci_device_id *ent){ struct net_device *dev; struct streamer_private *streamer_priv; unsigned long pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; int rc = 0; static int card_no=-1; u16 pcr;#if STREAMER_DEBUG printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev);#endif card_no++; dev = alloc_trdev(sizeof(*streamer_priv)); if (dev==NULL) { printk(KERN_ERR "lanstreamer: out of memory.\n"); return -ENOMEM; } SET_MODULE_OWNER(dev); streamer_priv = dev->priv;#if STREAMER_NETWORK_MONITOR#ifdef CONFIG_PROC_FS if (!dev_streamer) create_proc_read_entry("net/streamer_tr", 0, 0, streamer_proc_info, NULL); streamer_priv->next = dev_streamer; dev_streamer = streamer_priv;#endif#endif rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { printk(KERN_ERR "%s: No suitable PCI mapping available.\n", dev->name); rc = -ENODEV; goto err_out; } rc = pci_enable_device(pdev); if (rc) { printk(KERN_ERR "lanstreamer: unable to enable pci device\n"); rc=-EIO; goto err_out; } pci_set_master(pdev); rc = pci_set_mwi(pdev); if (rc) { printk(KERN_ERR "lanstreamer: unable to enable MWI on pci device\n"); goto err_out_disable; } pio_start = pci_resource_start(pdev, 0); pio_end = pci_resource_end(pdev, 0); pio_flags = pci_resource_flags(pdev, 0); pio_len = pci_resource_len(pdev, 0); mmio_start = pci_resource_start(pdev, 1); mmio_end = pci_resource_end(pdev, 1); mmio_flags = pci_resource_flags(pdev, 1); mmio_len = pci_resource_len(pdev, 1);#if STREAMER_DEBUG printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n", pio_start, pio_end, pio_len, pio_flags); printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n", mmio_start, mmio_end, mmio_flags, mmio_len);#endif if (!request_region(pio_start, pio_len, "lanstreamer")) { printk(KERN_ERR "lanstreamer: unable to get pci io addr %lx\n", pio_start); rc= -EBUSY; goto err_out_mwi; } if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) { printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %lx\n", mmio_start); rc= -EBUSY; goto err_out_free_pio; } streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len); if (streamer_priv->streamer_mmio == NULL) { printk(KERN_ERR "lanstreamer: unable to remap MMIO %lx\n", mmio_start); rc= -EIO; goto err_out_free_mmio; } init_waitqueue_head(&streamer_priv->srb_wait); init_waitqueue_head(&streamer_priv->trb_wait); dev->open = &streamer_open; dev->hard_start_xmit = &streamer_xmit; dev->change_mtu = &streamer_change_mtu; dev->stop = &streamer_close;#if STREAMER_IOCTL dev->do_ioctl = &streamer_ioctl;#else dev->do_ioctl = NULL;#endif dev->set_multicast_list = &streamer_set_rx_mode; dev->get_stats = &streamer_get_stats; dev->set_mac_address = &streamer_set_mac_address; dev->irq = pdev->irq; dev->base_addr=pio_start; SET_NETDEV_DEV(dev, &pdev->dev); streamer_priv->streamer_card_name = (char *)pdev->resource[0].name; streamer_priv->pci_dev = pdev; if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) streamer_priv->pkt_buf_sz = PKT_BUF_SZ; else streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; streamer_priv->streamer_ring_speed = ringspeed[card_no]; streamer_priv->streamer_message_level = message_level[card_no]; pci_set_drvdata(pdev, dev); spin_lock_init(&streamer_priv->streamer_lock); pci_read_config_word (pdev, PCI_COMMAND, &pcr); pcr |= PCI_COMMAND_SERR; pci_write_config_word (pdev, PCI_COMMAND, pcr); printk("%s \n", version); printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, streamer_priv->streamer_card_name, (unsigned int) dev->base_addr, streamer_priv->streamer_mmio, dev->irq); if (streamer_reset(dev)) goto err_out_unmap; rc = register_netdev(dev); if (rc) goto err_out_unmap; return 0;err_out_unmap: iounmap(streamer_priv->streamer_mmio);err_out_free_mmio: release_mem_region(mmio_start, mmio_len);err_out_free_pio: release_region(pio_start, pio_len);err_out_mwi: pci_clear_mwi(pdev);err_out_disable: pci_disable_device(pdev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -