[PATCH net-next 1/3] r8169: propagate errors from PHY write operations

From: Matheus Alves de Almeida

Date: Wed Sep 16 2026 - 11:34:09 EST


Currently, hardware timeouts and other errors are ignored during
PHY write operations.

Return an error when these operations fail and propagate it through
rtl_writephy().

Signed-off-by: Matheus Alves de Almeida <matheus.aalmeida@xxxxxxxxxxxx>
---
drivers/net/ethernet/realtek/r8169_firmware.h | 2 +-
drivers/net/ethernet/realtek/r8169_main.c | 44 +++++++++++--------
2 files changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169_firmware.h b/drivers/net/ethernet/realtek/r8169_firmware.h
index 7dc348ed8..1285a1c28 100644
--- a/drivers/net/ethernet/realtek/r8169_firmware.h
+++ b/drivers/net/ethernet/realtek/r8169_firmware.h
@@ -12,7 +12,7 @@
#include <linux/firmware.h>

struct rtl8169_private;
-typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
+typedef int (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);

#define RTL_VER_SIZE 32
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index 5415ff62a..3c37c5a6c 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -1145,14 +1145,15 @@ DECLARE_RTL_COND(rtl_ocp_gphy_cond)
return RTL_R32(tp, GPHY_OCP) & OCPAR_FLAG;
}

-static void r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
+static int r8168_phy_ocp_write(struct rtl8169_private *tp, u32 reg, u32 data)
{
if (rtl_ocp_reg_failure(reg))
- return;
+ return 0;

RTL_W32(tp, GPHY_OCP, OCPAR_FLAG | (reg << 15) | data);

- rtl_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10);
+ return rtl_loop_wait_low(tp, &rtl_ocp_gphy_cond, 25, 10) ?
+ 0 : -ETIMEDOUT;
}

static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
@@ -1337,11 +1338,11 @@ static void rtl8168g_phy_suspend_quirk(struct rtl8169_private *tp, int value)
}
};

-static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
+static int r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
{
if (reg == 0x1f) {
tp->ocp_base = value ? value << 4 : OCP_STD_PHY_BASE;
- return;
+ return 0;
}

if (tp->ocp_base != OCP_STD_PHY_BASE)
@@ -1350,7 +1351,7 @@ static void r8168g_mdio_write(struct rtl8169_private *tp, int reg, int value)
if (tp->ocp_base == OCP_STD_PHY_BASE && reg == MII_BMCR)
rtl8168g_phy_suspend_quirk(tp, value);

- r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
+ return r8168_phy_ocp_write(tp, tp->ocp_base + reg * 2, value);
}

static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
@@ -1364,14 +1365,15 @@ static int r8168g_mdio_read(struct rtl8169_private *tp, int reg)
return r8168_phy_ocp_read(tp, tp->ocp_base + reg * 2);
}

-static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
+static int mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
{
if (reg == 0x1f) {
tp->ocp_base = value << 4;
- return;
+ return 0;
}

r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);
+ return 0;
}

static bool rtl_is_8116af(struct rtl8169_private *tp)
@@ -1393,16 +1395,19 @@ DECLARE_RTL_COND(rtl_phyar_cond)
return RTL_R32(tp, PHYAR) & 0x80000000;
}

-static void r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
+static int r8169_mdio_write(struct rtl8169_private *tp, int reg, int value)
{
RTL_W32(tp, PHYAR, 0x80000000 | (reg & 0x1f) << 16 | (value & 0xffff));

- rtl_loop_wait_low(tp, &rtl_phyar_cond, 25, 20);
+ if (!rtl_loop_wait_low(tp, &rtl_phyar_cond, 25, 20))
+ return -ETIMEDOUT;
/*
* According to hardware specs a 20us delay is required after write
* complete indication, but before sending next command.
*/
udelay(20);
+
+ return 0;
}

static int r8169_mdio_read(struct rtl8169_private *tp, int reg)
@@ -1440,13 +1445,17 @@ static void r8168dp_2_mdio_stop(struct rtl8169_private *tp)
RTL_W32(tp, 0xd0, RTL_R32(tp, 0xd0) | R8168DP_1_MDIO_ACCESS_BIT);
}

-static void r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
+static int r8168dp_2_mdio_write(struct rtl8169_private *tp, int reg, int value)
{
+ int rc;
+
r8168dp_2_mdio_start(tp);

- r8169_mdio_write(tp, reg, value);
+ rc = r8169_mdio_write(tp, reg, value);

r8168dp_2_mdio_stop(tp);
+
+ return rc;
}

static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
@@ -1466,19 +1475,16 @@ static int r8168dp_2_mdio_read(struct rtl8169_private *tp, int reg)
return value;
}

-static void rtl_writephy(struct rtl8169_private *tp, int location, int val)
+static int rtl_writephy(struct rtl8169_private *tp, int location, int val)
{
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_28:
case RTL_GIGA_MAC_VER_31:
- r8168dp_2_mdio_write(tp, location, val);
- break;
+ return r8168dp_2_mdio_write(tp, location, val);
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_LAST:
- r8168g_mdio_write(tp, location, val);
- break;
+ return r8168g_mdio_write(tp, location, val);
default:
- r8169_mdio_write(tp, location, val);
- break;
+ return r8169_mdio_write(tp, location, val);
}
}

--
2.43.0