📄 tulip.c
字号:
for (i = 0; i < count; i++) { struct medialeaf *leaf = &mtable->mleaf[i]; if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */ leaf->type = 0; leaf->media = p[0] & 0x3f; leaf->leafdata = p; if ((p[2] & 0x61) == 0x01) /* Bogus, but Znyx boards do it. */ mtable->has_mii = 1; p += 4; } else { leaf->type = p[1]; if (p[1] == 0x05) { mtable->has_reset = i; leaf->media = p[2] & 0x0f; } else if (p[1] & 1) { mtable->has_mii = 1; leaf->media = 11; } else { mtable->has_nonmii = 1; leaf->media = p[2] & 0x0f; switch (leaf->media) { case 0: new_advertise |= 0x0020; break; case 4: new_advertise |= 0x0040; break; case 3: new_advertise |= 0x0080; break; case 5: new_advertise |= 0x0100; break; case 6: new_advertise |= 0x0200; break; } if (p[1] == 2 && leaf->media == 0) { if (p[2] & 0x40) { u32 base15 = get_unaligned((u16*)&p[7]); mtable->csr15dir = (get_unaligned((u16*)&p[9])<<16) + base15; mtable->csr15val = (get_unaligned((u16*)&p[11])<<16) + base15; } else { mtable->csr15dir = get_unaligned((u16*)&p[3])<<16; mtable->csr15val = get_unaligned((u16*)&p[5])<<16; } } } leaf->leafdata = p + 2; p += (p[0] & 0x3f) + 1; } if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; printk(KERN_INFO "%s: MII interface PHY %d, setup/reset " "sequences %d/%d long, capabilities %2.2x %2.2x.\n", dev->name, bp[0], bp[1], bp[2 + bp[1]*2], bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]); } printk(KERN_INFO "%s: Index #%d - Media %s (#%d) described " "by a %s (%d) block.\n", dev->name, i, medianame[leaf->media], leaf->media, block_name[leaf->type], leaf->type); } if (new_advertise) tp->to_advertise = new_advertise; }}/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*//* EEPROM_Ctrl bits. */#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */#define EE_CS 0x01 /* EEPROM chip select. */#define EE_DATA_WRITE 0x04 /* Data from the Tulip to EEPROM. */#define EE_WRITE_0 0x01#define EE_WRITE_1 0x05#define EE_DATA_READ 0x08 /* Data from the EEPROM chip. */#define EE_ENB (0x4800 | EE_CS)/* Delay between EEPROM clock transitions. Even at 33Mhz current PCI implementations don't overrun the EEPROM clock. We add a bus turn-around to insure that this remains true. */#define eeprom_delay() inl(ee_addr)/* The EEPROM commands include the alway-set leading bit. */#define EE_READ_CMD (6)/* Note: this routine returns extra data bits for size detection. */static int read_eeprom(long ioaddr, int location, int addr_len){ int i; unsigned retval = 0; long ee_addr = ioaddr + CSR9; int read_cmd = location | (EE_READ_CMD << addr_len); outl(EE_ENB & ~EE_CS, ee_addr); outl(EE_ENB, ee_addr); /* Shift the read command bits out. */ for (i = 4 + addr_len; i >= 0; i--) { short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; outl(EE_ENB | dataval, ee_addr); eeprom_delay(); outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); } outl(EE_ENB, ee_addr); for (i = 16; i > 0; i--) { outl(EE_ENB | EE_SHIFT_CLK, ee_addr); eeprom_delay(); retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0); outl(EE_ENB, ee_addr); eeprom_delay(); } /* Terminate the EEPROM access. */ outl(EE_ENB & ~EE_CS, ee_addr); return retval;}/* MII transceiver control section. Read and write the MII registers using software-generated serial MDIO protocol. See the MII specifications or DP83840A data sheet for details. *//* The maximum data clock rate is 2.5 Mhz. The minimum timing is usually met by back-to-back PCI I/O cycles, but we insert a delay to avoid "overclocking" issues or future 66Mhz PCI. */#define mdio_delay() inl(mdio_addr)/* Read and write the MII registers using software-generated serial MDIO protocol. It is just different enough from the EEPROM protocol to not share code. The maxium data clock rate is 2.5 Mhz. */#define MDIO_SHIFT_CLK 0x10000#define MDIO_DATA_WRITE0 0x00000#define MDIO_DATA_WRITE1 0x20000#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */#define MDIO_ENB_IN 0x40000#define MDIO_DATA_READ 0x80000static int mdio_read(struct device *dev, int phy_id, int location){ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; int retval = 0; long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; if (tp->chip_id == LC82C168) { int i = 1000; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); inl(ioaddr + 0xA0); inl(ioaddr + 0xA0); while (--i > 0) if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) return retval & 0xffff; return 0xffff; } if (tp->chip_id == COMET) { if (phy_id == 1) { if (location < 7) return inl(ioaddr + 0xB4 + (location<<2)); else if (location == 17) return inl(ioaddr + 0xD0); else if (location >= 29 && location <= 31) return inl(ioaddr + 0xD4 + ((location-29)<<2)); } return 0xffff; } /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the read command bits out. */ for (i = 15; i >= 0; i--) { int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Read the two transition, 16 data, and wire-idle bits. */ for (i = 19; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return (retval>>1) & 0xffff;}static void mdio_write(struct device *dev, int phy_id, int location, int value){ struct tulip_private *tp = (struct tulip_private *)dev->priv; int i; int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value; long ioaddr = dev->base_addr; long mdio_addr = ioaddr + CSR9; if (tp->chip_id == LC82C168) { int i = 1000; outl(cmd, ioaddr + 0xA0); do if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) break; while (--i > 0); return; } if (tp->chip_id == COMET) { if (phy_id != 1) return; if (location < 7) outl(value, ioaddr + 0xB4 + (location<<2)); else if (location == 17) outl(value, ioaddr + 0xD0); else if (location >= 29 && location <= 31) outl(value, ioaddr + 0xD4 + ((location-29)<<2)); return; } /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); mdio_delay(); outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Shift the command bits out. */ for (i = 31; i >= 0; i--) { int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0; outl(MDIO_ENB | dataval, mdio_addr); mdio_delay(); outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } /* Clear out extra bits. */ for (i = 2; i > 0; i--) { outl(MDIO_ENB_IN, mdio_addr); mdio_delay(); outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr); mdio_delay(); } return;}static inttulip_open(struct 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. */ if (tp->flags & HAS_PWRDWN) pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 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); if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)) return -EAGAIN; MOD_INC_USE_COUNT; /* 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); if (tulip_debug > 1) printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq); tulip_init_ring(dev);#if 0 if (tp->chip_id == PNIC2) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4))); addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0); outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] + (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16), ioaddr + 0xB0); outl(addr_high + (addr_high<<16), ioaddr + 0xB8); }#endif if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr)); u32 addr_high = cpu_to_le32(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->chip_id == COMET) { 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]; /* 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]; /* Put the setup frame on the Tx list. */ tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192); tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame); tp->tx_ring[0].status = cpu_to_le32(DescOwned); tp->cur_tx++; } outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3); outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4); 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 = 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 & 15; 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; (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 == 0 && tp->chip_id == DC21041) { tp->nway = 1; } if (dev->if_port == 0 && tp->chip_id == DC21142) { if (tp->mii_cnt) { 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], mdio_read(dev, tp->phys[0], 1)); outl(0x82020000, ioaddr + CSR6); tp->csr6 = 0x820E0000; dev->if_port = 11; outl(0x0000, ioaddr + CSR13); outl(0x0000, ioaddr + CSR14); } else t21142_start_nway(dev); } else if (tp->chip_id == PNIC2) { t21142_start_nway(dev); } else if (tp->chip_id == LC82C168 && ! tp->medialock) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -