X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=net%2Feth.c;h=953b7310bd5cf66362bf04534a552b08eaa3c830;hb=f5b977b30f48486f133c2a0c2875acfddc52745c;hp=1abf0274b489d98b79ef94885682fab0f18095e6;hpb=ab74c2644c3827d9293eb82d0e819c99958c9314;p=karo-tx-uboot.git diff --git a/net/eth.c b/net/eth.c index 1abf0274b4..953b7310bd 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; @@ -32,7 +34,7 @@ void eth_parse_enetaddr(const char *addr, uchar *enetaddr) int eth_getenv_enetaddr(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) @@ -60,25 +62,55 @@ 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(BootFile, s, sizeof(BootFile)); -} - 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 { + printf("Net Initialization Skipped\n"); + } +} + #ifdef CONFIG_DM_ETH /** * struct eth_device_priv - private structure for each Ethernet device @@ -98,6 +130,9 @@ struct eth_uclass_priv { struct udevice *current; }; +/* eth_errno - This stores the most recent failure code from DM functions */ +static int eth_errno; + static struct eth_uclass_priv *eth_get_uclass_priv(void) { struct uclass *uc; @@ -118,23 +153,75 @@ static void eth_set_current_to_next(void) uclass_first_device(UCLASS_ETH, &uc_priv->current); } +/* + * 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. + */ struct udevice *eth_get_dev(void) { struct eth_uclass_priv *uc_priv; uc_priv = eth_get_uclass_priv(); if (!uc_priv->current) - uclass_first_device(UCLASS_ETH, + eth_errno = uclass_first_device(UCLASS_ETH, &uc_priv->current); return uc_priv->current; } +/* + * 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. + */ static void eth_set_dev(struct udevice *dev) { - device_probe(dev); + if (dev && !device_active(dev)) + eth_errno = device_probe(dev); eth_get_uclass_priv()->current = dev; } +/* + * Find the udevice that either has the name passed in as devname or has an + * alias named devname. + */ +struct udevice *eth_get_dev_by_name(const char *devname) +{ + int seq = -1; + char *endp = NULL; + const char *startp = NULL; + struct udevice *it; + struct uclass *uc; + + /* Must be longer than 3 to be an alias */ + if (strlen(devname) > strlen("eth")) { + startp = devname + strlen("eth"); + seq = simple_strtoul(startp, &endp, 10); + } + + uclass_get(UCLASS_ETH, &uc); + uclass_foreach_dev(it, uc) { + /* + * 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(). + */ + device_probe(it); + /* + * Check for the name or the sequence number to match + */ + if (strcmp(it->name, devname) == 0 || + (endp > startp && it->seq == seq)) + return it; + } + + return NULL; +} + unsigned char *eth_get_ethaddr(void) { struct eth_pdata *pdata; @@ -184,10 +271,63 @@ 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; + } + + ret = eth_get_ops(dev)->write_hwaddr(dev); + 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; struct udevice *old_current; + int ret = -ENODEV; current = eth_get_dev(); if (!current) { @@ -200,32 +340,30 @@ int eth_init(void) 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); - - if (eth_get_ops(current)->start(current) >= 0) { + 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; } + debug("FAIL\n"); - /* This will ensure the new "current" attempted to probe */ + /* + * If ethrotate is enabled, this will change "current", + * otherwise we will drop out of this while loop immediately + */ eth_try_another(0); + /* This will ensure the new "current" attempted to probe */ current = eth_get_dev(); } while (old_current != current); - return -ENODEV; + return ret; } void eth_halt(void) @@ -245,6 +383,7 @@ void eth_halt(void) int eth_send(void *packet, int length) { struct udevice *current; + int ret; current = eth_get_dev(); if (!current) @@ -253,12 +392,20 @@ int eth_send(void *packet, int length) if (!device_active(current)) return -EINVAL; - return eth_get_ops(current)->send(current, packet, length); + 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\n", __func__, ret); + } + return ret; } int eth_rx(void) { struct udevice *current; + uchar *packet; + int ret; + int i; current = eth_get_dev(); if (!current) @@ -267,31 +414,22 @@ int eth_rx(void) if (!device_active(current)) return -EINVAL; - return eth_get_ops(current)->recv(current); -} - -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); + /* Process up to 32 packets at one time */ + for (i = 0; i < 32; i++) { + ret = eth_get_ops(current)->recv(current, &packet); + if (ret > 0) + net_process_received_packet(packet, ret); + if (ret >= 0 && eth_get_ops(current)->free_pkt) + eth_get_ops(current)->free_pkt(current, packet, ret); + if (ret <= 0) + break; + } + if (ret == -EAGAIN) + ret = 0; + if (ret < 0) { + /* We cannot completely return the error at present */ + debug("%s: recv() returned error %d\n", __func__, ret); } - return ret; } @@ -300,8 +438,7 @@ 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 @@ -314,6 +451,18 @@ int eth_initialize(void) printf("No ethernet found.\n"); bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { + 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); + } + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { if (num_devices) @@ -321,6 +470,9 @@ int eth_initialize(void) printf("eth%d: %s", dev->seq, dev->name); + if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + eth_write_hwaddr(dev); uclass_next_device(&dev); @@ -366,8 +518,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); @@ -379,14 +531,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; @@ -408,20 +566,11 @@ UCLASS_DRIVER(eth) = { .pre_remove = eth_pre_remove, .priv_auto_alloc_size = sizeof(struct eth_uclass_priv), .per_device_auto_alloc_size = sizeof(struct eth_device_priv), + .flags = DM_UC_FLAG_SEQ_ALIAS, }; #endif #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 { @@ -440,6 +589,11 @@ static void eth_set_current_to_next(void) eth_current = eth_current->next; } +static void eth_set_dev(struct eth_device *dev) +{ + eth_current = dev; +} + struct eth_device *eth_get_dev_by_name(const char *devname) { struct eth_device *dev, *target_dev; @@ -490,6 +644,36 @@ 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); + } + } + } 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) { @@ -498,39 +682,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; @@ -544,7 +735,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) @@ -591,32 +783,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"); @@ -659,14 +829,14 @@ int eth_initialize(void) * mcast_addr: multicast ipaddr from which multicast Mac is made * join: 1=join, 0=leave. */ -int eth_mcast_join(IPaddr_t mcast_ip, int join) +int eth_mcast_join(struct in_addr mcast_ip, int join) { u8 mcast_mac[6]; if (!eth_current || !eth_current->mcast) return -1; - mcast_mac[5] = htonl(mcast_ip) & 0xff; - mcast_mac[4] = (htonl(mcast_ip)>>8) & 0xff; - mcast_mac[3] = (htonl(mcast_ip)>>16) & 0x7f; + 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; mcast_mac[2] = 0x5e; mcast_mac[1] = 0x0; mcast_mac[0] = 0x1; @@ -702,25 +872,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); @@ -849,14 +1007,13 @@ 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) { static char *act; static int env_changed_id; - void *old_current; int env_id; env_id = get_env_id(); @@ -864,13 +1021,19 @@ void eth_set_current(void) act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_get_dev(); - do { - if (strcmp(eth_get_name(), act) == 0) - return; - eth_set_current_to_next(); - } while (old_current != eth_get_dev()); + + 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 { + eth_set_dev(eth_get_dev_by_name(act)); } eth_current_changed();