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