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