📄 acenic_np.c
字号:
/******************************************************************************* ** Copyright 2005 University of Cambridge Computer Laboratory. ** ** This file is part of Nprobe. ** ** Nprobe 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. ** ** Nprobe 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. ** ** You should have received a copy of the GNU General Public License ** along with Nprobe; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ** *******************************************************************************//* * acenic.c: Linux driver for the Alteon AceNIC Gigabit Ethernet card * and other Tigon based cards. * * Copyright 1998-2000 by Jes Sorensen, <jes@linuxcare.com>. * * Thanks to Alteon and 3Com for providing hardware and documentation * enabling me to write this driver. * * A mailing list for discussing the use of this driver has been * setup, please subscribe to the lists if you have any questions * about the driver. Send mail to linux-acenic-help@sunsite.auc.dk to * see how to subscribe. * * 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. * * Additional credits: * Pete Wyckoff <wyckoff@ca.sandia.gov>: Initial Linux/Alpha and trace * dump support. The trace dump support has not been * integrated yet however. * Troy Benjegerdes: Big Endian (PPC) patches. * Nate Stahl: Better out of memory handling and stats support. * Aman Singla: Nasty race between interrupt handler and tx code dealing * with 'testing the tx_ret_csm and setting tx_full' * David S. Miller <davem@redhat.com>: conversion to new PCI dma mapping * infrastructure and Sparc support * Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the * driver under Linux/Sparc64 * Matt Domsch <Matt_Domsch@dell.com>: Detect Alteon 1000baseT cards * Chip Salzenberg <chip@valinux.com>: Fix race condition between tx * handler and close() cleanup. * Ken Aaker <kdaaker@rchland.vnet.ibm.com>: Correct check for whether * memory mapped IO is enabled to * make the driver work on RS/6000. * Takayoshi Kouchi <kouchi@hpc.bs1.fc.nec.co.jp>: Identifying problem * where the driver would disable * bus master mode if it had to disable * write and invalidate. * Stephen Hack <stephen_hack@hp.com>: Fixed ace_set_mac_addr for little * endian systems. * Val Henson <vhenson@esscom.com>: Reset Jumbo skb producer and * rx producer index when * flushing the Jumbo ring. * Hans Grobler <grobh@sun.ac.za>: Memory leak fixes in the * driver init path. */#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/mm.h>#include <linux/sockios.h>#ifdef SIOCETHTOOL#include <linux/ethtool.h>#endif#include <net/sock.h>#include <net/ip.h>#include <asm/system.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#include "probe.h"//#define NP_dev_kfree_skb(skb) dev_kfree_skb(skb)//#define NP_dev_alloc_skb(sz) alloc_skb(sz, GFP_ATOMIC)//#define NP_netif_rx(skb) netif_rx(skb)#undef INDEX_DEBUG#ifdef CONFIG_ACENIC_OMIT_TIGON_I#define ACE_IS_TIGON_I(ap) 0#else#define ACE_IS_TIGON_I(ap) (ap->version == 1)#endif#ifndef PCI_VENDOR_ID_ALTEON#define PCI_VENDOR_ID_ALTEON 0x12ae #endif#ifndef PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE#define PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE 0x0001#define PCI_DEVICE_ID_ALTEON_ACENIC_COPPER 0x0002#endif#ifndef PCI_DEVICE_ID_3COM_3C985#define PCI_DEVICE_ID_3COM_3C985 0x0001#endif#ifndef PCI_VENDOR_ID_NETGEAR#define PCI_VENDOR_ID_NETGEAR 0x1385#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a#endif#ifndef PCI_DEVICE_ID_NETGEAR_GA620T#define PCI_DEVICE_ID_NETGEAR_GA620T 0x630a#endif/* * Farallon used the DEC vendor ID by mistake and they seem not * to care - stinky! */#ifndef PCI_DEVICE_ID_FARALLON_PN9000SX#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a#endif#ifndef PCI_VENDOR_ID_SGI#define PCI_VENDOR_ID_SGI 0x10a9#endif#ifndef PCI_DEVICE_ID_SGI_ACENIC#define PCI_DEVICE_ID_SGI_ACENIC 0x0009#endif#if LINUX_VERSION_CODE >= 0x20400static struct pci_device_id acenic_pci_tbl[] __initdata = { { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_ALTEON_ACENIC_COPPER, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C985, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, /* * Farallon used the DEC vendor ID on their cards incorrectly. */ { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, }, { }};MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);#endif#ifndef wmb#define wmb() mb()#endif#ifndef __exit#define __exit#endif#ifndef __devinit#define __devinit __init#endif#ifndef SMP_CACHE_BYTES#define SMP_CACHE_BYTES L1_CACHE_BYTES#endif#if (BITS_PER_LONG == 64)#define ACE_64BIT_PTR 1#endif#ifndef SET_MODULE_OWNER#define SET_MODULE_OWNER(dev) {do{} while(0);}#define ACE_MOD_INC_USE_COUNT MOD_INC_USE_COUNT#define ACE_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT#else#define ACE_MOD_INC_USE_COUNT {do{} while(0);}#define ACE_MOD_DEC_USE_COUNT {do{} while(0);}#endif#if (LINUX_VERSION_CODE < 0x02030d)#define pci_resource_start(dev, bar) dev->base_address[bar]#elif (LINUX_VERSION_CODE < 0x02032c)#define pci_resource_start(dev, bar) dev->resource[bar].start#endif#if (LINUX_VERSION_CODE < 0x02030e)#define net_device device#endif#if (LINUX_VERSION_CODE < 0x02032a)typedef u32 dma_addr_t;static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle){ void *virt_ptr; virt_ptr = kmalloc(size, GFP_KERNEL); if (!virt_ptr) return NULL; *dma_handle = virt_to_bus(virt_ptr); return virt_ptr;}#define pci_free_consistent(cookie, size, ptr, dma_ptr) kfree(ptr)#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)#define pci_unmap_single(cookie, address, size, dir)#endif#if (LINUX_VERSION_CODE < 0x02032b)/* * SoftNet * * For pre-softnet kernels we need to tell the upper layer not to * re-enter start_xmit() while we are in there. However softnet * guarantees not to enter while we are in there so there is no need * to do the netif_stop_queue() dance unless the transmit queue really * gets stuck. This should also improve performance according to tests * done by Aman Singla. */#define dev_kfree_skb_irq(a) dev_kfree_skb(a)#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy)#define netif_stop_queue(dev) set_bit(0, &dev->tbusy)#define late_stop_netif_stop_queue(dev) {do{} while(0);}#define early_stop_netif_stop_queue(dev) test_and_set_bit(0,&dev->tbusy)#define early_stop_netif_wake_queue(dev) netif_wake_queue(dev)static inline void netif_start_queue(struct net_device *dev){ dev->tbusy = 0; dev->interrupt = 0; dev->start = 1;}#define ace_mark_net_bh() mark_bh(NET_BH)#define netif_queue_stopped(dev) dev->tbusy#define netif_running(dev) dev->start#define ace_if_down(dev) {do{dev->start = 0;} while(0);}#define tasklet_struct tq_structstatic inline void tasklet_schedule(struct tasklet_struct *tasklet){ queue_task(tasklet, &tq_immediate); mark_bh(IMMEDIATE_BH);}static inline void tasklet_init(struct tasklet_struct *tasklet, void (*func)(unsigned long), unsigned long data){ tasklet->next = NULL; tasklet->sync = 0; tasklet->routine = (void (*)(void *))func; tasklet->data = (void *)data;}#define tasklet_kill(tasklet) {do{} while(0);}#else#define late_stop_netif_stop_queue(dev) netif_stop_queue(dev)#define early_stop_netif_stop_queue(dev) 0#define early_stop_netif_wake_queue(dev) {do{} while(0);}#define ace_mark_net_bh() {do{} while(0);}#define ace_if_down(dev) {do{} while(0);}#endif#if (LINUX_VERSION_CODE >= 0x02031b)#define NEW_NETINIT#define ACE_PROBE_ARG void#else#define ACE_PROBE_ARG struct net_device *dev#endif#define ACE_MAX_MOD_PARMS 8#define BOARD_IDX_STATIC 0#define BOARD_IDX_OVERFLOW -1#include "acenic_np.h"/* * These must be defined before the firmware is included. */#define MAX_TEXT_LEN 96*1024#define MAX_RODATA_LEN 8*1024#define MAX_DATA_LEN 2*1024#include "acenic_firmware.h"/* * This driver currently supports Tigon I and Tigon II based cards * including the Alteon AceNIC, the 3Com 3C985[B] and NetGear * GA620. The driver should also work on the SGI, DEC and Farallon * versions of the card, however I have not been able to test that * myself. * * This card is really neat, it supports receive hardware checksumming * and jumbo frames (up to 9000 bytes) and does a lot of work in the * firmware. Also the programming interface is quite neat, except for * the parts dealing with the i2c eeprom on the card ;-) * * Using jumbo frames: * * To enable jumbo frames, simply specify an mtu between 1500 and 9000 * bytes to ifconfig. Jumbo frames can be enabled or disabled at any time * by running `ifconfig eth<X> mtu <MTU>' with <X> being the Ethernet * interface number and <MTU> being the MTU value. * * Module parameters: * * When compiled as a loadable module, the driver allows for a number * of module parameters to be specified. The driver supports the * following module parameters: * * trace=<val> - Firmware trace level. This requires special traced * firmware to replace the firmware supplied with * the driver - for debugging purposes only. * * link=<val> - Link state. Normally you want to use the default link * parameters set by the driver. This can be used to * override these in case your switch doesn't negotiate * the link properly. Valid values are: * 0x0001 - Force half duplex link. * 0x0002 - Do not negotiate line speed with the other end. * 0x0010 - 10Mbit/sec link. * 0x0020 - 100Mbit/sec link. * 0x0040 - 1000Mbit/sec link. * 0x0100 - Do not negotiate flow control. * 0x0200 - Enable RX flow control Y * 0x0400 - Enable TX flow control Y (Tigon II NICs only). * Default value is 0x0270, ie. enable link+flow * control negotiation. Negotiating the highest * possible link speed with RX flow control enabled. * * When disabling link speed negotiation, only one link * speed is allowed to be specified! * * tx_coal_tick=<val> - number of coalescing clock ticks (us) allowed * to wait for more packets to arive before * interrupting the host, from the time the first * packet arrives. * * rx_coal_tick=<val> - number of coalescing clock ticks (us) allowed * to wait for more packets to arive in the transmit ring, * before interrupting the host, after transmitting the * first packet in the ring. * * max_tx_desc=<val> - maximum number of transmit descriptors * (packets) transmitted before interrupting the host. * * max_rx_desc=<val> - maximum number of receive descriptors * (packets) received before interrupting the host. * * tx_ratio=<val> - 7 bit value (0 - 63) specifying the split in 64th * increments of the NIC's on board memory to be used for * transmit and receive buffers. For the 1MB NIC app. 800KB * is available, on the 1/2MB NIC app. 300KB is available. * 68KB will always be available as a minimum for both * directions. The default value is a 50/50 split. * dis_pci_mem_inval=<val> - disable PCI memory write and invalidate * operations, default (1) is to always disable this as * that is what Alteon does on NT. I have not been able * to measure any real performance differences with * this on my systems. Set <val>=0 if you want to * enable these operations. * * If you use more than one NIC, specify the parameters for the * individual NICs with a comma, ie. trace=0,0x00001fff,0 you want to * run tracing on NIC #2 but not on NIC #1 and #3. * * TODO: * * - Proper multicast support. * - NIC dump support. * - More tuning parameters. * * The mini ring is not used under Linux and I am not sure it makes sense * to actually use it. * * New interrupt handler strategy: * * The old interrupt handler worked using the traditional method of * replacing an skbuff with a new one when a packet arrives. However * the rx rings do not need to contain a static number of buffer * descriptors, thus it makes sense to move the memory allocation out * of the main interrupt handler and do it in a bottom half handler * and only allocate new buffers when the number of buffers in the * ring is below a certain threshold. In order to avoid starving the * NIC under heavy load it is however necessary to force allocation * when hitting a minimum threshold. The strategy for alloction is as * follows: * * RX_LOW_BUF_THRES - allocate buffers in the bottom half * RX_PANIC_LOW_THRES - we are very low on buffers, allocate * the buffers in the interrupt handler * RX_RING_THRES - maximum number of buffers in the rx ring * RX_MINI_THRES - maximum number of buffers in the mini ring * RX_JUMBO_THRES - maximum number of buffers in the jumbo ring * * One advantagous side effect of this allocation approach is that the * entire rx processing can be done without holding any spin lock * since the rx rings and registers are totally independant of the tx * ring and its registers. This of course includes the kmalloc's of * new skb's. Thus start_xmit can run in parallel with rx processing * and the memory allocation on SMP systems. * * Note that running the skb reallocation in a bottom half opens up * another can of races which needs to be handled properly. In * particular it can happen that the interrupt handler tries to run * the reallocation while the bottom half is either running on another * CPU or was interrupted on the same CPU. To get around this the * driver uses bitops to prevent the reallocation routines from being * reentered. * * TX handling can also be done without holding any spin lock, wheee * this is fun! since tx_ret_csm is only written to by the interrupt * handler. The case to be aware of is when shutting down the device * and cleaning up where it is necessary to make sure that * start_xmit() is not running while this is happening. Well DaveM * informs me that this case is already protected against ... bye bye * Mr. Spin Lock, it was nice to know you. * * TX interrupts are now partly disabled so the NIC will only generate * TX interrupts for the number of coal ticks, not for the number of * TX packets in the queue. This should reduce the number of TX only, * ie. when no RX processing is done, interrupts seen. *//* * Threshold values for RX buffer allocation - the low water marks for * when to start refilling the rings are set to 75% of the ring * sizes. It seems to make sense to refill the rings entirely from the * intrrupt handler once it gets below the panic threshold, that way * we don't risk that the refilling is moved to another CPU when the * one running the interrupt handler just got the slab code hot in its * cache. */#define RX_RING_SIZE 128#define RX_MINI_SIZE 128#define RX_JUMBO_SIZE 48#define RX_PANIC_STD_THRES 16#define RX_PANIC_STD_REFILL (3*RX_PANIC_STD_THRES)/2#define RX_LOW_STD_THRES (3*RX_RING_SIZE)/4#define RX_PANIC_MINI_THRES 12
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -