]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - net/eth.c
dm: eth: Add support for aliases
[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                 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
364                 do {
365                         if (num_devices)
366                                 printf(", ");
367
368                         printf("eth%d: %s", dev->seq, dev->name);
369
370                         eth_write_hwaddr(dev);
371
372                         uclass_next_device(&dev);
373                         num_devices++;
374                 } while (dev);
375
376                 putc('\n');
377         }
378
379         return num_devices;
380 }
381
382 static int eth_post_bind(struct udevice *dev)
383 {
384         if (strchr(dev->name, ' ')) {
385                 printf("\nError: eth device name \"%s\" has a space!\n",
386                        dev->name);
387                 return -EINVAL;
388         }
389
390         return 0;
391 }
392
393 static int eth_pre_unbind(struct udevice *dev)
394 {
395         /* Don't hang onto a pointer that is going away */
396         if (dev == eth_get_uclass_priv()->current)
397                 eth_set_dev(NULL);
398
399         return 0;
400 }
401
402 static int eth_post_probe(struct udevice *dev)
403 {
404         struct eth_device_priv *priv = dev->uclass_priv;
405         struct eth_pdata *pdata = dev->platdata;
406         unsigned char env_enetaddr[6];
407
408         priv->state = ETH_STATE_INIT;
409
410         /* Check if the device has a MAC address in ROM */
411         if (eth_get_ops(dev)->read_rom_hwaddr)
412                 eth_get_ops(dev)->read_rom_hwaddr(dev);
413
414         eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
415         if (!is_zero_ether_addr(env_enetaddr)) {
416                 if (!is_zero_ether_addr(pdata->enetaddr) &&
417                     memcmp(pdata->enetaddr, env_enetaddr, 6)) {
418                         printf("\nWarning: %s MAC addresses don't match:\n",
419                                dev->name);
420                         printf("Address in SROM is         %pM\n",
421                                pdata->enetaddr);
422                         printf("Address in environment is  %pM\n",
423                                env_enetaddr);
424                 }
425
426                 /* Override the ROM MAC address */
427                 memcpy(pdata->enetaddr, env_enetaddr, 6);
428         } else if (is_valid_ether_addr(pdata->enetaddr)) {
429                 eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
430                 printf("\nWarning: %s using MAC address from ROM\n",
431                        dev->name);
432         } else if (is_zero_ether_addr(pdata->enetaddr)) {
433                 printf("\nError: %s address not set.\n",
434                        dev->name);
435                 return -EINVAL;
436         }
437
438         return 0;
439 }
440
441 static int eth_pre_remove(struct udevice *dev)
442 {
443         eth_get_ops(dev)->stop(dev);
444
445         return 0;
446 }
447
448 UCLASS_DRIVER(eth) = {
449         .name           = "eth",
450         .id             = UCLASS_ETH,
451         .post_bind      = eth_post_bind,
452         .pre_unbind     = eth_pre_unbind,
453         .post_probe     = eth_post_probe,
454         .pre_remove     = eth_pre_remove,
455         .priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
456         .per_device_auto_alloc_size = sizeof(struct eth_device_priv),
457         .flags          = DM_UC_FLAG_SEQ_ALIAS,
458 };
459 #endif
460
461 #ifndef CONFIG_DM_ETH
462 /*
463  * CPU and board-specific Ethernet initializations.  Aliased function
464  * signals caller to move on
465  */
466 static int __def_eth_init(bd_t *bis)
467 {
468         return -1;
469 }
470 int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
471 int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
472
473 #ifdef CONFIG_API
474 static struct {
475         uchar data[PKTSIZE];
476         int length;
477 } eth_rcv_bufs[PKTBUFSRX];
478
479 static unsigned int eth_rcv_current, eth_rcv_last;
480 #endif
481
482 static struct eth_device *eth_devices;
483 struct eth_device *eth_current;
484
485 static void eth_set_current_to_next(void)
486 {
487         eth_current = eth_current->next;
488 }
489
490 static void eth_set_dev(struct eth_device *dev)
491 {
492         eth_current = dev;
493 }
494
495 struct eth_device *eth_get_dev_by_name(const char *devname)
496 {
497         struct eth_device *dev, *target_dev;
498
499         BUG_ON(devname == NULL);
500
501         if (!eth_devices)
502                 return NULL;
503
504         dev = eth_devices;
505         target_dev = NULL;
506         do {
507                 if (strcmp(devname, dev->name) == 0) {
508                         target_dev = dev;
509                         break;
510                 }
511                 dev = dev->next;
512         } while (dev != eth_devices);
513
514         return target_dev;
515 }
516
517 struct eth_device *eth_get_dev_by_index(int index)
518 {
519         struct eth_device *dev, *target_dev;
520
521         if (!eth_devices)
522                 return NULL;
523
524         dev = eth_devices;
525         target_dev = NULL;
526         do {
527                 if (dev->index == index) {
528                         target_dev = dev;
529                         break;
530                 }
531                 dev = dev->next;
532         } while (dev != eth_devices);
533
534         return target_dev;
535 }
536
537 int eth_get_dev_index(void)
538 {
539         if (!eth_current)
540                 return -1;
541
542         return eth_current->index;
543 }
544
545 int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
546                    int eth_number)
547 {
548         unsigned char env_enetaddr[6];
549         int ret = 0;
550
551         eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
552
553         if (!is_zero_ether_addr(env_enetaddr)) {
554                 if (!is_zero_ether_addr(dev->enetaddr) &&
555                     memcmp(dev->enetaddr, env_enetaddr, 6)) {
556                         printf("\nWarning: %s MAC addresses don't match:\n",
557                                 dev->name);
558                         printf("Address in SROM is         %pM\n",
559                                 dev->enetaddr);
560                         printf("Address in environment is  %pM\n",
561                                 env_enetaddr);
562                 }
563
564                 memcpy(dev->enetaddr, env_enetaddr, 6);
565         } else if (is_valid_ether_addr(dev->enetaddr)) {
566                 eth_setenv_enetaddr_by_index(base_name, eth_number,
567                                              dev->enetaddr);
568                 printf("\nWarning: %s using MAC address from net device\n",
569                         dev->name);
570         } else if (is_zero_ether_addr(dev->enetaddr)) {
571                 printf("\nError: %s address not set.\n",
572                        dev->name);
573                 return -EINVAL;
574         }
575
576         if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
577                 if (!is_valid_ether_addr(dev->enetaddr)) {
578                         printf("\nError: %s address %pM illegal value\n",
579                                  dev->name, dev->enetaddr);
580                         return -EINVAL;
581                 }
582
583                 ret = dev->write_hwaddr(dev);
584                 if (ret)
585                         printf("\nWarning: %s failed to set MAC address\n", dev->name);
586         }
587
588         return ret;
589 }
590
591 int eth_register(struct eth_device *dev)
592 {
593         struct eth_device *d;
594         static int index;
595
596         assert(strlen(dev->name) < sizeof(dev->name));
597
598         if (!eth_devices) {
599                 eth_current = eth_devices = dev;
600                 eth_current_changed();
601         } else {
602                 for (d = eth_devices; d->next != eth_devices; d = d->next)
603                         ;
604                 d->next = dev;
605         }
606
607         dev->state = ETH_STATE_INIT;
608         dev->next  = eth_devices;
609         dev->index = index++;
610
611         return 0;
612 }
613
614 int eth_unregister(struct eth_device *dev)
615 {
616         struct eth_device *cur;
617
618         /* No device */
619         if (!eth_devices)
620                 return -ENODEV;
621
622         for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
623              cur = cur->next)
624                 ;
625
626         /* Device not found */
627         if (cur->next != dev)
628                 return -ENODEV;
629
630         cur->next = dev->next;
631
632         if (eth_devices == dev)
633                 eth_devices = dev->next == eth_devices ? NULL : dev->next;
634
635         if (eth_current == dev) {
636                 eth_current = eth_devices;
637                 eth_current_changed();
638         }
639
640         return 0;
641 }
642
643 int eth_initialize(void)
644 {
645         int num_devices = 0;
646         eth_devices = NULL;
647         eth_current = NULL;
648
649         bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
650 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
651         miiphy_init();
652 #endif
653
654 #ifdef CONFIG_PHYLIB
655         phy_init();
656 #endif
657
658         eth_env_init();
659
660         /*
661          * If board-specific initialization exists, call it.
662          * If not, call a CPU-specific one
663          */
664         if (board_eth_init != __def_eth_init) {
665                 if (board_eth_init(gd->bd) < 0)
666                         printf("Board Net Initialization Failed\n");
667         } else if (cpu_eth_init != __def_eth_init) {
668                 if (cpu_eth_init(gd->bd) < 0)
669                         printf("CPU Net Initialization Failed\n");
670         } else
671                 printf("Net Initialization Skipped\n");
672
673         if (!eth_devices) {
674                 puts("No ethernet found.\n");
675                 bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
676         } else {
677                 struct eth_device *dev = eth_devices;
678                 char *ethprime = getenv("ethprime");
679
680                 bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
681                 do {
682                         if (dev->index)
683                                 puts(", ");
684
685                         printf("%s", dev->name);
686
687                         if (ethprime && strcmp(dev->name, ethprime) == 0) {
688                                 eth_current = dev;
689                                 puts(" [PRIME]");
690                         }
691
692                         if (strchr(dev->name, ' '))
693                                 puts("\nWarning: eth device name has a space!"
694                                         "\n");
695
696                         eth_write_hwaddr(dev, "eth", dev->index);
697
698                         dev = dev->next;
699                         num_devices++;
700                 } while (dev != eth_devices);
701
702                 eth_current_changed();
703                 putc('\n');
704         }
705
706         return num_devices;
707 }
708
709 #ifdef CONFIG_MCAST_TFTP
710 /* Multicast.
711  * mcast_addr: multicast ipaddr from which multicast Mac is made
712  * join: 1=join, 0=leave.
713  */
714 int eth_mcast_join(IPaddr_t mcast_ip, int join)
715 {
716         u8 mcast_mac[6];
717         if (!eth_current || !eth_current->mcast)
718                 return -1;
719         mcast_mac[5] = htonl(mcast_ip) & 0xff;
720         mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff;
721         mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f;
722         mcast_mac[2] = 0x5e;
723         mcast_mac[1] = 0x0;
724         mcast_mac[0] = 0x1;
725         return eth_current->mcast(eth_current, mcast_mac, join);
726 }
727
728 /* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
729  * and this is the ethernet-crc method needed for TSEC -- and perhaps
730  * some other adapter -- hash tables
731  */
732 #define CRCPOLY_LE 0xedb88320
733 u32 ether_crc(size_t len, unsigned char const *p)
734 {
735         int i;
736         u32 crc;
737         crc = ~0;
738         while (len--) {
739                 crc ^= *p++;
740                 for (i = 0; i < 8; i++)
741                         crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
742         }
743         /* an reverse the bits, cuz of way they arrive -- last-first */
744         crc = (crc >> 16) | (crc << 16);
745         crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
746         crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
747         crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
748         crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
749         return crc;
750 }
751
752 #endif
753
754
755 int eth_init(void)
756 {
757         struct eth_device *old_current, *dev;
758
759         if (!eth_current) {
760                 puts("No ethernet found.\n");
761                 return -ENODEV;
762         }
763
764         /* Sync environment with network devices */
765         dev = eth_devices;
766         do {
767                 uchar env_enetaddr[6];
768
769                 if (eth_getenv_enetaddr_by_index("eth", dev->index,
770                                                  env_enetaddr))
771                         memcpy(dev->enetaddr, env_enetaddr, 6);
772
773                 dev = dev->next;
774         } while (dev != eth_devices);
775
776         old_current = eth_current;
777         do {
778                 debug("Trying %s\n", eth_current->name);
779
780                 if (eth_current->init(eth_current, gd->bd) >= 0) {
781                         eth_current->state = ETH_STATE_ACTIVE;
782
783                         return 0;
784                 }
785                 debug("FAIL\n");
786
787                 eth_try_another(0);
788         } while (old_current != eth_current);
789
790         return -ETIMEDOUT;
791 }
792
793 void eth_halt(void)
794 {
795         if (!eth_current)
796                 return;
797
798         eth_current->halt(eth_current);
799
800         eth_current->state = ETH_STATE_PASSIVE;
801 }
802
803 int eth_send(void *packet, int length)
804 {
805         if (!eth_current)
806                 return -ENODEV;
807
808         return eth_current->send(eth_current, packet, length);
809 }
810
811 int eth_rx(void)
812 {
813         if (!eth_current)
814                 return -ENODEV;
815
816         return eth_current->recv(eth_current);
817 }
818 #endif /* ifndef CONFIG_DM_ETH */
819
820 #ifdef CONFIG_API
821 static void eth_save_packet(void *packet, int length)
822 {
823         char *p = packet;
824         int i;
825
826         if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
827                 return;
828
829         if (PKTSIZE < length)
830                 return;
831
832         for (i = 0; i < length; i++)
833                 eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
834
835         eth_rcv_bufs[eth_rcv_last].length = length;
836         eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
837 }
838
839 int eth_receive(void *packet, int length)
840 {
841         char *p = packet;
842         void *pp = push_packet;
843         int i;
844
845         if (eth_rcv_current == eth_rcv_last) {
846                 push_packet = eth_save_packet;
847                 eth_rx();
848                 push_packet = pp;
849
850                 if (eth_rcv_current == eth_rcv_last)
851                         return -1;
852         }
853
854         length = min(eth_rcv_bufs[eth_rcv_current].length, length);
855
856         for (i = 0; i < length; i++)
857                 p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
858
859         eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
860         return length;
861 }
862 #endif /* CONFIG_API */
863
864 static void eth_current_changed(void)
865 {
866         char *act = getenv("ethact");
867         /* update current ethernet name */
868         if (eth_get_dev()) {
869                 if (act == NULL || strcmp(act, eth_get_name()) != 0)
870                         setenv("ethact", eth_get_name());
871         }
872         /*
873          * remove the variable completely if there is no active
874          * interface
875          */
876         else if (act != NULL)
877                 setenv("ethact", NULL);
878 }
879
880 void eth_try_another(int first_restart)
881 {
882         static void *first_failed;
883         char *ethrotate;
884
885         /*
886          * Do not rotate between network interfaces when
887          * 'ethrotate' variable is set to 'no'.
888          */
889         ethrotate = getenv("ethrotate");
890         if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
891                 return;
892
893         if (!eth_get_dev())
894                 return;
895
896         if (first_restart)
897                 first_failed = eth_get_dev();
898
899         eth_set_current_to_next();
900
901         eth_current_changed();
902
903         if (first_failed == eth_get_dev())
904                 NetRestartWrap = 1;
905 }
906
907 void eth_set_current(void)
908 {
909         static char *act;
910         static int  env_changed_id;
911         int     env_id;
912
913         env_id = get_env_id();
914         if ((act == NULL) || (env_changed_id != env_id)) {
915                 act = getenv("ethact");
916                 env_changed_id = env_id;
917         }
918         if (act != NULL)
919                 eth_set_dev(eth_get_dev_by_name(act));
920
921         eth_current_changed();
922 }
923
924 const char *eth_get_name(void)
925 {
926         return eth_get_dev() ? eth_get_dev()->name : "unknown";
927 }