2007-09-07 Daniel Hellstrom <daniel@gaisler.com>

* libchip/network/greth.c, libchip/network/greth.h: GRETH_GBIT support
	and GBIT PHY support for 10/100 MAC, also auto negotiation updated.
This commit is contained in:
Joel Sherrill
2007-09-07 15:01:15 +00:00
parent 13279f5dcf
commit 050249d25d
3 changed files with 535 additions and 172 deletions

View File

@@ -1,3 +1,8 @@
2007-09-07 Daniel Hellstrom <daniel@gaisler.com>
* libchip/network/greth.c, libchip/network/greth.h: GRETH_GBIT support
and GBIT PHY support for 10/100 MAC, also auto negotiation updated.
2007-08-02 Joel Sherrill <joel.sherrill@OARcorp.com> 2007-08-02 Joel Sherrill <joel.sherrill@OARcorp.com>
* configure.ac, wrapup/Makefile.am: Remove RDBG. * configure.ac, wrapup/Makefile.am: Remove RDBG.

View File

@@ -1,14 +1,14 @@
/* /*
* RTEMS driver for Opencores Ethernet Controller * Gaisler Research ethernet MAC driver
* * adapted from Opencores driver by Marko Isomaki
* 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 * The license and distribution terms for this file may be
* found in found in the file LICENSE in this distribution or at * found in found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE. * http://www.rtems.com/license/LICENSE.
* *
* $Id$ * $Id$
*
* 2007-09-07, Ported GBIT support from 4.6.5
*/ */
#include <rtems.h> #include <rtems.h>
@@ -18,6 +18,7 @@
#include <inttypes.h> #include <inttypes.h>
#include <errno.h> #include <errno.h>
#include <rtems/bspIo.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
@@ -47,9 +48,8 @@ extern m68k_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int ); extern rtems_isr_entry set_vector( rtems_isr_entry, rtems_vector_number, int );
#endif #endif
/*
#define GRETH_DEBUG /* #define GRETH_DEBUG */
*/
#ifdef CPU_U32_FIX #ifdef CPU_U32_FIX
extern void ipalign(struct mbuf *m); extern void ipalign(struct mbuf *m);
@@ -91,6 +91,14 @@ extern void ipalign(struct mbuf *m);
# error "Driver must have MCLBYTES > RBUF_SIZE" # error "Driver must have MCLBYTES > RBUF_SIZE"
#endif #endif
/* 4s Autonegotiation Timeout */
#ifndef GRETH_AUTONEGO_TIMEOUT_MS
#define GRETH_AUTONEGO_TIMEOUT_MS 4000
#endif
/* For optimizing the autonegotiation time */
#define GRETH_AUTONEGO_PRINT_TIME
/* Ethernet buffer descriptor */ /* Ethernet buffer descriptor */
typedef struct _greth_rxtxdesc { typedef struct _greth_rxtxdesc {
@@ -98,6 +106,7 @@ typedef struct _greth_rxtxdesc {
uint32_t *addr; /* Buffer pointer */ uint32_t *addr; /* Buffer pointer */
} greth_rxtxdesc; } greth_rxtxdesc;
/* /*
* Per-device data * Per-device data
*/ */
@@ -113,14 +122,26 @@ struct greth_softc
rtems_id txDaemonTid; rtems_id txDaemonTid;
unsigned int tx_ptr; unsigned int tx_ptr;
unsigned int tx_dptr;
unsigned int tx_cnt;
unsigned int rx_ptr; unsigned int rx_ptr;
unsigned int txbufs; unsigned int txbufs;
unsigned int rxbufs; unsigned int rxbufs;
greth_rxtxdesc *txdesc; greth_rxtxdesc *txdesc;
greth_rxtxdesc *rxdesc; greth_rxtxdesc *rxdesc;
struct mbuf **rxmbuf; struct mbuf **rxmbuf;
struct mbuf **txmbuf;
rtems_vector_number vector; rtems_vector_number vector;
/*Status*/
struct phy_device_info phydev;
int fd;
int sp;
int gb;
int gbit_mac;
int auto_neg;
unsigned int auto_neg_time;
/* /*
* Statistics * Statistics
*/ */
@@ -139,6 +160,7 @@ struct greth_softc
unsigned long txLateCollision; unsigned long txLateCollision;
unsigned long txRetryLimit; unsigned long txRetryLimit;
unsigned long txUnderrun; unsigned long txUnderrun;
}; };
static struct greth_softc greth; static struct greth_softc greth;
@@ -176,16 +198,16 @@ greth_interrupt_handler (rtems_vector_number v)
} }
#endif #endif
/* /*
#ifdef __leon__ #ifdef __leon__
LEON_Clear_interrupt(v-0x10); LEON_Clear_interrupt(v-0x10);
#endif #endif
*/ */
} }
static uint32_t read_mii(uint32_t addr) static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
{ {
while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
greth.regs->mdio_ctrl = addr << 6 | GRETH_MDIO_READ; greth.regs->mdio_ctrl = (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_READ;
while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL)) if (!(greth.regs->mdio_ctrl & GRETH_MDIO_LINKFAIL))
return((greth.regs->mdio_ctrl >> 16) & 0xFFFF); return((greth.regs->mdio_ctrl >> 16) & 0xFFFF);
@@ -195,13 +217,40 @@ static uint32_t read_mii(uint32_t addr)
} }
} }
static void write_mii(uint32_t addr, uint32_t data) static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
{ {
while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
greth.regs->mdio_ctrl = greth.regs->mdio_ctrl =
((data & 0xFFFF) << 16) | (addr << 8) | GRETH_MDIO_WRITE; ((data & 0xFFFF) << 16) | (phy_addr << 11) | (reg_addr << 6) | GRETH_MDIO_WRITE;
while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {} while (greth.regs->mdio_ctrl & GRETH_MDIO_BUSY) {}
} }
static void print_init_info(struct greth_softc *sc)
{
printf("greth: driver attached\n");
printf("**** PHY ****\n");
printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
printf("Current Operating Mode: ");
if (sc->gb) {
printf("1000 Mbit ");
} else if (sc->sp) {
printf("100 Mbit ");
} else {
printf("10 Mbit ");
}
if (sc->fd) {
printf("Full Duplex\n");
} else {
printf("Half Duplex\n");
}
#ifdef GRETH_AUTONEGO_PRINT_TIME
if ( sc->auto_neg ){
printf("Autonegotiation Time: %dms\n",sc->auto_neg_time);
}
#endif
}
/* /*
* Initialize the ethernet hardware * Initialize the ethernet hardware
*/ */
@@ -210,7 +259,13 @@ greth_initialize_hardware (struct greth_softc *sc)
{ {
struct mbuf *m; struct mbuf *m;
int i; int i;
int fd; int phyaddr;
int phyctrl;
int phystatus;
int tmp1;
int tmp2;
unsigned int msecs;
rtems_clock_time_value tstart, tnow;
greth_regs *regs; greth_regs *regs;
@@ -224,44 +279,172 @@ greth_initialize_hardware (struct greth_softc *sc)
regs->ctrl = GRETH_CTRL_RST; /* Reset ON */ regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
regs->ctrl = 0; /* Reset OFF */ regs->ctrl = 0; /* Reset OFF */
/* reset PHY and wait for complettion */ /* Check if mac is gbit capable*/
/* sc->gbit_mac = (regs->ctrl >> 27) & 1;
*/
write_mii(0, 0x8000); /* Get the phy address which assumed to have been set
while (read_mii(0) & 0x8000) {} correctly with the reset value in hardware*/
fd = regs->mdio_ctrl >> 24; /*duplex mode*/ phyaddr = (regs->mdio_ctrl >> 11) & 0x1F;
printf(
"greth: driver attached, PHY config: 0x%04" PRIx32 "\n", read_mii(0)); /* get phy control register default values */
while ((phyctrl = read_mii(phyaddr, 0)) & 0x8000) {}
/* reset PHY and wait for completion */
write_mii(phyaddr, 0, 0x8000 | phyctrl);
while ((read_mii(phyaddr, 0)) & 0x8000) {}
/* Check if PHY is autoneg capable and then determine operating mode,
otherwise force it to 10 Mbit halfduplex */
sc->gb = 0;
sc->fd = 0;
sc->sp = 0;
sc->auto_neg = 0;
sc->auto_neg_time = 0;
if ((phyctrl >> 12) & 1) {
/*wait for auto negotiation to complete*/
msecs = 0;
sc->auto_neg = 1;
if ( rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&tstart) == RTEMS_NOT_DEFINED){
/* Not inited, set to epoch */
rtems_time_of_day time;
time.year = 1988;
time.month = 1;
time.day = 1;
time.hour = 0;
time.minute = 0;
time.second = 0;
time.ticks = 0;
rtems_clock_set(&time);
tstart.seconds = 0;
tstart.microseconds = 0;
rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&tstart);
}
while (!(((phystatus = read_mii(phyaddr, 1)) >> 5) & 1)) {
if ( rtems_clock_get(RTEMS_CLOCK_GET_TIME_VALUE,&tnow) != RTEMS_SUCCESSFUL )
printk("rtems_clock_get failed\n\r");
msecs = (tnow.seconds-tstart.seconds)*1000+(tnow.microseconds-tstart.microseconds)/1000;
if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
sc->auto_neg_time = msecs;
printk("Auto negotiation timed out. Selecting default config\n\r");
tmp1 = read_mii(phyaddr, 0);
sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
sc->fd = (phyctrl >> 8) & 1;
goto auto_neg_done;
}
}
sc->auto_neg_time = msecs;
sc->phydev.adv = read_mii(phyaddr, 4);
sc->phydev.part = read_mii(phyaddr, 5);
if ((phystatus >> 8) & 1) {
sc->phydev.extadv = read_mii(phyaddr, 9);
sc->phydev.extpart = read_mii(phyaddr, 10);
if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000FD) &&
(sc->phydev.extpart & GRETH_MII_EXTPRT_1000FD)) {
sc->gb = 1;
sc->fd = 1;
}
if ( (sc->phydev.extadv & GRETH_MII_EXTADV_1000HD) &&
(sc->phydev.extpart & GRETH_MII_EXTPRT_1000HD)) {
sc->gb = 1;
sc->fd = 0;
}
}
if ((sc->gb == 0) || ((sc->gb == 1) && (sc->gbit_mac == 0))) {
if ( (sc->phydev.adv & GRETH_MII_100TXFD) &&
(sc->phydev.part & GRETH_MII_100TXFD)) {
sc->sp = 1;
sc->fd = 1;
}
if ( (sc->phydev.adv & GRETH_MII_100TXHD) &&
(sc->phydev.part & GRETH_MII_100TXHD)) {
sc->sp = 1;
sc->fd = 0;
}
if ( (sc->phydev.adv & GRETH_MII_10FD) &&
(sc->phydev.part & GRETH_MII_10FD)) {
sc->fd = 1;
}
}
}
auto_neg_done:
sc->phydev.vendor = 0;
sc->phydev.device = 0;
sc->phydev.rev = 0;
phystatus = read_mii(phyaddr, 1);
/*Read out PHY info if extended registers are available */
if (phystatus & 1) {
tmp1 = read_mii(phyaddr, 2);
tmp2 = read_mii(phyaddr, 3);
sc->phydev.vendor = (tmp1 << 6) | ((tmp2 >> 10) & 0x3F);
sc->phydev.rev = tmp2 & 0xF;
sc->phydev.device = (tmp2 >> 4) & 0x3F;
}
/* Force to 10 mbit half duplex if the 10/100 MAC is used with a 1000 PHY*/
/*check if marvell 88EE1111 PHY. Needs special reset handling */
if ((phystatus & 1) && (sc->phydev.vendor == 0x005043) && (sc->phydev.device == 0x0C)) {
if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
write_mii(phyaddr, 0, sc->sp << 13);
write_mii(phyaddr, 0, 0x8000);
sc->gb = 0;
sc->sp = 0;
sc->fd = 0;
}
} else {
if (((sc->gb) && !(sc->gbit_mac)) || !((phyctrl >> 12) & 1)) {
write_mii(phyaddr, 0, sc->sp << 13);
sc->gb = 0;
sc->sp = 0;
sc->fd = 0;
}
}
while ((read_mii(phyaddr, 0)) & 0x8000) {}
regs->ctrl = 0;
regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
regs->ctrl = 0;
/* Initialize rx/tx descriptor pointers */ /* Initialize rx/tx descriptor pointers */
sc->txdesc = (greth_rxtxdesc *) almalloc(1024); sc->txdesc = (greth_rxtxdesc *) almalloc(1024);
sc->rxdesc = (greth_rxtxdesc *) almalloc(1024); sc->rxdesc = (greth_rxtxdesc *) almalloc(1024);
sc->tx_ptr = 0; sc->tx_ptr = 0;
sc->tx_dptr = 0;
sc->tx_cnt = 0;
sc->rx_ptr = 0; sc->rx_ptr = 0;
regs->txdesc = (int) sc->txdesc; regs->txdesc = (int) sc->txdesc;
regs->rxdesc = (int) sc->rxdesc; regs->rxdesc = (int) sc->rxdesc;
sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf)); sc->rxmbuf = calloc(sc->rxbufs, sizeof(*sc->rxmbuf));
sc->txmbuf = calloc(sc->txbufs, sizeof(*sc->txmbuf));
for (i = 0; i < sc->txbufs; i++) for (i = 0; i < sc->txbufs; i++)
{ {
sc->txdesc[i].addr = (uint32_t *) calloc(1, GRETH_MAXBUF_LEN); sc->txdesc[i].ctrl = 0;
if (!(sc->gbit_mac)) {
sc->txdesc[i].addr = malloc(GRETH_MAXBUF_LEN);
}
#ifdef GRETH_DEBUG #ifdef GRETH_DEBUG
printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); /* printf("TXBUF: %08x\n", (int) sc->txdesc[i].addr); */
#endif #endif
} }
/*printf("RXbufs: %i\n", sc->rxbufs);*/
for (i = 0; i < sc->rxbufs; i++) for (i = 0; i < sc->rxbufs; i++)
{ {
MGETHDR (m, M_WAIT, MT_DATA); MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT); MCLGET (m, M_WAIT);
if (sc->gbit_mac)
m->m_data += 2;
m->m_pkthdr.rcvif = &sc->arpcom.ac_if; m->m_pkthdr.rcvif = &sc->arpcom.ac_if;
sc->rxmbuf[i] = m; sc->rxmbuf[i] = m;
sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *); sc->rxdesc[i].addr = (uint32_t *) mtod(m, uint32_t *);
sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ; sc->rxdesc[i].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
#ifdef GRETH_DEBUG #ifdef GRETH_DEBUG
printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); /* printf("RXBUF: %08x\n", (int) sc->rxdesc[i].addr); */
#endif #endif
} }
sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP; sc->rxdesc[sc->rxbufs - 1].ctrl |= GRETH_RXD_WRAP;
@@ -284,7 +467,9 @@ greth_initialize_hardware (struct greth_softc *sc)
regs->ctrl |= GRETH_CTRL_TXIRQ; regs->ctrl |= GRETH_CTRL_TXIRQ;
#endif #endif
regs->ctrl |= GRETH_CTRL_RXEN | (fd << 4) | GRETH_CTRL_RXIRQ; regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
print_init_info(sc);
} }
static void static void
@@ -297,7 +482,6 @@ greth_rxDaemon (void *arg)
unsigned int len, len_status, bad; unsigned int len, len_status, bad;
rtems_event_set events; rtems_event_set events;
/*printf("Started RxDaemon\n");*/
for (;;) for (;;)
{ {
rtems_bsdnet_event_receive (INTERRUPT_EVENT, rtems_bsdnet_event_receive (INTERRUPT_EVENT,
@@ -307,13 +491,10 @@ greth_rxDaemon (void *arg)
#ifdef GRETH_ETH_DEBUG #ifdef GRETH_ETH_DEBUG
printf ("r\n"); printf ("r\n");
#endif #endif
/*printf("Packet received\n");*/
while (!((len_status = while (!((len_status =
dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE)) dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
{ {
/*printf("Status: %x\n", dp->rxdesc[dp->rx_ptr].ctrl);*/
bad = 0; bad = 0;
if (len_status & GRETH_RXD_TOOLONG) if (len_status & GRETH_RXD_TOOLONG)
{ {
dp->rxLengthError++; dp->rxLengthError++;
@@ -334,46 +515,51 @@ greth_rxDaemon (void *arg)
dp->rxOverrun++; dp->rxOverrun++;
bad = 1; bad = 1;
} }
if (len_status & GRETH_RXD_LENERR)
{
dp->rxLengthError++;
bad = 1;
}
if (!bad) if (!bad)
{ {
/*printf("Received Ok packet\n");*/
/* pass on the packet in the receive buffer */ /* pass on the packet in the receive buffer */
len = len_status & 0x7FF; len = len_status & 0x7FF;
m = dp->rxmbuf[dp->rx_ptr]; m = dp->rxmbuf[dp->rx_ptr];
#ifdef GRETH_DEBUG
int i;
printf("RX: 0x%08x, Len: %d : ", (int) m->m_data, len);
for (i=0; i<len; i++)
printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
printf("\n");
#endif
m->m_len = m->m_pkthdr.len = m->m_len = m->m_pkthdr.len =
len - sizeof (struct ether_header); len - sizeof (struct ether_header);
/*printf("Packet of length: %i\n", len);*/
eh = mtod (m, struct ether_header *); eh = mtod (m, struct ether_header *);
m->m_data += sizeof (struct ether_header); m->m_data += sizeof (struct ether_header);
/*printf("Mbuf handling done\n");*/
#ifdef CPU_U32_FIX #ifdef CPU_U32_FIX
/*printf("Ip aligning\n");*/ if(!(dp->gbit_mac))
ipalign(m); /* Align packet on 32-bit boundary */ ipalign(m); /* Align packet on 32-bit boundary */
#endif #endif
/*printf("Calling stack\n");*/
/*printf("Ifp: %x, Eh: %x, M: %x\n", (int)ifp, (int)eh, (int)m);*/
ether_input (ifp, eh, m); ether_input (ifp, eh, m);
/*printf("Returned from stack\n");*/
/* get a new mbuf */
/*printf("Getting new mbuf\n");*/
MGETHDR (m, M_WAIT, MT_DATA); MGETHDR (m, M_WAIT, MT_DATA);
MCLGET (m, M_WAIT); MCLGET (m, M_WAIT);
/*printf("Got new mbuf\n");*/ if (dp->gbit_mac)
m->m_data += 2;
dp->rxmbuf[dp->rx_ptr] = m; dp->rxmbuf[dp->rx_ptr] = m;
m->m_pkthdr.rcvif = ifp; m->m_pkthdr.rcvif = ifp;
dp->rxdesc[dp->rx_ptr].addr = dp->rxdesc[dp->rx_ptr].addr =
(uint32_t *) mtod (m, uint32_t *); (uint32_t *) mtod (m, uint32_t *);
dp->rxPackets++; dp->rxPackets++;
} }
/*printf("Reenabling desc\n");*/
dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
if (dp->rx_ptr == dp->rxbufs - 1) { if (dp->rx_ptr == dp->rxbufs - 1) {
dp->rxdesc[dp->rx_ptr].ctrl |= GRETH_RXD_WRAP; dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ | GRETH_RXD_WRAP;
} else {
dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
} }
dp->regs->ctrl |= GRETH_CTRL_RXEN; dp->regs->ctrl |= GRETH_CTRL_RXEN;
/*printf("rxptr: %i\n", dp->rx_ptr);*/
dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs; dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
/*printf("RxDesc reenabled\n");*/
} }
} }
@@ -410,7 +596,7 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
len = 0; len = 0;
temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr; temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
#ifdef GRETH_DEBUG #ifdef GRETH_DEBUG
printf("TXD: 0x%08x\n", (int) m->m_data); printf("TXD: 0x%08x : BUF: 0x%08x\n", (int) m->m_data, (int) temp);
#endif #endif
for (;;) for (;;)
{ {
@@ -446,6 +632,75 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
inside = 0; inside = 0;
} }
static void
sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
{
struct greth_softc *dp = ifp->if_softc;
unsigned int len;
/*printf("Send packet entered\n");*/
if (inside) printf ("error: sendpacket re-entered!!\n");
inside = 1;
/*
* Waiting for Transmitter ready
*/
len = 0;
#ifdef GRETH_DEBUG
printf("TXD: 0x%08x\n", (int) m->m_data);
#endif
for (;;)
{
while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
{
#ifdef GRETH_SUSPEND_NOTXBUF
dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
rtems_event_set events;
rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
TOD_MILLISECONDS_TO_TICKS(500), &events);
#endif
}
#ifdef GRETH_DEBUG
int i;
printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
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;
dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
if (dp->tx_ptr < dp->txbufs-1) {
if ((m->m_next) == NULL) {
dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
break;
} else {
dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
}
} else {
if ((m->m_next) == NULL) {
dp->txdesc[dp->tx_ptr].ctrl =
GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
break;
} else {
dp->txdesc[dp->tx_ptr].ctrl =
GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
}
}
dp->txmbuf[dp->tx_ptr] = m;
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
dp->tx_cnt++;
m = m->m_next;
}
dp->txmbuf[dp->tx_ptr] = m;
dp->tx_cnt++;
dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
inside = 0;
}
/* /*
* Driver transmit daemon * Driver transmit daemon
*/ */
@@ -473,6 +728,8 @@ greth_txDaemon (void *arg)
/* /*
* Send packets till queue is empty * Send packets till queue is empty
*/ */
for (;;) for (;;)
{ {
/* /*
@@ -481,8 +738,53 @@ greth_txDaemon (void *arg)
IF_DEQUEUE (&ifp->if_snd, m); IF_DEQUEUE (&ifp->if_snd, m);
if (!m) if (!m)
break; break;
sendpacket(ifp, m);
}
ifp->if_flags &= ~IFF_OACTIVE;
}
}
sendpacket (ifp, m); /*
* Driver transmit daemon
*/
void
greth_txDaemon_gbit (void *arg)
{
struct greth_softc *sc = (struct greth_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 GRETH_DEBUG
printf ("t\n");
#endif
/*
* Send packets till queue is empty
*/
for (;;)
{
while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
m_free(sc->txmbuf[sc->tx_dptr]);
sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
sc->tx_cnt--;
}
/*
* Get the next mbuf chain to transmit.
*/
IF_DEQUEUE (&ifp->if_snd, m);
if (!m)
break;
sendpacket_gbit(ifp, m);
} }
ifp->if_flags &= ~IFF_OACTIVE; ifp->if_flags &= ~IFF_OACTIVE;
} }
@@ -521,10 +823,16 @@ greth_init (void *arg)
*/ */
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096, sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
greth_rxDaemon, sc); greth_rxDaemon, sc);
if (sc->gbit_mac) {
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
greth_txDaemon_gbit, sc);
} else {
sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096, sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
greth_txDaemon, sc); greth_txDaemon, sc);
} }
}
/* /*
* Tell the world that we're running. * Tell the world that we're running.
*/ */

