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 <command.h> 11 #include <environment.h> 12 #include <net.h> 13 #include <phy.h> 14 #include <linux/errno.h> 15 #include "eth_internal.h" 16 17 DECLARE_GLOBAL_DATA_PTR; 18 19 /* 20 * CPU and board-specific Ethernet initializations. Aliased function 21 * signals caller to move on 22 */ 23 static int __def_eth_init(bd_t *bis) 24 { 25 return -1; 26 } 27 int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init"))); 28 int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init"))); 29 30 #ifdef CONFIG_API 31 static struct { 32 uchar data[PKTSIZE]; 33 int length; 34 } eth_rcv_bufs[PKTBUFSRX]; 35 36 static unsigned int eth_rcv_current, eth_rcv_last; 37 #endif 38 39 static struct eth_device *eth_devices; 40 struct eth_device *eth_current; 41 42 void eth_set_current_to_next(void) 43 { 44 eth_current = eth_current->next; 45 } 46 47 void eth_set_dev(struct eth_device *dev) 48 { 49 eth_current = dev; 50 } 51 52 struct eth_device *eth_get_dev_by_name(const char *devname) 53 { 54 struct eth_device *dev, *target_dev; 55 56 BUG_ON(devname == NULL); 57 58 if (!eth_devices) 59 return NULL; 60 61 dev = eth_devices; 62 target_dev = NULL; 63 do { 64 if (strcmp(devname, dev->name) == 0) { 65 target_dev = dev; 66 break; 67 } 68 dev = dev->next; 69 } while (dev != eth_devices); 70 71 return target_dev; 72 } 73 74 struct eth_device *eth_get_dev_by_index(int index) 75 { 76 struct eth_device *dev, *target_dev; 77 78 if (!eth_devices) 79 return NULL; 80 81 dev = eth_devices; 82 target_dev = NULL; 83 do { 84 if (dev->index == index) { 85 target_dev = dev; 86 break; 87 } 88 dev = dev->next; 89 } while (dev != eth_devices); 90 91 return target_dev; 92 } 93 94 int eth_get_dev_index(void) 95 { 96 if (!eth_current) 97 return -1; 98 99 return eth_current->index; 100 } 101 102 static int on_ethaddr(const char *name, const char *value, enum env_op op, 103 int flags) 104 { 105 int index; 106 struct eth_device *dev; 107 108 if (!eth_devices) 109 return 0; 110 111 /* look for an index after "eth" */ 112 index = simple_strtoul(name + 3, NULL, 10); 113 114 dev = eth_devices; 115 do { 116 if (dev->index == index) { 117 switch (op) { 118 case env_op_create: 119 case env_op_overwrite: 120 eth_parse_enetaddr(value, dev->enetaddr); 121 eth_write_hwaddr(dev, "eth", dev->index); 122 break; 123 case env_op_delete: 124 memset(dev->enetaddr, 0, ARP_HLEN); 125 } 126 } 127 dev = dev->next; 128 } while (dev != eth_devices); 129 130 return 0; 131 } 132 U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr); 133 134 int eth_write_hwaddr(struct eth_device *dev, const char *base_name, 135 int eth_number) 136 { 137 unsigned char env_enetaddr[ARP_HLEN]; 138 int ret = 0; 139 140 eth_env_get_enetaddr_by_index(base_name, eth_number, env_enetaddr); 141 142 if (!is_zero_ethaddr(env_enetaddr)) { 143 if (!is_zero_ethaddr(dev->enetaddr) && 144 memcmp(dev->enetaddr, env_enetaddr, ARP_HLEN)) { 145 printf("\nWarning: %s MAC addresses don't match:\n", 146 dev->name); 147 printf("Address in SROM is %pM\n", 148 dev->enetaddr); 149 printf("Address in environment is %pM\n", 150 env_enetaddr); 151 } 152 153 memcpy(dev->enetaddr, env_enetaddr, ARP_HLEN); 154 } else if (is_valid_ethaddr(dev->enetaddr)) { 155 eth_env_set_enetaddr_by_index(base_name, eth_number, 156 dev->enetaddr); 157 } else if (is_zero_ethaddr(dev->enetaddr)) { 158 #ifdef CONFIG_NET_RANDOM_ETHADDR 159 net_random_ethaddr(dev->enetaddr); 160 printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", 161 dev->name, eth_number, dev->enetaddr); 162 #else 163 printf("\nError: %s address not set.\n", 164 dev->name); 165 return -EINVAL; 166 #endif 167 } 168 169 if (dev->write_hwaddr && !eth_mac_skip(eth_number)) { 170 if (!is_valid_ethaddr(dev->enetaddr)) { 171 printf("\nError: %s address %pM illegal value\n", 172 dev->name, dev->enetaddr); 173 return -EINVAL; 174 } 175 176 ret = dev->write_hwaddr(dev); 177 if (ret) 178 printf("\nWarning: %s failed to set MAC address\n", 179 dev->name); 180 } 181 182 return ret; 183 } 184 185 int eth_register(struct eth_device *dev) 186 { 187 struct eth_device *d; 188 static int index; 189 190 assert(strlen(dev->name) < sizeof(dev->name)); 191 192 if (!eth_devices) { 193 eth_devices = dev; 194 eth_current = dev; 195 eth_current_changed(); 196 } else { 197 for (d = eth_devices; d->next != eth_devices; d = d->next) 198 ; 199 d->next = dev; 200 } 201 202 dev->state = ETH_STATE_INIT; 203 dev->next = eth_devices; 204 dev->index = index++; 205 206 return 0; 207 } 208 209 int eth_unregister(struct eth_device *dev) 210 { 211 struct eth_device *cur; 212 213 /* No device */ 214 if (!eth_devices) 215 return -ENODEV; 216 217 for (cur = eth_devices; cur->next != eth_devices && cur->next != dev; 218 cur = cur->next) 219 ; 220 221 /* Device not found */ 222 if (cur->next != dev) 223 return -ENODEV; 224 225 cur->next = dev->next; 226 227 if (eth_devices == dev) 228 eth_devices = dev->next == eth_devices ? NULL : dev->next; 229 230 if (eth_current == dev) { 231 eth_current = eth_devices; 232 eth_current_changed(); 233 } 234 235 return 0; 236 } 237 238 int eth_initialize(void) 239 { 240 int num_devices = 0; 241 242 eth_devices = NULL; 243 eth_current = NULL; 244 eth_common_init(); 245 /* 246 * If board-specific initialization exists, call it. 247 * If not, call a CPU-specific one 248 */ 249 if (board_eth_init != __def_eth_init) { 250 if (board_eth_init(gd->bd) < 0) 251 printf("Board Net Initialization Failed\n"); 252 } else if (cpu_eth_init != __def_eth_init) { 253 if (cpu_eth_init(gd->bd) < 0) 254 printf("CPU Net Initialization Failed\n"); 255 } else { 256 printf("Net Initialization Skipped\n"); 257 } 258 259 if (!eth_devices) { 260 puts("No ethernet found.\n"); 261 bootstage_error(BOOTSTAGE_ID_NET_ETH_START); 262 } else { 263 struct eth_device *dev = eth_devices; 264 char *ethprime = env_get("ethprime"); 265 266 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); 267 do { 268 if (dev->index) 269 puts(", "); 270 271 printf("%s", dev->name); 272 273 if (ethprime && strcmp(dev->name, ethprime) == 0) { 274 eth_current = dev; 275 puts(" [PRIME]"); 276 } 277 278 if (strchr(dev->name, ' ')) 279 puts("\nWarning: eth device name has a space!" 280 "\n"); 281 282 eth_write_hwaddr(dev, "eth", dev->index); 283 284 dev = dev->next; 285 num_devices++; 286 } while (dev != eth_devices); 287 288 eth_current_changed(); 289 putc('\n'); 290 } 291 292 return num_devices; 293 } 294 295 #ifdef CONFIG_MCAST_TFTP 296 /* Multicast. 297 * mcast_addr: multicast ipaddr from which multicast Mac is made 298 * join: 1=join, 0=leave. 299 */ 300 int eth_mcast_join(struct in_addr mcast_ip, int join) 301 { 302 u8 mcast_mac[ARP_HLEN]; 303 if (!eth_current || !eth_current->mcast) 304 return -1; 305 mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff; 306 mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff; 307 mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f; 308 mcast_mac[2] = 0x5e; 309 mcast_mac[1] = 0x0; 310 mcast_mac[0] = 0x1; 311 return eth_current->mcast(eth_current, mcast_mac, join); 312 } 313 314 /* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c 315 * and this is the ethernet-crc method needed for TSEC -- and perhaps 316 * some other adapter -- hash tables 317 */ 318 #define CRCPOLY_LE 0xedb88320 319 u32 ether_crc(size_t len, unsigned char const *p) 320 { 321 int i; 322 u32 crc; 323 crc = ~0; 324 while (len--) { 325 crc ^= *p++; 326 for (i = 0; i < 8; i++) 327 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); 328 } 329 /* an reverse the bits, cuz of way they arrive -- last-first */ 330 crc = (crc >> 16) | (crc << 16); 331 crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00); 332 crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0); 333 crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc); 334 crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa); 335 return crc; 336 } 337 338 #endif 339 340 341 int eth_init(void) 342 { 343 struct eth_device *old_current; 344 345 if (!eth_current) { 346 puts("No ethernet found.\n"); 347 return -ENODEV; 348 } 349 350 old_current = eth_current; 351 do { 352 debug("Trying %s\n", eth_current->name); 353 354 if (eth_current->init(eth_current, gd->bd) >= 0) { 355 eth_current->state = ETH_STATE_ACTIVE; 356 357 return 0; 358 } 359 debug("FAIL\n"); 360 361 eth_try_another(0); 362 } while (old_current != eth_current); 363 364 return -ETIMEDOUT; 365 } 366 367 void eth_halt(void) 368 { 369 if (!eth_current) 370 return; 371 372 eth_current->halt(eth_current); 373 374 eth_current->state = ETH_STATE_PASSIVE; 375 } 376 377 int eth_is_active(struct eth_device *dev) 378 { 379 return dev && dev->state == ETH_STATE_ACTIVE; 380 } 381 382 int eth_send(void *packet, int length) 383 { 384 if (!eth_current) 385 return -ENODEV; 386 387 return eth_current->send(eth_current, packet, length); 388 } 389 390 int eth_rx(void) 391 { 392 if (!eth_current) 393 return -ENODEV; 394 395 return eth_current->recv(eth_current); 396 } 397 398 #ifdef CONFIG_API 399 static void eth_save_packet(void *packet, int length) 400 { 401 char *p = packet; 402 int i; 403 404 if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current) 405 return; 406 407 if (PKTSIZE < length) 408 return; 409 410 for (i = 0; i < length; i++) 411 eth_rcv_bufs[eth_rcv_last].data[i] = p[i]; 412 413 eth_rcv_bufs[eth_rcv_last].length = length; 414 eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX; 415 } 416 417 int eth_receive(void *packet, int length) 418 { 419 char *p = packet; 420 void *pp = push_packet; 421 int i; 422 423 if (eth_rcv_current == eth_rcv_last) { 424 push_packet = eth_save_packet; 425 eth_rx(); 426 push_packet = pp; 427 428 if (eth_rcv_current == eth_rcv_last) 429 return -1; 430 } 431 432 length = min(eth_rcv_bufs[eth_rcv_current].length, length); 433 434 for (i = 0; i < length; i++) 435 p[i] = eth_rcv_bufs[eth_rcv_current].data[i]; 436 437 eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX; 438 return length; 439 } 440 #endif /* CONFIG_API */ 441