2003-09-03 Jiri Gaisler <jiri@gaisler.com>

PR 477/networking
	* network/Makefile.am: Add driver for OpenCores NIC.
	* network/README.open_eth, network/open_eth.c, network/open_eth.h:
	New files.
This commit is contained in:
Joel Sherrill
2003-09-03 13:28:47 +00:00
parent 5a5347ba2c
commit 62ff2e4fc4
5 changed files with 998 additions and 4 deletions

View File

@@ -1,3 +1,10 @@
2003-09-03 Jiri Gaisler <jiri@gaisler.com>
PR 477/networking
* network/Makefile.am: Add driver for OpenCores NIC.
* network/README.open_eth, network/open_eth.c, network/open_eth.h:
New files.
2003-08-21 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* ide/Makefile.am: Don't include @RTEMS_BSP@.cfg.

View File

@@ -8,10 +8,11 @@ include_libchipdir = $(includedir)/libchip
LIBNAME = libnetchip
LIB = $(ARCH)/$(LIBNAME).a
C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c
C_FILES = cs8900.c dec21140.c i82586.c sonic.c if_fxp.c elnk.c open_eth.c
OBJS = $(C_FILES:%.c=$(ARCH)/%.$(OBJEXT))
include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h mii.h
include_libchip_HEADERS = cs8900.h i82586var.h if_fxpvar.h sonic.h if_media.h \
mii.h open_eth.h
include $(top_srcdir)/../../../automake/compile.am
include $(top_srcdir)/../../../automake/lib.am
@@ -46,7 +47,8 @@ endif
.PRECIOUS: $(LIB)
EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 README.sonic \
cs8900.c cs8900.c.bsp dec21140.c i82586.c if_fxp.c sonic.c
EXTRA_DIST = README README.cs8900 README.dec21140 README.i82586 \
README.open_eth README.sonic cs8900.c cs8900.c.bsp dec21140.c \
i82586.c if_fxp.c open_eth.c sonic.c
include $(top_srcdir)/../../../automake/local.am

View File

@@ -0,0 +1,73 @@
Driver for opencores ethernet MAC - README
------------------------------------------
The device name for the driver is 'open_eth1', the attach
function for the leon bsp is rtems_leon_open_eth_driver_attach().
No cache flushing is made when a frame is received. On leon,
this means that cache snooping must be configured in the
vhdl model and enabled by software.
TX interrupts are not used and masked in the interrupt mask
register.
For now, only 10 Mbit/s half-duplex is supported.
100 Mbit/s operations does not work reliably, the transmitter
locks up or skips frames. Seems to depend on the TX fifo
implementation in the opencores MAC. Send a mail to
jiri@gaisler.com if you know how to fix this.
Tested only on leon, using the GR-PCI-XC2V board @ 40 MHz.
Output from ttcp receiving 1 Mbyte file:
>>> ttcp -r -s
ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp
ttcp-r: socket
ttcp-r: accept from 192.168.0.2
ttcp-r: 1145339 bytes in 1.18 real seconds = 947.88 KB/sec +++
ttcp-r: 792 I/O calls, msec/call = 1.53, calls/sec = 671.19
ttcp-r: 0.0user 1.1sys 0:01real 100% 0i+0d 0maxrss 0+0pf 0+0csw
************ MBUF STATISTICS ************
mbufs:1024 clusters: 128 free: 112
drops: 0 waits: 0 drains: 0
free:1007 data:17 header:0 socket:0
pcb:0 rtable:0 htable:0 atable:0
soname:0 soopts:0 ftable:0 rights:0
ifaddr:0 control:0 oobdata:0
************ INTERFACE STATISTICS ************
***** open_eth1 *****
Address:192.168.0.66 Broadcast Address:192.168.0.255
Flags: Up Broadcast Running Simplex
Send queue limit:50 length:0 Dropped:0
Rx Packets:796 Rx Interrupts:796 Length:0
Bad CRC:0 Overrun:0 Miss:0
Tx Interrupts:0 Deferred:0 Missed Hearbeat:0
No Carrier:0 Retransmit Limit:0 Late Collision:0
Underrun:0 Raw output wait:0
************ IP Statistics ************
total packets received 795
datagrams delivered to upper level 795
total ip packets generated here 401
************ TCP Statistics ************
connections accepted 1
connections established 1
conn. closed (includes drops) 1
segs where we tried to get rtt 2
times we succeeded 2
delayed acks sent 4
total packets sent 401
ack-only packets sent 6
window update-only packets sent 394
control (SYN|FIN|RST) packets sent 1
total packets received 795
packets received in sequence 792
bytes received in sequence 1145339
rcvd ack packets 2
bytes acked by rcvd acks 2
times hdr predict ok for data pkts 791

View File

@@ -0,0 +1,739 @@
/*
* RTEMS driver for Opencores Ethernet Controller
*
* Weakly based on dec21140 rtems driver and open_eth linux driver
* Written by Jiri Gaisler, Gaisler Research
*
* The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at
* http://www.OARcorp.com/rtems/license.html.
*
*/
#include <rtems.h>
#define OPEN_ETH_SUPPORTED
#include <bsp.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <rtems/error.h>
#include <rtems/rtems_bsdnet.h>
#include <libchip/open_eth.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#ifdef malloc
#undef malloc
#endif
#ifdef free
#undef free
#endif
/*
#define OPEN_ETH_DEBUG
*/
#ifdef CPU_U32_FIX
extern void ipalign(struct mbuf *m);
#endif
/* message descriptor entry */
struct MDTX
{
char *buf;
};
struct MDRX
{
struct mbuf *m;
};
/*
* Number of OCs supported by this driver
*/
#define NOCDRIVER 1
/*
* Receive buffer size -- Allow for a full ethernet packet including CRC
*/
#define RBUF_SIZE 1536
#define ET_MINLEN 64 /* minimum message length */
/*
* RTEMS event used by interrupt handler to signal driver tasks.
* This must not be any of the events used by the network task synchronization.
*/
#define INTERRUPT_EVENT RTEMS_EVENT_1
/*
* RTEMS event used to start transmit daemon.
* This must not be the same as INTERRUPT_EVENT.
*/
#define START_TRANSMIT_EVENT RTEMS_EVENT_2
/* event to send when tx buffers become available */
#define OPEN_ETH_TX_WAIT_EVENT RTEMS_EVENT_3
/* suspend when all TX descriptors exhausted */
/*
#define OETH_SUSPEND_NOTXBUF
*/
#define OETH_RATE_10MHZ
#if (MCLBYTES < RBUF_SIZE)
# error "Driver must have MCLBYTES > RBUF_SIZE"
#endif
/*
* Per-device data
*/
struct open_eth_softc
{
struct arpcom arpcom;
oeth_regs *regs;
int acceptBroadcast;
rtems_id rxDaemonTid;
rtems_id txDaemonTid;
unsigned int tx_ptr;
unsigned int rx_ptr;
unsigned int txbufs;
unsigned int rxbufs;
struct MDTX *txdesc;
struct MDRX *rxdesc;
rtems_vector_number vector;
/*
* Statistics
*/
unsigned long rxInterrupts;
unsigned long rxPackets;
unsigned long rxLengthError;
unsigned long rxNonOctet;
unsigned long rxBadCRC;
unsigned long rxOverrun;
unsigned long rxMiss;
unsigned long rxCollision;
unsigned long txInterrupts;
unsigned long txDeferred;
unsigned long txHeartbeat;
unsigned long txLateCollision;
unsigned long txRetryLimit;
unsigned long txUnderrun;
unsigned long txLostCarrier;
unsigned long txRawWait;
};
static struct open_eth_softc oc;
/* OPEN_ETH interrupt handler */
static rtems_isr
open_eth_interrupt_handler (rtems_vector_number v)
{
unsigned32 status;
/* read and clear interrupt cause */
status = oc.regs->int_src;
oc.regs->int_src = status;
/* Frame received? */
if (status & (OETH_INT_RXF | OETH_INT_RXE))
{
oc.rxInterrupts++;
rtems_event_send (oc.rxDaemonTid, INTERRUPT_EVENT);
}
#ifdef OETH_SUSPEND_NOTXBUF
if (status & (OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE))
{
oc.txInterrupts++;
rtems_event_send (oc.txDaemonTid, OPEN_ETH_TX_WAIT_EVENT);
}
#endif
/*
#ifdef __leon__
LEON_Clear_interrupt(v-0x10);
#endif
*/
}
static unsigned32 read_mii(unsigned32 addr)
{
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
oc.regs->miiaddress = addr << 8;
oc.regs->miicommand = OETH_MIICOMMAND_RSTAT;
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
if (!(oc.regs->miistatus & OETH_MIISTATUS_NVALID))
return(oc.regs->miirx_data);
else {
printf("open_eth: failed to read mii\n");
return (0);
}
}
static void write_mii(unsigned32 addr, unsigned32 data)
{
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
oc.regs->miiaddress = addr << 8;
oc.regs->miitx_data = data;
oc.regs->miicommand = OETH_MIICOMMAND_WCTRLDATA;
while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}
}
/*
* Initialize the ethernet hardware
*/
static void
open_eth_initialize_hardware (struct open_eth_softc *sc)
{
struct mbuf *m;
int i;
int mii_cr = 0;
oeth_regs *regs;
regs = sc->regs;
/* Reset the controller. */
regs->ctrlmoder = 0;
regs->moder = OETH_MODER_RST; /* Reset ON */
regs->moder = 0; /* Reset OFF */
/* reset PHY and wait for complettion */
mii_cr = read_mii(0);
mii_cr = 0x3320;
#ifdef OETH_RATE_10MHZ
mii_cr = 0;
#endif
write_mii(0, mii_cr | 0x8000);
while (read_mii(0) & 0x8000) {}
write_mii(20, 0x1422);
#ifdef OETH_RATE_10MHZ
mii_cr = 0;
#endif
write_mii(0, mii_cr);
printf("open_eth: driver attached, PHY config : 0x%04x\n", read_mii(0));
#ifdef OPEN_ETH_DEBUG
printf("mii_cr: %04x\n", mii_cr);
for (i=0;i<21;i++)
printf("mii_reg %2d : 0x%04x\n", i, read_mii(i));
#endif
/* Setting TXBD base to sc->txbufs */
regs->tx_bd_num = sc->txbufs;
/* Initialize rx/tx pointers. */
sc->rx_ptr = 0;
sc->tx_ptr = 0;
/* Set min/max packet length */
regs->packet_len = 0x00400600;
/* Set IPGT register to recomended value */
regs->ipgt = 0x00000015;
/* Set IPGR1 register to recomended value */
regs->ipgr1 = 0x0000000c;
/* Set IPGR2 register to recomended value */
regs->ipgr2 = 0x00000012;
/* Set COLLCONF register to recomended value */
regs->collconf = 0x000f003f;
/* initialize TX descriptors */
sc->txdesc = calloc(sc->txbufs, sizeof(*sc->txdesc));
for (i = 0; i < sc->txbufs; i++)
{
sc->regs->xd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC;
sc->txdesc[i].buf = calloc(1, OETH_MAXBUF_LEN);
#ifdef OPEN_ETH_DEBUG
printf("TXBUF: %08x\n", (int) sc->txdesc[i].buf);
#endif
}
sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_WRAP;
/* allocate RX buffers */
sc->rxdesc = calloc(sc->rxbufs, sizeof(*sc->rxdesc));
for (i = 0; i < sc->rxbufs; i++)
{
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
sc->rxdesc[i].m = m;
sc->regs->xd[i + sc->txbufs].addr = mtod (m, unsigned32 *);
sc->regs->xd[i + sc->txbufs].len_status =
OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;
#ifdef OPEN_ETH_DEBUG
printf("RXBUF: %08x\n", (int) sc->rxdesc[i].m);
#endif
}
sc->regs->xd[sc->rxbufs + sc->txbufs - 1].len_status |= OETH_RX_BD_WRAP;
/* set ethernet address. */
regs->mac_addr1 = sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1];
regs->mac_addr0 = sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 |
sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5];
/* install interrupt vector */
set_vector (open_eth_interrupt_handler, sc->vector, 1);
/* clear all pending interrupts */
regs->int_src = 0xffffffff;
/* MAC mode register: PAD, IFG, CRCEN */
regs->moder = OETH_MODER_PAD | OETH_MODER_CRCEN | ((mii_cr & 0x100) << 2);
/* enable interrupts */
regs->int_mask = OETH_INT_MASK_RXF | OETH_INT_MASK_RXE | OETH_INT_MASK_RXC;
#ifdef OETH_SUSPEND_NOTXBUF
regs->int_mask |= OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE | OETH_INT_BUSY;*/
sc->regs->xd[(sc->txbufs - 1)/2].len_status |= OETH_TX_BD_IRQ;
sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_IRQ;
#endif
regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;
}
static void
open_eth_rxDaemon (void *arg)
{
struct ether_header *eh;
struct open_eth_softc *dp = (struct open_eth_softc *) &oc;
struct ifnet *ifp = &dp->arpcom.ac_if;
struct mbuf *m;
unsigned int len, len_status, bad;
rtems_event_set events;
for (;;)
{
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
RTEMS_NO_TIMEOUT, &events);
#ifdef OPEN_ETH_DEBUG
printf ("r\n");
#endif
while (!
((len_status =
dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status) & OETH_RX_BD_EMPTY))
{
bad = 0;
if (len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT))
{
dp->rxLengthError++;
bad = 1;
}
if (len_status & OETH_RX_BD_DRIBBLE)
{
dp->rxNonOctet++;
bad = 1;
}
if (len_status & OETH_RX_BD_CRCERR)
{
dp->rxBadCRC++;
bad = 1;
}
if (len_status & OETH_RX_BD_OVERRUN)
{
dp->rxOverrun++;
bad = 1;
}
if (len_status & OETH_RX_BD_MISS)
{
dp->rxMiss++;
bad = 1;
}
if (len_status & OETH_RX_BD_LATECOL)
{
dp->rxCollision++;
bad = 1;
}
if (!bad)
{
/* pass on the packet in the receive buffer */
len = len_status >> 16;
m = (struct mbuf *) (dp->rxdesc[dp->rx_ptr].m);
m->m_len = m->m_pkthdr.len =
len - sizeof (struct ether_header);
eh = mtod (m, struct ether_header *);
m->m_data += sizeof (struct ether_header);
#ifdef CPU_U32_FIX
ipalign(m); /* Align packet on 32-bit boundary */
#endif
ether_input (ifp, eh, m);
/* get a new mbuf */
MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT);
m->m_pkthdr.rcvif = ifp;
dp->rxdesc[dp->rx_ptr].m = m;
dp->regs->xd[dp->rx_ptr + dp->txbufs].addr =
(unsigned32 *) mtod (m, void *);
dp->rxPackets++;
}
dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status =
(dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status &
~OETH_TX_BD_STATS) | OETH_TX_BD_READY;
dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
}
}
}
static int inside = 0;
static void
sendpacket (struct ifnet *ifp, struct mbuf *m)
{
struct open_eth_softc *dp = ifp->if_softc;
unsigned char *temp;
struct mbuf *n;
unsigned int len, len_status;
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
/*
* Waiting for Transmitter ready
*/
n = m;
while (dp->regs->xd[dp->tx_ptr].len_status & OETH_TX_BD_READY)
{
#ifdef OETH_SUSPEND_NOTXBUF
rtems_event_set events;
rtems_bsdnet_event_receive (OPEN_ETH_TX_WAIT_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
TOD_MILLISECONDS_TO_TICKS(500), &events);
#endif
}
len = 0;
temp = (unsigned char *) dp->txdesc[dp->tx_ptr].buf;
dp->regs->xd[dp->tx_ptr].addr = (unsigned32 *) temp;
#ifdef OPEN_ETH_DEBUG
printf("TXD: 0x%08x\n", (int) m->m_data);
#endif
for (;;)
{
#ifdef OPEN_ETH_DEBUG
int i;
printf("MBUF: 0x%08x : ", (int) m->m_data);
for (i=0;i<m->m_len;i++)
printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
printf("\n");
#endif
len += m->m_len;
if (len <= RBUF_SIZE)
memcpy ((void *) temp, (char *) m->m_data, m->m_len);
temp += m->m_len;
if ((m = m->m_next) == NULL)
break;
}
m_freem (n);
/* don't send long packets */
if (len <= RBUF_SIZE) {
/* Clear all of the status flags. */
len_status = dp->regs->xd[dp->tx_ptr].len_status & ~OETH_TX_BD_STATS;
/* If the frame is short, tell CPM to pad it. */
if (len < ET_MINLEN) {
len_status |= OETH_TX_BD_PAD;
len = ET_MINLEN;
}
else
len_status &= ~OETH_TX_BD_PAD;
/* write buffer descriptor length and status */
len_status |= (len << 16) | (OETH_TX_BD_READY | OETH_TX_BD_CRC);
dp->regs->xd[dp->tx_ptr].len_status = len_status;
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
}
inside = 0;
}
/*
* Driver transmit daemon
*/
void
open_eth_txDaemon (void *arg)
{
struct open_eth_softc *sc = (struct open_eth_softc *) arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
struct mbuf *m;
rtems_event_set events;
for (;;)
{
/*
* Wait for packet
*/
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT, &events);
#ifdef OPEN_ETH_DEBUG
printf ("t\n");
#endif
/*
* Send packets till queue is empty
*/
for (;;)
{
/*
* Get the next mbuf chain to transmit.
*/
IF_DEQUEUE (&ifp->if_snd, m);
if (!m)
break;
sendpacket (ifp, m);
}
ifp->if_flags &= ~IFF_OACTIVE;
}
}
static void
open_eth_start (struct ifnet *ifp)
{
struct open_eth_softc *sc = ifp->if_softc;
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
ifp->if_flags |= IFF_OACTIVE;
}
/*
* Initialize and start the device
*/
static void
open_eth_init (void *arg)
{
struct open_eth_softc *sc = arg;
struct ifnet *ifp = &sc->arpcom.ac_if;
if (sc->txDaemonTid == 0)
{
/*
* Set up OPEN_ETH hardware
*/
open_eth_initialize_hardware (sc);
/*
* Start driver tasks
*/
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
open_eth_rxDaemon, sc);
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
open_eth_txDaemon, sc);
}
/*
* Tell the world that we're running.
*/
ifp->if_flags |= IFF_RUNNING;
}
/*
* Stop the device
*/
static void
open_eth_stop (struct open_eth_softc *sc)
{
struct ifnet *ifp = &sc->arpcom.ac_if;
ifp->if_flags &= ~IFF_RUNNING;
sc->regs->moder = 0; /* RX/TX OFF */
sc->regs->moder = OETH_MODER_RST; /* Reset ON */
sc->regs->moder = 0; /* Reset OFF */
}
/*
* Show interface statistics
*/
static void
open_eth_stats (struct open_eth_softc *sc)
{
printf (" Rx Packets:%-8lu", sc->rxPackets);
printf (" Rx Interrupts:%-8lu", sc->rxInterrupts);
printf (" Length:%-8lu", sc->rxLengthError);
printf (" Non-octet:%-8lu\n", sc->rxNonOctet);
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
printf (" Overrun:%-8lu", sc->rxOverrun);
printf (" Miss:%-8lu", sc->rxMiss);
printf (" Collision:%-8lu\n", sc->rxCollision);
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
printf (" Deferred:%-8lu", sc->txDeferred);
printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);
printf (" No Carrier:%-8lu", sc->txLostCarrier);
printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);
printf (" Late Collision:%-8lu\n", sc->txLateCollision);
printf (" Underrun:%-8lu", sc->txUnderrun);
printf (" Raw output wait:%-8lu\n", sc->txRawWait);
}
/*
* Driver ioctl handler
*/
static int
open_eth_ioctl (struct ifnet *ifp, int command, caddr_t data)
{
struct open_eth_softc *sc = ifp->if_softc;
int error = 0;
switch (command)
{
case SIOCGIFADDR:
case SIOCSIFADDR:
ether_ioctl (ifp, command, data);
break;
case SIOCSIFFLAGS:
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
{
case IFF_RUNNING:
open_eth_stop (sc);
break;
case IFF_UP:
open_eth_init (sc);
break;
case IFF_UP | IFF_RUNNING:
open_eth_stop (sc);
open_eth_init (sc);
break;
default:
break;
}
break;
case SIO_RTEMS_SHOW_STATS:
open_eth_stats (sc);
break;
/*
* FIXME: All sorts of multicast commands need to be added here!
*/
default:
error = EINVAL;
break;
}
return error;
}
/*
* Attach an OPEN_ETH driver to the system
*/
int
rtems_open_eth_driver_attach (struct rtems_bsdnet_ifconfig *config,
open_eth_configuration_t * chip)
{
struct open_eth_softc *sc;
struct ifnet *ifp;
int mtu;
int unitNumber;
char *unitName;
/* parse driver name */
if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0)
return 0;
sc = &oc;
ifp = &sc->arpcom.ac_if;
memset (sc, 0, sizeof (*sc));
if (config->hardware_address)
{
memcpy (sc->arpcom.ac_enaddr, config->hardware_address,
ETHER_ADDR_LEN);
}
else
{
memset (sc->arpcom.ac_enaddr, 0x08, ETHER_ADDR_LEN);
}
if (config->mtu)
mtu = config->mtu;
else
mtu = ETHERMTU;
sc->acceptBroadcast = !config->ignore_broadcast;
sc->regs = (void *) chip->base_address;
sc->vector = chip->vector;
sc->txbufs = chip->txd_count;
sc->rxbufs = chip->rxd_count;
/*
* Set up network interface values
*/
ifp->if_softc = sc;
ifp->if_unit = unitNumber;
ifp->if_name = unitName;
ifp->if_mtu = mtu;
ifp->if_init = open_eth_init;
ifp->if_ioctl = open_eth_ioctl;
ifp->if_start = open_eth_start;
ifp->if_output = ether_output;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
if (ifp->if_snd.ifq_maxlen == 0)
ifp->if_snd.ifq_maxlen = ifqmaxlen;
/*
* Attach the interface
*/
if_attach (ifp);
ether_ifattach (ifp);
#ifdef OPEN_ETH_DEBUG
printf ("OPEN_ETH : driver has been attached\n");
#endif
return 1;
};

