changeset 3163:9b6d0c32e124

* cdl/eth_freescale_enet.cdl: * src/if_freescale_enet.c: Add Redboot ESA support [Bugzilla 1001450]
author vae
date Wed, 22 Feb 2012 21:23:30 +0000
parents 4e0edd9d9f18
children 37f8bded2ac7
files packages/devs/eth/freescale/enet/current/ChangeLog packages/devs/eth/freescale/enet/current/cdl/eth_freescale_enet.cdl packages/devs/eth/freescale/enet/current/src/if_freescale_enet.c
diffstat 3 files changed, 161 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/packages/devs/eth/freescale/enet/current/ChangeLog
+++ b/packages/devs/eth/freescale/enet/current/ChangeLog
@@ -1,3 +1,9 @@
+2012-01-06  Ilija Kocho  <ilijak@siva.com.mk>
+
+	* cdl/eth_freescale_enet.cdl:
+	* src/if_freescale_enet.c:
+	Add Redboot ESA support [Bugzilla 1001450]
+
 2011-08-26  Ilija Kocho  <ilijak@siva.com.mk>
 
 	* cdl/eth_freescale_enet.cdl:
--- a/packages/devs/eth/freescale/enet/current/cdl/eth_freescale_enet.cdl
+++ b/packages/devs/eth/freescale/enet/current/cdl/eth_freescale_enet.cdl
@@ -87,7 +87,7 @@ cdl_package CYGPKG_DEVS_ETH_FREESCALE_EN
     cdl_option CYGPKG_DEVS_ETH_FREESCALE_ENET0_INTPRIO {
         display       "Interrupt priority"
         flavor        data
-        default_value 0xE0
+        default_value CYGNUM_DEVS_ETH_FREESCALE_ENET0_INTPRIO_SP
         description   "
             This option selects the interrupt priority for the EMAC
             interrupts."
@@ -256,8 +256,8 @@ cdl_package CYGPKG_DEVS_ETH_FREESCALE_EN
 
     cdl_component CYGSEM_DEVS_ETH_FREESCALE_ENET_ACCEL {
         display "TCP/IP acceleration"
-        flavor bool
-        default_value { is_active (CYGPKG_LWIP_CHECKSUMS) ? 1 : 0 }
+        flavor none
+        no_define
         description "
             Freescale ENET provides for hardware TCP/IP header checksum
             generation and check."
@@ -389,6 +389,44 @@ cdl_package CYGPKG_DEVS_ETH_FREESCALE_EN
             problems disable fast IRQ mask."
     }
 
+    cdl_component CYGPKG_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA {
+        display         "RedBoot manages ESA initialization data"
+        flavor          bool
+        default_value   0
+
+        active_if     CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
+        active_if     (CYGPKG_REDBOOT || CYGSEM_HAL_USE_ROM_MONITOR)
+
+        description   "
+            Enabling this option will allow the ethernet station
+            address to be acquired from RedBoot's configuration data,
+            stored in flash memory.  It can be overridden individually
+            by the 'Set the ethernet station address' option for each
+            interface."
+
+
+        cdl_component CYGPKG_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA_VARS {
+            display        "Export RedBoot command to set ESA in FLASH config"
+            flavor         none
+            no_define
+            description "
+                This component contains options which, when enabled, allow
+                RedBoot to support the setting of the ESA in the FLASH
+                configuration. This can then subsequently be accessed by
+                applications using virtual vector calls if those applications
+                are also built with
+                CYGPKG_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA enabled."
+
+            cdl_option CYGSEM_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA_ETH0 {
+                display         "RedBoot manages ESA for eth0"
+                flavor          bool
+                default_value   1
+                active_if       CYGSEM_REDBOOT_FLASH_CONFIG
+                active_if       CYGPKG_REDBOOT_NETWORKING
+            }
+        }
+    }
+    
     cdl_option CYGPKG_DEVS_ETH_FREESCALE_ENET_DEBUG_LEVEL {
          display "Driver debug output level"
          flavor  data
--- a/packages/devs/eth/freescale/enet/current/src/if_freescale_enet.c
+++ b/packages/devs/eth/freescale/enet/current/src/if_freescale_enet.c
@@ -243,6 +243,39 @@ CYG_MACRO_END
 
 #endif // CYGOPT_DEVS_ETH_FREESCALE_ENET_STATS
 
+// --------------------------------------------------------------
+// RedBoot configuration options for managing ESAs for us
+
+// Decide whether to have redboot config vars for it...
+#if defined(CYGSEM_REDBOOT_FLASH_CONFIG) && defined(CYGPKG_REDBOOT_NETWORKING)
+#include <redboot.h>
+#include <flash_config.h>
+
+#ifdef CYGSEM_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA_ETH0
+RedBoot_config_option("Network hardware address [MAC] for eth0",
+                      eth0_esa_data,
+                      ALWAYS_ENABLED, true,
+                      CONFIG_ESA, 0);
+#endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA_ETH0
+#endif  // CYGPKG_REDBOOT_NETWORKING && CYGSEM_REDBOOT_FLASH_CONFIG
+
+// and initialization code to read them
+// - independent of whether we are building RedBoot right now:
+#ifdef CYGPKG_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA
+#include <cyg/hal/hal_if.h>
+#ifndef CONFIG_ESA
+    #define CONFIG_ESA (6)
+#endif
+
+#define CYGHWR_DEVS_ETH_FREESCALE_ENET_GET_ESA( mac_address, ok )        \
+  CYG_MACRO_START                                                     \
+  ok = CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,     \
+                                    "eth0_esa_data",                  \
+                                    mac_address,                      \
+                                    CONFIG_ESA);                      \
+  CYG_MACRO_END
+#endif // CYGPKG_DEVS_ETH_FREESCALE_ENET_REDBOOT_HOLDS_ESA
+
 
 // ENET device ===============================================================
 // Freescale ENET driver private data ----------------------------------------
@@ -571,7 +604,7 @@ enet_init_bd(enet_bd_t *bd_p, cyg_uint32
         bd_p->ebd_ctrl = ebd_ctrl;
         bd_p->hlen_proto = 0;
         bd_p->payload_csum = 0;
-        bd_p->bdu = 0;
+        bd_p->bdu = ENET_TXBD_BDU;
         bd_p->timestamp_1588 = 0;
         bd_p->reserved[0] = 0;
         bd_p->reserved[1] = 0;
@@ -698,7 +731,9 @@ enet_eth_init(struct cyg_netdevtab_entry
     freescale_enet_priv_t *enet_priv_p =
           (freescale_enet_priv_t *) sc->driver_private;
     CYG_ADDRWORD enet_base = enet_priv_p->enet_base;
-
+#ifdef CYGHWR_DEVS_ETH_FREESCALE_ENET_GET_ESA
+    bool esa_ok = false;
+#endif
     enet_cfg_pins(enet_priv_p);
 
     HAL_WRITE_UINT32(enet_base + FREESCALE_ENET_REG_EIMR, 0);
@@ -736,6 +771,16 @@ enet_eth_init(struct cyg_netdevtab_entry
 # endif // CYGOPT_ETH_FREESCALE_ENET_TX_NOCOPY
 #endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
 
+#ifdef CYGHWR_DEVS_ETH_FREESCALE_ENET_GET_ESA
+    // Get MAC address from RedBoot configuration variables
+    CYGHWR_DEVS_ETH_FREESCALE_ENET_GET_ESA(&enet_priv_p->enaddr[0], esa_ok);
+    // If this call fails myMacAddr is unchanged and MAC address from
+    // CDL is used
+    if (!esa_ok) {
+       // Can't figure out ESA
+       debug1_printf("Freescale ENET - Warning! ESA unknown\n");
+    }
+#endif
     // Set the source address for the controller
     enet_set_mac_addr (enet_base, enet_priv_p->enaddr);
 
@@ -918,7 +963,7 @@ enet_eth_can_send(struct eth_drv_sc *sc)
     enet_bd_t *tx_bd_p = enet_priv_p->txbd_head_p;
 
     ENET_TXBD_NEXT(tx_bd_p, enet_priv_p);
-    debug2_printf("ENET: can send: %d\n", tx_bd_p->ctrl & ENET_TXBD_R);
+    debug2_printf("ENET: can send: %d\n", !(tx_bd_p->ctrl & ENET_TXBD_R));
     if(!(tx_bd_p->ctrl & ENET_TXBD_R))
         return 1;
     else
@@ -933,16 +978,20 @@ enet_eth_can_send(struct eth_drv_sc *sc)
 static void inline
 enet_eth_send_trigger(freescale_enet_priv_t *enet_priv_p)
 {
-    //  Inform ENET that transmit descriptor(s) is(are) available.
-    HAL_WRITE_UINT32(enet_priv_p->enet_base + FREESCALE_ENET_REG_TDAR,
-                     FREESCALE_ENET_TDAR_TDAR_M);
+    cyg_uint32 tdar;
+
+    do {
+        HAL_READ_UINT32(enet_priv_p->enet_base + FREESCALE_ENET_REG_TDAR, tdar);
+    } while(tdar & FREESCALE_ENET_TDAR_TDAR_M);
+    tdar = FREESCALE_ENET_TDAR_TDAR_M;
+    HAL_WRITE_UINT32(enet_priv_p->enet_base + FREESCALE_ENET_REG_TDAR, tdar);
 }
 
-#define ENET_ETH_SEND_RDY(__bd_p) \
+#define ENET_ETH_SEND_RDY(__bd_p,_ad_flag) \
 CYG_MACRO_START \
     cyg_uint16 ctrl; \
     ctrl = __bd_p->ctrl & ENET_TXBD_W; \
-    ctrl |= ENET_TXBD_R | ENET_TXBD_TC; \
+    ctrl |= ENET_TXBD_R | ENET_TXBD_TC | (_ad_flag); \
     __bd_p->ctrl = ctrl; \
 CYG_MACRO_END
 
@@ -970,30 +1019,32 @@ enet_eth_send_nocopy(struct eth_drv_sc *
         (sc->funs->eth_drv->tx_done)(sc, key, 0);
         return;
     }
-#if DEBUG_ENET >= 2
-    if(enet_priv_p->txbd_avail < 2) {
-        diag_printf("ENET Send: sg_len %d avail %d\n", sg_len, enet_priv_p->txbd_avail);
-    }
-#endif
+    debug3_printf("ENET Send: sg_len %d avail %d\n", sg_len, enet_priv_p->txbd_avail);
     tx_bd_p=enet_priv_p->txbd_head_p;
     for(sg_list_z=sg_list+sg_len; sg_list<sg_list_z; sg_list++) {
         ENET_TXBD_ALLOC(tx_bd_p, enet_priv_p);
         tx_bd_p->buffer_p=(cyg_uint8 *)CYG_CPU_TO_BE32(sg_list->buf);
         tx_bd_p->len=CYG_CPU_TO_BE16(sg_list->len);
+# ifdef CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
+        tx_bd_p->bdu = 0;
+# endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
         if(tx_bd0_p) {
-            ENET_ETH_SEND_RDY(tx_bd_p);
+            ENET_ETH_SEND_RDY(tx_bd_p, 0);
         } else {
             tx_bd0_p=tx_bd_p;
         }
-# ifdef CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
-        tx_bd_p->bdu = 0;
-# endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
     }
-    ENET_ETH_SEND_RDY(tx_bd0_p);
-    tx_bd_p->ctrl |= (ENET_TXBD_L | ENET_TXKEY_FLAG); // is last and has key
     tx_key_p=enet_priv_p->txkey_head_p;
     *tx_key_p = key;
     ENET_TXKEY_NEXT(tx_key_p, enet_priv_p);
+    if(tx_bd_p != tx_bd0_p) {
+        debug3_printf("ENET Send2: Key[%p] = 0x%x\n", tx_key_p, key);
+        tx_bd_p->ctrl |= (ENET_TXBD_L | ENET_TXKEY_FLAG); // is last and has key
+        ENET_ETH_SEND_RDY(tx_bd0_p, 0);
+    } else {
+        debug3_printf("ENET Send1: Key[%p] = 0x%x\n", tx_key_p, key);
+        ENET_ETH_SEND_RDY(tx_bd0_p, ENET_TXBD_L | ENET_TXKEY_FLAG);
+    }
     enet_priv_p->txkey_head_p = tx_key_p;
     enet_priv_p->txbd_head_p = tx_bd_p;
     enet_eth_send_trigger(enet_priv_p);
@@ -1014,45 +1065,43 @@ enet_eth_send_copying(struct eth_drv_sc 
     freescale_enet_priv_t *enet_priv_p =
           (freescale_enet_priv_t *)sc->driver_private;
     enet_bd_t *tx_bd_p;
-    enet_bd_t *tx_bd_save_p;
     struct eth_drv_sg *sg_list_z;
     cyg_uint16 ctrl;
+    cyg_uint8* txbuf_p;
+    cyg_uint32 txbuf_k;
+    enet_bd_t *tx_bd_save_p;
 
     tx_bd_p=enet_priv_p->txbd_head_p;
-    debug2_printf("ENET Send: sg_len %d\n", sg_len);
+# ifdef CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
+    while(!(tx_bd_p->bdu & ENET_TXBD_BDU)){
+        debug1_printf("ENET Send: Waiting for BDU %p\n", tx_bd_p);
+    }
+# endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
+    debug2_printf("ENET Send: sg_len %d total_len %d\n", sg_len, total_len);
+    tx_bd_save_p=tx_bd_p;
+    ENET_TXBD_NEXT(tx_bd_p, enet_priv_p);
+    txbuf_p = (cyg_uint8 *)CYG_CPU_TO_BE32((cyg_uint32)tx_bd_p->buffer_p);
+    txbuf_k = 0;
     for(sg_list_z=sg_list+sg_len; sg_list<sg_list_z; sg_list++) {
-        debug2_printf("ENET: Sending sg\n");
-        tx_bd_save_p=tx_bd_p;
-        ENET_TXBD_NEXT(tx_bd_p, enet_priv_p);
-
-        if(tx_bd_p->ctrl & ENET_TXBD_R) {
-            debug2_printf("ENET: Send underrun, waiting for free buf.\n");
-            enet_eth_send_trigger(enet_priv_p);
-            ENET_ETH_WAIT(1);
-            if(tx_bd_p->ctrl & ENET_TXBD_R) {
-                ENET_ETH_WAIT(1);
-                if(tx_bd_p->ctrl & ENET_TXBD_R) {
-                    debug2_printf("ENET Send: aborting packet.\n");
-                    enet_priv_p->txbd_head_p = tx_bd_save_p;
-                    (sc->funs->eth_drv->tx_done)(sc, key, 0);
-                    return;
-                }
-            }
+        if((txbuf_k += sg_list->len) > enet_priv_p->txbuf_size) {
+            debug1_printf("ENET Send: Buffer overflow: %d (max = %d)\n", txbuf_k,
+                          enet_priv_p->txbuf_size);
+            enet_priv_p->txbd_head_p = tx_bd_save_p;
+            (sc->funs->eth_drv->tx_done)(sc, key, 0);
+            return;
         }
-
-        memcpy((cyg_uint8 *)CYG_CPU_TO_BE32((cyg_uint32)tx_bd_p->buffer_p),
-               (void *)sg_list->buf, sg_list->len);
-        tx_bd_p->len=CYG_CPU_TO_BE16(sg_list->len);
-        ctrl = tx_bd_p->ctrl & ENET_TXBD_W;
-        ctrl |= ENET_TXBD_R | ENET_TXBD_TC;
-        tx_bd_p->ctrl = ctrl;
+        memcpy(txbuf_p, (cyg_uint8 *)sg_list->buf, sg_list->len);
+        txbuf_p += sg_list->len;
+    }
+    tx_bd_p->len=CYG_CPU_TO_BE16(total_len);
+    ctrl = tx_bd_p->ctrl & ENET_TXBD_W;
+    ctrl |= ENET_TXBD_R | ENET_TXBD_TC | ENET_TXBD_L;
 # ifdef CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
-        tx_bd_p->bdu = 0;
+    tx_bd_p->bdu = 0;
 # endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
-    }
-    tx_bd_p->ctrl |= (ENET_TXBD_L); // is last
+    tx_bd_p->ctrl = ctrl;
     enet_priv_p->txbd_head_p = tx_bd_p;
-    debug2_printf("ENET Send: trigger.\n");
+    debug2_printf("ENET Send: trigger, done.\n");
     enet_eth_send_trigger(enet_priv_p);
     (sc->funs->eth_drv->tx_done)(sc, key, 0);
 }
@@ -1070,11 +1119,12 @@ enet_eth_recv(struct eth_drv_sc *sc, str
     struct eth_drv_sg *sg_list_z;
     enet_bd_t *rx_bd_p;
 
+    debug3_printf("ENET recv: sg_len=%d first len=%d\n", sg_len, sg_list->len);
     rx_bd_p=enet_priv_p->rxbd_p;
     rxbuffer_p=(cyg_uint8 *)CYG_CPU_TO_BE32((cyg_uint32)rx_bd_p->buffer_p);
     for(sg_list_z=sg_list+sg_len; sg_list<sg_list_z; sg_list++) {
         if(sg_list->buf) {
-            memcpy((void *)sg_list->buf, rxbuffer_p, sg_list->len);
+            memcpy((cyg_uint8 *)sg_list->buf, rxbuffer_p, sg_list->len);
             rxbuffer_p+=sg_list->len;
         }
     }
@@ -1199,7 +1249,7 @@ enet_eth_deliver_nocopy(struct eth_drv_s
 
     tx_bd_tail_p = enet_priv_p->txbd_tail_p;
     HAL_READ_UINT32(enet_base + FREESCALE_ENET_REG_EIR, eir);
-    need_service = ENET_DELIVER_NEED_SERVICE;
+    need_service = eir & ENET_DELIVER_NEED_SERVICE;
     do {
         //Clear all ENET Interrupt events
         HAL_WRITE_UINT32(enet_base + FREESCALE_ENET_REG_EIR,
@@ -1256,12 +1306,19 @@ enet_eth_deliver_nocopy(struct eth_drv_s
                 } else {
                     ENET_BD_AVAIL_INC(enet_priv_p);
                     if(ctrl & ENET_TXKEY_FLAG){
+# ifdef CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
+                        while(!(tx_bd_tail_p->bdu & ENET_TXBD_BDU)){
+                            debug1_printf("ENET Send: Waiting for BDU %p\n", tx_bd_tail_p);
+                        }
+# endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
+                        tx_key_tail_p = enet_priv_p->txkey_tail_p;
+                        debug3_printf("ENET Deliver: Key[%p] = 0x%x\n",
+                                      tx_key_tail_p, *tx_key_tail_p);
+                        ENET_TXKEY_NEXT(tx_key_tail_p, enet_priv_p);
+                        enet_priv_p->txkey_tail_p = tx_key_tail_p;
                         ctrl &= ~ENET_TXKEY_FLAG;
                         tx_bd_tail_p->ctrl = ctrl;
-                        tx_key_tail_p = enet_priv_p->txkey_tail_p;
                         (tx_done)(sc, *tx_key_tail_p, 0);
-                        ENET_TXKEY_NEXT(tx_key_tail_p, enet_priv_p);
-                        enet_priv_p->txkey_tail_p = tx_key_tail_p;
                     }
                     if(enet_priv_p->txbd_avail == enet_priv_p->txbd_num) {
                         debug3_printf("ENET: Tx All sent.\n");
@@ -1275,6 +1332,7 @@ enet_eth_deliver_nocopy(struct eth_drv_s
         HAL_READ_UINT32(enet_base + FREESCALE_ENET_REG_EIR, eir);
         need_service |= eir & ENET_DELIVER_NEED_SERVICE;
     } while(need_service);
+    debug3_printf("ENET: Delivered.\n");
     enet_priv_p->txbd_tail_p = tx_bd_tail_p;
 # ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED
 #  ifdef CYGOPT_DEVS_ETH_FREESCALE_ENET_IRQ_FASTMASK
@@ -1307,7 +1365,7 @@ enet_eth_deliver_copying(struct eth_drv_
 
     recv = sc->funs->eth_drv->recv;
     HAL_READ_UINT32(enet_base + FREESCALE_ENET_REG_EIR, eir);
-    need_service = ENET_DELIVER_NEED_SERVICE;
+    need_service = eir & ENET_DELIVER_NEED_SERVICE;
     do {
         //Clear all ENET Interrupt events
         HAL_WRITE_UINT32(enet_base + FREESCALE_ENET_REG_EIR,
@@ -1335,7 +1393,7 @@ enet_eth_deliver_copying(struct eth_drv_
 # ifdef  CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
                 rx_bd_p->bdu = 0;
 # endif // CYGSEM_DEVS_ETH_FREESCALE_ENET_BD_ENHANCED
-                // Inform ENET that free Rx buffers have beeen freed.
+                // Inform ENET that Rx buffers have been freed.
                 HAL_WRITE_UINT32(enet_priv_p->enet_base +
                                  FREESCALE_ENET_REG_RDAR,
                                  FREESCALE_ENET_RDAR_RDAR_M);