]> git.sur5r.net Git - u-boot/blobdiff - net/eth.c
net: Move environment functions to the common file
[u-boot] / net / eth.c
index 72ce91c9d0bbb546c7d8b50098b161ca8cf124ea..af8fcaea9047a028bc69f667e53a7264f9f58d77 100644 (file)
--- a/net/eth.c
+++ b/net/eth.c
 #include <asm/errno.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
+#include "eth_internal.h"
 
 DECLARE_GLOBAL_DATA_PTR;
 
-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_ethaddr(enetaddr);
-}
-
-int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
-{
-       char buf[20];
-
-       sprintf(buf, "%pM", enetaddr);
-
-       return setenv(name, buf);
-}
-
-int eth_getenv_enetaddr_by_index(const char *base_name, int index,
-                                uchar *enetaddr)
-{
-       char enetvar[32];
-       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
-       return eth_getenv_enetaddr(enetvar, enetaddr);
-}
-
-static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
-                                uchar *enetaddr)
-{
-       char enetvar[32];
-       sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
-       return eth_setenv_enetaddr(enetvar, enetaddr);
-}
-
 static int eth_mac_skip(int index)
 {
        char enetvar[15];
@@ -85,32 +43,6 @@ static int __def_eth_init(bd_t *bis)
 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")));
 
-static void eth_common_init(void)
-{
-       bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
-       miiphy_init();
-#endif
-
-#ifdef CONFIG_PHYLIB
-       phy_init();
-#endif
-
-       /*
-        * If board-specific initialization exists, call it.
-        * If not, call a CPU-specific one
-        */
-       if (board_eth_init != __def_eth_init) {
-               if (board_eth_init(gd->bd) < 0)
-                       printf("Board Net Initialization Failed\n");
-       } else if (cpu_eth_init != __def_eth_init) {
-               if (cpu_eth_init(gd->bd) < 0)
-                       printf("CPU Net Initialization Failed\n");
-       } else {
-               printf("Net Initialization Skipped\n");
-       }
-}
-
 #ifdef CONFIG_DM_ETH
 /**
  * struct eth_device_priv - private structure for each Ethernet device
@@ -177,8 +109,12 @@ struct udevice *eth_get_dev(void)
  */
 static void eth_set_dev(struct udevice *dev)
 {
-       if (dev && !device_active(dev))
+       if (dev && !device_active(dev)) {
                eth_errno = device_probe(dev);
+               if (eth_errno)
+                       dev = NULL;
+       }
+
        eth_get_uclass_priv()->current = dev;
 }
 
@@ -193,10 +129,11 @@ struct udevice *eth_get_dev_by_name(const char *devname)
        const char *startp = NULL;
        struct udevice *it;
        struct uclass *uc;
+       int len = strlen("eth");
 
        /* Must be longer than 3 to be an alias */
-       if (strlen(devname) > strlen("eth")) {
-               startp = devname + strlen("eth");
+       if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
+               startp = devname + len;
                seq = simple_strtoul(startp, &endp, 10);
        }
 
@@ -210,10 +147,9 @@ struct udevice *eth_get_dev_by_name(const char *devname)
                 * match an alias or it will match a literal name and we'll pick
                 * up the error when we try to probe again in eth_set_dev().
                 */
-               device_probe(it);
-               /*
-                * Check for the name or the sequence number to match
-                */
+               if (device_probe(it))
+                       continue;
+               /* Check for the name or the sequence number to match */
                if (strcmp(it->name, devname) == 0 ||
                    (endp > startp && it->seq == seq))
                        return it;
@@ -287,7 +223,13 @@ static int eth_write_hwaddr(struct udevice *dev)
                        return -EINVAL;
                }
 
+               /*
+                * Drivers are allowed to decide not to implement this at
+                * run-time. E.g. Some devices may use it and some may not.
+                */
                ret = eth_get_ops(dev)->write_hwaddr(dev);
+               if (ret == -ENOSYS)
+                       ret = 0;
                if (ret)
                        printf("\nWarning: %s failed to set MAC address\n",
                               dev->name);
