public inbox for ecos-patches@sourceware.org
 help / color / mirror / Atom feed
* Updates for the AT91 EMAC driver
@ 2008-09-02 16:28 John Eigelaar
  0 siblings, 0 replies; 2+ messages in thread
From: John Eigelaar @ 2008-09-02 16:28 UTC (permalink / raw)
  To: Ecos-Patches

[-- Attachment #1: Type: text/plain, Size: 1313 bytes --]

Hi all,

This patch adds all the little fixes and tweaks  that I have made to this
driver over the last year. 

In a nutshell I have added support for the RX error interrupts as well as
the none buffer related TX error interrupts.
I thought that since the driver only transmits one frame at a time in its
current implementation that the under/over run interrupts
could be ignored for now.
I have also fixed a small bug in the receive function that cause the driver
to hang in an infinite loop when the sg_list buffers were bigger 
than the driver receive buffers.

There still remains a very nasty bug in the eth_deliver/DSR function. The
RBD handling of this function sometimes gets it wrong and 
Then hangs in an infinite loop while trying to find a SOF or the first non
software owned Receive buffer. I have added a quick fix kludge to
Try and clear out of the loop after it has cycled through all the buffers at
least once. At the moment I have run out of time to spend on the driver
though.

We are much closer to a real driver but it is still not there yet.

Apologies for not generating the patch from the packages directory, I
somehow stuffed up the cvs tree 
and was only able to do the diff from the drivers' current directory
(packages/devs/eth/arm/at91/current/) .  
 
Happy Hacking
John Eigelaar 

	

[-- Attachment #2: at91_eth.patch --]
[-- Type: application/octet-stream, Size: 12185 bytes --]

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;
    }
 }
 

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Updates for the AT91 EMAC driver
@ 2008-09-03  9:25 Jürgen Lambrecht
  0 siblings, 0 replies; 2+ messages in thread
From: Jürgen Lambrecht @ 2008-09-03  9:25 UTC (permalink / raw)
  To: Andrew Lunn, John Eigelaar; +Cc: ecos-patches

Hello John and Andrew,

I just received the ecos-patches-digest.

I will look at John's patch.
I will also try to make time to mail my patch. But for the moment my old 
pc (the only one with ecos cvs access) has crashed..
We'll see.

Kind regards,
Jürgen

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2008-09-03  9:25 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-09-02 16:28 Updates for the AT91 EMAC driver John Eigelaar
2008-09-03  9:25 Jürgen Lambrecht

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).