📄 tulip.c
字号:
{ "Macronix 98713 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, { "Macronix 98715 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, { "Macronix 98725 PMAC", 256, 0x0001ebef, HAS_MEDIA_TABLE, mxic_timer }, { "ASIX AX88140", 128, 0x0001fbff, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer }, { "Lite-On PNIC-II", 256, 0x0801fbff, HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer }, { "ADMtek Comet", 256, 0x0001abef, MC_HASH_ONLY, comet_timer }, { "Compex 9881 PMAC", 128, 0x0001ebef, HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer }, { "Intel DS21145 Tulip", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143, t21142_timer }, { "Xircom tulip work-alike", 128, 0x0801fbff, HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143, t21142_timer }, {0},};/* This matches the table above. Note 21142 == 21143. */enum chips { DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3, LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881, I21145,};/* A full-duplex map for media types. */enum MediaIs { MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8, MediaIs100=16};static const char media_cap[] ={0,0,0,16, 3,19,16,24, 27,4,7,5, 0,20,23,20 };static 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*/static u16 t21041_csr13[] = { 0xEF05, 0xEF0D, 0xEF0D, 0xEF05, 0xEF05, };static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };/* Offsets to the Command and Status Registers, "CSRs". All accesses must be longword instructions and quadword aligned. */enum tulip_offsets { CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28, CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58, CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };/* The bits in the CSR5 status registers, mostly interrupt sources. */enum status_bits { TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10, NormalIntr=0x10000, AbnormalIntr=0x8000, RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40, TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,};/* The Tulip Rx and Tx buffer descriptors. */struct tulip_rx_desc { s32 status; s32 length; u32 buffer1, buffer2;};struct tulip_tx_desc { s32 status; s32 length; u32 buffer1, buffer2; /* We use only buffer 1. */};enum desc_status_bits { DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,};/* Ring-wrap flag in length field, use for last ring entry. 0x01000000 means chain on buffer2 address, 0x02000000 means use the ring start address in CSR2/3. Note: Some work-alike chips do not function correctly in chained mode. The ASIX chip works only in chained mode. Thus we indicates ring mode, but always write the 'next' field for chained mode as well.*/#define DESC_RING_WRAP 0x02000000#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */struct medialeaf { u8 type; u8 media; unsigned char *leafdata;};struct mediatable { u16 defaultmedia; u8 leafcount, csr12dir; /* General purpose pin directions. */ unsigned has_mii:1, has_nonmii:1, has_reset:6; u32 csr15dir, csr15val; /* 21143 NWay setting. */ struct medialeaf mleaf[0];};struct mediainfo { struct mediainfo *next; int info_type; int index; unsigned char *info;};struct tulip_private { char devname[8]; /* Used only for kernel debugging. */ const char *product_name; struct device *next_module; struct tulip_rx_desc rx_ring[RX_RING_SIZE]; struct tulip_tx_desc tx_ring[TX_RING_SIZE]; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ struct sk_buff* tx_skbuff[TX_RING_SIZE]; /* The addresses of receive-in-place skbuffs. */ struct sk_buff* rx_skbuff[RX_RING_SIZE]; char *rx_buffs; /* Address of temporary Rx buffers. */ u16 setup_frame[96]; /* Pseudo-Tx frame to init address table. */ int chip_id; int revision; int flags; struct net_device_stats stats; struct timer_list timer; /* Media selection timer. */ int interrupt; /* In-interrupt flag. */ unsigned int cur_rx, cur_tx; /* The next free ring entry */ unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ unsigned int tx_full:1; /* The Tx queue is full. */ unsigned int full_duplex:1; /* Full-duplex operation requested. */ unsigned int full_duplex_lock:1; unsigned int fake_addr:1; /* Multiport board faked address. */ unsigned int default_port:4; /* Last dev->if_port value. */ unsigned int media2:4; /* Secondary monitored media port. */ unsigned int medialock:1; /* Don't sense media type. */ unsigned int mediasense:1; /* Media sensing in progress. */ unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */ unsigned int csr0; /* CSR0 setting. */ unsigned int csr6; /* Current CSR6 control settings. */ unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */ void (*link_change)(struct device *dev, int csr5); u16 to_advertise; /* NWay capabilities advertised. */ u16 lpar; /* 21143 Link partner ability. */ u16 advertising[4]; signed char phys[4], mii_cnt; /* MII device addresses. */ struct mediatable *mtable; int cur_index; /* Current media index. */ int saved_if_port; unsigned char pci_bus, pci_devfn; int ttimer; int susp_rx; unsigned long nir; int pad0, pad1; /* Used for 8-byte alignment */};static void parse_eeprom(struct device *dev);static int read_eeprom(long ioaddr, int location, int addr_len);static int mdio_read(struct device *dev, int phy_id, int location);static void mdio_write(struct device *dev, int phy_id, int location, int value);static void select_media(struct device *dev, int startup);static int tulip_open(struct device *dev);/* Chip-specific media selection (timer functions prototyped above). */static void t21142_lnk_change(struct device *dev, int csr5);static void t21142_start_nway(struct device *dev);static void pnic_lnk_change(struct device *dev, int csr5);static void pnic_do_nway(struct device *dev);static void tulip_tx_timeout(struct device *dev);static void tulip_init_ring(struct device *dev);static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);static int tulip_refill_rx(struct device *dev);static int tulip_rx(struct device *dev);static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);static int tulip_close(struct device *dev);static struct net_device_stats *tulip_get_stats(struct device *dev);#ifdef HAVE_PRIVATE_IOCTLstatic int private_ioctl(struct device *dev, struct ifreq *rq, int cmd);#endifstatic void set_rx_mode(struct device *dev);/* A list of all installed Tulip devices. */static struct device *root_tulip_dev = NULL;#ifndef CARDBUSint tulip_probe(struct device *dev){ int cards_found = 0; int pci_index = 0; unsigned char pci_bus, pci_device_fn; if ( ! pcibios_present()) return -ENODEV; for (;pci_index < 0xff; pci_index++) { u16 vendor, device, pci_command, new_command, subvendor; int chip_idx; int irq; long ioaddr; if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, reverse_probe ? 0xfe - pci_index : pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) { if (reverse_probe) continue; else break; } pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); pcibios_read_config_word(pci_bus, pci_device_fn, PCI_SUBSYSTEM_VENDOR_ID, &subvendor); if( subvendor == 0x1376 ){ printk("tulip: skipping LMC card.\n"); continue; } for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++) if (vendor == pci_tbl[chip_idx].vendor_id && (device & pci_tbl[chip_idx].device_id_mask) == pci_tbl[chip_idx].device_id) break; if (pci_tbl[chip_idx].vendor_id == 0) continue; {#if defined(PCI_SUPPORT_VER2) struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & ~3; irq = pdev->irq;#else u32 pci_ioaddr; u8 pci_irq_line; pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_0, &pci_ioaddr); pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &pci_irq_line); ioaddr = pci_ioaddr & ~3; irq = pci_irq_line;#endif } if (debug > 2) printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n", pci_tbl[chip_idx].name, ioaddr); if (check_region(ioaddr, pci_tbl[chip_idx].io_size)) continue; pcibios_read_config_word(pci_bus, pci_device_fn, PCI_COMMAND, &pci_command); new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO; if (pci_command != new_command) { printk(KERN_INFO " The PCI BIOS has not enabled the" " device at %d/%d! Updating PCI command %4.4x->%4.4x.\n", pci_bus, pci_device_fn, pci_command, new_command); pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, new_command); } dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr, irq, chip_idx, cards_found); /* Get and check the bus-master and latency values. */ if (dev) { u8 pci_latency; pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 10) { printk(KERN_INFO " PCI latency timer (CFLT) is " "unreasonably low at %d. Setting to 64 clocks.\n", pci_latency); pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, 64); } } dev = 0; cards_found++; } return cards_found ? 0 : -ENODEV;}#endif /* not CARDBUS */static struct device *tulip_probe1(int pci_bus, int pci_devfn, struct device *dev, long ioaddr, int irq, int chip_idx, int board_idx){ static int did_version = 0; /* Already printed version info. */ struct tulip_private *tp; /* See note below on the multiport cards. */ static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'}; static int last_irq = 0; static int multiport_cnt = 0; /* For four-port boards w/one EEPROM */ u8 chip_rev; int i; unsigned short sum; u8 ee_data[EEPROM_SIZE]; if (tulip_debug > 0 && did_version++ == 0) printk(KERN_INFO "%s", version); dev = init_etherdev(dev, 0); /* Make certain the data structures are quadword aligned. */ tp = (void *)(((long)kmalloc(sizeof(*tp), GFP_KERNEL | GFP_DMA) + 7) & ~7); memset(tp, 0, sizeof(*tp)); dev->priv = tp; tp->next_module = root_tulip_dev; root_tulip_dev = dev; pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev); /* Bring the 21041/21143 out of sleep mode. Caution: Snooze mode does not work with some boards! */ if (tulip_tbl[chip_idx].flags & HAS_PWRDWN) pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000); printk(KERN_INFO "%s: %s rev %d at %#3lx,", dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); /* Stop the chip's Tx and Rx processes. */ outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); /* Clear the missed-packet counter. */ (volatile int)inl(ioaddr + CSR8); if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { printk(" 21040 compatible mode,"); chip_idx = DC21040; } /* The station address ROM is read byte serially. The register must be polled, waiting for the value to be read bit serially from the EEPROM. */ sum = 0; if (chip_idx == DC21040) { outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ for (i = 0; i < 6; i++) { int value, boguscnt = 100000; do value = inl(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); dev->dev_addr[i] = value; sum += value & 0xff; } } else if (chip_idx == LC82C168) { for (i = 0; i < 3; i++) { int value, boguscnt = 100000; outl(0x600 | i, ioaddr + 0x98); do value = inl(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr); put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4)); for (i = 0; i < 6; i ++) sum += dev->dev_addr[i]; } else { /* A serial EEPROM interface, we read now and sort it out later. */ int sa_offset = 0; int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6; for (i = 0; i < sizeof(ee_data)/2; i++) ((u16 *)ee_data)[i] = le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size)); /* DEC now has a specification (see Notes) but early board makers just put the address in the first EEPROM locations. */ /* This does memcmp(eedata, eedata+16, 8) */ for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) sa_offset = 20;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -