blob: f06fdb27439ce2903ca9fb4f25c74b7d9aea7d69 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -05002 * (C) Copyright 2001-2015
wdenkc6097192002-11-03 00:24:07 +00003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -05004 * Joe Hershberger, National Instruments
wdenkc6097192002-11-03 00:24:07 +00005 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02006 * SPDX-License-Identifier: GPL-2.0+
wdenkc6097192002-11-03 00:24:07 +00007 */
8
9#include <common.h>
10#include <command.h>
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -050011#include <dm.h>
wdenkc6097192002-11-03 00:24:07 +000012#include <net.h>
Marian Balakowiczcbdd1c82005-11-30 18:06:04 +010013#include <miiphy.h>
Andy Flemingaecf6fc2011-04-08 02:10:27 -050014#include <phy.h>
Pavel Machek222981f2014-07-13 10:27:02 +020015#include <asm/errno.h>
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -050016#include <dm/device-internal.h>
wdenkc6097192002-11-03 00:24:07 +000017
Joe Hershberger3dbe17e2015-03-22 17:09:06 -050018DECLARE_GLOBAL_DATA_PTR;
19
Mike Frysingerc34319c2009-01-29 19:43:44 -050020void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
21{
22 char *end;
23 int i;
24
25 for (i = 0; i < 6; ++i) {
26 enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
27 if (addr)
28 addr = (*end) ? end + 1 : end;
29 }
30}
31
32int eth_getenv_enetaddr(char *name, uchar *enetaddr)
33{
34 eth_parse_enetaddr(getenv(name), enetaddr);
35 return is_valid_ether_addr(enetaddr);
36}
37
38int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
39{
40 char buf[20];
41
42 sprintf(buf, "%pM", enetaddr);
43
44 return setenv(name, buf);
45}
Mike Frysingere129d562009-07-15 21:31:28 -040046
Simon Glass62b36c92011-06-13 16:13:10 -070047int eth_getenv_enetaddr_by_index(const char *base_name, int index,
48 uchar *enetaddr)
Mike Frysingere129d562009-07-15 21:31:28 -040049{
50 char enetvar[32];
Simon Glass62b36c92011-06-13 16:13:10 -070051 sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
Mike Frysingere129d562009-07-15 21:31:28 -040052 return eth_getenv_enetaddr(enetvar, enetaddr);
53}
Mike Frysingerc34319c2009-01-29 19:43:44 -050054
Joe Hershberger6c6fe5f2012-07-10 16:23:22 -050055static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
Rob Herringc2938c02012-04-14 18:06:49 +000056 uchar *enetaddr)
57{
58 char enetvar[32];
59 sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
60 return eth_setenv_enetaddr(enetvar, enetaddr);
61}
62
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -050063static void eth_env_init(void)
64{
65 const char *s;
66
67 s = getenv("bootfile");
68 if (s != NULL)
Joe Hershberger290c8992015-04-08 01:41:02 -050069 copy_filename(net_boot_file_name, s,
70 sizeof(net_boot_file_name));
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -050071}
Rob Herringc2938c02012-04-14 18:06:49 +000072
Ben Warren6db991a2010-04-26 11:11:46 -070073static int eth_mac_skip(int index)
74{
75 char enetvar[15];
76 char *skip_state;
77 sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
78 return ((skip_state = getenv(enetvar)) != NULL);
79}
80
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -050081static void eth_current_changed(void);
82
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -050083#ifdef CONFIG_DM_ETH
84/**
85 * struct eth_device_priv - private structure for each Ethernet device
86 *
87 * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
88 */
89struct eth_device_priv {
90 enum eth_state_t state;
91};
92
93/**
94 * struct eth_uclass_priv - The structure attached to the uclass itself
95 *
96 * @current: The Ethernet device that the network functions are using
97 */
98struct eth_uclass_priv {
99 struct udevice *current;
100};
101
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500102/* eth_errno - This stores the most recent failure code from DM functions */
103static int eth_errno;
104
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500105static struct eth_uclass_priv *eth_get_uclass_priv(void)
106{
107 struct uclass *uc;
108
109 uclass_get(UCLASS_ETH, &uc);
110 assert(uc);
111 return uc->priv;
112}
113
114static void eth_set_current_to_next(void)
115{
116 struct eth_uclass_priv *uc_priv;
117
118 uc_priv = eth_get_uclass_priv();
119 if (uc_priv->current)
120 uclass_next_device(&uc_priv->current);
121 if (!uc_priv->current)
122 uclass_first_device(UCLASS_ETH, &uc_priv->current);
123}
124
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500125/*
126 * Typically this will simply return the active device.
127 * In the case where the most recent active device was unset, this will attempt
128 * to return the first device. If that device doesn't exist or fails to probe,
129 * this function will return NULL.
130 */
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500131struct udevice *eth_get_dev(void)
132{
133 struct eth_uclass_priv *uc_priv;
134
135 uc_priv = eth_get_uclass_priv();
136 if (!uc_priv->current)
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500137 eth_errno = uclass_first_device(UCLASS_ETH,
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500138 &uc_priv->current);
139 return uc_priv->current;
140}
141
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500142/*
143 * Typically this will just store a device pointer.
144 * In case it was not probed, we will attempt to do so.
145 * dev may be NULL to unset the active device.
146 */
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500147static void eth_set_dev(struct udevice *dev)
148{
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500149 if (dev && !device_active(dev))
150 eth_errno = device_probe(dev);
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500151 eth_get_uclass_priv()->current = dev;
152}
153
Joe Hershberger279d2f62015-03-22 17:09:16 -0500154/*
155 * Find the udevice that either has the name passed in as devname or has an
156 * alias named devname.
157 */
158struct udevice *eth_get_dev_by_name(const char *devname)
159{
160 int seq = -1;
161 char *endp = NULL;
162 const char *startp = NULL;
163 struct udevice *it;
164 struct uclass *uc;
165
166 /* Must be longer than 3 to be an alias */
167 if (strlen(devname) > strlen("eth")) {
168 startp = devname + strlen("eth");
169 seq = simple_strtoul(startp, &endp, 10);
170 }
171
172 uclass_get(UCLASS_ETH, &uc);
173 uclass_foreach_dev(it, uc) {
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500174 /*
175 * We need the seq to be valid, so try to probe it.
176 * If the probe fails, the seq will not match since it will be
177 * -1 instead of what we are looking for.
178 * We don't care about errors from probe here. Either they won't
179 * match an alias or it will match a literal name and we'll pick
180 * up the error when we try to probe again in eth_set_dev().
181 */
Joe Hershberger279d2f62015-03-22 17:09:16 -0500182 device_probe(it);
183 /*
184 * Check for the name or the sequence number to match
185 */
186 if (strcmp(it->name, devname) == 0 ||
187 (endp > startp && it->seq == seq))
188 return it;
189 }
190
191 return NULL;
192}
193
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500194unsigned char *eth_get_ethaddr(void)
195{
196 struct eth_pdata *pdata;
197
198 if (eth_get_dev()) {
199 pdata = eth_get_dev()->platdata;
200 return pdata->enetaddr;
201 }
202
203 return NULL;
204}
205
206/* Set active state without calling start on the driver */
207int eth_init_state_only(void)
208{
209 struct udevice *current;
210 struct eth_device_priv *priv;
211
212 current = eth_get_dev();
213 if (!current || !device_active(current))
214 return -EINVAL;
215
216 priv = current->uclass_priv;
217 priv->state = ETH_STATE_ACTIVE;
218
219 return 0;
220}
221
222/* Set passive state without calling stop on the driver */
223void eth_halt_state_only(void)
224{
225 struct udevice *current;
226 struct eth_device_priv *priv;
227
228 current = eth_get_dev();
229 if (!current || !device_active(current))
230 return;
231
232 priv = current->uclass_priv;
233 priv->state = ETH_STATE_PASSIVE;
234}
235
236int eth_get_dev_index(void)
237{
238 if (eth_get_dev())
239 return eth_get_dev()->seq;
240 return -1;
241}
242
243int eth_init(void)
244{
245 struct udevice *current;
246 struct udevice *old_current;
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500247 int ret = -ENODEV;
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500248
249 current = eth_get_dev();
250 if (!current) {
251 printf("No ethernet found.\n");
252 return -ENODEV;
253 }
254
255 old_current = current;
256 do {
257 debug("Trying %s\n", current->name);
258
259 if (device_active(current)) {
260 uchar env_enetaddr[6];
261 struct eth_pdata *pdata = current->platdata;
262
263 /* Sync environment with network device */
264 if (eth_getenv_enetaddr_by_index("eth", current->seq,
265 env_enetaddr))
266 memcpy(pdata->enetaddr, env_enetaddr, 6);
267 else
268 memset(pdata->enetaddr, 0, 6);
269
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500270 ret = eth_get_ops(current)->start(current);
271 if (ret >= 0) {
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500272 struct eth_device_priv *priv =
273 current->uclass_priv;
274
275 priv->state = ETH_STATE_ACTIVE;
276 return 0;
277 }
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500278 } else
279 ret = eth_errno;
280
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500281 debug("FAIL\n");
282
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500283 /*
284 * If ethrotate is enabled, this will change "current",
285 * otherwise we will drop out of this while loop immediately
286 */
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500287 eth_try_another(0);
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500288 /* This will ensure the new "current" attempted to probe */
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500289 current = eth_get_dev();
290 } while (old_current != current);
291
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500292 return ret;
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500293}
294
295void eth_halt(void)
296{
297 struct udevice *current;
298 struct eth_device_priv *priv;
299
300 current = eth_get_dev();
301 if (!current || !device_active(current))
302 return;
303
304 eth_get_ops(current)->stop(current);
305 priv = current->uclass_priv;
306 priv->state = ETH_STATE_PASSIVE;
307}
308
309int eth_send(void *packet, int length)
310{
311 struct udevice *current;
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500312 int ret;
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500313
314 current = eth_get_dev();
315 if (!current)
316 return -ENODEV;
317
318 if (!device_active(current))
319 return -EINVAL;
320
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500321 ret = eth_get_ops(current)->send(current, packet, length);
322 if (ret < 0) {
323 /* We cannot completely return the error at present */
324 debug("%s: send() returned error %d\n", __func__, ret);
325 }
326 return ret;
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500327}
328
329int eth_rx(void)
330{
331 struct udevice *current;
Joe Hershberger8207c542015-03-22 17:09:12 -0500332 uchar *packet;
333 int ret;
334 int i;
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500335
336 current = eth_get_dev();
337 if (!current)
338 return -ENODEV;
339
340 if (!device_active(current))
341 return -EINVAL;
342
Joe Hershberger8207c542015-03-22 17:09:12 -0500343 /* Process up to 32 packets at one time */
344 for (i = 0; i < 32; i++) {
345 ret = eth_get_ops(current)->recv(current, &packet);
346 if (ret > 0)
347 net_process_received_packet(packet, ret);
Joe Hershbergera892dc12015-04-03 20:09:46 -0500348 if (ret >= 0 && eth_get_ops(current)->free_pkt)
349 eth_get_ops(current)->free_pkt(current, packet, ret);
350 if (ret <= 0)
Joe Hershberger8207c542015-03-22 17:09:12 -0500351 break;
352 }
353 if (ret == -EAGAIN)
354 ret = 0;
Joe Hershbergerf4dc96a2015-03-22 17:09:24 -0500355 if (ret < 0) {
356 /* We cannot completely return the error at present */
357 debug("%s: recv() returned error %d\n", __func__, ret);
358 }
Joe Hershberger8207c542015-03-22 17:09:12 -0500359 return ret;
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500360}
361
362static int eth_write_hwaddr(struct udevice *dev)
363{
364 struct eth_pdata *pdata = dev->platdata;
365 int ret = 0;
366
367 if (!dev || !device_active(dev))
368 return -EINVAL;
369
370 /* seq is valid since the device is active */
371 if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
372 if (!is_valid_ether_addr(pdata->enetaddr)) {
373 printf("\nError: %s address %pM illegal value\n",
374 dev->name, pdata->enetaddr);
375 return -EINVAL;
376 }
377
378 ret = eth_get_ops(dev)->write_hwaddr(dev);
379 if (ret)
380 printf("\nWarning: %s failed to set MAC address\n",
381 dev->name);
382 }
383
384 return ret;
385}
386
387int eth_initialize(void)
388{
389 int num_devices = 0;
390 struct udevice *dev;
391
392 bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
393 eth_env_init();
394
395 /*
396 * Devices need to write the hwaddr even if not started so that Linux
397 * will have access to the hwaddr that u-boot stored for the device.
398 * This is accomplished by attempting to probe each device and calling
399 * their write_hwaddr() operation.
400 */
401 uclass_first_device(UCLASS_ETH, &dev);
402 if (!dev) {
403 printf("No ethernet found.\n");
404 bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
405 } else {
Joe Hershbergeraa52edd2015-03-22 17:09:17 -0500406 char *ethprime = getenv("ethprime");
407 struct udevice *prime_dev = NULL;
408
409 if (ethprime)
410 prime_dev = eth_get_dev_by_name(ethprime);
411 if (prime_dev) {
412 eth_set_dev(prime_dev);
413 eth_current_changed();
414 } else {
415 eth_set_dev(NULL);
416 }
417
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500418 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
419 do {
420 if (num_devices)
421 printf(", ");
422
423 printf("eth%d: %s", dev->seq, dev->name);
424
Joe Hershbergeraa52edd2015-03-22 17:09:17 -0500425 if (ethprime && dev == prime_dev)
426 printf(" [PRIME]");
427
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500428 eth_write_hwaddr(dev);
429
430 uclass_next_device(&dev);
431 num_devices++;
432 } while (dev);
433
434 putc('\n');
435 }
436
437 return num_devices;
438}
439
440static int eth_post_bind(struct udevice *dev)
441{
442 if (strchr(dev->name, ' ')) {
443 printf("\nError: eth device name \"%s\" has a space!\n",
444 dev->name);
445 return -EINVAL;
446 }
447
448 return 0;
449}
450
451static int eth_pre_unbind(struct udevice *dev)
452{
453 /* Don't hang onto a pointer that is going away */
454 if (dev == eth_get_uclass_priv()->current)
455 eth_set_dev(NULL);
456
457 return 0;
458}
459
460static int eth_post_probe(struct udevice *dev)
461{
462 struct eth_device_priv *priv = dev->uclass_priv;
463 struct eth_pdata *pdata = dev->platdata;
464 unsigned char env_enetaddr[6];
465
466 priv->state = ETH_STATE_INIT;
467
468 /* Check if the device has a MAC address in ROM */
469 if (eth_get_ops(dev)->read_rom_hwaddr)
470 eth_get_ops(dev)->read_rom_hwaddr(dev);
471
472 eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
473 if (!is_zero_ether_addr(env_enetaddr)) {
474 if (!is_zero_ether_addr(pdata->enetaddr) &&
475 memcmp(pdata->enetaddr, env_enetaddr, 6)) {
476 printf("\nWarning: %s MAC addresses don't match:\n",
477 dev->name);
478 printf("Address in SROM is %pM\n",
479 pdata->enetaddr);
480 printf("Address in environment is %pM\n",
481 env_enetaddr);
482 }
483
484 /* Override the ROM MAC address */
485 memcpy(pdata->enetaddr, env_enetaddr, 6);
486 } else if (is_valid_ether_addr(pdata->enetaddr)) {
487 eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
488 printf("\nWarning: %s using MAC address from ROM\n",
489 dev->name);
490 } else if (is_zero_ether_addr(pdata->enetaddr)) {
491 printf("\nError: %s address not set.\n",
492 dev->name);
493 return -EINVAL;
494 }
495
496 return 0;
497}
498
499static int eth_pre_remove(struct udevice *dev)
500{
501 eth_get_ops(dev)->stop(dev);
502
503 return 0;
504}
505
506UCLASS_DRIVER(eth) = {
507 .name = "eth",
508 .id = UCLASS_ETH,
509 .post_bind = eth_post_bind,
510 .pre_unbind = eth_pre_unbind,
511 .post_probe = eth_post_probe,
512 .pre_remove = eth_pre_remove,
513 .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
514 .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
Joe Hershberger279d2f62015-03-22 17:09:16 -0500515 .flags = DM_UC_FLAG_SEQ_ALIAS,
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500516};
517#endif
518
519#ifndef CONFIG_DM_ETH
Ben Warrend448a492008-06-23 22:57:27 -0700520/*
521 * CPU and board-specific Ethernet initializations. Aliased function
522 * signals caller to move on
523 */
524static int __def_eth_init(bd_t *bis)
525{
526 return -1;
527}
Peter Tyser21d2cd22009-04-20 11:08:46 -0500528int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
529int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
Ben Warrend448a492008-06-23 22:57:27 -0700530
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100531#ifdef CONFIG_API
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100532static struct {
533 uchar data[PKTSIZE];
534 int length;
535} eth_rcv_bufs[PKTBUFSRX];
536
Joe Hershberger5956ded2012-05-15 08:59:07 +0000537static unsigned int eth_rcv_current, eth_rcv_last;
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100538#endif
539
Joe Hershberger9f374062012-08-03 10:59:08 +0000540static struct eth_device *eth_devices;
541struct eth_device *eth_current;
wdenkc6097192002-11-03 00:24:07 +0000542
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500543static void eth_set_current_to_next(void)
544{
545 eth_current = eth_current->next;
546}
547
Joe Hershberger279d2f62015-03-22 17:09:16 -0500548static void eth_set_dev(struct eth_device *dev)
549{
550 eth_current = dev;
551}
552
Ben Warren97824d62010-07-29 12:56:11 -0700553struct eth_device *eth_get_dev_by_name(const char *devname)
Marian Balakowiczaab8c492005-10-28 22:30:33 +0200554{
555 struct eth_device *dev, *target_dev;
556
Helmut Raiger153bf3a2011-08-22 00:17:17 +0000557 BUG_ON(devname == NULL);
558
Marian Balakowiczaab8c492005-10-28 22:30:33 +0200559 if (!eth_devices)
560 return NULL;
561
562 dev = eth_devices;
563 target_dev = NULL;
564 do {
565 if (strcmp(devname, dev->name) == 0) {
566 target_dev = dev;
567 break;
568 }
569 dev = dev->next;
570 } while (dev != eth_devices);
571
572 return target_dev;
573}
574
Andy Fleminge7fd34b2009-02-11 15:07:24 -0600575struct eth_device *eth_get_dev_by_index(int index)
576{
577 struct eth_device *dev, *target_dev;
Andy Fleminge7fd34b2009-02-11 15:07:24 -0600578
579 if (!eth_devices)
580 return NULL;
581
582 dev = eth_devices;
583 target_dev = NULL;
584 do {
Michael Walle391da4c2011-10-27 11:31:35 +0000585 if (dev->index == index) {
Andy Fleminge7fd34b2009-02-11 15:07:24 -0600586 target_dev = dev;
587 break;
588 }
589 dev = dev->next;
Andy Fleminge7fd34b2009-02-11 15:07:24 -0600590 } while (dev != eth_devices);
591
592 return target_dev;
593}
594
Joe Hershberger5956ded2012-05-15 08:59:07 +0000595int eth_get_dev_index(void)
wdenkc6097192002-11-03 00:24:07 +0000596{
Joe Hershberger5956ded2012-05-15 08:59:07 +0000597 if (!eth_current)
Michael Walle391da4c2011-10-27 11:31:35 +0000598 return -1;
wdenkc6097192002-11-03 00:24:07 +0000599
Michael Walle391da4c2011-10-27 11:31:35 +0000600 return eth_current->index;
wdenkc6097192002-11-03 00:24:07 +0000601}
602
Simon Glass62b36c92011-06-13 16:13:10 -0700603int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
604 int eth_number)
605{
606 unsigned char env_enetaddr[6];
607 int ret = 0;
608
Eric Miaoae97ef62012-01-18 22:56:33 +0000609 eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
Simon Glass62b36c92011-06-13 16:13:10 -0700610
Joe Hershbergerca044ad2015-03-22 17:09:01 -0500611 if (!is_zero_ether_addr(env_enetaddr)) {
612 if (!is_zero_ether_addr(dev->enetaddr) &&
613 memcmp(dev->enetaddr, env_enetaddr, 6)) {
Simon Glass62b36c92011-06-13 16:13:10 -0700614 printf("\nWarning: %s MAC addresses don't match:\n",
615 dev->name);
616 printf("Address in SROM is %pM\n",
617 dev->enetaddr);
618 printf("Address in environment is %pM\n",
619 env_enetaddr);
620 }
621
622 memcpy(dev->enetaddr, env_enetaddr, 6);
Rob Herringc2938c02012-04-14 18:06:49 +0000623 } else if (is_valid_ether_addr(dev->enetaddr)) {
624 eth_setenv_enetaddr_by_index(base_name, eth_number,
625 dev->enetaddr);
626 printf("\nWarning: %s using MAC address from net device\n",
627 dev->name);
Joe Hershbergerca044ad2015-03-22 17:09:01 -0500628 } else if (is_zero_ether_addr(dev->enetaddr)) {
Pavel Machek222981f2014-07-13 10:27:02 +0200629 printf("\nError: %s address not set.\n",
630 dev->name);
631 return -EINVAL;
Simon Glass62b36c92011-06-13 16:13:10 -0700632 }
633
Pavel Machek222981f2014-07-13 10:27:02 +0200634 if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
635 if (!is_valid_ether_addr(dev->enetaddr)) {
636 printf("\nError: %s address %pM illegal value\n",
637 dev->name, dev->enetaddr);
638 return -EINVAL;
639 }
Benoît Thébaudeau050219e2012-08-10 07:56:21 +0000640
Simon Glass62b36c92011-06-13 16:13:10 -0700641 ret = dev->write_hwaddr(dev);
Pavel Machek222981f2014-07-13 10:27:02 +0200642 if (ret)
643 printf("\nWarning: %s failed to set MAC address\n", dev->name);
Benoît Thébaudeau050219e2012-08-10 07:56:21 +0000644 }
Simon Glass62b36c92011-06-13 16:13:10 -0700645
646 return ret;
647}
648
Simon Glass1e9961d2011-02-16 11:14:33 -0800649int eth_register(struct eth_device *dev)
650{
651 struct eth_device *d;
Joe Hershberger5956ded2012-05-15 08:59:07 +0000652 static int index;
Michal Simek5b4945b2011-08-29 23:30:13 +0000653
Mike Frysinger6b300dc2011-11-10 14:11:04 +0000654 assert(strlen(dev->name) < sizeof(dev->name));
Michal Simek5b4945b2011-08-29 23:30:13 +0000655
Simon Glass1e9961d2011-02-16 11:14:33 -0800656 if (!eth_devices) {
657 eth_current = eth_devices = dev;
658 eth_current_changed();
wdenkc6097192002-11-03 00:24:07 +0000659 } else {
Joe Hershberger5956ded2012-05-15 08:59:07 +0000660 for (d = eth_devices; d->next != eth_devices; d = d->next)
Detlev Zundeld46bcd32010-03-31 17:56:08 +0200661 ;
wdenkc6097192002-11-03 00:24:07 +0000662 d->next = dev;
663 }
664
665 dev->state = ETH_STATE_INIT;
666 dev->next = eth_devices;
Michael Walle391da4c2011-10-27 11:31:35 +0000667 dev->index = index++;
wdenkc6097192002-11-03 00:24:07 +0000668
669 return 0;
670}
671
Vincent Palatin451be502012-01-09 08:32:36 +0000672int eth_unregister(struct eth_device *dev)
673{
674 struct eth_device *cur;
675
676 /* No device */
677 if (!eth_devices)
Joe Hershbergerd0ce3412015-03-22 17:09:04 -0500678 return -ENODEV;
Vincent Palatin451be502012-01-09 08:32:36 +0000679
680 for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
681 cur = cur->next)
682 ;
683
684 /* Device not found */
685 if (cur->next != dev)
Joe Hershbergerd0ce3412015-03-22 17:09:04 -0500686 return -ENODEV;
Vincent Palatin451be502012-01-09 08:32:36 +0000687
688 cur->next = dev->next;
689
690 if (eth_devices == dev)
691 eth_devices = dev->next == eth_devices ? NULL : dev->next;
692
693 if (eth_current == dev) {
694 eth_current = eth_devices;
695 eth_current_changed();
696 }
697
698 return 0;
699}
700
Joe Hershberger3dbe17e2015-03-22 17:09:06 -0500701int eth_initialize(void)
wdenkc6097192002-11-03 00:24:07 +0000702{
Michael Walle391da4c2011-10-27 11:31:35 +0000703 int num_devices = 0;
wdenkc6097192002-11-03 00:24:07 +0000704 eth_devices = NULL;
705 eth_current = NULL;
706
Simon Glass0169e6b2012-02-13 13:51:18 +0000707 bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
Alexey Brodkin37ecfa12014-01-10 19:58:11 +0400708#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
Marian Balakowiczcbdd1c82005-11-30 18:06:04 +0100709 miiphy_init();
710#endif
Andy Flemingaecf6fc2011-04-08 02:10:27 -0500711
712#ifdef CONFIG_PHYLIB
713 phy_init();
714#endif
715
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500716 eth_env_init();
Mike Frysinger36fe7db2012-04-04 18:53:41 +0000717
Ben Warrencfdc8e02010-08-31 23:05:04 -0700718 /*
719 * If board-specific initialization exists, call it.
720 * If not, call a CPU-specific one
721 */
722 if (board_eth_init != __def_eth_init) {
Joe Hershberger3dbe17e2015-03-22 17:09:06 -0500723 if (board_eth_init(gd->bd) < 0)
Ben Warrencfdc8e02010-08-31 23:05:04 -0700724 printf("Board Net Initialization Failed\n");
725 } else if (cpu_eth_init != __def_eth_init) {
Joe Hershberger3dbe17e2015-03-22 17:09:06 -0500726 if (cpu_eth_init(gd->bd) < 0)
Ben Warrencfdc8e02010-08-31 23:05:04 -0700727 printf("CPU Net Initialization Failed\n");
728 } else
729 printf("Net Initialization Skipped\n");
Marian Balakowiczcbdd1c82005-11-30 18:06:04 +0100730
wdenkc6097192002-11-03 00:24:07 +0000731 if (!eth_devices) {
Joe Hershberger5956ded2012-05-15 08:59:07 +0000732 puts("No ethernet found.\n");
Simon Glass0169e6b2012-02-13 13:51:18 +0000733 bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
wdenkc6097192002-11-03 00:24:07 +0000734 } else {
735 struct eth_device *dev = eth_devices;
Joe Hershberger5956ded2012-05-15 08:59:07 +0000736 char *ethprime = getenv("ethprime");
wdenkc6097192002-11-03 00:24:07 +0000737
Simon Glass0169e6b2012-02-13 13:51:18 +0000738 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
wdenkc6097192002-11-03 00:24:07 +0000739 do {
Michael Walle391da4c2011-10-27 11:31:35 +0000740 if (dev->index)
Joe Hershberger5956ded2012-05-15 08:59:07 +0000741 puts(", ");
wdenkc6097192002-11-03 00:24:07 +0000742
743 printf("%s", dev->name);
744
Joe Hershberger5956ded2012-05-15 08:59:07 +0000745 if (ethprime && strcmp(dev->name, ethprime) == 0) {
wdenkc6097192002-11-03 00:24:07 +0000746 eth_current = dev;
Joe Hershberger5956ded2012-05-15 08:59:07 +0000747 puts(" [PRIME]");
wdenkc6097192002-11-03 00:24:07 +0000748 }
749
Mike Frysinger2843ed92010-06-09 22:10:48 -0400750 if (strchr(dev->name, ' '))
Joe Hershberger5956ded2012-05-15 08:59:07 +0000751 puts("\nWarning: eth device name has a space!"
752 "\n");
Mike Frysinger2843ed92010-06-09 22:10:48 -0400753
Pavel Machek222981f2014-07-13 10:27:02 +0200754 eth_write_hwaddr(dev, "eth", dev->index);
wdenkc6097192002-11-03 00:24:07 +0000755
wdenkc6097192002-11-03 00:24:07 +0000756 dev = dev->next;
Michael Walle391da4c2011-10-27 11:31:35 +0000757 num_devices++;
Joe Hershberger5956ded2012-05-15 08:59:07 +0000758 } while (dev != eth_devices);
wdenkc6097192002-11-03 00:24:07 +0000759
Simon Glass1e9961d2011-02-16 11:14:33 -0800760 eth_current_changed();
Joe Hershberger5956ded2012-05-15 08:59:07 +0000761 putc('\n');
wdenkc6097192002-11-03 00:24:07 +0000762 }
763
Michael Walle391da4c2011-10-27 11:31:35 +0000764 return num_devices;
wdenkc6097192002-11-03 00:24:07 +0000765}
766
David Updegraff7280da72007-06-11 10:41:07 -0500767#ifdef CONFIG_MCAST_TFTP
768/* Multicast.
769 * mcast_addr: multicast ipaddr from which multicast Mac is made
Wolfgang Denk627f5c32007-08-14 09:47:27 +0200770 * join: 1=join, 0=leave.
David Updegraff7280da72007-06-11 10:41:07 -0500771 */
Joe Hershberger5874dec2015-04-08 01:41:01 -0500772int eth_mcast_join(struct in_addr mcast_ip, int join)
David Updegraff7280da72007-06-11 10:41:07 -0500773{
Joe Hershberger5956ded2012-05-15 08:59:07 +0000774 u8 mcast_mac[6];
Wolfgang Denk627f5c32007-08-14 09:47:27 +0200775 if (!eth_current || !eth_current->mcast)
David Updegraff7280da72007-06-11 10:41:07 -0500776 return -1;
Joe Hershberger5874dec2015-04-08 01:41:01 -0500777 mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
778 mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
779 mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
David Updegraff7280da72007-06-11 10:41:07 -0500780 mcast_mac[2] = 0x5e;
781 mcast_mac[1] = 0x0;
782 mcast_mac[0] = 0x1;
783 return eth_current->mcast(eth_current, mcast_mac, join);
784}
785
Wolfgang Denk627f5c32007-08-14 09:47:27 +0200786/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
787 * and this is the ethernet-crc method needed for TSEC -- and perhaps
David Updegraff7280da72007-06-11 10:41:07 -0500788 * some other adapter -- hash tables
789 */
790#define CRCPOLY_LE 0xedb88320
Joe Hershberger5956ded2012-05-15 08:59:07 +0000791u32 ether_crc(size_t len, unsigned char const *p)
David Updegraff7280da72007-06-11 10:41:07 -0500792{
793 int i;
794 u32 crc;
795 crc = ~0;
796 while (len--) {
797 crc ^= *p++;
798 for (i = 0; i < 8; i++)
799 crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
800 }
801 /* an reverse the bits, cuz of way they arrive -- last-first */
802 crc = (crc >> 16) | (crc << 16);
803 crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
804 crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
805 crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
806 crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
807 return crc;
808}
wdenkc6097192002-11-03 00:24:07 +0000809
David Updegraff7280da72007-06-11 10:41:07 -0500810#endif
811
wdenkc6097192002-11-03 00:24:07 +0000812
Joe Hershberger3dbe17e2015-03-22 17:09:06 -0500813int eth_init(void)
wdenkc6097192002-11-03 00:24:07 +0000814{
Mike Frysingere129d562009-07-15 21:31:28 -0400815 struct eth_device *old_current, *dev;
wdenkc6097192002-11-03 00:24:07 +0000816
Stefan Roese11da2be2008-03-04 17:40:41 +0100817 if (!eth_current) {
Joe Hershberger5956ded2012-05-15 08:59:07 +0000818 puts("No ethernet found.\n");
Joe Hershbergerd0ce3412015-03-22 17:09:04 -0500819 return -ENODEV;
Stefan Roese11da2be2008-03-04 17:40:41 +0100820 }
wdenkc6097192002-11-03 00:24:07 +0000821
Mike Frysingere129d562009-07-15 21:31:28 -0400822 /* Sync environment with network devices */
Mike Frysingere129d562009-07-15 21:31:28 -0400823 dev = eth_devices;
824 do {
825 uchar env_enetaddr[6];
826
Michael Walle391da4c2011-10-27 11:31:35 +0000827 if (eth_getenv_enetaddr_by_index("eth", dev->index,
Simon Glass62b36c92011-06-13 16:13:10 -0700828 env_enetaddr))
Mike Frysingere129d562009-07-15 21:31:28 -0400829 memcpy(dev->enetaddr, env_enetaddr, 6);
830
Mike Frysingere129d562009-07-15 21:31:28 -0400831 dev = dev->next;
832 } while (dev != eth_devices);
833
wdenkc6097192002-11-03 00:24:07 +0000834 old_current = eth_current;
835 do {
Robin Getz9e0a4d62009-07-23 03:01:03 -0400836 debug("Trying %s\n", eth_current->name);
wdenkc6097192002-11-03 00:24:07 +0000837
Joe Hershberger3dbe17e2015-03-22 17:09:06 -0500838 if (eth_current->init(eth_current, gd->bd) >= 0) {
wdenkc6097192002-11-03 00:24:07 +0000839 eth_current->state = ETH_STATE_ACTIVE;
840
Upakul Barkakatyaed33582007-11-29 12:16:13 +0530841 return 0;
wdenkc6097192002-11-03 00:24:07 +0000842 }
Robin Getz9e0a4d62009-07-23 03:01:03 -0400843 debug("FAIL\n");
wdenkc6097192002-11-03 00:24:07 +0000844
845 eth_try_another(0);
846 } while (old_current != eth_current);
847
Joe Hershbergerd0ce3412015-03-22 17:09:04 -0500848 return -ETIMEDOUT;
wdenkc6097192002-11-03 00:24:07 +0000849}
850
851void eth_halt(void)
852{
853 if (!eth_current)
854 return;
855
856 eth_current->halt(eth_current);
857
858 eth_current->state = ETH_STATE_PASSIVE;
859}
860
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000861int eth_send(void *packet, int length)
wdenkc6097192002-11-03 00:24:07 +0000862{
863 if (!eth_current)
Joe Hershbergerd0ce3412015-03-22 17:09:04 -0500864 return -ENODEV;
wdenkc6097192002-11-03 00:24:07 +0000865
866 return eth_current->send(eth_current, packet, length);
867}
868
869int eth_rx(void)
870{
871 if (!eth_current)
Joe Hershbergerd0ce3412015-03-22 17:09:04 -0500872 return -ENODEV;
wdenkc6097192002-11-03 00:24:07 +0000873
874 return eth_current->recv(eth_current);
875}
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500876#endif /* ifndef CONFIG_DM_ETH */
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100877
878#ifdef CONFIG_API
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000879static void eth_save_packet(void *packet, int length)
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100880{
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000881 char *p = packet;
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100882 int i;
883
884 if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
885 return;
886
887 if (PKTSIZE < length)
888 return;
889
890 for (i = 0; i < length; i++)
891 eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
892
893 eth_rcv_bufs[eth_rcv_last].length = length;
894 eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
895}
896
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000897int eth_receive(void *packet, int length)
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100898{
Joe Hershberger4b7747e2012-05-15 08:59:04 +0000899 char *p = packet;
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100900 void *pp = push_packet;
901 int i;
902
903 if (eth_rcv_current == eth_rcv_last) {
904 push_packet = eth_save_packet;
905 eth_rx();
906 push_packet = pp;
907
908 if (eth_rcv_current == eth_rcv_last)
909 return -1;
910 }
911
Michael Walledf7c98a2012-06-22 11:24:28 +0000912 length = min(eth_rcv_bufs[eth_rcv_current].length, length);
Rafal Jaworowski1f2c9a42007-12-27 18:19:02 +0100913
914 for (i = 0; i < length; i++)
915 p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
916
917 eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
918 return length;
919}
920#endif /* CONFIG_API */
wdenkc6097192002-11-03 00:24:07 +0000921
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500922static void eth_current_changed(void)
923{
924 char *act = getenv("ethact");
925 /* update current ethernet name */
926 if (eth_get_dev()) {
927 if (act == NULL || strcmp(act, eth_get_name()) != 0)
928 setenv("ethact", eth_get_name());
929 }
930 /*
931 * remove the variable completely if there is no active
932 * interface
933 */
934 else if (act != NULL)
935 setenv("ethact", NULL);
936}
937
wdenkc6097192002-11-03 00:24:07 +0000938void eth_try_another(int first_restart)
939{
Joe Hershbergerc7eceaf2015-03-22 17:09:10 -0500940 static void *first_failed;
Remy Bohmer0fce5152011-02-19 20:15:14 +0100941 char *ethrotate;
Matthias Fuchs204f0ec2008-01-17 07:45:05 +0100942
943 /*
944 * Do not rotate between network interfaces when
945 * 'ethrotate' variable is set to 'no'.
946 */
Joe Hershberger5956ded2012-05-15 08:59:07 +0000947 ethrotate = getenv("ethrotate");
948 if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
Matthias Fuchs204f0ec2008-01-17 07:45:05 +0100949 return;
wdenkc6097192002-11-03 00:24:07 +0000950
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500951 if (!eth_get_dev())
wdenkc6097192002-11-03 00:24:07 +0000952 return;
953
Joe Hershberger5956ded2012-05-15 08:59:07 +0000954 if (first_restart)
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500955 first_failed = eth_get_dev();
wdenkc6097192002-11-03 00:24:07 +0000956
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500957 eth_set_current_to_next();
wdenkc6097192002-11-03 00:24:07 +0000958
Simon Glass1e9961d2011-02-16 11:14:33 -0800959 eth_current_changed();
wdenk145d2c12004-04-15 21:48:45 +0000960
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500961 if (first_failed == eth_get_dev())
wdenkc6097192002-11-03 00:24:07 +0000962 NetRestartWrap = 1;
wdenkc6097192002-11-03 00:24:07 +0000963}
964
wdenk145d2c12004-04-15 21:48:45 +0000965void eth_set_current(void)
966{
Joe Hershberger5956ded2012-05-15 08:59:07 +0000967 static char *act;
968 static int env_changed_id;
Heiko Schocher0c303fa2009-02-10 09:38:52 +0100969 int env_id;
wdenk145d2c12004-04-15 21:48:45 +0000970
Heiko Schocher0c303fa2009-02-10 09:38:52 +0100971 env_id = get_env_id();
972 if ((act == NULL) || (env_changed_id != env_id)) {
973 act = getenv("ethact");
974 env_changed_id = env_id;
975 }
Joe Hershbergeraa52edd2015-03-22 17:09:17 -0500976
977 if (act == NULL) {
978 char *ethprime = getenv("ethprime");
979 void *dev = NULL;
980
981 if (ethprime)
982 dev = eth_get_dev_by_name(ethprime);
983 if (dev)
984 eth_set_dev(dev);
985 else
986 eth_set_dev(NULL);
987 } else {
Joe Hershberger279d2f62015-03-22 17:09:16 -0500988 eth_set_dev(eth_get_dev_by_name(act));
Joe Hershbergeraa52edd2015-03-22 17:09:17 -0500989 }
wdenk145d2c12004-04-15 21:48:45 +0000990
Simon Glass1e9961d2011-02-16 11:14:33 -0800991 eth_current_changed();
wdenk145d2c12004-04-15 21:48:45 +0000992}
wdenk145d2c12004-04-15 21:48:45 +0000993
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500994const char *eth_get_name(void)
wdenkc6abb7e2003-11-17 21:14:37 +0000995{
Joe Hershbergere1e8a8c2015-03-22 17:09:03 -0500996 return eth_get_dev() ? eth_get_dev()->name : "unknown";
wdenkc6abb7e2003-11-17 21:14:37 +0000997}