typhoon.c
来自「linux 内核源代码」· C语言 代码 · 共 2,282 行 · 第 1/5 页
C
2,282 行
/* typhoon.c: A Linux Ethernet device driver for 3Com 3CR990 family of NICs *//* Written 2002-2004 by David Dillow <dave@thedillows.org> Based on code written 1998-2000 by Donald Becker <becker@scyld.com> and Linux 2.2.x driver by David P. McLean <davidpmclean@yahoo.com>. This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. Drivers based on or derived from this code fall under the GPL and must retain the authorship, copyright and license notice. This file is not a complete program and may only be used when the entire operating system is licensed under the GPL. This software is available on a public web site. It may enable cryptographic capabilities of the 3Com hardware, and may be exported from the United States under License Exception "TSU" pursuant to 15 C.F.R. Section 740.13(e). This work was funded by the National Library of Medicine under the Department of Energy project number 0274DD06D1 and NLM project number Y1-LM-2015-01. This driver is designed for the 3Com 3CR990 Family of cards with the 3XP Processor. It has been tested on x86 and sparc64. KNOWN ISSUES: *) The current firmware always strips the VLAN tag off, even if we tell it not to. You should filter VLANs at the switch as a workaround (good practice in any event) until we can get this fixed. *) Cannot DMA Rx packets to a 2 byte aligned address. Also firmware issue. Hopefully 3Com will fix it. *) Waiting for a command response takes 8ms due to non-preemptable polling. Only significant for getting stats and creating SAs, but an ugly wart never the less. TODO: *) Doesn't do IPSEC offloading. Yet. Keep yer pants on, it's coming. *) Add more support for ethtool (especially for NIC stats) *) Allow disabling of RX checksum offloading *) Fix MAC changing to work while the interface is up (Need to put commands on the TX ring, which changes the locking) *) Add in FCS to {rx,tx}_bytes, since the hardware doesn't. See http://oss.sgi.com/cgi-bin/mesg.cgi?a=netdev&i=20031215152211.7003fe8e.rddunlap%40osdl.org*//* Set the copy breakpoint for the copy-only-tiny-frames scheme. * Setting to > 1518 effectively disables this feature. */static int rx_copybreak = 200;/* Should we use MMIO or Port IO? * 0: Port IO * 1: MMIO * 2: Try MMIO, fallback to Port IO */static unsigned int use_mmio = 2;/* end user-configurable values *//* Maximum number of multicast addresses to filter (vs. rx-all-multicast). */static const int multicast_filter_limit = 32;/* Operational parameters that are set at compile time. *//* Keep the ring sizes a power of two for compile efficiency. * The compiler will convert <unsigned>'%'<2^N> into a bit mask. * Making the Tx ring too large decreases the effectiveness of channel * bonding and packet priority. * There are no ill effects from too-large receive rings. * * We don't currently use the Hi Tx ring so, don't make it very big. * * Beware that if we start using the Hi Tx ring, we will need to change * typhoon_num_free_tx() and typhoon_tx_complete() to account for that. */#define TXHI_ENTRIES 2#define TXLO_ENTRIES 128#define RX_ENTRIES 32#define COMMAND_ENTRIES 16#define RESPONSE_ENTRIES 32#define COMMAND_RING_SIZE (COMMAND_ENTRIES * sizeof(struct cmd_desc))#define RESPONSE_RING_SIZE (RESPONSE_ENTRIES * sizeof(struct resp_desc))/* The 3XP will preload and remove 64 entries from the free buffer * list, and we need one entry to keep the ring from wrapping, so * to keep this a power of two, we use 128 entries. */#define RXFREE_ENTRIES 128#define RXENT_ENTRIES (RXFREE_ENTRIES - 1)/* Operational parameters that usually are not changed. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT (2*HZ)#define PKT_BUF_SZ 1536#define DRV_MODULE_NAME "typhoon"#define DRV_MODULE_VERSION "1.5.8"#define DRV_MODULE_RELDATE "06/11/09"#define PFX DRV_MODULE_NAME ": "#define ERR_PFX KERN_ERR PFX#include <linux/module.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/mm.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/ethtool.h>#include <linux/if_vlan.h>#include <linux/crc32.h>#include <linux/bitops.h>#include <asm/processor.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/in6.h>#include <linux/version.h>#include <linux/dma-mapping.h>#include "typhoon.h"#include "typhoon-firmware.h"static const char version[] __devinitdata = "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";MODULE_AUTHOR("David Dillow <dave@thedillows.org>");MODULE_VERSION(DRV_MODULE_VERSION);MODULE_LICENSE("GPL");MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and " "the buffer given back to the NIC. Default " "is 200.");MODULE_PARM_DESC(use_mmio, "Use MMIO (1) or PIO(0) to access the NIC. " "Default is to try MMIO and fallback to PIO.");module_param(rx_copybreak, int, 0);module_param(use_mmio, int, 0);#if defined(NETIF_F_TSO) && MAX_SKB_FRAGS > 32#warning Typhoon only supports 32 entries in its SG list for TSO, disabling TSO#undef NETIF_F_TSO#endif#if TXLO_ENTRIES <= (2 * MAX_SKB_FRAGS)#error TX ring too small!#endifstruct typhoon_card_info { char *name; int capabilities;};#define TYPHOON_CRYPTO_NONE 0x00#define TYPHOON_CRYPTO_DES 0x01#define TYPHOON_CRYPTO_3DES 0x02#define TYPHOON_CRYPTO_VARIABLE 0x04#define TYPHOON_FIBER 0x08#define TYPHOON_WAKEUP_NEEDS_RESET 0x10enum typhoon_cards { TYPHOON_TX = 0, TYPHOON_TX95, TYPHOON_TX97, TYPHOON_SVR, TYPHOON_SVR95, TYPHOON_SVR97, TYPHOON_TXM, TYPHOON_BSVR, TYPHOON_FX95, TYPHOON_FX97, TYPHOON_FX95SVR, TYPHOON_FX97SVR, TYPHOON_FXM,};/* directly indexed by enum typhoon_cards, above */static const struct typhoon_card_info typhoon_card_info[] __devinitdata = { { "3Com Typhoon (3C990-TX)", TYPHOON_CRYPTO_NONE}, { "3Com Typhoon (3CR990-TX-95)", TYPHOON_CRYPTO_DES}, { "3Com Typhoon (3CR990-TX-97)", TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES}, { "3Com Typhoon (3C990SVR)", TYPHOON_CRYPTO_NONE}, { "3Com Typhoon (3CR990SVR95)", TYPHOON_CRYPTO_DES}, { "3Com Typhoon (3CR990SVR97)", TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES}, { "3Com Typhoon2 (3C990B-TX-M)", TYPHOON_CRYPTO_VARIABLE}, { "3Com Typhoon2 (3C990BSVR)", TYPHOON_CRYPTO_VARIABLE}, { "3Com Typhoon (3CR990-FX-95)", TYPHOON_CRYPTO_DES | TYPHOON_FIBER}, { "3Com Typhoon (3CR990-FX-97)", TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER}, { "3Com Typhoon (3CR990-FX-95 Server)", TYPHOON_CRYPTO_DES | TYPHOON_FIBER}, { "3Com Typhoon (3CR990-FX-97 Server)", TYPHOON_CRYPTO_DES | TYPHOON_CRYPTO_3DES | TYPHOON_FIBER}, { "3Com Typhoon2 (3C990B-FX-97)", TYPHOON_CRYPTO_VARIABLE | TYPHOON_FIBER},};/* Notes on the new subsystem numbering scheme: * bits 0-1 indicate crypto capabilities: (0) variable, (1) DES, or (2) 3DES * bit 4 indicates if this card has secured firmware (we don't support it) * bit 8 indicates if this is a (0) copper or (1) fiber card * bits 12-16 indicate card type: (0) client and (1) server */static struct pci_device_id typhoon_pci_tbl[] = { { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990, PCI_ANY_ID, PCI_ANY_ID, 0, 0,TYPHOON_TX }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_95, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_TX95 }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_TX_97, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_TX97 }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B, PCI_ANY_ID, 0x1000, 0, 0, TYPHOON_TXM }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B, PCI_ANY_ID, 0x1102, 0, 0, TYPHOON_FXM }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990B, PCI_ANY_ID, 0x2000, 0, 0, TYPHOON_BSVR }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX, PCI_ANY_ID, 0x1101, 0, 0, TYPHOON_FX95 }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX, PCI_ANY_ID, 0x1102, 0, 0, TYPHOON_FX97 }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX, PCI_ANY_ID, 0x2101, 0, 0, TYPHOON_FX95SVR }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990_FX, PCI_ANY_ID, 0x2102, 0, 0, TYPHOON_FX97SVR }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR95, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR95 }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR97, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR97 }, { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3CR990SVR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPHOON_SVR }, { 0, }};MODULE_DEVICE_TABLE(pci, typhoon_pci_tbl);/* Define the shared memory area * Align everything the 3XP will normally be using. * We'll need to move/align txHi if we start using that ring. */#define __3xp_aligned ____cacheline_alignedstruct typhoon_shared { struct typhoon_interface iface; struct typhoon_indexes indexes __3xp_aligned; struct tx_desc txLo[TXLO_ENTRIES] __3xp_aligned; struct rx_desc rxLo[RX_ENTRIES] __3xp_aligned; struct rx_desc rxHi[RX_ENTRIES] __3xp_aligned; struct cmd_desc cmd[COMMAND_ENTRIES] __3xp_aligned; struct resp_desc resp[RESPONSE_ENTRIES] __3xp_aligned; struct rx_free rxBuff[RXFREE_ENTRIES] __3xp_aligned; u32 zeroWord; struct tx_desc txHi[TXHI_ENTRIES];} __attribute__ ((packed));struct rxbuff_ent { struct sk_buff *skb; dma_addr_t dma_addr;};struct typhoon { /* Tx cache line section */ struct transmit_ring txLoRing ____cacheline_aligned; struct pci_dev * tx_pdev; void __iomem *tx_ioaddr; u32 txlo_dma_addr; /* Irq/Rx cache line section */ void __iomem *ioaddr ____cacheline_aligned; struct typhoon_indexes *indexes; u8 awaiting_resp; u8 duplex; u8 speed; u8 card_state; struct basic_ring rxLoRing; struct pci_dev * pdev; struct net_device * dev; struct napi_struct napi; spinlock_t state_lock; struct vlan_group * vlgrp; struct basic_ring rxHiRing; struct basic_ring rxBuffRing; struct rxbuff_ent rxbuffers[RXENT_ENTRIES]; /* general section */ spinlock_t command_lock ____cacheline_aligned; struct basic_ring cmdRing; struct basic_ring respRing; struct net_device_stats stats; struct net_device_stats stats_saved; const char * name; struct typhoon_shared * shared; dma_addr_t shared_dma; __le16 xcvr_select; __le16 wol_events; __le32 offload; /* unused stuff (future use) */ int capabilities; struct transmit_ring txHiRing;};enum completion_wait_values { NoWait = 0, WaitNoSleep, WaitSleep,};/* These are the values for the typhoon.card_state variable. * These determine where the statistics will come from in get_stats(). * The sleep image does not support the statistics we need. */enum state_values { Sleeping = 0, Running,};/* PCI writes are not guaranteed to be posted in order, but outstanding writes * cannot pass a read, so this forces current writes to post. */#define typhoon_post_pci_writes(x) \ do { if(likely(use_mmio)) ioread32(x+TYPHOON_REG_HEARTBEAT); } while(0)/* We'll wait up to six seconds for a reset, and half a second normally. */#define TYPHOON_UDELAY 50#define TYPHOON_RESET_TIMEOUT_SLEEP (6 * HZ)#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)#define typhoon_synchronize_irq(x) synchronize_irq(x)#if defined(NETIF_F_TSO)#define skb_tso_size(x) (skb_shinfo(x)->gso_size)#define TSO_NUM_DESCRIPTORS 2#define TSO_OFFLOAD_ON TYPHOON_OFFLOAD_TCP_SEGMENT#else#define NETIF_F_TSO 0#define skb_tso_size(x) 0#define TSO_NUM_DESCRIPTORS 0#define TSO_OFFLOAD_ON 0#endifstatic inline voidtyphoon_inc_index(u32 *index, const int count, const int num_entries){ /* Increment a ring index -- we can use this for all rings execept * the Rx rings, as they use different size descriptors * otherwise, everything is the same size as a cmd_desc */ *index += count * sizeof(struct cmd_desc); *index %= num_entries * sizeof(struct cmd_desc);}static inline voidtyphoon_inc_cmd_index(u32 *index, const int count){ typhoon_inc_index(index, count, COMMAND_ENTRIES);}static inline voidtyphoon_inc_resp_index(u32 *index, const int count){ typhoon_inc_index(index, count, RESPONSE_ENTRIES);}static inline voidtyphoon_inc_rxfree_index(u32 *index, const int count){ typhoon_inc_index(index, count, RXFREE_ENTRIES);}static inline voidtyphoon_inc_tx_index(u32 *index, const int count){ /* if we start using the Hi Tx ring, this needs updateing */ typhoon_inc_index(index, count, TXLO_ENTRIES);}static inline voidtyphoon_inc_rx_index(u32 *index, const int count){ /* sizeof(struct rx_desc) != sizeof(struct cmd_desc) */ *index += count * sizeof(struct rx_desc); *index %= RX_ENTRIES * sizeof(struct rx_desc);}static inttyphoon_reset(void __iomem *ioaddr, int wait_type){ int i, err = 0; int timeout; if(wait_type == WaitNoSleep) timeout = TYPHOON_RESET_TIMEOUT_NOSLEEP; else timeout = TYPHOON_RESET_TIMEOUT_SLEEP; iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); iowrite32(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET); typhoon_post_pci_writes(ioaddr); udelay(1); iowrite32(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET); if(wait_type != NoWait) { for(i = 0; i < timeout; i++) { if(ioread32(ioaddr + TYPHOON_REG_STATUS) == TYPHOON_STATUS_WAITING_FOR_HOST) goto out; if(wait_type == WaitSleep) schedule_timeout_uninterruptible(1); else udelay(TYPHOON_UDELAY); } err = -ETIMEDOUT; }out: iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); /* The 3XP seems to need a little extra time to complete the load * of the sleep image before we can reliably boot it. Failure to * do this occasionally results in a hung adapter after boot in * typhoon_init_one() while trying to read the MAC address or * putting the card to sleep. 3Com's driver waits 5ms, but * that seems to be overkill. However, if we can sleep, we might * as well give it that much time. Otherwise, we'll give it 500us, * which should be enough (I've see it work well at 100us, but still * saw occasional problems.) */ if(wait_type == WaitSleep) msleep(5); else udelay(500); return err;}static inttyphoon_wait_status(void __iomem *ioaddr, u32 wait_value){ int i, err = 0; for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) { if(ioread32(ioaddr + TYPHOON_REG_STATUS) == wait_value) goto out; udelay(TYPHOON_UDELAY);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?