[rtems commit] PR 2011/networking - GRETH: performance improvements and one bugfix

Joel Sherrill joel at rtems.org
Thu Feb 2 19:08:54 UTC 2012


Module:    rtems
Branch:    master
Commit:    0f700ffc211fe2c54407f19e4f5e9db38a29215a
Changeset: http://git.rtems.org/rtems/commit/?id=0f700ffc211fe2c54407f19e4f5e9db38a29215a

Author:    Joel Sherrill <joel.sherrill at oarcorp.com>
Date:      Thu Feb  2 13:06:26 2012 -0600

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 at gaisler.com>

---

 c/src/libchip/network/greth.c |  497 ++++++++++++++++++++++++++---------------
 1 files changed, 317 insertions(+), 180 deletions(-)

diff --git a/c/src/libchip/network/greth.c b/c/src/libchip/network/greth.c
index 05d74c7..aff4d0f 100644
--- a/c/src/libchip/network/greth.c
+++ b/c/src/libchip/network/greth.c
@@ -84,11 +84,6 @@ extern void ipalign(struct mbuf *m);
  /* event to send when tx buffers become available */
 #define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
 
- /* suspend when all TX descriptors exhausted */
- /*
-#define GRETH_SUSPEND_NOTXBUF
- */
-
 #if (MCLBYTES < RBUF_SIZE)
 # error "Driver must have MCLBYTES > RBUF_SIZE"
 #endif
@@ -120,8 +115,7 @@ struct greth_softc
    greth_regs *regs;
 
    int acceptBroadcast;
-   rtems_id rxDaemonTid;
-   rtems_id txDaemonTid;
+   rtems_id daemonTid;
 
    unsigned int tx_ptr;
    unsigned int tx_dptr;
@@ -135,6 +129,12 @@ struct greth_softc
    struct mbuf **txmbuf;
    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*/
    struct phy_device_info phydev;
    int fd;
@@ -167,6 +167,9 @@ struct greth_softc
 
 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)
 {
         char *tmp;
@@ -177,33 +180,40 @@ static char *almalloc(int sz)
 
 /* GRETH interrupt handler */
 
-static rtems_isr
+rtems_isr
 greth_interrupt_handler (rtems_vector_number v)
 {
         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;
         greth.regs->status = status;
+        ctrl = greth.regs->ctrl;
 
         /* Frame received? */
-        if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))
+        if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
         {
                 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++;
-                rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT);
+                ctrl &= ~GRETH_CTRL_TXIRQ;
+                events |= GRETH_TX_WAIT_EVENT;
         }
-#endif
-        /*
-          #ifdef __leon__
-          LEON_Clear_interrupt(v-0x10);
-          #endif
-        */
+        
+        /* Clear interrupt sources */
+        greth.regs->ctrl = ctrl;
+        
+        /* 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)
@@ -230,6 +240,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)
 {
         printf("greth: driver attached\n");
+		if ( sc->auto_neg == -1 ){
+		        printf("Auto negotiation timed out. Selecting default config\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: ");
@@ -268,7 +281,6 @@ greth_initialize_hardware (struct greth_softc *sc)
     int tmp2;
     unsigned int msecs;
     struct timeval tstart, tnow;
-    int anegtout;
 
     greth_regs *regs;
 
@@ -304,10 +316,6 @@ greth_initialize_hardware (struct greth_softc *sc)
     sc->sp = 0;
     sc->auto_neg = 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) {
             /*wait for auto negotiation to complete*/
             msecs = 0;
@@ -334,7 +342,7 @@ greth_initialize_hardware (struct greth_softc *sc)
                     msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000;
                     if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
                             sc->auto_neg_time = msecs;
-                            anegtout = 1
+                            sc->auto_neg = -1; /* Failed */
                             tmp1 = read_mii(phyaddr, 0);
                             sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
                             sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
@@ -383,7 +391,7 @@ auto_neg_done:
     phystatus = read_mii(phyaddr, 1);
 
     /*Read out PHY info if extended registers are available */
