]>
Commit | Line | Data |
---|---|---|
4fd8d077 SG |
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 <[email protected]> | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <bootdev.h> | |
11 | #include <bootflow.h> | |
12 | #include <command.h> | |
13 | #include <bootmeth.h> | |
14 | #include <distro.h> | |
15 | #include <dm.h> | |
16 | #include <log.h> | |
17 | #include <net.h> | |
18 | ||
19 | static int eth_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, | |
20 | struct bootflow *bflow) | |
21 | { | |
22 | char name[60]; | |
23 | int ret; | |
24 | ||
25 | /* Must be an Ethernet device */ | |
26 | ret = bootflow_iter_uses_network(iter); | |
27 | if (ret) | |
28 | return log_msg_ret("net", ret); | |
29 | ||
30 | ret = bootmeth_check(bflow->method, iter); | |
31 | if (ret) | |
32 | return log_msg_ret("check", ret); | |
33 | ||
34 | /* | |
35 | * Like distro boot, this assumes there is only one Ethernet device. | |
36 | * In this case, that means that @eth is ignored | |
37 | */ | |
38 | ||
39 | snprintf(name, sizeof(name), "%s.%d", dev->name, iter->part); | |
40 | bflow->name = strdup(name); | |
41 | if (!bflow->name) | |
42 | return log_msg_ret("name", -ENOMEM); | |
43 | ||
44 | /* | |
45 | * There is not a direct interface to the network stack so run | |
46 | * everything through the command-line interpreter for now. | |
47 | * | |
48 | * Don't bother checking the result of dhcp. It can fail with: | |
49 | * | |
50 | * DHCP client bound to address 192.168.4.50 (4 ms) | |
51 | * *** Warning: no boot file name; using 'C0A80432.img' | |
52 | * Using smsc95xx_eth device | |
53 | * TFTP from server 192.168.4.1; our IP address is 192.168.4.50 | |
54 | * Filename 'C0A80432.img'. | |
55 | * Load address: 0x200000 | |
56 | * Loading: * | |
57 | * TFTP error: 'File not found' (1) | |
58 | * | |
59 | * This is not a real failure, since we don't actually care if the | |
60 | * boot file exists. | |
61 | */ | |
62 | log_debug("running dhcp\n"); | |
63 | run_command("dhcp", 0); | |
64 | bflow->state = BOOTFLOWST_MEDIA; | |
65 | ||
66 | /* See distro_pxe_read_bootflow() for the standard impl of this */ | |
67 | log_debug("dhcp complete - reading bootflow with method %s\n", | |
68 | bflow->method->name); | |
69 | ret = bootmeth_read_bootflow(bflow->method, bflow); | |
70 | log_debug("reading bootflow returned %d\n", ret); | |
71 | if (ret) | |
72 | return log_msg_ret("method", ret); | |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
77 | static int eth_bootdev_bind(struct udevice *dev) | |
78 | { | |
79 | struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); | |
80 | ||
81 | ucp->prio = BOOTDEVP_4_NET_BASE; | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
86 | struct bootdev_ops eth_bootdev_ops = { | |
87 | .get_bootflow = eth_get_bootflow, | |
88 | }; | |
89 | ||
90 | static const struct udevice_id eth_bootdev_ids[] = { | |
91 | { .compatible = "u-boot,bootdev-eth" }, | |
92 | { } | |
93 | }; | |
94 | ||
95 | U_BOOT_DRIVER(eth_bootdev) = { | |
96 | .name = "eth_bootdev", | |
97 | .id = UCLASS_BOOTDEV, | |
98 | .ops = ð_bootdev_ops, | |
99 | .bind = eth_bootdev_bind, | |
100 | .of_match = eth_bootdev_ids, | |
101 | }; |