📄 tulip.c
字号:
/*********************************************************************//* EEPROM Parsing Code *//*********************************************************************/static void parse_eeprom(struct nic *nic){ unsigned char *p, *ee_data = tp->eeprom; int new_advertise = 0; int i;#ifdef TULIP_DEBUG_WHERE whereami("parse_eeprom\n");#endif tp->mtable = 0; /* Detect an old-style (SA only) EEPROM layout: memcmp(ee_data, ee_data+16, 8). */ for (i = 0; i < 8; i ++) if (ee_data[i] != ee_data[16+i]) break; if (i >= 8) { /* Do a fix-up based on the vendor half of the station address. */ for (i = 0; eeprom_fixups[i].name; i++) { if (nic->node_addr[0] == eeprom_fixups[i].addr0 && nic->node_addr[1] == eeprom_fixups[i].addr1 && nic->node_addr[2] == eeprom_fixups[i].addr2) { if (nic->node_addr[2] == 0xE8 && ee_data[0x1a] == 0x55) i++; /* An Accton EN1207, not an outlaw Maxtech. */ memcpy(ee_data + 26, eeprom_fixups[i].newtable, sizeof(eeprom_fixups[i].newtable));#ifdef TULIP_DEBUG printf("%s: Old format EEPROM on '%s' board.\n%s: Using substitute media control info.\n", tp->nic_name, eeprom_fixups[i].name, tp->nic_name);#endif break; } } if (eeprom_fixups[i].name == NULL) { /* No fixup found. */#ifdef TULIP_DEBUG printf("%s: Old style EEPROM with no media selection information.\n", tp->nic_name);#endif return; } } if (ee_data[19] > 1) {#ifdef TULIP_DEBUG printf("%s: Multiport cards (%d ports) may not work correctly.\n", tp->nic_name, ee_data[19]);#endif } p = (void *)ee_data + ee_data[27]; if (ee_data[27] == 0) { /* No valid media table. */#ifdef TULIP_DEBUG if (tulip_debug > 1) { printf("%s: No Valid Media Table. ee_data[27] = %hhX\n", tp->nic_name, ee_data[27]); }#endif } else if (tp->chip_id == DC21041) { int media = get_u16(p); int count = p[2]; p += 3; printf("%s: 21041 Media table, default media %hX (%s).\n", tp->nic_name, media, media & 0x0800 ? "Autosense" : medianame[media & 15]); for (i = 0; i < count; i++) { unsigned char media_block = *p++; int media_code = media_block & MEDIA_MASK; if (media_block & 0x40) p += 6; switch(media_code) { case 0: new_advertise |= 0x0020; break; case 4: new_advertise |= 0x0040; break; } printf("%s: 21041 media #%d, %s.\n", tp->nic_name, media_code, medianame[media_code]); } } else { unsigned char csr12dir = 0; int count; struct mediatable *mtable; u16 media = get_u16(p); p += 2; if (tp->flags & CSR12_IN_SROM) csr12dir = *p++; count = *p++; tp->mtable = mtable = (struct mediatable *)&tp->media_table_storage[0]; mtable->defaultmedia = media; mtable->leafcount = count; mtable->csr12dir = csr12dir; mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0; mtable->csr15dir = mtable->csr15val = 0; printf("%s: EEPROM default media type %s.\n", tp->nic_name, media & 0x0800 ? "Autosense" : medianame[media & MEDIA_MASK]); 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 { switch(leaf->type = p[1]) { case 5: mtable->has_reset = i; leaf->media = p[2] & 0x0f; break; case 1: case 3: mtable->has_mii = 1; leaf->media = 11; break; case 2: if ((p[2] & 0x3f) == 0) { u32 base15 = (p[2] & 0x40) ? get_u16(p + 7) : 0x0008; u16 *p1 = (u16 *)(p + (p[2] & 0x40 ? 9 : 3)); mtable->csr15dir = (get_unaligned(p1 + 0)<<16) + base15; mtable->csr15val = (get_unaligned(p1 + 1)<<16) + base15; } /* Fall through. */ case 0: case 4: mtable->has_nonmii = 1; leaf->media = p[2] & MEDIA_MASK; 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; } break; default: leaf->media = 19; } leaf->leafdata = p + 2; p += (p[0] & 0x3f) + 1; }#ifdef TULIP_DEBUG if (tulip_debug > 1 && leaf->media == 11) { unsigned char *bp = leaf->leafdata; printf("%s: MII interface PHY %d, setup/reset sequences %d/%d long, capabilities %hhX %hhX.\n", tp->nic_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]); }#endif printf("%s: Index #%d - Media %s (#%d) described " "by a %s (%d) block.\n", tp->nic_name, i, medianame[leaf->media], leaf->media, leaf->type < 6 ? block_name[leaf->type] : "UNKNOWN", leaf->type); } if (new_advertise) tp->sym_advertise = new_advertise; }}/*********************************************************************//* tulip_init_ring - setup the tx and rx descriptors *//*********************************************************************/static void tulip_init_ring(struct nic *nic){ int i;#ifdef TULIP_DEBUG_WHERE whereami("tulip_init_ring\n");#endif tp->cur_rx = 0; for (i = 0; i < RX_RING_SIZE; i++) { rx_ring[i].status = cpu_to_le32(0x80000000); rx_ring[i].length = cpu_to_le32(BUFLEN); rx_ring[i].buffer1 = virt_to_le32desc(&rxb[i * BUFLEN]); rx_ring[i].buffer2 = virt_to_le32desc(&rx_ring[i+1]); } /* Mark the last entry as wrapping the ring. */ rx_ring[i-1].length = cpu_to_le32(DESC_RING_WRAP | BUFLEN); rx_ring[i-1].buffer2 = virt_to_le32desc(&rx_ring[0]); /* We only use 1 transmit buffer, but we use 2 descriptors so transmit engines have somewhere to point to if they feel the need */ tx_ring[0].status = 0x00000000; tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]); tx_ring[0].buffer2 = virt_to_le32desc(&tx_ring[1]); /* this descriptor should never get used, since it will never be owned by the machine (status will always == 0) */ tx_ring[1].status = 0x00000000; tx_ring[1].buffer1 = virt_to_le32desc(&txb[0]); tx_ring[1].buffer2 = virt_to_le32desc(&tx_ring[0]); /* Mark the last entry as wrapping the ring, though this should never happen */ tx_ring[1].length = cpu_to_le32(DESC_RING_WRAP | BUFLEN);}/*********************************************************************//* eth_reset - Reset adapter *//*********************************************************************/static void tulip_reset(struct nic *nic){ int i; unsigned long to; u32 addr_low, addr_high;#ifdef TULIP_DEBUG_WHERE whereami("tulip_reset\n");#endif /* Stop Tx and RX */ outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6); /* 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(0x814C0000, ioaddr + CSR6); } /* Reset the chip, holding bit 0 set at least 50 PCI cycles. */ outl(0x00000001, ioaddr + CSR0); tulip_wait(1); /* turn off reset and set cache align=16lword, burst=unlimit */ outl(tp->csr0, ioaddr + CSR0); /* Wait the specified 50 PCI cycles after a reset */ tulip_wait(1); /* set up transmit and receive descriptors */ tulip_init_ring(nic); if (tp->chip_id == PNIC2) { u32 addr_high = (nic->node_addr[1]<<8) + (nic->node_addr[0]<<0); /* This address setting does not appear to impact chip operation?? */ outl((nic->node_addr[5]<<8) + nic->node_addr[4] + (nic->node_addr[3]<<24) + (nic->node_addr[2]<<16), ioaddr + 0xB0); outl(addr_high + (addr_high<<16), ioaddr + 0xB8); } /* MC_HASH_ONLY boards don't support setup packets */ if (tp->flags & MC_HASH_ONLY) { u32 addr_low = cpu_to_le32(get_unaligned((u32 *)nic->node_addr)); u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(nic->node_addr+4))); /* clear multicast hash filters and setup MAC address filters */ if (tp->flags & IS_ASIX) { outl(0, ioaddr + CSR13); outl(addr_low, ioaddr + CSR14); outl(1, ioaddr + CSR13); outl(addr_high, ioaddr + CSR14); outl(2, ioaddr + CSR13); outl(0, ioaddr + CSR14); outl(3, ioaddr + CSR13); outl(0, 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 { /* for other boards we send a setup packet to initialize the filters */ u32 tx_flags = 0x08000000 | 192; /* construct perfect filter frame with mac address as first match and broadcast address for all others */ for (i=0; i<192; i++) txb[i] = 0xFF; txb[0] = nic->node_addr[0]; txb[1] = nic->node_addr[1]; txb[4] = nic->node_addr[2]; txb[5] = nic->node_addr[3]; txb[8] = nic->node_addr[4]; txb[9] = nic->node_addr[5]; tx_ring[0].length = cpu_to_le32(tx_flags); tx_ring[0].buffer1 = virt_to_le32desc(&txb[0]); tx_ring[0].status = cpu_to_le32(0x80000000); } /* Point to rx and tx descriptors */ outl((unsigned long)&rx_ring[0], ioaddr + CSR3); outl((unsigned long)&tx_ring[0], ioaddr + CSR4); init_media(nic); /* set the chip's operating mode (but don't turn on xmit and recv yet) */ outl((tp->csr6 & ~0x00002002), ioaddr + CSR6); /* send setup packet for cards that support it */ if (!(tp->flags & MC_HASH_ONLY)) { /* enable transmit wait for completion */ outl(tp->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 ("%s: TX Setup Timeout.\n", tp->nic_name); } } if (tp->chip_id == LC82C168) tulip_check_duplex(nic); /* enable transmit and receive */ outl(tp->csr6 | 0x00002002, ioaddr + CSR6);}/*********************************************************************//* eth_transmit - Transmit a frame *//*********************************************************************/static void tulip_transmit(struct nic *nic, const char *d, unsigned int t, unsigned int s, const char *p){ u16 nstype; u32 to; u32 csr6 = inl(ioaddr + CSR6);#ifdef TULIP_DEBUG_WHERE whereami("tulip_transmit\n");#endif /* Disable Tx */ outl(csr6 & ~0x00002000, ioaddr + CSR6); memcpy(txb, d, ETH_ALEN); memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); nstype = htons((u16) t); memcpy(txb + 2 * ETH_ALEN, (u8 *)&nstype, 2); memcpy(txb + ETH_HLEN, p, s); s += ETH_HLEN; s &= 0x0FFF; /* pad to minimum packet size */ while (s < ETH_ZLEN) txb[s++] = '\0';#ifdef TULIP_DEBUG if (tulip_debug > 1) printf("%s: sending %d bytes ethtype %hX\n", tp->nic_name, s, t);#endif /* setup the transmit descriptor */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -