X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=net%2Feth.c;h=c542f4aa3b3b1e4f2e6fbb5db4c0ea579aefe45e;hb=5e68ff3949a3eebf62ba639171814f39c8e46a84;hp=f06fdb27439ce2903ca9fb4f25c74b7d9aea7d69;hpb=1411157d857840da444db63f6ba3a3a658a99c5b;p=oweals%2Fu-boot.git diff --git a/net/eth.c b/net/eth.c index f06fdb2743..c542f4aa3b 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_ether_addr(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,26 +62,57 @@ 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]; char *skip_state; + sprintf(enetvar, index ? "eth%dmacskip" : "ethmacskip", index); - return ((skip_state = getenv(enetvar)) != NULL); + skip_state = getenv(enetvar); + return skip_state != NULL; } static void eth_current_changed(void); +/* + * 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 + + /* + * 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\n"); + } else if (cpu_eth_init != __def_eth_init) { + if (cpu_eth_init(gd->bd) < 0) + printf("CPU Net Initialization Failed\n"); + } else { +#ifndef CONFIG_DM_ETH + printf("Net Initialization Skipped\n"); +#endif + } +} + #ifdef CONFIG_DM_ETH /** * struct eth_device_priv - private structure for each Ethernet device @@ -146,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; } @@ -162,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); } @@ -179,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; @@ -240,6 +277,64 @@ int eth_get_dev_index(void) return -1; } +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("\nError: %s address %pM illegal value\n", + dev->name, pdata->enetaddr); + 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); + } + + 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; @@ -254,31 +349,26 @@ int eth_init(void) old_current = current; do { - debug("Trying %s\n", current->name); - - if (device_active(current)) { - uchar env_enetaddr[6]; - struct eth_pdata *pdata = current->platdata; - - /* Sync environment with network device */ - if (eth_getenv_enetaddr_by_index("eth", current->seq, - env_enetaddr)) - memcpy(pdata->enetaddr, env_enetaddr, 6); - else - memset(pdata->enetaddr, 0, 6); - - 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; + 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 { + ret = eth_errno; } - } else - ret = eth_errno; - debug("FAIL\n"); + debug("FAIL\n"); + } else { + debug("PROBE FAIL\n"); + } /* * If ethrotate is enabled, this will change "current", @@ -306,6 +396,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; @@ -330,6 +431,7 @@ int eth_rx(void) { struct udevice *current; uchar *packet; + int flags; int ret; int i; @@ -341,8 +443,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) @@ -359,38 +463,12 @@ int eth_rx(void) return ret; } -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_ether_addr(pdata->enetaddr)) { - printf("\nError: %s address %pM illegal value\n", - dev->name, pdata->enetaddr); - return -EINVAL; - } - - ret = eth_get_ops(dev)->write_hwaddr(dev); - if (ret) - printf("\nWarning: %s failed to set MAC address\n", - dev->name); - } - - return ret; -} - int eth_initialize(void) { int num_devices = 0; struct udevice *dev; - bootstage_mark(BOOTSTAGE_ID_NET_ETH_START); - eth_env_init(); + eth_common_init(); /* * Devices need to write the hwaddr even if not started so that Linux @@ -470,8 +548,8 @@ static int eth_post_probe(struct udevice *dev) eth_get_ops(dev)->read_rom_hwaddr(dev); eth_getenv_enetaddr_by_index("eth", dev->seq, env_enetaddr); - if (!is_zero_ether_addr(env_enetaddr)) { - if (!is_zero_ether_addr(pdata->enetaddr) && + if (!is_zero_ethaddr(env_enetaddr)) { + if (!is_zero_ethaddr(pdata->enetaddr) && memcmp(pdata->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", dev->name); @@ -483,14 +561,20 @@ static int eth_post_probe(struct udevice *dev) /* Override the ROM MAC address */ memcpy(pdata->enetaddr, env_enetaddr, 6); - } else if (is_valid_ether_addr(pdata->enetaddr)) { + } else if (is_valid_ethaddr(pdata->enetaddr)) { eth_setenv_enetaddr_by_index("eth", dev->seq, pdata->enetaddr); printf("\nWarning: %s using MAC address from ROM\n", dev->name); - } else if (is_zero_ether_addr(pdata->enetaddr)) { + } 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; @@ -498,8 +582,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; } @@ -514,19 +603,9 @@ 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 -/* - * 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"))); #ifdef CONFIG_API static struct { @@ -600,6 +679,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) { @@ -608,39 +718,46 @@ int eth_write_hwaddr(struct eth_device *dev, const char *base_name, eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr); - if (!is_zero_ether_addr(env_enetaddr)) { - if (!is_zero_ether_addr(dev->enetaddr) && + if (!is_zero_ethaddr(env_enetaddr)) { + if (!is_zero_ethaddr(dev->enetaddr) && memcmp(dev->enetaddr, env_enetaddr, 6)) { printf("\nWarning: %s MAC addresses don't match:\n", - dev->name); + dev->name); printf("Address in SROM is %pM\n", - dev->enetaddr); + dev->enetaddr); printf("Address in environment is %pM\n", - env_enetaddr); + env_enetaddr); } memcpy(dev->enetaddr, env_enetaddr, 6); - } else if (is_valid_ether_addr(dev->enetaddr)) { + } 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_ether_addr(dev->enetaddr)) { + 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)) { - if (!is_valid_ether_addr(dev->enetaddr)) { + if (!is_valid_ethaddr(dev->enetaddr)) { printf("\nError: %s address %pM illegal value\n", - dev->name, dev->enetaddr); + dev->name, dev->enetaddr); return -EINVAL; } ret = dev->write_hwaddr(dev); if (ret) - printf("\nWarning: %s failed to set MAC address\n", dev->name); + printf("\nWarning: %s failed to set MAC address\n", + dev->name); } return ret; @@ -654,7 +771,8 @@ int eth_register(struct eth_device *dev) assert(strlen(dev->name) < sizeof(dev->name)); if (!eth_devices) { - eth_current = eth_devices = dev; + eth_devices = dev; + eth_current = dev; eth_current_changed(); } else { for (d = eth_devices; d->next != eth_devices; d = d->next) @@ -701,32 +819,10 @@ int eth_unregister(struct eth_device *dev) int eth_initialize(void) { int num_devices = 0; + eth_devices = NULL; eth_current = NULL; - - 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 - - eth_env_init(); - - /* - * 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\n"); - } else if (cpu_eth_init != __def_eth_init) { - if (cpu_eth_init(gd->bd) < 0) - printf("CPU Net Initialization Failed\n"); - } else - printf("Net Initialization Skipped\n"); + eth_common_init(); if (!eth_devices) { puts("No ethernet found.\n"); @@ -812,25 +908,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]; - - if (eth_getenv_enetaddr_by_index("eth", dev->index, - env_enetaddr)) - memcpy(dev->enetaddr, env_enetaddr, 6); - - dev = dev->next; - } while (dev != eth_devices); - old_current = eth_current; do { debug("Trying %s\n", eth_current->name); @@ -858,6 +942,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) @@ -959,7 +1048,7 @@ void eth_try_another(int first_restart) eth_current_changed(); if (first_failed == eth_get_dev()) - NetRestartWrap = 1; + net_restart_wrap = 1; } void eth_set_current(void)