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