]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - net/eth.c
imported U-Boot Release 2009.08 from Freescale BSP L2.6.31_10.08.01
[karo-tx-uboot.git] / net / eth.c
index e8ac251a4fee0c6945fe40e36ba135511d6249d8..9b503124fb637dea1accad08f890c4b5d1a25c11 100755 (executable)
--- a/net/eth.c
+++ b/net/eth.c
 #include <net.h>
 #include <miiphy.h>
 
-#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI)
+#ifdef CONFIG_CMD_NET
+void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+{
+       char *end;
+       int i;
+
+       for (i = 0; i < 6; ++i) {
+               enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
+               if (addr)
+                       addr = (*end) ? end + 1 : end;
+       }
+}
+
+int eth_getenv_enetaddr(char *name, uchar *enetaddr)
+{
+       eth_parse_enetaddr(getenv(name), enetaddr);
+       return is_valid_ether_addr(enetaddr);
+}
+
+int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
+{
+       char buf[20];
+
+       sprintf(buf, "%pM", enetaddr);
 
-#ifdef CFG_GT_6426x
-extern int gt6426x_eth_initialize(bd_t *bis);
+       return setenv(name, buf);
+}
+
+int eth_getenv_enetaddr_by_index(int index, uchar *enetaddr)
+{
+       char enetvar[32];
+       sprintf(enetvar, index ? "eth%daddr" : "ethaddr", index);
+       return eth_getenv_enetaddr(enetvar, enetaddr);
+}
 #endif
 
-extern int au1x00_enet_initialize(bd_t*);
-extern int dc21x4x_initialize(bd_t*);
-extern int e1000_initialize(bd_t*);
-extern int eepro100_initialize(bd_t*);
-extern int eth_3com_initialize(bd_t*);
-extern int fec_initialize(bd_t*);
-extern int inca_switch_initialize(bd_t*);
-extern int mpc5xxx_fec_initialize(bd_t*);
-extern int mpc8220_fec_initialize(bd_t*);
+#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI)
+
+/*
+ * CPU and board-specific Ethernet initializations.  Aliased function
+ * signals caller to move on
+ */
+static int __def_eth_init(bd_t *bis)
+{
+       return -1;
+}
+int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
+
 extern int mv6436x_eth_initialize(bd_t *);
 extern int mv6446x_eth_initialize(bd_t *);
-extern int natsemi_initialize(bd_t*);
-extern int ns8382x_initialize(bd_t*);
-extern int pcnet_initialize(bd_t*);
-extern int plb2800_eth_initialize(bd_t*);
-extern int ppc_4xx_eth_initialize(bd_t *);
-extern int rtl8139_initialize(bd_t*);
-extern int rtl8169_initialize(bd_t*);
-extern int scc_initialize(bd_t*);
-extern int skge_initialize(bd_t*);
-extern int tsec_initialize(bd_t*, int, char *);
-extern int npe_initialize(bd_t *);
+
+#ifdef CONFIG_API
+extern void (*push_packet)(volatile void *, int);
+
+static struct {
+       uchar data[PKTSIZE];
+       int length;
+} eth_rcv_bufs[PKTBUFSRX];
+
+static unsigned int eth_rcv_current = 0, eth_rcv_last = 0;
+#endif
 
 static struct eth_device *eth_devices, *eth_current;
 
@@ -82,6 +116,28 @@ struct eth_device *eth_get_dev_by_name(char *devname)
        return target_dev;
 }
 