View File

@@ -9,6 +9,7 @@
* $Id$ * $Id$
*/ */
#ifndef _GR_ETH_ #ifndef _GR_ETH_
#define _GR_ETH_ #define _GR_ETH_
@@ -41,11 +42,22 @@ typedef struct _greth_regs {
#define GRETH_TXD_ENABLE 0x0800 /* Tx BD Enable */ #define GRETH_TXD_ENABLE 0x0800 /* Tx BD Enable */
#define GRETH_TXD_WRAP 0x1000 /* Tx BD Wrap (last BD) */ #define GRETH_TXD_WRAP 0x1000 /* Tx BD Wrap (last BD) */
#define GRETH_TXD_IRQ 0x2000 /* Tx BD IRQ Enable */ #define GRETH_TXD_IRQ 0x2000 /* Tx BD IRQ Enable */
#define GRETH_TXD_MORE 0x20000 /* Tx BD More (more descs for packet) */
#define GRETH_TXD_IPCS 0x40000 /* Tx BD insert ip chksum */
#define GRETH_TXD_TCPCS 0x80000 /* Tx BD insert tcp chksum */
#define GRETH_TXD_UDPCS 0x100000 /* Tx BD insert udp chksum */
#define GRETH_TXD_UNDERRUN 0x4000 /* Tx BD Underrun Status */ #define GRETH_TXD_UNDERRUN 0x4000 /* Tx BD Underrun Status */
#define GRETH_TXD_RETLIM 0x8000 /* Tx BD Retransmission Limit Status */ #define GRETH_TXD_RETLIM 0x8000 /* Tx BD Retransmission Limit Status */
#define GRETH_TXD_LATECOL 0x10000 /* Tx BD Late Collision */
#define GRETH_TXD_STATS (GRETH_TXD_UNDERRUN | \ #define GRETH_TXD_STATS (GRETH_TXD_UNDERRUN | \
GRETH_TXD_RETLIM) GRETH_TXD_RETLIM | \
GRETH_TXD_LATECOL)
#define GRETH_TXD_CS (GRETH_TXD_IPCS | \
GRETH_TXD_TCPCS | \
GRETH_TXD_UDPCS)
/* Rx BD */ /* Rx BD */
#define GRETH_RXD_ENABLE 0x0800 /* Rx BD Enable */ #define GRETH_RXD_ENABLE 0x0800 /* Rx BD Enable */
@@ -56,6 +68,15 @@ typedef struct _greth_regs {
#define GRETH_RXD_TOOLONG 0x8000 /* Rx BD Too Long Status */ #define GRETH_RXD_TOOLONG 0x8000 /* Rx BD Too Long Status */
#define GRETH_RXD_CRCERR 0x10000 /* Rx BD CRC Error Status */ #define GRETH_RXD_CRCERR 0x10000 /* Rx BD CRC Error Status */
#define GRETH_RXD_OVERRUN 0x20000 /* Rx BD Overrun Status */ #define GRETH_RXD_OVERRUN 0x20000 /* Rx BD Overrun Status */
#define GRETH_RXD_LENERR 0x40000 /* Rx BD Length Error */
#define GRETH_RXD_ID 0x40000 /* Rx BD IP Detected */
#define GRETH_RXD_IR 0x40000 /* Rx BD IP Chksum Error */
#define GRETH_RXD_UD 0x40000 /* Rx BD UDP Detected*/
#define GRETH_RXD_UR 0x40000 /* Rx BD UDP Chksum Error */
#define GRETH_RXD_TD 0x40000 /* Rx BD TCP Detected */
#define GRETH_RXD_TR 0x40000 /* Rx BD TCP Chksum Error */
#define GRETH_RXD_STATS (GRETH_RXD_OVERRUN | \ #define GRETH_RXD_STATS (GRETH_RXD_OVERRUN | \
GRETH_RXD_DRIBBLE | \ GRETH_RXD_DRIBBLE | \
GRETH_RXD_TOOLONG | \ GRETH_RXD_TOOLONG | \
@@ -87,6 +108,21 @@ typedef struct _greth_regs {
#define GRETH_MDIO_PHYADR 0x0000F800 /* PHY address */ #define GRETH_MDIO_PHYADR 0x0000F800 /* PHY address */
#define GRETH_MDIO_DATA 0xFFFF0000 /* MDIO DATA */ #define GRETH_MDIO_DATA 0xFFFF0000 /* MDIO DATA */
/* MII registers */
#define GRETH_MII_EXTADV_1000FD 0x00000200
#define GRETH_MII_EXTADV_1000HD 0x00000100
#define GRETH_MII_EXTPRT_1000FD 0x00000800
#define GRETH_MII_EXTPRT_1000HD 0x00000400
#define GRETH_MII_100T4 0x00000200
#define GRETH_MII_100TXFD 0x00000100
#define GRETH_MII_100TXHD 0x00000080
#define GRETH_MII_10FD 0x00000040
#define GRETH_MII_10HD 0x00000020
/* Attach routine */ /* Attach routine */
int rtems_greth_driver_attach ( int rtems_greth_driver_attach (
@@ -94,11 +130,25 @@ int rtems_greth_driver_attach (
greth_configuration_t *chip greth_configuration_t *chip
); );
/* PHY data */
struct phy_device_info
{
int vendor;
int device;
int rev;
int adv;
int part;
int extadv;
int extpart;
};
/* /*
#ifdef CPU_U32_FIX #ifdef CPU_U32_FIX
void ipalign(struct mbuf *m); void ipalign(struct mbuf *m);
#endif #endif
*/
*/
#endif #endif