xref: /openbmc/u-boot/net/eth_common.c (revision 16d761e3)
1 /*
2  * (C) Copyright 2001-2015
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  * Joe Hershberger, National Instruments
5  *
6  * SPDX-License-Identifier:	GPL-2.0+
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <miiphy.h>
12 #include <net.h>
13 #include "eth_internal.h"
14 
15 void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
16 {
17 	char *end;
18 	int i;
19 
20 	for (i = 0; i < 6; ++i) {
21 		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
22 		if (addr)
23 			addr = (*end) ? end + 1 : end;
24 	}
25 }
26 
27 int eth_env_get_enetaddr(const char *name, uchar *enetaddr)
28 {
29 	eth_parse_enetaddr(env_get(name), enetaddr);
30 	return is_valid_ethaddr(enetaddr);
31 }
32 
33 int eth_env_set_enetaddr(const char *name, const uchar *enetaddr)
34 {
35 	char buf[ARP_HLEN_ASCII + 1];
36 
37 	if (eth_env_get_enetaddr(name, (uchar *)buf))
38 		return -EEXIST;
39 
40 	sprintf(buf, "%pM", enetaddr);
41 
42 	return env_set(name, buf);
43 }
44 
45 int eth_env_get_enetaddr_by_index(const char *base_name, int index,
46 				 uchar *enetaddr)
47 {
48 	char enetvar[32];
49 	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
50 	return eth_env_get_enetaddr(enetvar, enetaddr);
51 }
52 
53 int eth_env_set_enetaddr_by_index(const char *base_name, int index,
54 				 uchar *enetaddr)
55 {
56 	char enetvar[32];
57 	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
58 	return eth_env_set_enetaddr(enetvar, enetaddr);
59 }
60 
61 void eth_common_init(void)
62 {
63 	bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
64 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
65 	miiphy_init();
66 #endif
67 
68 #ifdef CONFIG_PHYLIB
69 	phy_init();
70 #endif
71 }
72 
73 int eth_mac_skip(int index)
74 {
75 	char enetvar[15];
76 	char *skip_state;
77 
78 	sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
79 	skip_state = env_get(enetvar);
80 	return skip_state != NULL;
81 }
82 
83 void eth_current_changed(void)
84 {
85 	char *act = env_get("ethact");
86 	char *ethrotate;
87 
88 	/*
89 	 * The call to eth_get_dev() below has a side effect of rotating
90 	 * ethernet device if uc_priv->current == NULL. This is not what
91 	 * we want when 'ethrotate' variable is 'no'.
92 	 */
93 	ethrotate = env_get("ethrotate");
94 	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
95 		return;
96 
97 	/* update current ethernet name */
98 	if (eth_get_dev()) {
99 		if (act == NULL || strcmp(act, eth_get_name()) != 0)
100 			env_set("ethact", eth_get_name());
101 	}
102 	/*
103 	 * remove the variable completely if there is no active
104 	 * interface
105 	 */
106 	else if (act != NULL)
107 		env_set("ethact", NULL);
108 }
109 
110 void eth_try_another(int first_restart)
111 {
112 	static void *first_failed;
113 	char *ethrotate;
114 
115 	/*
116 	 * Do not rotate between network interfaces when
117 	 * 'ethrotate' variable is set to 'no'.
118 	 */
119 	ethrotate = env_get("ethrotate");
120 	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
121 		return;
122 
123 	if (!eth_get_dev())
124 		return;
125 
126 	if (first_restart)
127 		first_failed = eth_get_dev();
128 
129 	eth_set_current_to_next();
130 
131 	eth_current_changed();
132 
133 	if (first_failed == eth_get_dev())
134 		net_restart_wrap = 1;
135 }
136 
137 void eth_set_current(void)
138 {
139 	static char *act;
140 	static int  env_changed_id;
141 	int	env_id;
142 
143 	env_id = get_env_id();
144 	if ((act == NULL) || (env_changed_id != env_id)) {
145 		act = env_get("ethact");
146 		env_changed_id = env_id;
147 	}
148 
149 	if (act == NULL) {
150 		char *ethprime = env_get("ethprime");
151 		void *dev = NULL;
152 
153 		if (ethprime)
154 			dev = eth_get_dev_by_name(ethprime);
155 		if (dev)
156 			eth_set_dev(dev);
157 		else
158 			eth_set_dev(NULL);
159 	} else {
160 		eth_set_dev(eth_get_dev_by_name(act));
161 	}
162 
163 	eth_current_changed();
164 }
165 
166 const char *eth_get_name(void)
167 {
168 	return eth_get_dev() ? eth_get_dev()->name : "unknown";
169 }
170