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

📄 tulip_core.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. *//*	Maintained by Jeff Garzik <jgarzik@pobox.com>	Copyright 2000-2002  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.{pdf,ps,html}	for more information on this driver, or visit the project	Web page at http://sourceforge.net/projects/tulip/*/#define DRV_NAME	"tulip"#define DRV_VERSION	"0.9.15-pre12"#define DRV_RELDATE	"Aug 9, 2002"#include <linux/config.h>#include <linux/module.h>#include "tulip.h"#include <linux/pci.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__) || defined(__SH5__)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__) || defined(__x86_64__)static int csr0 = 0x01A00000 | 0xE000;#elif defined(__i386__) || defined(__powerpc__)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_PARM(tulip_debug, "i");MODULE_PARM(max_interrupt_work, "i");MODULE_PARM(rx_copybreak, "i");MODULE_PARM(csr0, "i");MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");#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[] = {  /* DC21040 */  { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },  /* DC21041 */  { "Digital DC21041 Tulip", 128, 0x0001ebef,	HAS_MEDIA_TABLE | HAS_NWAY, tulip_timer },  /* 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 },  /* CONEXANT */  {	"Conexant LANfinity", 256, 0x0001ebef,	HAS_MII, tulip_timer },};static struct pci_device_id tulip_pci_tbl[] __devinitdata = {	{ 0x1011, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21040 },	{ 0x1011, 0x0014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DC21041 },	{ 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 },	{ 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 },	{ 0x14f1, 0x1803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CONEXANT },	{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },	/* ALi 1563 integrated ethernet */	{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },	/* 3Com 3CSOHO100B-TX */	{ } /* 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, };u8 t21040_csr13[] = {2,0x0C,8,4,  4,0,0,0, 0,0,0,0, 4,0,0,0};/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/u16 t21041_csr13[] = {	csr13_mask_10bt,		/* 10-T */	csr13_mask_auibnc,		/* 10-2 */	csr13_mask_auibnc,		/* AUI */	csr13_mask_10bt,		/* 10-T */	csr13_mask_10bt,		/* 10T-FD */};u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };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);static 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 = (struct tulip_private *)dev->priv;	long ioaddr = dev->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))		outl(0x00040000, ioaddr + CSR6);	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */	outl(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. */	outl(tp->csr0, ioaddr + CSR0);	udelay(100);	if (tulip_debug > 1)		printk(KERN_DEBUG "%s: tulip_up(), irq==%d.\n", dev->name, dev->irq);	outl(tp->rx_ring_dma, ioaddr + CSR3);	outl(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) {			outl(0, ioaddr + CSR13);			outl(addr_low,  ioaddr + CSR14);			outl(1, ioaddr + CSR13);			outl(addr_high, ioaddr + CSR14);		} else if (tp->flags & COMET_MAC_ADDR) {			outl(addr_low,  ioaddr + 0xA4);			outl(addr_high, ioaddr + 0xA8);			outl(0, ioaddr + 0xAC);			outl(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. */			outl(0x0000, ioaddr + CSR13);			outl(0x0000, ioaddr + CSR14);			outl(0x0008, ioaddr + CSR15);		}		tulip_select_media(dev, 1);	} else if (tp->chip_id == DC21041) {		dev->if_port = 0;		tp->nway = tp->mediasense = 1;		tp->nwayset = tp->lpar = 0;		outl(0x00000000, ioaddr + CSR13);		outl(0xFFFFFFFF, ioaddr + CSR14);		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */		tp->csr6 = 0x80020000;		if (tp->sym_advertise & 0x0040)			tp->csr6 |= FullDuplex;		outl(tp->csr6, ioaddr + CSR6);		outl(0x0000EF01, ioaddr + CSR13);	} 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));			outl(csr6_mask_defstate, ioaddr + CSR6);			tp->csr6 = csr6_mask_hdcap;			dev->if_port = 11;			outl(0x0000, ioaddr + CSR13);			outl(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 */	        outl(inl(ioaddr+CSR5)| 0x00008010, ioaddr + CSR5);	        outl(inl(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);			outl(0x0001, ioaddr + CSR15);		} else if (inl(ioaddr + CSR5) & TPLnkPass)			pnic_do_nway(dev);		else {			/* Start with 10mbps to do autonegotiation. */			outl(0x32, ioaddr + CSR12);			tp->csr6 = 0x00420000;			outl(0x0001B078, ioaddr + 0xB8);			outl(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);		outl(0x0f370000 | inw(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;		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);		outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);	} else if (tp->chip_id == COMET || tp->chip_id == CONEXANT) {		/* Enable automatic Tx underrun recovery. */		outl(inl(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);	outl(tp->csr6 | TxOn, ioaddr + CSR6);	/* Enable interrupts by setting the interrupt mask. */

⌨️ 快捷键说明

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