typhoon.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,314 行 · 第 1/5 页
C
2,314 行
/* typhoon.c: A Linux Ethernet device driver for 3Com 3CR990 family of NICs *//* Written 2002-2003 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. *) I've not tested multicast. I think it works, but reports welcome. *) Doesn't do IPSEC offloading. Yet. Keep yer pants on, it's coming.*//* Set the copy breakpoint for the copy-only-tiny-frames scheme. * Setting to > 1518 effectively disables this feature. */static int rx_copybreak = 200;/* 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.3"#define DRV_MODULE_RELDATE "03/12/15"#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/init.h>#include <linux/delay.h>#include <linux/ethtool.h>#include <linux/if_vlan.h>#include <linux/crc32.h>#include <asm/processor.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/in6.h>#include <asm/checksum.h>#include <linux/version.h>#include "typhoon.h"#include "typhoon-firmware.h"static char version[] __devinitdata = "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";MODULE_AUTHOR("David Dillow <dave@thedillows.org>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");MODULE_PARM(rx_copybreak, "i");#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 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 capabilites: (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; 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; u16 xcvr_select; u16 wol_events; u32 offload; u32 pci_state[16]; /* 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 { readl(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)#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)#define typhoon_synchronize_irq(x) synchronize_irq()#else#define typhoon_synchronize_irq(x) synchronize_irq(x)#endif#if defined(NETIF_F_TSO)#define skb_tso_size(x) (skb_shinfo(x)->tso_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; writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); writel(TYPHOON_RESET_ALL, ioaddr + TYPHOON_REG_SOFT_RESET); typhoon_post_pci_writes(ioaddr); udelay(1); writel(TYPHOON_RESET_NONE, ioaddr + TYPHOON_REG_SOFT_RESET); if(wait_type != NoWait) { for(i = 0; i < timeout; i++) { if(readl(ioaddr + TYPHOON_REG_STATUS) == TYPHOON_STATUS_WAITING_FOR_HOST) goto out; if(wait_type == WaitSleep) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(1); } else udelay(TYPHOON_UDELAY); } err = -ETIMEDOUT; }out: writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); writel(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_STATUS); udelay(100); return err; /* 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 -- with a 50usec delay, it survives * 35000 typhoon_init_one() calls, where it only make it 25-100 * without it. * * As it turns out, still occasionally getting a hung adapter, * so I'm bumping it to 100us. */}static inttyphoon_wait_status(void __iomem *ioaddr, u32 wait_value){ int i, err = 0; for(i = 0; i < TYPHOON_WAIT_TIMEOUT; i++) { if(readl(ioaddr + TYPHOON_REG_STATUS) == wait_value) goto out; udelay(TYPHOON_UDELAY); } err = -ETIMEDOUT;out: return err;}static inline voidtyphoon_media_status(struct net_device *dev, struct resp_desc *resp){ if(resp->parm1 & TYPHOON_MEDIA_STAT_NO_LINK) netif_carrier_off(dev); else netif_carrier_on(dev);}static inline voidtyphoon_hello(struct typhoon *tp){ struct basic_ring *ring = &tp->cmdRing; struct cmd_desc *cmd; /* We only get a hello request if we've not sent anything to the * card in a long while. If the lock is held, then we're in the
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?