From 8c49e53208bbbf68fdb27250d98ca20e267602e6 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 30 Jan 2023 08:20:55 +0100 Subject: net: ifup: have ifup -a poll for link up in parallel DHCP is usually fairly quick, but link up check timeout is 10 seconds, which adds up, especially on systems with bigger DSA switches. The workaround is to set ethX.mode=disabled for other ports, but let's improve the default a bit and have barebox poll link ups in parallel, so instead of (number_of_ports_wihout_link * 10s), we just wait 10s at most. For setups where this is a problem, users may revert to ifup in sequence by doing ifup -a -s. Signed-off-by: Ahmad Fatoum Link: https://lore.barebox.org/20230130072057.34349-2-a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer --- net/eth.c | 28 ++++++++++++----- net/ifup.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 102 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/net/eth.c b/net/eth.c index 6fb64afea0..ccac5e2a64 100644 --- a/net/eth.c +++ b/net/eth.c @@ -176,13 +176,29 @@ int eth_complete(struct string_list *sl, char *instr) } #endif +int eth_carrier_poll_once(struct eth_device *edev) +{ + int ret; + + if (!IS_ENABLED(CONFIG_PHYLIB)) + return 0; + + if (!edev->phydev) + return 0; + + ret = phy_update_status(edev->phydev); + if (ret) + return ret; + + edev->last_link_check = get_time_ns(); + return edev->phydev->link ? 0 : -ENETDOWN; +} + /* * Check for link if we haven't done so for longer. */ static int eth_carrier_check(struct eth_device *edev, bool may_wait) { - int ret; - if (!IS_ENABLED(CONFIG_PHYLIB)) return 0; @@ -190,12 +206,8 @@ static int eth_carrier_check(struct eth_device *edev, bool may_wait) return 0; if (!edev->last_link_check || - is_timeout(edev->last_link_check, 5 * SECOND)) { - ret = phy_update_status(edev->phydev); - if (ret) - return ret; - edev->last_link_check = get_time_ns(); - } + is_timeout(edev->last_link_check, 5 * SECOND)) + eth_carrier_poll_once(edev); if (may_wait && !edev->phydev->link) { phy_wait_aneg_done(edev->phydev); diff --git a/net/ifup.c b/net/ifup.c index e4d5374db3..c491ea03c1 100644 --- a/net/ifup.c +++ b/net/ifup.c @@ -179,6 +179,28 @@ static void set_linux_bootarg(struct eth_device *edev) } } +static int ifup_edev_conf(struct eth_device *edev, unsigned flags) +{ + int ret; + + if (edev->global_mode == ETH_MODE_DHCP) { + if (IS_ENABLED(CONFIG_NET_DHCP)) { + ret = dhcp(edev, NULL); + } else { + dev_err(&edev->dev, "DHCP support not available\n"); + ret = -ENOSYS; + } + if (ret) + return ret; + } + + set_linux_bootarg(edev); + + edev->ifup = true; + + return 0; +} + int ifup_edev(struct eth_device *edev, unsigned flags) { int ret; @@ -205,22 +227,10 @@ int ifup_edev(struct eth_device *edev, unsigned flags) if (ret) return ret; - if (edev->global_mode == ETH_MODE_DHCP) { - if (IS_ENABLED(CONFIG_NET_DHCP)) { - ret = dhcp(edev, NULL); - } else { - dev_err(&edev->dev, "DHCP support not available\n"); - ret = -ENOSYS; - } - if (ret) - return ret; - } - - set_linux_bootarg(edev); - - edev->ifup = true; + if (flags & IFUP_FLAG_SKIP_CONF) + return 1; - return 0; + return ifup_edev_conf(edev, flags); } void ifdown_edev(struct eth_device *edev) @@ -260,9 +270,54 @@ int ifdown(const char *ethname) static int net_ifup_force_detect; -int ifup_all(unsigned flags) +static bool ifup_edev_need_conf(struct eth_device *edev) +{ + return edev->active && !edev->ifup && + edev->global_mode != ETH_MODE_DISABLED; +} + +static void __ifup_all_parallel(unsigned flags) { struct eth_device *edev; + unsigned netdev_count = 0; + u64 start; + int ret; + + for_each_netdev(edev) { + ret = ifup_edev(edev, flags | IFUP_FLAG_SKIP_CONF); + if (ret == 1) + netdev_count++; + } + + start = get_time_ns(); + while (netdev_count && !is_timeout(start, PHY_AN_TIMEOUT * SECOND)) { + for_each_netdev(edev) { + if (!ifup_edev_need_conf(edev)) + continue; + + ret = eth_carrier_poll_once(edev); + if (ret) + continue; + + ifup_edev_conf(edev, flags); + if (!edev->ifup) + continue; + + netdev_count--; + } + } +} + +static void __ifup_all_sequence(unsigned flags) +{ + struct eth_device *edev; + + for_each_netdev(edev) + ifup_edev(edev, flags); +} + +int ifup_all(unsigned flags) +{ DIR *dir; struct dirent *d; @@ -285,8 +340,10 @@ int ifup_all(unsigned flags) list_empty(&netdev_list)) device_detect_all(); - for_each_netdev(edev) - ifup_edev(edev, flags); + if (flags & IFUP_FLAG_PARALLEL) + __ifup_all_parallel(flags); + else + __ifup_all_sequence(flags); return 0; } @@ -315,14 +372,17 @@ BAREBOX_MAGICVAR(global.net.ifup_force_detect, static int do_ifup(int argc, char *argv[]) { int opt; - unsigned flags = 0; + unsigned flags = IFUP_FLAG_PARALLEL; int all = 0; - while ((opt = getopt(argc, argv, "af")) > 0) { + while ((opt = getopt(argc, argv, "asf")) > 0) { switch (opt) { case 'f': flags |= IFUP_FLAG_FORCE; break; + case 's': + flags &= ~IFUP_FLAG_PARALLEL; + break; case 'a': all = 1; break; @@ -346,13 +406,14 @@ BAREBOX_CMD_HELP_TEXT("/env/network/ file. See Documentation/user/networki BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-a", "bring up all interfaces") +BAREBOX_CMD_HELP_OPT ("-s", "bring up interfaces in sequence, not in parallel") BAREBOX_CMD_HELP_OPT ("-f", "Force. Configure even if ip already set") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(ifup) .cmd = do_ifup, BAREBOX_CMD_DESC("bring a network interface up") - BAREBOX_CMD_OPTS("[-af] [INTF]") + BAREBOX_CMD_OPTS("[-asf] [INTF]") BAREBOX_CMD_GROUP(CMD_GRP_NET) BAREBOX_CMD_COMPLETE(eth_complete) BAREBOX_CMD_HELP(cmd_ifup_help) -- cgit v1.2.1