+struct eth_device *eth_get_dev_by_index(int index)
+{
+       struct eth_device *dev, *target_dev;
+       int idx = 0;
+
+       if (!eth_devices)
+               return NULL;
+
+       dev = eth_devices;
+       target_dev = NULL;
+       do {
+               if (idx == index) {
+                       target_dev = dev;
+                       break;
+               }
+               dev = dev->next;
+               idx++;
+       } while (dev != eth_devices);
+
+       return target_dev;
+}
+
 int eth_get_dev_index (void)
 {
        struct eth_device *dev;
@@ -131,133 +187,35 @@ int eth_register(struct eth_device* dev)
 
 int eth_initialize(bd_t *bis)
 {
-       char enetvar[32], env_enetaddr[6];
-       int i, eth_number = 0;
-       char *tmp, *end;
+       unsigned char env_enetaddr[6];
+       int eth_number = 0;
 
        eth_devices = NULL;
        eth_current = NULL;
 
-#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+       show_boot_progress (64);
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
        miiphy_init();
 #endif
+       /* Try board-specific initialization first.  If it fails or isn't
+        * present, try the cpu-specific initialization */
+       if (board_eth_init(bis) < 0)
+               cpu_eth_init(bis);
 
-#ifdef CONFIG_DB64360
-       mv6436x_eth_initialize(bis);
-#endif
-#ifdef CONFIG_CPCI750
+#if defined(CONFIG_DB64360) || defined(CONFIG_CPCI750)
        mv6436x_eth_initialize(bis);
 #endif
-#ifdef CONFIG_DB64460
+#if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx)
        mv6446x_eth_initialize(bis);
 #endif
-#if defined(CONFIG_4xx) && !defined(CONFIG_IOP480) && !defined(CONFIG_AP1000)
-       ppc_4xx_eth_initialize(bis);
-#endif
-#ifdef CONFIG_INCA_IP_SWITCH
-       inca_switch_initialize(bis);
-#endif
-#ifdef CONFIG_PLB2800_ETHER
-       plb2800_eth_initialize(bis);
-#endif
-#ifdef SCC_ENET
-       scc_initialize(bis);
-#endif
-#if defined(CONFIG_MPC5xxx_FEC)
-       mpc5xxx_fec_initialize(bis);
-#endif
-#if defined(CONFIG_MPC8220_FEC)
-       mpc8220_fec_initialize(bis);
-#endif
-#if defined(CONFIG_SK98)
-       skge_initialize(bis);
-#endif
-#if defined(CONFIG_MPC85XX_TSEC1)
-       tsec_initialize(bis, 0, CONFIG_MPC85XX_TSEC1_NAME);
-#elif defined(CONFIG_MPC83XX_TSEC1)
-       tsec_initialize(bis, 0, CONFIG_MPC83XX_TSEC1_NAME);
-#endif
-#if defined(CONFIG_MPC85XX_TSEC2)
-       tsec_initialize(bis, 1, CONFIG_MPC85XX_TSEC2_NAME);
-#elif defined(CONFIG_MPC83XX_TSEC2)
-       tsec_initialize(bis, 1, CONFIG_MPC83XX_TSEC2_NAME);
-#endif
-#if defined(CONFIG_MPC85XX_FEC)
-       tsec_initialize(bis, 2, CONFIG_MPC85XX_FEC_NAME);
-#else
-#    if defined(CONFIG_MPC85XX_TSEC3)
-       tsec_initialize(bis, 2, CONFIG_MPC85XX_TSEC3_NAME);
-#    elif defined(CONFIG_MPC83XX_TSEC3)
-       tsec_initialize(bis, 2, CONFIG_MPC83XX_TSEC3_NAME);
-#    endif
-#    if defined(CONFIG_MPC85XX_TSEC4)
-       tsec_initialize(bis, 3, CONFIG_MPC85XX_TSEC4_NAME);
-#    elif defined(CONFIG_MPC83XX_TSEC4)
-       tsec_initialize(bis, 3, CONFIG_MPC83XX_TSEC4_NAME);
-#    endif
-#endif
-#if defined(CONFIG_MPC86XX_TSEC1)
-       tsec_initialize(bis, 0, CONFIG_MPC86XX_TSEC1_NAME);
-#endif
-
-#if defined(CONFIG_MPC86XX_TSEC2)
-       tsec_initialize(bis, 1, CONFIG_MPC86XX_TSEC2_NAME);
-#endif
-
-#if defined(CONFIG_MPC86XX_TSEC3)
-       tsec_initialize(bis, 2, CONFIG_MPC86XX_TSEC3_NAME);
-#endif
-
-#if defined(CONFIG_MPC86XX_TSEC4)
-       tsec_initialize(bis, 3, CONFIG_MPC86XX_TSEC4_NAME);
-#endif
-
-#if defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FCC)
-       fec_initialize(bis);
-#endif
-#if defined(CONFIG_AU1X00)
-       au1x00_enet_initialize(bis);
-#endif
-#if defined(CONFIG_IXP4XX_NPE)
-       npe_initialize(bis);
-#endif
-#ifdef CONFIG_E1000
-       e1000_initialize(bis);
-#endif
-#ifdef CONFIG_EEPRO100
-       eepro100_initialize(bis);
-#endif
-#ifdef CONFIG_TULIP
-       dc21x4x_initialize(bis);
-#endif
-#ifdef CONFIG_3COM
-       eth_3com_initialize(bis);
-#endif
-#ifdef CONFIG_PCNET
-       pcnet_initialize(bis);
-#endif
-#ifdef CFG_GT_6426x
-       gt6426x_eth_initialize(bis);
-#endif
-#ifdef CONFIG_NATSEMI
-       natsemi_initialize(bis);
-#endif
-#ifdef CONFIG_NS8382X
-       ns8382x_initialize(bis);
-#endif
-#if defined(CONFIG_RTL8139)
-       rtl8139_initialize(bis);
-#endif
-#if defined(CONFIG_RTL8169)
-       rtl8169_initialize(bis);
-#endif
-
        if (!eth_devices) {
                puts ("No ethernet found.\n");
+               show_boot_progress (-64);
        } else {
                struct eth_device *dev = eth_devices;
                char *ethprime = getenv ("ethprime");
 
+               show_boot_progress (65);
                do {
                        if (eth_number)
                                puts (", ");
@@ -269,14 +227,7 @@ int eth_initialize(bd_t *bis)
                                puts (" [PRIME]");
                        }
 
-                       sprintf(enetvar, eth_number ? "eth%daddr" : "ethaddr", eth_number);
-                       tmp = getenv (enetvar);
-
-                       for (i=0; i<6; i++) {
-                               env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
-                               if (tmp)
-                                       tmp = (*end) ? end+1 : end;
-                       }
+                       eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);
 
                        if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) {
                                if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) &&
@@ -284,16 +235,10 @@ int eth_initialize(bd_t *bis)
                                {
                                        printf ("\nWarning: %s MAC addresses don't match:\n",
                                                dev->name);
-                                       printf ("Address in SROM is         "
-                                              "%02X:%02X:%02X:%02X:%02X:%02X\n",
-                                              dev->enetaddr[0], dev->enetaddr[1],
-                                              dev->enetaddr[2], dev->enetaddr[3],
-                                              dev->enetaddr[4], dev->enetaddr[5]);
-                                       printf ("Address in environment is  "
-                                              "%02X:%02X:%02X:%02X:%02X:%02X\n",
-                                              env_enetaddr[0], env_enetaddr[1],
-                                              env_enetaddr[2], env_enetaddr[3],
-                                              env_enetaddr[4], env_enetaddr[5]);
+                                       printf ("Address in SROM is         %pM\n",
+                                               dev->enetaddr);
+                                       printf ("Address in environment is  %pM\n",
+                                               env_enetaddr);
                                }
 
                                memcpy(dev->enetaddr, env_enetaddr, 6);
@@ -319,63 +264,90 @@ int eth_initialize(bd_t *bis)
        return eth_number;
 }
 
