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