-    if (phystatus & 1) {
+    if (phystatus & 1) {  
             tmp1 = read_mii(phyaddr, 2);
             tmp2 = read_mii(phyaddr, 3);
 
@@ -470,28 +478,29 @@ auto_neg_done:
     mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
     regs->mac_addr_lsb = mac_addr_lsb;
 
-    /* install interrupt vector */
-    set_vector(greth_interrupt_handler, sc->vector, 1);
+    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;
-
-#ifdef GRETH_SUSPEND_NOTXBUF
-    regs->ctrl |= GRETH_CTRL_TXIRQ;
-#endif
+    
+    /* install interrupt vector */
+    set_vector(greth_interrupt_handler, sc->vector, 1);
 
     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);
 }
 
-static void
-greth_rxDaemon (void *arg)
+void
+greth_Daemon (void *arg)
 {
     struct ether_header *eh;
     struct greth_softc *dp = (struct greth_softc *) &greth;
@@ -499,16 +508,36 @@ greth_rxDaemon (void *arg)
     struct mbuf *m;
     unsigned int len, len_status, bad;
     rtems_event_set events;
+    rtems_interrupt_level level;
+    int first;
 
     for (;;)
       {
-        rtems_bsdnet_event_receive (INTERRUPT_EVENT,
+        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
                                     RTEMS_WAIT | RTEMS_EVENT_ANY,
                                     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
     printf ("r\n");
 #endif
+    first=1;
+    /* Scan for Received packets */
+again:
     while (!((len_status =
 		    dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
 	    {
@@ -576,40 +605,50 @@ greth_rxDaemon (void *arg)
                     } else {
                             dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
                     }
+                    rtems_interrupt_disable(level);
                     dp->regs->ctrl |= GRETH_CTRL_RXEN;
+                    rtems_interrupt_enable(level);
                     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 void
+static int
 sendpacket (struct ifnet *ifp, struct mbuf *m)
 {
     struct greth_softc *dp = ifp->if_softc;
     unsigned char *temp;
     struct mbuf *n;
     unsigned int len;
+    rtems_interrupt_level level;
 
     /*printf("Send packet entered\n");*/
     if (inside) printf ("error: sendpacket re-entered!!\n");
     inside = 1;
+
     /*
-     * Waiting for Transmitter ready
+     * Is there a free descriptor available?
      */
-    n = m;
+    if ( dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE ){
+            /* No. */
+            inside = 0;
+            return 1;
+    }
 
-    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
-      }
+    /* Remember head of chain */
+    n = m;
 
     len = 0;
     temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
@@ -644,179 +683,282 @@ sendpacket (struct ifnet *ifp, struct mbuf *m)
                     dp->txdesc[dp->tx_ptr].ctrl =
                             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;
+            rtems_interrupt_disable(level);
+            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
+            rtems_interrupt_enable(level);
+            
     }
     inside = 0;
+    
+    return 0;
 }
 
 
-static void
+int
 sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
 {
         struct greth_softc *dp = ifp->if_softc;
         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");
         inside = 1;
-        /*
-         * Waiting for Transmitter ready
-         */
 
         len = 0;
 #ifdef GRETH_DEBUG
         printf("TXD: 0x%08x\n", (int) m->m_data);
 #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 (;;)
         {
-                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");
+            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;
+
+            /* Wrap around? */
             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;
-                    }
+                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
+            }else{
+                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
             }
+
+            /* 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->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
             dp->tx_cnt++;
             m = m->m_next;
-
-    }
+        }
         dp->txmbuf[dp->tx_ptr] = m;
+        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;
-        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
+        rtems_interrupt_enable(level);
+
         inside = 0;
+
+        return 0;
 }
 
-/*
- * Driver transmit daemon
- */
-void
-greth_txDaemon (void *arg)
+int greth_process_tx_gbit(struct greth_softc *sc)
 {
-    struct greth_softc *sc = (struct greth_softc *) arg;
     struct ifnet *ifp = &sc->arpcom.ac_if;
     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);
+            if (!m){
+                /* Hardware has sent all schedule packets, this
+                 * makes the stack enter at greth_start next time
+                 * a packet is to be sent.
+                 */
+                ifp->if_flags &= ~IFF_OACTIVE;
+                break;
+            }
+        }
 
-            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
-                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
-                                        RTEMS_NO_TIMEOUT, &events);
-#ifdef GRETH_DEBUG
-            printf ("t\n");
-#endif
+        /* 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 */
 
-            /*
-             * Send packets till queue is empty
+            /* 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;
 
-
-            for (;;)
-	    {
-                    /*
-                     * Get the next mbuf chain to transmit.
-                     */
-                    IF_DEQUEUE (&ifp->if_snd, m);
-                    if (!m)
-                            break;
-                    sendpacket(ifp, 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;
             }
-            ifp->if_flags &= ~IFF_OACTIVE;
+
+            return -1;
+        }else{
+            /* Sent Ok, proceed to process more packets if available */
+        }
     }
