X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=net%2Feth.c;h=45fe6e3c1c08408d6245d4803df6a5f7ed8f4ced;hb=4d2749be62b4bf749766a030c74688031edcfbad;hp=04a544c872a07c8e17ee003262a9d50f7bf3f8b1;hpb=f566c9949fbdce2e09a900c5343ca9986e5ba360;p=oweals%2Fu-boot.git diff --git a/net/eth.c b/net/eth.c index 04a544c872..45fe6e3c1c 100644 --- a/net/eth.c +++ b/net/eth.c @@ -9,11 +9,13 @@ #include #include #include +#include #include #include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -29,13 +31,13 @@ void eth_parse_enetaddr(const char *addr, uchar *enetaddr) } } -int eth_getenv_enetaddr(char *name, uchar *enetaddr) +int eth_getenv_enetaddr(const char *name, uchar *enetaddr) { eth_parse_enetaddr(getenv(name), enetaddr); return is_valid_ethaddr(enetaddr); } -int eth_setenv_enetaddr(char *name, const uchar *enetaddr) +int eth_setenv_enetaddr(const char *name, const uchar *enetaddr) { char buf[20]; @@ -60,16 +62,6 @@ static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, return eth_setenv_enetaddr(enetvar, enetaddr); } -static void eth_env_init(void) -{ - const char *s; - - s = getenv("bootfile"); - if (s != NULL) - copy_filename(net_boot_file_name, s, - sizeof(net_boot_file_name)); -} - static int eth_mac_skip(int index) { char enetvar[15]; @@ -104,8 +96,6 @@ static void eth_common_init(void) phy_init(); #endif - eth_env_init(); - /* * If board-specific initialization exists, call it. * If not, call a CPU-specific one @@ -117,7 +107,9 @@ static void eth_common_init(void) if (cpu_eth_init(gd->bd) < 0) printf("CPU Net Initialization Failed\n"); } else { +#ifndef CONFIG_DM_ETH printf("Net Initialization Skipped\n"); +#endif } } @@ -187,8 +179,12 @@ struct udevice *eth_get_dev(void) */ static void eth_set_dev(struct udevice *dev) { - if (dev && !device_active(dev)) + if (dev && !device_active(dev)) { eth_errno = device_probe(dev); + if (eth_errno) + dev = NULL; + } + eth_get_uclass_priv()->current = dev; } @@ -203,10 +199,11 @@ struct udevice *eth_get_dev_by_name(const char *devname) const char *startp = NULL; struct udevice *it; struct uclass *uc; + int len = strlen("eth"); /* Must be longer than 3 to be an alias */ - if (strlen(devname) > strlen("eth")) { - startp = devname + strlen("eth"); + if (!strncmp(devname, "eth", len) && strlen(devname) > len) { + startp = devname + len; seq = simple_strtoul(startp, &endp, 10); } @@ -220,10 +217,9 @@ struct udevice *eth_get_dev_by_name(const char *devname) * 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(). */ - device_probe(it); - /* - * Check for the name or the sequence number to match - */ + if (device_probe(it)) + continue; + /* Check for the name or the sequence number to match */ if (strcmp(it->name, devname) == 0 || (endp > startp && it->seq == seq)) return it; @@ -297,7 +293,13 @@ static int eth_write_hwaddr(struct udevice *dev) return -EINVAL; } + /* + * Drivers are allowed to decide not to implement this at + * run-time. E.g. Some devices may use it and some may not. + */ ret = eth_get_ops(dev)->write_hwaddr(dev); + if (ret == -ENOSYS) + ret = 0; if (ret) printf("\nWarning: %s failed to set MAC address\n", dev->name); @@ -306,56 +308,84 @@ static int eth_write_hwaddr(struct udevice *dev) return ret; } +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); + int eth_init(void) { - struct udevice *current; + char *ethact = getenv("ethact"); + char *ethrotate = getenv("ethrotate"); + struct udevice *current = NULL; struct udevice *old_current; int ret = -ENODEV; - current = eth_get_dev(); + /* + * When 'ethrotate' variable is set to 'no' and 'ethact' variable + * is already set to an ethernet device, we should stick to 'ethact'. + */ + if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) { + if (ethact) { + current = eth_get_dev_by_name(ethact); + if (!current) + return -EINVAL; + } + } + if (!current) { - printf("No ethernet found.\n"); - return -ENODEV; + current = eth_get_dev(); + if (!current) { + printf("No ethernet found.\n"); + return -ENODEV; + } } old_current = current; do { - debug("Trying %s\n", current->name); - - if (device_active(current)) { - uchar env_enetaddr[6]; - struct eth_pdata *pdata = current->platdata; - int enetaddr_changed = 0; - - /* Sync environment with network device */ - if (eth_getenv_enetaddr_by_index("eth", current->seq, - env_enetaddr)) { - enetaddr_changed = memcmp(pdata->enetaddr, - env_enetaddr, 6); - memcpy(pdata->enetaddr, env_enetaddr, 6); + if (current) { + debug("Trying %s\n", 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 { - memset(env_enetaddr, 0, 6); - enetaddr_changed = memcmp(pdata->enetaddr, - env_enetaddr, 6); - memset(pdata->enetaddr, 0, 6); + ret = eth_errno; } - if (enetaddr_changed) - eth_write_hwaddr(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; - } + debug("FAIL\n"); } else { - ret = eth_errno; + debug("PROBE FAIL\n"); } - debug("FAIL\n"); - /* * If ethrotate is enabled, this will change "current", * otherwise we will drop out of this while loop immediately @@ -382,6 +412,17 @@ void eth_halt(void) priv->state = ETH_STATE_PASSIVE; } +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; +} + int eth_send(void *packet, int length) { struct udevice *current; @@ -406,6 +447,7 @@ int eth_rx(void) { struct udevice *current; uchar *packet; + int flags; int ret; int i; @@ -417,8 +459,10 @@ int eth_rx(void) return -EINVAL; /* Process up to 32 packets at one time */ + flags = ETH_RECV_CHECK_DEVICE; for (i = 0; i < 32; i++) { - ret = eth_get_ops(current)->recv(current, &packet); + ret = eth_get_ops(current)->recv(current, flags, &packet); + flags = 0; if (ret > 0) net_process_received_packet(packet, ret); if (ret >= 0 && eth_get_ops(current)->free_pkt) @@ -513,6 +557,34 @@ static int eth_post_probe(struct udevice *dev) struct eth_pdata *pdata = dev->platdata; unsigned char env_enetaddr[6]; +#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 + priv->state = ETH_STATE_INIT; /* Check if the device has a MAC address in ROM */ @@ -538,9 +610,15 @@ static int eth_post_probe(struct udevice *dev) printf("\nWarning: %s using MAC address from ROM\n", dev->name); } else if (is_zero_ethaddr(pdata->enetaddr)) { +#ifdef CONFIG_NET_RANDOM_ETHADDR + net_random_ethaddr(pdata->enetaddr); + printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", + dev->name, dev->seq, pdata->enetaddr); +#else printf("\nError: %s address not set.\n", dev->name); return -EINVAL; +#endif } return 0; @@ -548,8 +626,13 @@ static int eth_post_probe(struct udevice *dev) static int eth_pre_remove(struct udevice *dev) { + struct eth_pdata *pdata = dev->platdata; + eth_get_ops(dev)->stop(dev); + /* clear the MAC address */ + memset(pdata->enetaddr, 0, 6); + return 0; } @@ -564,7 +647,7 @@ UCLASS_DRIVER(eth) = { .per_device_auto_alloc_size = sizeof(struct eth_device_priv), .flags = DM_UC_FLAG_SEQ_ALIAS, }; -#endif +#endif /* #ifdef CONFIG_DM_ETH */ #ifndef CONFIG_DM_ETH @@ -640,6 +723,37 @@ int eth_get_dev_index(void) return eth_current->index; } +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); + } + } + dev = dev->next; + } while (dev != eth_devices); + + return 0; +} +U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr); + int eth_write_hwaddr(struct eth_device *dev, const char *base_name, int eth_number) { @@ -663,12 +777,16 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, } else if (is_valid_ethaddr(dev->enetaddr)) { eth_setenv_enetaddr_by_index(base_name, eth_number, dev->enetaddr); - printf("\nWarning: %s using MAC address from net device\n", - dev->name); } else if (is_zero_ethaddr(dev->enetaddr)) { +#ifdef CONFIG_NET_RANDOM_ETHADDR + net_random_ethaddr(dev->enetaddr); + printf("\nWarning: %s (eth%d) using random MAC address - %pM\n", + dev->name, eth_number, dev->enetaddr); +#else printf("\nError: %s address not set.\n", dev->name); return -EINVAL; +#endif } if (dev->write_hwaddr && !eth_mac_skip(eth_number)) { @@ -832,36 +950,13 @@ u32 ether_crc(size_t len, unsigned char const *p) int eth_init(void) { - struct eth_device *old_current, *dev; + struct eth_device *old_current; if (!eth_current) { puts("No ethernet found.\n"); return -ENODEV; } - /* Sync environment with network devices */ - dev = eth_devices; - do { - uchar env_enetaddr[6]; - int enetaddr_changed = 0; - - if (eth_getenv_enetaddr_by_index("eth", dev->index, - env_enetaddr)) { - enetaddr_changed = memcmp(dev->enetaddr, - env_enetaddr, 6); - memcpy(dev->enetaddr, env_enetaddr, 6); - } else { - memset(env_enetaddr, 0, 6); - enetaddr_changed = memcmp(dev->enetaddr, - env_enetaddr, 6); - memset(dev->enetaddr, 0, 6); - } - if (enetaddr_changed) - eth_write_hwaddr(dev, "eth", dev->index); - - dev = dev->next; - } while (dev != eth_devices); - old_current = eth_current; do { debug("Trying %s\n", eth_current->name); @@ -889,6 +984,11 @@ void eth_halt(void) eth_current->state = ETH_STATE_PASSIVE; } +int eth_is_active(struct eth_device *dev) +{ + return dev && dev->state == ETH_STATE_ACTIVE; +} + int eth_send(void *packet, int length) { if (!eth_current) @@ -953,6 +1053,17 @@ int eth_receive(void *packet, int length) static void eth_current_changed(void) { char *act = getenv("ethact"); + char *ethrotate; + + /* + * The call to eth_get_dev() below has a side effect of rotating + * ethernet device if uc_priv->current == NULL. This is not what + * we want when 'ethrotate' variable is 'no'. + */ + ethrotate = getenv("ethrotate"); + if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) + return; + /* update current ethernet name */ if (eth_get_dev()) { if (act == NULL || strcmp(act, eth_get_name()) != 0)