uboot/net/eth_legacy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2001-2015
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 * Joe Hershberger, National Instruments
   6 */
   7
   8#include <common.h>
   9#include <command.h>
  10#include <env.h>
  11#include <net.h>
  12#include <phy.h>
  13#include <linux/errno.h>
  14#include <net/pcap.h>
  15#include "eth_internal.h"
  16
  17DECLARE_GLOBAL_DATA_PTR;
  18
  19/*
  20 * CPU and board-specific Ethernet initializations.  Aliased function
  21 * signals caller to move on
  22 */
  23static int __def_eth_init(bd_t *bis)
  24{
  25        return -1;
  26}
  27int cpu_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
  28int board_eth_init(bd_t *bis) __attribute__((weak, alias("__def_eth_init")));
  29
  30#ifdef CONFIG_API
  31static struct {
  32        uchar data[PKTSIZE];
  33        int length;
  34} eth_rcv_bufs[PKTBUFSRX];
  35
  36static unsigned int eth_rcv_current, eth_rcv_last;
  37#endif
  38
  39static struct eth_device *eth_devices;
  40struct eth_device *eth_current;
  41
  42void eth_set_current_to_next(void)
  43{
  44        eth_current = eth_current->next;
  45}
  46
  47void eth_set_dev(struct eth_device *dev)
  48{
  49        eth_current = dev;
  50}
  51
  52struct eth_device *eth_get_dev_by_name(const char *devname)
  53{
  54        struct eth_device *dev, *target_dev;
  55
  56        BUG_ON(devname == NULL);
  57
  58        if (!eth_devices)
  59                return NULL;
  60
  61        dev = eth_devices;
  62        target_dev = NULL;
  63        do {
  64                if (strcmp(devname, dev->name) == 0) {
  65                        target_dev = dev;
  66                        break;
  67                }
  68                dev = dev->next;
  69        } while (dev != eth_devices);
  70
  71        return target_dev;
  72}
  73
  74struct eth_device *eth_get_dev_by_index(int index)
  75{
  76        struct eth_device *dev, *target_dev;
  77
  78        if (!eth_devices)
  79                return NULL;
  80
  81        dev = eth_devices;
  82        target_dev = NULL;
  83        do {
  84                if (dev->index == index) {
  85                        target_dev = dev;
  86                        break;
  87                }
  88                dev = dev->next;
  89        } while (dev != eth_devices);
  90
  91        return target_dev;
  92}
  93
  94int eth_get_dev_index(void)
  95{
  96        if (!eth_current)
  97                return -1;
  98
  99        return eth_current->index;
 100}
 101
 102static int on_ethaddr(const char *name, const char *value, enum env_op op,
 103        int flags)
 104{
 105        int index;
 106        struct eth_device *dev;
 107
 108        if (!eth_devices)
 109                return 0;
 110
 111        /* look for an index after "eth" */
 112        index = simple_strtoul(name + 3, NULL, 10);
 113
 114        dev = eth_devices;
 115        do {
 116                if (dev->index == index) {
 117                        switch (op) {
 118                        case env_op_create:
 119                        case env_op_overwrite:
 120                                string_to_enetaddr(value, dev->enetaddr);
 121                                eth_write_hwaddr(dev, "eth", dev->index);
 122                                break;
 123                        case env_op_delete:
 124                                memset(dev->enetaddr, 0, ARP_HLEN);
 125                        }
 126                }
 127                dev = dev->next;
 128        } while (dev != eth_devices);
 129
 130        return 0;
 131}
 132U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
 133
 134int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
 135                   int eth_number)
 136{
 137        unsigned char env_enetaddr[ARP_HLEN];
 138        int ret = 0;
 139
 140        eth_env_get_enetaddr_by_index(base_name, eth_number, env_enetaddr);
 141
 142        if (!is_zero_ethaddr(env_enetaddr)) {
 143                if (!is_zero_ethaddr(dev->enetaddr) &&
 144                    memcmp(dev->enetaddr, env_enetaddr, ARP_HLEN)) {
 145                        printf("\nWarning: %s MAC addresses don't match:\n",
 146                               dev->name);
 147                        printf("Address in SROM is         %pM\n",
 148                               dev->enetaddr);
 149                        printf("Address in environment is  %pM\n",
 150                               env_enetaddr);
 151                }
 152
 153                memcpy(dev->enetaddr, env_enetaddr, ARP_HLEN);
 154        } else if (is_valid_ethaddr(dev->enetaddr)) {
 155                eth_env_set_enetaddr_by_index(base_name, eth_number,
 156                                              dev->enetaddr);
 157        } else if (is_zero_ethaddr(dev->enetaddr)) {
 158#ifdef CONFIG_NET_RANDOM_ETHADDR
 159                net_random_ethaddr(dev->enetaddr);
 160                printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
 161                       dev->name, eth_number, dev->enetaddr);
 162#else
 163                printf("\nError: %s address not set.\n",
 164                       dev->name);
 165                return -EINVAL;
 166#endif
 167        }
 168
 169        if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
 170                if (!is_valid_ethaddr(dev->enetaddr)) {
 171                        printf("\nError: %s address %pM illegal value\n",
 172                               dev->name, dev->enetaddr);
 173                        return -EINVAL;
 174                }
 175
 176                ret = dev->write_hwaddr(dev);
 177                if (ret)
 178                        printf("\nWarning: %s failed to set MAC address\n",
 179                               dev->name);
 180        }
 181
 182        return ret;
 183}
 184
 185int eth_register(struct eth_device *dev)
 186{
 187        struct eth_device *d;
 188        static int index;
 189
 190        assert(strlen(dev->name) < sizeof(dev->name));
 191
 192        if (!eth_devices) {
 193                eth_devices = dev;
 194                eth_current = dev;
 195                eth_current_changed();
 196        } else {
 197                for (d = eth_devices; d->next != eth_devices; d = d->next)
 198                        ;
 199                d->next = dev;
 200        }
 201
 202        dev->state = ETH_STATE_INIT;
 203        dev->next  = eth_devices;
 204        dev->index = index++;
 205
 206        return 0;
 207}
 208
 209int eth_unregister(struct eth_device *dev)
 210{
 211        struct eth_device *cur;
 212
 213        /* No device */
 214        if (!eth_devices)
 215                return -ENODEV;
 216
 217        for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
 218             cur = cur->next)
 219                ;
 220
 221        /* Device not found */
 222        if (cur->next != dev)
 223                return -ENODEV;
 224
 225        cur->next = dev->next;
 226
 227        if (eth_devices == dev)
 228                eth_devices = dev->next == eth_devices ? NULL : dev->next;
 229
 230        if (eth_current == dev) {
 231                eth_current = eth_devices;
 232                eth_current_changed();
 233        }
 234
 235        return 0;
 236}
 237
 238int eth_initialize(void)
 239{
 240        int num_devices = 0;
 241
 242        eth_devices = NULL;
 243        eth_current = NULL;
 244        eth_common_init();
 245        /*
 246         * If board-specific initialization exists, call it.
 247         * If not, call a CPU-specific one
 248         */
 249        if (board_eth_init != __def_eth_init) {
 250                if (board_eth_init(gd->bd) < 0)
 251                        printf("Board Net Initialization Failed\n");
 252        } else if (cpu_eth_init != __def_eth_init) {
 253                if (cpu_eth_init(gd->bd) < 0)
 254                        printf("CPU Net Initialization Failed\n");
 255        } else {
 256                printf("Net Initialization Skipped\n");
 257        }
 258
 259        if (!eth_devices) {
 260                puts("No ethernet found.\n");
 261                bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
 262        } else {
 263                struct eth_device *dev = eth_devices;
 264                char *ethprime = env_get("ethprime");
 265
 266                bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
 267                do {
 268                        if (dev->index)
 269                                puts(", ");
 270
 271                        printf("%s", dev->name);
 272
 273                        if (ethprime && strcmp(dev->name, ethprime) == 0) {
 274                                eth_current = dev;
 275                                puts(" [PRIME]");
 276                        }
 277
 278                        if (strchr(dev->name, ' '))
 279                                puts("\nWarning: eth device name has a space!"
 280                                        "\n");
 281
 282                        eth_write_hwaddr(dev, "eth", dev->index);
 283
 284                        dev = dev->next;
 285                        num_devices++;
 286                } while (dev != eth_devices);
 287
 288                eth_current_changed();
 289                putc('\n');
 290        }
 291
 292        return num_devices;
 293}
 294
 295/* Multicast.
 296 * mcast_addr: multicast ipaddr from which multicast Mac is made
 297 * join: 1=join, 0=leave.
 298 */
 299int eth_mcast_join(struct in_addr mcast_ip, int join)
 300{
 301        u8 mcast_mac[ARP_HLEN];
 302        if (!eth_current || !eth_current->mcast)
 303                return -1;
 304        mcast_mac[5] = htonl(mcast_ip.s_addr) & 0xff;
 305        mcast_mac[4] = (htonl(mcast_ip.s_addr)>>8) & 0xff;
 306        mcast_mac[3] = (htonl(mcast_ip.s_addr)>>16) & 0x7f;
 307        mcast_mac[2] = 0x5e;
 308        mcast_mac[1] = 0x0;
 309        mcast_mac[0] = 0x1;
 310        return eth_current->mcast(eth_current, mcast_mac, join);
 311}
 312
 313int eth_init(void)
 314{
 315        struct eth_device *old_current;
 316
 317        if (!eth_current) {
 318                puts("No ethernet found.\n");
 319                return -ENODEV;
 320        }
 321
 322        old_current = eth_current;
 323        do {
 324                debug("Trying %s\n", eth_current->name);
 325
 326                if (eth_current->init(eth_current, gd->bd) >= 0) {
 327                        eth_current->state = ETH_STATE_ACTIVE;
 328
 329                        return 0;
 330                }
 331                debug("FAIL\n");
 332
 333                eth_try_another(0);
 334        } while (old_current != eth_current);
 335
 336        return -ETIMEDOUT;
 337}
 338
 339void eth_halt(void)
 340{
 341        if (!eth_current)
 342                return;
 343
 344        eth_current->halt(eth_current);
 345
 346        eth_current->state = ETH_STATE_PASSIVE;
 347}
 348
 349int eth_is_active(struct eth_device *dev)
 350{
 351        return dev && dev->state == ETH_STATE_ACTIVE;
 352}
 353
 354int eth_send(void *packet, int length)
 355{
 356        int ret;
 357
 358        if (!eth_current)
 359                return -ENODEV;
 360
 361        ret = eth_current->send(eth_current, packet, length);
 362#if defined(CONFIG_CMD_PCAP)
 363        if (ret >= 0)
 364                pcap_post(packet, lengeth, true);
 365#endif
 366        return ret;
 367}
 368
 369int eth_rx(void)
 370{
 371        if (!eth_current)
 372                return -ENODEV;
 373
 374        return eth_current->recv(eth_current);
 375}
 376
 377#ifdef CONFIG_API
 378static void eth_save_packet(void *packet, int length)
 379{
 380        char *p = packet;
 381        int i;
 382
 383        if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
 384                return;
 385
 386        if (PKTSIZE < length)
 387                return;
 388
 389        for (i = 0; i < length; i++)
 390                eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
 391
 392        eth_rcv_bufs[eth_rcv_last].length = length;
 393        eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
 394}
 395
 396int eth_receive(void *packet, int length)
 397{
 398        char *p = packet;
 399        void *pp = push_packet;
 400        int i;
 401
 402        if (eth_rcv_current == eth_rcv_last) {
 403                push_packet = eth_save_packet;
 404                eth_rx();
 405                push_packet = pp;
 406
 407                if (eth_rcv_current == eth_rcv_last)
 408                        return -1;
 409        }
 410
 411        length = min(eth_rcv_bufs[eth_rcv_current].length, length);
 412
 413        for (i = 0; i < length; i++)
 414                p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
 415
 416        eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
 417        return length;
 418}
 419#endif /* CONFIG_API */
 420