From caa2ad6f8c8cc4c295c77aaff464c580d52c3ba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvin=20=C5=A0ipraga?= Date: Thu, 2 Oct 2025 11:43:36 +0200 Subject: [PATCH 01/19] tftp: make TFTP ports unconditionally configurable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few lines of code being guarded by the CONFIG_TFTP_PORT option seems an unnecessary restriction on the TFTP support provided by a vanilla U-Boot image. In cases where the TFTP server cannot run as superuser - and hence cannot run on the well-known port 69 - this quirk incurs a full reconfiguration and rebuild of the bootloader only in order to select the appropriate destination port. Remove the CONFIG_TFTP_PORT option entirely and make the tftpdstp and tftpsrcp variables always have an effect. Their being unset will mean that U-Boot behaves the same as if CONFIG_TFTP_PORT was unset. Update the documentation accordingly. And fix up the single board which was originally enabling this option. Signed-off-by: Alvin Šipraga Reviewed-by: Quentin Schulz --- configs/gurnard_defconfig | 1 - doc/usage/cmd/tftpput.rst | 8 ++------ net/Kconfig | 18 ------------------ net/tftp.c | 3 +-- 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/configs/gurnard_defconfig b/configs/gurnard_defconfig index bde531a6003..85643f249ae 100644 --- a/configs/gurnard_defconfig +++ b/configs/gurnard_defconfig @@ -42,7 +42,6 @@ CONFIG_ENV_OVERWRITE=y CONFIG_ENV_IS_IN_NAND=y CONFIG_ENV_RELOC_GD_ENV_ADDR=y CONFIG_NET_RETRY_COUNT=20 -CONFIG_TFTP_PORT=y CONFIG_TFTP_TSIZE=y CONFIG_AT91_GPIO=y CONFIG_GENERIC_ATMEL_MCI=y diff --git a/doc/usage/cmd/tftpput.rst b/doc/usage/cmd/tftpput.rst index 351c9faa38b..2bcb3032cb2 100644 --- a/doc/usage/cmd/tftpput.rst +++ b/doc/usage/cmd/tftpput.rst @@ -19,9 +19,8 @@ Description The tftpput command is used to transfer a file to a TFTP server. By default the destination port is 69 and the source port is pseudo-random. -If CONFIG_TFTP_PORT=y, the environment variable *tftpsrcp* can be used to set -the source port and the environment variable *tftpdstp* can be used to set -the destination port. +The environment variable *tftpsrcp* can be used to set the source port and the +environment variable *tftpdstp* can be used to set the destination port. address memory address where the data starts @@ -75,9 +74,6 @@ The command is only available if CONFIG_CMD_TFTPPUT=y. CONFIG_TFTP_BLOCKSIZE defines the size of the TFTP blocks sent. It defaults to 1468 matching an ethernet MTU of 1500. -If CONFIG_TFTP_PORT=y, the environment variables *tftpsrcp* and *tftpdstp* can -be used to set the source and the destination ports. - CONFIG_TFTP_WINDOWSIZE can be used to set the TFTP window size of transmits after which an ACK response is required. The window size defaults to 1. diff --git a/net/Kconfig b/net/Kconfig index 40ec6bbce76..7ba64d43b39 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -60,24 +60,6 @@ config SYS_FAULT_ECHO_LINK_DOWN this option is active, then CONFIG_SYS_FAULT_MII_ADDR also needs to be configured. -config TFTP_PORT - bool "Set TFTP UDP source/destination ports via the environment" - help - If this is defined, the environment variable tftpsrcp is used to - supply the TFTP UDP source port value. If tftpsrcp isn't defined, - the normal pseudo-random port number generator is used. - - Also, the environment variable tftpdstp is used to supply the TFTP - UDP destination port value. If tftpdstp isn't defined, the normal - port 69 is used. - - The purpose for tftpsrcp is to allow a TFTP server to blindly start - the TFTP transfer using the pre-configured target IP address and UDP - port. This has the effect of "punching through" the (Windows XP) - firewall, allowing the remainder of the TFTP transfer to proceed - normally. A better solution is to properly configure the firewall, - but sometimes that is not allowed. - config TFTP_WINDOWSIZE int "TFTP window size" default 1 diff --git a/net/tftp.c b/net/tftp.c index 1ca9a5ea7cf..1760877107f 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -926,14 +926,13 @@ void tftp_start(enum proto_t protocol) /* Use a pseudo-random port unless a specific port is set */ tftp_our_port = 1024 + (get_timer(0) % 3072); -#ifdef CONFIG_TFTP_PORT ep = env_get("tftpdstp"); if (ep != NULL) tftp_remote_port = simple_strtol(ep, NULL, 10); ep = env_get("tftpsrcp"); if (ep != NULL) tftp_our_port = simple_strtol(ep, NULL, 10); -#endif + tftp_cur_block = 0; tftp_windowsize = 1; tftp_last_nack = 0; From efe1d6303f243cf3588dd1974fbfdef0d7a02c42 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Wed, 1 Oct 2025 14:30:50 -0600 Subject: [PATCH 02/19] uthreads: Make use of CONFIG_IS_ENABLED consistently We do not yet support UTHREADS in xPL phases. However, we have the need to dummy out certain functions so that xPL can build when full U-Boot has UTHREADS enabled. Update the few places that need to use CONFIG_IS_ENABLED so that we have the correct dummy in xPL. Signed-off-by: Tom Rini Acked-by: Jerome Forissier --- include/uthread.h | 4 ++-- lib/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/uthread.h b/include/uthread.h index 11a19aa9488..78dab77f196 100644 --- a/include/uthread.h +++ b/include/uthread.h @@ -72,7 +72,7 @@ struct uthread_mutex { #define UTHREAD_MUTEX_INITIALIZER { .state = UTHREAD_MUTEX_UNLOCKED } -#ifdef CONFIG_UTHREAD +#if CONFIG_IS_ENABLED(UTHREAD) /** * uthread_create() - Create a uthread object and make it ready for execution @@ -184,5 +184,5 @@ static inline bool uthread_grp_done(unsigned int grp_id) #define uthread_mutex_trylock(_mutex) ({ 0 }) #define uthread_mutex_unlock(_mutex) ({ 0; }) -#endif /* CONFIG_UTHREAD */ +#endif /* CONFIG_IS_ENABLED(UTHREAD) */ #endif /* _UTHREAD_H_ */ diff --git a/lib/Makefile b/lib/Makefile index a2e60668864..07702cef7e7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -161,7 +161,7 @@ obj-$(CONFIG_LIB_ELF) += elf.o obj-$(CONFIG_$(PHASE_)SEMIHOSTING) += semihosting.o -obj-$(CONFIG_UTHREAD) += uthread.o +obj-$(CONFIG_$(PHASE_)UTHREAD) += uthread.o # # Build a fast OID lookup registry from include/linux/oid_registry.h From 4cc1fe3f5617133e1d5a180f1d62cc987dc4e81d Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 25 Sep 2025 14:44:11 -0600 Subject: [PATCH 03/19] arm: socfpga: Tighten a few more driver dependencies Some drivers which depend on SoCFPGA specific headers had not had appropriate dependencies list in Kconfig. Add ARCH_SOCFPGA or TARGET_SOCFPGA_SOC64 where appropriate. Signed-off-by: Tom Rini --- drivers/net/Kconfig | 4 ++-- drivers/power/domain/Kconfig | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 7ae28c4e0d5..c2ef9fb52f7 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -190,7 +190,7 @@ config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" select REGMAP select SYSCON - depends on DWC_ETH_XGMAC + depends on ARCH_SOCFPGA && DWC_ETH_XGMAC default y if TARGET_SOCFPGA_AGILEX5 help The Synopsys Designware Ethernet XGMAC IP block with specific @@ -376,7 +376,7 @@ config ETH_DESIGNWARE_SOCFPGA select SYSCON select DW_ALTDESCRIPTOR bool "Altera SoCFPGA extras for Synopsys Designware Ethernet MAC" - depends on ETH_DESIGNWARE + depends on ARCH_SOCFPGA && ETH_DESIGNWARE help The Altera SoCFPGA requires additional configuration of the Altera system manager to correctly interface with the PHY. diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig index ebf5d828cb0..0ad885c9e8b 100644 --- a/drivers/power/domain/Kconfig +++ b/drivers/power/domain/Kconfig @@ -20,7 +20,7 @@ config APPLE_PMGR_POWER_DOMAIN config AGILEX5_PMGR_POWER_DOMAIN bool "Enable the Agilex5 PMGR power domain driver" - depends on SPL_POWER_DOMAIN + depends on SPL_POWER_DOMAIN && TARGET_SOCFPGA_SOC64 help Enable support for power gating peripherals' SRAM specified in the handoff data values obtained from the bitstream to reduce From f8220460372b2e2c12afec3faf89921dd4e39b6c Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 25 Sep 2025 14:44:12 -0600 Subject: [PATCH 04/19] net: Add SYS_FAULT_MII_ADDR to Kconfig The support found under SYS_FAULT_ECHO_LINK_DOWN requires that the SYS_FAULT_MII_ADDR symbol also be set. This wasn't previously found in Kconfig, so add it now. Signed-off-by: Tom Rini Acked-by: Jerome Forissier --- README | 3 --- net/Kconfig | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README b/README index b95c72bb367..20a73bab802 100644 --- a/README +++ b/README @@ -1216,9 +1216,6 @@ Note: once the monitor has been relocated, then it will complain if the default environment is used; a new CRC is computed as soon as you use the "saveenv" command to store a valid environment. -- CONFIG_SYS_FAULT_MII_ADDR: - MII address of the PHY to check for the Ethernet link state. - - CONFIG_DISPLAY_BOARDINFO Display information about the board that U-Boot is running on when U-Boot starts up. The board function checkboard() is called diff --git a/net/Kconfig b/net/Kconfig index 7ba64d43b39..42fcba5323f 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -60,6 +60,10 @@ config SYS_FAULT_ECHO_LINK_DOWN this option is active, then CONFIG_SYS_FAULT_MII_ADDR also needs to be configured. +config SYS_FAULT_MII_ADDR + hex "MII address of the PHY to check for the Ethernet link state" + depends on SYS_FAULT_ECHO_LINK_DOWN && LED_STATUS_RED_ENABLE + config TFTP_WINDOWSIZE int "TFTP window size" default 1 From 99707a0baaa85736529a172f515b44598e5a8bc8 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 25 Sep 2025 14:44:13 -0600 Subject: [PATCH 05/19] net: Remove BOOTP_VENDOREX support It has been over a decade since we had a platform that implemented the bootp vendor extension support hook. Remove this option due to lack of use. Signed-off-by: Tom Rini Acked-by: Jerome Forissier --- cmd/Kconfig | 4 ---- net/bootp.c | 13 ------------- net/bootp.h | 4 ---- 3 files changed, 21 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 5fcf37e67b9..9929087a8bb 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1951,10 +1951,6 @@ config BOOTP_BOOTPATH Even though the config is called BOOTP_BOOTPATH, it stores the path in the variable 'rootpath'. -config BOOTP_VENDOREX - bool "Support vendor extensions from BOOTP/DHCP server" - depends on CMD_BOOTP - config BOOTP_BOOTFILESIZE bool "Request & store 'bootfilesize' from BOOTP/DHCP server" depends on CMD_BOOTP diff --git a/net/bootp.c b/net/bootp.c index 19e7453daed..a28d11cb368 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -491,9 +491,6 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip, #endif int clientarch = -1; -#if defined(CONFIG_BOOTP_VENDOREX) - u8 *x; -#endif #if defined(CONFIG_BOOTP_SEND_HOSTNAME) char *hostname; #endif @@ -584,12 +581,6 @@ static int dhcp_extended(u8 *e, int message_type, struct in_addr server_ip, e = add_vci(e); -#if defined(CONFIG_BOOTP_VENDOREX) - x = dhcp_vendorex_prep(e); - if (x) - return x - start; -#endif - *e++ = 55; /* Parameter Request List */ cnt = e++; /* Pointer to count of requested items */ *cnt = 0; @@ -977,10 +968,6 @@ static void dhcp_process_options(uchar *popt, uchar *end) } break; default: -#if defined(CONFIG_BOOTP_VENDOREX) - if (dhcp_vendorex_proc(popt)) - break; -#endif printf("*** Unhandled DHCP Option in OFFER/ACK:" " %d\n", *popt); break; diff --git a/net/bootp.h b/net/bootp.h index 47c743479e7..14f5af68e15 100644 --- a/net/bootp.h +++ b/net/bootp.h @@ -24,10 +24,6 @@ #if defined(CONFIG_CMD_DHCP) /* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */ #define OPT_FIELD_SIZE 312 -#if defined(CONFIG_BOOTP_VENDOREX) -extern u8 *dhcp_vendorex_prep(u8 *e); /*rtn new e after add own opts. */ -extern u8 *dhcp_vendorex_proc(u8 *e); /*rtn next e if mine,else NULL */ -#endif #else #define OPT_FIELD_SIZE 64 #endif From 772703b77e51f8c1685e7daaa9935dc46b21a30e Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 25 Sep 2025 14:44:14 -0600 Subject: [PATCH 06/19] net: Tighten more driver dependencies In this case, the mediatek network drivers cannot build outside of ARCH_MEDIATEK or ARCH_MTMIPS, and so express this requirement in Kconfig as well. In the case of DWC_ETH_XGMAC / DWC_ETH_XGMAC_SOCFPGA, the file controlled by the DWC_ETH_XGMAC option references a socfpga-specific array defined in the file controlled by DWC_ETH_XGMAC_SOCFPGA. Rework these options in Kconfig to handle this dependency. Signed-off-by: Tom Rini --- drivers/net/Kconfig | 5 +++-- drivers/net/mtk_eth/Kconfig | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index c2ef9fb52f7..8576b0c3798 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -179,7 +179,7 @@ config CALXEDA_XGMAC machines. config DWC_ETH_XGMAC - bool "Synopsys DWC Ethernet XGMAC device support" + bool select PHYLIB help This driver supports the Synopsys Designware Ethernet XGMAC (10G @@ -190,7 +190,8 @@ config DWC_ETH_XGMAC_SOCFPGA bool "Synopsys DWC Ethernet XGMAC device support for SOCFPGA" select REGMAP select SYSCON - depends on ARCH_SOCFPGA && DWC_ETH_XGMAC + select DWC_ETH_XGMAC + depends on ARCH_SOCFPGA default y if TARGET_SOCFPGA_AGILEX5 help The Synopsys Designware Ethernet XGMAC IP block with specific diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index e8cdf408237..a2060b8bd01 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -1,6 +1,7 @@ config MEDIATEK_ETH bool "MediaTek Ethernet GMAC Driver" + depends on ARCH_MEDIATEK || ARCH_MTMIPS select PHYLIB select DM_GPIO select DM_RESET From 83633e5774a107315f33ee7800a647b74854d48f Mon Sep 17 00:00:00 2001 From: Beiyan Yun Date: Tue, 23 Sep 2025 15:12:58 +0800 Subject: [PATCH 07/19] net: phy: aquantia: switch to use phy_get_ofnode() Use PHY API phy_get_ofnode() helper to get PHY DT node. Signed-off-by: Beiyan Yun --- drivers/net/phy/aquantia.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index f63a13824ca..903fcd667f6 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -338,7 +338,7 @@ static int aquantia_set_proto(struct phy_device *phydev, static int aquantia_dts_config(struct phy_device *phydev) { - ofnode node = phydev->node; + ofnode node = phy_get_ofnode(phydev); u32 prop; u16 reg; From efaadc02b736da82ef9868d11960a63faae9b3fe Mon Sep 17 00:00:00 2001 From: Beiyan Yun Date: Tue, 23 Sep 2025 15:12:59 +0800 Subject: [PATCH 08/19] doc: bindings: fix aquantia-phy.txt typo Fix typo: "weays" -> "ways" Signed-off-by: Beiyan Yun --- doc/device-tree-bindings/net/aquantia-phy.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/device-tree-bindings/net/aquantia-phy.txt b/doc/device-tree-bindings/net/aquantia-phy.txt index 89ce61e05bb..7dd3d45df12 100644 --- a/doc/device-tree-bindings/net/aquantia-phy.txt +++ b/doc/device-tree-bindings/net/aquantia-phy.txt @@ -4,7 +4,7 @@ This text describes properties that are applicable to Aquantia PHY nodes in addition to the bindings in phy.txt. Aquantia PHYs allow some flexibility in the way they are wired in a system, -they allow MDI pins to be reversed, LEDs linked up in different weays, have an +they allow MDI pins to be reversed, LEDs linked up in different ways, have an I2C slave interface that can be used for debug. Normally the configuration corresponding to these is driven by the PHY firmware with the downside that a custom firmware is needed for each integration of a PHY. From 9b2e1079e7db35155710a401eb52007abe449ad7 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:41 +0200 Subject: [PATCH 09/19] net: mediatek: mt7531/7988: fix broken PHY turn ON/OFF The PHY for MT7531/MT7988 are never actully turned ON/OFF for the affected PHY as we are read/writing to the wrong PHY address. This is caused by the fact that we use the MT753X_PHY_ADDR macro 2 times offsetting the address multiple times. One in the _setup() function and one in the mt7531_mii_read/write. Drop the additional usage of MT753X_PHY_ADDR in setup() to correctly set the PHY. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth/mt7531.c | 20 +++++++------------- drivers/net/mtk_eth/mt7988.c | 12 +++++------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/net/mtk_eth/mt7531.c b/drivers/net/mtk_eth/mt7531.c index 32d6bebbbdb..965bc3cb7e9 100644 --- a/drivers/net/mtk_eth/mt7531.c +++ b/drivers/net/mtk_eth/mt7531.c @@ -22,17 +22,13 @@ static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg) { - u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); - - return mt7531_mmd_read(priv, phy_addr, 0x1f, reg); + return mt7531_mmd_read(priv, 0, 0x1f, reg); } static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 val) { - u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0); - - mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val); + mt7531_mmd_write(priv, 0, 0x1f, reg, val); } static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv) @@ -171,7 +167,7 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; u32 i, val, pmcr, port5_sgmii; - u16 phy_addr, phy_val; + u16 phy_val; priv->smi_addr = MT753X_DFL_SMI_ADDR; priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; @@ -180,10 +176,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } /* Force MAC link down before reset */ @@ -239,10 +234,9 @@ static int mt7531_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } mt7531_phy_setting(priv); diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index a416d87840c..87b6ed30cd0 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -61,7 +61,7 @@ static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; - u16 phy_addr, phy_val; + u16 phy_val; u32 pmcr; int i; @@ -72,10 +72,9 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } switch (priv->epriv.phy_interface) { @@ -128,10 +127,9 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); - phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR); + phy_val = mt7531_mii_read(priv, i, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val); + mt7531_mii_write(priv, i, MII_BMCR, phy_val); } mt7988_phy_setting(priv); From 85f3d070e27c3024c6d2c58ecbfd0ecb2343cc0c Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:42 +0200 Subject: [PATCH 10/19] net: mediatek: mt7988: restore PHY page on PHY setting exit On exiting the phy_setting function for MT7988, the PHY page is never restored to Page 0. This can cause all kind of problem with reading the status of the PHY at runtime. Correctly restore PHY page on exiting the PHY setting function. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth/mt7988.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index 87b6ed30cd0..06bbe049da3 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -34,8 +34,10 @@ static void mt7988_phy_setting(struct mt753x_switch_priv *priv) u32 i; for (i = 0; i < MT753X_NUM_PHYS; i++) { - /* Enable HW auto downshift */ + /* Set PHY to PHY page 1 */ mt7531_mii_write(priv, i, 0x1f, 0x1); + + /* Enable HW auto downshift */ val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); val |= PHY_EN_DOWN_SHFIT; mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); @@ -44,6 +46,9 @@ static void mt7988_phy_setting(struct mt753x_switch_priv *priv) val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); val |= PHY_LINKDOWN_POWER_SAVING_EN; mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); + + /* Restore PHY to PHY page 0 */ + mt7531_mii_write(priv, i, 0x1f, 0x0); } } From ca4264db44c1ece69d208f63c4bfe607c60751d9 Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:43 +0200 Subject: [PATCH 11/19] net: mediatek: mt7988: free allocated MDIO bus on cleanup Correctly free the MDIO Bus on calling cleanup function. While at it also fix a copy-paste error and rename the cleanup function name to the more specific name. Signed-off-by: Christian Marangi --- drivers/net/mtk_eth/mt7988.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index 06bbe049da3..b77660be55c 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -142,11 +142,13 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) return mt7531_mdio_register(priv); } -static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv) +static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; + struct mii_dev *mdio_bus = priv->mdio_bus; - mdio_unregister(priv->mdio_bus); + mdio_unregister(mdio_bus); + mdio_free(mdio_bus); return 0; } @@ -158,6 +160,6 @@ MTK_ETH_SWITCH(mt7988) = { .reset_wait_time = 50, .setup = mt7988_setup, - .cleanup = mt7531_cleanup, + .cleanup = mt7988_cleanup, .mac_control = mt7988_mac_control, }; From b24268d151a0c28772785e14703491364becda5b Mon Sep 17 00:00:00 2001 From: Christian Marangi Date: Sat, 20 Sep 2025 18:09:44 +0200 Subject: [PATCH 12/19] net: mediatek: move MT7531 MMIO MDIO to dedicated driver In preparation for support of MDIO on AN7581, move the MT7531 MMIO logic to a dedicated driver and permit usage of the mdio read/write function to the mtk_eth driver. This only affect MT7988 that can use MMIO operation to access the Switch register. The MT7988 code is updated to make use of the external driver. This permits Airoha driver to make use of DM_MDIO to bind for the MT7531 driver that have the same exact register. Signed-off-by: Christian Marangi --- drivers/net/Kconfig | 3 + drivers/net/Makefile | 1 + drivers/net/mdio-mt7531-mmio.c | 168 +++++++++++++++++++++++++++++++++ drivers/net/mdio-mt7531-mmio.h | 9 ++ drivers/net/mtk_eth/Kconfig | 1 + drivers/net/mtk_eth/mt7988.c | 85 ++++++++++++++--- 6 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 drivers/net/mdio-mt7531-mmio.c create mode 100644 drivers/net/mdio-mt7531-mmio.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8576b0c3798..c9b35b5a2ff 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -967,6 +967,9 @@ config TSEC_ENET This driver implements support for the (Enhanced) Three-Speed Ethernet Controller found on Freescale SoCs. +config MDIO_MT7531_MMIO + bool + source "drivers/net/mtk_eth/Kconfig" config HIFEMAC_ETH diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f8f9a71f815..a3c3420898c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_MACB) += macb.o obj-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o obj-$(CONFIG_MDIO_IPQ4019) += mdio-ipq4019.o obj-$(CONFIG_MDIO_GPIO_BITBANG) += mdio_gpio.o +obj-$(CONFIG_MDIO_MT7531_MMIO) += mdio-mt7531-mmio.o obj-$(CONFIG_MDIO_MUX_I2CREG) += mdio_mux_i2creg.o obj-$(CONFIG_MDIO_MUX_MESON_G12A) += mdio_mux_meson_g12a.o obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio_mux_meson_gxl.o diff --git a/drivers/net/mdio-mt7531-mmio.c b/drivers/net/mdio-mt7531-mmio.c new file mode 100644 index 00000000000..3e325ca58da --- /dev/null +++ b/drivers/net/mdio-mt7531-mmio.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include +#include +#include +#include +#include + +#define MT7531_PHY_IAC 0x701c +#define MT7531_PHY_ACS_ST BIT(31) +#define MT7531_MDIO_REG_ADDR_CL22 GENMASK(29, 25) +#define MT7531_MDIO_DEV_ADDR MT7531_MDIO_REG_ADDR_CL22 +#define MT7531_MDIO_PHY_ADDR GENMASK(24, 20) +#define MT7531_MDIO_CMD GENMASK(19, 18) +#define MT7531_MDIO_CMD_READ_CL45 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x3) +#define MT7531_MDIO_CMD_READ_CL22 FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x2) +#define MT7531_MDIO_CMD_WRITE FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x1) +#define MT7531_MDIO_CMD_ADDR FIELD_PREP_CONST(MT7531_MDIO_CMD, 0x0) +#define MT7531_MDIO_ST GENMASK(17, 16) +#define MT7531_MDIO_ST_CL22 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x1) +#define MT7531_MDIO_ST_CL45 FIELD_PREP_CONST(MT7531_MDIO_ST, 0x0) +#define MT7531_MDIO_RW_DATA GENMASK(15, 0) +#define MT7531_MDIO_REG_ADDR_CL45 MT7531_MDIO_RW_DATA + +#define MT7531_MDIO_TIMEOUT 100000 +#define MT7531_MDIO_SLEEP 20 + +struct mt7531_mdio_priv { + phys_addr_t switch_regs; +}; + +static int mt7531_mdio_wait_busy(struct mt7531_mdio_priv *priv) +{ + unsigned int busy; + + return readl_poll_sleep_timeout(priv->switch_regs + MT7531_PHY_IAC, + busy, (busy & MT7531_PHY_ACS_ST) == 0, + MT7531_MDIO_SLEEP, MT7531_MDIO_TIMEOUT); +} + +static int mt7531_mdio_read(struct mt7531_mdio_priv *priv, int addr, int devad, int reg) +{ + u32 val; + + if (devad != MDIO_DEVAD_NONE) { + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | + MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR | + FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + } + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr); + if (devad != MDIO_DEVAD_NONE) + val |= MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_READ_CL45 | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad); + else + val |= MT7531_MDIO_ST_CL22 | MT7531_MDIO_CMD_READ_CL22 | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = readl(priv->switch_regs + MT7531_PHY_IAC); + return val & MT7531_MDIO_RW_DATA; +} + +static int mt7531_mdio_write(struct mt7531_mdio_priv *priv, int addr, int devad, + int reg, u16 value) +{ + u32 val; + + if (devad != MDIO_DEVAD_NONE) { + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | + MT7531_MDIO_ST_CL45 | MT7531_MDIO_CMD_ADDR | + FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad) | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL45, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + } + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + val = MT7531_PHY_ACS_ST | FIELD_PREP(MT7531_MDIO_PHY_ADDR, addr) | + MT7531_MDIO_CMD_WRITE | FIELD_PREP(MT7531_MDIO_RW_DATA, value); + if (devad != MDIO_DEVAD_NONE) + val |= MT7531_MDIO_ST_CL45 | + FIELD_PREP(MT7531_MDIO_DEV_ADDR, devad); + else + val |= MT7531_MDIO_ST_CL22 | + FIELD_PREP(MT7531_MDIO_REG_ADDR_CL22, reg); + + writel(val, priv->switch_regs + MT7531_PHY_IAC); + + if (mt7531_mdio_wait_busy(priv)) + return -ETIMEDOUT; + + return 0; +} + +int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = bus->priv; + + return mt7531_mdio_read(priv, addr, devad, reg); +} + +int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = bus->priv; + + return mt7531_mdio_write(priv, addr, devad, reg, value); +} + +static int dm_mt7531_mdio_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + return mt7531_mdio_read(priv, addr, devad, reg); +} + +static int dm_mt7531_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 value) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + return mt7531_mdio_write(priv, addr, devad, reg, value); +} + +static const struct mdio_ops mt7531_mdio_ops = { + .read = dm_mt7531_mdio_read, + .write = dm_mt7531_mdio_write, +}; + +static int mt7531_mdio_probe(struct udevice *dev) +{ + struct mt7531_mdio_priv *priv = dev_get_priv(dev); + + priv->switch_regs = dev_read_addr(dev); + if (priv->switch_regs == FDT_ADDR_T_NONE) + return -EINVAL; + + return 0; +} + +U_BOOT_DRIVER(mt7531_mdio) = { + .name = "mt7531-mdio-mmio", + .id = UCLASS_MDIO, + .probe = mt7531_mdio_probe, + .ops = &mt7531_mdio_ops, + .priv_auto = sizeof(struct mt7531_mdio_priv), +}; diff --git a/drivers/net/mdio-mt7531-mmio.h b/drivers/net/mdio-mt7531-mmio.h new file mode 100644 index 00000000000..f98102cb939 --- /dev/null +++ b/drivers/net/mdio-mt7531-mmio.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +struct mt7531_mdio_mmio_priv { + phys_addr_t switch_regs; +}; + +int mt7531_mdio_mmio_read(struct mii_dev *bus, int addr, int devad, int reg); +int mt7531_mdio_mmio_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 value); diff --git a/drivers/net/mtk_eth/Kconfig b/drivers/net/mtk_eth/Kconfig index a2060b8bd01..5d4e54ab90e 100644 --- a/drivers/net/mtk_eth/Kconfig +++ b/drivers/net/mtk_eth/Kconfig @@ -31,6 +31,7 @@ config MTK_ETH_SWITCH_MT7531 config MTK_ETH_SWITCH_MT7988 bool "Support for MediaTek MT7988 built-in ethernet switch" depends on TARGET_MT7988 + select MDIO_MT7531_MMIO default y config MTK_ETH_SWITCH_AN8855 diff --git a/drivers/net/mtk_eth/mt7988.c b/drivers/net/mtk_eth/mt7988.c index b77660be55c..29b6363cbd7 100644 --- a/drivers/net/mtk_eth/mt7988.c +++ b/drivers/net/mtk_eth/mt7988.c @@ -6,6 +6,7 @@ * Author: Mark Lee */ +#include #include #include #include @@ -14,6 +15,8 @@ #include "mtk_eth.h" #include "mt753x.h" +#include "../mdio-mt7531-mmio.h" + static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data) { *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg); @@ -30,25 +33,34 @@ static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data) static void mt7988_phy_setting(struct mt753x_switch_priv *priv) { + struct mii_dev *mdio_bus = priv->mdio_bus; u16 val; u32 i; for (i = 0; i < MT753X_NUM_PHYS; i++) { + u16 addr = MT753X_PHY_ADDR(priv->phy_base, i); + /* Set PHY to PHY page 1 */ - mt7531_mii_write(priv, i, 0x1f, 0x1); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + 0x1f, 0x1); /* Enable HW auto downshift */ - val = mt7531_mii_read(priv, i, PHY_EXT_REG_14); + val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_14); val |= PHY_EN_DOWN_SHFIT; - mt7531_mii_write(priv, i, PHY_EXT_REG_14, val); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_14, val); /* PHY link down power saving enable */ - val = mt7531_mii_read(priv, i, PHY_EXT_REG_17); + val = mt7531_mdio_mmio_read(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_17); val |= PHY_LINKDOWN_POWER_SAVING_EN; - mt7531_mii_write(priv, i, PHY_EXT_REG_17, val); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + PHY_EXT_REG_17, val); /* Restore PHY to PHY page 0 */ - mt7531_mii_write(priv, i, 0x1f, 0x0); + mt7531_mdio_mmio_write(mdio_bus, addr, MDIO_DEVAD_NONE, + 0x1f, 0x0); } } @@ -63,23 +75,66 @@ static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable) mt7988_reg_write(priv, PMCR_REG(6), pmcr); } +static int mt7988_mdio_register(struct mt753x_switch_priv *priv) +{ + struct mt7531_mdio_mmio_priv *mdio_priv; + struct mii_dev *mdio_bus = mdio_alloc(); + int ret; + + if (!mdio_bus) + return -ENOMEM; + + mdio_priv = malloc(sizeof(*mdio_priv)); + if (!mdio_priv) + return -ENOMEM; + + mdio_priv->switch_regs = (phys_addr_t)priv->epriv.ethsys_base + GSW_BASE; + + mdio_bus->read = mt7531_mdio_mmio_read; + mdio_bus->write = mt7531_mdio_mmio_write; + snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name); + + mdio_bus->priv = mdio_priv; + + ret = mdio_register(mdio_bus); + if (ret) { + free(mdio_bus->priv); + mdio_free(mdio_bus); + return ret; + } + + priv->mdio_bus = mdio_bus; + + return 0; +} + static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) { struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv; - u16 phy_val; + struct mii_dev *mdio_bus; + u16 phy_addr, phy_val; + int ret, i; u32 pmcr; - int i; priv->smi_addr = MT753X_DFL_SMI_ADDR; priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK; priv->reg_read = mt7988_reg_read; priv->reg_write = mt7988_reg_write; + ret = mt7988_mdio_register(priv); + if (ret) + return ret; + + mdio_bus = priv->mdio_bus; + /* Turn off PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_val = mt7531_mii_read(priv, i, MII_BMCR); + phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); + phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_BMCR); phy_val |= BMCR_PDOWN; - mt7531_mii_write(priv, i, MII_BMCR, phy_val); + mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE, + MII_BMCR, phy_val); } switch (priv->epriv.phy_interface) { @@ -132,14 +187,17 @@ static int mt7988_setup(struct mtk_eth_switch_priv *swpriv) /* Turn on PHYs */ for (i = 0; i < MT753X_NUM_PHYS; i++) { - phy_val = mt7531_mii_read(priv, i, MII_BMCR); + phy_addr = MT753X_PHY_ADDR(priv->phy_base, i); + phy_val = mt7531_mdio_mmio_read(mdio_bus, phy_addr, + MDIO_DEVAD_NONE, MII_BMCR); phy_val &= ~BMCR_PDOWN; - mt7531_mii_write(priv, i, MII_BMCR, phy_val); + mt7531_mdio_mmio_write(mdio_bus, phy_addr, MDIO_DEVAD_NONE, + MII_BMCR, phy_val); } mt7988_phy_setting(priv); - return mt7531_mdio_register(priv); + return 0; } static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) @@ -148,6 +206,7 @@ static int mt7988_cleanup(struct mtk_eth_switch_priv *swpriv) struct mii_dev *mdio_bus = priv->mdio_bus; mdio_unregister(mdio_bus); + free(mdio_bus->priv); mdio_free(mdio_bus); return 0; From 4b8e78585171787794611205d661b97bc5f4dd83 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Thu, 9 Oct 2025 14:30:14 +0200 Subject: [PATCH 13/19] net: make dhcp_run() common for NET and NET_LWIP There are currently two implementations of dhcp_run(): one in cmd/net.c for NET and one in net/lwip/dhcp.c for NET_LWIP. There is no justification for that. Therefore, move the NET version into net/net-common.c to be used by both stacks, and drop the NET_LWIP version which by the way does not look totally correct. Signed-off-by: Jerome Forissier Suggested-by: Tom Rini Acked-by: Benjamin Hahn --- cmd/net.c | 36 ++---------------------------------- include/net-common.h | 10 ++++++++++ include/net-lwip.h | 1 - net/lwip/dhcp.c | 22 ---------------------- net/net-common.c | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 47 insertions(+), 57 deletions(-) diff --git a/cmd/net.c b/cmd/net.c index 886735ea14f..24099764493 100644 --- a/cmd/net.c +++ b/cmd/net.c @@ -134,8 +134,8 @@ U_BOOT_CMD(dhcp6, 3, 1, do_dhcp6, #endif #if defined(CONFIG_CMD_DHCP) -static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, - char *const argv[]) +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) { return netboot_common(DHCP, cmdtp, argc, argv); } @@ -145,38 +145,6 @@ U_BOOT_CMD( "boot image via network using DHCP/TFTP protocol", "[loadAddress] [[hostIPaddr:]bootfilename]" ); - -int dhcp_run(ulong addr, const char *fname, bool autoload) -{ - char *dhcp_argv[] = {"dhcp", NULL, (char *)fname, NULL}; - struct cmd_tbl cmdtp = {}; /* dummy */ - char file_addr[17]; - int old_autoload; - int ret, result; - - log_debug("addr=%lx, fname=%s, autoload=%d\n", addr, fname, autoload); - old_autoload = env_get_yesno("autoload"); - ret = env_set("autoload", autoload ? "y" : "n"); - if (ret) - return log_msg_ret("en1", -EINVAL); - - if (autoload) { - sprintf(file_addr, "%lx", addr); - dhcp_argv[1] = file_addr; - } - - result = do_dhcp(&cmdtp, 0, !autoload ? 1 : fname ? 3 : 2, dhcp_argv); - - ret = env_set("autoload", old_autoload == -1 ? NULL : - old_autoload ? "y" : "n"); - if (ret) - return log_msg_ret("en2", -EINVAL); - - if (result) - return log_msg_ret("res", -ENOENT); - - return 0; -} #endif #if defined(CONFIG_CMD_NFS) diff --git a/include/net-common.h b/include/net-common.h index 1112af381a9..78d98e5bba0 100644 --- a/include/net-common.h +++ b/include/net-common.h @@ -479,6 +479,16 @@ int net_loop(enum proto_t protocol); */ int dhcp_run(ulong addr, const char *fname, bool autoload); +/** + * do_dhcp - Run the dhcp command + * + * @cmdtp: Unused + * @flag: Command flags (CMD_FLAG_...) + * @argc: Number of arguments + * @argv: List of arguments + * Return: result (see enum command_ret_t) + */ +int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); /** * do_ping - Run the ping command diff --git a/include/net-lwip.h b/include/net-lwip.h index e88e2186635..c910def5719 100644 --- a/include/net-lwip.h +++ b/include/net-lwip.h @@ -50,7 +50,6 @@ int net_lwip_dns_resolve(char *name_or_ip, ip_addr_t *ip); */ bool wget_validate_uri(char *uri); -int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]); diff --git a/net/lwip/dhcp.c b/net/lwip/dhcp.c index 531bf2c6705..b798014ebcb 100644 --- a/net/lwip/dhcp.c +++ b/net/lwip/dhcp.c @@ -150,25 +150,3 @@ int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc, char *const 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); -} diff --git a/net/net-common.c b/net/net-common.c index b064557d524..442b0597558 100644 --- a/net/net-common.c +++ b/net/net-common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include @@ -48,3 +49,37 @@ void net_sntp_set_rtc(u32 seconds) tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); } + +#if defined(CONFIG_CMD_DHCP) +int dhcp_run(ulong addr, const char *fname, bool autoload) +{ + char *dhcp_argv[] = {"dhcp", NULL, (char *)fname, NULL}; + struct cmd_tbl cmdtp = {}; /* dummy */ + char file_addr[17]; + int old_autoload; + int ret, result; + + log_debug("addr=%lx, fname=%s, autoload=%d\n", addr, fname, autoload); + old_autoload = env_get_yesno("autoload"); + ret = env_set("autoload", autoload ? "y" : "n"); + if (ret) + return log_msg_ret("en1", -EINVAL); + + if (autoload) { + sprintf(file_addr, "%lx", addr); + dhcp_argv[1] = file_addr; + } + + result = do_dhcp(&cmdtp, 0, !autoload ? 1 : fname ? 3 : 2, dhcp_argv); + + ret = env_set("autoload", old_autoload == -1 ? NULL : + old_autoload ? "y" : "n"); + if (ret) + return log_msg_ret("en2", -EINVAL); + + if (result) + return log_msg_ret("res", -ENOENT); + + return 0; +} +#endif From ec127937199d7ec7116f07bb1642565ab6671a36 Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Wed, 8 Oct 2025 10:31:38 +0300 Subject: [PATCH 14/19] net: airoha: simplify rx/free packet logic a bit The commit 997786bbf473 ("drivers/net/airoha_eth: fix stalling in package receiving") can be improved. Instead of returning previous descriptor it's possible: * do nothing in even descriptor case * return 2 descriptor to the queue (current and previous) in the odd descriptor case. This patch: * implements above approach * remove logic not required within new approach * adds note that PKTBUFSRX must be even and larger than 7 for reliable driver operations Signed-off-by: Mikhail Kshevetskiy --- drivers/net/airoha_eth.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/drivers/net/airoha_eth.c b/drivers/net/airoha_eth.c index 6588eb3a806..19c3d60044c 100644 --- a/drivers/net/airoha_eth.c +++ b/drivers/net/airoha_eth.c @@ -449,14 +449,10 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, RX_RING_SIZE_MASK, FIELD_PREP(RX_RING_SIZE_MASK, ndesc)); - /* - * See arht_eth_free_pkt() for the reasons used to fill - * REG_RX_CPU_IDX(qid) register. - */ airoha_qdma_rmw(qdma, REG_RX_RING_SIZE(qid), RX_RING_THR_MASK, FIELD_PREP(RX_RING_THR_MASK, 0)); airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, - FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 3)); + FIELD_PREP(RX_RING_CPU_IDX_MASK, q->ndesc - 1)); airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, FIELD_PREP(RX_RING_DMA_IDX_MASK, q->head)); @@ -920,7 +916,6 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length) struct airoha_qdma *qdma = ð->qdma[0]; struct airoha_queue *q; int qid; - u16 prev, pprev; if (!packet) return 0; @@ -930,22 +925,29 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length) /* * Due to cpu cache issue the airoha_qdma_reset_rx_desc() function - * will always touch 2 descriptors: - * - if current descriptor is even, then the previous and the one - * before previous descriptors will be touched (previous cacheline) - * - if current descriptor is odd, then only current and previous - * descriptors will be touched (current cacheline) + * will always touch 2 descriptors placed on the same cacheline: + * - if current descriptor is even, then current and next + * descriptors will be touched + * - if current descriptor is odd, then current and previous + * descriptors will be touched * - * Thus, to prevent possible destroying of rx queue, only (q->ndesc - 2) - * descriptors might be used for packet receiving. + * Thus, to prevent possible destroying of rx queue, we should: + * - do nothing in the even descriptor case, + * - utilize 2 descriptors (current and previous one) in the + * odd descriptor case. + * + * WARNING: Observations shows that PKTBUFSRX must be even and + * larger than 7 for reliable driver operations. */ - prev = (q->head + q->ndesc - 1) % q->ndesc; - pprev = (q->head + q->ndesc - 2) % q->ndesc; - q->head = (q->head + 1) % q->ndesc; + if (q->head & 0x01) { + airoha_qdma_reset_rx_desc(q, q->head - 1); + airoha_qdma_reset_rx_desc(q, q->head); - airoha_qdma_reset_rx_desc(q, prev); - airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, - FIELD_PREP(RX_RING_CPU_IDX_MASK, pprev)); + airoha_qdma_rmw(qdma, REG_RX_CPU_IDX(qid), RX_RING_CPU_IDX_MASK, + FIELD_PREP(RX_RING_CPU_IDX_MASK, q->head)); + } + + q->head = (q->head + 1) % q->ndesc; return 0; } From 648d2ade0b764847b248f5cc362a19510046289b Mon Sep 17 00:00:00 2001 From: Mikhail Kshevetskiy Date: Wed, 8 Oct 2025 10:31:39 +0300 Subject: [PATCH 15/19] net: airoha: increase the number of rx network buffers According to commit 997786bbf473 ("drivers/net/airoha_eth: fix stalling in package receiving") the minimal possible value of SYS_RX_ETH_BUFFER is 4. Unfortunately it's too small for reliable ping. Observations shows that SYS_RX_ETH_BUFFER must be at least 8. Signed-off-by: Mikhail Kshevetskiy --- configs/an7581_evb_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/configs/an7581_evb_defconfig b/configs/an7581_evb_defconfig index 0ccab4f066f..baa3fc3f5de 100644 --- a/configs/an7581_evb_defconfig +++ b/configs/an7581_evb_defconfig @@ -43,6 +43,7 @@ CONFIG_ENV_IS_IN_MMC=y CONFIG_ENV_RELOC_GD_ENV_ADDR=y CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y CONFIG_NET_RANDOM_ETHADDR=y +CONFIG_SYS_RX_ETH_BUFFER=8 CONFIG_REGMAP=y CONFIG_SYSCON=y CONFIG_CLK=y From 34369d34e413ac32a131dd144b55ad04873e4854 Mon Sep 17 00:00:00 2001 From: "Lucien.Jheng" Date: Mon, 6 Oct 2025 20:49:15 +0800 Subject: [PATCH 16/19] net: phy: add paged PHY register accessors Synchronize paged PHY helpers with Linux v6.17. Add support for PHY devices that use paged register access by implementing the following functions: - phy_save_page(): Save current page number - phy_select_page(): Switch to a specific page and return previous page - phy_restore_page(): Restore previously saved page Also adds read_page and write_page callbacks to the phy_driver structure to enable driver-specific page handling. These helpers allow safe access to paged PHY registers by ensuring proper page selection and restoration, even in error conditions, which will be used by the Airoha PHY driver. Signed-off-by: Lucien.Jheng --- drivers/net/phy/phy.c | 113 ++++++++++++++++++++++++++++++++++++++++++ include/phy.h | 8 +++ 2 files changed, 121 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 9702d042296..b58283fe3d5 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1250,3 +1250,116 @@ bool phy_interface_is_ncsi(void) return 0; #endif } + +/** + * __phy_read_page() - read the current page + * @phydev: a pointer to a &struct phy_device + * + * Returns page index or < 0 on error + */ +static int __phy_read_page(struct phy_device *phydev) +{ + struct phy_driver *drv = phydev->drv; + + if (!drv->read_page) { + debug("read_page callback not available, PHY driver not loaded?\n"); + return -EOPNOTSUPP; + } + + return drv->read_page(phydev); +} + +/** + * __phy_write_page() - Write a new page + * @phydev: a pointer to a &struct phy_device + * @page: page index to select + * + * Returns 0 or < 0 on error. + */ +static int __phy_write_page(struct phy_device *phydev, int page) +{ + struct phy_driver *drv = phydev->drv; + + if (!drv->write_page) { + debug("write_page callback not available, PHY driver not loaded?\n"); + return -EOPNOTSUPP; + } + + return drv->write_page(phydev, page); +} + +/** + * phy_save_page() - save the current page + * @phydev: a pointer to a &struct phy_device + * + * Return the current page number. On error, + * returns a negative errno. phy_restore_page() must always be called + * after this, irrespective of success or failure of this call. + */ +int phy_save_page(struct phy_device *phydev) +{ + return __phy_read_page(phydev); +} + +/** + * phy_select_page - Switch to a PHY page and return the previous page + * @phydev: a pointer to a &struct phy_device + * @page: desired page + * + * NOTE: Save the current PHY page, and set the current page. + * On error, returns a negative errno, otherwise returns the previous page number. + * phy_restore_page() must always be called after this, irrespective + * of success or failure of this call. + */ +int phy_select_page(struct phy_device *phydev, int page) +{ + int ret, oldpage; + + oldpage = ret = phy_save_page(phydev); + if (ret < 0) + return ret; + + if (oldpage != page) { + ret = __phy_write_page(phydev, page); + if (ret < 0) + return ret; + } + + return oldpage; +} + +/** + * phy_restore_page - Restore a previously saved page and propagate status + * @phydev: a pointer to a &struct phy_device + * @oldpage: the old page, return value from phy_save_page() or phy_select_page() + * @ret: operation's return code + * + * Restoring @oldpage if it is a valid page. + * This function propagates the earliest error code from the group of + * operations. + * + * Returns: + * @oldpage if it was a negative value, otherwise + * @ret if it was a negative errno value, otherwise + * phy_write_page()'s negative value if it were in error, otherwise + * @ret. + */ +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret) +{ + int r; + + if (oldpage >= 0) { + r = __phy_write_page(phydev, oldpage); + + /* Propagate the operation return code if the page write + * was successful. + */ + if (ret >= 0 && r < 0) + ret = r; + } else { + /* Propagate the phy page selection error code */ + ret = oldpage; + } + + return ret; +} \ No newline at end of file diff --git a/include/phy.h b/include/phy.h index 36354aaf774..ae9fd1652cc 100644 --- a/include/phy.h +++ b/include/phy.h @@ -123,6 +123,11 @@ struct phy_driver { int (*write_mmd)(struct phy_device *phydev, int devad, int reg, u16 val); + /** @read_page: Return the current PHY register page number */ + int (*read_page)(struct phy_device *phydev); + /** @write_page: Set the current PHY register page number */ + int (*write_page)(struct phy_device *phydev, int page); + /* driver private data */ ulong data; }; @@ -314,6 +319,9 @@ int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum, u16 mask, u16 set); int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 mask, u16 set); +int phy_save_page(struct phy_device *phydev); +int phy_select_page(struct phy_device *phydev, int page); +int phy_restore_page(struct phy_device *phydev, int oldpage, int ret); int phy_startup(struct phy_device *phydev); int phy_config(struct phy_device *phydev); From 81e5708cc2c865df606e49aed5415adb2a662171 Mon Sep 17 00:00:00 2001 From: Paul HENRYS Date: Thu, 9 Oct 2025 17:43:28 +0200 Subject: [PATCH 17/19] net: bootp: Prevent buffer overflow to avoid leaking the RAM content CVE-2024-42040 describes a possible buffer overflow when calling bootp_process_vendor() in bootp_handler() since the total length of the packet is passed to bootp_process_vendor() without being reduced to len-(offsetof(struct bootp_hdr,bp_vend)+4). The packet length is also checked against its minimum size to avoid reading data from struct bootp_hdr outside of the packet length. Signed-off-by: Paul HENRYS Signed-off-by: Philippe Reynes --- net/bootp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/net/bootp.c b/net/bootp.c index a28d11cb368..64fca9a42d9 100644 --- a/net/bootp.c +++ b/net/bootp.c @@ -379,6 +379,14 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip, debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n", src, dest, len, sizeof(struct bootp_hdr)); + /* Check the minimum size of a BOOTP packet is respected. + * A BOOTP packet is between 300 bytes and 576 bytes big + */ + if (len < offsetof(struct bootp_hdr, bp_vend) + 64) { + printf("Error: got an invalid BOOTP packet (len=%u)\n", len); + return; + } + bp = (struct bootp_hdr *)pkt; /* Filter out pkts we don't want */ @@ -396,7 +404,8 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct in_addr sip, /* Retrieve extended information (we must parse the vendor area) */ if (net_read_u32((u32 *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)) - bootp_process_vendor((uchar *)&bp->bp_vend[4], len); + bootp_process_vendor((uchar *)&bp->bp_vend[4], len - + (offsetof(struct bootp_hdr, bp_vend) + 4)); net_set_timeout_handler(0, (thand_f *)0); bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop"); From 85c2c2c517ac8a6bba406bfd84fa11b26bbcb9aa Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Fri, 10 Oct 2025 11:36:33 -0600 Subject: [PATCH 18/19] net: phy: Make driver overloading get_phy_id depend on !COMPILE_TEST With commit 597fe041a85f ("net/phy: enable get_phy_id redefinable") we made get_phy_id a public but weak function, so that PHY drivers that had required non-standard ways of getting the PHY ID could be supported. However, overloading a weak function multiple times is (rightly) a link error. At this point, we have two PHYs which make use of this feature, so make both of them only available when COMPILE_TEST is unset, as part of being able to support "allyesconfig" in the future. Signed-off-by: Tom Rini --- drivers/net/phy/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 185c6a3156e..018be98705a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -56,6 +56,7 @@ endif # B53_SWITCH config MV88E61XX_SWITCH bool "Marvell MV88E61xx Ethernet switch PHY support." + depends on !COMPILE_TEST if MV88E61XX_SWITCH @@ -119,6 +120,7 @@ config PHY_BROADCOM config PHY_CORTINA bool "Cortina Ethernet PHYs support" + depends on !COMPILE_TEST config SYS_CORTINA_NO_FW_UPLOAD bool "Cortina firmware loading support" From ed6ec8d1ca0658d811df1cc78d06fec4f7f69fc9 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 14 Oct 2025 13:20:05 +0800 Subject: [PATCH 19/19] net: designware: fix bitbang init error The Synchronous Abort and reset errors occurred due to incorrect parameter passing during initialization. Signed-off-by: Jim Liu [jf: add missing #if IS_ENABLED(CONFIG_BITBANGMII)] Signed-off-by: Jerome Forissier --- drivers/net/designware.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/designware.c b/drivers/net/designware.c index 2fd92cf16bb..6ed9c6d538a 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -125,6 +125,16 @@ static int dw_mdio_reset(struct mii_dev *bus) return __dw_mdio_reset(dev); } + +#if IS_ENABLED(CONFIG_BITBANGMII) +static int dw_bb_mdio_reset(struct mii_dev *bus) +{ + struct dw_eth_dev *priv = bus->priv; + + return __dw_mdio_reset(priv->dev); +} +#endif + #endif #if IS_ENABLED(CONFIG_DM_MDIO) @@ -348,7 +358,7 @@ static int dw_bb_mdio_init(const char *name, struct udevice *dev) bus->read = dw_bb_miiphy_read; bus->write = dw_bb_miiphy_write; #if CONFIG_IS_ENABLED(DM_GPIO) - bus->reset = dw_mdio_reset; + bus->reset = dw_bb_mdio_reset; #endif bus->priv = dwpriv;