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