]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - net/eth.c
dm: eth: Add support for ethprime env var
[karo-tx-uboot.git] / net / eth.c
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 <dm.h>
12 #include <net.h>
13 #include <miiphy.h>
14 #include <phy.h>
15 #include <asm/errno.h>
16 #include <dm/device-internal.h>
17
18 DECLARE_GLOBAL_DATA_PTR;
19
20 void 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
32 int eth_getenv_enetaddr(char *name, uchar *enetaddr)
33 {
34         eth_parse_enetaddr(getenv(name), enetaddr);
35         return is_valid_ether_addr(enetaddr);
36 }
37
38 int 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 }
46
47 int eth_getenv_enetaddr_by_index(const char *base_name, int index,
48                                  uchar *enetaddr)
49 {
50         char enetvar[32];
51         sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
52         return eth_getenv_enetaddr(enetvar, enetaddr);
53 }
54
55 static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
56                                  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
63 static void eth_env_init(void)
64 {
65         const char *s;
66
67         s = getenv("bootfile");
68         if (s != NULL)
69                 copy_filename(BootFile, s, sizeof(BootFile));
70 }
71
72 static int eth_mac_skip(int index)
73 {
74         char enetvar[15];
75         char *skip_state;
76         sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
77         return ((skip_state = getenv(enetvar)) != NULL);
78 }
79
80 static void eth_current_changed(void);
81
82 #ifdef CONFIG_DM_ETH
83 /**
84  * struct eth_device_priv - private structure for each Ethernet device
85  *
86  * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
87  */
88 struct eth_device_priv {
89         enum eth_state_t state;
90 };
91
92 /**
93  * struct eth_uclass_priv - The structure attached to the uclass itself
94  *
95  * @current: The Ethernet device that the network functions are using
96  */
97 struct eth_uclass_priv {
98         struct udevice *current;
99 };
100
101 static struct eth_uclass_priv *eth_get_uclass_priv(void)
102 {
103         struct uclass *uc;
104
105         uclass_get(UCLASS_ETH, &uc);
106         assert(uc);
107         return uc->priv;
108 }
109
110 static void eth_set_current_to_next(void)
111 {
112         struct eth_uclass_priv *uc_priv;
113
114         uc_priv = eth_get_uclass_priv();
115         if (uc_priv->current)
116                 uclass_next_device(&uc_priv->current);
117         if (!uc_priv->current)
118                 uclass_first_device(UCLASS_ETH, &uc_priv->current);
119 }
120
121 struct udevice *eth_get_dev(void)
122 {
123         struct eth_uclass_priv *uc_priv;
124
125         uc_priv = eth_get_uclass_priv();
126         if (!uc_priv->current)
127                 uclass_first_device(UCLASS_ETH,
128                                     &uc_priv->current);
129         return uc_priv->current;
130 }
131
132 static void eth_set_dev(struct udevice *dev)
133 {
134         device_probe(dev);
135         eth_get_uclass_priv()->current = dev;
136 }
137
138 /*
139  * Find the udevice that either has the name passed in as devname or has an
140  * alias named devname.
141  */
142 struct udevice *eth_get_dev_by_name(const char *devname)
143 {
144         int seq = -1;
145         char *endp = NULL;
146         const char *startp = NULL;
147         struct udevice *it;
148         struct uclass *uc;
149
150         /* Must be longer than 3 to be an alias */
151         if (strlen(devname) > strlen("eth")) {
152                 startp = devname + strlen("eth");
153                 seq = simple_strtoul(startp, &endp, 10);
154         }
155
156         uclass_get(UCLASS_ETH, &uc);
157         uclass_foreach_dev(it, uc) {
158                 /* We need the seq to be valid, so make sure it's probed */
159                 device_probe(it);
160                 /*
161                  * Check for the name or the sequence number to match
162                  */
163                 if (strcmp(it->name, devname) == 0 ||
164                     (endp > startp && it->seq == seq))
165                         return it;
166         }
167
168         return NULL;
169 }
170
171 unsigned char *eth_get_ethaddr(void)
172 {
173         struct eth_pdata *pdata;
174
175         if (eth_get_dev()) {
176                 pdata = eth_get_dev()->platdata;
177                 return pdata->enetaddr;
178         }
179
180         return NULL;
181 }
182
183 /* Set active state without calling start on the driver */
184 int eth_init_state_only(void)
185 {
186         struct udevice *current;
187         struct eth_device_priv *priv;
188
189         current = eth_get_dev();
190         if (!current || !device_active(current))
191                 return -EINVAL;
192
193         priv = current->uclass_priv;
194         priv->state = ETH_STATE_ACTIVE;
195
196         return 0;
197 }
198
199 /* Set passive state without calling stop on the driver */
200 void eth_halt_state_only(void)
201 {
202         struct udevice *current;
203         struct eth_device_priv *priv;
204
205         current = eth_get_dev();
206         if (!current || !device_active(current))
207                 return;
208
209         priv = current->uclass_priv;
210         priv->state = ETH_STATE_PASSIVE;
211 }
212
213 int eth_get_dev_index(void)
214 {
215         if (eth_get_dev())
216                 return eth_get_dev()->seq;
217         return -1;
218 }
219
220 int eth_init(void)
221 {
222         struct udevice *current;
223         struct udevice *old_current;
224
225         current = eth_get_dev();
226         if (!current) {
227                 printf("No ethernet found.\n");
228                 return -ENODEV;
229         }
230
231         old_current = current;
232         do {
233                 debug("Trying %s\n", current->name);
234
235                 if (device_active(current)) {
236                         uchar env_enetaddr[6];
237                         struct eth_pdata *pdata = current->platdata;
238
239                         /* Sync environment with network device */
240                         if (eth_getenv_enetaddr_by_index("eth", current->seq,
241                                                          env_enetaddr))
242                                 memcpy(pdata->enetaddr, env_enetaddr, 6);
243                         else
244                                 memset(pdata->enetaddr, 0, 6);
245
246                         if (eth_get_ops(current)->start(current) >= 0) {
247                                 struct eth_device_priv *priv =
248                                         current->uclass_priv;
249
250                                 priv->state = ETH_STATE_ACTIVE;
251                                 return 0;
252                         }
253                 }
254                 debug("FAIL\n");
255
256                 /* This will ensure the new "current" attempted to probe */
257                 eth_try_another(0);
258                 current = eth_get_dev();
259         } while (old_current != current);
260
261         return -ENODEV;
262 }
263
264 void eth_halt(void)
265 {
266         struct udevice *current;
267         struct eth_device_priv *priv;
268
269         current = eth_get_dev();
270         if (!current || !device_active(current))
271                 return;
272
273         eth_get_ops(current)->stop(current);
274         priv = current->uclass_priv;
275         priv->state = ETH_STATE_PASSIVE;
276 }
277
278 int eth_send(void *packet, int length)
279 {
280         struct udevice *current;
281
282         current = eth_get_dev();
283         if (!current)
284                 return -ENODEV;
285
286         if (!device_active(current))
287                 return -EINVAL;
288
289         return eth_get_ops(current)->send(current, packet, length);
290 }
291
292 int eth_rx(void)
293 {
294         struct udevice *current;
295         uchar *packet;
296         int ret;
297         int i;
298
299         current = eth_get_dev();
300         if (!current)
301                 return -ENODEV;
302
303         if (!device_active(current))
304                 return -EINVAL;
305
306         /* Process up to 32 packets at one time */
307         for (i = 0; i < 32; i++) {
308                 ret = eth_get_ops(current)->recv(current, &packet);
309                 if (ret > 0)
310                         net_process_received_packet(packet, ret);
311                 else
312                         break;
313         }
314         if (ret == -EAGAIN)
315                 ret = 0;
316         return ret;
317 }
318
319 static int eth_write_hwaddr(struct udevice *dev)
320 {
321         struct eth_pdata *pdata = dev->platdata;
322         int ret = 0;
323
324         if (!dev || !device_active(dev))
325                 return -EINVAL;
326
327         /* seq is valid since the device is active */
328         if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
329                 if (!is_valid_ether_addr(pdata->enetaddr)) {
330                         printf("\nError: %s address %pM illegal value\n",
331                                dev->name, pdata->enetaddr);
332                         return -EINVAL;
333                 }
334
335                 ret = eth_get_ops(dev)->write_hwaddr(dev);
336                 if (ret)
337                         printf("\nWarning: %s failed to set MAC address\n",
338                                dev->name);
339         }
340
341         return ret;
342 }
343
344 int eth_initialize(void)
345 {
346         int num_devices = 0;
347         struct udevice *dev;
348
349         bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
350         eth_env_init();
351
352         /*
353          * Devices need to write the hwaddr even if not started so that Linux
354          * will have access to the hwaddr that u-boot stored for the device.
355          * This is accomplished by attempting to probe each device and calling
356          * their write_hwaddr() operation.
357          */
358         uclass_first_device(UCLASS_ETH, &dev);
359         if (!dev) {
360                 printf("No ethernet found.\n");
361                 bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
362         } else {
363                 char *ethprime = getenv("ethprime");
364                 struct udevice *prime_dev = NULL;
365
366                 if (ethprime)
367                         prime_dev = eth_get_dev_by_name(ethprime);
368                 if (prime_dev) {
369                         eth_set_dev(prime_dev);
370                         eth_current_changed();
371                 } else {
372                         eth_set_dev(NULL);
373                 }
374
375                 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
376                 do {
377                         if (num_devices)
378                                 printf(", ");
379
380                         printf("eth%d: %s", dev->seq, dev->name);
381
382                         if (ethprime && dev == prime_dev)
383                                 printf(" [PRIME]");
384
385                         eth_write_hwaddr(dev);
386
387                         uclass_next_device(&dev);
388                         num_devices++;
389                 } while (dev);
390
391                 putc('\n');
392         }
393
394         return num_devices;
395 }
396
397 static int eth_post_bind(struct udevice *dev)
398 {
399         if (strchr(dev->name, ' ')) {
400                 printf("\nError: eth device name \"%s\" has a space!\n",
401                        dev->name);
402                 return -EINVAL;
403         }
404
405         return 0;
406 }
407
408 static int eth_pre_unbind(struct udevice *dev)
409 {
410         /* Don't hang onto a pointer that is going away */
411         if (dev == eth_get_uclass_priv()->current)
412                 eth_set_dev(NULL);
413
414         return 0;
415 }
416
417 static int eth_post_probe(struct udevice *dev)
418 {
419         struct eth_device_priv *priv = dev->uclass_priv;
420         struct eth_pdata *pdata = dev->platdata;
421         unsigned char env_enetaddr[6];
422
423         priv->state = ETH_STATE_INIT;
424
425         /* Check if the device has a MAC address in ROM */
426         if (eth_get_ops(dev)->read_rom_hwaddr)
427                 eth_get_ops(dev)->read_rom_hwaddr(dev);
428
429         eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
430         if (!is_zero_ether_addr(env_enetaddr)) {
431                 if (!is_zero_ether_addr(pdata->enetaddr) &&
432                     memcmp(pdata->enetaddr, env_enetaddr, 6)) {
433                         printf("\nWarning: %s MAC addresses don't match:\n",
434                                dev->name);
435                         printf("Address in SROM is         %pM\n",
436                                pdata->enetaddr);
437                         printf("Address in environment is  %pM\n",
438                                env_enetaddr);
439                 }
440
441                 /* Override the ROM MAC address */
442                 memcpy(pdata->enetaddr, env_enetaddr, 6);
443         } else if (is_valid_ether_addr(pdata->enetaddr)) {
444                 eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
445                 printf("\nWarning: %s using MAC address from ROM\n",
446                        dev->name);
447         } else if (is_zero_ether_addr(pdata->enetaddr)) {
448                 printf("\nError: %s address not set.\n",
449                        dev->name);
450                 return -EINVAL;
451         }
452
453         return 0;
454 }
455
456 static int eth_pre_remove(struct udevice *dev)
457 {
458         eth_get_ops(dev)->stop(dev);
459
460         return 0;
461 }
462
463 UCLASS_DRIVER(eth) = {
464         .name           = "eth",
465         .id             = UCLASS_ETH,
466         .post_bind      = eth_post_bind,
467         .pre_unbind     = eth_pre_unbind,
468         .post_probe     = eth_post_probe,
469         .pre_remove     = eth_pre_remove,
470         .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
471         .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
472         .flags          = DM_UC_FLAG_SEQ_ALIAS,
473 };
474 #endif
475
476 #ifndef CONFIG_DM_ETH
477 /*
478  * CPU and board-specific Ethernet initializations.  Aliased function
479  * signals caller to move on
480  */
481 static int __def_eth_init(bd_t *bis)
482 {
483         return -1;
484 }
485 int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
486 int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
487
488 #ifdef CONFIG_API
489 static struct {
490         uchar data[PKTSIZE];
491         int length;
492 } eth_rcv_bufs[PKTBUFSRX];
493
494 static unsigned int eth_rcv_current, eth_rcv_last;
495 #endif
496
497 static struct eth_device *eth_devices;
498 struct eth_device *eth_current;
499
500 static void eth_set_current_to_next(void)
501 {
502         eth_current = eth_current->next;
503 }
504
505 static void eth_set_dev(struct eth_device *dev)
506 {
507         eth_current = dev;
508 }
509
510 struct eth_device *eth_get_dev_by_name(const char *devname)
511 {
512         struct eth_device *dev, *target_dev;
513
514         BUG_ON(devname == NULL);
515
516         if (!eth_devices)
517                 return NULL;
518
519         dev = eth_devices;
520         target_dev = NULL;
521         do {
522                 if (strcmp(devname, dev->name) == 0) {
523                         target_dev = dev;
524                         break;
525                 }
526                 dev = dev->next;
527         } while (dev != eth_devices);
528
529         return target_dev;
530 }
531
532 struct eth_device *eth_get_dev_by_index(int index)
533 {
534         struct eth_device *dev, *target_dev;
535
536         if (!eth_devices)
537                 return NULL;
538
539         dev = eth_devices;
540         target_dev = NULL;
541         do {
542                 if (dev->index == index) {
543                         target_dev = dev;
544                         break;
545                 }
546                 dev = dev->next;
547         } while (dev != eth_devices);
548
549         return target_dev;
550 }
551
552 int eth_get_dev_index(void)
553 {
554         if (!eth_current)
555                 return -1;
556
557         return eth_current->index;
558 }
559
560 int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
561                    int eth_number)
562 {
563         unsigned char env_enetaddr[6];
564         int ret = 0;
565
566         eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
567
568         if (!is_zero_ether_addr(env_enetaddr)) {
569                 if (!is_zero_ether_addr(dev->enetaddr) &&
570                     memcmp(dev->enetaddr, env_enetaddr, 6)) {
571                         printf("\nWarning: %s MAC addresses don't match:\n",
572                                 dev->name);
573                         printf("Address in SROM is         %pM\n",
574                                 dev->enetaddr);
575                         printf("Address in environment is  %pM\n",
576                                 env_enetaddr);
577                 }
578
579                 memcpy(dev->enetaddr, env_enetaddr, 6);
580         } else if (is_valid_ether_addr(dev->enetaddr)) {
581                 eth_setenv_enetaddr_by_index(base_name, eth_number,
582                                              dev->enetaddr);
583                 printf("\nWarning: %s using MAC address from net device\n",
584                         dev->name);
585         } else if (is_zero_ether_addr(dev->enetaddr)) {
586                 printf("\nError: %s address not set.\n",
587                        dev->name);
588                 return -EINVAL;
589         }
590
591         if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
592                 if (!is_valid_ether_addr(dev->enetaddr)) {
593                         printf("\nError: %s address %pM illegal value\n",
594                                  dev->name, dev->enetaddr);
595                         return -EINVAL;
596                 }
597
598                 ret = dev->write_hwaddr(dev);
599                 if (ret)
600                         printf("\nWarning: %s failed to set MAC address\n", dev->name);
601         }
602
603         return ret;
604 }
605
606 int eth_register(struct eth_device *dev)
607 {
608         struct eth_device *d;
609         static int index;
610
611         assert(strlen(dev->name) < sizeof(dev->name));
612
613         if (!eth_devices) {
614                 eth_current = eth_devices = dev;
615                 eth_current_changed();
616         } else {
617                 for (d = eth_devices; d->next != eth_devices; d = d->next)
618                         ;
619                 d->next = dev;
620         }
621
622         dev->state = ETH_STATE_INIT;
623         dev->next  = eth_devices;
624         dev->index = index++;
625
626         return 0;
627 }
628
629 int eth_unregister(struct eth_device *dev)
630 {
631         struct eth_device *cur;
632
633         /* No device */
634         if (!eth_devices)
635                 return -ENODEV;
636
637         for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
638              cur = cur->next)
639                 ;
640
641         /* Device not found */
642         if (cur->next != dev)
643                 return -ENODEV;
644
645         cur->next = dev->next;
646
647         if (eth_devices == dev)
648                 eth_devices = dev->next == eth_devices ? NULL : dev->next;
649
650         if (eth_current == dev) {
651                 eth_current = eth_devices;
652                 eth_current_changed();
653         }
654
655         return 0;
656 }
657
658 int eth_initialize(void)
659 {
660         int num_devices = 0;
661         eth_devices = NULL;
662         eth_current = NULL;
663
664         bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
665 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
666         miiphy_init();
667 #endif
668
669 #ifdef CONFIG_PHYLIB
670         phy_init();
671 #endif
672
673         eth_env_init();
674
675         /*
676          * If board-specific initialization exists, call it.
677          * If not, call a CPU-specific one
678          */
679         if (board_eth_init != __def_eth_init) {
680                 if (board_eth_init(gd->bd) < 0)
681                         printf("Board Net Initialization Failed\n");
682         } else if (cpu_eth_init != __def_eth_init) {
683                 if (cpu_eth_init(gd->bd) < 0)
684                         printf("CPU Net Initialization Failed\n");
685         } else
686                 printf("Net Initialization Skipped\n");
687
688         if (!eth_devices) {
689                 puts("No ethernet found.\n");
690                 bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
691         } else {
692                 struct eth_device *dev = eth_devices;
693                 char *ethprime = getenv("ethprime");
694
695                 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
696                 do {
697                         if (dev->index)
698                                 puts(", ");
699
700                         printf("%s", dev->name);
701
702                         if (ethprime && strcmp(dev->name, ethprime) == 0) {
703                                 eth_current = dev;
704                                 puts(" [PRIME]");
705                         }
706
707                         if (strchr(dev->name, ' '))
708                                 puts("\nWarning: eth device name has a space!"
709                                         "\n");
710
711                         eth_write_hwaddr(dev, "eth", dev->index);
712
713                         dev = dev->next;
714                         num_devices++;
715                 } while (dev != eth_devices);
716
717                 eth_current_changed();
718                 putc('\n');
719         }
720
721         return num_devices;
722 }
723
724 #ifdef CONFIG_MCAST_TFTP
725 /* Multicast.
726  * mcast_addr: multicast ipaddr from which multicast Mac is made
727  * join: 1=join, 0=leave.
728  */
729 int eth_mcast_join(IPaddr_t mcast_ip, int join)
730 {
731         u8 mcast_mac[6];
732         if (!eth_current || !eth_current->mcast)
733                 return -1;
734         mcast_mac[5] = htonl(mcast_ip) & 0xff;
735         mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff;
736         mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f;
737         mcast_mac[2] = 0x5e;
738         mcast_mac[1] = 0x0;
739         mcast_mac[0] = 0x1;
740         return eth_current->mcast(eth_current, mcast_mac, join);
741 }
742
743 /* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
744  * and this is the ethernet-crc method needed for TSEC -- and perhaps
745  * some other adapter -- hash tables
746  */
747 #define CRCPOLY_LE 0xedb88320
748 u32 ether_crc(size_t len, unsigned char const *p)
749 {
750         int i;
751         u32 crc;
752         crc = ~0;
753         while (len--) {
754                 crc ^= *p++;
755                 for (i = 0; i < 8; i++)
756                         crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
757         }
758         /* an reverse the bits, cuz of way they arrive -- last-first */
759         crc = (crc >> 16) | (crc << 16);
760         crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
761         crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
762         crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
763         crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
764         return crc;
765 }
766
767 #endif
768
769
770 int eth_init(void)
771 {
772         struct eth_device *old_current, *dev;
773
774         if (!eth_current) {
775                 puts("No ethernet found.\n");
776                 return -ENODEV;
777         }
778
779         /* Sync environment with network devices */
780         dev = eth_devices;
781         do {
782                 uchar env_enetaddr[6];
783
784                 if (eth_getenv_enetaddr_by_index("eth", dev->index,
785                                                  env_enetaddr))
786                         memcpy(dev->enetaddr, env_enetaddr, 6);
787
788                 dev = dev->next;
789         } while (dev != eth_devices);
790
791         old_current = eth_current;
792         do {
793                 debug("Trying %s\n", eth_current->name);
794
795                 if (eth_current->init(eth_current, gd->bd) >= 0) {
796                         eth_current->state = ETH_STATE_ACTIVE;
797
798                         return 0;
799                 }
800                 debug("FAIL\n");
801
802                 eth_try_another(0);
803         } while (old_current != eth_current);
804
805         return -ETIMEDOUT;
806 }
807
808 void eth_halt(void)
809 {
810         if (!eth_current)
811                 return;
812
813         eth_current->halt(eth_current);
814
815         eth_current->state = ETH_STATE_PASSIVE;
816 }
817
818 int eth_send(void *packet, int length)
819 {
820         if (!eth_current)
821                 return -ENODEV;
822
823         return eth_current->send(eth_current, packet, length);
824 }
825
826 int eth_rx(void)
827 {
828         if (!eth_current)
829                 return -ENODEV;
830
831         return eth_current->recv(eth_current);
832 }
833 #endif /* ifndef CONFIG_DM_ETH */
834
835 #ifdef CONFIG_API
836 static void eth_save_packet(void *packet, int length)
837 {
838         char *p = packet;
839         int i;
840
841         if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
842                 return;
843
844         if (PKTSIZE < length)
845                 return;
846
847         for (i = 0; i < length; i++)
848                 eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
849
850         eth_rcv_bufs[eth_rcv_last].length = length;
851         eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
852 }
853
854 int eth_receive(void *packet, int length)
855 {
856         char *p = packet;
857         void *pp = push_packet;
858         int i;
859
860         if (eth_rcv_current == eth_rcv_last) {
861                 push_packet = eth_save_packet;
862                 eth_rx();
863                 push_packet = pp;
864
865                 if (eth_rcv_current == eth_rcv_last)
866                         return -1;
867         }
868
869         length = min(eth_rcv_bufs[eth_rcv_current].length, length);
870
871         for (i = 0; i < length; i++)
872                 p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
873
874         eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
875         return length;
876 }
877 #endif /* CONFIG_API */
878
879 static void eth_current_changed(void)
880 {
881         char *act = getenv("ethact");
882         /* update current ethernet name */
883         if (eth_get_dev()) {
884                 if (act == NULL || strcmp(act, eth_get_name()) != 0)
885                         setenv("ethact", eth_get_name());
886         }
887         /*
888          * remove the variable completely if there is no active
889          * interface
890          */
891         else if (act != NULL)
892                 setenv("ethact", NULL);
893 }
894
895 void eth_try_another(int first_restart)
896 {
897         static void *first_failed;
898         char *ethrotate;
899
900         /*
901          * Do not rotate between network interfaces when
902          * 'ethrotate' variable is set to 'no'.
903          */
904         ethrotate = getenv("ethrotate");
905         if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
906                 return;
907
908         if (!eth_get_dev())
909                 return;
910
911         if (first_restart)
912                 first_failed = eth_get_dev();
913
914         eth_set_current_to_next();
915
916         eth_current_changed();
917
918         if (first_failed == eth_get_dev())
919                 NetRestartWrap = 1;
920 }
921
922 void eth_set_current(void)
923 {
924         static char *act;
925         static int  env_changed_id;
926         int     env_id;
927
928         env_id = get_env_id();
929         if ((act == NULL) || (env_changed_id != env_id)) {
930                 act = getenv("ethact");
931                 env_changed_id = env_id;
932         }
933
934         if (act == NULL) {
935                 char *ethprime = getenv("ethprime");
936                 void *dev = NULL;
937
938                 if (ethprime)
939                         dev = eth_get_dev_by_name(ethprime);
940                 if (dev)
941                         eth_set_dev(dev);
942                 else
943                         eth_set_dev(NULL);
944         } else {
945                 eth_set_dev(eth_get_dev_by_name(act));
946         }
947
948         eth_current_changed();
949 }
950
951 const char *eth_get_name(void)
952 {
953         return eth_get_dev() ? eth_get_dev()->name : "unknown";
954 }