mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 15:15:44 +00:00
PR 2011/networking - GRETH: performance improvements and one bugfix
GRETH driver updated, 10-15% performance improvements for GBIT MAC, unnecessary RX interrupts not taken which under heavy load saves approx. 1500 interrupts/s, one task removed saving about 5kb memory and 1 bug solved. BUG: RX interrupt was enabled before the RX-daemon was created which could result in a faulty call to rtems_event_send. Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
This commit is contained in:
@@ -82,11 +82,6 @@ extern void ipalign(struct mbuf *m);
|
|||||||
/* event to send when tx buffers become available */
|
/* event to send when tx buffers become available */
|
||||||
#define GRETH_TX_WAIT_EVENT RTEMS_EVENT_3
|
#define GRETH_TX_WAIT_EVENT RTEMS_EVENT_3
|
||||||
|
|
||||||
/* suspend when all TX descriptors exhausted */
|
|
||||||
/*
|
|
||||||
#define GRETH_SUSPEND_NOTXBUF
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if (MCLBYTES < RBUF_SIZE)
|
#if (MCLBYTES < RBUF_SIZE)
|
||||||
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
# error "Driver must have MCLBYTES > RBUF_SIZE"
|
||||||
#endif
|
#endif
|
||||||
@@ -118,8 +113,7 @@ struct greth_softc
|
|||||||
greth_regs *regs;
|
greth_regs *regs;
|
||||||
|
|
||||||
int acceptBroadcast;
|
int acceptBroadcast;
|
||||||
rtems_id rxDaemonTid;
|
rtems_id daemonTid;
|
||||||
rtems_id txDaemonTid;
|
|
||||||
|
|
||||||
unsigned int tx_ptr;
|
unsigned int tx_ptr;
|
||||||
unsigned int tx_dptr;
|
unsigned int tx_dptr;
|
||||||
@@ -133,6 +127,12 @@ struct greth_softc
|
|||||||
struct mbuf **txmbuf;
|
struct mbuf **txmbuf;
|
||||||
rtems_vector_number vector;
|
rtems_vector_number vector;
|
||||||
|
|
||||||
|
/* TX descriptor interrupt generation */
|
||||||
|
int tx_int_gen;
|
||||||
|
int tx_int_gen_cur;
|
||||||
|
struct mbuf *next_tx_mbuf;
|
||||||
|
int max_fragsize;
|
||||||
|
|
||||||
/*Status*/
|
/*Status*/
|
||||||
struct phy_device_info phydev;
|
struct phy_device_info phydev;
|
||||||
int fd;
|
int fd;
|
||||||
@@ -165,6 +165,9 @@ struct greth_softc
|
|||||||
|
|
||||||
static struct greth_softc greth;
|
static struct greth_softc greth;
|
||||||
|
|
||||||
|
int greth_process_tx_gbit(struct greth_softc *sc);
|
||||||
|
int greth_process_tx(struct greth_softc *sc);
|
||||||
|
|
||||||
static char *almalloc(int sz)
|
static char *almalloc(int sz)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
@@ -175,33 +178,40 @@ static char *almalloc(int sz)
|
|||||||
|
|
||||||
/* GRETH interrupt handler */
|
/* GRETH interrupt handler */
|
||||||
|
|
||||||
static rtems_isr
|
rtems_isr
|
||||||
greth_interrupt_handler (rtems_vector_number v)
|
greth_interrupt_handler (rtems_vector_number v)
|
||||||
{
|
{
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
/* read and clear interrupt cause */
|
uint32_t ctrl;
|
||||||
|
rtems_event_set events = 0;
|
||||||
|
|
||||||
|
/* read and clear interrupt cause */
|
||||||
status = greth.regs->status;
|
status = greth.regs->status;
|
||||||
greth.regs->status = status;
|
greth.regs->status = status;
|
||||||
|
ctrl = greth.regs->ctrl;
|
||||||
|
|
||||||
/* Frame received? */
|
/* Frame received? */
|
||||||
if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))
|
if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
|
||||||
{
|
{
|
||||||
greth.rxInterrupts++;
|
greth.rxInterrupts++;
|
||||||
rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT);
|
/* Stop RX-Error and RX-Packet interrupts */
|
||||||
|
ctrl &= ~GRETH_CTRL_RXIRQ;
|
||||||
|
events |= INTERRUPT_EVENT;
|
||||||
}
|
}
|
||||||
#ifdef GRETH_SUSPEND_NOTXBUF
|
|
||||||
if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ))
|
if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
|
||||||
{
|
{
|
||||||
greth.txInterrupts++;
|
greth.txInterrupts++;
|
||||||
rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT);
|
ctrl &= ~GRETH_CTRL_TXIRQ;
|
||||||
|
events |= GRETH_TX_WAIT_EVENT;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
/*
|
/* Clear interrupt sources */
|
||||||
#ifdef __leon__
|
greth.regs->ctrl = ctrl;
|
||||||
LEON_Clear_interrupt(v-0x10);
|
|
||||||
#endif
|
/* Send the event(s) */
|
||||||
*/
|
if ( events )
|
||||||
|
rtems_event_send (greth.daemonTid, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
|
static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
|
||||||
@@ -228,6 +238,9 @@ static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data)
|
|||||||
static void print_init_info(struct greth_softc *sc)
|
static void print_init_info(struct greth_softc *sc)
|
||||||
{
|
{
|
||||||
printf("greth: driver attached\n");
|
printf("greth: driver attached\n");
|
||||||
|
if ( sc->auto_neg == -1 ){
|
||||||
|
printf("Auto negotiation timed out. Selecting default config\n");
|
||||||
|
}
|
||||||
printf("**** PHY ****\n");
|
printf("**** PHY ****\n");
|
||||||
printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
|
printf("Vendor: %x Device: %x Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
|
||||||
printf("Current Operating Mode: ");
|
printf("Current Operating Mode: ");
|
||||||
@@ -266,7 +279,6 @@ greth_initialize_hardware (struct greth_softc *sc)
|
|||||||
int tmp2;
|
int tmp2;
|
||||||
unsigned int msecs;
|
unsigned int msecs;
|
||||||
struct timeval tstart, tnow;
|
struct timeval tstart, tnow;
|
||||||
int anegtout;
|
|
||||||
|
|
||||||
greth_regs *regs;
|
greth_regs *regs;
|
||||||
|
|
||||||
@@ -302,10 +314,6 @@ greth_initialize_hardware (struct greth_softc *sc)
|
|||||||
sc->sp = 0;
|
sc->sp = 0;
|
||||||
sc->auto_neg = 0;
|
sc->auto_neg = 0;
|
||||||
sc->auto_neg_time = 0;
|
sc->auto_neg_time = 0;
|
||||||
/* the anegtout variable is needed because print cannot be done before mac has
|
|
||||||
been reconfigured due to a possible deadlock situation if rtems
|
|
||||||
is run through the edcl with uart polling (-u)*/
|
|
||||||
anegtout = 0;
|
|
||||||
if ((phyctrl >> 12) & 1) {
|
if ((phyctrl >> 12) & 1) {
|
||||||
/*wait for auto negotiation to complete*/
|
/*wait for auto negotiation to complete*/
|
||||||
msecs = 0;
|
msecs = 0;
|
||||||
@@ -332,7 +340,7 @@ greth_initialize_hardware (struct greth_softc *sc)
|
|||||||
msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000;
|
msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000;
|
||||||
if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
|
if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
|
||||||
sc->auto_neg_time = msecs;
|
sc->auto_neg_time = msecs;
|
||||||
anegtout = 1
|
sc->auto_neg = -1; /* Failed */
|
||||||
tmp1 = read_mii(phyaddr, 0);
|
tmp1 = read_mii(phyaddr, 0);
|
||||||
sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
|
sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
|
||||||
sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
|
sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
|
||||||
@@ -381,7 +389,7 @@ auto_neg_done:
|
|||||||
phystatus = read_mii(phyaddr, 1);
|
phystatus = read_mii(phyaddr, 1);
|
||||||
|
|
||||||
/*Read out PHY info if extended registers are available */
|
/*Read out PHY info if extended registers are available */
|
||||||
if (phystatus & 1) {
|
if (phystatus & 1) {
|
||||||
tmp1 = read_mii(phyaddr, 2);
|
tmp1 = read_mii(phyaddr, 2);
|
||||||
tmp2 = read_mii(phyaddr, 3);
|
tmp2 = read_mii(phyaddr, 3);
|
||||||
|
|
||||||
@@ -468,28 +476,29 @@ auto_neg_done:
|
|||||||
mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
|
mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
|
||||||
regs->mac_addr_lsb = mac_addr_lsb;
|
regs->mac_addr_lsb = mac_addr_lsb;
|
||||||
|
|
||||||
|
if ( sc->rxbufs < 10 ) {
|
||||||
|
sc->tx_int_gen = sc->tx_int_gen_cur = 1;
|
||||||
|
}else{
|
||||||
|
sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
|
||||||
|
}
|
||||||
|
sc->next_tx_mbuf = NULL;
|
||||||
|
|
||||||
|
if ( !sc->gbit_mac )
|
||||||
|
sc->max_fragsize = 1;
|
||||||
|
|
||||||
|
/* clear all pending interrupts */
|
||||||
|
regs->status = 0xffffffff;
|
||||||
|
|
||||||
/* install interrupt vector */
|
/* install interrupt vector */
|
||||||
set_vector(greth_interrupt_handler, sc->vector, 1);
|
set_vector(greth_interrupt_handler, sc->vector, 1);
|
||||||
|
|
||||||
/* clear all pending interrupts */
|
|
||||||
|
|
||||||
regs->status = 0xffffffff;
|
|
||||||
|
|
||||||
#ifdef GRETH_SUSPEND_NOTXBUF
|
|
||||||
regs->ctrl |= GRETH_CTRL_TXIRQ;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
|
regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
|
||||||
|
|
||||||
if (anegtout) {
|
|
||||||
printk("Auto negotiation timed out. Selecting default config\n\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
print_init_info(sc);
|
print_init_info(sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
greth_rxDaemon (void *arg)
|
greth_Daemon (void *arg)
|
||||||
{
|
{
|
||||||
struct ether_header *eh;
|
struct ether_header *eh;
|
||||||
struct greth_softc *dp = (struct greth_softc *) &greth;
|
struct greth_softc *dp = (struct greth_softc *) &greth;
|
||||||
@@ -497,16 +506,36 @@ greth_rxDaemon (void *arg)
|
|||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
unsigned int len, len_status, bad;
|
unsigned int len, len_status, bad;
|
||||||
rtems_event_set events;
|
rtems_event_set events;
|
||||||
|
rtems_interrupt_level level;
|
||||||
|
int first;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
rtems_bsdnet_event_receive (INTERRUPT_EVENT,
|
rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
|
||||||
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
||||||
RTEMS_NO_TIMEOUT, &events);
|
RTEMS_NO_TIMEOUT, &events);
|
||||||
|
|
||||||
|
if ( events & GRETH_TX_WAIT_EVENT ){
|
||||||
|
/* TX interrupt.
|
||||||
|
* We only end up here when all TX descriptors has been used,
|
||||||
|
* and
|
||||||
|
*/
|
||||||
|
if ( dp->gbit_mac )
|
||||||
|
greth_process_tx_gbit(dp);
|
||||||
|
else
|
||||||
|
greth_process_tx(dp);
|
||||||
|
|
||||||
|
/* If we didn't get a RX interrupt we don't process it */
|
||||||
|
if ( (events & INTERRUPT_EVENT) == 0 )
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef GRETH_ETH_DEBUG
|
#ifdef GRETH_ETH_DEBUG
|
||||||
printf ("r\n");
|
printf ("r\n");
|
||||||
#endif
|
#endif
|
||||||
|
first=1;
|
||||||
|
/* Scan for Received packets */
|
||||||
|
again:
|
||||||
while (!((len_status =
|
while (!((len_status =
|
||||||
dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
|
dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
|
||||||
{
|
{
|
||||||
@@ -574,40 +603,50 @@ greth_rxDaemon (void *arg)
|
|||||||
} else {
|
} else {
|
||||||
dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
|
dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
|
||||||
}
|
}
|
||||||
|
rtems_interrupt_disable(level);
|
||||||
dp->regs->ctrl |= GRETH_CTRL_RXEN;
|
dp->regs->ctrl |= GRETH_CTRL_RXEN;
|
||||||
|
rtems_interrupt_enable(level);
|
||||||
dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
|
dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Always scan twice to avoid deadlock */
|
||||||
|
if ( first ){
|
||||||
|
first=0;
|
||||||
|
rtems_interrupt_disable(level);
|
||||||
|
dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
|
||||||
|
rtems_interrupt_enable(level);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int inside = 0;
|
static int inside = 0;
|
||||||
static void
|
static int
|
||||||
sendpacket (struct ifnet *ifp, struct mbuf *m)
|
sendpacket (struct ifnet *ifp, struct mbuf *m)
|
||||||
{
|
{
|
||||||
struct greth_softc *dp = ifp->if_softc;
|
struct greth_softc *dp = ifp->if_softc;
|
||||||
unsigned char *temp;
|
unsigned char *temp;
|
||||||
struct mbuf *n;
|
struct mbuf *n;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
rtems_interrupt_level level;
|
||||||
|
|
||||||
/*printf("Send packet entered\n");*/
|
/*printf("Send packet entered\n");*/
|
||||||
if (inside) printf ("error: sendpacket re-entered!!\n");
|
if (inside) printf ("error: sendpacket re-entered!!\n");
|
||||||
inside = 1;
|
inside = 1;
|
||||||
/*
|
|
||||||
* Waiting for Transmitter ready
|
|
||||||
*/
|
|
||||||
n = m;
|
|
||||||
|
|
||||||
while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
|
/*
|
||||||
{
|
* Is there a free descriptor available?
|
||||||
#ifdef GRETH_SUSPEND_NOTXBUF
|
*/
|
||||||
dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
|
if ( dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE ){
|
||||||
rtems_event_set events;
|
/* No. */
|
||||||
rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
|
inside = 0;
|
||||||
RTEMS_WAIT | RTEMS_EVENT_ANY,
|
return 1;
|
||||||
TOD_MILLISECONDS_TO_TICKS(500), &events);
|
}
|
||||||
#endif
|
|
||||||
}
|
/* Remember head of chain */
|
||||||
|
n = m;
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
|
temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
|
||||||
@@ -642,179 +681,282 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
|
|||||||
dp->txdesc[dp->tx_ptr].ctrl =
|
dp->txdesc[dp->tx_ptr].ctrl =
|
||||||
GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
|
GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
|
||||||
}
|
}
|
||||||
dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
|
|
||||||
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
|
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
|
||||||
|
rtems_interrupt_disable(level);
|
||||||
|
dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
|
||||||
|
rtems_interrupt_enable(level);
|
||||||
|
|
||||||
}
|
}
|
||||||
inside = 0;
|
inside = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
int
|
||||||
sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
|
sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
|
||||||
{
|
{
|
||||||
struct greth_softc *dp = ifp->if_softc;
|
struct greth_softc *dp = ifp->if_softc;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
||||||
|
unsigned int ctrl;
|
||||||
|
int frags;
|
||||||
|
struct mbuf *mtmp;
|
||||||
|
int int_en;
|
||||||
|
rtems_interrupt_level level;
|
||||||
|
|
||||||
/*printf("Send packet entered\n");*/
|
|
||||||
if (inside) printf ("error: sendpacket re-entered!!\n");
|
if (inside) printf ("error: sendpacket re-entered!!\n");
|
||||||
inside = 1;
|
inside = 1;
|
||||||
/*
|
|
||||||
* Waiting for Transmitter ready
|
|
||||||
*/
|
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
#ifdef GRETH_DEBUG
|
#ifdef GRETH_DEBUG
|
||||||
printf("TXD: 0x%08x\n", (int) m->m_data);
|
printf("TXD: 0x%08x\n", (int) m->m_data);
|
||||||
#endif
|
#endif
|
||||||
|
/* Get number of fragments too see if we have enough
|
||||||
|
* resources.
|
||||||
|
*/
|
||||||
|
frags=1;
|
||||||
|
mtmp=m;
|
||||||
|
while(mtmp->m_next){
|
||||||
|
frags++;
|
||||||
|
mtmp = mtmp->m_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( frags > dp->max_fragsize )
|
||||||
|
dp->max_fragsize = frags;
|
||||||
|
|
||||||
|
if ( frags > dp->txbufs ){
|
||||||
|
inside = 0;
|
||||||
|
printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( frags > (dp->txbufs-dp->tx_cnt) ){
|
||||||
|
inside = 0;
|
||||||
|
/* Return number of fragments */
|
||||||
|
return frags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Enable interrupt from descriptor every tx_int_gen
|
||||||
|
* descriptor. Typically every 16 descriptor. This
|
||||||
|
* is only to reduce the number of interrupts during
|
||||||
|
* heavy load.
|
||||||
|
*/
|
||||||
|
dp->tx_int_gen_cur-=frags;
|
||||||
|
if ( dp->tx_int_gen_cur <= 0 ){
|
||||||
|
dp->tx_int_gen_cur = dp->tx_int_gen;
|
||||||
|
int_en = GRETH_TXD_IRQ;
|
||||||
|
}else{
|
||||||
|
int_en = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this stage we know that enough descriptors are available */
|
||||||
for (;;)
|
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
|
#ifdef GRETH_DEBUG
|
||||||
int i;
|
int i;
|
||||||
printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
|
printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
|
||||||
for (i=0; i<m->m_len; i++)
|
for (i=0; i<m->m_len; i++)
|
||||||
printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
|
printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
len += m->m_len;
|
len += m->m_len;
|
||||||
dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
|
dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
|
||||||
|
|
||||||
|
/* Wrap around? */
|
||||||
if (dp->tx_ptr < dp->txbufs-1) {
|
if (dp->tx_ptr < dp->txbufs-1) {
|
||||||
if ((m->m_next) == NULL) {
|
ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
|
||||||
dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
|
}else{
|
||||||
break;
|
ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
|
||||||
} 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable Descriptor */
|
||||||
|
if ((m->m_next) == NULL) {
|
||||||
|
dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
|
||||||
|
break;
|
||||||
|
}else{
|
||||||
|
dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next */
|
||||||
dp->txmbuf[dp->tx_ptr] = m;
|
dp->txmbuf[dp->tx_ptr] = m;
|
||||||
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
|
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
|
||||||
dp->tx_cnt++;
|
dp->tx_cnt++;
|
||||||
m = m->m_next;
|
m = m->m_next;
|
||||||
|
}
|
||||||
}
|
|
||||||
dp->txmbuf[dp->tx_ptr] = m;
|
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;
|
dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
|
||||||
|
dp->tx_cnt++;
|
||||||
|
|
||||||
|
/* Tell Hardware about newly enabled descriptor */
|
||||||
|
rtems_interrupt_disable(level);
|
||||||
|
dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
|
||||||
|
rtems_interrupt_enable(level);
|
||||||
|
|
||||||
inside = 0;
|
inside = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int greth_process_tx_gbit(struct greth_softc *sc)
|
||||||
* Driver transmit daemon
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
greth_txDaemon (void *arg)
|
|
||||||
{
|
{
|
||||||
struct greth_softc *sc = (struct greth_softc *) arg;
|
|
||||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
rtems_event_set events;
|
rtems_interrupt_level level;
|
||||||
|
int first=1;
|
||||||
|
|
||||||
for (;;)
|
/*
|
||||||
{
|
* Send packets till queue is empty
|
||||||
|
*/
|
||||||
|
for (;;){
|
||||||
|
/* Reap Sent packets */
|
||||||
|
while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl) && !(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--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( sc->next_tx_mbuf ){
|
||||||
|
/* Get packet we tried but faild to transmit last time */
|
||||||
|
m = sc->next_tx_mbuf;
|
||||||
|
sc->next_tx_mbuf = NULL; /* Mark packet taken */
|
||||||
|
}else{
|
||||||
/*
|
/*
|
||||||
* Wait for packet
|
* Get the next mbuf chain to transmit from Stack.
|
||||||
*/
|
*/
|
||||||
|
IF_DEQUEUE (&ifp->if_snd, m);
|
||||||
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
|
if (!m){
|
||||||
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
/* Hardware has sent all schedule packets, this
|
||||||
RTEMS_NO_TIMEOUT, &events);
|
* makes the stack enter at greth_start next time
|
||||||
#ifdef GRETH_DEBUG
|
* a packet is to be sent.
|
||||||
printf ("t\n");
|
*/
|
||||||
#endif
|
ifp->if_flags &= ~IFF_OACTIVE;
|
||||||
|
break;
|
||||||
/*
|
|
||||||
* 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;
|
}
|
||||||
|
|
||||||
|
/* Are there free descriptors available? */
|
||||||
|
/* Try to send packet, if it a negative number is returned. */
|
||||||
|
if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
|
||||||
|
/* Not enough resources */
|
||||||
|
|
||||||
|
/* Since we have taken the mbuf out of the "send chain"
|
||||||
|
* we must remember to use that next time we come back.
|
||||||
|
* or else we have dropped a packet.
|
||||||
|
*/
|
||||||
|
sc->next_tx_mbuf = m;
|
||||||
|
|
||||||
|
/* Not enough resources, enable interrupt for transmissions
|
||||||
|
* this way we will be informed when more TX-descriptors are
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
if ( first ){
|
||||||
|
first = 0;
|
||||||
|
rtems_interrupt_disable(level);
|
||||||
|
ifp->if_flags |= IFF_OACTIVE;
|
||||||
|
sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
|
||||||
|
rtems_interrupt_enable(level);
|
||||||
|
|
||||||
|
/* We must check again to be sure that we didn't
|
||||||
|
* miss an interrupt (if a packet was sent just before
|
||||||
|
* enabling interrupts)
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}else{
|
||||||
|
/* Sent Ok, proceed to process more packets if available */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int greth_process_tx(struct greth_softc *sc)
|
||||||
* 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 ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
rtems_event_set events;
|
rtems_interrupt_level level;
|
||||||
|
int first=1;
|
||||||
|
|
||||||
for (;;)
|
/*
|
||||||
{
|
* Send packets till queue is empty
|
||||||
|
*/
|
||||||
|
for (;;){
|
||||||
|
if ( sc->next_tx_mbuf ){
|
||||||
|
/* Get packet we tried but failed to transmit last time */
|
||||||
|
m = sc->next_tx_mbuf;
|
||||||
|
sc->next_tx_mbuf = NULL; /* Mark packet taken */
|
||||||
|
}else{
|
||||||
/*
|
/*
|
||||||
* Wait for packet
|
* Get the next mbuf chain to transmit from Stack.
|
||||||
*/
|
*/
|
||||||
|
IF_DEQUEUE (&ifp->if_snd, m);
|
||||||
rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
|
if (!m){
|
||||||
RTEMS_EVENT_ANY | RTEMS_WAIT,
|
/* Hardware has sent all schedule packets, this
|
||||||
RTEMS_NO_TIMEOUT, &events);
|
* makes the stack enter at greth_start next time
|
||||||
#ifdef GRETH_DEBUG
|
* a packet is to be sent.
|
||||||
printf ("t\n");
|
*/
|
||||||
#endif
|
ifp->if_flags &= ~IFF_OACTIVE;
|
||||||
|
break;
|
||||||
/*
|
|
||||||
* 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;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Try to send packet, failed if it a non-zero number is returned. */
|
||||||
|
if ( sendpacket(ifp, m) ){
|
||||||
|
/* Not enough resources */
|
||||||
|
|
||||||
|
/* Since we have taken the mbuf out of the "send chain"
|
||||||
|
* we must remember to use that next time we come back.
|
||||||
|
* or else we have dropped a packet.
|
||||||
|
*/
|
||||||
|
sc->next_tx_mbuf = m;
|
||||||
|
|
||||||
|
/* Not enough resources, enable interrupt for transmissions
|
||||||
|
* this way we will be informed when more TX-descriptors are
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
if ( first ){
|
||||||
|
first = 0;
|
||||||
|
rtems_interrupt_disable(level);
|
||||||
|
ifp->if_flags |= IFF_OACTIVE;
|
||||||
|
sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
|
||||||
|
rtems_interrupt_enable(level);
|
||||||
|
|
||||||
|
/* We must check again to be sure that we didn't
|
||||||
|
* miss an interrupt (if a packet was sent just before
|
||||||
|
* enabling interrupts)
|
||||||
|
*/
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}else{
|
||||||
|
/* Sent Ok, proceed to process more packets if available */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
greth_start (struct ifnet *ifp)
|
greth_start (struct ifnet *ifp)
|
||||||
{
|
{
|
||||||
struct greth_softc *sc = ifp->if_softc;
|
struct greth_softc *sc = ifp->if_softc;
|
||||||
|
|
||||||
ifp->if_flags |= IFF_OACTIVE;
|
if ( ifp->if_flags & IFF_OACTIVE )
|
||||||
rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
|
return;
|
||||||
|
|
||||||
|
if ( sc->gbit_mac ){
|
||||||
|
/* No use trying to handle this if we are waiting on GRETH
|
||||||
|
* to send the previously scheduled packets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
greth_process_tx_gbit(sc);
|
||||||
|
}else{
|
||||||
|
greth_process_tx(sc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -826,34 +968,25 @@ greth_init (void *arg)
|
|||||||
struct greth_softc *sc = arg;
|
struct greth_softc *sc = arg;
|
||||||
struct ifnet *ifp = &sc->arpcom.ac_if;
|
struct ifnet *ifp = &sc->arpcom.ac_if;
|
||||||
|
|
||||||
if (sc->txDaemonTid == 0)
|
if (sc->daemonTid == 0) {
|
||||||
{
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up GRETH hardware
|
* Start driver tasks
|
||||||
*/
|
*/
|
||||||
greth_initialize_hardware (sc);
|
sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
|
||||||
|
greth_Daemon, sc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start driver tasks
|
* Set up GRETH hardware
|
||||||
*/
|
*/
|
||||||
sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
|
greth_initialize_hardware (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,
|
|
||||||
greth_txDaemon, sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tell the world that we're running.
|
* Tell the world that we're running.
|
||||||
*/
|
*/
|
||||||
ifp->if_flags |= IFF_RUNNING;
|
ifp->if_flags |= IFF_RUNNING;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -869,6 +1002,8 @@ greth_stop (struct greth_softc *sc)
|
|||||||
sc->regs->ctrl = 0; /* RX/TX OFF */
|
sc->regs->ctrl = 0; /* RX/TX OFF */
|
||||||
sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
|
sc->regs->ctrl = GRETH_CTRL_RST; /* Reset ON */
|
||||||
sc->regs->ctrl = 0; /* Reset OFF */
|
sc->regs->ctrl = 0; /* Reset OFF */
|
||||||
|
|
||||||
|
sc->next_tx_mbuf = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -885,6 +1020,8 @@ greth_stats (struct greth_softc *sc)
|
|||||||
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
|
printf (" Bad CRC:%-8lu", sc->rxBadCRC);
|
||||||
printf (" Overrun:%-8lu", sc->rxOverrun);
|
printf (" Overrun:%-8lu", sc->rxOverrun);
|
||||||
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
|
printf (" Tx Interrupts:%-8lu", sc->txInterrupts);
|
||||||
|
printf (" Maximal Frags:%-8d", sc->max_fragsize);
|
||||||
|
printf (" GBIT MAC:%-8d", sc->gbit_mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user