Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/arm/at91/current/ChangeLog,v
retrieving revision 1.3
diff -u -r1.3 ChangeLog
--- ChangeLog	9 Apr 2007 12:59:30 -0000	1.3
+++ ChangeLog	2 Sep 2008 16:06:19 -0000
@@ -1,3 +1,12 @@
+2008-09-02  John Eigelaar  <jeigelaar@mweb.co.za>
+
+	* src/if_at91.c: Added handling of RX Errors.
+	  Added partial handling of TX Errors.
+	  Added a temporary fix to limit the amount of time spent in 
+	  the loops clearing the receive buffers. 
+	  Fixed a bug in the receive function for unpacking the receive buffers
+	  into the driver sg_list.
+
 2007-04-08  Uwe Kindler  <uwe_kindler@web.de>
 
 	* cdl/at91_eth.cdl: Fixed typo. (Removed AT91RM9200 from
Index: src/if_at91.c
===================================================================
RCS file: /cvs/ecos/ecos/packages/devs/eth/arm/at91/current/src/if_at91.c,v
retrieving revision 1.2
diff -u -r1.2 if_at91.c
--- src/if_at91.c	23 Mar 2007 19:02:09 -0000	1.2
+++ src/if_at91.c	2 Sep 2008 16:06:21 -0000
@@ -505,10 +505,6 @@
    /* Enable  IO Clock */
    HAL_WRITE_UINT32(priv->base+AT91_EMAC_USRIO,AT91_EMAC_USRIO_CLKEN);
 
-   /* Disable all the interrupts for the moment            */
-   /* The Start function actually enables all that we need */
-   //HAL_WRITE_UINT32(priv->base + AT91_EMAC_IDR, 0x3FFF);
-
    // If we are building an interrupt enabled version, install the
    // interrupt handler
 #ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
@@ -564,12 +560,15 @@
    CYG_ASSERTC(priv->phy);
 
    at91_mdio_enable();
+   debug1_printf("AT91_ETH: Initialising PHY\n");
    if (!_eth_phy_init(priv->phy))
    {
+      debug1_printf("AT91_ETH: PHY Init ERROR\n");
       at91_mdio_disable();
       return (false);
    }
 
+   debug1_printf("AT91_ETH: PHY Initialised\n");
    // Get the current mode and print it
    phy_state = _eth_phy_state(priv->phy);
    at91_mdio_disable();
@@ -646,9 +645,9 @@
    cyg_uint32 bits;
 
    // Enable the interrupts we are interested in
-   // TODO: We probably need to add at least the RBNA interrupt here
-   //       as well in order to do some error handling
-   bits = (AT91_EMAC_ISR_RCOM | AT91_EMAC_ISR_TCOM);
+   // TODO: We have added some Receive Error interrupts now but the transmit
+   //       errors still remaan unresolved
+   bits = (AT91_EMAC_ISR_RCOM | AT91_EMAC_ISR_RBNA | AT91_EMAC_ISR_ROVR | AT91_EMAC_ISR_TCOM | AT91_EMAC_ISR_RTRY);
 
    HAL_WRITE_UINT32(priv->base + AT91_EMAC_IER, bits);
 
@@ -794,13 +793,17 @@
 
    ret = CYG_ISR_HANDLED;
 
-   //TODO: We should probably be handling some of the error interrupts as well
+   //All the transmit errors that affects 
+   //the way in which we drive the upper layer ethernet driver
+   //is signalled through TCOM
+   // TODO: Handling for buffer related (under/overrun) erros
    if(isr & AT91_EMAC_ISR_TCOM)
    {
       ret = CYG_ISR_CALL_DSR;
    }
 
-   if(isr & AT91_EMAC_ISR_RCOM)
+   //We handle the buffer related receive errors now
+   if(isr & (AT91_EMAC_ISR_RCOM|AT91_EMAC_ISR_RBNA|AT91_EMAC_ISR_ROVR))
    {
       ret = CYG_ISR_CALL_DSR;
    }
@@ -820,6 +823,9 @@
    cyg_uint32 ctr;
    cyg_uint32 cnt;
    cyg_uint32 idx;
+   cyg_uint32 recv_ctr;
+
+
 
    /* Get the Transmit Status */
    HAL_READ_UINT32(priv->base+AT91_EMAC_TSR,tsr);
@@ -830,21 +836,15 @@
    HAL_WRITE_UINT32(priv->base+AT91_EMAC_RSR,rsr);
 
 
-   //TODO: The interrupts other than RCOMP and TCOMP needs to be
-   //      handled properly especially stuff like RBNA which could have
-   //      serious effects on driver performance
-
-   /* Service the TX buffers */
+   /* The COL interrupt does not add any value 
+      in terms of driver management as it only signifies the start
+      of the next TX retry */
    if (tsr&AT91_EMAC_TSR_COL)  //1
    {
       debug1_printf("AT91_ETH: Tx COL\n");
    }
 
-   if (tsr&AT91_EMAC_TSR_RLE)  //2
-   {
-      debug1_printf("AT91_ETH: Tx RLE\n");
-   }
-
+   //TODO: Proper handling of these two buffer errors
    if (tsr&AT91_EMAC_TSR_BNQ)  //4
    {
       debug1_printf("AT91_ETH: Tx BEX\n");
@@ -856,42 +856,100 @@
    }
 
    /* Check that the last transmission is completed */
+   /* From ther eth_drv code ther does not seem to be any
+      distinction between a succesfull and a failed transmission */
    if (tsr&AT91_EMAC_TSR_COMP) //5
    {
+      /* Normal completion */
       at91_reset_tbd(priv);
       _eth_drv_tx_done(sc,priv->curr_tx_key,0);
       priv->tx_busy = false;
    }
+   else if (tsr&AT91_EMAC_TSR_RLE)  //2
+   {
+      /* Failed Completion */
+      at91_reset_tbd(priv);
+      _eth_drv_tx_done(sc,priv->curr_tx_key,0);
+      priv->tx_busy = false;
+   }
+
+   /* First check for the serious receive errors and take appropriate action*/
+   if(rsr&(AT91_EMAC_RSR_BNA|AT91_EMAC_RSR_OVR))
+   {
+
+      /* We stop the receiver, reset and clear all the rx buffer and start the shoe again*/
+      at91_disable_rx(priv);
+     at91_rb_init(priv);
+     // And tell the EMAC where the first receive buffer descriptor is
+     HAL_WRITE_UINT32(priv->base + AT91_EMAC_RBQP, (cyg_uint32)priv->rbd);
+     if(rsr&AT91_EMAC_RSR_BNA)
+        debug1_printf("AT91_ETH: RBNA\n");
+     if(rsr&AT91_EMAC_RSR_OVR)
+        debug1_printf("AT91_ETH: ROVR\n");
+
+     priv->curr_rbd_idx = 0;
 
-   /* Service the RX buffers when we get something */
-   if (rsr&AT91_EMAC_RSR_REC)
+     at91_enable_rx(priv);
+   }
+
+   /* Service the RX buffers when we get something and no errors ocurred*/
+   else if (rsr&AT91_EMAC_RSR_REC)
    {
+
+      recv_ctr = 0;
+
       /* Do this all until we find the first EMAC Buffer */
       while (priv->rbd[priv->curr_rbd_idx].addr & AT91_EMAC_RBD_ADDR_OWNER_SW)
       {
 
+         recv_ctr++;
          //Firstly walk through to either the first buffer that belongs 
          // to the controller or the first SOF
-         while ((priv->rbd[priv->curr_rbd_idx].addr & 
-		 AT91_EMAC_RBD_ADDR_OWNER_SW) && 
-                !(priv->rbd[priv->curr_rbd_idx].sr & 
-		  AT91_EMAC_RBD_SR_SOF))
+         ctr = 0;
+         while ((priv->rbd[priv->curr_rbd_idx].addr & AT91_EMAC_RBD_ADDR_OWNER_SW) 
+                && !(priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_SOF))
          {
-            priv->rbd[priv->curr_rbd_idx].addr &= 
-	      ~(AT91_EMAC_RBD_ADDR_OWNER_SW);
+            priv->rbd[priv->curr_rbd_idx].addr &= ~(AT91_EMAC_RBD_ADDR_OWNER_SW);
+
             priv->curr_rbd_idx++;
             if (priv->curr_rbd_idx >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
             {
                priv->curr_rbd_idx = 0;
             }
+
+            /* If we haven't found anything in all of the buffers something horrible 
+               has happened and we better get out and reset the receive show */
+            ctr++;
+            if(ctr >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
+            {
+               break;
+            }
+         }
+
+         if(ctr >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
+         {
+            /* We could not find a SOF or a controller owned buffer in all the buffers so ... */
+            /* Do the same as for the other RX error interrupts */
+            /* We stop the receiver, reset and clear all the rx buffer and start the shoe again*/
+
+            at91_disable_rx(priv);
+            at91_rb_init(priv);
+
+            /* And tell the EMAC where the first receive buffer descriptor is */
+            HAL_WRITE_UINT32(priv->base + AT91_EMAC_RBQP, (cyg_uint32)priv->rbd);
+            priv->curr_rbd_idx = 0;
+
+            debug1_printf("AT91_ETH: RX Sync ERRROR\n");
+            at91_enable_rx(priv);
+            break;
          }
 
          /* Check that we did find a SOF*/
-         if ((priv->rbd[priv->curr_rbd_idx].addr & 
-	      AT91_EMAC_RBD_ADDR_OWNER_SW) && 
-             (priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_SOF))
+         else if ((priv->rbd[priv->curr_rbd_idx].addr & AT91_EMAC_RBD_ADDR_OWNER_SW) 
+             && (priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_SOF))
          {
             cnt = 0;
+
             for (ctr=0;ctr<CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS;ctr++)
             {
                idx = (ctr+priv->curr_rbd_idx)%CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS;
@@ -902,21 +960,45 @@
                      after the buffer has been cleared
                    */
                   if (cnt)
+                  {
                      _eth_drv_recv(sc,cnt);
+                  }
                   break;
                }
             }
          }
+
+
+         if(recv_ctr >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
+         {
+
+            // We have now looped through all the buffers and still we are not done
+            // Now we say what da ...
+            // and try and reset the show
+            
+            //TODO: Somehow this trick does not work at this point in the show.
+            //      It seems that a reset of the Receiver now puts the EMAC into some
+            //      unrecoverable state where it no longer works. I haven't had time yet 
+            //      to look into the actual state of the RBDs when we are here and what the actual 
+            //      cause might be.
+
+            debug1_printf("AT91_ETH: RX Loop OVR\n");
+#if 0
+            at91_disable_rx(priv);
+            at91_rb_init(priv);
+
+            /* And tell the EMAC where the first receive buffer descriptor is */
+            HAL_WRITE_UINT32(priv->base + AT91_EMAC_RBQP, (cyg_uint32)priv->rbd);
+            priv->curr_rbd_idx = 0;
+
+            at91_enable_rx(priv);
+            break;
+#endif 
+         }   
+
       }
-   }
 
-   if (rsr&AT91_EMAC_RSR_BNA)
-   {
-      debug1_printf("AT91_ETH: Rx BNA\n");
-   }
-   if (rsr&AT91_EMAC_RSR_OVR)
-   {
-      debug1_printf("AT91_ETH: Rx OVR\n");
+
    }
 
 }
@@ -935,6 +1017,8 @@
    cyg_uint8 * sg_buf;
    cyg_uint32 total_bytes = 0;
 
+   total_bytes = 0;
+
    for(i = 0;i<sg_len;i++)
    {
       while(bytes_in_list < sg_list[i].len)
@@ -943,9 +1027,7 @@
 
          if(priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_EOF)
          {
-	      bytes_in_buffer = 
-		((priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_LEN_MASK)
-		 - total_bytes) - buffer_pos;
+	      bytes_in_buffer = ((priv->rbd[priv->curr_rbd_idx].sr & AT91_EMAC_RBD_SR_LEN_MASK) - total_bytes) - buffer_pos;
          }
          else
          {
@@ -957,9 +1039,8 @@
          if(bytes_needed_list < bytes_in_buffer)
          {
             if(sg_buf != NULL)
-               memcpy(&sg_buf[bytes_in_list],
-		      &priv->rb[priv->curr_rbd_idx].rb[buffer_pos],
-		      bytes_needed_list);
+               memcpy(&sg_buf[bytes_in_list],&priv->rb[priv->curr_rbd_idx].rb[buffer_pos],bytes_needed_list);
+
             bytes_in_list += bytes_needed_list;
             buffer_pos += bytes_needed_list;
             total_bytes += bytes_needed_list;
@@ -967,15 +1048,14 @@
          else
          {
             if(sg_buf != NULL)
-              memcpy(&sg_buf[bytes_in_list],
-		     &priv->rb[priv->curr_rbd_idx].rb[buffer_pos],
-		     bytes_in_buffer);
+              memcpy(&sg_buf[bytes_in_list],&priv->rb[priv->curr_rbd_idx].rb[buffer_pos],bytes_in_buffer);
+
+
             bytes_in_list += bytes_in_buffer;
             total_bytes += bytes_in_buffer;
 
             /* Step our buffer on one */
-            priv->rbd[priv->curr_rbd_idx].addr &= 
-	      ~(AT91_EMAC_RBD_ADDR_OWNER_SW);
+            priv->rbd[priv->curr_rbd_idx].addr &= ~(AT91_EMAC_RBD_ADDR_OWNER_SW);
             priv->curr_rbd_idx++;
             if(priv->curr_rbd_idx >= CYGNUM_DEVS_ETH_ARM_AT91_RX_BUFS)
             {
@@ -984,6 +1064,9 @@
             buffer_pos = 0;
          }
       }
+      /* We have filled this sg buffer 
+         Now reset the variables to move on */
+      bytes_in_list = 0;
    }
 }
 