View File

@@ -0,0 +1,173 @@
/* Opencores ethernet MAC driver */
/* adapted from linux driver by Jiri Gaisler */
#ifndef _OPEN_ETH_
#define _OPEN_ETH_
/* Configuration Information */
typedef struct {
unsigned32 base_address;
unsigned32 vector;
unsigned32 txd_count;
unsigned32 rxd_count;
} open_eth_configuration_t;
/* Ethernet buffer descriptor */
typedef struct _oeth_rxtxdesc {
volatile unsigned32 len_status; /* Length and status */
volatile unsigned32 *addr; /* Buffer pointer */
} oeth_rxtxdesc;
/* Ethernet configuration registers */
typedef struct _oeth_regs {
volatile unsigned32 moder; /* Mode Register */
volatile unsigned32 int_src; /* Interrupt Source Register */
volatile unsigned32 int_mask; /* Interrupt Mask Register */
volatile unsigned32 ipgt; /* Back to Bak Inter Packet Gap Register */
volatile unsigned32 ipgr1; /* Non Back to Back Inter Packet Gap Register 1 */
volatile unsigned32 ipgr2; /* Non Back to Back Inter Packet Gap Register 2 */
volatile unsigned32 packet_len; /* Packet Length Register (min. and max.) */
volatile unsigned32 collconf; /* Collision and Retry Configuration Register */
volatile unsigned32 tx_bd_num; /* Transmit Buffer Descriptor Number Register */
volatile unsigned32 ctrlmoder; /* Control Module Mode Register */
volatile unsigned32 miimoder; /* MII Mode Register */
volatile unsigned32 miicommand; /* MII Command Register */
volatile unsigned32 miiaddress; /* MII Address Register */
volatile unsigned32 miitx_data; /* MII Transmit Data Register */
volatile unsigned32 miirx_data; /* MII Receive Data Register */
volatile unsigned32 miistatus; /* MII Status Register */
volatile unsigned32 mac_addr0; /* MAC Individual Address Register 0 */
volatile unsigned32 mac_addr1; /* MAC Individual Address Register 1 */
volatile unsigned32 hash_addr0; /* Hash Register 0 */
volatile unsigned32 hash_addr1; /* Hash Register 1 */
volatile unsigned32 txctrl; /* Transmitter control register */
unsigned32 empty[235]; /* Unused space */
oeth_rxtxdesc xd[128]; /* TX & RX descriptors */
} oeth_regs;
#define OETH_TOTAL_BD 128
#define OETH_MAXBUF_LEN 0x610
/* Tx BD */
#define OETH_TX_BD_READY 0x8000 /* Tx BD Ready */
#define OETH_TX_BD_IRQ 0x4000 /* Tx BD IRQ Enable */
#define OETH_TX_BD_WRAP 0x2000 /* Tx BD Wrap (last BD) */
#define OETH_TX_BD_PAD 0x1000 /* Tx BD Pad Enable */
#define OETH_TX_BD_CRC 0x0800 /* Tx BD CRC Enable */
#define OETH_TX_BD_UNDERRUN 0x0100 /* Tx BD Underrun Status */
#define OETH_TX_BD_RETRY 0x00F0 /* Tx BD Retry Status */
#define OETH_TX_BD_RETLIM 0x0008 /* Tx BD Retransmission Limit Status */
#define OETH_TX_BD_LATECOL 0x0004 /* Tx BD Late Collision Status */
#define OETH_TX_BD_DEFER 0x0002 /* Tx BD Defer Status */
#define OETH_TX_BD_CARRIER 0x0001 /* Tx BD Carrier Sense Lost Status */
#define OETH_TX_BD_STATS (OETH_TX_BD_UNDERRUN | \
OETH_TX_BD_RETRY | \
OETH_TX_BD_RETLIM | \
OETH_TX_BD_LATECOL | \
OETH_TX_BD_DEFER | \
OETH_TX_BD_CARRIER)
/* Rx BD */
#define OETH_RX_BD_EMPTY 0x8000 /* Rx BD Empty */
#define OETH_RX_BD_IRQ 0x4000 /* Rx BD IRQ Enable */
#define OETH_RX_BD_WRAP 0x2000 /* Rx BD Wrap (last BD) */
#define OETH_RX_BD_MISS 0x0080 /* Rx BD Miss Status */
#define OETH_RX_BD_OVERRUN 0x0040 /* Rx BD Overrun Status */
#define OETH_RX_BD_INVSIMB 0x0020 /* Rx BD Invalid Symbol Status */
#define OETH_RX_BD_DRIBBLE 0x0010 /* Rx BD Dribble Nibble Status */
#define OETH_RX_BD_TOOLONG 0x0008 /* Rx BD Too Long Status */
#define OETH_RX_BD_SHORT 0x0004 /* Rx BD Too Short Frame Status */
#define OETH_RX_BD_CRCERR 0x0002 /* Rx BD CRC Error Status */
#define OETH_RX_BD_LATECOL 0x0001 /* Rx BD Late Collision Status */
#define OETH_RX_BD_STATS (OETH_RX_BD_MISS | \
OETH_RX_BD_OVERRUN | \
OETH_RX_BD_INVSIMB | \
OETH_RX_BD_DRIBBLE | \
OETH_RX_BD_TOOLONG | \
OETH_RX_BD_SHORT | \
OETH_RX_BD_CRCERR | \
OETH_RX_BD_LATECOL)
/* MODER Register */
#define OETH_MODER_RXEN 0x00000001 /* Receive Enable */
#define OETH_MODER_TXEN 0x00000002 /* Transmit Enable */
#define OETH_MODER_NOPRE 0x00000004 /* No Preamble */
#define OETH_MODER_BRO 0x00000008 /* Reject Broadcast */
#define OETH_MODER_IAM 0x00000010 /* Use Individual Hash */
#define OETH_MODER_PRO 0x00000020 /* Promiscuous (receive all) */
#define OETH_MODER_IFG 0x00000040 /* Min. IFG not required */
#define OETH_MODER_LOOPBCK 0x00000080 /* Loop Back */
#define OETH_MODER_NOBCKOF 0x00000100 /* No Backoff */
#define OETH_MODER_EXDFREN 0x00000200 /* Excess Defer */
#define OETH_MODER_FULLD 0x00000400 /* Full Duplex */
#define OETH_MODER_RST 0x00000800 /* Reset MAC */
#define OETH_MODER_DLYCRCEN 0x00001000 /* Delayed CRC Enable */
#define OETH_MODER_CRCEN 0x00002000 /* CRC Enable */
#define OETH_MODER_HUGEN 0x00004000 /* Huge Enable */
#define OETH_MODER_PAD 0x00008000 /* Pad Enable */
#define OETH_MODER_RECSMALL 0x00010000 /* Receive Small */
/* Interrupt Source Register */
#define OETH_INT_TXB 0x00000001 /* Transmit Buffer IRQ */
#define OETH_INT_TXE 0x00000002 /* Transmit Error IRQ */
#define OETH_INT_RXF 0x00000004 /* Receive Frame IRQ */
#define OETH_INT_RXE 0x00000008 /* Receive Error IRQ */
#define OETH_INT_BUSY 0x00000010 /* Busy IRQ */
#define OETH_INT_TXC 0x00000020 /* Transmit Control Frame IRQ */
#define OETH_INT_RXC 0x00000040 /* Received Control Frame IRQ */
/* Interrupt Mask Register */
#define OETH_INT_MASK_TXB 0x00000001 /* Transmit Buffer IRQ Mask */
#define OETH_INT_MASK_TXE 0x00000002 /* Transmit Error IRQ Mask */
#define OETH_INT_MASK_RXF 0x00000004 /* Receive Frame IRQ Mask */
#define OETH_INT_MASK_RXE 0x00000008 /* Receive Error IRQ Mask */
#define OETH_INT_MASK_BUSY 0x00000010 /* Busy IRQ Mask */
#define OETH_INT_MASK_TXC 0x00000020 /* Transmit Control Frame IRQ Mask */
#define OETH_INT_MASK_RXC 0x00000040 /* Received Control Frame IRQ Mask */
/* Control Module Mode Register */
#define OETH_CTRLMODER_PASSALL 0x00000001 /* Pass Control Frames */
#define OETH_CTRLMODER_RXFLOW 0x00000002 /* Receive Control Flow Enable */
#define OETH_CTRLMODER_TXFLOW 0x00000004 /* Transmit Control Flow Enable */
/* MII Mode Register */
#define OETH_MIIMODER_CLKDIV 0x000000FF /* Clock Divider */
#define OETH_MIIMODER_NOPRE 0x00000100 /* No Preamble */
#define OETH_MIIMODER_RST 0x00000200 /* MIIM Reset */
/* MII Command Register */
#define OETH_MIICOMMAND_SCANSTAT 0x00000001 /* Scan Status */
#define OETH_MIICOMMAND_RSTAT 0x00000002 /* Read Status */
#define OETH_MIICOMMAND_WCTRLDATA 0x00000004 /* Write Control Data */
/* MII Address Register */
#define OETH_MIIADDRESS_FIAD 0x0000001F /* PHY Address */
#define OETH_MIIADDRESS_RGAD 0x00001F00 /* RGAD Address */
/* MII Status Register */
#define OETH_MIISTATUS_LINKFAIL 0x00000001 /* Link Fail */
#define OETH_MIISTATUS_BUSY 0x00000002 /* MII Busy */
#define OETH_MIISTATUS_NVALID 0x00000004 /* Data in MII Status Register is invalid */
/* Attatch routine */
int rtems_open_eth_driver_attach (
struct rtems_bsdnet_ifconfig *config,
open_eth_configuration_t *chip
);
/*
#ifdef CPU_U32_FIX
void ipalign(struct mbuf *m);
#endif
*/
#endif /* _OPEN_ETH_ */