uboot/net/eth_bootdev.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Bootdevice for ethernet (uses PXE)
   4 *
   5 * Copyright 2021 Google LLC
   6 * Written by Simon Glass <sjg@chromium.org>
   7 */
   8
   9#define LOG_CATEGORY UCLASS_BOOTSTD
  10
  11#include <common.h>
  12#include <bootdev.h>
  13#include <bootflow.h>
  14#include <command.h>
  15#include <bootmeth.h>
  16#include <distro.h>
  17#include <dm.h>
  18#include <init.h>
  19#include <log.h>
  20#include <net.h>
  21#include <test/test.h>
  22
  23static int eth_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
  24                            struct bootflow *bflow)
  25{
  26        char name[60];
  27        int ret;
  28
  29        /* Must be an Ethernet device */
  30        ret = bootflow_iter_check_net(iter);
  31        if (ret)
  32                return log_msg_ret("net", ret);
  33
  34        ret = bootmeth_check(bflow->method, iter);
  35        if (ret)
  36                return log_msg_ret("check", ret);
  37
  38        /*
  39         * Like distro boot, this assumes there is only one Ethernet device.
  40         * In this case, that means that @eth is ignored
  41         */
  42
  43        snprintf(name, sizeof(name), "%s.%d", dev->name, iter->part);
  44        bflow->name = strdup(name);
  45        if (!bflow->name)
  46                return log_msg_ret("name", -ENOMEM);
  47
  48        /* See distro_pxe_read_bootflow() for the standard impl of this */
  49        log_debug("dhcp complete - reading bootflow with method '%s'\n",
  50                  bflow->method->name);
  51        ret = bootmeth_read_bootflow(bflow->method, bflow);
  52        log_debug("reading bootflow returned %d\n", ret);
  53        if (ret)
  54                return log_msg_ret("method", ret);
  55
  56        return 0;
  57}
  58
  59static int eth_bootdev_bind(struct udevice *dev)
  60{
  61        struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
  62
  63        ucp->prio = BOOTDEVP_6_NET_BASE;
  64
  65        return 0;
  66}
  67
  68static int eth_bootdev_hunt(struct bootdev_hunter *info, bool show)
  69{
  70        int ret;
  71
  72        if (!test_eth_enabled())
  73                return 0;
  74
  75        /* init PCI first since this is often used to provide Ehternet */
  76        if (IS_ENABLED(CONFIG_PCI)) {
  77                ret = pci_init();
  78                if (ret)
  79                        log_warning("Failed to init PCI (%dE)\n", ret);
  80        }
  81
  82        /*
  83         * Ethernet devices can also come from USB, but that is a higher
  84         * priority (BOOTDEVP_5_SCAN_SLOW) than ethernet, so it should have been
  85         * enumerated already. If something like 'bootflow scan dhcp' is used
  86         * then the user will need to run 'usb start' first.
  87         */
  88        if (IS_ENABLED(CONFIG_CMD_DHCP)) {
  89                ret = dhcp_run(0, NULL, false);
  90                if (ret)
  91                        return -EINVAL;
  92        }
  93
  94        return 0;
  95}
  96
  97struct bootdev_ops eth_bootdev_ops = {
  98        .get_bootflow   = eth_get_bootflow,
  99};
 100
 101static const struct udevice_id eth_bootdev_ids[] = {
 102        { .compatible = "u-boot,bootdev-eth" },
 103        { }
 104};
 105
 106U_BOOT_DRIVER(eth_bootdev) = {
 107        .name           = "eth_bootdev",
 108        .id             = UCLASS_BOOTDEV,
 109        .ops            = &eth_bootdev_ops,
 110        .bind           = eth_bootdev_bind,
 111        .of_match       = eth_bootdev_ids,
 112};
 113
 114BOOTDEV_HUNTER(eth_bootdev_hunt) = {
 115        .prio           = BOOTDEVP_6_NET_BASE,
 116        .uclass         = UCLASS_ETH,
 117        .hunt           = eth_bootdev_hunt,
 118        .drv            = DM_DRIVER_REF(eth_bootdev),
 119};
 120