From 89286e26a4c4623cc115fe7bad0e02cfd1a6a754 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sun, 22 Mar 2009 17:13:51 +0000 Subject: [PATCH] Fix an error that was causing Tx to timeout improperly git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@1639 7fd9a85b-ad96-42d3-883c-3090e2eb8679 --- nuttx/ChangeLog | 6 +- nuttx/Documentation/NuttX.html | 8 ++- nuttx/arch/z80/src/ez80/ez80_emac.c | 90 ++++++++++++++--------------- 3 files changed, 55 insertions(+), 49 deletions(-) diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 9515b3796..c2c3eccbd 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -662,5 +662,9 @@ * net/uip: Correct UDP bind behavior. It should select a valid port number if it receives a port number of zero. * netutils/dhcpd: Corrrect for ZDS compiler. Fix issue with re-use of a - port number. Fix a number of broadcast-related problems. + port number. Fixed a number of broadcast-related problems. * eZ80Acclaim!: Add a tiny webserver configuration + * eZ80Acclaim!: Fixed an important bug in the EMAC Tx timeout logic. It was + always timing out when the load was heavy and worse, for some reason, + resetting the Tx function caused unexpected registers to be reset in + the Rcv function was well. diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html index 4f1e88a66..08d056b73 100644 --- a/nuttx/Documentation/NuttX.html +++ b/nuttx/Documentation/NuttX.html @@ -8,7 +8,7 @@

NuttX RTOS

-

Last Updated: March 21, 2009

+

Last Updated: March 22, 2009

