Blame view

net/eth.c 23.3 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
  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;
  	}
  }
219cc94a3   Josh Wu   net: change the e...
32
  int eth_getenv_enetaddr(const char *name, uchar *enetaddr)
3f6e6993e   Mike Frysinger   net: new utility ...
33
34
  {
  	eth_parse_enetaddr(getenv(name), enetaddr);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
35
  	return is_valid_ethaddr(enetaddr);
3f6e6993e   Mike Frysinger   net: new utility ...
36
  }
219cc94a3   Josh Wu   net: change the e...
37
  int eth_setenv_enetaddr(const char *name, const uchar *enetaddr)
3f6e6993e   Mike Frysinger   net: new utility ...
38
39
40
41
42
43
44
  {
  	char buf[20];
  
  	sprintf(buf, "%pM", enetaddr);
  
  	return setenv(name, buf);
  }
86848a74c   Mike Frysinger   net: sync env eth...
45

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

154177e14   Joe Hershberger   net: Inline the n...
54
  static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index,
c88ef3c12   Rob Herring   net: allow settin...
55
56
57
58
59
60
  				 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...
61
62
63
64
  static int eth_mac_skip(int index)
  {
  	char enetvar[15];
  	char *skip_state;
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
65

ecee9324d   Ben Warren   Program net devic...
66
  	sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index);
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
67
68
  	skip_state = getenv(enetvar);
  	return skip_state != NULL;
ecee9324d   Ben Warren   Program net devic...
69
  }
84eb1fba7   Joe Hershberger   net: Refactor in ...
70
  static void eth_current_changed(void);
3bc427006   Simon Glass   dm: net: Use exis...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  /*
   * 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...
92
93
94
95
96
97
98
99
100
101
102
103
104
  	/*
  	 * 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 {
d8f79afa0   Bin Meng   dm: eth: Do not p...
105
  #ifndef CONFIG_DM_ETH
3bc427006   Simon Glass   dm: net: Use exis...
106
107
  		printf("Net Initialization Skipped
  ");
d8f79afa0   Bin Meng   dm: eth: Do not p...
108
  #endif
3bc427006   Simon Glass   dm: net: Use exis...
109
110
  	}
  }
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)
  {
ac1d31380   Bin Meng   net: eth: Check r...
173
  	if (dev && !device_active(dev)) {
60304592b   Joe Hershberger   net: Improve erro...
174
  		eth_errno = device_probe(dev);
ac1d31380   Bin Meng   net: eth: Check r...
175
176
177
  		if (eth_errno)
  			dev = NULL;
  	}
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
178
179
  	eth_get_uclass_priv()->current = dev;
  }
e58780dcb   Joe Hershberger   dm: eth: Add supp...
180
181
182
183
184
185
186
187
188
189
190
  /*
   * 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;
e408c4218   Bin Meng   dm: eth: Correctl...
191
  	int len = strlen("eth");
e58780dcb   Joe Hershberger   dm: eth: Add supp...
192
193
  
  	/* Must be longer than 3 to be an alias */
e408c4218   Bin Meng   dm: eth: Correctl...
194
195
  	if (!strncmp(devname, "eth", len) && strlen(devname) > len) {
  		startp = devname + len;
e58780dcb   Joe Hershberger   dm: eth: Add supp...
196
197
198
199
200
  		seq = simple_strtoul(startp, &endp, 10);
  	}
  
  	uclass_get(UCLASS_ETH, &uc);
  	uclass_foreach_dev(it, uc) {
60304592b   Joe Hershberger   net: Improve erro...
201
202
203
204
205
206
207
208
  		/*
  		 * 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().
  		 */
ac1d31380   Bin Meng   net: eth: Check r...
209
210
211
  		if (device_probe(it))
  			continue;
  		/* Check for the name or the sequence number to match */
e58780dcb   Joe Hershberger   dm: eth: Add supp...
212
213
214
215
216
217
218
  		if (strcmp(it->name, devname) == 0 ||
  		    (endp > startp && it->seq == seq))
  			return it;
  	}
  
  	return NULL;
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
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
264
265
266
  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...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
  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;
  		}
