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