+    return 0;
 }
 
-/*
- * Driver transmit daemon
- */
-void
-greth_txDaemon_gbit (void *arg)
+int greth_process_tx(struct greth_softc *sc)
 {
-    struct greth_softc *sc = (struct greth_softc *) arg;
     struct ifnet *ifp = &sc->arpcom.ac_if;
     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);
+            if (!m){
+                /* Hardware has sent all schedule packets, this
+                 * makes the stack enter at greth_start next time
+                 * a packet is to be sent.
+                 */
+                ifp->if_flags &= ~IFF_OACTIVE;
+                break;
+            }
+        }
 
-            rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
-                                        RTEMS_EVENT_ANY | RTEMS_WAIT,
-                                        RTEMS_NO_TIMEOUT, &events);
-#ifdef GRETH_DEBUG
-            printf ("t\n");
-#endif
+        /* Try to send packet, failed if it a non-zero number is returned. */
+        if ( sendpacket(ifp, m) ){
+            /* Not enough resources */
 
-            /*
-             * Send packets till queue is empty
+            /* 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.
              */
-            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);
+            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;
             }
-            ifp->if_flags &= ~IFF_OACTIVE;
+
+            return -1;
+        }else{
+            /* Sent Ok, proceed to process more packets if available */
+        }
     }
+    return 0;
 }
 
-
 static void
 greth_start (struct ifnet *ifp)
 {
     struct greth_softc *sc = ifp->if_softc;
 
-    ifp->if_flags |= IFF_OACTIVE;
-    rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
+    if ( ifp->if_flags & IFF_OACTIVE )
+            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);
+    }
 }
 
 /*
@@ -828,34 +970,25 @@ greth_init (void *arg)
     struct greth_softc *sc = arg;
     struct ifnet *ifp = &sc->arpcom.ac_if;
 
-    if (sc->txDaemonTid == 0)
-      {
+    if (sc->daemonTid == 0) {
 
-	  /*
-	   * Set up GRETH hardware
-	   */
-          greth_initialize_hardware (sc);
+        /*
+         * Start driver tasks
+         */
+        sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
+                                              greth_Daemon, sc);
 
-	  /*
-	   * Start driver tasks
-	   */
-	  sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
-						  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);
-          }
+        /*
+         * Set up GRETH hardware
+         */
+        greth_initialize_hardware (sc);
 
-      }
+    }
 
     /*
      * Tell the world that we're running.
      */
     ifp->if_flags |= IFF_RUNNING;
-
 }
 
 /*
@@ -871,6 +1004,8 @@ greth_stop (struct greth_softc *sc)
     sc->regs->ctrl = 0;		        /* RX/TX OFF */
     sc->regs->ctrl = GRETH_CTRL_RST;	/* Reset ON */
     sc->regs->ctrl = 0;	         	/* Reset OFF */
+    
+    sc->next_tx_mbuf = NULL;
 }
 
 
@@ -887,6 +1022,8 @@ greth_stats (struct greth_softc *sc)
   printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
   printf ("         Overrun:%-8lu", sc->rxOverrun);
   printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
+  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
+  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
 }
 
 /*




More information about the vc mailing list