📄 tulip_core.c
字号:
/* 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 + -