Blame view

net/eth.c 21.8 KB
c609719b8   wdenk   Initial revision
1
  /*
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
2
   * (C) Copyright 2001-2015
c609719b8   wdenk   Initial revision
3
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
4
   * Joe Hershberger, National Instruments
c609719b8   wdenk   Initial revision
5
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
6
   * SPDX-License-Identifier:	GPL-2.0+
c609719b8   wdenk   Initial revision
7
8
9
10
   */
  
  #include <common.h>
  #include <command.h>
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
11
  #include <dm.h>
6e0d26c05   Joe Hershberger   net: Handle ethad...
12
  #include <environment.h>
c609719b8   wdenk   Initial revision
13
  #include <net.h>
d9785c14b   Marian Balakowicz   Fix miiphy global...
14
  #include <miiphy.h>
5f184715e   Andy Fleming   Create PHY Lib fo...
15
  #include <phy.h>
75d9a45cb   Pavel Machek   Ethernet: let use...
16
  #include <asm/errno.h>
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
17
  #include <dm/device-internal.h>
6e0d26c05   Joe Hershberger   net: Handle ethad...
18
  #include <dm/uclass-internal.h>
c609719b8   wdenk   Initial revision
19

d2eaec600   Joe Hershberger   net: Remove the b...
20
  DECLARE_GLOBAL_DATA_PTR;
3f6e6993e   Mike Frysinger   net: new utility ...
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
  {
  	char *end;
  	int i;
  
  	for (i = 0; i < 6; ++i) {
  		enetaddr[i] = addr ? simple_strtoul(addr, &end, 16) : 0;
  		if (addr)
  			addr = (*end) ? end + 1 : end;
  	}
  }
  
  int eth_getenv_enetaddr(char *name, uchar *enetaddr)
  {
  	eth_parse_enetaddr(getenv(name), enetaddr);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
36
  	return is_valid_ethaddr(enetaddr);
3f6e6993e   Mike Frysinger   net: new utility ...
37
38
39
40
41
42
43
44
45
46
  }
  
  int eth_setenv_enetaddr(char *name, const uchar *enetaddr)
  {
  	char buf[20];
  
  	sprintf(buf, "%pM", enetaddr);
  
  	return setenv(name, buf);
  }
86848a74c   Mike Frysinger   net: sync env eth...
47

7616e7850   Simon Glass   Add Ethernet hard...
48
49
  int eth_getenv_enetaddr_by_index(const char *base_name, int index,
  				 uchar *enetaddr)
86848a74c   Mike Frysinger   net: sync env eth...
50
51
  {
  	char enetvar[32];
7616e7850   Simon Glass   Add Ethernet hard...
52
  	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
86848a74c   Mike Frysinger   net: sync env eth...
53
54
  	return eth_getenv_enetaddr(enetvar, enetaddr);
  }
3f6e6993e   Mike Frysinger   net: new utility ...
55

154177e14   Joe Hershberger   net: Inline the n...
56
  static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
c88ef3c12   Rob Herring   net: allow settin...
57
58
59
60
61
62
  				 uchar *enetaddr)
  {
  	char enetvar[32];
  	sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index);
  	return eth_setenv_enetaddr(enetvar, enetaddr);
  }
ecee9324d   Ben Warren   Program net devic...
63
64
65
66
  static int eth_mac_skip(int index)
  {
  	char enetvar[15];
  	char *skip_state;
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
67

ecee9324d   Ben Warren   Program net devic...
68
  	sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
69
70
  	skip_state = getenv(enetvar);
  	return skip_state != NULL;
ecee9324d   Ben Warren   Program net devic...
71
  }
84eb1fba7   Joe Hershberger   net: Refactor in ...
72
  static void eth_current_changed(void);
