dm: eth: Add support for aliases
authorJoe Hershberger <joe.hershberger@ni.com>
Sun, 22 Mar 2015 22:09:16 +0000 (17:09 -0500)
committerSimon Glass <sjg@chromium.org>
Sat, 18 Apr 2015 17:11:13 +0000 (11:11 -0600)
Allow network devices to be referred to as "eth0" instead of
"eth@12345678" when specified in ethact.

Add tests to verify this behavior.

Signed-off-by: Joe Hershberger <joe.hershberger@ni.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
include/configs/sandbox.h
include/net.h
net/eth.c
test/dm/eth.c
test/dm/test.dts

index e225ce6772c8684a242d8cf231e8fa32441fa559..9769a8dd806d4871ca719b3e94ec5ef4e4f11304 100644 (file)
 
 #define SANDBOX_ETH_SETTINGS           "ethaddr=00:00:11:22:33:44\0" \
                                        "eth1addr=00:00:11:22:33:45\0" \
-                                       "eth2addr=00:00:11:22:33:46\0" \
+                                       "eth5addr=00:00:11:22:33:46\0" \
                                        "ipaddr=1.2.3.4\0"
 
 #define CONFIG_EXTRA_ENV_SETTINGS      SANDBOX_SERIAL_SETTINGS \
index 0a1b3a827ced5053e23fae98f74727392c21d95c..942fa4c929ecd84a6f4f300c0c3c28ead5eadeca 100644 (file)
@@ -124,6 +124,11 @@ struct eth_ops {
 #define eth_get_ops(dev) ((struct eth_ops *)(dev)->driver->ops)
 
 struct udevice *eth_get_dev(void); /* get the current device */
+/*
+ * The devname can be either an exact name given by the driver or device tree
+ * or it can be an alias of the form "eth%d"
+ */
+struct udevice *eth_get_dev_by_name(const char *devname);
 unsigned char *eth_get_ethaddr(void); /* get the current device MAC */
 /* Used only when NetConsole is enabled */
 int eth_init_state_only(void); /* Set active state */
index 058c55a0e6e6ca0885040b957170958abb44e6f7..a2e6f34535e08fa3b6841afe4216879dd47a8897 100644 (file)
--- a/net/eth.c
+++ b/net/eth.c
@@ -135,6 +135,39 @@ static void eth_set_dev(struct udevice *dev)
        eth_get_uclass_priv()->current = dev;
 }
 
+/*
+ * Find the udevice that either has the name passed in as devname or has an
+ * alias named devname.
+ */
+struct udevice *eth_get_dev_by_name(const char *devname)
+{
+       int seq = -1;
+       char *endp = NULL;
+       const char *startp = NULL;
+       struct udevice *it;
+       struct uclass *uc;
+
+       /* Must be longer than 3 to be an alias */
+       if (strlen(devname) > strlen("eth")) {
+               startp = devname + strlen("eth");
+               seq = simple_strtoul(startp, &endp, 10);
+       }
+
+       uclass_get(UCLASS_ETH, &uc);
+       uclass_foreach_dev(it, uc) {
+               /* We need the seq to be valid, so make sure it's probed */
+               device_probe(it);
+               /*
+                * Check for the name or the sequence number to match
+                */
+               if (strcmp(it->name, devname) == 0 ||
+                   (endp > startp && it->seq == seq))
+                       return it;
+       }
+
+       return NULL;
+}
+
 unsigned char *eth_get_ethaddr(void)
 {
        struct eth_pdata *pdata;
@@ -421,6 +454,7 @@ UCLASS_DRIVER(eth) = {
        .pre_remove     = eth_pre_remove,
        .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
        .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
+       .flags          = DM_UC_FLAG_SEQ_ALIAS,
 };
 #endif
 
@@ -453,6 +487,11 @@ static void eth_set_current_to_next(void)
        eth_current = eth_current->next;
 }
 
+static void eth_set_dev(struct eth_device *dev)
+{
+       eth_current = dev;
+}
+
 struct eth_device *eth_get_dev_by_name(const char *devname)
 {
        struct eth_device *dev, *target_dev;
@@ -869,7 +908,6 @@ void eth_set_current(void)
 {
        static char *act;
        static int  env_changed_id;
-       void *old_current;
        int     env_id;
 
        env_id = get_env_id();
@@ -877,14 +915,8 @@ void eth_set_current(void)
                act = getenv("ethact");
                env_changed_id = env_id;
        }
-       if (act != NULL) {
-               old_current = eth_get_dev();
-               do {
-                       if (strcmp(eth_get_name(), act) == 0)
-                               return;
-                       eth_set_current_to_next();
-               } while (old_current != eth_get_dev());
-       }
+       if (act != NULL)
+               eth_set_dev(eth_get_dev_by_name(act));
 
        eth_current_changed();
 }
index 04ccf4982098d9a81b4f4bbfe073c9682ef6c9b8..5688b71de07162ed6c48513750d0e93d3bf53ab2 100644 (file)
@@ -36,3 +36,27 @@ static int dm_test_eth(struct dm_test_state *dms)
        return 0;
 }
 DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
+
+static int dm_test_eth_alias(struct dm_test_state *dms)
+{
+       NetPingIP = string_to_ip("1.1.2.2");
+       setenv("ethact", "eth0");
+       ut_assertok(NetLoop(PING));
+       ut_asserteq_str("eth@10002000", getenv("ethact"));
+
+       setenv("ethact", "eth1");
+       ut_assertok(NetLoop(PING));
+       ut_asserteq_str("eth@10004000", getenv("ethact"));
+
+       /* Expected to fail since eth2 is not defined in the device tree */
+       setenv("ethact", "eth2");
+       ut_assertok(NetLoop(PING));
+       ut_asserteq_str("eth@10002000", getenv("ethact"));
+
+       setenv("ethact", "eth5");
+       ut_assertok(NetLoop(PING));
+       ut_asserteq_str("eth@10003000", getenv("ethact"));
+
+       return 0;
+}
+DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT);
index 762ddc3507efa5d98ca34bc2e3e8bce6a9ba899c..0ab0916858aaeab5a8c9af7ce1dee6c3ba8d2b2d 100644 (file)
@@ -18,6 +18,8 @@
                testfdt3 = "/b-test";
                testfdt5 = "/some-bus/c-test@5";
                testfdt8 = "/a-test";
+               eth0 = "/eth@10002000";
+               eth5 = &eth_5;
        };
 
        uart0: serial {
                fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x00>;
        };
 
-       eth@10003000 {
+       eth_5: eth@10003000 {
                compatible = "sandbox,eth";
                reg = <0x10003000 0x1000>;
                fake-host-hwaddr = <0x00 0x00 0x66 0x44 0x22 0x11>;