uboot/net/eth_legacy.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2001-2015
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 * Joe Hershberger, National Instruments
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9#include <common.h>
  10#include <command.h>
  11#include <environment.h>
  12#include <net.h>
  13#include <phy.h>
  14#include <asm/errno.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                                eth_parse_enetaddr(value, dev->enetaddr);
 121                                break;
 122                        case env_op_delete:
 123                                memset(dev->enetaddr, 0, 6);
 124                        }
 125                }
 126                dev = dev->next;
 127        } while (dev != eth_devices);
 128
 129        return 0;
 130}
 131U_BOOT_ENV_CALLBACK(ethaddr, on_ethaddr);
 132
 133int eth_write_hwaddr(struct eth_device *dev, const char *base_name,
 134                   int eth_number)
 135{
 136        unsigned char env_enetaddr[6];
 137        int ret = 0;
 138
 139        eth_getenv_enetaddr_by_index(base_name, eth_number, env_enetaddr);
 140
 141        if (!is_zero_ethaddr(env_enetaddr)) {
 142                if (!is_zero_ethaddr(dev->enetaddr) &&
 143                    memcmp(dev->enetaddr, env_enetaddr, 6)) {
 144                        printf("\nWarning: %s MAC addresses don't match:\n",
 145                               dev->name);
 146                        printf("Address in SROM is         %pM\n",
 147                               dev->enetaddr);
 148                        printf("Address in environment is  %pM\n",
 149                               env_enetaddr);
 150                }
 151
 152                memcpy(dev->enetaddr, env_enetaddr, 6);
 153        } else if (is_valid_ethaddr(dev->enetaddr)) {
 154                eth_setenv_enetaddr_by_index(base_name, eth_number,
 155                                             dev->enetaddr);
 156        } else if (is_zero_ethaddr(dev->enetaddr)) {
 157#ifdef CONFIG_NET_RANDOM_ETHADDR
 158                net_random_ethaddr(dev->enetaddr);
 159                printf("\nWarning: %s (eth%d) using random MAC address - %pM\n",
 160                       dev->name, eth_number, dev->enetaddr);
 161#else
 162                printf("\nError: %s address not set.\n",
 163                       dev->name);
 164                return -EINVAL;
 165#endif
 166        }
 167
 168        if (dev->write_hwaddr && !eth_mac_skip(eth_number)) {
 169                if (!is_valid_ethaddr(dev->enetaddr)) {
 170                        printf("\nError: %s address %pM illegal value\n",
 171                               dev->name, dev->enetaddr);
 172                        return -EINVAL;
 173                }
 174
 175                ret = dev->write_hwaddr(dev);
 176                if (ret)
 177                        printf("\nWarning: %s failed to set MAC address\n",
 178                               dev->name);
 179        }
 180
 181        return ret;
 182}
 183
 184int eth_register(struct eth_device *dev)
 185{
 186        struct eth_device *d;
 187        static int index;
 188
 189        assert(strlen(dev->name) < sizeof(dev->name));
 190
 191        if (!eth_devices) {
 192                eth_devices = dev;
 193                eth_current = dev;
 194                eth_current_changed();
 195        } else {
 196                for (d = eth_devices; d->next != eth_devices; d = d->next)
 197                        ;
 198                d->next = dev;
 199        }
 200
 201        dev->state = ETH_STATE_INIT;
 202        dev->next  = eth_devices;
 203        dev->index = index++;
 204
 205        return 0;
 206}
 207
 208int eth_unregister(struct eth_device *dev)
 209{
 210        struct eth_device *cur;
 211
 212        /* No device */
 213        if (!eth_devices)
 214                return -ENODEV;
 215
 216        for (cur = eth_devices; cur->next != eth_devices && cur->next != dev;
 217             cur = cur->next)
 218                ;
 219
 220        /* Device not found */
 221        if (cur->next != dev)
 222                return -ENODEV;
 223
 224        cur->next = dev->next;
 225
 226        if (eth_devices == dev)
 227                eth_devices = dev->next == eth_devices ? NULL : dev->next;
 228
 229        if (eth_current == dev) {
 230                eth_current = eth_devices;
 231                eth_current_changed();
 232        }
 233
 234        return 0;
 235}
 236
 237int eth_initialize(void)
 238{
 239        int num_devices = 0;
 240
 241        eth_devices = NULL;
 242        eth_current = NULL;
 243        eth_common_init();
 244        /*
 245         * If board-specific initialization exists, call it.
 246         * If not, call a CPU-specific one
 247         */
 248        if (board_eth_init != __def_eth_init) {
 249                if (board_eth_init(gd->bd) < 0)
 250                        printf("Board Net Initialization Failed\n");
 251        } else if (cpu_eth_init != __def_eth_init) {
 252                if (cpu_eth_init(gd->bd) < 0)
 253                        printf("CPU Net Initialization Failed\n");
 254        } else {
 255                printf("Net Initialization Skipped\n");
 256        }
 257
 258        if (!eth_devices) {
 259                puts("No ethernet found.\n");
 260                bootstage_error(BOOTSTAGE_ID_NET_ETH_START);
 261        } else {
 262                struct eth_device *dev = eth_devices;
 263                char *ethprime = getenv("ethprime");
 264
 265                bootstage_mark(BOOTSTAGE_ID_NET_ETH_INIT);
 266                do {
 267                        if (dev->index)
 268                                puts(", ");
 269
 270                        printf("%s", dev->name);
 271
 272                        if (ethprime && strcmp(dev->name, ethprime) == 0) {
 273                                eth_current = dev;
 274                                puts(" [PRIME]");
 275                        }
 276
 277                        if (strchr(dev->name, ' '))
 278                                puts("\nWarning: eth device name has a space!"
 279                                        "\n");
 280
 281                        eth_write_hwaddr(dev, "eth", dev->index);
 282
 283                        dev = dev->next;
 284                        num_devices++;
 285                } while (dev != eth_devices);
 286
 287                eth_current_changed();
 288                putc('\n');
 289        }
 290
 291        return num_devices;
 292}
 293
 294#ifdef CONFIG_MCAST_TFTP
 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[6];
 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
 313/* the 'way' for ethernet-CRC-32. Spliced in from Linux lib/crc32.c
 314 * and this is the ethernet-crc method needed for TSEC -- and perhaps
 315 * some other adapter -- hash tables
 316 */
 317#define CRCPOLY_LE 0xedb88320
 318u32 ether_crc(size_t len, unsigned char const *p)
 319{
 320        int i;
 321        u32 crc;
 322        crc = ~0;
 323        while (len--) {
 324                crc ^= *p++;
 325                for (i = 0; i < 8; i++)
 326                        crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
 327        }
 328        /* an reverse the bits, cuz of way they arrive -- last-first */
 329        crc = (crc >> 16) | (crc << 16);
 330        crc = (crc >> 8 & 0x00ff00ff) | (crc << 8 & 0xff00ff00);
 331        crc = (crc >> 4 & 0x0f0f0f0f) | (crc << 4 & 0xf0f0f0f0);
 332        crc = (crc >> 2 & 0x33333333) | (crc << 2 & 0xcccccccc);
 333        crc = (crc >> 1 & 0x55555555) | (crc << 1 & 0xaaaaaaaa);
 334        return crc;
 335}
 336
 337#endif
 338
 339
 340int eth_init(void)
 341{
 342        struct eth_device *old_current;
 343
 344        if (!eth_current) {
 345                puts("No ethernet found.\n");
 346                return -ENODEV;
 347        }
 348
 349        old_current = eth_current;
 350        do {
 351                debug("Trying %s\n", eth_current->name);
 352
 353                if (eth_current->init(eth_current, gd->bd) >= 0) {
 354                        eth_current->state = ETH_STATE_ACTIVE;
 355
 356                        return 0;
 357                }
 358                debug("FAIL\n");
 359
 360                eth_try_another(0);
 361        } while (old_current != eth_current);
 362
 363        return -ETIMEDOUT;
 364}
 365
 366void eth_halt(void)
 367{
 368        if (!eth_current)
 369                return;
 370
 371        eth_current->halt(eth_current);
 372
 373        eth_current->state = ETH_STATE_PASSIVE;
 374}
 375
 376int eth_is_active(struct eth_device *dev)
 377{
 378        return dev && dev->state == ETH_STATE_ACTIVE;
 379}
 380
 381int eth_send(void *packet, int length)
 382{
 383        if (!eth_current)
 384                return -ENODEV;
 385
 386        return eth_current->send(eth_current, packet, length);
 387}
 388
 389int eth_rx(void)
 390{
 391        if (!eth_current)
 392                return -ENODEV;
 393
 394        return eth_current->recv(eth_current);
 395}
 396
 397#ifdef CONFIG_API
 398static void eth_save_packet(void *packet, int length)
 399{
 400        char *p = packet;
 401        int i;
 402
 403        if ((eth_rcv_last+1) % PKTBUFSRX == eth_rcv_current)
 404                return;
 405
 406        if (PKTSIZE < length)
 407                return;
 408
 409        for (i = 0; i < length; i++)
 410                eth_rcv_bufs[eth_rcv_last].data[i] = p[i];
 411
 412        eth_rcv_bufs[eth_rcv_last].length = length;
 413        eth_rcv_last = (eth_rcv_last + 1) % PKTBUFSRX;
 414}
 415
 416int eth_receive(void *packet, int length)
 417{
 418        char *p = packet;
 419        void *pp = push_packet;
 420        int i;
 421
 422        if (eth_rcv_current == eth_rcv_last) {
 423                push_packet = eth_save_packet;
 424                eth_rx();
 425                push_packet = pp;
 426
 427                if (eth_rcv_current == eth_rcv_last)
 428                        return -1;
 429        }
 430
 431        length = min(eth_rcv_bufs[eth_rcv_current].length, length);
 432
 433        for (i = 0; i < length; i++)
 434                p[i] = eth_rcv_bufs[eth_rcv_current].data[i];
 435
 436        eth_rcv_current = (eth_rcv_current + 1) % PKTBUFSRX;
 437        return length;
 438}
 439#endif /* CONFIG_API */
 440