X-Git-Url: https://git.kernelconcepts.de/?a=blobdiff_plain;f=net%2Feth.c;h=d3ec8d64d596d3a8e51336617b8de0032c87812b;hb=c640f5efd9e497938adf72f7635a72abb09bb611;hp=7adc9e6f1671a87cc50a4bb0a544e56d520bf673;hpb=c619a0dd89c609e2d7b0468f7da0728621524473;p=karo-tx-uboot.git diff --git a/net/eth.c b/net/eth.c index 7adc9e6f16..d3ec8d64d5 100644 --- a/net/eth.c +++ b/net/eth.c @@ -1,30 +1,23 @@ /* - * (C) Copyright 2001-2010 + * (C) Copyright 2001-2015 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * Joe Hershberger, National Instruments * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA + * SPDX-License-Identifier: GPL-2.0+ */ #include #include +#include +#include #include #include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { @@ -41,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) @@ -53,23 +46,34 @@ int eth_setenv_enetaddr(char *name, const uchar *enetaddr) return setenv(name, buf); } -int eth_getenv_enetaddr_by_index(int index, uchar *enetaddr) +int eth_getenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr) { char enetvar[32]; - sprintf(enetvar, index ? "eth%daddr" : "ethaddr", index); + sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index); return eth_getenv_enetaddr(enetvar, enetaddr); } -#ifdef CONFIG_NET_MULTI +static inline int eth_setenv_enetaddr_by_index(const char *base_name, int index, + uchar *enetaddr) +{ + char enetvar[32]; + sprintf(enetvar, index ? "%s%daddr" : "%saddr", base_name, index); + return eth_setenv_enetaddr(enetvar, enetaddr); +} 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 @@ -81,31 +85,530 @@ static int __def_eth_init(bd_t *bis) 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"))); -extern int mv6436x_eth_initialize(bd_t *); -extern int mv6446x_eth_initialize(bd_t *); +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_API -extern void (*push_packet)(volatile void *, int); +#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 + * + * @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; +}; + +/* 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; + + 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); +} + +/* + * 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) + 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) +{ + 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; + + 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; +} + +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; + struct udevice *old_current; + int ret = -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)) { + 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"); + + /* + * 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 ret; +} + +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; +} + +int eth_send(void *packet, int length) +{ + struct udevice *current; + int ret; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + return -EINVAL; + + 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 flags; + int ret; + int i; + + current = eth_get_dev(); + if (!current) + return -ENODEV; + + if (!device_active(current)) + 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, flags, &packet); + flags = 0; + 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; +} + +int eth_initialize(void) +{ + int num_devices = 0; + struct udevice *dev; + + eth_common_init(); + + /* + * 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.\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) + printf(", "); + + printf("eth%d: %s", dev->seq, dev->name); + + if (ethprime && dev == prime_dev) + printf(" [PRIME]"); + + eth_write_hwaddr(dev); + uclass_next_device(&dev); + num_devices++; + } while (dev); + + putc('\n'); + } + + return num_devices; +} + +static int eth_post_bind(struct udevice *dev) +{ + if (strchr(dev->name, ' ')) { + printf("\nError: eth device name \"%s\" has a space!\n", + 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]; + + 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); + 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); + printf("Address in SROM is %pM\n", + pdata->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + /* Override the ROM MAC address */ + memcpy(pdata->enetaddr, env_enetaddr, 6); + } 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_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; +} + +static int eth_pre_remove(struct udevice *dev) +{ + eth_get_ops(dev)->stop(dev); + + 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), + .flags = DM_UC_FLAG_SEQ_ALIAS, +}; +#endif + +#ifndef CONFIG_DM_ETH + +#ifdef CONFIG_API static struct { uchar data[PKTSIZE]; int length; } eth_rcv_bufs[PKTBUFSRX]; -static unsigned int eth_rcv_current = 0, eth_rcv_last = 0; +static unsigned int eth_rcv_current, eth_rcv_last; #endif -static struct eth_device *eth_devices, *eth_current; +static struct eth_device *eth_devices; +struct eth_device *eth_current; -struct eth_device *eth_get_dev(void) +static void eth_set_current_to_next(void) { - return eth_current; + eth_current = eth_current->next; } -struct eth_device *eth_get_dev_by_name(char *devname) +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; + BUG_ON(devname == NULL); + if (!eth_devices) return NULL; @@ -125,7 +628,6 @@ struct eth_device *eth_get_dev_by_name(char *devname) struct eth_device *eth_get_dev_by_index(int index) { struct eth_device *dev, *target_dev; - int idx = 0; if (!eth_devices) return NULL; @@ -133,53 +635,118 @@ struct eth_device *eth_get_dev_by_index(int index) dev = eth_devices; target_dev = NULL; do { - if (idx == index) { + if (dev->index == index) { target_dev = dev; break; } dev = dev->next; - idx++; } while (dev != eth_devices); return target_dev; } -int eth_get_dev_index (void) +int eth_get_dev_index(void) +{ + if (!eth_current) + return -1; + + 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; - int num = 0; - if (!eth_devices) { - return (-1); - } + if (!eth_devices) + return 0; - for (dev = eth_devices; dev; dev = dev->next) { - if (dev == eth_current) - break; - ++num; + /* 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) +{ + unsigned char env_enetaddr[6]; + int ret = 0; + + eth_getenv_enetaddr_by_index(base_name, eth_number, env_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); + printf("Address in SROM is %pM\n", + dev->enetaddr); + printf("Address in environment is %pM\n", + env_enetaddr); + } + + memcpy(dev->enetaddr, env_enetaddr, 6); + } 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) { - return (num); + if (dev->write_hwaddr && !eth_mac_skip(eth_number)) { + if (!is_valid_ethaddr(dev->enetaddr)) { + printf("\nError: %s address %pM illegal value\n", + dev->name, dev->enetaddr); + return -EINVAL; + } + + ret = dev->write_hwaddr(dev); + if (ret) + printf("\nWarning: %s failed to set MAC address\n", + dev->name); } - return (0); + return ret; } -int eth_register(struct eth_device* dev) +int eth_register(struct eth_device *dev) { struct eth_device *d; + static int index; + + assert(strlen(dev->name) < sizeof(dev->name)); if (!eth_devices) { - eth_current = eth_devices = dev; -#ifdef CONFIG_NET_MULTI - /* update current ethernet name */ - { - char *act = getenv("ethact"); - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } -#endif + eth_devices = dev; + eth_current = dev; + eth_current_changed(); } else { for (d = eth_devices; d->next != eth_devices; d = d->next) ; @@ -188,92 +755,82 @@ int eth_register(struct eth_device* dev) dev->state = ETH_STATE_INIT; dev->next = eth_devices; + dev->index = index++; return 0; } -int eth_initialize(bd_t *bis) +int eth_unregister(struct eth_device *dev) { - unsigned char env_enetaddr[6]; - int eth_number = 0; + struct eth_device *cur; + + /* No device */ + if (!eth_devices) + return -ENODEV; + + for (cur = eth_devices; cur->next != eth_devices && cur->next != dev; + cur = cur->next) + ; + + /* Device not found */ + if (cur->next != dev) + return -ENODEV; + + 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; +} + +int eth_initialize(void) +{ + int num_devices = 0; eth_devices = NULL; eth_current = NULL; + eth_common_init(); - show_boot_progress (64); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - miiphy_init(); -#endif - /* Try board-specific initialization first. If it fails or isn't - * present, try the cpu-specific initialization */ - if (board_eth_init(bis) < 0) - cpu_eth_init(bis); - -#if defined(CONFIG_DB64360) || defined(CONFIG_CPCI750) - mv6436x_eth_initialize(bis); -#endif -#if defined(CONFIG_DB64460) || defined(CONFIG_P3Mx) - mv6446x_eth_initialize(bis); -#endif if (!eth_devices) { - puts ("No ethernet found.\n"); - show_boot_progress (-64); + puts("No ethernet found.\n"); + bootstage_error(BOOTSTAGE_ID_NET_ETH_START); } else { struct eth_device *dev = eth_devices; - char *ethprime = getenv ("ethprime"); + char *ethprime = getenv("ethprime"); - show_boot_progress (65); + bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT); do { - if (eth_number) - puts (", "); + if (dev->index) + puts(", "); printf("%s", dev->name); - if (ethprime && strcmp (dev->name, ethprime) == 0) { + if (ethprime && strcmp(dev->name, ethprime) == 0) { eth_current = dev; - puts (" [PRIME]"); + puts(" [PRIME]"); } - eth_getenv_enetaddr_by_index(eth_number, env_enetaddr); - - if (memcmp(env_enetaddr, "\0\0\0\0\0\0", 6)) { - if (memcmp(dev->enetaddr, "\0\0\0\0\0\0", 6) && - memcmp(dev->enetaddr, env_enetaddr, 6)) - { - printf ("\nWarning: %s MAC addresses don't match:\n", - dev->name); - printf ("Address in SROM is %pM\n", - dev->enetaddr); - printf ("Address in environment is %pM\n", - env_enetaddr); - } - - memcpy(dev->enetaddr, env_enetaddr, 6); - } - if (dev->write_hwaddr && - !eth_mac_skip(eth_number) && - is_valid_ether_addr(dev->enetaddr)) { - dev->write_hwaddr(dev); - } + if (strchr(dev->name, ' ')) + puts("\nWarning: eth device name has a space!" + "\n"); + + eth_write_hwaddr(dev, "eth", dev->index); - eth_number++; dev = dev->next; - } while(dev != eth_devices); - -#ifdef CONFIG_NET_MULTI - /* update current ethernet name */ - if (eth_current) { - char *act = getenv("ethact"); - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } else - setenv("ethact", NULL); -#endif + num_devices++; + } while (dev != eth_devices); - putc ('\n'); + eth_current_changed(); + putc('\n'); } - return eth_number; + return num_devices; } #ifdef CONFIG_MCAST_TFTP @@ -281,14 +838,14 @@ int eth_initialize(bd_t *bis) * mcast_addr: multicast ipaddr from which multicast Mac is made * join: 1=join, 0=leave. */ -int eth_mcast_join( IPaddr_t mcast_ip, u8 join) +int eth_mcast_join(struct in_addr mcast_ip, int join) { - u8 mcast_mac[6]; + 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; @@ -300,7 +857,7 @@ int eth_mcast_join( IPaddr_t mcast_ip, u8 join) * some other adapter -- hash tables */ #define CRCPOLY_LE 0xedb88320 -u32 ether_crc (size_t len, unsigned char const *p) +u32 ether_crc(size_t len, unsigned char const *p) { int i; u32 crc; @@ -322,34 +879,20 @@ u32 ether_crc (size_t len, unsigned char const *p) #endif -int eth_init(bd_t *bis) +int eth_init(void) { - int eth_number; - struct eth_device *old_current, *dev; + struct eth_device *old_current; if (!eth_current) { - puts ("No ethernet found.\n"); - return -1; + puts("No ethernet found.\n"); + return -ENODEV; } - /* Sync environment with network devices */ - eth_number = 0; - dev = eth_devices; - do { - uchar env_enetaddr[6]; - - if (eth_getenv_enetaddr_by_index(eth_number, env_enetaddr)) - memcpy(dev->enetaddr, env_enetaddr, 6); - - ++eth_number; - dev = dev->next; - } while (dev != eth_devices); - old_current = eth_current; do { debug("Trying %s\n", eth_current->name); - if (eth_current->init(eth_current,bis) >= 0) { + if (eth_current->init(eth_current, gd->bd) >= 0) { eth_current->state = ETH_STATE_ACTIVE; return 0; @@ -359,7 +902,7 @@ int eth_init(bd_t *bis) eth_try_another(0); } while (old_current != eth_current); - return -1; + return -ETIMEDOUT; } void eth_halt(void) @@ -372,10 +915,10 @@ void eth_halt(void) eth_current->state = ETH_STATE_PASSIVE; } -int eth_send(volatile void *packet, int length) +int eth_send(void *packet, int length) { if (!eth_current) - return -1; + return -ENODEV; return eth_current->send(eth_current, packet, length); } @@ -383,15 +926,16 @@ int eth_send(volatile void *packet, int length) int eth_rx(void) { if (!eth_current) - return -1; + return -ENODEV; return eth_current->recv(eth_current); } +#endif /* ifndef CONFIG_DM_ETH */ #ifdef CONFIG_API -static void eth_save_packet(volatile void *packet, int length) +static void eth_save_packet(void *packet, int length) { - volatile char *p = packet; + char *p = packet; int i; if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current) @@ -407,9 +951,9 @@ static void eth_save_packet(volatile void *packet, int length) eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX; } -int eth_receive(volatile void *packet, int length) +int eth_receive(void *packet, int length) { - volatile char *p = packet; + char *p = packet; void *pp = push_packet; int i; @@ -422,10 +966,7 @@ int eth_receive(volatile void *packet, int length) return -1; } - if (length < eth_rcv_bufs[eth_rcv_current].length) - return -1; - - length = eth_rcv_bufs[eth_rcv_current].length; + length = min(eth_rcv_bufs[eth_rcv_current].length, length); for (i = 0; i < length; i++) p[i] = eth_rcv_bufs[eth_rcv_current].data[i]; @@ -435,100 +976,79 @@ int eth_receive(volatile void *packet, int length) } #endif /* CONFIG_API */ +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); +} + void eth_try_another(int first_restart) { - static struct eth_device *first_failed = NULL; + static void *first_failed; char *ethrotate; /* * Do not rotate between network interfaces when * 'ethrotate' variable is set to 'no'. */ - if (((ethrotate = getenv ("ethrotate")) != NULL) && - (strcmp(ethrotate, "no") == 0)) + ethrotate = getenv("ethrotate"); + if ((ethrotate != NULL) && (strcmp(ethrotate, "no") == 0)) return; - if (!eth_current) + if (!eth_get_dev()) return; - if (first_restart) { - first_failed = eth_current; - } + if (first_restart) + first_failed = eth_get_dev(); - eth_current = eth_current->next; + eth_set_current_to_next(); -#ifdef CONFIG_NET_MULTI - /* update current ethernet name */ - { - char *act = getenv("ethact"); - if (act == NULL || strcmp(act, eth_current->name) != 0) - setenv("ethact", eth_current->name); - } -#endif + eth_current_changed(); - if (first_failed == eth_current) { - NetRestartWrap = 1; - } + if (first_failed == eth_get_dev()) + net_restart_wrap = 1; } -#ifdef CONFIG_NET_MULTI void eth_set_current(void) { - static char *act = NULL; - static int env_changed_id = 0; - struct eth_device* old_current; + static char *act; + static int env_changed_id; int env_id; - if (!eth_current) /* XXX no current */ - return; - env_id = get_env_id(); if ((act == NULL) || (env_changed_id != env_id)) { act = getenv("ethact"); env_changed_id = env_id; } - if (act != NULL) { - old_current = eth_current; - do { - if (strcmp(eth_current->name, act) == 0) - return; - eth_current = eth_current->next; - } while (old_current != eth_current); - } - setenv("ethact", eth_current->name); -} -#endif - -char *eth_get_name (void) -{ - return (eth_current ? eth_current->name : "unknown"); -} - -#else /* !CONFIG_NET_MULTI */ + if (act == NULL) { + char *ethprime = getenv("ethprime"); + void *dev = NULL; -#warning Ethernet driver is deprecated. Please update to use CONFIG_NET_MULTI - -extern int at91rm9200_miiphy_initialize(bd_t *bis); -extern int mcf52x2_miiphy_initialize(bd_t *bis); -extern int ns7520_miiphy_initialize(bd_t *bis); + 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(); +} -int eth_initialize(bd_t *bis) +const char *eth_get_name(void) { -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) - miiphy_init(); -#endif - -#if defined(CONFIG_AT91RM9200) - at91rm9200_miiphy_initialize(bis); -#endif -#if defined(CONFIG_MCF52x2) - mcf52x2_miiphy_initialize(bis); -#endif -#if defined(CONFIG_DRIVER_NS7520_ETHERNET) - ns7520_miiphy_initialize(bis); -#endif - return 0; + return eth_get_dev() ? eth_get_dev()->name : "unknown"; } -#endif