mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-25 23:06:15 +00:00

Move the initialization of the ethernet devices out of the new_netif() function. Indeed, new_netif() accepts a struct device argument, which is expected to be valid and active. The activation and selection of this device are achieved by eth_init() (on first time the network stack is used) and eth_set_current(). This is what takes care of the ethrotate and ethact environment variables. Therefore, move these calls to a new function: net_lwip_set_current(), and use it whenever a net-lwip command is run. This patch hopefully fixes the incorrect net-lwip behavior observed on boards with multiple ethernet interfaces [1]. Tested on an i.MX8MPlus EVK equipped wih two ethernet ports. The dhcp command succeeds whether the cable is plugged into the first or second port. [1] https://lists.denx.de/pipermail/u-boot/2025-January/576326.html Reported-by: E Shattow <e@freeshell.de> Tested-by: E Shattow <e@freeshell.de> Signed-off-by: Jerome Forissier <jerome.forissier@linaro.org>
159 lines
3.3 KiB
C
159 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/* Copyright (C) 2024 Linaro Ltd. */
|
|
|
|
#include <command.h>
|
|
#include <console.h>
|
|
#include <log.h>
|
|
#include <dm/device.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/errno.h>
|
|
#include <lwip/dhcp.h>
|
|
#include <lwip/dns.h>
|
|
#include <lwip/timeouts.h>
|
|
#include <net.h>
|
|
#include <time.h>
|
|
|
|
#define DHCP_TIMEOUT_MS 10000
|
|
|
|
#ifdef CONFIG_CMD_TFTPBOOT
|
|
/* Boot file obtained from DHCP (if present) */
|
|
static char boot_file_name[DHCP_BOOT_FILE_LEN];
|
|
#endif
|
|
|
|
static void call_lwip_dhcp_fine_tmr(void *ctx)
|
|
{
|
|
dhcp_fine_tmr();
|
|
sys_timeout(10, call_lwip_dhcp_fine_tmr, NULL);
|
|
}
|
|
|
|
static int dhcp_loop(struct udevice *udev)
|
|
{
|
|
char ipstr[] = "ipaddr\0\0";
|
|
char maskstr[] = "netmask\0\0";
|
|
char gwstr[] = "gatewayip\0\0";
|
|
unsigned long start;
|
|
struct netif *netif;
|
|
struct dhcp *dhcp;
|
|
bool bound;
|
|
int idx;
|
|
|
|
idx = dev_seq(udev);
|
|
if (idx < 0 || idx > 99) {
|
|
log_err("unexpected idx %d\n", idx);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
netif = net_lwip_new_netif_noip(udev);
|
|
if (!netif)
|
|
return CMD_RET_FAILURE;
|
|
|
|
start = get_timer(0);
|
|
|
|
if (dhcp_start(netif))
|
|
return CMD_RET_FAILURE;
|
|
|
|
call_lwip_dhcp_fine_tmr(NULL);
|
|
|
|
/* Wait for DHCP to complete */
|
|
do {
|
|
net_lwip_rx(udev, netif);
|
|
sys_check_timeouts();
|
|
bound = dhcp_supplied_address(netif);
|
|
if (bound)
|
|
break;
|
|
if (ctrlc()) {
|
|
printf("Abort\n");
|
|
break;
|
|
}
|
|
mdelay(1);
|
|
} while (get_timer(start) < DHCP_TIMEOUT_MS);
|
|
|
|
sys_untimeout(call_lwip_dhcp_fine_tmr, NULL);
|
|
|
|
if (!bound) {
|
|
net_lwip_remove_netif(netif);
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
dhcp = netif_dhcp_data(netif);
|
|
|
|
env_set("bootfile", dhcp->boot_file_name);
|
|
|
|
if (idx > 0) {
|
|
sprintf(ipstr, "ipaddr%d", idx);
|
|
sprintf(maskstr, "netmask%d", idx);
|
|
sprintf(gwstr, "gatewayip%d", idx);
|
|
} else {
|
|
net_ip.s_addr = dhcp->offered_ip_addr.addr;
|
|
}
|
|
|
|
env_set(ipstr, ip4addr_ntoa(&dhcp->offered_ip_addr));
|
|
env_set(maskstr, ip4addr_ntoa(&dhcp->offered_sn_mask));
|
|
env_set("serverip", ip4addr_ntoa(&dhcp->server_ip_addr));
|
|
if (dhcp->offered_gw_addr.addr != 0)
|
|
env_set(gwstr, ip4addr_ntoa(&dhcp->offered_gw_addr));
|
|
|
|
#ifdef CONFIG_PROT_DNS_LWIP
|
|
env_set("dnsip", ip4addr_ntoa(dns_getserver(0)));
|
|
env_set("dnsip2", ip4addr_ntoa(dns_getserver(1)));
|
|
#endif
|
|
#ifdef CONFIG_CMD_TFTPBOOT
|
|
if (dhcp->boot_file_name[0] != '\0')
|
|
strncpy(boot_file_name, dhcp->boot_file_name,
|
|
sizeof(boot_file_name));
|
|
#endif
|
|
|
|
printf("DHCP client bound to address %pI4 (%lu ms)\n",
|
|
&dhcp->offered_ip_addr, get_timer(start));
|
|
|
|
net_lwip_remove_netif(netif);
|
|
return CMD_RET_SUCCESS;
|
|
}
|
|
|
|
int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
|
|
{
|
|
int ret;
|
|
struct udevice *dev;
|
|
|
|
net_lwip_set_current();
|
|
|
|
dev = eth_get_dev();
|
|
if (!dev) {
|
|
log_err("No network device\n");
|
|
return CMD_RET_FAILURE;
|
|
}
|
|
|
|
ret = dhcp_loop(dev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (argc > 1) {
|
|
struct cmd_tbl cmdtp = {};
|
|
|
|
return do_tftpb(&cmdtp, 0, argc, argv);
|
|
}
|
|
|
|
return CMD_RET_SUCCESS;
|
|
}
|
|
|
|
int dhcp_run(ulong addr, const char *fname, bool autoload)
|
|
{
|
|
char *dhcp_argv[] = {"dhcp", NULL, };
|
|
#ifdef CONFIG_CMD_TFTPBOOT
|
|
char *tftp_argv[] = {"tftpboot", boot_file_name, NULL, };
|
|
#endif
|
|
struct cmd_tbl cmdtp = {}; /* dummy */
|
|
|
|
if (autoload) {
|
|
#ifdef CONFIG_CMD_TFTPBOOT
|
|
/* Assume DHCP was already performed */
|
|
if (boot_file_name[0])
|
|
return do_tftpb(&cmdtp, 0, 2, tftp_argv);
|
|
return 0;
|
|
#else
|
|
return -EOPNOTSUPP;
|
|
#endif
|
|
}
|
|
|
|
return do_dhcp(&cmdtp, 0, 1, dhcp_argv);
|
|
}
|