📄 tulip.c
字号:
/* 0x60000000 = no interrupt on completion */ tx_ring[0].length = cpu_to_le32(0x60000000 | s); tx_ring[0].status = cpu_to_le32(0x80000000); /* Point to transmit descriptor */ outl((u32)&tx_ring[0], ioaddr + CSR4); /* Enable Tx */ outl(csr6 | 0x00002000, ioaddr + CSR6); /* immediate transmit demand */ outl(0, ioaddr + CSR1); to = currticks() + TX_TIME_OUT; while ((tx_ring[0].status & 0x80000000) && (currticks() < to)) /* wait */ ; if (currticks() >= to) { printf ("TX Timeout!\n"); } /* Disable Tx */ outl(csr6 & ~0x00002000, ioaddr + CSR6);}/*********************************************************************//* eth_poll - Wait for a frame *//*********************************************************************/static int tulip_poll(struct nic *nic){#ifdef TULIP_DEBUG_WHERE whereami("tulip_poll\n");#endif /* no packet waiting. packet still owned by NIC */ if (rx_ring[tp->cur_rx].status & 0x80000000) return 0;#ifdef TULIP_DEBUG_WHERE whereami("tulip_poll got one\n");#endif nic->packetlen = (rx_ring[tp->cur_rx].status & 0x3FFF0000) >> 16; /* if we get a corrupted packet. throw it away and move on */ if (rx_ring[tp->cur_rx].status & 0x00008000) { /* return the descriptor and buffer to receive ring */ rx_ring[tp->cur_rx].status = 0x80000000; tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; return 0; } /* copy packet to working buffer */ memcpy(nic->packet, rxb + tp->cur_rx * BUFLEN, nic->packetlen); /* return the descriptor and buffer to receive ring */ rx_ring[tp->cur_rx].status = 0x80000000; tp->cur_rx = (++tp->cur_rx) % RX_RING_SIZE; return 1;}/*********************************************************************//* eth_disable - Disable the interface *//*********************************************************************/static void tulip_disable(struct nic *nic){#ifdef TULIP_DEBUG_WHERE whereami("tulip_disable\n");#endif /* disable interrupts */ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* Clear the missed-packet counter. */ (volatile unsigned long)inl(ioaddr + CSR8);}/*********************************************************************//* eth_probe - Look for an adapter *//*********************************************************************/struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci){ u32 i, l1, l2; u8 chip_rev; u8 ee_data[EEPROM_SIZE]; unsigned short sum; int chip_idx; static unsigned char last_phys_addr[ETH_ALEN] = {0x00, 'L', 'i', 'n', 'u', 'x'}; if (io_addrs == 0 || *io_addrs == 0) return 0; ioaddr = *io_addrs; /* point to private storage */ tp = &tpx; tp->vendor_id = pci->vendor; tp->dev_id = pci->dev_id; tp->nic_name = pci->name; tp->if_port = 0; tp->default_port = 0; adjust_pci_device(pci); /* disable interrupts */ outl(0x00000000, ioaddr + CSR7); /* Stop the chip's Tx and Rx processes. */ outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* Clear the missed-packet counter. */ (volatile unsigned long)inl(ioaddr + CSR8); printf("\n"); /* so we start on a fresh line */#ifdef TULIP_DEBUG_WHERE whereami("tulip_probe\n");#endif#ifdef TULIP_DEBUG if (tulip_debug > 1) printf ("%s: Looking for Tulip Chip: Vendor=%hX Device=%hX\n", tp->nic_name, tp->vendor_id, tp->dev_id);#endif /* Figure out which chip we're dealing with */ i = 0; chip_idx = -1; while (pci_id_tbl[i].name) { if ( (((u32) tp->dev_id << 16) | tp->vendor_id) == (pci_id_tbl[i].id.pci & pci_id_tbl[i].id.pci_mask) ) { chip_idx = pci_id_tbl[i].drv_flags; break; } i++; } if (chip_idx == -1) { printf ("%s: Unknown Tulip Chip: Vendor=%hX Device=%hX\n", tp->nic_name, tp->vendor_id, tp->dev_id); return 0; } tp->pci_id_idx = i; tp->flags = tulip_tbl[chip_idx].flags;#ifdef TULIP_DEBUG if (tulip_debug > 1) { printf ("%s: tp->pci_id_idx == %d, name == %s\n", tp->nic_name, tp->pci_id_idx, pci_id_tbl[tp->pci_id_idx].name); printf ("%s: chip_idx == %d, name == %s\n", tp->nic_name, chip_idx, tulip_tbl[chip_idx].chip_name); }#endif /* Bring the 21041/21143 out of sleep mode. Caution: Snooze mode does not work with some boards! */ if (tp->flags & HAS_PWRDWN) pcibios_write_config_dword(pci->bus, pci->devfn, 0x40, 0x00000000); if (inl(ioaddr + CSR5) == 0xFFFFFFFF) { printf("%s: The Tulip chip at %X is not functioning.\n", tp->nic_name, ioaddr); return 0; } pcibios_read_config_byte(pci->bus, pci->devfn, PCI_REVISION, &chip_rev); printf("%s: [chip: %s] rev %d at %hX\n", tp->nic_name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr); printf("%s: Vendor=%hX Device=%hX", tp->nic_name, tp->vendor_id, tp->dev_id); if (chip_idx == DC21041 && inl(ioaddr + CSR9) & 0x8000) { printf(" 21040 compatible mode."); chip_idx = DC21040; } printf("\n"); /* The SROM/EEPROM interface varies dramatically. */ sum = 0; if (chip_idx == DC21040) { outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */ for (i = 0; i < ETH_ALEN; i++) { int value, boguscnt = 100000; do value = inl(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); nic->node_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*)nic->node_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ put_unaligned(inl(ioaddr + 0xA4), (u32 *)nic->node_addr); put_unaligned(inl(ioaddr + 0xA8), (u16 *)(nic->node_addr + 4)); for (i = 0; i < ETH_ALEN; i ++) sum += nic->node_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; if (ee_data[0] == 0xff && ee_data[1] == 0xff && ee_data[2] == 0) { sa_offset = 2; /* Grrr, damn Matrox boards. */ } for (i = 0; i < ETH_ALEN; i ++) { nic->node_addr[i] = ee_data[i + sa_offset]; sum += ee_data[i + sa_offset]; } } /* Lite-On boards have the address byte-swapped. */ if ((nic->node_addr[0] == 0xA0 || nic->node_addr[0] == 0xC0) && nic->node_addr[1] == 0x00) for (i = 0; i < ETH_ALEN; i+=2) { char tmp = nic->node_addr[i]; nic->node_addr[i] = nic->node_addr[i+1]; nic->node_addr[i+1] = tmp; } if (sum == 0 || sum == ETH_ALEN*0xff) { printf("%s: EEPROM not present!\n", tp->nic_name); for (i = 0; i < ETH_ALEN-1; i++) nic->node_addr[i] = last_phys_addr[i]; nic->node_addr[i] = last_phys_addr[i] + 1; } for (i = 0; i < ETH_ALEN; i++) last_phys_addr[i] = nic->node_addr[i]; printf("%s: %! at ioaddr %hX\n", tp->nic_name, nic->node_addr, ioaddr); tp->chip_id = chip_idx; tp->revision = chip_rev; tp->csr0 = csr0; /* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. And the ASIX must have a burst limit or horrible things happen. */ if (chip_idx == DC21143 && chip_rev == 65) tp->csr0 &= ~0x01000000; else if (tp->flags & IS_ASIX) tp->csr0 |= 0x2000; if (media_cap[tp->default_port] & MediaIsMII) { u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 }; tp->mii_advertise = media2advert[tp->default_port - 9]; tp->mii_advertise |= (tp->flags & HAS_8023X); /* Matching bits! */ } /* This is logically part of the probe routine, but too complex to write inline. */ if (tp->flags & HAS_MEDIA_TABLE) { memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom)); parse_eeprom(nic); } start_link(nic); /* reset the device and make ready for tx and rx of packets */ tulip_reset(nic); nic->reset = tulip_reset; nic->poll = tulip_poll; nic->transmit = tulip_transmit; nic->disable = tulip_disable; /* give the board a chance to reset before returning */ tulip_wait(4*TICKS_PER_SEC); return nic;}static void start_link(struct nic *nic){ int i;#ifdef TULIP_DEBUG_WHERE whereami("start_link\n");#endif if ((tp->flags & ALWAYS_CHECK_MII) || (tp->mtable && tp->mtable->has_mii) || ( ! tp->mtable && (tp->flags & HAS_MII))) { unsigned int phy, phy_idx; if (tp->mtable && tp->mtable->has_mii) { for (i = 0; i < tp->mtable->leafcount; i++) if (tp->mtable->mleaf[i].media == 11) { tp->cur_index = i; tp->saved_if_port = tp->if_port; select_media(nic, 2); tp->if_port = tp->saved_if_port; break; } } /* Find the connected MII xcvrs. */ for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) { int mii_status = mdio_read(nic, phy, 1); if ((mii_status & 0x8301) == 0x8001 || ((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) { int mii_reg0 = mdio_read(nic, phy, 0); int mii_advert = mdio_read(nic, phy, 4); int to_advert; if (tp->mii_advertise) to_advert = tp->mii_advertise; else if (tp->advertising[phy_idx]) to_advert = tp->advertising[phy_idx]; else /* Leave unchanged. */ tp->mii_advertise = to_advert = mii_advert; tp->phys[phy_idx++] = phy; printf("%s: MII transceiver %d config %hX status %hX advertising %hX.\n", tp->nic_name, phy, mii_reg0, mii_status, mii_advert); /* Fixup for DLink with miswired PHY. */ if (mii_advert != to_advert) { printf("%s: Advertising %hX on PHY %d previously advertising %hX.\n", tp->nic_name, to_advert, phy, mii_advert); mdio_write(nic, phy, 4, to_advert); } /* Enable autonegotiation: some boards default to off. */ mdio_write(nic, phy, 0, mii_reg0 | (tp->full_duplex ? 0x1100 : 0x1000) | (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0)); } } tp->mii_cnt = phy_idx; if (tp->mtable && tp->mtable->has_mii && phy_idx == 0) { printf("%s: ***WARNING***: No MII transceiver found!\n", tp->nic_name); tp->phys[0] = 1; } } /* Reset the xcvr interface and turn on heartbeat. */ switch (tp->chip_id) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -