update the network support to etherboot-4.5.8.

This commit is contained in:
okuji committed 2000-04-22 01:17:09 +00:00
1 parent 26fef18cb8
commit 5ff25f9b8f
51 files changed
+5395 -3479

No files matched your search

+605 -286
View File
@@ -1,380 +1,699 @@
/*
Etherboot DEC Tulip driver
adapted by Ken Yap from
/*
Tulip and clone Etherboot Driver
By Marty Connor (mdc@thinguin.org)
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
FreeBSD netboot DEC 21143 driver
Based on Ken Yap's Tulip Etherboot Driver and Donald Becker's
Linux Tulip Driver. Supports N-Way speed auto-configuration on
MX98715, MX98715A and MX98725. Support inexpensive PCI 10/100 cards
based on the Macronix MX987x5 chip, such as the SOHOware Fast
model SFA110A, and the LinkSYS model LNE100TX. The NetGear
model FA310X, based on the LC82C168 chip is supported.
The TRENDnet TE100-PCIA NIC which uses a genuine Intel 21143-PD
chipset is supported.
Author: David Sharp
date: Nov/98
Documentation and source code used:
Source for Etherboot driver at
http://etherboot.sourceforge.net/
MX98715A Data Sheet and MX98715A Application Note
on http://www.macronix.com/ (PDF format files)
Source for Linux tulip driver at
http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
Known to work on DEC DE500 using 21143-PC chipset.
Even on cards with the same chipset there can be
incompatablity problems with the way media selection
and status LED settings are done. See comments below.
Some code fragments were taken from verious places,
Ken Yap's etherboot, FreeBSD's if_de.c, and various
Linux related files. DEC's manuals for the 21143 and
SROM format were very helpful. The Linux de driver
development page has a number of links to useful
related information. Have a look at:
ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html
Adapted by Ken Yap from
FreeBSD netboot DEC 21143 driver
Author: David Sharp
date: Nov/98
Some code fragments were taken from verious places, Ken Yap's
etherboot, FreeBSD's if_de.c, and various Linux related files.
DEC's manuals for the 21143 and SROM format were very helpful.
The Linux de driver development page has a number of links to
useful related information. Have a look at:
ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/tulip-devel.html
*/
/*********************************************************************/
/* Revision History */
/*********************************************************************/
/*
29 Feb 2000 mdc 0.75b7
Increased reset delay to 3 seconds because Macronix cards seem to
need more reset time before card comes back to a usable state.
26 Feb 2000 mdc 0.75b6
Added a 1 second delay after initializing the transmitter because
some cards seem to need the time or they drop the first packet
transmitted.
23 Feb 2000 mdc 0.75b5
removed udelay code and used currticks() for more reliable delay
code in reset pause and sanity timeouts. Added function prototypes
and TX debugging code.
21 Feb 2000 mdc patch to Etherboot 4.4.3
Incorporated patches from Bob Edwards and Paul Mackerras of
Linuxcare's OZLabs to deal with inefficiencies in tulip_transmit
and udelay. We now wait for packet transmission to complete
(or sanity timeout).
04 Feb 2000 Robert.Edwards@anu.edu.au patch to Etherboot 4.4.2
patch to tulip.c that implements the automatic selection of the MII
interface on cards using the Intel/DEC 21143 reference design, in
particular, the TRENDnet TE100-PCIA NIC which uses a genuine Intel
21143-PD chipset.
11 Jan 2000 mdc 0.75b4
Added support for NetGear FA310TX card based on the LC82C168
chip. This should also support Lite-On LC82C168 boards.
Added simple MII support. Re-arranged code to better modularize
initializations.
04 Dec 1999 mdc 0.75b3
Added preliminary support for LNE100TX PCI cards. Should work for
PNIC2 cards. No MII support, but single interface (RJ45) tulip
cards seem to not care.
03 Dec 1999 mdc 0.75b2
Renamed from mx987x5 to tulip, merged in original tulip init code
from tulip.c to support other tulip compatible cards.
02 Dec 1999 mdc 0.75b1
Released Beta MX987x5 Driver for code review and testing to netboot
and thinguin mailing lists.
*/
/*********************************************************************/
/* Declarations */
/*********************************************************************/
#include "etherboot.h"
#include "nic.h"
#include "pci.h"
#include "tulip.h"
#include "cards.h"
#undef TULIP_DEBUG
#undef TULIP_DEBUG_WHERE
#define TX_TIME_OUT 2*TICKS_PER_SEC
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
/* Register offsets for tulip device */
enum tulip_offsets {
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78, CSR16=0x80, CSR20=0xA0
};
#define DEC_21142_CSR6_TTM 0x00400000 /* Transmit Threshold Mode */
#define DEC_21142_CSR6_HBD 0x00080000 /* Heartbeat Disable */
#define DEC_21142_CSR6_PS 0x00040000 /* Port Select */
/* EEPROM Address width definitions */
#define EEPROM_ADDRLEN 6
#define EEPROM_SIZE 128 /* 2 << EEPROM_ADDRLEN */
/* Data Read from the EEPROM */
static unsigned char ee_data[EEPROM_SIZE];
/* The EEPROM commands include the alway-set leading bit. */
#define EE_WRITE_CMD (5 << addr_len)
#define EE_READ_CMD (6 << addr_len)
#define EE_ERASE_CMD (7 << addr_len)
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
#define EE_CS 0x01 /* EEPROM chip select. */
#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
#define EE_WRITE_0 0x01
#define EE_WRITE_1 0x05
#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
#define EE_ENB (0x4800 | EE_CS)
/* Delay between EEPROM clock transitions. Even at 33Mhz current PCI
implementations don't overrun the EEPROM clock. We add a bus
turn-around to insure that this remains true. */
#define eeprom_delay() inl(ee_addr)
/* helpful macro if on a big_endian machine for changing byte order.
not strictly needed on Intel */
#define le16_to_cpu(val) (val)
/* transmit and receive descriptor format */
struct txdesc {
volatile unsigned long status; /* owner, status */
unsigned long buf1sz:11, /* size of buffer 1 */
buf2sz:11, /* size of buffer 2 */
control:10; /* control bits */
const unsigned char *buf1addr; /* buffer 1 address */
const unsigned char *buf2addr; /* buffer 2 address */
};
struct rxdesc {
volatile unsigned long status; /* owner, status */
unsigned long buf1sz:11, /* size of buffer 1 */
buf2sz:11, /* size of buffer 2 */
control:10; /* control bits */
unsigned char *buf1addr; /* buffer 1 address */
unsigned char *buf2addr; /* buffer 2 address */
};
/* Size of transmit and receive buffers */
#define BUFLEN 1536
/*********************************************************************/
/* Global Storage */
/*********************************************************************/
/* PCI Bus parameters */
static unsigned short vendor, dev_id;
static unsigned short ioaddr;
static unsigned int *membase;
static unsigned long devfn;
static unsigned char srom[1024];
static unsigned long ioaddr;
#define BUFLEN 1600 /* must be longword divisable */
/* buffers must be longword aligned */
/* Note: transmit and receive buffers must be longword aligned and
longword divisable */
/* transmit descriptor and buffer */
static struct txrxdesc txd;
static unsigned char txb[BUFLEN];
static struct txdesc txd __attribute__ ((aligned(4)));
#ifndef USE_INTERNAL_BUFFER
#define txb ((char *)0x10000 - BUFLEN)
#else
static unsigned char txb[BUFLEN] __attribute__ ((aligned(4)));
#endif
/* receive descriptor(s) and buffer(s) */
#define NRXD 4
static struct txrxdesc rxd[NRXD];
static int rxd_tail = 0;
static unsigned char rxb[NRXD][BUFLEN];
static struct rxdesc rxd[NRXD] __attribute__ ((aligned(4)));
#ifndef USE_INTERNAL_BUFFER
#define rxb ((char *)0x10000 - NRXD * BUFLEN - BUFLEN)
#else
static unsigned char rxb[NRXD * BUFLEN] __attribute__ ((aligned(4)));
#endif
static int rxd_tail;
static unsigned char ehdr[ETHER_HDR_SIZE]; /* buffer for ethernet header */
/* buffer for ethernet header */
static unsigned char ehdr[ETHER_HDR_SIZE];
enum tulip_offsets {
CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
/*********************************************************************/
/* Function Prototypes */
/*********************************************************************/
static void whereami(const char *str);
static int lc82c168_mdio_read(int phy_id, int location);
static void lc82c168_mdio_write(int phy_id, int location, int value);
static void lc82c168_do_mii();
static int read_eeprom(unsigned long ioaddr, int location, int addr_len);
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs,
struct pci_device *pci);
static void tulip_init_ring(struct nic *nic);
static void tulip_reset(struct nic *nic);
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t,
unsigned int s, const char *p);
static int tulip_poll(struct nic *nic);
static void tulip_disable(struct nic *nic);
static void whereami (const char *str);
#ifdef TULIP_DEBUG
static void tulip_more(void);
#endif /* TULIP_DEBUG */
static void tulip_wait(unsigned int nticks);
/*********************************************************************/
/* Utility Routines */
/*********************************************************************/
/***************************************************************************/
/* 21143 specific stuff */
/***************************************************************************/
/* XXX assume 33MHz PCI bus, this is not very accurate and should be
used only with gross over estimations of required delay times unless
you tune UADJUST to your specific processor and I/O subsystem */
#define UADJUST 870
static void udelay(unsigned long usec) {
unsigned long i;
for (i=((usec*UADJUST)/33)+1; i>0; i--) (void) TULIP_CSR_READ(csr_0);
static inline void whereami (const char *str)
{
#ifdef TULIP_DEBUG_WHERE
printf("%s\n", str);
/* sleep(2); */
#endif
}
/* The following srom related code was taken from FreeBSD's if_de.c */
/* with minor alterations to make it work here. the Linux code is */
/* better but this was easier to use */
static void delay_300ns()
#ifdef TULIP_DEBUG
static void tulip_more()
{
int idx;
for (idx = (300 / 33) + 1; idx > 0; idx--)
(void) TULIP_CSR_READ(csr_busmode);
printf("\n\n-- more --");
while (!iskey())
/* wait */;
getchar();
printf("\n\n");
}
#endif /* TULIP_DEBUG */
static void tulip_wait(unsigned int nticks)
{
unsigned int to = currticks() + nticks;
while (currticks() < to)
/* wait */ ;
}
#define EMIT do { TULIP_CSR_WRITE(csr_srom_mii, csr); delay_300ns(); } while (0)
static void srom_idle()
/*********************************************************************/
/* Media Descriptor Code */
/*********************************************************************/
static int lc82c168_mdio_read(int phy_id, int location)
{
unsigned bit, csr;
int i = 1000;
int retval = 0;
csr = SROMSEL ; EMIT;
csr = SROMSEL | SROMRD; EMIT;
csr ^= SROMCS; EMIT;
csr ^= SROMCLKON; EMIT;
/*
* Write 25 cycles of 0 which will force the SROM to be idle.
*/
for (bit = 3 + SROM_BITWIDTH + 16; bit > 0; bit--) {
csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
csr ^= SROMCLKON; EMIT; /* clock high; data valid */
whereami("mdio_read\n");
outl(0x60020000 | (phy_id<<23) | (location<<18), ioaddr + 0xA0);
inl(ioaddr + 0xA0);
inl(ioaddr + 0xA0);
while (--i > 0)
if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
return retval & 0xFFFF;
if (i == 0) printf("mdio read timeout!\n");
return 0xFFFF;
}
static void lc82c168_mdio_write(int phy_id, int location, int value)
{
int i = 1000;
int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
whereami("mdio_write\n");
outl(cmd, ioaddr + 0xA0);
do
if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
break;
while (--i > 0);
if (i == 0) printf("mdio write timeout!\n");
return;
}
static void lc82c168_do_mii(void)
{
int phy, phy_idx;
whereami("do_mii\n");
for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < 4; phy++) {
int mii_status = lc82c168_mdio_read(phy, 1);
if ((mii_status & 0x8301) == 0x8001 ||
((mii_status & 0x8000) == 0 && (mii_status & 0x7800) != 0)) {
int mii_reg0 = lc82c168_mdio_read(phy, 0);
int mii_advert = lc82c168_mdio_read(phy, 4);
int mii_reg4 = ((mii_status >> 6) & 0x01E1) | 1;
phy_idx++;
printf("%s: MII trcvr #%d "
"config %x status %x advertising %x reg4 %x.\n",
"LC82C168", phy, mii_reg0, mii_status, mii_advert, mii_reg4);
lc82c168_mdio_write(phy, 0, mii_reg0 | 0x1000);
if (mii_advert != mii_reg4)
lc82c168_mdio_write(phy, 4, mii_reg4);
}
csr ^= SROMCLKOFF; EMIT;
csr ^= SROMCS; EMIT;
csr = 0; EMIT;
}
#ifdef TULIP_DEBUG
printf("mii_cnt = %d\n", phy_idx);
#endif
}
static void srom_read()
/*********************************************************************/
/* EEPROM Reading Code */
/*********************************************************************/
/* EEPROM routines adapted from the Linux Tulip Code */
/* Reading a serial EEPROM is a "bit" grungy, but we work our way
through:->.
*/
static int read_eeprom(unsigned long ioaddr, int location, int addr_len)
{
unsigned idx;
const unsigned bitwidth = SROM_BITWIDTH;
const unsigned cmdmask = (SROMCMD_RD << bitwidth);
const unsigned msb = 1 << (bitwidth + 3 - 1);
unsigned lastidx = (1 << bitwidth) - 1;
int i;
unsigned short retval = 0;
long ee_addr = ioaddr + CSR9;
int read_cmd = location | EE_READ_CMD;
srom_idle();
whereami("read_eeprom\n");
for (idx = 0; idx <= lastidx; idx++) {
unsigned lastbit, data, bits, bit, csr;
csr = SROMSEL ; EMIT;
csr = SROMSEL | SROMRD; EMIT;
csr ^= SROMCSON; EMIT;
csr ^= SROMCLKON; EMIT;
outl(EE_ENB & ~EE_CS, ee_addr);
outl(EE_ENB, ee_addr);
lastbit = 0;
for (bits = idx|cmdmask, bit = bitwidth + 3; bit > 0; bit--, bits <<= 1)
{
const unsigned thisbit = bits & msb;
csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
if (thisbit != lastbit) {
csr ^= SROMDOUT; EMIT; /* clock low; invert data */
} else {
EMIT;
}
csr ^= SROMCLKON; EMIT; /* clock high; data valid */
lastbit = thisbit;
}
csr ^= SROMCLKOFF; EMIT;
/* Shift the read command bits out. */
for (i = 4 + addr_len; i >= 0; i--) {
short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
outl(EE_ENB | dataval, ee_addr);
eeprom_delay();
outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
}
outl(EE_ENB, ee_addr);
for (data = 0, bits = 0; bits < 16; bits++) {
data <<= 1;
csr ^= SROMCLKON; EMIT; /* clock high; data valid */
data |= TULIP_CSR_READ(csr_srom_mii) & SROMDIN ? 1 : 0;
csr ^= SROMCLKOFF; EMIT; /* clock low; data not valid */
}
srom[idx*2] = data & 0xFF;
srom[idx*2+1] = data >> 8;
csr = SROMSEL | SROMRD; EMIT;
csr = 0; EMIT;
}
srom_idle();
for (i = 16; i > 0; i--) {
outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
eeprom_delay();
retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
outl(EE_ENB, ee_addr);
eeprom_delay();
}
/* Terminate the EEPROM access. */
outl(EE_ENB & ~EE_CS, ee_addr);
return retval;
}
/*********************************************************************/
/* tulip_init_ring - setup the tx and rx descriptors */
/*********************************************************************/
static void tulip_init_ring(struct nic *nic)
{
int i;
/**************************************************************************
ETH_RESET - Reset adapter
***************************************************************************/
/* setup the transmit descriptor */
txd.buf1addr = &txb[0];
txd.buf2addr = &txb[0]; /* just in case */
txd.buf1sz = 192; /* setup packet must be 192 bytes */
txd.buf2sz = 0;
txd.control = 0x028; /* setup packet + TER */
txd.status = 0x80000000; /* give ownership to device */
/* 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];
/* setup receive descriptor */
for (i=0; i<NRXD; i++) {
rxd[i].buf1addr = &rxb[i * BUFLEN];
rxd[i].buf2addr = 0; /* not used */
rxd[i].buf1sz = BUFLEN;
rxd[i].buf2sz = 0; /* not used */
rxd[i].control = 0x0;
rxd[i].status = 0x80000000; /* give ownership to device */
}
/* Set Receive end of ring on last descriptor */
rxd[NRXD - 1].control = 0x008;
rxd_tail = 0;
}
/*********************************************************************/
/* eth_reset - Reset adapter */
/*********************************************************************/
static void tulip_reset(struct nic *nic)
{
int x,cnt=2;
unsigned long csr6,csr15;
unsigned long to, csr6;
outl(0x00000001, ioaddr + CSR0);
udelay(1000);
/* turn off reset and set cache align=16lword, burst=unlimit */
outl(0x01A08000, ioaddr + CSR0);
whereami("tulip_reset\n");
/* for some reason the media selection does not take
the first time se it is repeated. */
/* Stop Tx and RX */
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
while(cnt--) {
/* stop TX,RX processes */
if (cnt == 1)
outl(0x32404000, ioaddr + CSR6);
else
outl(0x32000040, ioaddr + CSR6);
if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) {
/* set up 10-BASE-T Control Port */
outl(0xFFFFFFFF, ioaddr + CSR14);
/* set up 10-BASE-T Status Port */
outl(0x00001000, ioaddr + CSR12);
/* Set Operation Control Register (CSR6) for MX987x5
to allow N-Way Active Speed selection, and
start the chip's Tx to process setup frame.
While it is possible to force speed selection,
this is probably more useful most of the time.
*/
outl(0x01A80200, ioaddr + CSR6);
/* XXX - media selection is vendor specific and hard coded right
here. This should be fixed to use the hints in the SROM and
allow media selection by the user at runtime. MII support
should also be added. Support for chips other than the
21143 should be added here as well */
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_LC82C115) {
/* This is MX987x5 init code. It seems to work for the LNE100TX
but should be replaced when we figure out the right way
to do this initialization
*/
outl(0xFFFFFFFF, ioaddr + CSR14);
outl(0x00001000, ioaddr + CSR12);
outl(0x01A80200, ioaddr + CSR6);
/* start set to 10Mbps half-duplex */
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) {
/* setup SIA */
outl(0x0, ioaddr + CSR13); /* reset SIA */
outl(0x7f3f, ioaddr + CSR14);
outl(0x8000008, ioaddr + CSR15);
outl(0x0, ioaddr + CSR13);
outl(0x1, ioaddr + CSR13);
outl(0x2404000, ioaddr + CSR6);
lc82c168_do_mii();
/* initalize GP */
outl(0x8af0008, ioaddr + CSR15);
outl(0x50008, ioaddr + CSR15);
} else if (vendor == PCI_VENDOR_ID_DEC && dev_id == PCI_DEVICE_ID_DEC_21142) {
/* nothing */
} else {
/* If we don't know what to do with the card, set to 10Mbps half-duplex */
/* end set to 10Mbps half-duplex */
outl(0x00000000, ioaddr + CSR13);
outl(0x7F3F0000, ioaddr + CSR14);
outl(0x08000008, ioaddr + CSR15);
outl(0x00000000, ioaddr + CSR13);
outl(0x00000001, ioaddr + CSR13);
outl(0x02404000, ioaddr + CSR6);
outl(0x08AF0008, ioaddr + CSR15);
outl(0x00050008, ioaddr + CSR15);
if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) {
/* do stuff for MX98715 */
outl(0x01a80000, ioaddr + CSR6);
outl(0xFFFFFFFF, ioaddr + CSR14);
outl(0x00001000, ioaddr + CSR12);
}
outl(0x0, ioaddr + CSR7); /* disable interrupts */
}
/* construct setup packet which is used by the 21143 to
program its CAM to recognize interesting MAC addresses */
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
outl(0x00000001, ioaddr + CSR0);
memset(&txd, 0, sizeof(struct txrxdesc));
txd.buf1addr = &txb[0];
txd.buf2addr = &txb[0]; /* just in case */
txd.buf1sz = 192; /* setup packet must be 192 bytes */
txd.buf2sz = 0;
txd.control = 0x020; /* setup packet */
txd.status = 0x80000000; /* give ownership to 21143 */
tulip_wait(3*TICKS_PER_SEC);
/* construct perfect filter frame */
/* with mac address as first match */
/* and broadcast address for all others */
/* turn off reset and set cache align=16lword, burst=unlimit */
outl(0x01A08000, ioaddr + CSR0);
for(x=0;x<192;x++) txb[x] = 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];
outl((unsigned long)&txd, ioaddr + CSR4); /* set xmit buf */
outl(0x2406000, ioaddr + CSR6); /* start transmiter */
/* set up transmit and receive descriptors */
tulip_init_ring(nic);
udelay(50000); /* wait for the setup packet to be processed */
/* Point to receive descriptor */
outl((unsigned long)&rxd[0], ioaddr + CSR3);
outl((unsigned long)&txd , ioaddr + CSR4);
}
csr6 = 0x02404000;
/* setup receive descriptor */
{
int x;
for(x=0;x<NRXD;x++) {
memset(&rxd[x], 0, sizeof(struct txrxdesc));
rxd[x].buf1addr = &rxb[x][0];
rxd[x].buf2addr = 0; /* not used */
rxd[x].buf1sz = BUFLEN;
rxd[x].buf2sz = 0; /* not used */
rxd[x].control = 0x0;
rxd[x].status = 0x80000000; /* give ownership it to 21143 */
}
rxd[NRXD - 1].control = 0x008; /* Set Receive end of ring on la
st descriptor */
rxd_tail = 0;
}
/* Chip specific init code */
/* tell DC211XX where to find rx descriptor list */
outl((unsigned long)&rxd[0], ioaddr + CSR3);
/* start the receiver */
outl(0x2406002, ioaddr + CSR6);
if (vendor == PCI_VENDOR_ID_MACRONIX && dev_id == PCI_DEVICE_ID_MX987x5) {
csr6 = 0x01880200;
/* Set CSR16 and CSR20 to values that allow device modification */
outl(0x0B3C0000 | inl(ioaddr + CSR16), ioaddr + CSR16);
outl(0x00011000 | inl(ioaddr + CSR20), ioaddr + CSR20);
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_LC82C115) {
/* This is MX987x5 init code. It seems to work for the LNE100TX
but should be replaced when we figure out the right way
to do this initialization.
*/
csr6 = 0x01880200;
outl(0x0B3C0000 | inl(ioaddr + CSR16), ioaddr + CSR16);
outl(0x00011000 | inl(ioaddr + CSR20), ioaddr + CSR20);
} else if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) {
csr6 = 0x814C0000;
outl(0x00000001, ioaddr + CSR15);
} else if (vendor == PCI_VENDOR_ID_DEC && dev_id == PCI_DEVICE_ID_DEC_21142) {
/* check SROM for evidence of an MII interface */
/* get Controller_0 Info Leaf Offset from SROM - assume already in ee_data */
int offset = ee_data [27] + (ee_data [28] << 8);
/* check offset range and if we have an extended type 3 Info Block */
if ((offset >= 30) && (offset < 120) && (ee_data [offset + 3] > 128) &&
(ee_data [offset + 4] == 3)) {
/* must have an MII interface - disable heartbeat, select port etc. */
csr6 |= (DEC_21142_CSR6_HBD | DEC_21142_CSR6_PS);
csr6 &= ~(DEC_21142_CSR6_TTM);
}
}
/* set the chip's operating mode */
outl(csr6, ioaddr + CSR6);
/* Start Tx */
outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6);
/* immediate transmit demand */
outl(0, ioaddr + CSR1);
to = currticks() + TX_TIME_OUT;
while ((txd.status & 0x80000000) && (currticks() < to))
/* wait */ ;
if (currticks() >= to) {
printf ("TX Setup Timeout!\n");
}
#ifdef TULIP_DEBUG
printf("txd.status = %X\n", txd.status);
printf("ticks = %d\n", currticks() - (to - TX_TIME_OUT));
tulip_more();
#endif
/* enable RX */
outl(inl(ioaddr + CSR6) | 0x00000002, ioaddr + CSR6);
/* immediate poll demand */
outl(0, ioaddr + CSR2);
}
/**************************************************************************
ETH_TRANSMIT - Transmit a frame
***************************************************************************/
static const char padmap[] = {
0, 3, 2, 1};
static void tulip_transmit(struct nic *nic, char *d, unsigned int t, unsigned int s, char *p)
/*********************************************************************/
/* eth_transmit - Transmit a frame */
/*********************************************************************/
static void tulip_transmit(struct nic *nic, const char *d, unsigned int t,
unsigned int s, const char *p)
{
unsigned int len;
int pad;
int status;
unsigned char c;
unsigned long time;
unsigned long to;
/* setup ethernet header */
whereami("tulip_transmit\n");
memcpy(ehdr, d, ETHER_ADDR_SIZE);
memcpy(&ehdr[ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE);
ehdr[ETHER_ADDR_SIZE*2] = (t >> 8) & 0xff;
ehdr[ETHER_ADDR_SIZE*2+1] = t & 0xff;
/* Stop Tx */
outl(inl(ioaddr + CSR6) & ~0x00002000, ioaddr + CSR6);
/* setup the transmit descriptor */
/* setup ethernet header */
memcpy(ehdr, d, ETHER_ADDR_SIZE);
memcpy(&ehdr[ETHER_ADDR_SIZE], nic->node_addr, ETHER_ADDR_SIZE);
ehdr[ETHER_ADDR_SIZE*2] = (t >> 8) & 0xFF;
ehdr[ETHER_ADDR_SIZE*2+1] = t & 0xFF;
memset(&txd, 0, sizeof(struct txrxdesc));
/* setup the transmit descriptor */
txd.buf1addr = &ehdr[0]; /* ethernet header */
txd.buf1sz = ETHER_HDR_SIZE;
txd.buf2addr = p; /* packet to transmit */
txd.buf2sz = s;
txd.control = 0x00000188; /* LS+FS+TER */
txd.status = 0x80000000; /* give ownership to device */
txd.buf1addr = &ehdr[0]; /* ethernet header */
txd.buf1sz = ETHER_HDR_SIZE;
/* Point to transmit descriptor */
outl((unsigned long)&txd, ioaddr + CSR4);
txd.buf2addr = p; /* packet to transmit */
txd.buf2sz = s;
/* Start Tx */
outl(inl(ioaddr + CSR6) | 0x00002000, ioaddr + CSR6);
txd.control = 0x188; /* LS+FS+TER */
/* immediate transmit demand */
outl(0, ioaddr + CSR1);
txd.status = 0x80000000; /* give it to 21143 */
to = currticks() + TX_TIME_OUT;
while ((txd.status & 0x80000000) && (currticks() < to))
/* wait */ ;
outl(inl(ioaddr + CSR6) & ~0x00004000, ioaddr + CSR6);
outl((unsigned long)&txd, ioaddr + CSR4);
outl(inl(ioaddr + CSR6) | 0x00004000, ioaddr + CSR6);
/* Wait for transmit to complete before returning. not well tested.
time = currticks();
while(txd.status & 0x80000000) {
if (currticks() - time > 20) {
printf("transmit timeout.\n");
break;
}
}
*/
if (currticks() >= to) {
printf ("TX Timeout!\n");
}
}
/**************************************************************************
ETH_POLL - Wait for a frame
***************************************************************************/
/*********************************************************************/
/* eth_poll - Wait for a frame */
/*********************************************************************/
static int tulip_poll(struct nic *nic)
{
/* common variables */
unsigned short type = 0;
int x;
whereami("tulip_poll\n");
if (rxd[rxd_tail].status & 0x80000000) return 0;
if (rxd[rxd_tail].status & 0x80000000)
return 0;
nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
whereami("tulip_poll got one\n");
/* copy packet to working buffer */
/* XXX - this copy could be avoided with a little more work
but for now we are content with it because the optimised
memcpy(, , ) is quite fast */
nic->packetlen = (rxd[rxd_tail].status & 0x3FFF0000) >> 16;
memcpy(nic->packet, &rxb[rxd_tail][0], nic->packetlen);
/* copy packet to working buffer */
/* XXX - this copy could be avoided with a little more work
but for now we are content with it because the optimised
memcpy is quite fast */
/* return the descriptor and buffer to recieve ring */
rxd[rxd_tail].status = 0x80000000;
rxd_tail++;
if (rxd_tail == NRXD) rxd_tail = 0;
memcpy(nic->packet, rxb + rxd_tail * BUFLEN, nic->packetlen);
return 1;
/* return the descriptor and buffer to receive ring */
rxd[rxd_tail].status = 0x80000000;
rxd_tail++;
if (rxd_tail == NRXD) rxd_tail = 0;
return 1;
}
/*********************************************************************/
/* eth_disable - Disable the interface */
/*********************************************************************/
static void tulip_disable(struct nic *nic)
{
/* nothing for the moment */
whereami("tulip_disable\n");
/* The other Etherboot drivers don't seem to do anything here,
so for now, we will not either */
#if 0
/* 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);
#endif
}
/*********************************************************************/
/* eth_probe - Look for an adapter */
/*********************************************************************/
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs,
struct pci_device *pci)
{
unsigned int i;
/**************************************************************************
ETH_PROBE - Look for an adapter
***************************************************************************/
struct nic *tulip_probe(struct nic *nic, unsigned short *io_addrs, struct pci_device *pci)
{
int i;
whereami("tulip_probe\n");
if (io_addrs == 0 || *io_addrs == 0)
return (0);
vendor = pci->vendor;
dev_id = pci->dev_id;
ioaddr = *io_addrs;
membase = (unsigned int *)pci->membase;
if (io_addrs == 0 || *io_addrs == 0)
return 0;
/* wakeup chip */
pcibios_write_config_dword(0,pci->devfn,0x40,0x00000000);
vendor = pci->vendor;
dev_id = pci->dev_id;
ioaddr = *io_addrs;
/* Stop the chip's Tx and Rx processes. */
/* outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6); */
/* Clear the missed-packet counter. */
/* (volatile int)inl(ioaddr + CSR8); */
/* wakeup chip */
pcibios_write_config_dword(0, pci->devfn, 0x40, 0x00000000);
srom_read();
/* Stop the chip's Tx and Rx processes. */
outl(inl(ioaddr + CSR6) & ~0x00002002, ioaddr + CSR6);
for (i=0; i < 6; i++)
nic->node_addr[i] = srom[20+i];
/* Clear the missed-packet counter. */
(volatile unsigned long)inl(ioaddr + CSR8);
printf("Tulip %b:%b:%b:%b:%b:%b at ioaddr 0x%x\n",
srom[20],srom[21],srom[22],srom[23],srom[24],srom[25],
ioaddr);
/* Get MAC Address */
tulip_reset(nic);
/* Hardware Address retrieval method for LC82C168 */
if (vendor == PCI_VENDOR_ID_LINKSYS && dev_id == PCI_DEVICE_ID_DEC_TULIP) {
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);
nic->node_addr[i*2] = (u8)((value >> 8) & 0xFF);
nic->node_addr[i*2 + 1] = (u8)( value & 0xFF);
}
} else {
/* read EEPROM data */
for (i = 0; i < sizeof(ee_data)/2; i++)
((unsigned short *)ee_data)[i] =
le16_to_cpu(read_eeprom(ioaddr, i, EEPROM_ADDRLEN));
nic->reset = tulip_reset;
nic->poll = tulip_poll;
nic->transmit = tulip_transmit;
nic->disable = tulip_disable;
return nic;
/* extract MAC address from EEPROM buffer */
for (i=0; i<6; i++)
nic->node_addr[i] = ee_data[20+i];
}
printf("Tulip %b:%b:%b:%b:%b:%b at ioaddr 0x%x\n",
nic->node_addr[0],nic->node_addr[1],nic->node_addr[2],nic->node_addr[3],
nic->node_addr[4],nic->node_addr[5],ioaddr);
/* initialize device */
tulip_reset(nic);
nic->reset = tulip_reset;
nic->poll = tulip_poll;
nic->transmit = tulip_transmit;
nic->disable = tulip_disable;
return nic;
}