@@ -1353,8 +1353,12 @@ nuttx-0.4.4 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> * net/uip: Correct UDP bind behavior. It should select a valid port number if it receives a port number of zero. * netutils/dhcpd: Corrrect for ZDS compiler. Fix issue with re-use of a - port number. Fix a number of broadcast-related problems. + port number. Fixed a number of broadcast-related problems. * eZ80Acclaim!: Add a tiny webserver configuration + * eZ80Acclaim!: Fixed an important bug in the EMAC Tx timeout logic. It was + always timing out when the load was heavy and worse, for some reason, + resetting the Tx function caused unexpected registers to be reset in + the Rcv function was well. pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/nuttx/arch/z80/src/ez80/ez80_emac.c b/nuttx/arch/z80/src/ez80/ez80_emac.c index 817668595..df550b715 100644 --- a/nuttx/arch/z80/src/ez80/ez80_emac.c +++ b/nuttx/arch/z80/src/ez80/ez80_emac.c @@ -276,7 +276,7 @@ struct ez80emac_driver_s * Tx/Rx memory). * txhead: Points to the oldest Tx descriptor queued for output (but for * which output has not yet completed. Initialized to NULL; set - * by ez80emac_transmit() when Tx is started and by ez80emac_reclaimtxdesc() + * by ez80emac_transmit() when Tx is started and by ez80emac_txinterrupt() * when Tx processing completes. txhead == NULL is also a sure * indication that there is no Tx in progress. * txnext: Points to the next free Tx descriptor. Initialized to txstart; set @@ -946,7 +946,7 @@ static int ez80emac_transmit(struct ez80emac_driver_s *priv) * handler and, therefore, may be suspended when debug output is generated! */ - nllvdbg("ENTRY: txnext=%p {%06x, %u, %04x} trp=%02x%02x\n", + nllvdbg("txnext=%p {%06x, %u, %04x} trp=%02x%02x\n", priv->txnext, priv->txnext->np, priv->txnext->pktsize, priv->txnext->stat, inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L)); @@ -1025,11 +1025,11 @@ static int ez80emac_transmit(struct ez80emac_driver_s *priv) outp(EZ80_EMAC_PTMR, EMAC_PTMR); irqrestore(flags); - nllvdbg("EXIT: txdesc=%p {%06x, %u, %04x}\n", + nllvdbg("txdesc=%p {%06x, %u, %04x}\n", txdesc, txdesc->np, txdesc->pktsize, txdesc->stat); - nllvdbg(" txnext=%p {%06x, %u, %04x} trp=%02x%02x\n", + nllvdbg("txnext=%p {%06x, %u, %04x} trp=%02x%02x\n", txnext, txnext->np, txnext->pktsize, txnext->stat, - inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L)); + inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L)); /* Setup the TX timeout watchdog (perhaps restarting the timer) */ @@ -1323,7 +1323,7 @@ static int ez80emac_receive(struct ez80emac_driver_s *priv) static int ez80emac_txinterrupt(int irq, FAR void *context) { FAR struct ez80emac_driver_s *priv = &g_emac; - FAR struct ez80emac_desc_s *txdesc = priv->txhead; + FAR struct ez80emac_desc_s *txhead = priv->txhead; ubyte regval; ubyte istat; @@ -1340,74 +1340,72 @@ static int ez80emac_txinterrupt(int irq, FAR void *context) istat = inp(EZ80_EMAC_ISTAT) & EMAC_ISTAT_TXEVENTS; outp(EZ80_EMAC_ISTAT, istat); + EMAC_STAT(priv, tx_int); + /* All events are packet/control frame transmit complete events */ nvdbg("txhead=%p {%06x, %u, %04x} trp=%02x%02x istat=%02x\n", - txdesc, txdesc->np, txdesc->pktsize, txdesc->stat, + txhead, txhead->np, txhead->pktsize, txhead->stat, inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L), istat); - EMAC_STAT(priv, tx_int); + /* Handle all packets in the list that are no longer owned by the hardware */ - /* Check if the packet is still owned by the hardware */ - - if ((txdesc->stat & EMAC_TXDESC_OWNER) != 0) + while (txhead && (txhead->stat & EMAC_TXDESC_OWNER) == 0) { - ndbg("Descriptor %p still owned by H/W {%06x, %u, %04x} trp=%02x%02x istat=%02x\n", - txdesc, txdesc->np, txdesc->pktsize, txdesc->stat, - inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L), istat); - return OK; + if ((txhead->stat & EMAC_TXDESC_ABORT) != 0) + { + ndbg("Descriptor %p aborted {%06x, %u, %04x} trp=%02x%02x\n", + txhead, txhead->np, txhead->pktsize, txhead->stat, + inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L)); + + EMAC_STAT(priv, tx_errors); + EMAC_STAT(priv, tx_abterrors); + } + + /* Get the address of the next Tx descriptor in the list (if any) */ + + txhead = (FAR struct ez80emac_desc_s *)txhead->np; + if (txhead) + { + nvdbg("txhead=%p {%06x, %u, %04x} trp=%02x%02x\n", + txhead, txhead->np, txhead->pktsize, txhead->stat, + inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L)); + } } - /* Handle errors */ + /* Save the new head. If it is NULL, then we have read all the way to + * the terminating description with np==NULL. + */ - else if ((txdesc->stat & EMAC_TXDESC_ABORT) != 0) - { - ndbg("Descriptor %p aborted {%06x, %u, %04x} trp=%02x%02x istat=%02x\n", - txdesc, txdesc->np, txdesc->pktsize, txdesc->stat, - inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L), istat); - - EMAC_STAT(priv, tx_errors); - EMAC_STAT(priv, tx_abterrors); - } - - /* Get the address of the next Tx descriptor in the list (if any) */ - - priv->txhead = (FAR struct ez80emac_desc_s *)txdesc->np; + priv->txhead = txhead; if (!priv->txhead) { - /* No pending TX -- This should never happen because there - * is always a dummy descriptor at the end of the list owned - * by the host. Reset to the beginining of the buffer - * and stop the poll timer + nvdbg("No pending Tx.. Stopping XMIT function.\n"); + + /* Stop the Tx poll timer. (It will get restarted when we have + * something to send */ outp(EZ80_EMAC_PTMR, 0); - priv->txnext = priv->txstart; /* Reset the transmit function. That should force the TRP to be - * the same as TDLP which is the set to txstart. + * the same as TDLP which is then set to txstart. */ +#if 0 // Seems to reset RWP as well ??? + priv->txnext = priv->txstart; + regval = inp(EZ80_EMAC_RST); regval |= EMAC_RST_HRTFN; outp(EZ80_EMAC_RST, regval); regval &= ~EMAC_RST_HRTFN; outp(EZ80_EMAC_RST, regval); +#endif - /* If no further xmits are pending, then cancel the TX timeout */ + /* Cancel any pending the TX timeout */ wd_cancel(priv->txtimeout); } - - /* Clean up the old Tx descriptor -- not really necessary */ - - txdesc->np = 0; - txdesc->pktsize = 0; - txdesc->stat = 0; - - nvdbg("New txhead=%p {%06x, %u, %04x} trp=%02x%02x istat=%02x\n", - priv->txhead, priv->txhead->np, priv->txhead->pktsize, priv->txhead->stat, - inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L), istat); return OK; }