Notice: We have migrated to GitLab launching 2024-05-01 see here: https://gitlab.rtems.org/

Ticket #2011: 0008-GRETH-performance-improvements_HEAD.patch

File 0008-GRETH-performance-improvements_HEAD.patch, 24.2 KB (added by Daniel Hellstrom, on 02/02/12 at 15:48:42)

patch2 for HEAD

  • c/src/libchip/network/greth.c

    From 6c66b134e18dc24b3fe8b2d9a9a6954c6bc6840e Mon Sep 17 00:00:00 2001
    From: Daniel Hellstrom <daniel@gaisler.com>
    Date: Fri, 2 Dec 2011 10:47:58 +0100
    Subject: [PR 08] 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>
    ---
     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 b extern void ipalign(struct mbuf *m); 
    8484 /* event to send when tx buffers become available */
    8585#define GRETH_TX_WAIT_EVENT  RTEMS_EVENT_3
    8686
    87  /* suspend when all TX descriptors exhausted */
    88  /*
    89 #define GRETH_SUSPEND_NOTXBUF
    90  */
    91 
    9287#if (MCLBYTES < RBUF_SIZE)
    9388# error "Driver must have MCLBYTES > RBUF_SIZE"
    9489#endif
    struct greth_softc 
    120115   greth_regs *regs;
    121116
    122117   int acceptBroadcast;
    123    rtems_id rxDaemonTid;
    124    rtems_id txDaemonTid;
     118   rtems_id daemonTid;
    125119
    126120   unsigned int tx_ptr;
    127121   unsigned int tx_dptr;
    struct greth_softc 
    135129   struct mbuf **txmbuf;
    136130   rtems_vector_number vector;
    137131
     132   /* TX descriptor interrupt generation */
     133   int tx_int_gen;
     134   int tx_int_gen_cur;
     135   struct mbuf *next_tx_mbuf;
     136   int max_fragsize;
     137
    138138   /*Status*/
    139139   struct phy_device_info phydev;
    140140   int fd;
    struct greth_softc 
    167167
    168168static struct greth_softc greth;
    169169
     170int greth_process_tx_gbit(struct greth_softc *sc);
     171int greth_process_tx(struct greth_softc *sc);
     172
    170173static char *almalloc(int sz)
    171174{
    172175        char *tmp;
    static char *almalloc(int sz) 
    177180
    178181/* GRETH interrupt handler */
    179182
    180 static rtems_isr
     183rtems_isr
    181184greth_interrupt_handler (rtems_vector_number v)
    182185{
    183186        uint32_t status;
    184         /* read and clear interrupt cause */
     187        uint32_t ctrl;
     188        rtems_event_set events = 0;
    185189
     190        /* read and clear interrupt cause */
    186191        status = greth.regs->status;
    187192        greth.regs->status = status;
     193        ctrl = greth.regs->ctrl;
    188194
    189195        /* Frame received? */
    190         if (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ))
     196        if ((ctrl & GRETH_CTRL_RXIRQ) && (status & (GRETH_STATUS_RXERR | GRETH_STATUS_RXIRQ)))
    191197        {
    192198                greth.rxInterrupts++;
    193                 rtems_event_send (greth.rxDaemonTid, INTERRUPT_EVENT);
     199                /* Stop RX-Error and RX-Packet interrupts */
     200                ctrl &= ~GRETH_CTRL_RXIRQ;
     201                events |= INTERRUPT_EVENT;
    194202        }
    195 #ifdef GRETH_SUSPEND_NOTXBUF
    196         if (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ))
     203       
     204        if ( (ctrl & GRETH_CTRL_TXIRQ) && (status & (GRETH_STATUS_TXERR | GRETH_STATUS_TXIRQ)) )
    197205        {
    198206                greth.txInterrupts++;
    199                 rtems_event_send (greth.txDaemonTid, GRETH_TX_WAIT_EVENT);
     207                ctrl &= ~GRETH_CTRL_TXIRQ;
     208                events |= GRETH_TX_WAIT_EVENT;
    200209        }
    201 #endif
    202         /*
    203           #ifdef __leon__
    204           LEON_Clear_interrupt(v-0x10);
    205           #endif
    206         */
     210       
     211        /* Clear interrupt sources */
     212        greth.regs->ctrl = ctrl;
     213       
     214        /* Send the event(s) */
     215        if ( events )
     216            rtems_event_send (greth.daemonTid, events);
    207217}
    208218
    209219static uint32_t read_mii(uint32_t phy_addr, uint32_t reg_addr)
    static void write_mii(uint32_t phy_addr, uint32_t reg_addr, uint32_t data) 
    230240static void print_init_info(struct greth_softc *sc)
    231241{
    232242        printf("greth: driver attached\n");
     243                if ( sc->auto_neg == -1 ){
     244                        printf("Auto negotiation timed out. Selecting default config\n");
     245                }
    233246        printf("**** PHY ****\n");
    234247        printf("Vendor: %x   Device: %x   Revision: %d\n",sc->phydev.vendor, sc->phydev.device, sc->phydev.rev);
    235248        printf("Current Operating Mode: ");
    greth_initialize_hardware (struct greth_softc *sc) 
    268281    int tmp2;
    269282    unsigned int msecs;
    270283    struct timeval tstart, tnow;
    271     int anegtout;
    272284
    273285    greth_regs *regs;
    274286
    greth_initialize_hardware (struct greth_softc *sc) 
    304316    sc->sp = 0;
    305317    sc->auto_neg = 0;
    306318    sc->auto_neg_time = 0;
    307     /* the anegtout variable is needed because print cannot be done before mac has
    308        been reconfigured due to a possible deadlock situation if rtems
    309        is run through the edcl with uart polling (-u)*/
    310     anegtout = 0;
    311319    if ((phyctrl >> 12) & 1) {
    312320            /*wait for auto negotiation to complete*/
    313321            msecs = 0;
    greth_initialize_hardware (struct greth_softc *sc) 
    334342                    msecs = (tnow.tv_sec-tstart.tv_sec)*1000+(tnow.tv_usec-tstart.tv_usec)/1000;
    335343                    if ( msecs > GRETH_AUTONEGO_TIMEOUT_MS ){
    336344                            sc->auto_neg_time = msecs;
    337                             anegtout = 1
     345                            sc->auto_neg = -1; /* Failed */
    338346                            tmp1 = read_mii(phyaddr, 0);
    339347                            sc->gb = ((phyctrl >> 6) & 1) && !((phyctrl >> 13) & 1);
    340348                            sc->sp = !((phyctrl >> 6) & 1) && ((phyctrl >> 13) & 1);
    auto_neg_done: 
    383391    phystatus = read_mii(phyaddr, 1);
    384392
    385393    /*Read out PHY info if extended registers are available */
    386     if (phystatus & 1) {
     394    if (phystatus & 1) { 
    387395            tmp1 = read_mii(phyaddr, 2);
    388396            tmp2 = read_mii(phyaddr, 3);
    389397
    auto_neg_done: 
    470478    mac_addr_lsb |= sc->arpcom.ac_enaddr[5];
    471479    regs->mac_addr_lsb = mac_addr_lsb;
    472480
    473     /* install interrupt vector */
    474     set_vector(greth_interrupt_handler, sc->vector, 1);
     481    if ( sc->rxbufs < 10 ) {
     482        sc->tx_int_gen = sc->tx_int_gen_cur = 1;
     483    }else{
     484        sc->tx_int_gen = sc->tx_int_gen_cur = sc->txbufs/2;
     485    }
     486    sc->next_tx_mbuf = NULL;
     487   
     488    if ( !sc->gbit_mac )
     489        sc->max_fragsize = 1;
    475490
    476491    /* clear all pending interrupts */
    477 
    478492    regs->status = 0xffffffff;
    479 
    480 #ifdef GRETH_SUSPEND_NOTXBUF
    481     regs->ctrl |= GRETH_CTRL_TXIRQ;
    482 #endif
     493   
     494    /* install interrupt vector */
     495    set_vector(greth_interrupt_handler, sc->vector, 1);
    483496
    484497    regs->ctrl |= GRETH_CTRL_RXEN | (sc->fd << 4) | GRETH_CTRL_RXIRQ | (sc->sp << 7) | (sc->gb << 8);
    485    
    486     if (anegtout) {
    487             printk("Auto negotiation timed out. Selecting default config\n\r");
    488     }
    489    
     498
    490499    print_init_info(sc);
    491500}
    492501
    493 static void
    494 greth_rxDaemon (void *arg)
     502void
     503greth_Daemon (void *arg)
    495504{
    496505    struct ether_header *eh;
    497506    struct greth_softc *dp = (struct greth_softc *) &greth;
    greth_rxDaemon (void *arg) 
    499508    struct mbuf *m;
    500509    unsigned int len, len_status, bad;
    501510    rtems_event_set events;
     511    rtems_interrupt_level level;
     512    int first;
    502513
    503514    for (;;)
    504515      {
    505         rtems_bsdnet_event_receive (INTERRUPT_EVENT,
     516        rtems_bsdnet_event_receive (INTERRUPT_EVENT | GRETH_TX_WAIT_EVENT,
    506517                                    RTEMS_WAIT | RTEMS_EVENT_ANY,
    507518                                    RTEMS_NO_TIMEOUT, &events);
    508519
     520        if ( events & GRETH_TX_WAIT_EVENT ){
     521            /* TX interrupt.
     522             * We only end up here when all TX descriptors has been used,
     523             * and
     524             */
     525            if ( dp->gbit_mac )
     526                greth_process_tx_gbit(dp);
     527            else
     528                greth_process_tx(dp);
     529           
     530            /* If we didn't get a RX interrupt we don't process it */
     531            if ( (events & INTERRUPT_EVENT) == 0 )
     532                continue;
     533        }
     534
    509535#ifdef GRETH_ETH_DEBUG
    510536    printf ("r\n");
    511537#endif
     538    first=1;
     539    /* Scan for Received packets */
     540again:
    512541    while (!((len_status =
    513542                    dp->rxdesc[dp->rx_ptr].ctrl) & GRETH_RXD_ENABLE))
    514543            {
    greth_rxDaemon (void *arg) 
    576605                    } else {
    577606                            dp->rxdesc[dp->rx_ptr].ctrl = GRETH_RXD_ENABLE | GRETH_RXD_IRQ;
    578607                    }
     608                    rtems_interrupt_disable(level);
    579609                    dp->regs->ctrl |= GRETH_CTRL_RXEN;
     610                    rtems_interrupt_enable(level);
    580611                    dp->rx_ptr = (dp->rx_ptr + 1) % dp->rxbufs;
    581612            }
     613
     614        /* Always scan twice to avoid deadlock */
     615        if ( first ){
     616            first=0;
     617            rtems_interrupt_disable(level);
     618            dp->regs->ctrl |= GRETH_CTRL_RXIRQ;
     619            rtems_interrupt_enable(level);
     620            goto again;
     621        }
     622
    582623      }
    583624
    584625}
    585626
    586627static int inside = 0;
    587 static void
     628static int
    588629sendpacket (struct ifnet *ifp, struct mbuf *m)
    589630{
    590631    struct greth_softc *dp = ifp->if_softc;
    591632    unsigned char *temp;
    592633    struct mbuf *n;
    593634    unsigned int len;
     635    rtems_interrupt_level level;
    594636
    595637    /*printf("Send packet entered\n");*/
    596638    if (inside) printf ("error: sendpacket re-entered!!\n");
    597639    inside = 1;
     640
    598641    /*
    599      * Waiting for Transmitter ready
     642     * Is there a free descriptor available?
    600643     */
    601     n = m;
     644    if ( dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE ){
     645            /* No. */
     646            inside = 0;
     647            return 1;
     648    }
    602649
    603     while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
    604       {
    605 #ifdef GRETH_SUSPEND_NOTXBUF
    606         dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
    607         rtems_event_set events;
    608         rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
    609                                     RTEMS_WAIT | RTEMS_EVENT_ANY,
    610                                     TOD_MILLISECONDS_TO_TICKS(500), &events);
    611 #endif
    612       }
     650    /* Remember head of chain */
     651    n = m;
    613652
    614653    len = 0;
    615654    temp = (unsigned char *) dp->txdesc[dp->tx_ptr].addr;
    sendpacket (struct ifnet *ifp, struct mbuf *m) 
    644683                    dp->txdesc[dp->tx_ptr].ctrl =
    645684                            GRETH_TXD_WRAP | GRETH_TXD_ENABLE | len;
    646685            }
    647             dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
    648686            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
     687            rtems_interrupt_disable(level);
     688            dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
     689            rtems_interrupt_enable(level);
     690           
    649691    }
    650692    inside = 0;
     693   
     694    return 0;
    651695}
    652696
    653697
    654 static void
     698int
    655699sendpacket_gbit (struct ifnet *ifp, struct mbuf *m)
    656700{
    657701        struct greth_softc *dp = ifp->if_softc;
    658702        unsigned int len;
     703       
     704        unsigned int ctrl;
     705        int frags;
     706        struct mbuf *mtmp;
     707        int int_en;
     708        rtems_interrupt_level level;
    659709
    660         /*printf("Send packet entered\n");*/
    661710        if (inside) printf ("error: sendpacket re-entered!!\n");
    662711        inside = 1;
    663         /*
    664          * Waiting for Transmitter ready
    665          */
    666712
    667713        len = 0;
    668714#ifdef GRETH_DEBUG
    669715        printf("TXD: 0x%08x\n", (int) m->m_data);
    670716#endif
     717        /* Get number of fragments too see if we have enough
     718         * resources.
     719         */
     720        frags=1;
     721        mtmp=m;
     722        while(mtmp->m_next){
     723            frags++;
     724            mtmp = mtmp->m_next;
     725        }
     726       
     727        if ( frags > dp->max_fragsize )
     728            dp->max_fragsize = frags;
     729       
     730        if ( frags > dp->txbufs ){
     731            inside = 0;
     732            printf("GRETH: MBUF-chain cannot be sent. Increase descriptor count.\n");
     733            return -1;
     734        }
     735       
     736        if ( frags > (dp->txbufs-dp->tx_cnt) ){
     737            inside = 0;
     738            /* Return number of fragments */
     739            return frags;
     740        }
     741       
     742       
     743        /* Enable interrupt from descriptor every tx_int_gen
     744         * descriptor. Typically every 16 descriptor. This
     745         * is only to reduce the number of interrupts during
     746         * heavy load.
     747         */
     748        dp->tx_int_gen_cur-=frags;
     749        if ( dp->tx_int_gen_cur <= 0 ){
     750            dp->tx_int_gen_cur = dp->tx_int_gen;
     751            int_en = GRETH_TXD_IRQ;
     752        }else{
     753            int_en = 0;
     754        }
     755       
     756        /* At this stage we know that enough descriptors are available */
    671757        for (;;)
    672758        {
    673                 while (dp->txdesc[dp->tx_ptr].ctrl & GRETH_TXD_ENABLE)
    674                 {
    675 #ifdef GRETH_SUSPEND_NOTXBUF
    676                         dp->txdesc[dp->tx_ptr].ctrl |= GRETH_TXD_IRQ;
    677                         rtems_event_set events;
    678                         rtems_bsdnet_event_receive (GRETH_TX_WAIT_EVENT,
    679                                                     RTEMS_WAIT | RTEMS_EVENT_ANY,
    680                                                     TOD_MILLISECONDS_TO_TICKS(500), &events);
    681 #endif
    682                 }
     759               
    683760#ifdef GRETH_DEBUG
    684                 int i;
    685                 printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
    686                 for (i=0; i<m->m_len; i++)
    687                         printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
    688                 printf("\n");
     761            int i;
     762            printf("MBUF: 0x%08x, Len: %d : ", (int) m->m_data, m->m_len);
     763            for (i=0; i<m->m_len; i++)
     764                printf("%x%x", (m->m_data[i] >> 4) & 0x0ff, m->m_data[i] & 0x0ff);
     765            printf("\n");
    689766#endif
    690767            len += m->m_len;
    691768            dp->txdesc[dp->tx_ptr].addr = (uint32_t *)m->m_data;
     769
     770            /* Wrap around? */
    692771            if (dp->tx_ptr < dp->txbufs-1) {
    693                     if ((m->m_next) == NULL) {
    694                             dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
    695                             break;
    696                     } else {
    697                             dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
    698                     }
    699             } else {
    700                     if ((m->m_next) == NULL) {
    701                             dp->txdesc[dp->tx_ptr].ctrl =
    702                                     GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_CS | m->m_len;
    703                             break;
    704                     } else {
    705                             dp->txdesc[dp->tx_ptr].ctrl =
    706                                     GRETH_TXD_WRAP | GRETH_TXD_ENABLE | GRETH_TXD_MORE | GRETH_TXD_CS | m->m_len;
    707                     }
     772                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS;
     773            }else{
     774                ctrl = GRETH_TXD_ENABLE | GRETH_TXD_CS | GRETH_TXD_WRAP;
    708775            }
     776
     777            /* Enable Descriptor */
     778            if ((m->m_next) == NULL) {
     779                dp->txdesc[dp->tx_ptr].ctrl = ctrl | int_en | m->m_len;
     780                break;
     781            }else{
     782                dp->txdesc[dp->tx_ptr].ctrl = GRETH_TXD_MORE | ctrl | int_en | m->m_len;
     783            }
     784
     785            /* Next */
    709786            dp->txmbuf[dp->tx_ptr] = m;
    710787            dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
    711788            dp->tx_cnt++;
    712789            m = m->m_next;
    713 
    714     }
     790        }
    715791        dp->txmbuf[dp->tx_ptr] = m;
     792        dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
    716793        dp->tx_cnt++;
     794
     795        /* Tell Hardware about newly enabled descriptor */
     796        rtems_interrupt_disable(level);
    717797        dp->regs->ctrl = dp->regs->ctrl | GRETH_CTRL_TXEN;
    718         dp->tx_ptr = (dp->tx_ptr + 1) % dp->txbufs;
     798        rtems_interrupt_enable(level);
     799
    719800        inside = 0;
     801
     802        return 0;
    720803}
    721804
    722 /*
    723  * Driver transmit daemon
    724  */
    725 void
    726 greth_txDaemon (void *arg)
     805int greth_process_tx_gbit(struct greth_softc *sc)
    727806{
    728     struct greth_softc *sc = (struct greth_softc *) arg;
    729807    struct ifnet *ifp = &sc->arpcom.ac_if;
    730808    struct mbuf *m;
    731     rtems_event_set events;
     809    rtems_interrupt_level level;
     810    int first=1;
    732811
    733     for (;;)
    734     {
     812    /*
     813     * Send packets till queue is empty
     814     */
     815    for (;;){
     816        /* Reap Sent packets */
     817        while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
     818            m_free(sc->txmbuf[sc->tx_dptr]);
     819            sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
     820            sc->tx_cnt--;
     821        }
     822
     823        if ( sc->next_tx_mbuf ){
     824            /* Get packet we tried but faild to transmit last time */
     825            m = sc->next_tx_mbuf;
     826            sc->next_tx_mbuf = NULL; /* Mark packet taken */
     827        }else{
    735828            /*
    736              * Wait for packet
     829             * Get the next mbuf chain to transmit from Stack.
    737830             */
     831            IF_DEQUEUE (&ifp->if_snd, m);
     832            if (!m){
     833                /* Hardware has sent all schedule packets, this
     834                 * makes the stack enter at greth_start next time
     835                 * a packet is to be sent.
     836                 */
     837                ifp->if_flags &= ~IFF_OACTIVE;
     838                break;
     839            }
     840        }
    738841
    739             rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
    740                                         RTEMS_EVENT_ANY | RTEMS_WAIT,
    741                                         RTEMS_NO_TIMEOUT, &events);
    742 #ifdef GRETH_DEBUG
    743             printf ("t\n");
    744 #endif
     842        /* Are there free descriptors available? */
     843        /* Try to send packet, if it a negative number is returned. */
     844        if ( (sc->tx_cnt >= sc->txbufs) || sendpacket_gbit(ifp, m) ){
     845            /* Not enough resources */
    745846
    746             /*
    747              * Send packets till queue is empty
     847            /* Since we have taken the mbuf out of the "send chain"
     848             * we must remember to use that next time we come back.
     849             * or else we have dropped a packet.
    748850             */
     851            sc->next_tx_mbuf = m;
    749852
    750 
    751             for (;;)
    752             {
    753                     /*
    754                      * Get the next mbuf chain to transmit.
    755                      */
    756                     IF_DEQUEUE (&ifp->if_snd, m);
    757                     if (!m)
    758                             break;
    759                     sendpacket(ifp, m);
     853            /* Not enough resources, enable interrupt for transmissions
     854             * this way we will be informed when more TX-descriptors are
     855             * available.
     856             */
     857            if ( first ){
     858                first = 0;
     859                rtems_interrupt_disable(level);
     860                ifp->if_flags |= IFF_OACTIVE;
     861                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
     862                rtems_interrupt_enable(level);
     863
     864                /* We must check again to be sure that we didn't
     865                 * miss an interrupt (if a packet was sent just before
     866                 * enabling interrupts)
     867                 */
     868                continue;
    760869            }
    761             ifp->if_flags &= ~IFF_OACTIVE;
     870
     871            return -1;
     872        }else{
     873            /* Sent Ok, proceed to process more packets if available */
     874        }
    762875    }
     876    return 0;
    763877}
    764878
    765 /*
    766  * Driver transmit daemon
    767  */
    768 void
    769 greth_txDaemon_gbit (void *arg)
     879int greth_process_tx(struct greth_softc *sc)
    770880{
    771     struct greth_softc *sc = (struct greth_softc *) arg;
    772881    struct ifnet *ifp = &sc->arpcom.ac_if;
    773882    struct mbuf *m;
    774     rtems_event_set events;
     883    rtems_interrupt_level level;
     884    int first=1;
    775885
    776     for (;;)
    777     {
     886    /*
     887     * Send packets till queue is empty
     888     */
     889    for (;;){
     890        if ( sc->next_tx_mbuf ){
     891            /* Get packet we tried but failed to transmit last time */
     892            m = sc->next_tx_mbuf;
     893            sc->next_tx_mbuf = NULL; /* Mark packet taken */
     894        }else{
    778895            /*
    779              * Wait for packet
     896             * Get the next mbuf chain to transmit from Stack.
    780897             */
     898            IF_DEQUEUE (&ifp->if_snd, m);
     899            if (!m){
     900                /* Hardware has sent all schedule packets, this
     901                 * makes the stack enter at greth_start next time
     902                 * a packet is to be sent.
     903                 */
     904                ifp->if_flags &= ~IFF_OACTIVE;
     905                break;
     906            }
     907        }
    781908
    782             rtems_bsdnet_event_receive (START_TRANSMIT_EVENT,
    783                                         RTEMS_EVENT_ANY | RTEMS_WAIT,
    784                                         RTEMS_NO_TIMEOUT, &events);
    785 #ifdef GRETH_DEBUG
    786             printf ("t\n");
    787 #endif
     909        /* Try to send packet, failed if it a non-zero number is returned. */
     910        if ( sendpacket(ifp, m) ){
     911            /* Not enough resources */
    788912
    789             /*
    790              * Send packets till queue is empty
     913            /* Since we have taken the mbuf out of the "send chain"
     914             * we must remember to use that next time we come back.
     915             * or else we have dropped a packet.
    791916             */
    792             for (;;)
    793             {
    794                     while((sc->tx_cnt > 0) && !(sc->txdesc[sc->tx_dptr].ctrl & GRETH_TXD_ENABLE)) {
    795                             m_free(sc->txmbuf[sc->tx_dptr]);
    796                             sc->tx_dptr = (sc->tx_dptr + 1) % sc->txbufs;
    797                             sc->tx_cnt--;
    798                     }
    799                     /*
    800                      * Get the next mbuf chain to transmit.
    801                      */
    802                     IF_DEQUEUE (&ifp->if_snd, m);
    803                     if (!m)
    804                             break;
    805                     sendpacket_gbit(ifp, m);
     917            sc->next_tx_mbuf = m;
     918
     919            /* Not enough resources, enable interrupt for transmissions
     920             * this way we will be informed when more TX-descriptors are
     921             * available.
     922             */
     923            if ( first ){
     924                first = 0;
     925                rtems_interrupt_disable(level);
     926                ifp->if_flags |= IFF_OACTIVE;
     927                sc->regs->ctrl |= GRETH_CTRL_TXIRQ;
     928                rtems_interrupt_enable(level);
     929
     930                /* We must check again to be sure that we didn't
     931                 * miss an interrupt (if a packet was sent just before
     932                 * enabling interrupts)
     933                 */
     934                continue;
    806935            }
    807             ifp->if_flags &= ~IFF_OACTIVE;
     936
     937            return -1;
     938        }else{
     939            /* Sent Ok, proceed to process more packets if available */
     940        }
    808941    }
     942    return 0;
    809943}
    810944
    811 
    812945static void
    813946greth_start (struct ifnet *ifp)
    814947{
    815948    struct greth_softc *sc = ifp->if_softc;
    816949
    817     ifp->if_flags |= IFF_OACTIVE;
    818     rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT);
     950    if ( ifp->if_flags & IFF_OACTIVE )
     951            return;
    819952
     953    if ( sc->gbit_mac ){
     954        /* No use trying to handle this if we are waiting on GRETH
     955         * to send the previously scheduled packets.
     956         */
     957
     958        greth_process_tx_gbit(sc);
     959    }else{
     960        greth_process_tx(sc);
     961    }
    820962}
    821963
    822964/*
    greth_init (void *arg) 
    828970    struct greth_softc *sc = arg;
    829971    struct ifnet *ifp = &sc->arpcom.ac_if;
    830972
    831     if (sc->txDaemonTid == 0)
    832       {
     973    if (sc->daemonTid == 0) {
    833974
    834           /*
    835            * Set up GRETH hardware
    836            */
    837           greth_initialize_hardware (sc);
     975        /*
     976         * Start driver tasks
     977         */
     978        sc->daemonTid = rtems_bsdnet_newproc ("DCrxtx", 4096,
     979                                              greth_Daemon, sc);
    838980
    839           /*
    840            * Start driver tasks
    841            */
    842           sc->rxDaemonTid = rtems_bsdnet_newproc ("DCrx", 4096,
    843                                                   greth_rxDaemon, sc);
    844           if (sc->gbit_mac) {
    845                   sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
    846                                                           greth_txDaemon_gbit, sc);
    847           } else {
    848                   sc->txDaemonTid = rtems_bsdnet_newproc ("DCtx", 4096,
    849                                                           greth_txDaemon, sc);
    850           }
     981        /*
     982         * Set up GRETH hardware
     983         */
     984        greth_initialize_hardware (sc);
    851985
    852       }
     986    }
    853987
    854988    /*
    855989     * Tell the world that we're running.
    856990     */
    857991    ifp->if_flags |= IFF_RUNNING;
    858 
    859992}
    860993
    861994/*
    greth_stop (struct greth_softc *sc) 
    8711004    sc->regs->ctrl = 0;                 /* RX/TX OFF */
    8721005    sc->regs->ctrl = GRETH_CTRL_RST;    /* Reset ON */
    8731006    sc->regs->ctrl = 0;                 /* Reset OFF */
     1007   
     1008    sc->next_tx_mbuf = NULL;
    8741009}
    8751010
    8761011
    greth_stats (struct greth_softc *sc) 
    8871022  printf ("            Bad CRC:%-8lu", sc->rxBadCRC);
    8881023  printf ("         Overrun:%-8lu", sc->rxOverrun);
    8891024  printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);
     1025  printf ("      Maximal Frags:%-8d", sc->max_fragsize);
     1026  printf ("      GBIT MAC:%-8d", sc->gbit_mac);
    8901027}
    8911028
    8921029/*