3bc427006   Simon Glass   dm: net: Use exis...
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  /*
   * CPU and board-specific Ethernet initializations.  Aliased function
   * signals caller to move on
   */
  static int __def_eth_init(bd_t *bis)
  {
  	return -1;
  }
  int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
  int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
  
  static void eth_common_init(void)
  {
  	bootstage_mark(BOOTSTAGE_ID_NET_ETH_START);
  #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
  	miiphy_init();
  #endif
  
  #ifdef CONFIG_PHYLIB
  	phy_init();
  #endif
3bc427006   Simon Glass   dm: net: Use exis...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  	/*
  	 * If board-specific initialization exists, call it.
  	 * If not, call a CPU-specific one
  	 */
  	if (board_eth_init != __def_eth_init) {
  		if (board_eth_init(gd->bd) < 0)
  			printf("Board Net Initialization Failed
  ");
  	} else if (cpu_eth_init != __def_eth_init) {
  		if (cpu_eth_init(gd->bd) < 0)
  			printf("CPU Net Initialization Failed
  ");
  	} else {
  		printf("Net Initialization Skipped
  ");
  	}
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
  #ifdef CONFIG_DM_ETH
  /**
   * struct eth_device_priv - private structure for each Ethernet device
   *
   * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t)
   */
  struct eth_device_priv {
  	enum eth_state_t state;
  };
  
  /**
   * struct eth_uclass_priv - The structure attached to the uclass itself
   *
   * @current: The Ethernet device that the network functions are using
   */
  struct eth_uclass_priv {
  	struct udevice *current;
  };
60304592b   Joe Hershberger   net: Improve erro...
129
130
  /* eth_errno - This stores the most recent failure code from DM functions */
  static int eth_errno;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
  static struct eth_uclass_priv *eth_get_uclass_priv(void)
  {
  	struct uclass *uc;
  
  	uclass_get(UCLASS_ETH, &uc);
  	assert(uc);
  	return uc->priv;
  }
  
  static void eth_set_current_to_next(void)
  {
  	struct eth_uclass_priv *uc_priv;
  
  	uc_priv = eth_get_uclass_priv();
  	if (uc_priv->current)
  		uclass_next_device(&uc_priv->current);
  	if (!uc_priv->current)
  		uclass_first_device(UCLASS_ETH, &uc_priv->current);
  }
60304592b   Joe Hershberger   net: Improve erro...
150
151
152
153
154
155
  /*
   * Typically this will simply return the active device.
   * In the case where the most recent active device was unset, this will attempt
   * to return the first device. If that device doesn't exist or fails to probe,
   * this function will return NULL.
   */
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
156
157
158
159
160
161
  struct udevice *eth_get_dev(void)
  {
  	struct eth_uclass_priv *uc_priv;
  
  	uc_priv = eth_get_uclass_priv();
  	if (!uc_priv->current)
60304592b   Joe Hershberger   net: Improve erro...
162
  		eth_errno = uclass_first_device(UCLASS_ETH,
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
163
164
165
  				    &uc_priv->current);
  	return uc_priv->current;
  }
60304592b   Joe Hershberger   net: Improve erro...
166
167
168
169
170
  /*
   * Typically this will just store a device pointer.
   * In case it was not probed, we will attempt to do so.
   * dev may be NULL to unset the active device.
   */
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
171
172
  static void eth_set_dev(struct udevice *dev)
  {
60304592b   Joe Hershberger   net: Improve erro...
173
174
  	if (dev && !device_active(dev))
  		eth_errno = device_probe(dev);
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
175
176
  	eth_get_uclass_priv()->current = dev;
  }
e58780dcb   Joe Hershberger   dm: eth: Add supp...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  /*
   * Find the udevice that either has the name passed in as devname or has an
   * alias named devname.
   */
  struct udevice *eth_get_dev_by_name(const char *devname)
  {
  	int seq = -1;
  	char *endp = NULL;
  	const char *startp = NULL;
  	struct udevice *it;
  	struct uclass *uc;
  
  	/* Must be longer than 3 to be an alias */
  	if (strlen(devname) > strlen("eth")) {
  		startp = devname + strlen("eth");
  		seq = simple_strtoul(startp, &endp, 10);
  	}
  
  	uclass_get(UCLASS_ETH, &uc);
  	uclass_foreach_dev(it, uc) {
60304592b   Joe Hershberger   net: Improve erro...
197
198
199
200
201
202
203
204
  		/*
  		 * We need the seq to be valid, so try to probe it.
  		 * If the probe fails, the seq will not match since it will be
  		 * -1 instead of what we are looking for.
  		 * We don't care about errors from probe here. Either they won't
  		 * match an alias or it will match a literal name and we'll pick
  		 * up the error when we try to probe again in eth_set_dev().
  		 */
e58780dcb   Joe Hershberger   dm: eth: Add supp...
205
206
207
208
209
210
211
212
213
214
215
  		device_probe(it);
  		/*
  		 * Check for the name or the sequence number to match
  		 */
  		if (strcmp(it->name, devname) == 0 ||
  		    (endp > startp && it->seq == seq))
  			return it;
  	}
  
  	return NULL;
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  unsigned char *eth_get_ethaddr(void)
  {
  	struct eth_pdata *pdata;
  
  	if (eth_get_dev()) {
  		pdata = eth_get_dev()->platdata;
  		return pdata->enetaddr;
  	}
  
  	return NULL;
  }
  
  /* Set active state without calling start on the driver */
  int eth_init_state_only(void)
  {
  	struct udevice *current;
  	struct eth_device_priv *priv;
  
  	current = eth_get_dev();
  	if (!current || !device_active(current))
  		return -EINVAL;
  
  	priv = current->uclass_priv;
  	priv->state = ETH_STATE_ACTIVE;
  
  	return 0;
  }
  
  /* Set passive state without calling stop on the driver */
  void eth_halt_state_only(void)
  {
  	struct udevice *current;
  	struct eth_device_priv *priv;
  
  	current = eth_get_dev();
  	if (!current || !device_active(current))
  		return;
  
  	priv = current->uclass_priv;
  	priv->state = ETH_STATE_PASSIVE;
  }
  
  int eth_get_dev_index(void)
  {
  	if (eth_get_dev())
  		return eth_get_dev()->seq;
  	return -1;
  }
f566c9949   Joe Hershberger   net: Update hardw...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  static int eth_write_hwaddr(struct udevice *dev)
  {
  	struct eth_pdata *pdata = dev->platdata;
  	int ret = 0;
  
  	if (!dev || !device_active(dev))
  		return -EINVAL;
  
  	/* seq is valid since the device is active */
  	if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) {
  		if (!is_valid_ethaddr(pdata->enetaddr)) {
  			printf("
  Error: %s address %pM illegal value
  ",
  			       dev->name, pdata->enetaddr);
  			return -EINVAL;
  		}
  
  		ret = eth_get_ops(dev)->write_hwaddr(dev);
  		if (ret)
  			printf("
  Warning: %s failed to set MAC address
  ",
  			       dev->name);
  	}
  
  	return ret;
  }
6e0d26c05   Joe Hershberger   net: Handle ethad...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  static int on_ethaddr(const char *name, const char *value, enum env_op op,
  	int flags)
  {
  	int index;
  	int retval;
  	struct udevice *dev;
  
  	/* look for an index after "eth" */
  	index = simple_strtoul(name + 3, NULL, 10);
  
  	retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev);
  	if (!retval) {
  		struct eth_pdata *pdata = dev->platdata;
  		switch (op) {
  		case env_op_create:
  		case env_op_overwrite:
  			eth_parse_enetaddr(value, pdata->enetaddr);
  			break;
  		case env_op_delete:
  			memset(pdata->enetaddr, 0, 6);
  		}
  	}
  
  	return 0;
  }
  U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
318
319
320
321
  int eth_init(void)
  {
  	struct udevice *current;
  	struct udevice *old_current;
60304592b   Joe Hershberger   net: Improve erro...
322
  	int ret = -ENODEV;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
  
  	current = eth_get_dev();
  	if (!current) {
  		printf("No ethernet found.
  ");
  		return -ENODEV;
  	}
  
  	old_current = current;
  	do {
  		debug("Trying %s
  ", current->name);
  
  		if (device_active(current)) {
60304592b   Joe Hershberger   net: Improve erro...
337
338
  			ret = eth_get_ops(current)->start(current);
  			if (ret >= 0) {
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
339
340
341
342
343
344
  				struct eth_device_priv *priv =
  					current->uclass_priv;
  
  				priv->state = ETH_STATE_ACTIVE;
  				return 0;
  			}
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
345
  		} else {
60304592b   Joe Hershberger   net: Improve erro...
346
  			ret = eth_errno;
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
347
  		}
60304592b   Joe Hershberger   net: Improve erro...
348

05c3e68f8   Joe Hershberger   dm: eth: Add basi...
349
350
  		debug("FAIL
  ");
60304592b   Joe Hershberger   net: Improve erro...
351
352
353
354
  		/*
  		 * If ethrotate is enabled, this will change "current",
  		 * otherwise we will drop out of this while loop immediately
  		 */
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
355
  		eth_try_another(0);
60304592b   Joe Hershberger   net: Improve erro...
356
  		/* This will ensure the new "current" attempted to probe */
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
357
358
  		current = eth_get_dev();
  	} while (old_current != current);
60304592b   Joe Hershberger   net: Improve erro...
359
  	return ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  }
  
  void eth_halt(void)
  {
  	struct udevice *current;
  	struct eth_device_priv *priv;
  
  	current = eth_get_dev();
  	if (!current || !device_active(current))
  		return;
  
  	eth_get_ops(current)->stop(current);
  	priv = current->uclass_priv;
  	priv->state = ETH_STATE_PASSIVE;
  }
  
  int eth_send(void *packet, int length)
  {
  	struct udevice *current;
60304592b   Joe Hershberger   net: Improve erro...
379
  	int ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
380
381
382
383
384
385
386
  
  	current = eth_get_dev();
  	if (!current)
  		return -ENODEV;
  
  	if (!device_active(current))
  		return -EINVAL;
60304592b   Joe Hershberger   net: Improve erro...
387
388
389
390
391
392
393
  	ret = eth_get_ops(current)->send(current, packet, length);
  	if (ret < 0) {
  		/* We cannot completely return the error at present */
  		debug("%s: send() returned error %d
  ", __func__, ret);
  	}
  	return ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
394
395
396
397
398
  }
  
  int eth_rx(void)
  {
  	struct udevice *current;
17591405a   Joe Hershberger   dm: eth: Pass the...
399
400
401
  	uchar *packet;
  	int ret;
  	int i;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
402
403
404
405
406
407
408
  
  	current = eth_get_dev();
  	if (!current)
  		return -ENODEV;
  
  	if (!device_active(current))
  		return -EINVAL;
17591405a   Joe Hershberger   dm: eth: Pass the...
409
410
411
412
413
  	/* Process up to 32 packets at one time */
  	for (i = 0; i < 32; i++) {
  		ret = eth_get_ops(current)->recv(current, &packet);
  		if (ret > 0)
  			net_process_received_packet(packet, ret);
63c9729a1   Joe Hershberger   dm: eth: Provide ...
414
415
416
  		if (ret >= 0 && eth_get_ops(current)->free_pkt)
  			eth_get_ops(current)->free_pkt(current, packet, ret);
  		if (ret <= 0)
17591405a   Joe Hershberger   dm: eth: Pass the...
417
418
419
420
  			break;
  	}
  	if (ret == -EAGAIN)
  		ret = 0;
60304592b   Joe Hershberger   net: Improve erro...
421
422
423
424
425
  	if (ret < 0) {
  		/* We cannot completely return the error at present */
  		debug("%s: recv() returned error %d
  ", __func__, ret);
  	}
17591405a   Joe Hershberger   dm: eth: Pass the...
426
  	return ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
427
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
428
429
430
431
  int eth_initialize(void)
  {
  	int num_devices = 0;
  	struct udevice *dev;
3bc427006   Simon Glass   dm: net: Use exis...
432
  	eth_common_init();
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
433
434
435
436
437
438
439
440
441
442
443
444
445
  
  	/*
  	 * Devices need to write the hwaddr even if not started so that Linux
  	 * will have access to the hwaddr that u-boot stored for the device.
  	 * This is accomplished by attempting to probe each device and calling
  	 * their write_hwaddr() operation.
  	 */
  	uclass_first_device(UCLASS_ETH, &dev);
  	if (!dev) {
  		printf("No ethernet found.
  ");
  		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
  	} else {
6536b9bb7   Joe Hershberger   dm: eth: Add supp...
446
447
448
449
450
451
452
453
454
455
456
  		char *ethprime = getenv("ethprime");
  		struct udevice *prime_dev = NULL;
  
  		if (ethprime)
  			prime_dev = eth_get_dev_by_name(ethprime);
  		if (prime_dev) {
  			eth_set_dev(prime_dev);
  			eth_current_changed();
  		} else {
  			eth_set_dev(NULL);
  		}
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
457
458
459
460
461
462
  		bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
  		do {
  			if (num_devices)
  				printf(", ");
  
  			printf("eth%d: %s", dev->seq, dev->name);
6536b9bb7   Joe Hershberger   dm: eth: Add supp...
463
464
  			if (ethprime && dev == prime_dev)
  				printf(" [PRIME]");
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  			eth_write_hwaddr(dev);
  
  			uclass_next_device(&dev);
  			num_devices++;
  		} while (dev);
  
  		putc('
  ');
  	}
  
  	return num_devices;
  }
  
  static int eth_post_bind(struct udevice *dev)
  {
  	if (strchr(dev->name, ' ')) {
  		printf("
  Error: eth device name \"%s\" has a space!
  ",
  		       dev->name);
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  static int eth_pre_unbind(struct udevice *dev)
  {
  	/* Don't hang onto a pointer that is going away */
  	if (dev == eth_get_uclass_priv()->current)
  		eth_set_dev(NULL);
  
  	return 0;
  }
  
  static int eth_post_probe(struct udevice *dev)
  {
  	struct eth_device_priv *priv = dev->uclass_priv;
  	struct eth_pdata *pdata = dev->platdata;
  	unsigned char env_enetaddr[6];
  
  	priv->state = ETH_STATE_INIT;
  
  	/* Check if the device has a MAC address in ROM */
  	if (eth_get_ops(dev)->read_rom_hwaddr)
  		eth_get_ops(dev)->read_rom_hwaddr(dev);
  
  	eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
513
514
  	if (!is_zero_ethaddr(env_enetaddr)) {
  		if (!is_zero_ethaddr(pdata->enetaddr) &&
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
  		    memcmp(pdata->enetaddr, env_enetaddr, 6)) {
  			printf("
  Warning: %s MAC addresses don't match:
  ",
  			       dev->name);
  			printf("Address in SROM is         %pM
  ",
  			       pdata->enetaddr);
  			printf("Address in environment is  %pM
  ",
  			       env_enetaddr);
  		}
  
  		/* Override the ROM MAC address */
  		memcpy(pdata->enetaddr, env_enetaddr, 6);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
530
  	} else if (is_valid_ethaddr(pdata->enetaddr)) {
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
531
532
533
534
535
  		eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr);
  		printf("
  Warning: %s using MAC address from ROM
  ",
  		       dev->name);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
536
  	} else if (is_zero_ethaddr(pdata->enetaddr)) {
bef1014b3   Joe Hershberger   net: Implement ra...
537
538
539
540
541
542
543
  #ifdef CONFIG_NET_RANDOM_ETHADDR
  		net_random_ethaddr(pdata->enetaddr);
  		printf("
  Warning: %s (eth%d) using random MAC address - %pM
  ",
  		       dev->name, dev->seq, pdata->enetaddr);
  #else
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
544
545
546
547
548
  		printf("
  Error: %s address not set.
  ",
  		       dev->name);
  		return -EINVAL;
bef1014b3   Joe Hershberger   net: Implement ra...
549
  #endif
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
  	}
  
  	return 0;
  }
  
  static int eth_pre_remove(struct udevice *dev)
  {
  	eth_get_ops(dev)->stop(dev);
  
  	return 0;
  }
  
  UCLASS_DRIVER(eth) = {
  	.name		= "eth",
  	.id		= UCLASS_ETH,
  	.post_bind	= eth_post_bind,
  	.pre_unbind	= eth_pre_unbind,
  	.post_probe	= eth_post_probe,
  	.pre_remove	= eth_pre_remove,
  	.priv_auto_alloc_size = sizeof(struct eth_uclass_priv),
  	.per_device_auto_alloc_size = sizeof(struct eth_device_priv),
e58780dcb   Joe Hershberger   dm: eth: Add supp...
571
  	.flags		= DM_UC_FLAG_SEQ_ALIAS,
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
572
573
574
575
  };
  #endif
  
  #ifndef CONFIG_DM_ETH
dd35479a5   Ben Warren   Add mechanisms fo...
576

f85b60710   Rafal Jaworowski   Introduce new eth...
577
  #ifdef CONFIG_API
f85b60710   Rafal Jaworowski   Introduce new eth...
578
579
580
581
  static struct {
  	uchar data[PKTSIZE];
  	int length;
  } eth_rcv_bufs[PKTBUFSRX];
66c7385a5   Joe Hershberger   net: cosmetic: et...
582
  static unsigned int eth_rcv_current, eth_rcv_last;
f85b60710   Rafal Jaworowski   Introduce new eth...
583
  #endif
f8be7d659   Joe Hershberger   net: Improve the ...
584
585
  static struct eth_device *eth_devices;
  struct eth_device *eth_current;
c609719b8   wdenk   Initial revision
586

84eb1fba7   Joe Hershberger   net: Refactor in ...
587
588
589
590
  static void eth_set_current_to_next(void)
  {
  	eth_current = eth_current->next;
  }
e58780dcb   Joe Hershberger   dm: eth: Add supp...
591
592
593
594
  static void eth_set_dev(struct eth_device *dev)
  {
  	eth_current = dev;
  }
d7fb9bcfb   Ben Warren   Fix compile warni...
595
  struct eth_device *eth_get_dev_by_name(const char *devname)
63ff004c4   Marian Balakowicz   Add support for m...
596
597
  {
  	struct eth_device *dev, *target_dev;
7e7f903fc   Helmut Raiger   net/eth.c: throw ...
598
  	BUG_ON(devname == NULL);
63ff004c4   Marian Balakowicz   Add support for m...
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
  	if (!eth_devices)
  		return NULL;
  
  	dev = eth_devices;
  	target_dev = NULL;
  	do {
  		if (strcmp(devname, dev->name) == 0) {
  			target_dev = dev;
  			break;
  		}
  		dev = dev->next;
  	} while (dev != eth_devices);
  
  	return target_dev;
  }
9e56986a2   Andy Fleming   Add eth_get_dev_b...
614
615
616
  struct eth_device *eth_get_dev_by_index(int index)
  {
  	struct eth_device *dev, *target_dev;
9e56986a2   Andy Fleming   Add eth_get_dev_b...
617
618
619
620
621
622
623
  
  	if (!eth_devices)
  		return NULL;
  
  	dev = eth_devices;
  	target_dev = NULL;
  	do {
fea7dcae5   Michael Walle   net: introduce pe...
624
  		if (dev->index == index) {
9e56986a2   Andy Fleming   Add eth_get_dev_b...
625
626
627
628
  			target_dev = dev;
  			break;
  		}
  		dev = dev->next;
9e56986a2   Andy Fleming   Add eth_get_dev_b...
629
630
631
632
  	} while (dev != eth_devices);
  
  	return target_dev;
  }
66c7385a5   Joe Hershberger   net: cosmetic: et...
633
  int eth_get_dev_index(void)
c609719b8   wdenk   Initial revision
634
  {
66c7385a5   Joe Hershberger   net: cosmetic: et...
635
  	if (!eth_current)
fea7dcae5   Michael Walle   net: introduce pe...
636
  		return -1;
c609719b8   wdenk   Initial revision
637

fea7dcae5   Michael Walle   net: introduce pe...
638
  	return eth_current->index;
c609719b8   wdenk   Initial revision
639
  }
6e0d26c05   Joe Hershberger   net: Handle ethad...
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  static int on_ethaddr(const char *name, const char *value, enum env_op op,
  	int flags)
  {
  	int index;
  	struct eth_device *dev;
  
  	if (!eth_devices)
  		return 0;
  
  	/* look for an index after "eth" */
  	index = simple_strtoul(name + 3, NULL, 10);
  
  	dev = eth_devices;
  	do {
  		if (dev->index == index) {
  			switch (op) {
  			case env_op_create:
  			case env_op_overwrite:
  				eth_parse_enetaddr(value, dev->enetaddr);
  				break;
  			case env_op_delete:
  				memset(dev->enetaddr, 0, 6);
  			}
  		}
  	} while (dev != eth_devices);
  
  	return 0;
  }
  U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
7616e7850   Simon Glass   Add Ethernet hard...
669
670
671
672
673
  int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
  		   int eth_number)
  {
  	unsigned char env_enetaddr[6];
  	int ret = 0;
693766442   Eric Miao   net/eth.c: fix et...
674
  	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
7616e7850   Simon Glass   Add Ethernet hard...
675

0adb5b761   Joe Hershberger   net: cosmetic: Na...
676
677
  	if (!is_zero_ethaddr(env_enetaddr)) {
  		if (!is_zero_ethaddr(dev->enetaddr) &&
4c7c65afb   Joe Hershberger   net: Rename helpe...
678
  		    memcmp(dev->enetaddr, env_enetaddr, 6)) {
7616e7850   Simon Glass   Add Ethernet hard...
679
680
681
  			printf("
  Warning: %s MAC addresses don't match:
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
682
  			       dev->name);
7616e7850   Simon Glass   Add Ethernet hard...
683
684
  			printf("Address in SROM is         %pM
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
685
  			       dev->enetaddr);
7616e7850   Simon Glass   Add Ethernet hard...
686
687
  			printf("Address in environment is  %pM
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
688
  			       env_enetaddr);
7616e7850   Simon Glass   Add Ethernet hard...
689
690
691
  		}
  
  		memcpy(dev->enetaddr, env_enetaddr, 6);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
692
  	} else if (is_valid_ethaddr(dev->enetaddr)) {
c88ef3c12   Rob Herring   net: allow settin...
693
694
695
696
697
  		eth_setenv_enetaddr_by_index(base_name, eth_number,
  					     dev->enetaddr);
  		printf("
  Warning: %s using MAC address from net device
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
698
  		       dev->name);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
699
  	} else if (is_zero_ethaddr(dev->enetaddr)) {
bef1014b3   Joe Hershberger   net: Implement ra...
700
701
702
703
704
705
706
  #ifdef CONFIG_NET_RANDOM_ETHADDR
  		net_random_ethaddr(dev->enetaddr);
  		printf("
  Warning: %s (eth%d) using random MAC address - %pM
  ",
  		       dev->name, eth_number, dev->enetaddr);
  #else
75d9a45cb   Pavel Machek   Ethernet: let use...
707
708
709
710
711
  		printf("
  Error: %s address not set.
  ",
  		       dev->name);
  		return -EINVAL;
bef1014b3   Joe Hershberger   net: Implement ra...
712
  #endif
7616e7850   Simon Glass   Add Ethernet hard...
713
  	}
75d9a45cb   Pavel Machek   Ethernet: let use...
714
  	if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
0adb5b761   Joe Hershberger   net: cosmetic: Na...
715
  		if (!is_valid_ethaddr(dev->enetaddr)) {
75d9a45cb   Pavel Machek   Ethernet: let use...
716
717
718
  			printf("
  Error: %s address %pM illegal value
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
719
  			       dev->name, dev->enetaddr);
75d9a45cb   Pavel Machek   Ethernet: let use...
720
721
  			return -EINVAL;
  		}
460f949f8   Benoît Thébaudeau   net: eth_write_hw...
722

7616e7850   Simon Glass   Add Ethernet hard...
723
  		ret = dev->write_hwaddr(dev);
75d9a45cb   Pavel Machek   Ethernet: let use...
724
  		if (ret)
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
725
726
727
728
  			printf("
  Warning: %s failed to set MAC address
  ",
  			       dev->name);
460f949f8   Benoît Thébaudeau   net: eth_write_hw...
729
  	}
7616e7850   Simon Glass   Add Ethernet hard...
730
731
732
  
  	return ret;
  }
89d48367e   Simon Glass   Add USB host ethe...
733
734
735
  int eth_register(struct eth_device *dev)
  {
  	struct eth_device *d;
66c7385a5   Joe Hershberger   net: cosmetic: et...
736
  	static int index;
58c583b6c   Michal Simek   net: Check networ...
737

f6add132f   Mike Frysinger   net/miiphy/serial...
738
  	assert(strlen(dev->name) < sizeof(dev->name));
58c583b6c   Michal Simek   net: Check networ...
739

89d48367e   Simon Glass   Add USB host ethe...
740
  	if (!eth_devices) {
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
741
742
  		eth_devices = dev;
  		eth_current = dev;
89d48367e   Simon Glass   Add USB host ethe...
743
  		eth_current_changed();
c609719b8   wdenk   Initial revision
744
  	} else {
66c7385a5   Joe Hershberger   net: cosmetic: et...
745
  		for (d = eth_devices; d->next != eth_devices; d = d->next)
aba4b69d0   Detlev Zundel   net: Trivial codi...
746
  			;
c609719b8   wdenk   Initial revision
747
748
749
750
751
  		d->next = dev;
  	}
  
  	dev->state = ETH_STATE_INIT;
  	dev->next  = eth_devices;
fea7dcae5   Michael Walle   net: introduce pe...
752
  	dev->index = index++;
c609719b8   wdenk   Initial revision
753
754
755
  
  	return 0;
  }
e7e982d69   Vincent Palatin   eth: remove usb-e...
756
757
758
759
760
761
  int eth_unregister(struct eth_device *dev)
  {
  	struct eth_device *cur;
  
  	/* No device */
  	if (!eth_devices)
05324a488   Joe Hershberger   net: Change retur...
762
  		return -ENODEV;
e7e982d69   Vincent Palatin   eth: remove usb-e...
763
764
765
766
767
768
769
  
  	for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
  	     cur = cur->next)
  		;
  
  	/* Device not found */
  	if (cur->next != dev)
05324a488   Joe Hershberger   net: Change retur...
770
  		return -ENODEV;
e7e982d69   Vincent Palatin   eth: remove usb-e...
771
772
773
774
775
776
777
778
779
780
781
782
783
  
  	cur->next = dev->next;
  
  	if (eth_devices == dev)
  		eth_devices = dev->next == eth_devices ? NULL : dev->next;
  
  	if (eth_current == dev) {
  		eth_current = eth_devices;
  		eth_current_changed();
  	}
  
  	return 0;
  }
d2eaec600   Joe Hershberger   net: Remove the b...
784
  int eth_initialize(void)
c609719b8   wdenk   Initial revision
785
  {
fea7dcae5   Michael Walle   net: introduce pe...
786
  	int num_devices = 0;
3bc427006   Simon Glass   dm: net: Use exis...
787

c609719b8   wdenk   Initial revision
788
789
  	eth_devices = NULL;
  	eth_current = NULL;
3bc427006   Simon Glass   dm: net: Use exis...
790
  	eth_common_init();
d9785c14b   Marian Balakowicz   Fix miiphy global...
791

c609719b8   wdenk   Initial revision
792
  	if (!eth_devices) {
66c7385a5   Joe Hershberger   net: cosmetic: et...
793
794
  		puts("No ethernet found.
  ");
770605e4f   Simon Glass   bootstage: Replac...
795
  		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
c609719b8   wdenk   Initial revision
796
797
  	} else {
  		struct eth_device *dev = eth_devices;
66c7385a5   Joe Hershberger   net: cosmetic: et...
798
  		char *ethprime = getenv("ethprime");
c609719b8   wdenk   Initial revision
799

770605e4f   Simon Glass   bootstage: Replac...
800
  		bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
c609719b8   wdenk   Initial revision
801
  		do {
fea7dcae5   Michael Walle   net: introduce pe...
802
  			if (dev->index)
66c7385a5   Joe Hershberger   net: cosmetic: et...
803
  				puts(", ");
c609719b8   wdenk   Initial revision
804
805
  
  			printf("%s", dev->name);
66c7385a5   Joe Hershberger   net: cosmetic: et...
806
  			if (ethprime && strcmp(dev->name, ethprime) == 0) {
c609719b8   wdenk   Initial revision
807
  				eth_current = dev;
66c7385a5   Joe Hershberger   net: cosmetic: et...
808
  				puts(" [PRIME]");
c609719b8   wdenk   Initial revision
809
  			}
1384f3bb8   Mike Frysinger   net: warn about s...
810
  			if (strchr(dev->name, ' '))
66c7385a5   Joe Hershberger   net: cosmetic: et...
811
812
813
814
  				puts("
  Warning: eth device name has a space!"
  					"
  ");
1384f3bb8   Mike Frysinger   net: warn about s...
815

75d9a45cb   Pavel Machek   Ethernet: let use...
816
  			eth_write_hwaddr(dev, "eth", dev->index);
c609719b8   wdenk   Initial revision
817

c609719b8   wdenk   Initial revision
818
  			dev = dev->next;
fea7dcae5   Michael Walle   net: introduce pe...
819
  			num_devices++;
66c7385a5   Joe Hershberger   net: cosmetic: et...
820
  		} while (dev != eth_devices);
c609719b8   wdenk   Initial revision
821

89d48367e   Simon Glass   Add USB host ethe...
822
  		eth_current_changed();
66c7385a5   Joe Hershberger   net: cosmetic: et...
823
824
  		putc('
  ');
c609719b8   wdenk   Initial revision
825
  	}
fea7dcae5   Michael Walle   net: introduce pe...
826
  	return num_devices;
c609719b8   wdenk   Initial revision
827
  }
53a5c424b   David Updegraff   multicast tftp: R...
828
829
830
  #ifdef CONFIG_MCAST_TFTP
  /* Multicast.
   * mcast_addr: multicast ipaddr from which multicast Mac is made
85eb5caf6   Wolfgang Denk   Coding style clea...
831
   * join: 1=join, 0=leave.
53a5c424b   David Updegraff   multicast tftp: R...
832
   */
049a95a77   Joe Hershberger   net: cosmetic: Ch...
833
  int eth_mcast_join(struct in_addr mcast_ip, int join)
53a5c424b   David Updegraff   multicast tftp: R...
834
  {
66c7385a5   Joe Hershberger   net: cosmetic: et...
835
  	u8 mcast_mac[6];
85eb5caf6   Wolfgang Denk   Coding style clea...
836
  	if (!eth_current || !eth_current->mcast)
53a5c424b   David Updegraff   multicast tftp: R...
837
  		return -1;
049a95a77   Joe Hershberger   net: cosmetic: Ch...
838
839
840
  	mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
  	mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
  	mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
53a5c424b   David Updegraff   multicast tftp: R...
841
842
843
844
845
  	mcast_mac[2] = 0x5e;
  	mcast_mac[1] = 0x0;
  	mcast_mac[0] = 0x1;
  	return eth_current->mcast(eth_current, mcast_mac, join);
  }
85eb5caf6   Wolfgang Denk   Coding style clea...
846
847
  /* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
   * and this is the ethernet-crc method needed for TSEC -- and perhaps
53a5c424b   David Updegraff   multicast tftp: R...
848
849
850
   * some other adapter -- hash tables
   */
  #define CRCPOLY_LE 0xedb88320
66c7385a5   Joe Hershberger   net: cosmetic: et...
851
  u32 ether_crc(size_t len, unsigned char const *p)
53a5c424b   David Updegraff   multicast tftp: R...
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
  {
  	int i;
  	u32 crc;
  	crc = ~0;
  	while (len--) {
  		crc ^= *p++;
  		for (i = 0; i < 8; i++)
  			crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
  	}
  	/* an reverse the bits, cuz of way they arrive -- last-first */
  	crc = (crc >> 16) | (crc << 16);
  	crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
  	crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
  	crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
  	crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
  	return crc;
  }
  
  #endif
c609719b8   wdenk   Initial revision
871

d2eaec600   Joe Hershberger   net: Remove the b...
872
  int eth_init(void)
c609719b8   wdenk   Initial revision
873
  {
6e0d26c05   Joe Hershberger   net: Handle ethad...
874
  	struct eth_device *old_current;
c609719b8   wdenk   Initial revision
875

6bc113886   Stefan Roese   net: Print error ...
876
  	if (!eth_current) {
66c7385a5   Joe Hershberger   net: cosmetic: et...
877
878
  		puts("No ethernet found.
  ");
05324a488   Joe Hershberger   net: Change retur...
879
  		return -ENODEV;
6bc113886   Stefan Roese   net: Print error ...
880
  	}
c609719b8   wdenk   Initial revision
881
882
883
  
  	old_current = eth_current;
  	do {
0ebf04c60   Robin Getz   minor debug clean...
884
885
  		debug("Trying %s
  ", eth_current->name);
c609719b8   wdenk   Initial revision
886

d2eaec600   Joe Hershberger   net: Remove the b...
887
  		if (eth_current->init(eth_current, gd->bd) >= 0) {
c609719b8   wdenk   Initial revision
888
  			eth_current->state = ETH_STATE_ACTIVE;
505be87a6   Upakul Barkakaty   NET: Proper retur...
889
  			return 0;
c609719b8   wdenk   Initial revision
890
  		}
0ebf04c60   Robin Getz   minor debug clean...
891
892
  		debug("FAIL
  ");
c609719b8   wdenk   Initial revision
893
894
895
  
  		eth_try_another(0);
  	} while (old_current != eth_current);
05324a488   Joe Hershberger   net: Change retur...
896
  	return -ETIMEDOUT;
c609719b8   wdenk   Initial revision
897
898
899
900
901
902
903
904
905
906
907
  }
  
  void eth_halt(void)
  {
  	if (!eth_current)
  		return;
  
  	eth_current->halt(eth_current);
  
  	eth_current->state = ETH_STATE_PASSIVE;
  }
db288a960   Joe Hershberger   net: Remove volat...
908
  int eth_send(void *packet, int length)
c609719b8   wdenk   Initial revision
909
910
  {
  	if (!eth_current)
05324a488   Joe Hershberger   net: Change retur...
911
  		return -ENODEV;
c609719b8   wdenk   Initial revision
912
913
914
915
916
917
918
  
  	return eth_current->send(eth_current, packet, length);
  }
  
  int eth_rx(void)
  {
  	if (!eth_current)
05324a488   Joe Hershberger   net: Change retur...
919
  		return -ENODEV;
c609719b8   wdenk   Initial revision
920
921
922
  
  	return eth_current->recv(eth_current);
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
923
  #endif /* ifndef CONFIG_DM_ETH */
c609719b8   wdenk   Initial revision
924

f85b60710   Rafal Jaworowski   Introduce new eth...
925
  #ifdef CONFIG_API
db288a960   Joe Hershberger   net: Remove volat...
926
  static void eth_save_packet(void *packet, int length)
f85b60710   Rafal Jaworowski   Introduce new eth...
927
  {
db288a960   Joe Hershberger   net: Remove volat...
928
  	char *p = packet;
f85b60710   Rafal Jaworowski   Introduce new eth...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  	int i;
  
  	if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
  		return;
  
  	if (PKTSIZE < length)
  		return;
  
  	for (i = 0; i < length; i++)
  		eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
  
  	eth_rcv_bufs[eth_rcv_last].length = length;
  	eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
  }
db288a960   Joe Hershberger   net: Remove volat...
943
  int eth_receive(void *packet, int length)
f85b60710   Rafal Jaworowski   Introduce new eth...
944
  {
db288a960   Joe Hershberger   net: Remove volat...
945
  	char *p = packet;
f85b60710   Rafal Jaworowski   Introduce new eth...
946
947
948
949
950
951
952
953
954
955
956
  	void *pp = push_packet;
  	int i;
  
  	if (eth_rcv_current == eth_rcv_last) {
  		push_packet = eth_save_packet;
  		eth_rx();
  		push_packet = pp;
  
  		if (eth_rcv_current == eth_rcv_last)
  			return -1;
  	}
46c07bcf1   Michael Walle   api: net: fix len...
957
  	length = min(eth_rcv_bufs[eth_rcv_current].length, length);
f85b60710   Rafal Jaworowski   Introduce new eth...
958
959
960
961
962
963
964
965
  
  	for (i = 0; i < length; i++)
  		p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
  
  	eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
  	return length;
  }
  #endif /* CONFIG_API */
84eb1fba7   Joe Hershberger   net: Refactor in ...
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
  static void eth_current_changed(void)
  {
  	char *act = getenv("ethact");
  	/* update current ethernet name */
  	if (eth_get_dev()) {
  		if (act == NULL || strcmp(act, eth_get_name()) != 0)
  			setenv("ethact", eth_get_name());
  	}
  	/*
  	 * remove the variable completely if there is no active
  	 * interface
  	 */
  	else if (act != NULL)
  		setenv("ethact", NULL);
  }
c609719b8   wdenk   Initial revision
981
982
  void eth_try_another(int first_restart)
  {
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
983
  	static void *first_failed;
c650e1be4   Remy Bohmer   Fix compile warni...
984
  	char *ethrotate;
e16925773   Matthias Fuchs   net: add 'ethrota...
985
986
987
988
989
  
  	/*
  	 * Do not rotate between network interfaces when
  	 * 'ethrotate' variable is set to 'no'.
  	 */
66c7385a5   Joe Hershberger   net: cosmetic: et...
990
991
  	ethrotate = getenv("ethrotate");
  	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
e16925773   Matthias Fuchs   net: add 'ethrota...
992
  		return;
c609719b8   wdenk   Initial revision
993

84eb1fba7   Joe Hershberger   net: Refactor in ...
994
  	if (!eth_get_dev())
c609719b8   wdenk   Initial revision
995
  		return;
66c7385a5   Joe Hershberger   net: cosmetic: et...
996
  	if (first_restart)
84eb1fba7   Joe Hershberger   net: Refactor in ...
997
  		first_failed = eth_get_dev();
c609719b8   wdenk   Initial revision
998

84eb1fba7   Joe Hershberger   net: Refactor in ...
999
  	eth_set_current_to_next();
c609719b8   wdenk   Initial revision
1000

89d48367e   Simon Glass   Add USB host ethe...
1001
  	eth_current_changed();
a3d991bd0   wdenk   Patches by Pantel...
1002

84eb1fba7   Joe Hershberger   net: Refactor in ...
1003
  	if (first_failed == eth_get_dev())
bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
1004
  		net_restart_wrap = 1;
c609719b8   wdenk   Initial revision
1005
  }
a3d991bd0   wdenk   Patches by Pantel...
1006
1007
  void eth_set_current(void)
  {
66c7385a5   Joe Hershberger   net: cosmetic: et...
1008
1009
  	static char *act;
  	static int  env_changed_id;
2f70c49e5   Heiko Schocher   netloop: speed up...
1010
  	int	env_id;
a3d991bd0   wdenk   Patches by Pantel...
1011

2f70c49e5   Heiko Schocher   netloop: speed up...
1012
1013
1014
1015
1016
  	env_id = get_env_id();
  	if ((act == NULL) || (env_changed_id != env_id)) {
  		act = getenv("ethact");
  		env_changed_id = env_id;
  	}
6536b9bb7   Joe Hershberger   dm: eth: Add supp...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  
  	if (act == NULL) {
  		char *ethprime = getenv("ethprime");
  		void *dev = NULL;
  
  		if (ethprime)
  			dev = eth_get_dev_by_name(ethprime);
  		if (dev)
  			eth_set_dev(dev);
  		else
  			eth_set_dev(NULL);
  	} else {
e58780dcb   Joe Hershberger   dm: eth: Add supp...
1029
  		eth_set_dev(eth_get_dev_by_name(act));
6536b9bb7   Joe Hershberger   dm: eth: Add supp...
1030
  	}
a3d991bd0   wdenk   Patches by Pantel...
1031

89d48367e   Simon Glass   Add USB host ethe...
1032
  	eth_current_changed();
a3d991bd0   wdenk   Patches by Pantel...
1033
  }
a3d991bd0   wdenk   Patches by Pantel...
1034

84eb1fba7   Joe Hershberger   net: Refactor in ...
1035
  const char *eth_get_name(void)
5bb226e82   wdenk   * Use "-fPIC" ins...
1036
  {
84eb1fba7   Joe Hershberger   net: Refactor in ...
1037
  	return eth_get_dev() ? eth_get_dev()->name : "unknown";
5bb226e82   wdenk   * Use "-fPIC" ins...
1038
  }