blob: 9c19730c81ff805c48fecfff825e227524315c36 [file] [log] [blame] [raw]
/**************************************************************************
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:
*/