@@ -325,35 +267,55 @@ U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
 
 int eth_init(void)
 {
-       struct udevice *current;
+       char *ethact = getenv("ethact");
+       char *ethrotate = getenv("ethrotate");
+       struct udevice *current = NULL;
        struct udevice *old_current;
        int ret = -ENODEV;
 
-       current = eth_get_dev();
+       /*
+        * When 'ethrotate' variable is set to 'no' and 'ethact' variable
+        * is already set to an ethernet device, we should stick to 'ethact'.
+        */
+       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) {
+               if (ethact) {
+                       current = eth_get_dev_by_name(ethact);
+                       if (!current)
+                               return -EINVAL;
+               }
+       }
+
        if (!current) {
-               printf("No ethernet found.\n");
-               return -ENODEV;
+               current = eth_get_dev();
+               if (!current) {
+                       printf("No ethernet found.\n");
+                       return -ENODEV;
+               }
        }
 
        old_current = current;
        do {
-               debug("Trying %s\n", current->name);
-
-               if (device_active(current)) {
-                       ret = eth_get_ops(current)->start(current);
-                       if (ret >= 0) {
-                               struct eth_device_priv *priv =
-                                       current->uclass_priv;
-
-                               priv->state = ETH_STATE_ACTIVE;
-                               return 0;
+               if (current) {
+                       debug("Trying %s\n", current->name);
+
+                       if (device_active(current)) {
+                               ret = eth_get_ops(current)->start(current);
+                               if (ret >= 0) {
+                                       struct eth_device_priv *priv =
+                                               current->uclass_priv;
+
+                                       priv->state = ETH_STATE_ACTIVE;
+                                       return 0;
+                               }
+                       } else {
+                               ret = eth_errno;
                        }
+
+                       debug("FAIL\n");
                } else {
-                       ret = eth_errno;
+                       debug("PROBE FAIL\n");
                }
 
-               debug("FAIL\n");
-
                /*
                 * If ethrotate is enabled, this will change "current",
                 * otherwise we will drop out of this while loop immediately
@@ -380,6 +342,17 @@ void eth_halt(void)
        priv->state = ETH_STATE_PASSIVE;
 }
 
+int eth_is_active(struct udevice *dev)
+{
+       struct eth_device_priv *priv;
+
+       if (!dev || !device_active(dev))
+               return 0;
+
+       priv = dev_get_uclass_priv(dev);
+       return priv->state == ETH_STATE_ACTIVE;
+}
+
 int eth_send(void *packet, int length)
 {
        struct udevice *current;
@@ -514,6 +487,34 @@ static int eth_post_probe(struct udevice *dev)
        struct eth_pdata *pdata = dev->platdata;
        unsigned char env_enetaddr[6];
 
+#if defined(CONFIG_NEEDS_MANUAL_RELOC)
+       struct eth_ops *ops = eth_get_ops(dev);
+       static int reloc_done;
+
+       if (!reloc_done) {
+               if (ops->start)
+                       ops->start += gd->reloc_off;
+               if (ops->send)
+                       ops->send += gd->reloc_off;
+               if (ops->recv)
+                       ops->recv += gd->reloc_off;
+               if (ops->free_pkt)
+                       ops->free_pkt += gd->reloc_off;
+               if (ops->stop)
+                       ops->stop += gd->reloc_off;
+#ifdef CONFIG_MCAST_TFTP
+               if (ops->mcast)
+                       ops->mcast += gd->reloc_off;
+#endif
+               if (ops->write_hwaddr)
+                       ops->write_hwaddr += gd->reloc_off;
+               if (ops->read_rom_hwaddr)
+                       ops->read_rom_hwaddr += gd->reloc_off;
+
+               reloc_done++;
+       }
+#endif
+
        priv->state = ETH_STATE_INIT;
 
        /* Check if the device has a MAC address in ROM */
@@ -555,8 +556,13 @@ static int eth_post_probe(struct udevice *dev)
 
 static int eth_pre_remove(struct udevice *dev)
 {
+       struct eth_pdata *pdata = dev->platdata;
+
        eth_get_ops(dev)->stop(dev);
 
+       /* clear the MAC address */
+       memset(pdata->enetaddr, 0, 6);
+
        return 0;
 }
 
@@ -571,7 +577,7 @@ UCLASS_DRIVER(eth) = {
        .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
        .flags          = DM_UC_FLAG_SEQ_ALIAS,
 };
-#endif
+#endif /* #ifdef CONFIG_DM_ETH */
 
 #ifndef CONFIG_DM_ETH
 
@@ -671,6 +677,7 @@ static int on_ethaddr(const char *name, const char *value, enum env_op op,
                                memset(dev->enetaddr, 0, 6);
                        }
                }
+               dev = dev->next;
        } while (dev != eth_devices);
 
        return 0;
@@ -700,8 +707,6 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
        } else if (is_valid_ethaddr(dev->enetaddr)) {
                eth_setenv_enetaddr_by_index(base_name, eth_number,
                                             dev->enetaddr);
-               printf("\nWarning: %s using MAC address from net device\n",
-                      dev->name);
        } else if (is_zero_ethaddr(dev->enetaddr)) {
 #ifdef CONFIG_NET_RANDOM_ETHADDR
                net_random_ethaddr(dev->enetaddr);
@@ -790,6 +795,19 @@ int eth_initialize(void)
        eth_devices = NULL;
        eth_current = NULL;
        eth_common_init();
+       /*
+        * If board-specific initialization exists, call it.
+        * If not, call a CPU-specific one
+        */
+       if (board_eth_init != __def_eth_init) {
+               if (board_eth_init(gd->bd) < 0)
+                       printf("Board Net Initialization Failed\n");
+       } else if (cpu_eth_init != __def_eth_init) {
+               if (cpu_eth_init(gd->bd) < 0)
+                       printf("CPU Net Initialization Failed\n");
+       } else {
+               printf("Net Initialization Skipped\n");
+       }
 
        if (!eth_devices) {
                puts("No ethernet found.\n");
@@ -909,6 +927,11 @@ void eth_halt(void)
        eth_current->state = ETH_STATE_PASSIVE;
 }
 
+int eth_is_active(struct eth_device *dev)
+{
+       return dev && dev->state == ETH_STATE_ACTIVE;
+}
+
 int eth_send(void *packet, int length)
 {
        if (!eth_current)
@@ -973,6 +996,17 @@ int eth_receive(void *packet, int length)
 static void eth_current_changed(void)
 {
        char *act = getenv("ethact");
+       char *ethrotate;
+
+       /*
+        * The call to eth_get_dev() below has a side effect of rotating
+        * ethernet device if uc_priv->current == NULL. This is not what
+        * we want when 'ethrotate' variable is 'no'.
+        */
+       ethrotate = getenv("ethrotate");
+       if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
+               return;
+
        /* update current ethernet name */
        if (eth_get_dev()) {
                if (act == NULL || strcmp(act, eth_get_name()) != 0)