⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tulip_core.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. *//*	Maintained by Jeff Garzik <jgarzik@pobox.com>	Copyright 2000,2001  The Linux Kernel Team	Written/copyright 1994-2001 by Donald Becker.	This software may be used and distributed according to the terms	of the GNU General Public License, incorporated herein by reference.	Please refer to Documentation/DocBook/tulip-user.{pdf,ps,html}	for more information on this driver, or visit the project	Web page at http://sourceforge.net/projects/tulip/*/#include <linux/config.h>#define DRV_NAME	"tulip"#ifdef CONFIG_TULIP_NAPI#define DRV_VERSION    "1.1.13-NAPI" /* Keep at least for test */#else#define DRV_VERSION	"1.1.13"#endif#define DRV_RELDATE	"May 11, 2002"#include <linux/module.h>#include <linux/pci.h>#include "tulip.h"#include <linux/init.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include <linux/mii.h>#include <linux/ethtool.h>#include <linux/crc32.h>#include <asm/unaligned.h>#include <asm/uaccess.h>#ifdef __sparc__#include <asm/pbm.h>#endifstatic char version[] __devinitdata =	"Linux Tulip driver version " DRV_VERSION " (" DRV_RELDATE ")\n";/* A few user-configurable values. *//* Maximum events (Rx packets, etc.) to handle at each interrupt. */static unsigned int max_interrupt_work = 25;#define MAX_UNITS 8/* Used to pass the full-duplex flag, etc. */static int full_duplex[MAX_UNITS];static int options[MAX_UNITS];static int mtu[MAX_UNITS];			/* Jumbo MTU for interfaces. *//*  The possible media types that can be set in options[] are: */const char * const medianame[32] = {	"10baseT", "10base2", "AUI", "100baseTx",	"10baseT-FDX", "100baseTx-FDX", "100baseT4", "100baseFx",	"100baseFx-FDX", "MII 10baseT", "MII 10baseT-FDX", "MII",	"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FDX", "MII 100baseT4",	"MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "Invalid-19",	"","","","", "","","","",  "","","","Transceiver reset",};/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \	|| defined(__sparc_) || defined(__ia64__) \	|| defined(__sh__) || defined(__mips__)static int rx_copybreak = 1518;#elsestatic int rx_copybreak = 100;#endif/*  Set the bus performance register.	Typical: Set 16 longword cache alignment, no burst limit.	Cache alignment bits 15:14	     Burst length 13:8		0000	No alignment  0x00000000 unlimited		0800 8 longwords		4000	8  longwords		0100 1 longword		1000 16 longwords		8000	16 longwords		0200 2 longwords	2000 32 longwords		C000	32  longwords		0400 4 longwords	Warning: many older 486 systems are broken and require setting 0x00A04800	   8 longword cache alignment, 8 longword burst.	ToDo: Non-Intel setting could be better.*/#if defined(__alpha__) || defined(__ia64__)static int csr0 = 0x01A00000 | 0xE000;#elif defined(__i386__) || defined(__powerpc__) || defined(__x86_64__)static int csr0 = 0x01A00000 | 0x8000;#elif defined(__sparc__) || defined(__hppa__)/* The UltraSparc PCI controllers will disconnect at every 64-byte * crossing anyways so it makes no sense to tell Tulip to burst * any more than that. */static int csr0 = 0x01A00000 | 0x9000;#elif defined(__arm__) || defined(__sh__)static int csr0 = 0x01A00000 | 0x4800;#elif defined(__mips__)static int csr0 = 0x00200000 | 0x4000;#else#warning Processor architecture undefined!static int csr0 = 0x00A00000 | 0x4800;#endif/* Operational parameters that usually are not changed. *//* Time in jiffies before concluding the transmitter is hung. */#define TX_TIMEOUT  (4*HZ)MODULE_AUTHOR("The Linux Kernel Team");MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_VERSION);module_param(tulip_debug, int, 0);module_param(max_interrupt_work, int, 0);module_param(rx_copybreak, int, 0);module_param(csr0, int, 0);module_param_array(options, int, NULL, 0);module_param_array(full_duplex, int, NULL, 0);#define PFX DRV_NAME ": "#ifdef TULIP_DEBUGint tulip_debug = TULIP_DEBUG;#elseint tulip_debug = 1;#endif/* * This table use during operation for capabilities and media timer. * * It is indexed via the values in 'enum chips' */struct tulip_chip_table tulip_tbl[] = {  { }, /* placeholder for array, slot unused currently */  { }, /* placeholder for array, slot unused currently */  /* DC21140 */  { "Digital DS21140 Tulip", 128, 0x0001ebef,	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer },  /* DC21142, DC21143 */  { "Digital DS21143 Tulip", 128, 0x0801fbff,	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY	| HAS_INTR_MITIGATION | HAS_PCI_MWI, t21142_timer },  /* LC82C168 */  { "Lite-On 82c168 PNIC", 256, 0x0001fbef,	HAS_MII | HAS_PNICNWAY, pnic_timer },  /* MX98713 */  { "Macronix 98713 PMAC", 128, 0x0001ebef,	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },  /* MX98715 */  { "Macronix 98715 PMAC", 256, 0x0001ebef,	HAS_MEDIA_TABLE, mxic_timer },  /* MX98725 */  { "Macronix 98725 PMAC", 256, 0x0001ebef,	HAS_MEDIA_TABLE, mxic_timer },  /* AX88140 */  { "ASIX AX88140", 128, 0x0001fbff,	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY	| IS_ASIX, tulip_timer },  /* PNIC2 */  { "Lite-On PNIC-II", 256, 0x0801fbff,	HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer },  /* COMET */  { "ADMtek Comet", 256, 0x0001abef,	HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },  /* COMPEX9881 */  { "Compex 9881 PMAC", 128, 0x0001ebef,	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },  /* I21145 */  { "Intel DS21145 Tulip", 128, 0x0801fbff,	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI	| HAS_NWAY | HAS_PCI_MWI, t21142_timer },  /* DM910X */  { "Davicom DM9102/DM9102A", 128, 0x0001ebef,	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,	tulip_timer },  /* RS7112 */  { "Conexant LANfinity", 256, 0x0001ebef,	HAS_MII | HAS_ACPI, tulip_timer },};static struct pci_device_id tulip_pci_tbl[] = {	{ 0x1011, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21140 },	{ 0x1011, 0x0019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21143 },	{ 0x11AD, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, LC82C168 },	{ 0x10d9, 0x0512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98713 },	{ 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },/*	{ 0x10d9, 0x0531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98725 },*/	{ 0x125B, 0x1400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AX88140 },	{ 0x11AD, 0xc115, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PNIC2 },	{ 0x1317, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1317, 0x0985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1317, 0x1985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1317, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x13D1, 0xAB02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x13D1, 0xAB03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x13D1, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x104A, 0x0981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x104A, 0x2774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1259, 0xa120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x11F6, 0x9881, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMPEX9881 },	{ 0x8086, 0x0039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, I21145 },	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },	{ 0x1113, 0x1216, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1113, 0x1217, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MX98715 },	{ 0x1113, 0x9511, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1186, 0x1541, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1186, 0x1561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1186, 0x1591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x1737, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */	{ 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */	{ 0x1414, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	{ } /* terminate list */};MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);/* A full-duplex map for media types. */const char tulip_media_cap[32] ={0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20,  28,31,0,0, };static void tulip_tx_timeout(struct net_device *dev);static void tulip_init_ring(struct net_device *dev);static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);static int tulip_open(struct net_device *dev);static int tulip_close(struct net_device *dev);static void tulip_up(struct net_device *dev);static void tulip_down(struct net_device *dev);static struct net_device_stats *tulip_get_stats(struct net_device *dev);static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);static void set_rx_mode(struct net_device *dev);#ifdef CONFIG_NET_POLL_CONTROLLERstatic void poll_tulip(struct net_device *dev);#endifstatic void tulip_set_power_state (struct tulip_private *tp,				   int sleep, int snooze){	if (tp->flags & HAS_ACPI) {		u32 tmp, newtmp;		pci_read_config_dword (tp->pdev, CFDD, &tmp);		newtmp = tmp & ~(CFDD_Sleep | CFDD_Snooze);		if (sleep)			newtmp |= CFDD_Sleep;		else if (snooze)			newtmp |= CFDD_Snooze;		if (tmp != newtmp)			pci_write_config_dword (tp->pdev, CFDD, newtmp);	}}static void tulip_up(struct net_device *dev){	struct tulip_private *tp = netdev_priv(dev);	void __iomem *ioaddr = tp->base_addr;	int next_tick = 3*HZ;	int i;	/* Wake the chip from sleep/snooze mode. */	tulip_set_power_state (tp, 0, 0);	/* On some chip revs we must set the MII/SYM port before the reset!? */	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))		iowrite32(0x00040000, ioaddr + CSR6);	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */	iowrite32(0x00000001, ioaddr + CSR0);	udelay(100);	/* Deassert reset.	   Wait the specified 50 PCI cycles after a reset by initializing	   Tx and Rx queues and the address filter list. */	iowrite32(tp->csr0, ioaddr + CSR0);	udelay(100);	if (tulip_debug > 1)		printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);	iowrite32(tp->rx_ring_dma, ioaddr + CSR3);	iowrite32(tp->tx_ring_dma, ioaddr + CSR4);	tp->cur_rx = tp->cur_tx = 0;	tp->dirty_rx = tp->dirty_tx = 0;	if (tp->flags & MC_HASH_ONLY) {		u32 addr_low = le32_to_cpu(get_unaligned((u32 *)dev->dev_addr));		u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4)));		if (tp->chip_id == AX88140) {			iowrite32(0, ioaddr + CSR13);			iowrite32(addr_low,  ioaddr + CSR14);			iowrite32(1, ioaddr + CSR13);			iowrite32(addr_high, ioaddr + CSR14);		} else if (tp->flags & COMET_MAC_ADDR) {			iowrite32(addr_low,  ioaddr + 0xA4);			iowrite32(addr_high, ioaddr + 0xA8);			iowrite32(0, ioaddr + 0xAC);			iowrite32(0, ioaddr + 0xB0);		}	} else {		/* This is set_rx_mode(), but without starting the transmitter. */		u16 *eaddrs = (u16 *)dev->dev_addr;		u16 *setup_frm = &tp->setup_frame[15*6];		dma_addr_t mapping;		/* 21140 bug: you must add the broadcast address. */		memset(tp->setup_frame, 0xff, sizeof(tp->setup_frame));		/* Fill the final entry of the table with our physical address. */		*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];		*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];		*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];		mapping = pci_map_single(tp->pdev, tp->setup_frame,					 sizeof(tp->setup_frame),					 PCI_DMA_TODEVICE);		tp->tx_buffers[tp->cur_tx].skb = NULL;		tp->tx_buffers[tp->cur_tx].mapping = mapping;		/* Put the setup frame on the Tx list. */		tp->tx_ring[tp->cur_tx].length = cpu_to_le32(0x08000000 | 192);		tp->tx_ring[tp->cur_tx].buffer1 = cpu_to_le32(mapping);		tp->tx_ring[tp->cur_tx].status = cpu_to_le32(DescOwned);		tp->cur_tx++;	}	tp->saved_if_port = dev->if_port;	if (dev->if_port == 0)		dev->if_port = tp->default_port;	/* Allow selecting a default media. */	i = 0;	if (tp->mtable == NULL)		goto media_picked;	if (dev->if_port) {		int looking_for = tulip_media_cap[dev->if_port] & MediaIsMII ? 11 :			(dev->if_port == 12 ? 0 : dev->if_port);		for (i = 0; i < tp->mtable->leafcount; i++)			if (tp->mtable->mleaf[i].media == looking_for) {				printk(KERN_INFO "%s: Using user-specified media %s.\n",					   dev->name, medianame[dev->if_port]);				goto media_picked;			}	}	if ((tp->mtable->defaultmedia & 0x0800) == 0) {		int looking_for = tp->mtable->defaultmedia & MEDIA_MASK;		for (i = 0; i < tp->mtable->leafcount; i++)			if (tp->mtable->mleaf[i].media == looking_for) {				printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",					   dev->name, medianame[looking_for]);				goto media_picked;			}	}	/* Start sensing first non-full-duplex media. */	for (i = tp->mtable->leafcount - 1;		 (tulip_media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)		;media_picked:	tp->csr6 = 0;	tp->cur_index = i;	tp->nwayset = 0;	if (dev->if_port) {		if (tp->chip_id == DC21143  &&		    (tulip_media_cap[dev->if_port] & MediaIsMII)) {			/* We must reset the media CSRs when we force-select MII mode. */			iowrite32(0x0000, ioaddr + CSR13);			iowrite32(0x0000, ioaddr + CSR14);			iowrite32(0x0008, ioaddr + CSR15);		}		tulip_select_media(dev, 1);	} else if (tp->chip_id == DC21142) {		if (tp->mii_cnt) {			tulip_select_media(dev, 1);			if (tulip_debug > 1)				printk(KERN_INFO "%s: Using MII transceiver %d, status "					   "%4.4x.\n",					   dev->name, tp->phys[0], tulip_mdio_read(dev, tp->phys[0], 1));			iowrite32(csr6_mask_defstate, ioaddr + CSR6);			tp->csr6 = csr6_mask_hdcap;			dev->if_port = 11;			iowrite32(0x0000, ioaddr + CSR13);			iowrite32(0x0000, ioaddr + CSR14);		} else			t21142_start_nway(dev);	} else if (tp->chip_id == PNIC2) {	        /* for initial startup advertise 10/100 Full and Half */	        tp->sym_advertise = 0x01E0;                /* enable autonegotiate end interrupt */	        iowrite32(ioread32(ioaddr+CSR5)| 0x00008010, ioaddr + CSR5);	        iowrite32(ioread32(ioaddr+CSR7)| 0x00008010, ioaddr + CSR7);		pnic2_start_nway(dev);	} else if (tp->chip_id == LC82C168  &&  ! tp->medialock) {		if (tp->mii_cnt) {			dev->if_port = 11;			tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);			iowrite32(0x0001, ioaddr + CSR15);		} else if (ioread32(ioaddr + CSR5) & TPLnkPass)			pnic_do_nway(dev);		else {			/* Start with 10mbps to do autonegotiation. */			iowrite32(0x32, ioaddr + CSR12);			tp->csr6 = 0x00420000;			iowrite32(0x0001B078, ioaddr + 0xB8);			iowrite32(0x0201B078, ioaddr + 0xB8);			next_tick = 1*HZ;		}	} else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)			   && ! tp->medialock) {		dev->if_port = 0;		tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);		iowrite32(0x0f370000 | ioread16(ioaddr + 0x80), ioaddr + 0x80);	} else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {		/* Provided by BOLO, Macronix - 12/10/1998. */		dev->if_port = 0;		tp->csr6 = 0x01a80200;		iowrite32(0x0f370000 | ioread16(ioaddr + 0x80), ioaddr + 0x80);		iowrite32(0x11000 | ioread16(ioaddr + 0xa0), ioaddr + 0xa0);	} else if (tp->chip_id == COMET || tp->chip_id == CONEXANT) {		/* Enable automatic Tx underrun recovery. */		iowrite32(ioread32(ioaddr + 0x88) | 1, ioaddr + 0x88);		dev->if_port = tp->mii_cnt ? 11 : 0;		tp->csr6 = 0x00040000;	} else if (tp->chip_id == AX88140) {		tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;	} else		tulip_select_media(dev, 1);	/* Start the chip's Tx to process setup frame. */	tulip_stop_rxtx(tp);	barrier();	udelay(5);	iowrite32(tp->csr6 | TxOn, ioaddr + CSR6);	/* Enable interrupts by setting the interrupt mask. */	iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);	iowrite32(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);	tulip_start_rxtx(tp);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -