Commit db9391e165dd0bb94caa246d5ade756b491b09d4
net: Move driver-model code into its own file
Every other uclass is in its own file. Create a new eth-uclass.c file and move the driver-model code into it, so that networking is consistent. Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Acked-by: Joe Hershberger <joe.hershberger@ni.com>
Showing 3 changed files with 553 additions and 543 deletions Side-by-side Diff
... | ... | @@ -12,7 +12,11 @@ |
12 | 12 | obj-$(CONFIG_CMD_NET) += bootp.o |
13 | 13 | obj-$(CONFIG_CMD_CDP) += cdp.o |
14 | 14 | obj-$(CONFIG_CMD_DNS) += dns.o |
15 | +ifdef CONFIG_DM_ETH | |
16 | +obj-$(CONFIG_CMD_NET) += eth-uclass.o | |
17 | +else | |
15 | 18 | obj-$(CONFIG_CMD_NET) += eth.o |
19 | +endif | |
16 | 20 | obj-$(CONFIG_CMD_NET) += eth_common.o |
17 | 21 | obj-$(CONFIG_CMD_LINK_LOCAL) += link_local.o |
18 | 22 | obj-$(CONFIG_CMD_NET) += net.o |
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 <dm.h> | |
11 | +#include <environment.h> | |
12 | +#include <net.h> | |
13 | +#include <dm/device-internal.h> | |
14 | +#include <dm/uclass-internal.h> | |
15 | +#include "eth_internal.h" | |
16 | + | |
17 | +/** | |
18 | + * struct eth_device_priv - private structure for each Ethernet device | |
19 | + * | |
20 | + * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t) | |
21 | + */ | |
22 | +struct eth_device_priv { | |
23 | + enum eth_state_t state; | |
24 | +}; | |
25 | + | |
26 | +/** | |
27 | + * struct eth_uclass_priv - The structure attached to the uclass itself | |
28 | + * | |
29 | + * @current: The Ethernet device that the network functions are using | |
30 | + */ | |
31 | +struct eth_uclass_priv { | |
32 | + struct udevice *current; | |
33 | +}; | |
34 | + | |
35 | +/* eth_errno - This stores the most recent failure code from DM functions */ | |
36 | +static int eth_errno; | |
37 | + | |
38 | +static struct eth_uclass_priv *eth_get_uclass_priv(void) | |
39 | +{ | |
40 | + struct uclass *uc; | |
41 | + | |
42 | + uclass_get(UCLASS_ETH, &uc); | |
43 | + assert(uc); | |
44 | + return uc->priv; | |
45 | +} | |
46 | + | |
47 | +void eth_set_current_to_next(void) | |
48 | +{ | |
49 | + struct eth_uclass_priv *uc_priv; | |
50 | + | |
51 | + uc_priv = eth_get_uclass_priv(); | |
52 | + if (uc_priv->current) | |
53 | + uclass_next_device(&uc_priv->current); | |
54 | + if (!uc_priv->current) | |
55 | + uclass_first_device(UCLASS_ETH, &uc_priv->current); | |
56 | +} | |
57 | + | |
58 | +/* | |
59 | + * Typically this will simply return the active device. | |
60 | + * In the case where the most recent active device was unset, this will attempt | |
61 | + * to return the first device. If that device doesn't exist or fails to probe, | |
62 | + * this function will return NULL. | |
63 | + */ | |
64 | +struct udevice *eth_get_dev(void) | |
65 | +{ | |
66 | + struct eth_uclass_priv *uc_priv; | |
67 | + | |
68 | + uc_priv = eth_get_uclass_priv(); | |
69 | + if (!uc_priv->current) | |
70 | + eth_errno = uclass_first_device(UCLASS_ETH, | |
71 | + &uc_priv->current); | |
72 | + return uc_priv->current; | |
73 | +} | |
74 | + | |
75 | +/* | |
76 | + * Typically this will just store a device pointer. | |
77 | + * In case it was not probed, we will attempt to do so. | |
78 | + * dev may be NULL to unset the active device. | |
79 | + */ | |
80 | +void eth_set_dev(struct udevice *dev) | |
81 | +{ | |
82 | + if (dev && !device_active(dev)) { | |
83 | + eth_errno = device_probe(dev); | |
84 | + if (eth_errno) | |
85 | + dev = NULL; | |
86 | + } | |
87 | + | |
88 | + eth_get_uclass_priv()->current = dev; | |
89 | +} | |
90 | + | |
91 | +/* | |
92 | + * Find the udevice that either has the name passed in as devname or has an | |
93 | + * alias named devname. | |
94 | + */ | |
95 | +struct udevice *eth_get_dev_by_name(const char *devname) | |
96 | +{ | |
97 | + int seq = -1; | |
98 | + char *endp = NULL; | |
99 | + const char *startp = NULL; | |
100 | + struct udevice *it; | |
101 | + struct uclass *uc; | |
102 | + int len = strlen("eth"); | |
103 | + | |
104 | + /* Must be longer than 3 to be an alias */ | |
105 | + if (!strncmp(devname, "eth", len) && strlen(devname) > len) { | |
106 | + startp = devname + len; | |
107 | + seq = simple_strtoul(startp, &endp, 10); | |
108 | + } | |
109 | + | |
110 | + uclass_get(UCLASS_ETH, &uc); | |
111 | + uclass_foreach_dev(it, uc) { | |
112 | + /* | |
113 | + * We need the seq to be valid, so try to probe it. | |
114 | + * If the probe fails, the seq will not match since it will be | |
115 | + * -1 instead of what we are looking for. | |
116 | + * We don't care about errors from probe here. Either they won't | |
117 | + * match an alias or it will match a literal name and we'll pick | |
118 | + * up the error when we try to probe again in eth_set_dev(). | |
119 | + */ | |
120 | + if (device_probe(it)) | |
121 | + continue; | |
122 | + /* Check for the name or the sequence number to match */ | |
123 | + if (strcmp(it->name, devname) == 0 || | |
124 | + (endp > startp && it->seq == seq)) | |
125 | + return it; | |
126 | + } | |
127 | + | |
128 | + return NULL; | |
129 | +} | |
130 | + | |
131 | +unsigned char *eth_get_ethaddr(void) | |
132 | +{ | |
133 | + struct eth_pdata *pdata; | |
134 | + | |
135 | + if (eth_get_dev()) { | |
136 | + pdata = eth_get_dev()->platdata; | |
137 | + return pdata->enetaddr; | |
138 | + } | |
139 | + | |
140 | + return NULL; | |
141 | +} | |
142 | + | |
143 | +/* Set active state without calling start on the driver */ | |
144 | +int eth_init_state_only(void) | |
145 | +{ | |
146 | + struct udevice *current; | |
147 | + struct eth_device_priv *priv; | |
148 | + | |
149 | + current = eth_get_dev(); | |
150 | + if (!current || !device_active(current)) | |
151 | + return -EINVAL; | |
152 | + | |
153 | + priv = current->uclass_priv; | |
154 | + priv->state = ETH_STATE_ACTIVE; | |
155 | + | |
156 | + return 0; | |
157 | +} | |
158 | + | |
159 | +/* Set passive state without calling stop on the driver */ | |
160 | +void eth_halt_state_only(void) | |
161 | +{ | |
162 | + struct udevice *current; | |
163 | + struct eth_device_priv *priv; | |
164 | + | |
165 | + current = eth_get_dev(); | |
166 | + if (!current || !device_active(current)) | |
167 | + return; | |
168 | + | |
169 | + priv = current->uclass_priv; | |
170 | + priv->state = ETH_STATE_PASSIVE; | |
171 | +} | |
172 | + | |
173 | +int eth_get_dev_index(void) | |
174 | +{ | |
175 | + if (eth_get_dev()) | |
176 | + return eth_get_dev()->seq; | |
177 | + return -1; | |
178 | +} | |
179 | + | |
180 | +static int eth_write_hwaddr(struct udevice *dev) | |
181 | +{ | |
182 | + struct eth_pdata *pdata = dev->platdata; | |
183 | + int ret = 0; | |
184 | + | |
185 | + if (!dev || !device_active(dev)) | |
186 | + return -EINVAL; | |
187 | + | |
188 | + /* seq is valid since the device is active */ | |
189 | + if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { | |
190 | + if (!is_valid_ethaddr(pdata->enetaddr)) { | |
191 | + printf("\nError: %s address %pM illegal value\n", | |
192 | + dev->name, pdata->enetaddr); | |
193 | + return -EINVAL; | |
194 | + } | |
195 | + | |
196 | + /* | |
197 | + * Drivers are allowed to decide not to implement this at | |
198 | + * run-time. E.g. Some devices may use it and some may not. | |
199 | + */ | |
200 | + ret = eth_get_ops(dev)->write_hwaddr(dev); | |
201 | + if (ret == -ENOSYS) | |
202 | + ret = 0; | |
203 | + if (ret) | |
204 | + printf("\nWarning: %s failed to set MAC address\n", | |
205 | + dev->name); | |
206 | + } | |
207 | + | |
208 | + return ret; | |
209 | +} | |
210 | + | |
211 | +static int on_ethaddr(const char *name, const char *value, enum env_op op, | |
212 | + int flags) | |
213 | +{ | |
214 | + int index; | |
215 | + int retval; | |
216 | + struct udevice *dev; | |
217 | + | |
218 | + /* look for an index after "eth" */ | |
219 | + index = simple_strtoul(name + 3, NULL, 10); | |
220 | + | |
221 | + retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev); | |
222 | + if (!retval) { | |
223 | + struct eth_pdata *pdata = dev->platdata; | |
224 | + switch (op) { | |
225 | + case env_op_create: | |
226 | + case env_op_overwrite: | |
227 | + eth_parse_enetaddr(value, pdata->enetaddr); | |
228 | + break; | |
229 | + case env_op_delete: | |
230 | + memset(pdata->enetaddr, 0, 6); | |
231 | + } | |
232 | + } | |
233 | + | |
234 | + return 0; | |
235 | +} | |
236 | +U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr); | |
237 | + | |
238 | +int eth_init(void) | |
239 | +{ | |
240 | + char *ethact = getenv("ethact"); | |
241 | + char *ethrotate = getenv("ethrotate"); | |
242 | + struct udevice *current = NULL; | |
243 | + struct udevice *old_current; | |
244 | + int ret = -ENODEV; | |
245 | + | |
246 | + /* | |
247 | + * When 'ethrotate' variable is set to 'no' and 'ethact' variable | |
248 | + * is already set to an ethernet device, we should stick to 'ethact'. | |
249 | + */ | |
250 | + if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) { | |
251 | + if (ethact) { | |
252 | + current = eth_get_dev_by_name(ethact); | |
253 | + if (!current) | |
254 | + return -EINVAL; | |
255 | + } | |
256 | + } | |
257 | + | |
258 | + if (!current) { | |
259 | + current = eth_get_dev(); | |
260 | + if (!current) { | |
261 | + printf("No ethernet found.\n"); | |
262 | + return -ENODEV; | |
263 | + } | |
264 | + } | |
265 | + | |
266 | + old_current = current; | |
267 | + do { | |
268 | + if (current) { | |
269 | + debug("Trying %s\n", current->name); | |
270 | + | |
271 | + if (device_active(current)) { | |
272 | + ret = eth_get_ops(current)->start(current); | |
273 | + if (ret >= 0) { | |
274 | + struct eth_device_priv *priv = | |
275 | + current->uclass_priv; | |
276 | + | |
277 | + priv->state = ETH_STATE_ACTIVE; | |
278 | + return 0; | |
279 | + } | |
280 | + } else { | |
281 | + ret = eth_errno; | |
282 | + } | |
283 | + | |
284 | + debug("FAIL\n"); | |
285 | + } else { | |
286 | + debug("PROBE FAIL\n"); | |
287 | + } | |
288 | + | |
289 | + /* | |
290 | + * If ethrotate is enabled, this will change "current", | |
291 | + * otherwise we will drop out of this while loop immediately | |
292 | + */ | |
293 | + eth_try_another(0); | |
294 | + /* This will ensure the new "current" attempted to probe */ | |
295 | + current = eth_get_dev(); | |
296 | + } while (old_current != current); | |
297 | + | |
298 | + return ret; | |
299 | +} | |
300 | + | |
301 | +void eth_halt(void) | |
302 | +{ | |
303 | + struct udevice *current; | |
304 | + struct eth_device_priv *priv; | |
305 | + | |
306 | + current = eth_get_dev(); | |
307 | + if (!current || !device_active(current)) | |
308 | + return; | |
309 | + | |
310 | + eth_get_ops(current)->stop(current); | |
311 | + priv = current->uclass_priv; | |
312 | + priv->state = ETH_STATE_PASSIVE; | |
313 | +} | |
314 | + | |
315 | +int eth_is_active(struct udevice *dev) | |
316 | +{ | |
317 | + struct eth_device_priv *priv; | |
318 | + | |
319 | + if (!dev || !device_active(dev)) | |
320 | + return 0; | |
321 | + | |
322 | + priv = dev_get_uclass_priv(dev); | |
323 | + return priv->state == ETH_STATE_ACTIVE; | |
324 | +} | |
325 | + | |
326 | +int eth_send(void *packet, int length) | |
327 | +{ | |
328 | + struct udevice *current; | |
329 | + int ret; | |
330 | + | |
331 | + current = eth_get_dev(); | |
332 | + if (!current) | |
333 | + return -ENODEV; | |
334 | + | |
335 | + if (!device_active(current)) | |
336 | + return -EINVAL; | |
337 | + | |
338 | + ret = eth_get_ops(current)->send(current, packet, length); | |
339 | + if (ret < 0) { | |
340 | + /* We cannot completely return the error at present */ | |
341 | + debug("%s: send() returned error %d\n", __func__, ret); | |
342 | + } | |
343 | + return ret; | |
344 | +} | |
345 | + | |
346 | +int eth_rx(void) | |
347 | +{ | |
348 | + struct udevice *current; | |
349 | + uchar *packet; | |
350 | + int flags; | |
351 | + int ret; | |
352 | + int i; | |
353 | + | |
354 | + current = eth_get_dev(); | |
355 | + if (!current) | |
356 | + return -ENODEV; | |
357 | + | |
358 | + if (!device_active(current)) | |
359 | + return -EINVAL; | |
360 | + | |
361 | + /* Process up to 32 packets at one time */ | |
362 | + flags = ETH_RECV_CHECK_DEVICE; | |
363 | + for (i = 0; i < 32; i++) { | |
364 | + ret = eth_get_ops(current)->recv(current, flags, &packet); | |
365 | + flags = 0; | |
366 | + if (ret > 0) | |
367 | + net_process_received_packet(packet, ret); | |
368 | + if (ret >= 0 && eth_get_ops(current)->free_pkt) | |
369 | + eth_get_ops(current)->free_pkt(current, packet, ret); | |
370 | + if (ret <= 0) | |
371 | + break; | |
372 | + } | |
373 | + if (ret == -EAGAIN) | |
374 | + ret = 0; | |
375 | + if (ret < 0) { | |
376 | + /* We cannot completely return the error at present */ | |
377 | + debug("%s: recv() returned error %d\n", __func__, ret); | |
378 | + } | |
379 | + return ret; | |
380 | +} | |
381 | + | |
382 | +int eth_initialize(void) | |
383 | +{ | |
384 | + int num_devices = 0; | |
385 | + struct udevice *dev; | |
386 | + | |
387 | + eth_common_init(); | |
388 | + | |
389 | + /* | |
390 | + * Devices need to write the hwaddr even if not started so that Linux | |
391 | + * will have access to the hwaddr that u-boot stored for the device. | |
392 | + * This is accomplished by attempting to probe each device and calling | |
393 | + * their write_hwaddr() operation. | |
394 | + */ | |
395 | + uclass_first_device(UCLASS_ETH, &dev); | |
396 | + if (!dev) { | |
397 | + printf("No ethernet found.\n"); | |
398 | + bootstage_error(BOOTSTAGE_ID_NET_ETH_START); | |
399 | + } else { | |
400 | + char *ethprime = getenv("ethprime"); | |
401 | + struct udevice *prime_dev = NULL; | |
402 | + | |
403 | + if (ethprime) | |
404 | + prime_dev = eth_get_dev_by_name(ethprime); | |
405 | + if (prime_dev) { | |
406 | + eth_set_dev(prime_dev); | |
407 | + eth_current_changed(); | |
408 | + } else { | |
409 | + eth_set_dev(NULL); | |
410 | + } | |
411 | + | |
412 | + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); | |
413 | + do { | |
414 | + if (num_devices) | |
415 | + printf(", "); | |
416 | + | |
417 | + printf("eth%d: %s", dev->seq, dev->name); | |
418 | + | |
419 | + if (ethprime && dev == prime_dev) | |
420 | + printf(" [PRIME]"); | |
421 | + | |
422 | + eth_write_hwaddr(dev); | |
423 | + | |
424 | + uclass_next_device(&dev); | |
425 | + num_devices++; | |
426 | + } while (dev); | |
427 | + | |
428 | + putc('\n'); | |
429 | + } | |
430 | + | |
431 | + return num_devices; | |
432 | +} | |
433 | + | |
434 | +static int eth_post_bind(struct udevice *dev) | |
435 | +{ | |
436 | + if (strchr(dev->name, ' ')) { | |
437 | + printf("\nError: eth device name \"%s\" has a space!\n", | |
438 | + dev->name); | |
439 | + return -EINVAL; | |
440 | + } | |
441 | + | |
442 | + return 0; | |
443 | +} | |
444 | + | |
445 | +static int eth_pre_unbind(struct udevice *dev) | |
446 | +{ | |
447 | + /* Don't hang onto a pointer that is going away */ | |
448 | + if (dev == eth_get_uclass_priv()->current) | |
449 | + eth_set_dev(NULL); | |
450 | + | |
451 | + return 0; | |
452 | +} | |
453 | + | |
454 | +static int eth_post_probe(struct udevice *dev) | |
455 | +{ | |
456 | + struct eth_device_priv *priv = dev->uclass_priv; | |
457 | + struct eth_pdata *pdata = dev->platdata; | |
458 | + unsigned char env_enetaddr[6]; | |
459 | + | |
460 | +#if defined(CONFIG_NEEDS_MANUAL_RELOC) | |
461 | + struct eth_ops *ops = eth_get_ops(dev); | |
462 | + static int reloc_done; | |
463 | + | |
464 | + if (!reloc_done) { | |
465 | + if (ops->start) | |
466 | + ops->start += gd->reloc_off; | |
467 | + if (ops->send) | |
468 | + ops->send += gd->reloc_off; | |
469 | + if (ops->recv) | |
470 | + ops->recv += gd->reloc_off; | |
471 | + if (ops->free_pkt) | |
472 | + ops->free_pkt += gd->reloc_off; | |
473 | + if (ops->stop) | |
474 | + ops->stop += gd->reloc_off; | |
475 | +#ifdef CONFIG_MCAST_TFTP | |
476 | + if (ops->mcast) | |
477 | + ops->mcast += gd->reloc_off; | |
478 | +#endif | |
479 | + if (ops->write_hwaddr) | |
480 | + ops->write_hwaddr += gd->reloc_off; | |
481 | + if (ops->read_rom_hwaddr) | |
482 | + ops->read_rom_hwaddr += gd->reloc_off; | |
483 | + | |
484 | + reloc_done++; | |
485 | + } | |
486 | +#endif | |
487 | + | |
488 | + priv->state = ETH_STATE_INIT; | |
489 | + | |
490 | + /* Check if the device has a MAC address in ROM */ | |
491 | + if (eth_get_ops(dev)->read_rom_hwaddr) | |
492 | + eth_get_ops(dev)->read_rom_hwaddr(dev); | |
493 | + | |
494 | + eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); | |
495 | + if (!is_zero_ethaddr(env_enetaddr)) { | |
496 | + if (!is_zero_ethaddr(pdata->enetaddr) && | |
497 | + memcmp(pdata->enetaddr, env_enetaddr, 6)) { | |
498 | + printf("\nWarning: %s MAC addresses don't match:\n", | |
499 | + dev->name); | |
500 | + printf("Address in SROM is %pM\n", | |
501 | + pdata->enetaddr); | |
502 | + printf("Address in environment is %pM\n", | |
503 | + env_enetaddr); | |
504 | + } | |
505 | + | |
506 | + /* Override the ROM MAC address */ | |
507 | + memcpy(pdata->enetaddr, env_enetaddr, 6); | |
508 | + } else if (is_valid_ethaddr(pdata->enetaddr)) { | |
509 | + eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); | |
510 | + printf("\nWarning: %s using MAC address from ROM\n", | |
511 | + dev->name); | |
512 | + } else if (is_zero_ethaddr(pdata->enetaddr)) { | |
513 | +#ifdef CONFIG_NET_RANDOM_ETHADDR | |
514 | + net_random_ethaddr(pdata->enetaddr); | |
515 | + printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", | |
516 | + dev->name, dev->seq, pdata->enetaddr); | |
517 | +#else | |
518 | + printf("\nError: %s address not set.\n", | |
519 | + dev->name); | |
520 | + return -EINVAL; | |
521 | +#endif | |
522 | + } | |
523 | + | |
524 | + return 0; | |
525 | +} | |
526 | + | |
527 | +static int eth_pre_remove(struct udevice *dev) | |
528 | +{ | |
529 | + struct eth_pdata *pdata = dev->platdata; | |
530 | + | |
531 | + eth_get_ops(dev)->stop(dev); | |
532 | + | |
533 | + /* clear the MAC address */ | |
534 | + memset(pdata->enetaddr, 0, 6); | |
535 | + | |
536 | + return 0; | |
537 | +} | |
538 | + | |
539 | +UCLASS_DRIVER(eth) = { | |
540 | + .name = "eth", | |
541 | + .id = UCLASS_ETH, | |
542 | + .post_bind = eth_post_bind, | |
543 | + .pre_unbind = eth_pre_unbind, | |
544 | + .post_probe = eth_post_probe, | |
545 | + .pre_remove = eth_pre_remove, | |
546 | + .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), | |
547 | + .per_device_auto_alloc_size = sizeof(struct eth_device_priv), | |
548 | + .flags = DM_UC_FLAG_SEQ_ALIAS, | |
549 | +}; |
... | ... | @@ -8,14 +8,10 @@ |
8 | 8 | |
9 | 9 | #include <common.h> |
10 | 10 | #include <command.h> |
11 | -#include <dm.h> | |
12 | 11 | #include <environment.h> |
13 | 12 | #include <net.h> |
14 | -#include <miiphy.h> | |
15 | 13 | #include <phy.h> |
16 | 14 | #include <asm/errno.h> |
17 | -#include <dm/device-internal.h> | |
18 | -#include <dm/uclass-internal.h> | |
19 | 15 | #include "eth_internal.h" |
20 | 16 | |
21 | 17 | DECLARE_GLOBAL_DATA_PTR; |
... | ... | @@ -31,544 +27,6 @@ |
31 | 27 | int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init"))); |
32 | 28 | int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init"))); |
33 | 29 | |
34 | -#ifdef CONFIG_DM_ETH | |
35 | -/** | |
36 | - * struct eth_device_priv - private structure for each Ethernet device | |
37 | - * | |
38 | - * @state: The state of the Ethernet MAC driver (defined by enum eth_state_t) | |
39 | - */ | |
40 | -struct eth_device_priv { | |
41 | - enum eth_state_t state; | |
42 | -}; | |
43 | - | |
44 | -/** | |
45 | - * struct eth_uclass_priv - The structure attached to the uclass itself | |
46 | - * | |
47 | - * @current: The Ethernet device that the network functions are using | |
48 | - */ | |
49 | -struct eth_uclass_priv { | |
50 | - struct udevice *current; | |
51 | -}; | |
52 | - | |
53 | -/* eth_errno - This stores the most recent failure code from DM functions */ | |
54 | -static int eth_errno; | |
55 | - | |
56 | -static struct eth_uclass_priv *eth_get_uclass_priv(void) | |
57 | -{ | |
58 | - struct uclass *uc; | |
59 | - | |
60 | - uclass_get(UCLASS_ETH, &uc); | |
61 | - assert(uc); | |
62 | - return uc->priv; | |
63 | -} | |
64 | - | |
65 | -void eth_set_current_to_next(void) | |
66 | -{ | |
67 | - struct eth_uclass_priv *uc_priv; | |
68 | - | |
69 | - uc_priv = eth_get_uclass_priv(); | |
70 | - if (uc_priv->current) | |
71 | - uclass_next_device(&uc_priv->current); | |
72 | - if (!uc_priv->current) | |
73 | - uclass_first_device(UCLASS_ETH, &uc_priv->current); | |
74 | -} | |
75 | - | |
76 | -/* | |
77 | - * Typically this will simply return the active device. | |
78 | - * In the case where the most recent active device was unset, this will attempt | |
79 | - * to return the first device. If that device doesn't exist or fails to probe, | |
80 | - * this function will return NULL. | |
81 | - */ | |
82 | -struct udevice *eth_get_dev(void) | |
83 | -{ | |
84 | - struct eth_uclass_priv *uc_priv; | |
85 | - | |
86 | - uc_priv = eth_get_uclass_priv(); | |
87 | - if (!uc_priv->current) | |
88 | - eth_errno = uclass_first_device(UCLASS_ETH, | |
89 | - &uc_priv->current); | |
90 | - return uc_priv->current; | |
91 | -} | |
92 | - | |
93 | -/* | |
94 | - * Typically this will just store a device pointer. | |
95 | - * In case it was not probed, we will attempt to do so. | |
96 | - * dev may be NULL to unset the active device. | |
97 | - */ | |
98 | -void eth_set_dev(struct udevice *dev) | |
99 | -{ | |
100 | - if (dev && !device_active(dev)) { | |
101 | - eth_errno = device_probe(dev); | |
102 | - if (eth_errno) | |
103 | - dev = NULL; | |
104 | - } | |
105 | - | |
106 | - eth_get_uclass_priv()->current = dev; | |
107 | -} | |
108 | - | |
109 | -/* | |
110 | - * Find the udevice that either has the name passed in as devname or has an | |
111 | - * alias named devname. | |
112 | - */ | |
113 | -struct udevice *eth_get_dev_by_name(const char *devname) | |
114 | -{ | |
115 | - int seq = -1; | |
116 | - char *endp = NULL; | |
117 | - const char *startp = NULL; | |
118 | - struct udevice *it; | |
119 | - struct uclass *uc; | |
120 | - int len = strlen("eth"); | |
121 | - | |
122 | - /* Must be longer than 3 to be an alias */ | |
123 | - if (!strncmp(devname, "eth", len) && strlen(devname) > len) { | |
124 | - startp = devname + len; | |
125 | - seq = simple_strtoul(startp, &endp, 10); | |
126 | - } | |
127 | - | |
128 | - uclass_get(UCLASS_ETH, &uc); | |
129 | - uclass_foreach_dev(it, uc) { | |
130 | - /* | |
131 | - * We need the seq to be valid, so try to probe it. | |
132 | - * If the probe fails, the seq will not match since it will be | |
133 | - * -1 instead of what we are looking for. | |
134 | - * We don't care about errors from probe here. Either they won't | |
135 | - * match an alias or it will match a literal name and we'll pick | |
136 | - * up the error when we try to probe again in eth_set_dev(). | |
137 | - */ | |
138 | - if (device_probe(it)) | |
139 | - continue; | |
140 | - /* Check for the name or the sequence number to match */ | |
141 | - if (strcmp(it->name, devname) == 0 || | |
142 | - (endp > startp && it->seq == seq)) | |
143 | - return it; | |
144 | - } | |
145 | - | |
146 | - return NULL; | |
147 | -} | |
148 | - | |
149 | -unsigned char *eth_get_ethaddr(void) | |
150 | -{ | |
151 | - struct eth_pdata *pdata; | |
152 | - | |
153 | - if (eth_get_dev()) { | |
154 | - pdata = eth_get_dev()->platdata; | |
155 | - return pdata->enetaddr; | |
156 | - } | |
157 | - | |
158 | - return NULL; | |
159 | -} | |
160 | - | |
161 | -/* Set active state without calling start on the driver */ | |
162 | -int eth_init_state_only(void) | |
163 | -{ | |
164 | - struct udevice *current; | |
165 | - struct eth_device_priv *priv; | |
166 | - | |
167 | - current = eth_get_dev(); | |
168 | - if (!current || !device_active(current)) | |
169 | - return -EINVAL; | |
170 | - | |
171 | - priv = current->uclass_priv; | |
172 | - priv->state = ETH_STATE_ACTIVE; | |
173 | - | |
174 | - return 0; | |
175 | -} | |
176 | - | |
177 | -/* Set passive state without calling stop on the driver */ | |
178 | -void eth_halt_state_only(void) | |
179 | -{ | |
180 | - struct udevice *current; | |
181 | - struct eth_device_priv *priv; | |
182 | - | |
183 | - current = eth_get_dev(); | |
184 | - if (!current || !device_active(current)) | |
185 | - return; | |
186 | - | |
187 | - priv = current->uclass_priv; | |
188 | - priv->state = ETH_STATE_PASSIVE; | |
189 | -} | |
190 | - | |
191 | -int eth_get_dev_index(void) | |
192 | -{ | |
193 | - if (eth_get_dev()) | |
194 | - return eth_get_dev()->seq; | |
195 | - return -1; | |
196 | -} | |
197 | - | |
198 | -static int eth_write_hwaddr(struct udevice *dev) | |
199 | -{ | |
200 | - struct eth_pdata *pdata = dev->platdata; | |
201 | - int ret = 0; | |
202 | - | |
203 | - if (!dev || !device_active(dev)) | |
204 | - return -EINVAL; | |
205 | - | |
206 | - /* seq is valid since the device is active */ | |
207 | - if (eth_get_ops(dev)->write_hwaddr && !eth_mac_skip(dev->seq)) { | |
208 | - if (!is_valid_ethaddr(pdata->enetaddr)) { | |
209 | - printf("\nError: %s address %pM illegal value\n", | |
210 | - dev->name, pdata->enetaddr); | |
211 | - return -EINVAL; | |
212 | - } | |
213 | - | |
214 | - /* | |
215 | - * Drivers are allowed to decide not to implement this at | |
216 | - * run-time. E.g. Some devices may use it and some may not. | |
217 | - */ | |
218 | - ret = eth_get_ops(dev)->write_hwaddr(dev); | |
219 | - if (ret == -ENOSYS) | |
220 | - ret = 0; | |
221 | - if (ret) | |
222 | - printf("\nWarning: %s failed to set MAC address\n", | |
223 | - dev->name); | |
224 | - } | |
225 | - | |
226 | - return ret; | |
227 | -} | |
228 | - | |
229 | -static int on_ethaddr(const char *name, const char *value, enum env_op op, | |
230 | - int flags) | |
231 | -{ | |
232 | - int index; | |
233 | - int retval; | |
234 | - struct udevice *dev; | |
235 | - | |
236 | - /* look for an index after "eth" */ | |
237 | - index = simple_strtoul(name + 3, NULL, 10); | |
238 | - | |
239 | - retval = uclass_find_device_by_seq(UCLASS_ETH, index, false, &dev); | |
240 | - if (!retval) { | |
241 | - struct eth_pdata *pdata = dev->platdata; | |
242 | - switch (op) { | |
243 | - case env_op_create: | |
244 | - case env_op_overwrite: | |
245 | - eth_parse_enetaddr(value, pdata->enetaddr); | |
246 | - break; | |
247 | - case env_op_delete: | |
248 | - memset(pdata->enetaddr, 0, 6); | |
249 | - } | |
250 | - } | |
251 | - | |
252 | - return 0; | |
253 | -} | |
254 | -U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr); | |
255 | - | |
256 | -int eth_init(void) | |
257 | -{ | |
258 | - char *ethact = getenv("ethact"); | |
259 | - char *ethrotate = getenv("ethrotate"); | |
260 | - struct udevice *current = NULL; | |
261 | - struct udevice *old_current; | |
262 | - int ret = -ENODEV; | |
263 | - | |
264 | - /* | |
265 | - * When 'ethrotate' variable is set to 'no' and 'ethact' variable | |
266 | - * is already set to an ethernet device, we should stick to 'ethact'. | |
267 | - */ | |
268 | - if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) { | |
269 | - if (ethact) { | |
270 | - current = eth_get_dev_by_name(ethact); | |
271 | - if (!current) | |
272 | - return -EINVAL; | |
273 | - } | |
274 | - } | |
275 | - | |
276 | - if (!current) { | |
277 | - current = eth_get_dev(); | |
278 | - if (!current) { | |
279 | - printf("No ethernet found.\n"); | |
280 | - return -ENODEV; | |
281 | - } | |
282 | - } | |
283 | - | |
284 | - old_current = current; | |
285 | - do { | |
286 | - if (current) { | |
287 | - debug("Trying %s\n", current->name); | |
288 | - | |
289 | - if (device_active(current)) { | |
290 | - ret = eth_get_ops(current)->start(current); | |
291 | - if (ret >= 0) { | |
292 | - struct eth_device_priv *priv = | |
293 | - current->uclass_priv; | |
294 | - | |
295 | - priv->state = ETH_STATE_ACTIVE; | |
296 | - return 0; | |
297 | - } | |
298 | - } else { | |
299 | - ret = eth_errno; | |
300 | - } | |
301 | - | |
302 | - debug("FAIL\n"); | |
303 | - } else { | |
304 | - debug("PROBE FAIL\n"); | |
305 | - } | |
306 | - | |
307 | - /* | |
308 | - * If ethrotate is enabled, this will change "current", | |
309 | - * otherwise we will drop out of this while loop immediately | |
310 | - */ | |
311 | - eth_try_another(0); | |
312 | - /* This will ensure the new "current" attempted to probe */ | |
313 | - current = eth_get_dev(); | |
314 | - } while (old_current != current); | |
315 | - | |
316 | - return ret; | |
317 | -} | |
318 | - | |
319 | -void eth_halt(void) | |
320 | -{ | |
321 | - struct udevice *current; | |
322 | - struct eth_device_priv *priv; | |
323 | - | |
324 | - current = eth_get_dev(); | |
325 | - if (!current || !device_active(current)) | |
326 | - return; | |
327 | - | |
328 | - eth_get_ops(current)->stop(current); | |
329 | - priv = current->uclass_priv; | |
330 | - priv->state = ETH_STATE_PASSIVE; | |
331 | -} | |
332 | - | |
333 | -int eth_is_active(struct udevice *dev) | |
334 | -{ | |
335 | - struct eth_device_priv *priv; | |
336 | - | |
337 | - if (!dev || !device_active(dev)) | |
338 | - return 0; | |
339 | - | |
340 | - priv = dev_get_uclass_priv(dev); | |
341 | - return priv->state == ETH_STATE_ACTIVE; | |
342 | -} | |
343 | - | |
344 | -int eth_send(void *packet, int length) | |
345 | -{ | |
346 | - struct udevice *current; | |
347 | - int ret; | |
348 | - | |
349 | - current = eth_get_dev(); | |
350 | - if (!current) | |
351 | - return -ENODEV; | |
352 | - | |
353 | - if (!device_active(current)) | |
354 | - return -EINVAL; | |
355 | - | |
356 | - ret = eth_get_ops(current)->send(current, packet, length); | |
357 | - if (ret < 0) { | |
358 | - /* We cannot completely return the error at present */ | |
359 | - debug("%s: send() returned error %d\n", __func__, ret); | |
360 | - } | |
361 | - return ret; | |
362 | -} | |
363 | - | |
364 | -int eth_rx(void) | |
365 | -{ | |
366 | - struct udevice *current; | |
367 | - uchar *packet; | |
368 | - int flags; | |
369 | - int ret; | |
370 | - int i; | |
371 | - | |
372 | - current = eth_get_dev(); | |
373 | - if (!current) | |
374 | - return -ENODEV; | |
375 | - | |
376 | - if (!device_active(current)) | |
377 | - return -EINVAL; | |
378 | - | |
379 | - /* Process up to 32 packets at one time */ | |
380 | - flags = ETH_RECV_CHECK_DEVICE; | |
381 | - for (i = 0; i < 32; i++) { | |
382 | - ret = eth_get_ops(current)->recv(current, flags, &packet); | |
383 | - flags = 0; | |
384 | - if (ret > 0) | |
385 | - net_process_received_packet(packet, ret); | |
386 | - if (ret >= 0 && eth_get_ops(current)->free_pkt) | |
387 | - eth_get_ops(current)->free_pkt(current, packet, ret); | |
388 | - if (ret <= 0) | |
389 | - break; | |
390 | - } | |
391 | - if (ret == -EAGAIN) | |
392 | - ret = 0; | |
393 | - if (ret < 0) { | |
394 | - /* We cannot completely return the error at present */ | |
395 | - debug("%s: recv() returned error %d\n", __func__, ret); | |
396 | - } | |
397 | - return ret; | |
398 | -} | |
399 | - | |
400 | -int eth_initialize(void) | |
401 | -{ | |
402 | - int num_devices = 0; | |
403 | - struct udevice *dev; | |
404 | - | |
405 | - eth_common_init(); | |
406 | - | |
407 | - /* | |
408 | - * Devices need to write the hwaddr even if not started so that Linux | |
409 | - * will have access to the hwaddr that u-boot stored for the device. | |
410 | - * This is accomplished by attempting to probe each device and calling | |
411 | - * their write_hwaddr() operation. | |
412 | - */ | |
413 | - uclass_first_device(UCLASS_ETH, &dev); | |
414 | - if (!dev) { | |
415 | - printf("No ethernet found.\n"); | |
416 | - bootstage_error(BOOTSTAGE_ID_NET_ETH_START); | |
417 | - } else { | |
418 | - char *ethprime = getenv("ethprime"); | |
419 | - struct udevice *prime_dev = NULL; | |
420 | - | |
421 | - if (ethprime) | |
422 | - prime_dev = eth_get_dev_by_name(ethprime); | |
423 | - if (prime_dev) { | |
424 | - eth_set_dev(prime_dev); | |
425 | - eth_current_changed(); | |
426 | - } else { | |
427 | - eth_set_dev(NULL); | |
428 | - } | |
429 | - | |
430 | - bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); | |
431 | - do { | |
432 | - if (num_devices) | |
433 | - printf(", "); | |
434 | - | |
435 | - printf("eth%d: %s", dev->seq, dev->name); | |
436 | - | |
437 | - if (ethprime && dev == prime_dev) | |
438 | - printf(" [PRIME]"); | |
439 | - | |
440 | - eth_write_hwaddr(dev); | |
441 | - | |
442 | - uclass_next_device(&dev); | |
443 | - num_devices++; | |
444 | - } while (dev); | |
445 | - | |
446 | - putc('\n'); | |
447 | - } | |
448 | - | |
449 | - return num_devices; | |
450 | -} | |
451 | - | |
452 | -static int eth_post_bind(struct udevice *dev) | |
453 | -{ | |
454 | - if (strchr(dev->name, ' ')) { | |
455 | - printf("\nError: eth device name \"%s\" has a space!\n", | |
456 | - dev->name); | |
457 | - return -EINVAL; | |
458 | - } | |
459 | - | |
460 | - return 0; | |
461 | -} | |
462 | - | |
463 | -static int eth_pre_unbind(struct udevice *dev) | |
464 | -{ | |
465 | - /* Don't hang onto a pointer that is going away */ | |
466 | - if (dev == eth_get_uclass_priv()->current) | |
467 | - eth_set_dev(NULL); | |
468 | - | |
469 | - return 0; | |
470 | -} | |
471 | - | |
472 | -static int eth_post_probe(struct udevice *dev) | |
473 | -{ | |
474 | - struct eth_device_priv *priv = dev->uclass_priv; | |
475 | - struct eth_pdata *pdata = dev->platdata; | |
476 | - unsigned char env_enetaddr[6]; | |
477 | - | |
478 | -#if defined(CONFIG_NEEDS_MANUAL_RELOC) | |
479 | - struct eth_ops *ops = eth_get_ops(dev); | |
480 | - static int reloc_done; | |
481 | - | |
482 | - if (!reloc_done) { | |
483 | - if (ops->start) | |
484 | - ops->start += gd->reloc_off; | |
485 | - if (ops->send) | |
486 | - ops->send += gd->reloc_off; | |
487 | - if (ops->recv) | |
488 | - ops->recv += gd->reloc_off; | |
489 | - if (ops->free_pkt) | |
490 | - ops->free_pkt += gd->reloc_off; | |
491 | - if (ops->stop) | |
492 | - ops->stop += gd->reloc_off; | |
493 | -#ifdef CONFIG_MCAST_TFTP | |
494 | - if (ops->mcast) | |
495 | - ops->mcast += gd->reloc_off; | |
496 | -#endif | |
497 | - if (ops->write_hwaddr) | |
498 | - ops->write_hwaddr += gd->reloc_off; | |
499 | - if (ops->read_rom_hwaddr) | |
500 | - ops->read_rom_hwaddr += gd->reloc_off; | |
501 | - | |
502 | - reloc_done++; | |
503 | - } | |
504 | -#endif | |
505 | - | |
506 | - priv->state = ETH_STATE_INIT; | |
507 | - | |
508 | - /* Check if the device has a MAC address in ROM */ | |
509 | - if (eth_get_ops(dev)->read_rom_hwaddr) | |
510 | - eth_get_ops(dev)->read_rom_hwaddr(dev); | |
511 | - | |
512 | - eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); | |
513 | - if (!is_zero_ethaddr(env_enetaddr)) { | |
514 | - if (!is_zero_ethaddr(pdata->enetaddr) && | |
515 | - memcmp(pdata->enetaddr, env_enetaddr, 6)) { | |
516 | - printf("\nWarning: %s MAC addresses don't match:\n", | |
517 | - dev->name); | |
518 | - printf("Address in SROM is %pM\n", | |
519 | - pdata->enetaddr); | |
520 | - printf("Address in environment is %pM\n", | |
521 | - env_enetaddr); | |
522 | - } | |
523 | - | |
524 | - /* Override the ROM MAC address */ | |
525 | - memcpy(pdata->enetaddr, env_enetaddr, 6); | |
526 | - } else if (is_valid_ethaddr(pdata->enetaddr)) { | |
527 | - eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); | |
528 | - printf("\nWarning: %s using MAC address from ROM\n", | |
529 | - dev->name); | |
530 | - } else if (is_zero_ethaddr(pdata->enetaddr)) { | |
531 | -#ifdef CONFIG_NET_RANDOM_ETHADDR | |
532 | - net_random_ethaddr(pdata->enetaddr); | |
533 | - printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", | |
534 | - dev->name, dev->seq, pdata->enetaddr); | |
535 | -#else | |
536 | - printf("\nError: %s address not set.\n", | |
537 | - dev->name); | |
538 | - return -EINVAL; | |
539 | -#endif | |
540 | - } | |
541 | - | |
542 | - return 0; | |
543 | -} | |
544 | - | |
545 | -static int eth_pre_remove(struct udevice *dev) | |
546 | -{ | |
547 | - struct eth_pdata *pdata = dev->platdata; | |
548 | - | |
549 | - eth_get_ops(dev)->stop(dev); | |
550 | - | |
551 | - /* clear the MAC address */ | |
552 | - memset(pdata->enetaddr, 0, 6); | |
553 | - | |
554 | - return 0; | |
555 | -} | |
556 | - | |
557 | -UCLASS_DRIVER(eth) = { | |
558 | - .name = "eth", | |
559 | - .id = UCLASS_ETH, | |
560 | - .post_bind = eth_post_bind, | |
561 | - .pre_unbind = eth_pre_unbind, | |
562 | - .post_probe = eth_post_probe, | |
563 | - .pre_remove = eth_pre_remove, | |
564 | - .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), | |
565 | - .per_device_auto_alloc_size = sizeof(struct eth_device_priv), | |
566 | - .flags = DM_UC_FLAG_SEQ_ALIAS, | |
567 | -}; | |
568 | -#endif /* #ifdef CONFIG_DM_ETH */ | |
569 | - | |
570 | -#ifndef CONFIG_DM_ETH | |
571 | - | |
572 | 30 | #ifdef CONFIG_API |
573 | 31 | static struct { |
574 | 32 | uchar data[PKTSIZE]; |
... | ... | @@ -935,7 +393,6 @@ |
935 | 393 | |
936 | 394 | return eth_current->recv(eth_current); |
937 | 395 | } |
938 | -#endif /* ifndef CONFIG_DM_ETH */ | |
939 | 396 | |
940 | 397 | #ifdef CONFIG_API |
941 | 398 | static void eth_save_packet(void *packet, int length) |
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e
-
mentioned in commit a7c45e