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