-void eth_set_enetaddr(int num, char *addr) {
-       struct eth_device *dev;
-       unsigned char enetaddr[6];
-       char *end;
-       int i;
+#ifdef CONFIG_MCAST_TFTP
+/* Multicast.
+ * mcast_addr: multicast ipaddr from which multicast Mac is made
+ * join: 1=join, 0=leave.
+ */
+int eth_mcast_join( IPaddr_t mcast_ip, u8 join)
+{
+ u8 mcast_mac[6];
+       if (!eth_current || !eth_current->mcast)
+               return -1;
+       mcast_mac[5] = htonl(mcast_ip) & 0xff;
+       mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff;
+       mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f;
+       mcast_mac[2] = 0x5e;
+       mcast_mac[1] = 0x0;
+       mcast_mac[0] = 0x1;
+       return eth_current->mcast(eth_current, mcast_mac, join);
+}
 
-       debug ("eth_set_enetaddr(num=%d, addr=%s)\n", num, addr);
+/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
+ * and this is the ethernet-crc method needed for TSEC -- and perhaps
+ * some other adapter -- hash tables
+ */
+#define CRCPOLY_LE 0xedb88320
+u32 ether_crc (size_t len, unsigned char const *p)
+{
+       int i;
+       u32 crc;
+       crc = ~0;
+       while (len--) {
+               crc ^= *p++;
+               for (i = 0; i < 8; i++)
+                       crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+       }
+       /* an reverse the bits, cuz of way they arrive -- last-first */
+       crc = (crc >> 16) | (crc << 16);
+       crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
+       crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
+       crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
+       crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
+       return crc;
+}
 
-       if (!eth_devices)
-               return;
+#endif
 
-       for (i=0; i<6; i++) {
-               enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
-               if (addr)
-                       addr = (*end) ? end+1 : end;
-       }
 
-       dev = eth_devices;
-       while(num-- > 0) {
-               dev = dev->next;
+int eth_init(bd_t *bis)
+{
+       int eth_number;
+       struct eth_device *old_current, *dev;
 
-               if (dev == eth_devices)
-                       return;
+       if (!eth_current) {
+               puts ("No ethernet found.\n");
+               return -1;
        }
 
-       debug ( "Setting new HW address on %s\n"
-               "New Address is             %02X:%02X:%02X:%02X:%02X:%02X\n",
-               dev->name,
-               enetaddr[0], enetaddr[1],
-               enetaddr[2], enetaddr[3],
-               enetaddr[4], enetaddr[5]);
-
-       memcpy(dev->enetaddr, enetaddr, 6);
-}
+       /* Sync environment with network devices */
+       eth_number = 0;
+       dev = eth_devices;
+       do {
+               uchar env_enetaddr[6];
 
-int eth_init(bd_t *bis)
-{
-       struct eth_device* old_current;
+               if (eth_getenv_enetaddr_by_index(eth_number, env_enetaddr))
+                       memcpy(dev->enetaddr, env_enetaddr, 6);
 
-       if (!eth_current)
-               return 0;
+               ++eth_number;
+               dev = dev->next;
+       } while (dev != eth_devices);
 
        old_current = eth_current;
        do {
-               debug ("Trying %s\n", eth_current->name);
+               debug("Trying %s\n", eth_current->name);
 
-               if (eth_current->init(eth_current, bis)) {
+               if (eth_current->init(eth_current,bis) >= 0) {
                        eth_current->state = ETH_STATE_ACTIVE;
 
-                       return 1;
+                       return 0;
                }
-               debug  ("FAIL\n");
+               debug("FAIL\n");
 
                eth_try_another(0);
        } while (old_current != eth_current);
 
-       return 0;
+       return -1;
 }
 
 void eth_halt(void)
@@ -404,9 +376,65 @@ int eth_rx(void)
        return eth_current->recv(eth_current);
 }
 
+#ifdef CONFIG_API
+static void eth_save_packet(volatile void *packet, int length)
+{
+       volatile char *p = packet;
+       int i;
+
+       if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
+               return;
+
+       if (PKTSIZE < length)
+               return;
+
+       for (i = 0; i < length; i++)
+               eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
+
+       eth_rcv_bufs[eth_rcv_last].length = length;
+       eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
+}
+
+int eth_receive(volatile void *packet, int length)
+{
+       volatile char *p = packet;
+       void *pp = push_packet;
+       int i;
+
+       if (eth_rcv_current == eth_rcv_last) {
+               push_packet = eth_save_packet;
+               eth_rx();
+               push_packet = pp;
+
+               if (eth_rcv_current == eth_rcv_last)
+                       return -1;
+       }
+
+       if (length < eth_rcv_bufs[eth_rcv_current].length)
+               return -1;
+
+       length = eth_rcv_bufs[eth_rcv_current].length;
+
+       for (i = 0; i < length; i++)
+               p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
+
+       eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
+       return length;
+}
+#endif /* CONFIG_API */
+
 void eth_try_another(int first_restart)
 {
        static struct eth_device *first_failed = NULL;
+       char *ethrotate;
+
+       /*
+        * Do not rotate between network interfaces when
+        * 'ethrotate' variable is set to 'no'.
+        */
+       if (((ethrotate = getenv ("ethrotate")) != NULL) &&
+           (strcmp(ethrotate, "no") == 0))
+               return;
 
        if (!eth_current)
                return;
@@ -434,13 +462,19 @@ void eth_try_another(int first_restart)
 #ifdef CONFIG_NET_MULTI
 void eth_set_current(void)
 {
-       char *act;
+       static char *act = NULL;
+       static int  env_changed_id = 0;
        struct eth_device* old_current;
+       int     env_id;
 
        if (!eth_current)       /* XXX no current */
                return;
 
-       act = getenv("ethact");
+       env_id = get_env_id();
+       if ((act == NULL) || (env_changed_id != env_id)) {
+               act = getenv("ethact");
+               env_changed_id = env_id;
+       }
        if (act != NULL) {
                old_current = eth_current;
                do {
@@ -458,30 +492,28 @@ char *eth_get_name (void)
 {
        return (eth_current ? eth_current->name : "unknown");
 }
-#elif (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_NET_MULTI)
+#elif defined(CONFIG_CMD_NET) && !defined(CONFIG_NET_MULTI)
+
+#warning Ethernet driver is deprecated.  Please update to use CONFIG_NET_MULTI
 
 extern int at91rm9200_miiphy_initialize(bd_t *bis);
-extern int emac4xx_miiphy_initialize(bd_t *bis);
 extern int mcf52x2_miiphy_initialize(bd_t *bis);
 extern int ns7520_miiphy_initialize(bd_t *bis);
 
+
 int eth_initialize(bd_t *bis)
 {
-#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
        miiphy_init();
 #endif
 
 #if defined(CONFIG_AT91RM9200)
        at91rm9200_miiphy_initialize(bis);
 #endif
-#if defined(CONFIG_4xx) && !defined(CONFIG_IOP480) \
-       && !defined(CONFIG_AP1000) && !defined(CONFIG_405)
-       emac4xx_miiphy_initialize(bis);
-#endif
 #if defined(CONFIG_MCF52x2)
        mcf52x2_miiphy_initialize(bis);
 #endif
-#if defined(CONFIG_NETARM)
+#if defined(CONFIG_DRIVER_NS7520_ETHERNET)
        ns7520_miiphy_initialize(bis);
 #endif
        return 0;