mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-21 06:49:35 +00:00
747 lines
23 KiB
C
747 lines
23 KiB
C
|
|
/**************************************************************************
|
|
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:
|
|
*/
|