b86f795a3   Simon Glass   net: Allow driver...
284
285
286
287
  		/*
  		 * Drivers are allowed to decide not to implement this at
  		 * run-time. E.g. Some devices may use it and some may not.
  		 */
f566c9949   Joe Hershberger   net: Update hardw...
288
  		ret = eth_get_ops(dev)->write_hwaddr(dev);
b86f795a3   Simon Glass   net: Allow driver...
289
290
  		if (ret == -ENOSYS)
  			ret = 0;
f566c9949   Joe Hershberger   net: Update hardw...
291
292
293
294
295
296
297
298
299
  		if (ret)
  			printf("
  Warning: %s failed to set MAC address
  ",
  			       dev->name);
  	}
  
  	return ret;
  }
6e0d26c05   Joe Hershberger   net: Handle ethad...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  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...
326
327
328
329
  int eth_init(void)
  {
  	struct udevice *current;
  	struct udevice *old_current;
60304592b   Joe Hershberger   net: Improve erro...
330
  	int ret = -ENODEV;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
331
332
333
334
335
336
337
338
339
340
  
  	current = eth_get_dev();
  	if (!current) {
  		printf("No ethernet found.
  ");
  		return -ENODEV;
  	}
  
  	old_current = current;
  	do {
ac1d31380   Bin Meng   net: eth: Check r...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  		if (current) {
  			debug("Trying %s
  ", current->name);
  
  			if (device_active(current)) {
  				ret = eth_get_ops(current)->start(current);
  				if (ret >= 0) {
  					struct eth_device_priv *priv =
  						current->uclass_priv;
  
  					priv->state = ETH_STATE_ACTIVE;
  					return 0;
  				}
  			} else {
  				ret = eth_errno;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
356
  			}
ac1d31380   Bin Meng   net: eth: Check r...
357
358
359
  
  			debug("FAIL
  ");
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
360
  		} else {
ac1d31380   Bin Meng   net: eth: Check r...
361
362
  			debug("PROBE FAIL
  ");
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
363
  		}
60304592b   Joe Hershberger   net: Improve erro...
364

60304592b   Joe Hershberger   net: Improve erro...
365
366
367
368
  		/*
  		 * 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...
369
  		eth_try_another(0);
60304592b   Joe Hershberger   net: Improve erro...
370
  		/* This will ensure the new "current" attempted to probe */
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
371
372
  		current = eth_get_dev();
  	} while (old_current != current);
60304592b   Joe Hershberger   net: Improve erro...
373
  	return ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  }
  
  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;
  }
eaa8a195c   Bernhard Nortmann   net: expose eth_i...
389
390
391
392
393
394
395
396
397
398
  int eth_is_active(struct udevice *dev)
  {
  	struct eth_device_priv *priv;
  
  	if (!dev || !device_active(dev))
  		return 0;
  
  	priv = dev_get_uclass_priv(dev);
  	return priv->state == ETH_STATE_ACTIVE;
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
399
400
401
  int eth_send(void *packet, int length)
  {
  	struct udevice *current;
60304592b   Joe Hershberger   net: Improve erro...
402
  	int ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
403
404
405
406
407
408
409
  
  	current = eth_get_dev();
  	if (!current)
  		return -ENODEV;
  
  	if (!device_active(current))
  		return -EINVAL;
60304592b   Joe Hershberger   net: Improve erro...
410
411
412
413
414
415
416
  	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...
417
418
419
420
421
  }
  
  int eth_rx(void)
  {
  	struct udevice *current;
17591405a   Joe Hershberger   dm: eth: Pass the...
422
  	uchar *packet;
a1ca92eaa   Simon Glass   dm: eth: Avoid bl...
423
  	int flags;
17591405a   Joe Hershberger   dm: eth: Pass the...
424
425
  	int ret;
  	int i;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
426
427
428
429
430
431
432
  
  	current = eth_get_dev();
  	if (!current)
  		return -ENODEV;
  
  	if (!device_active(current))
  		return -EINVAL;
17591405a   Joe Hershberger   dm: eth: Pass the...
433
  	/* Process up to 32 packets at one time */
a1ca92eaa   Simon Glass   dm: eth: Avoid bl...
434
  	flags = ETH_RECV_CHECK_DEVICE;
17591405a   Joe Hershberger   dm: eth: Pass the...
435
  	for (i = 0; i < 32; i++) {
a1ca92eaa   Simon Glass   dm: eth: Avoid bl...
436
437
  		ret = eth_get_ops(current)->recv(current, flags, &packet);
  		flags = 0;
17591405a   Joe Hershberger   dm: eth: Pass the...
438
439
  		if (ret > 0)
  			net_process_received_packet(packet, ret);
63c9729a1   Joe Hershberger   dm: eth: Provide ...
440
441
442
  		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...
443
444
445
446
  			break;
  	}
  	if (ret == -EAGAIN)
  		ret = 0;
60304592b   Joe Hershberger   net: Improve erro...
447
448
449
450
451
  	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...
452
  	return ret;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
453
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
454
455
456
457
  int eth_initialize(void)
  {
  	int num_devices = 0;
  	struct udevice *dev;
3bc427006   Simon Glass   dm: net: Use exis...
458
  	eth_common_init();
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
459
460
461
462
463
464
465
466
467
468
469
470
471
  
  	/*
  	 * 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...
472
473
474
475
476
477
478
479
480
481
482
  		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...
483
484
485
486
487
488
  		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...
489
490
  			if (ethprime && dev == prime_dev)
  				printf(" [PRIME]");
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
  			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];
94067580a   Michal Simek   dm: net: Fix DM f...
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
  #if defined(CONFIG_NEEDS_MANUAL_RELOC)
  	struct eth_ops *ops = eth_get_ops(dev);
  	static int reloc_done;
  
  	if (!reloc_done) {
  		if (ops->start)
  			ops->start += gd->reloc_off;
  		if (ops->send)
  			ops->send += gd->reloc_off;
  		if (ops->recv)
  			ops->recv += gd->reloc_off;
  		if (ops->free_pkt)
  			ops->free_pkt += gd->reloc_off;
  		if (ops->stop)
  			ops->stop += gd->reloc_off;
  #ifdef CONFIG_MCAST_TFTP
  		if (ops->mcast)
  			ops->mcast += gd->reloc_off;
  #endif
  		if (ops->write_hwaddr)
  			ops->write_hwaddr += gd->reloc_off;
  		if (ops->read_rom_hwaddr)
  			ops->read_rom_hwaddr += gd->reloc_off;
  
  		reloc_done++;
  	}
  #endif
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
558
559
560
561
562
563
564
  	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...
565
566
  	if (!is_zero_ethaddr(env_enetaddr)) {
  		if (!is_zero_ethaddr(pdata->enetaddr) &&
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  		    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...
582
  	} else if (is_valid_ethaddr(pdata->enetaddr)) {
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
583
584
585
586
587
  		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...
588
  	} else if (is_zero_ethaddr(pdata->enetaddr)) {
bef1014b3   Joe Hershberger   net: Implement ra...
589
590
591
592
593
594
595
  #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...
596
597
598
599
600
  		printf("
  Error: %s address not set.
  ",
  		       dev->name);
  		return -EINVAL;
bef1014b3   Joe Hershberger   net: Implement ra...
601
  #endif
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
602
603
604
605
606
607
608
  	}
  
  	return 0;
  }
  
  static int eth_pre_remove(struct udevice *dev)
  {
a16edabe7   Bin Meng   net: eth: Clear M...
609
  	struct eth_pdata *pdata = dev->platdata;
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
610
  	eth_get_ops(dev)->stop(dev);
a16edabe7   Bin Meng   net: eth: Clear M...
611
612
  	/* clear the MAC address */
  	memset(pdata->enetaddr, 0, 6);
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
613
614
615
616
617
618
619
620
621
622
623
624
  	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...
625
  	.flags		= DM_UC_FLAG_SEQ_ALIAS,
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
626
  };
eaa8a195c   Bernhard Nortmann   net: expose eth_i...
627
  #endif /* #ifdef CONFIG_DM_ETH */
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
628
629
  
  #ifndef CONFIG_DM_ETH
dd35479a5   Ben Warren   Add mechanisms fo...
630

f85b60710   Rafal Jaworowski   Introduce new eth...
631
  #ifdef CONFIG_API
f85b60710   Rafal Jaworowski   Introduce new eth...
632
633
634
635
  static struct {
  	uchar data[PKTSIZE];
  	int length;
  } eth_rcv_bufs[PKTBUFSRX];
66c7385a5   Joe Hershberger   net: cosmetic: et...
636
  static unsigned int eth_rcv_current, eth_rcv_last;
f85b60710   Rafal Jaworowski   Introduce new eth...
637
  #endif
f8be7d659   Joe Hershberger   net: Improve the ...
638
639
  static struct eth_device *eth_devices;
  struct eth_device *eth_current;
c609719b8   wdenk   Initial revision
640

84eb1fba7   Joe Hershberger   net: Refactor in ...
641
642
643
644
  static void eth_set_current_to_next(void)
  {
  	eth_current = eth_current->next;
  }
e58780dcb   Joe Hershberger   dm: eth: Add supp...
645
646
647
648
  static void eth_set_dev(struct eth_device *dev)
  {
  	eth_current = dev;
  }
d7fb9bcfb   Ben Warren   Fix compile warni...
649
  struct eth_device *eth_get_dev_by_name(const char *devname)
63ff004c4   Marian Balakowicz   Add support for m...
650
651
  {
  	struct eth_device *dev, *target_dev;
7e7f903fc   Helmut Raiger   net/eth.c: throw ...
652
  	BUG_ON(devname == NULL);
63ff004c4   Marian Balakowicz   Add support for m...
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  	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...
668
669
670
  struct eth_device *eth_get_dev_by_index(int index)
  {
  	struct eth_device *dev, *target_dev;
9e56986a2   Andy Fleming   Add eth_get_dev_b...
671
672
673
674
675
676
677
  
  	if (!eth_devices)
  		return NULL;
  
  	dev = eth_devices;
  	target_dev = NULL;
  	do {
fea7dcae5   Michael Walle   net: introduce pe...
678
  		if (dev->index == index) {
9e56986a2   Andy Fleming   Add eth_get_dev_b...
679
680
681
682
  			target_dev = dev;
  			break;
  		}
  		dev = dev->next;
9e56986a2   Andy Fleming   Add eth_get_dev_b...
683
684
685
686
  	} while (dev != eth_devices);
  
  	return target_dev;
  }
66c7385a5   Joe Hershberger   net: cosmetic: et...
687
  int eth_get_dev_index(void)
c609719b8   wdenk   Initial revision
688
  {
66c7385a5   Joe Hershberger   net: cosmetic: et...
689
  	if (!eth_current)
fea7dcae5   Michael Walle   net: introduce pe...
690
  		return -1;
c609719b8   wdenk   Initial revision
691

fea7dcae5   Michael Walle   net: introduce pe...
692
  	return eth_current->index;
c609719b8   wdenk   Initial revision
693
  }
6e0d26c05   Joe Hershberger   net: Handle ethad...
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
  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);
  			}
  		}
7aba0f2c2   Gong Qianyu   net/eth: fix a bu...
718
  		dev = dev->next;
6e0d26c05   Joe Hershberger   net: Handle ethad...
719
720
721
722
723
  	} while (dev != eth_devices);
  
  	return 0;
  }
  U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
7616e7850   Simon Glass   Add Ethernet hard...
724
725
726
727
728
  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...
729
  	eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
7616e7850   Simon Glass   Add Ethernet hard...
730

0adb5b761   Joe Hershberger   net: cosmetic: Na...
731
732
  	if (!is_zero_ethaddr(env_enetaddr)) {
  		if (!is_zero_ethaddr(dev->enetaddr) &&
4c7c65afb   Joe Hershberger   net: Rename helpe...
733
  		    memcmp(dev->enetaddr, env_enetaddr, 6)) {
7616e7850   Simon Glass   Add Ethernet hard...
734
735
736
  			printf("
  Warning: %s MAC addresses don't match:
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
737
  			       dev->name);
7616e7850   Simon Glass   Add Ethernet hard...
738
739
  			printf("Address in SROM is         %pM
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
740
  			       dev->enetaddr);
7616e7850   Simon Glass   Add Ethernet hard...
741
742
  			printf("Address in environment is  %pM
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
743
  			       env_enetaddr);
7616e7850   Simon Glass   Add Ethernet hard...
744
745
746
  		}
  
  		memcpy(dev->enetaddr, env_enetaddr, 6);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
747
  	} else if (is_valid_ethaddr(dev->enetaddr)) {
c88ef3c12   Rob Herring   net: allow settin...
748
749
750
751
752
  		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...
753
  		       dev->name);
0adb5b761   Joe Hershberger   net: cosmetic: Na...
754
  	} else if (is_zero_ethaddr(dev->enetaddr)) {
bef1014b3   Joe Hershberger   net: Implement ra...
755
756
757
758
759
760
761
  #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...
762
763
764
765
766
  		printf("
  Error: %s address not set.
  ",
  		       dev->name);
  		return -EINVAL;
bef1014b3   Joe Hershberger   net: Implement ra...
767
  #endif
7616e7850   Simon Glass   Add Ethernet hard...
768
  	}
