| |
| /************************************************************************** |
| NETBOOT - BOOTP/TFTP Bootstrap Program |
| |
| Author: Martin Renters |
| Date: May/94 |
| |
| This code is based heavily on David Greenman's if_ed.c driver |
| |
| Copyright (C) 1993-1994, David Greenman, Martin Renters. |
| This software may be used, modified, copied, distributed, and sold, in |
| both source and binary form provided that the above copyright and these |
| terms are retained. Under no circumstances are the authors responsible for |
| the proper functioning of this software, nor do the authors assume any |
| responsibility for damages incurred with its use. |
| |
| 3c503 support added by Bill Paul (wpaul@ctr.columbia.edu) on 11/15/94 |
| SMC8416 support added by Bill Paul (wpaul@ctr.columbia.edu) on 12/25/94 |
| |
| **************************************************************************/ |
| |
| #if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) || defined(INCLUDE_WD) || defined(INCLUDE_T503) |
| |
| #include "netboot.h" |
| #include "nic.h" |
| #include "ns8390.h" |
| |
| static unsigned char eth_vendor, eth_flags, eth_laar; |
| static unsigned short eth_nic_base, eth_asic_base; |
| static unsigned char eth_memsize, eth_rx_start, eth_tx_start; |
| static Address eth_bmem, eth_rmem; |
| |
| #if defined(INCLUDE_WD) |
| #define eth_probe wd_probe |
| #else |
| #if defined(INCLUDE_T503) |
| #define eth_probe t503_probe |
| #else |
| #if defined(INCLUDE_NE) |
| #define eth_probe ne_probe |
| #else |
| #if defined(INCLUDE_NEPCI) |
| #define eth_probe nepci_probe |
| #else |
| Error you must define one of the above |
| #endif |
| #endif |
| #endif |
| #endif |
| |
| |
| |
| static void net_bcopy (char *s, char *d, int l) |
| { |
| while (l--) |
| *d++ = *s++; |
| } |
| |
| |
| #if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) |
| /************************************************************************** |
| ETH_PIO_READ - Read a frame via Programmed I/O |
| **************************************************************************/ |
| static void eth_pio_read(src, dst, cnt) |
| unsigned int src; |
| unsigned char *dst; |
| unsigned int cnt; |
| { |
| if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; } |
| outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 | |
| D8390_COMMAND_STA); |
| outb(eth_nic_base + D8390_P0_RBCR0, cnt); |
| outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8); |
| outb(eth_nic_base + D8390_P0_RSAR0, src); |
| outb(eth_nic_base + D8390_P0_RSAR1, src>>8); |
| outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD0 | |
| D8390_COMMAND_STA); |
| if (eth_flags & FLAG_16BIT) { |
| cnt >>= 1; /* number of words */ |
| while (cnt--) { |
| *((unsigned short *)dst) = inw(eth_asic_base + NE_DATA); |
| dst += 2; |
| } |
| } |
| else { |
| while (cnt--) |
| *(dst++) = inb(eth_asic_base + NE_DATA); |
| } |
| } |
| |
| /************************************************************************** |
| ETH_PIO_WRITE - Write a frame via Programmed I/O |
| **************************************************************************/ |
| static void eth_pio_write(src, dst, cnt) |
| unsigned char *src; |
| unsigned int dst; |
| unsigned int cnt; |
| { |
| if (eth_flags & FLAG_16BIT) { ++cnt; cnt &= ~1; } |
| outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD2 | |
| D8390_COMMAND_STA); |
| outb(eth_nic_base + D8390_P0_ISR, D8390_ISR_RDC); |
| outb(eth_nic_base + D8390_P0_RBCR0, cnt); |
| outb(eth_nic_base + D8390_P0_RBCR1, cnt>>8); |
| outb(eth_nic_base + D8390_P0_RSAR0, dst); |
| outb(eth_nic_base + D8390_P0_RSAR1, dst>>8); |
| outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_RD1 | |
| D8390_COMMAND_STA); |
| if (eth_flags & FLAG_16BIT) { |
| cnt >>= 1; /* number of words */ |
| while (cnt--) { |
| outw_p(eth_asic_base + NE_DATA, *((unsigned short *)src)); |
| src += 2; |
| } |
| } |
| else { |
| while (cnt--) |
| outb_p(eth_asic_base + NE_DATA, *(src++)); |
| } |
| while((inb_p(eth_nic_base + D8390_P0_ISR) & D8390_ISR_RDC) |
| != D8390_ISR_RDC); |
| } |
| #else |
| /************************************************************************** |
| ETH_PIO_READ - Dummy routine when NE2000 not compiled in |
| **************************************************************************/ |
| static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {} |
| #endif |
| |
| /************************************************************************** |
| ETH_RESET - Reset adapter |
| **************************************************************************/ |
| static void eth_reset(struct nic *nic) |
| { |
| int i; |
| if (eth_flags & FLAG_790) |
| outb(eth_nic_base+D8390_P0_COMMAND, |
| D8390_COMMAND_PS0 | D8390_COMMAND_STP); |
| else |
| outb(eth_nic_base+D8390_P0_COMMAND, |
| D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | |
| D8390_COMMAND_STP); |
| if (eth_flags & FLAG_16BIT) |
| outb(eth_nic_base+D8390_P0_DCR, 0x49); |
| else |
| outb(eth_nic_base+D8390_P0_DCR, 0x48); |
| outb(eth_nic_base+D8390_P0_RBCR0, 0); |
| outb(eth_nic_base+D8390_P0_RBCR1, 0); |
| outb(eth_nic_base+D8390_P0_RCR, 0x20); /* monitor mode */ |
| outb(eth_nic_base+D8390_P0_TCR, 2); |
| outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start); |
| outb(eth_nic_base+D8390_P0_PSTART, eth_rx_start); |
| if (eth_flags & FLAG_790) outb(eth_nic_base + 0x09, 0); |
| outb(eth_nic_base+D8390_P0_PSTOP, eth_memsize); |
| outb(eth_nic_base+D8390_P0_BOUND, eth_memsize - 1); |
| outb(eth_nic_base+D8390_P0_ISR, 0xFF); |
| outb(eth_nic_base+D8390_P0_IMR, 0); |
| if (eth_flags & FLAG_790) |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 | |
| D8390_COMMAND_STP); |
| else |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1 | |
| D8390_COMMAND_RD2 | D8390_COMMAND_STP); |
| for (i=0; i<ETHER_ADDR_SIZE; i++) |
| outb(eth_nic_base+D8390_P1_PAR0+i, nic->node_addr[i]); |
| for (i=0; i<ETHER_ADDR_SIZE; i++) |
| outb(eth_nic_base+D8390_P1_MAR0+i, 0xFF); |
| outb(eth_nic_base+D8390_P1_CURR, eth_rx_start); |
| if (eth_flags & FLAG_790) |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | |
| D8390_COMMAND_STA); |
| else |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | |
| D8390_COMMAND_RD2 | D8390_COMMAND_STA); |
| outb(eth_nic_base+D8390_P0_ISR, 0xFF); |
| outb(eth_nic_base+D8390_P0_TCR, 0); |
| outb(eth_nic_base+D8390_P0_RCR, 4); /* allow broadcast frames */ |
| #ifdef INCLUDE_T503 |
| if (eth_vendor == VENDOR_3COM) { |
| /* |
| * No way to tell whether or not we're supposed to use |
| * the 3Com's transceiver unless the user tells us. |
| * 'aui' should have some compile time default value |
| * which can be changed from the command menu. |
| */ |
| if (nic->aui) |
| outb(eth_asic_base + _3COM_CR, 0); |
| else |
| outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL); |
| } |
| #endif |
| } |
| |
| /************************************************************************** |
| ETH_TRANSMIT - Transmit a frame |
| **************************************************************************/ |
| static void eth_transmit( |
| struct nic *nic, |
| char *d, /* Destination */ |
| unsigned int t, /* Type */ |
| unsigned int s, /* size */ |
| char *p) /* Packet */ |
| { |
| int c; /* used in NETBOOT16 */ |
| |
| |
| #ifdef INCLUDE_T503 |
| if (eth_vendor == VENDOR_3COM) { |
| #ifdef NETBOOT32 |
| net_bcopy(d, (void *)eth_bmem, ETHER_ADDR_SIZE); /* dst */ |
| net_bcopy(nic->node_addr, (void *)eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); /* src */ |
| *((char *)eth_bmem+12) = t>>8; /* type */ |
| *((char *)eth_bmem+13) = t; |
| net_bcopy(p, (void *)eth_bmem+ETHER_HDR_SIZE, s); |
| s += ETHER_HDR_SIZE; |
| while (s < ETH_MIN_PACKET) *((char *)eth_bmem+(s++)) = 0; |
| #endif |
| #ifdef NETBOOT16 |
| bcopyf(d, eth_bmem, ETHER_ADDR_SIZE); |
| bcopyf(nic->node_addr, eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); |
| c = t >> 8; |
| bcopyf(&c, eth_bmem+12, 1); |
| c = t; |
| bcopyf(&c, eth_bmem+13, 1); |
| bcopyf(p, (Address)(eth_bmem+ETHER_HDR_SIZE), s); |
| s += ETHER_HDR_SIZE; |
| if (s < ETH_MIN_PACKET) |
| bzerof(eth_bmem+s, ETH_MIN_PACKET-s), s = ETH_MIN_PACKET; |
| #endif |
| } |
| #endif |
| #ifdef INCLUDE_WD |
| if (eth_vendor == VENDOR_WD) { /* Memory interface */ |
| if (eth_flags & FLAG_16BIT) { |
| outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN); |
| inb(0x84); |
| } |
| if (eth_flags & FLAG_790) { |
| outb(eth_asic_base + WD_MSR, WD_MSR_MENB); |
| inb(0x84); |
| } |
| inb(0x84); |
| #ifdef NETBOOT32 |
| net_bcopy(d, (void *)eth_bmem, ETHER_ADDR_SIZE); /* dst */ |
| |
| net_bcopy(nic->node_addr, (void *)eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); /* src */ |
| *((char *)eth_bmem+12) = t>>8; /* type */ |
| *((char *)eth_bmem+13) = t; |
| net_bcopy(p, (void *)eth_bmem+ETHER_HDR_SIZE, s); |
| s += ETHER_HDR_SIZE; |
| while (s < ETH_MIN_PACKET) *((char *)eth_bmem+(s++)) = 0; |
| #endif |
| #ifdef NETBOOT16 |
| bcopyf(d, eth_bmem, ETHER_ADDR_SIZE); |
| bcopyf(nic->node_addr, eth_bmem+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); |
| c = t >> 8; |
| /* bcc generates worse code without (const+const) below */ |
| bcopyf(&c, eth_bmem+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE), 1); |
| c = t; |
| bcopyf(&c, eth_bmem+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE+1), 1); |
| bcopyf(p, (Address)(eth_bmem+ETHER_HDR_SIZE), s); |
| s += ETHER_HDR_SIZE; |
| if (s < ETH_MIN_PACKET) |
| bzerof(eth_bmem+s, ETH_MIN_PACKET-s), s = ETH_MIN_PACKET; |
| #endif |
| if (eth_flags & FLAG_790) { |
| outb(eth_asic_base + WD_MSR, 0); |
| inb(0x84); |
| } |
| if (eth_flags & FLAG_16BIT) { |
| outb(eth_asic_base + WD_LAAR, eth_laar & ~WD_LAAR_M16EN); |
| inb(0x84); |
| } |
| } |
| #endif |
| #if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) |
| if (eth_vendor == VENDOR_NOVELL) { /* Programmed I/O */ |
| unsigned short type; |
| type = (t >> 8) | (t << 8); |
| eth_pio_write(d, eth_tx_start<<8, ETHER_ADDR_SIZE); |
| eth_pio_write(nic->node_addr, (eth_tx_start<<8)+ETHER_ADDR_SIZE, ETHER_ADDR_SIZE); |
| /* bcc generates worse code without (const+const) below */ |
| eth_pio_write((unsigned char *)&type, (eth_tx_start<<8)+(ETHER_ADDR_SIZE+ETHER_ADDR_SIZE), 2); |
| eth_pio_write(p, (eth_tx_start<<8)+ETHER_HDR_SIZE, s); |
| s += ETHER_HDR_SIZE; |
| if (s < ETH_MIN_PACKET) s = ETH_MIN_PACKET; |
| } |
| #endif |
| if (eth_flags & FLAG_790) |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | |
| D8390_COMMAND_STA); |
| else |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | |
| D8390_COMMAND_RD2 | D8390_COMMAND_STA); |
| outb(eth_nic_base+D8390_P0_TPSR, eth_tx_start); |
| outb(eth_nic_base+D8390_P0_TBCR0, s); |
| outb(eth_nic_base+D8390_P0_TBCR1, s>>8); |
| if (eth_flags & FLAG_790) |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | |
| D8390_COMMAND_TXP | D8390_COMMAND_STA); |
| else |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0 | |
| D8390_COMMAND_TXP | D8390_COMMAND_RD2 | |
| D8390_COMMAND_STA); |
| } |
| |
| /************************************************************************** |
| ETH_POLL - Wait for a frame |
| **************************************************************************/ |
| static int eth_poll(struct nic *nic) |
| { |
| int ret = 0; |
| unsigned char rstat, curr, next; |
| unsigned short len, frag; |
| unsigned short pktoff; |
| unsigned char *p; |
| struct ringbuffer pkthdr; |
| rstat = inb(eth_nic_base+D8390_P0_RSR); |
| if (rstat & D8390_RSTAT_OVER) { |
| eth_reset(nic); |
| return(0); |
| } |
| if (!(rstat & D8390_RSTAT_PRX)) return(0); |
| next = inb(eth_nic_base+D8390_P0_BOUND)+1; |
| if (next >= eth_memsize) next = eth_rx_start; |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS1); |
| curr = inb(eth_nic_base+D8390_P1_CURR); |
| outb(eth_nic_base+D8390_P0_COMMAND, D8390_COMMAND_PS0); |
| if (curr >= eth_memsize) curr=eth_rx_start; |
| if (curr == next) return(0); |
| if (eth_vendor == VENDOR_WD) { |
| if (eth_flags & FLAG_16BIT) { |
| outb(eth_asic_base + WD_LAAR, eth_laar | WD_LAAR_M16EN); |
| inb(0x84); |
| } |
| if (eth_flags & FLAG_790) { |
| outb(eth_asic_base + WD_MSR, WD_MSR_MENB); |
| inb(0x84); |
| } |
| inb(0x84); |
| } |
| pktoff = next << 8; |
| if (eth_flags & FLAG_PIO) |
| eth_pio_read(pktoff, (char *)&pkthdr, 4); |
| else |
| #ifdef NETBOOT32 |
| net_bcopy((void *)eth_rmem + pktoff, &pkthdr, 4); |
| #endif |
| #ifdef NETBOOT16 |
| fnet_bcopy(eth_rmem + pktoff, &pkthdr, 4); |
| #endif |
| pktoff += sizeof(pkthdr); |
| len = pkthdr.len - 4; /* sub CRC */ |
| if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || pkthdr.len < ETH_MIN_PACKET || pkthdr.len > ETH_MAX_PACKET) { |
| printf("B"); |
| return (0); |
| } |
| else { |
| p = nic->packet; |
| nic->packetlen = len; /* available to caller */ |
| frag = (eth_memsize << 8) - pktoff; |
| if (len > frag) { /* We have a wrap-around */ |
| /* read first part */ |
| if (eth_flags & FLAG_PIO) |
| eth_pio_read(pktoff, p, frag); |
| else |
| #ifdef NETBOOT32 |
| net_bcopy((void *)eth_rmem + pktoff, p, frag); |
| #endif |
| #ifdef NETBOOT16 |
| fnet_bcopy(eth_rmem + pktoff, p, frag); |
| #endif |
| pktoff = eth_rx_start << 8; |
| p += frag; |
| len -= frag; |
| } |
| /* read second part */ |
| if (eth_flags & FLAG_PIO) |
| eth_pio_read(pktoff, p, len); |
| else |
| #ifdef NETBOOT32 |
| net_bcopy((void *)eth_rmem + pktoff, p, len); |
| #endif |
| #ifdef NETBOOT16 |
| fnet_bcopy(eth_rmem + pktoff, p, len); |
| #endif |
| ret = 1; |
| } |
| if (eth_vendor == VENDOR_WD) { |
| if (eth_flags & FLAG_790) { |
| outb(eth_asic_base + WD_MSR, 0); |
| inb(0x84); |
| } |
| if (eth_flags & FLAG_16BIT) { |
| outb(eth_asic_base + WD_LAAR, eth_laar & |
| ~WD_LAAR_M16EN); |
| inb(0x84); |
| } |
| inb(0x84); |
| } |
| next = pkthdr.next; /* frame number of next packet */ |
| if (next == eth_rx_start) |
| next = eth_memsize; |
| outb(eth_nic_base+D8390_P0_BOUND, next-1); |
| return(ret); |
| } |
| |
| /************************************************************************** |
| ETH_DISABLE - Turn off adapter |
| **************************************************************************/ |
| static void eth_disable(struct nic *nic) |
| { |
| } |
| |
| /************************************************************************** |
| ETH_PROBE - Look for an adapter |
| **************************************************************************/ |
| struct nic *eth_probe(struct nic *nic, unsigned short *probe_addrs) |
| { |
| int i; |
| struct wd_board *brd; |
| unsigned short chksum; |
| unsigned char c; |
| #if defined(INCLUDE_WD) && defined(NETBOOT16) |
| unsigned char bmem13, bmem11; |
| #endif |
| |
| eth_vendor = VENDOR_NONE; |
| |
| #ifdef INCLUDE_WD |
| /****************************************************************** |
| Search for WD/SMC cards |
| ******************************************************************/ |
| for (eth_asic_base = WD_LOW_BASE; eth_asic_base <= WD_HIGH_BASE; |
| eth_asic_base += 0x20) { |
| chksum = 0; |
| for (i=8; i<16; i++) |
| chksum += inb(i+eth_asic_base); |
| if ((chksum & 0x00FF) == 0x00FF) |
| break; |
| } |
| if (eth_asic_base <= WD_HIGH_BASE) { /* We've found a board */ |
| eth_vendor = VENDOR_WD; |
| eth_nic_base = eth_asic_base + WD_NIC_ADDR; |
| c = inb(eth_asic_base+WD_BID); /* Get board id */ |
| for (brd = wd_boards; brd->name; brd++) |
| if (brd->id == c) break; |
| if (!brd->name) { |
| printf("\r\nUnknown Ethernet type %x\r\n", c); |
| return(0); /* Unknown type */ |
| } |
| eth_flags = brd->flags; |
| eth_memsize = brd->memsize; |
| eth_tx_start = 0; |
| eth_rx_start = D8390_TXBUF_SIZE; |
| if ((c == TYPE_WD8013EP) && |
| (inb(eth_asic_base + WD_ICR) & WD_ICR_16BIT)) { |
| eth_flags = FLAG_16BIT; |
| eth_memsize = MEM_16384; |
| } |
| if ((c & WD_SOFTCONFIG) && (!(eth_flags & FLAG_790))) { |
| #ifdef NETBOOT32 |
| eth_bmem = (0x80000 | |
| ((inb(eth_asic_base + WD_MSR) & 0x3F) << 13)); |
| #endif |
| #ifdef NETBOOT16 |
| eth_bmem = inb(eth_asic_base + WD_MSR) & 0x3F; |
| eth_bmem <<= 13; |
| eth_bmem |= 0x80000; |
| #endif |
| } else |
| eth_bmem = WD_DEFAULT_MEM; |
| #ifdef NETBOOT16 |
| /* cast is to force evaluation in long precision */ |
| bmem13 = (Address)eth_bmem >> 13; |
| bmem11 = (Address)eth_bmem >> 11; |
| #endif |
| #ifdef NETBOOT32 |
| if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { |
| *((unsigned int *)(eth_bmem + 8192)) = (unsigned int)0; |
| if (*((unsigned int *)(eth_bmem + 8192))) { |
| brd += 2; |
| eth_memsize = brd->memsize; |
| } |
| } |
| #endif |
| #ifdef NETBOOT16 |
| if (brd->id == TYPE_SMC8216T || brd->id == TYPE_SMC8216C) { |
| i = 0; |
| bcopyf(&i, eth_bmem + 8192, sizeof(i)); |
| if (!fbsame(eth_bmem + 8192, 0, sizeof(i))) { |
| brd += 2; |
| eth_memsize = brd->memsize; |
| } |
| } |
| #endif |
| outb(eth_asic_base + WD_MSR, 0x80); /* Reset */ |
| printf("\r\n%s base 0x%x, memory 0x%x, addr ", |
| brd->name, eth_asic_base, eth_bmem); |
| for (i=0; i<ETHER_ADDR_SIZE; i++) { |
| printf("%x",((int)(nic->node_addr[i] = |
| inb(i+eth_asic_base+WD_LAR)) & 0xff)); |
| if (i < ETHER_ADDR_SIZE-1) printf (":"); |
| } |
| if (eth_flags & FLAG_790) { |
| outb(eth_asic_base+WD_MSR, WD_MSR_MENB); |
| outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) | |
| 0x80)); |
| #ifdef NETBOOT32 |
| outb(eth_asic_base+0x0B, |
| (((unsigned)eth_bmem >> 13) & 0x0F) | |
| (((unsigned)eth_bmem >> 11) & 0x40) | |
| (inb(eth_asic_base+0x0B) & 0xB0)); |
| #endif |
| #ifdef NETBOOT16 |
| outb(eth_asic_base+0x0B, |
| (bmem13 & 0x0F) | |
| (bmem11 & 0x40) | |
| (inb(eth_asic_base+0x0B) & 0xB0)); |
| #endif |
| outb(eth_asic_base+0x04, (inb(eth_asic_base+0x04) & |
| ~0x80)); |
| } else { |
| #ifdef NETBOOT32 |
| outb(eth_asic_base+WD_MSR, |
| (((unsigned)eth_bmem >> 13) & 0x3F) | 0x40); |
| #endif |
| #ifdef NETBOOT16 |
| outb(eth_asic_base+WD_MSR, |
| (bmem13 & 0x3F) | 0x40); |
| #endif |
| } |
| if (eth_flags & FLAG_16BIT) { |
| if (eth_flags & FLAG_790) { |
| eth_laar = inb(eth_asic_base + WD_LAAR); |
| outb(eth_asic_base + WD_LAAR, WD_LAAR_M16EN); |
| inb(0x84); |
| } else { |
| outb(eth_asic_base + WD_LAAR, (eth_laar = |
| WD_LAAR_M16EN | WD_LAAR_L16EN | 1)); |
| } |
| } |
| printf("\r\n"); |
| |
| } |
| #endif |
| #ifdef INCLUDE_T503 |
| /****************************************************************** |
| Search for 3Com 3c503 if no WD/SMC cards |
| ******************************************************************/ |
| if (eth_vendor == VENDOR_NONE) { |
| int idx; |
| static unsigned short base[] = { |
| 0x300, 0x310, 0x330, 0x350, |
| 0x250, 0x280, 0x2A0, 0x2E0, 0 }; |
| /* this must parallel the table above */ |
| static unsigned char bcfr[] = { |
| _3COM_BCFR_300, _3COM_BCFR_310, |
| _3COM_BCFR_330, _3COM_BCFR_350, |
| _3COM_BCFR_250, _3COM_BCFR_280, |
| _3COM_BCFR_2A0, _3COM_BCFR_2E0, 0 }; |
| |
| /* Loop through possible addresses checking each one */ |
| |
| for (idx = 0; (eth_nic_base = base[idx]) != 0; ++idx) { |
| |
| eth_asic_base = eth_nic_base + _3COM_ASIC_OFFSET; |
| /* |
| * Note that we use the same settings for both 8 and 16 bit cards: |
| * both have an 8K bank of memory at page 1 while only the 16 bit |
| * cards have a bank at page 0. |
| */ |
| eth_memsize = MEM_16384; |
| eth_tx_start = 32; |
| eth_rx_start = 32 + D8390_TXBUF_SIZE; |
| |
| /* Check our base address */ |
| |
| if (inb(eth_asic_base + _3COM_BCFR) != bcfr[idx]) |
| continue; /* nope */ |
| |
| /* Now get the shared memory address */ |
| |
| switch (inb(eth_asic_base + _3COM_PCFR)) { |
| case _3COM_PCFR_DC000: |
| eth_bmem = 0xdc000; |
| break; |
| case _3COM_PCFR_D8000: |
| eth_bmem = 0xd8000; |
| break; |
| case _3COM_PCFR_CC000: |
| eth_bmem = 0xcc000; |
| break; |
| case _3COM_PCFR_C8000: |
| eth_bmem = 0xc8000; |
| break; |
| default: |
| continue; /* nope */ |
| } |
| break; |
| } |
| |
| if (base[idx] == 0) /* not found */ |
| return (0); |
| eth_vendor = VENDOR_3COM; |
| |
| |
| /* Need this to make eth_poll() happy. */ |
| |
| eth_rmem = eth_bmem - 0x2000; |
| |
| /* Reset NIC and ASIC */ |
| |
| outb (eth_asic_base + _3COM_CR , _3COM_CR_RST | _3COM_CR_XSEL); |
| outb (eth_asic_base + _3COM_CR , _3COM_CR_XSEL); |
| |
| /* Get our ethernet address */ |
| |
| outb(eth_asic_base + _3COM_CR, _3COM_CR_EALO | _3COM_CR_XSEL); |
| printf("\r\n3Com 3c503 base 0x%x, memory 0x%X addr ", |
| eth_nic_base, eth_bmem); |
| for (i=0; i<ETHER_ADDR_SIZE; i++) { |
| printf("%b",(int)(nic->node_addr[i] = |
| inb(eth_nic_base+i))); |
| if (i < ETHER_ADDR_SIZE-1) printf (":"); |
| } |
| outb(eth_asic_base + _3COM_CR, _3COM_CR_XSEL); |
| /* |
| * Initialize GA configuration register. Set bank and enable shared |
| * mem. We always use bank 1. |
| */ |
| outb(eth_asic_base + _3COM_GACFR, _3COM_GACFR_RSEL | |
| _3COM_GACFR_MBS0); |
| |
| outb(eth_asic_base + _3COM_VPTR2, 0xff); |
| outb(eth_asic_base + _3COM_VPTR1, 0xff); |
| outb(eth_asic_base + _3COM_VPTR0, 0x00); |
| /* |
| * Clear memory and verify that it worked (we use only 8K) |
| */ |
| #ifdef NETBOOT32 |
| bzero((char *)eth_bmem, 0x2000); |
| for(i = 0; i < 0x2000; ++i) |
| if (*(((char *)eth_bmem)+i)) { |
| printf ("Failed to clear 3c503 shared mem.\r\n"); |
| return (0); |
| } |
| #endif |
| #ifdef NETBOOT16 |
| bzerof(eth_bmem, 0x2000); |
| if (!fbsame(eth_bmem, 0, 0x2000)) { |
| printf ("Failed to clear 3c503 shared mem.\r\n"); |
| return (0); |
| } |
| #endif |
| /* |
| * Initialize GA page/start/stop registers. |
| */ |
| outb(eth_asic_base + _3COM_PSTR, eth_tx_start); |
| outb(eth_asic_base + _3COM_PSPR, eth_memsize); |
| |
| printf ("\r\n"); |
| |
| } |
| #endif |
| #if defined(INCLUDE_NE) || defined(INCLUDE_NEPCI) |
| /****************************************************************** |
| Search for NE1000/2000 if no WD/SMC or 3com cards |
| ******************************************************************/ |
| if (eth_vendor == VENDOR_NONE) { |
| char romdata[16], testbuf[32]; |
| int idx; |
| static char test[] = "NE1000/2000 memory"; |
| #ifndef NE_SCAN |
| #define NE_SCAN 0 |
| #endif |
| static unsigned short base[] = {NE_SCAN, 0}; |
| /* if no addresses supplied, fall back on defaults */ |
| if (probe_addrs == 0 || probe_addrs[0] == 0) |
| probe_addrs = base; |
| eth_bmem = 0; /* No shared memory */ |
| for (idx = 0; (eth_nic_base = probe_addrs[idx]) != 0; ++idx) { |
| eth_flags = FLAG_PIO; |
| eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; |
| eth_memsize = MEM_16384; |
| eth_tx_start = 32; |
| eth_rx_start = 32 + D8390_TXBUF_SIZE; |
| c = inb(eth_asic_base + NE_RESET); |
| outb(eth_asic_base + NE_RESET, c); |
| inb(0x84); |
| outb(eth_nic_base + D8390_P0_COMMAND, D8390_COMMAND_STP | |
| D8390_COMMAND_RD2); |
| outb(eth_nic_base + D8390_P0_RCR, D8390_RCR_MON); |
| outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_FT1 | D8390_DCR_LS); |
| outb(eth_nic_base + D8390_P0_PSTART, MEM_8192); |
| outb(eth_nic_base + D8390_P0_PSTOP, MEM_16384); |
| eth_pio_write(test, 8192, sizeof(test)); |
| eth_pio_read(8192, testbuf, sizeof(test)); |
| if (!bcmp(test, testbuf, sizeof(test))) |
| break; |
| eth_flags |= FLAG_16BIT; |
| eth_memsize = MEM_32768; |
| eth_tx_start = 64; |
| eth_rx_start = 64 + D8390_TXBUF_SIZE; |
| outb(eth_nic_base + D8390_P0_DCR, D8390_DCR_WTS | |
| D8390_DCR_FT1 | D8390_DCR_LS); |
| outb(eth_nic_base + D8390_P0_PSTART, MEM_16384); |
| outb(eth_nic_base + D8390_P0_PSTOP, MEM_32768); |
| eth_pio_write(test, 16384, sizeof(test)); |
| eth_pio_read(16384, testbuf, sizeof(test)); |
| if (!bcmp(testbuf, test, sizeof(test))) |
| break; |
| } |
| if (eth_nic_base == 0) |
| return (0); |
| if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ |
| eth_flags |= FLAG_16BIT; |
| eth_vendor = VENDOR_NOVELL; |
| eth_pio_read(0, romdata, 16); |
| printf("\r\nNE*000 base 0x%x, addr ", eth_nic_base); |
| for (i=0; i<ETHER_ADDR_SIZE; i++) { |
| printf("%x",(int)(nic->node_addr[i] = romdata[i |
| + ((eth_flags & FLAG_16BIT) ? i : 0)])); |
| if (i < ETHER_ADDR_SIZE-1) printf (":"); |
| } |
| printf("\r\n"); |
| } |
| #endif |
| if (eth_vendor == VENDOR_NONE) return(0); |
| |
| if (eth_vendor != VENDOR_3COM) eth_rmem = eth_bmem; |
| eth_reset(nic); |
| nic->reset = eth_reset; |
| nic->poll = eth_poll; |
| nic->transmit = eth_transmit; |
| nic->disable = eth_disable; |
| return(nic); |
| } |
| |
| #endif |
| |
| /* |
| * Local variables: |
| * c-basic-offset: 8 |
| * End: |
| */ |