75d9a45cb   Pavel Machek   Ethernet: let use...
769
  	if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
0adb5b761   Joe Hershberger   net: cosmetic: Na...
770
  		if (!is_valid_ethaddr(dev->enetaddr)) {
75d9a45cb   Pavel Machek   Ethernet: let use...
771
772
773
  			printf("
  Error: %s address %pM illegal value
  ",
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
774
  			       dev->name, dev->enetaddr);
75d9a45cb   Pavel Machek   Ethernet: let use...
775
776
  			return -EINVAL;
  		}
460f949f8   Benoît Thébaudeau   net: eth_write_hw...
777

7616e7850   Simon Glass   Add Ethernet hard...
778
  		ret = dev->write_hwaddr(dev);
75d9a45cb   Pavel Machek   Ethernet: let use...
779
  		if (ret)
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
780
781
782
783
  			printf("
  Warning: %s failed to set MAC address
  ",
  			       dev->name);
460f949f8   Benoît Thébaudeau   net: eth_write_hw...
784
  	}
7616e7850   Simon Glass   Add Ethernet hard...
785
786
787
  
  	return ret;
  }
89d48367e   Simon Glass   Add USB host ethe...
788
789
790
  int eth_register(struct eth_device *dev)
  {
  	struct eth_device *d;
66c7385a5   Joe Hershberger   net: cosmetic: et...
791
  	static int index;
58c583b6c   Michal Simek   net: Check networ...
792

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

89d48367e   Simon Glass   Add USB host ethe...
795
  	if (!eth_devices) {
ff819a3a3   Joe Hershberger   net: cosmetic: Fi...
796
797
  		eth_devices = dev;
  		eth_current = dev;
89d48367e   Simon Glass   Add USB host ethe...
798
  		eth_current_changed();
c609719b8   wdenk   Initial revision
799
  	} else {
66c7385a5   Joe Hershberger   net: cosmetic: et...
800
  		for (d = eth_devices; d->next != eth_devices; d = d->next)
aba4b69d0   Detlev Zundel   net: Trivial codi...
801
  			;
c609719b8   wdenk   Initial revision
802
803
804
805
806
  		d->next = dev;
  	}
  
  	dev->state = ETH_STATE_INIT;
  	dev->next  = eth_devices;
fea7dcae5   Michael Walle   net: introduce pe...
807
  	dev->index = index++;
c609719b8   wdenk   Initial revision
808
809
810
  
  	return 0;
  }
e7e982d69   Vincent Palatin   eth: remove usb-e...
811
812
813
814
815
816
  int eth_unregister(struct eth_device *dev)
  {
  	struct eth_device *cur;
  
  	/* No device */
  	if (!eth_devices)
05324a488   Joe Hershberger   net: Change retur...
817
  		return -ENODEV;
e7e982d69   Vincent Palatin   eth: remove usb-e...
818
819
820
821
822
823
824
  
  	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...
825
  		return -ENODEV;
e7e982d69   Vincent Palatin   eth: remove usb-e...
826
827
828
829
830
831
832
833
834
835
836
837
838
  
  	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...
839
  int eth_initialize(void)
c609719b8   wdenk   Initial revision
840
  {
fea7dcae5   Michael Walle   net: introduce pe...
841
  	int num_devices = 0;
3bc427006   Simon Glass   dm: net: Use exis...
842

c609719b8   wdenk   Initial revision
843
844
  	eth_devices = NULL;
  	eth_current = NULL;
3bc427006   Simon Glass   dm: net: Use exis...
845
  	eth_common_init();
d9785c14b   Marian Balakowicz   Fix miiphy global...
846

c609719b8   wdenk   Initial revision
847
  	if (!eth_devices) {
66c7385a5   Joe Hershberger   net: cosmetic: et...
848
849
  		puts("No ethernet found.
  ");
770605e4f   Simon Glass   bootstage: Replac...
850
  		bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
c609719b8   wdenk   Initial revision
851
852
  	} else {
  		struct eth_device *dev = eth_devices;
66c7385a5   Joe Hershberger   net: cosmetic: et...
853
  		char *ethprime = getenv("ethprime");
c609719b8   wdenk   Initial revision
854

770605e4f   Simon Glass   bootstage: Replac...
855
  		bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
c609719b8   wdenk   Initial revision
856
  		do {
fea7dcae5   Michael Walle   net: introduce pe...
857
  			if (dev->index)
66c7385a5   Joe Hershberger   net: cosmetic: et...
858
  				puts(", ");
c609719b8   wdenk   Initial revision
859
860
  
  			printf("%s", dev->name);
66c7385a5   Joe Hershberger   net: cosmetic: et...
861
  			if (ethprime && strcmp(dev->name, ethprime) == 0) {
c609719b8   wdenk   Initial revision
862
  				eth_current = dev;
66c7385a5   Joe Hershberger   net: cosmetic: et...
863
  				puts(" [PRIME]");
c609719b8   wdenk   Initial revision
864
  			}
1384f3bb8   Mike Frysinger   net: warn about s...
865
  			if (strchr(dev->name, ' '))
66c7385a5   Joe Hershberger   net: cosmetic: et...
866
867
868
869
  				puts("
  Warning: eth device name has a space!"
  					"
  ");
1384f3bb8   Mike Frysinger   net: warn about s...
870

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

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

89d48367e   Simon Glass   Add USB host ethe...
877
  		eth_current_changed();
66c7385a5   Joe Hershberger   net: cosmetic: et...
878
879
  		putc('
  ');
c609719b8   wdenk   Initial revision
880
  	}
fea7dcae5   Michael Walle   net: introduce pe...
881
  	return num_devices;
c609719b8   wdenk   Initial revision
882
  }
53a5c424b   David Updegraff   multicast tftp: R...
883
884
885
  #ifdef CONFIG_MCAST_TFTP
  /* Multicast.
   * mcast_addr: multicast ipaddr from which multicast Mac is made
85eb5caf6   Wolfgang Denk   Coding style clea...
886
   * join: 1=join, 0=leave.
53a5c424b   David Updegraff   multicast tftp: R...
887
   */
049a95a77   Joe Hershberger   net: cosmetic: Ch...
888
  int eth_mcast_join(struct in_addr mcast_ip, int join)
53a5c424b   David Updegraff   multicast tftp: R...
889
  {
66c7385a5   Joe Hershberger   net: cosmetic: et...
890
  	u8 mcast_mac[6];
85eb5caf6   Wolfgang Denk   Coding style clea...
891
  	if (!eth_current || !eth_current->mcast)
53a5c424b   David Updegraff   multicast tftp: R...
892
  		return -1;
049a95a77   Joe Hershberger   net: cosmetic: Ch...
893
894
895
  	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...
896
897
898
899
900
  	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...
901
902
  /* 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...
903
904
905
   * some other adapter -- hash tables
   */
  #define CRCPOLY_LE 0xedb88320
66c7385a5   Joe Hershberger   net: cosmetic: et...
906
  u32 ether_crc(size_t len, unsigned char const *p)
53a5c424b   David Updegraff   multicast tftp: R...
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
  {
  	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
926

d2eaec600   Joe Hershberger   net: Remove the b...
927
  int eth_init(void)
c609719b8   wdenk   Initial revision
928
  {
6e0d26c05   Joe Hershberger   net: Handle ethad...
929
  	struct eth_device *old_current;
c609719b8   wdenk   Initial revision
930

6bc113886   Stefan Roese   net: Print error ...
931
  	if (!eth_current) {
66c7385a5   Joe Hershberger   net: cosmetic: et...
932
933
  		puts("No ethernet found.
  ");
05324a488   Joe Hershberger   net: Change retur...
934
  		return -ENODEV;
6bc113886   Stefan Roese   net: Print error ...
935
  	}
c609719b8   wdenk   Initial revision
936
937
938
  
  	old_current = eth_current;
  	do {
0ebf04c60   Robin Getz   minor debug clean...
939
940
  		debug("Trying %s
  ", eth_current->name);
c609719b8   wdenk   Initial revision
941

d2eaec600   Joe Hershberger   net: Remove the b...
942
  		if (eth_current->init(eth_current, gd->bd) >= 0) {
c609719b8   wdenk   Initial revision
943
  			eth_current->state = ETH_STATE_ACTIVE;
505be87a6   Upakul Barkakaty   NET: Proper retur...
944
  			return 0;
c609719b8   wdenk   Initial revision
945
  		}
0ebf04c60   Robin Getz   minor debug clean...
946
947
  		debug("FAIL
  ");
c609719b8   wdenk   Initial revision
948
949
950
  
  		eth_try_another(0);
  	} while (old_current != eth_current);
05324a488   Joe Hershberger   net: Change retur...
951
  	return -ETIMEDOUT;
c609719b8   wdenk   Initial revision
952
953
954
955
956
957
958
959
960
961
962
  }
  
  void eth_halt(void)
  {
  	if (!eth_current)
  		return;
  
  	eth_current->halt(eth_current);
  
  	eth_current->state = ETH_STATE_PASSIVE;
  }
eaa8a195c   Bernhard Nortmann   net: expose eth_i...
963
964
965
966
  int eth_is_active(struct eth_device *dev)
  {
  	return dev && dev->state == ETH_STATE_ACTIVE;
  }
db288a960   Joe Hershberger   net: Remove volat...
967
  int eth_send(void *packet, int length)
c609719b8   wdenk   Initial revision
968
969
  {
  	if (!eth_current)
05324a488   Joe Hershberger   net: Change retur...
970
  		return -ENODEV;
c609719b8   wdenk   Initial revision
971
972
973
974
975
976
977
  
  	return eth_current->send(eth_current, packet, length);
  }
  
  int eth_rx(void)
  {
  	if (!eth_current)
05324a488   Joe Hershberger   net: Change retur...
978
  		return -ENODEV;
c609719b8   wdenk   Initial revision
979
980
981
  
  	return eth_current->recv(eth_current);
  }
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
982
  #endif /* ifndef CONFIG_DM_ETH */
c609719b8   wdenk   Initial revision
983

f85b60710   Rafal Jaworowski   Introduce new eth...
984
  #ifdef CONFIG_API
db288a960   Joe Hershberger   net: Remove volat...
985
  static void eth_save_packet(void *packet, int length)
f85b60710   Rafal Jaworowski   Introduce new eth...
986
  {
db288a960   Joe Hershberger   net: Remove volat...
987
  	char *p = packet;
f85b60710   Rafal Jaworowski   Introduce new eth...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
  	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...
1002
  int eth_receive(void *packet, int length)
f85b60710   Rafal Jaworowski   Introduce new eth...
1003
  {
db288a960   Joe Hershberger   net: Remove volat...
1004
  	char *p = packet;
f85b60710   Rafal Jaworowski   Introduce new eth...
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  	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...
1016
  	length = min(eth_rcv_bufs[eth_rcv_current].length, length);
f85b60710   Rafal Jaworowski   Introduce new eth...
1017
1018
1019
1020
1021
1022
1023
1024
  
  	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 ...
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
  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
1040
1041
  void eth_try_another(int first_restart)
  {
05c3e68f8   Joe Hershberger   dm: eth: Add basi...
1042
  	static void *first_failed;
c650e1be4   Remy Bohmer   Fix compile warni...
1043
  	char *ethrotate;
e16925773   Matthias Fuchs   net: add 'ethrota...
1044
1045
1046
1047
1048
  
  	/*
  	 * Do not rotate between network interfaces when
  	 * 'ethrotate' variable is set to 'no'.
  	 */
66c7385a5   Joe Hershberger   net: cosmetic: et...
1049
1050
  	ethrotate = getenv("ethrotate");
  	if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0))
e16925773   Matthias Fuchs   net: add 'ethrota...
1051
  		return;
c609719b8   wdenk   Initial revision
1052

84eb1fba7   Joe Hershberger   net: Refactor in ...
1053
  	if (!eth_get_dev())
c609719b8   wdenk   Initial revision
1054
  		return;
66c7385a5   Joe Hershberger   net: cosmetic: et...
1055
  	if (first_restart)
84eb1fba7   Joe Hershberger   net: Refactor in ...
1056
  		first_failed = eth_get_dev();
c609719b8   wdenk   Initial revision
1057

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

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

84eb1fba7   Joe Hershberger   net: Refactor in ...
1062
  	if (first_failed == eth_get_dev())
bc0571fc1   Joe Hershberger   net: cosmetic: Fi...
1063
  		net_restart_wrap = 1;
c609719b8   wdenk   Initial revision
1064
  }
a3d991bd0   wdenk   Patches by Pantel...
1065
1066
  void eth_set_current(void)
  {
66c7385a5   Joe Hershberger   net: cosmetic: et...
1067
1068
  	static char *act;
  	static int  env_changed_id;
2f70c49e5   Heiko Schocher   netloop: speed up...
1069
  	int	env_id;
a3d991bd0   wdenk   Patches by Pantel...
1070

2f70c49e5   Heiko Schocher   netloop: speed up...
1071
1072
1073
1074
1075
  	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...
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  
  	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...
1088
  		eth_set_dev(eth_get_dev_by_name(act));
6536b9bb7   Joe Hershberger   dm: eth: Add supp...
1089
  	}
a3d991bd0   wdenk   Patches by Pantel...
1090

89d48367e   Simon Glass   Add USB host ethe...
1091
  	eth_current_changed();
a3d991bd0   wdenk   Patches by Pantel...
1092
  }
a3d991bd0   wdenk   Patches by Pantel...
1093

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