| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/10 05:33 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"R8169"
],
"FocusSymbols": [
"phylink_update_mac_pause_capabilities",
"rtl8169_change_mtu",
"rtl_init_phylink",
"rtl8169_pcs_config",
"rtl8169_pcs_get_state",
"rtl_mac_link_up",
"rtl_mac_link_down",
"rtl_mac_select_pcs",
"rtl_mac_disable_tx_lpi",
"rtl_mac_enable_tx_lpi",
"rtl8169_sds_read",
"r8127_sds_read",
"r8127_sds_write",
"r8127_sds_modify",
"r8127_sfp_init_1g",
"r8127_sfp_init_10g",
"rtl_get_sfp_mode",
"rtl_is_8116af",
"rtl_lowpower_hidden_functions",
"rtl8169_get_link_ksettings",
"rtl8169_set_link_ksettings",
"rtl8169_nway_reset",
"rtl8169_ioctl"
],
"Reasoning": "The patch converts the Realtek r8169 driver to use the phylink API and introduces a new phylink function to dynamically update MAC pause capabilities. These are functional changes to reachable core networking and driver code.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/10 05:33 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 76a29616490114f3862fa4207a87afc66786d9be\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Jul 10 05:33:57 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig\nindex 9b0f4f9631dbaa..5818a9a500a86d 100644\n--- a/drivers/net/ethernet/realtek/Kconfig\n+++ b/drivers/net/ethernet/realtek/Kconfig\n@@ -86,8 +86,8 @@ config R8169\n \tdepends on PCI\n \tselect FW_LOADER\n \tselect CRC32\n-\tselect PHYLIB\n \tselect REALTEK_PHY\n+\tselect PHYLINK\n \thelp\n \t Say Y here if you have a Realtek Ethernet adapter belonging to\n \t the following families:\ndiff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c\nindex ec4fc21fa21fb0..c0b0c2bc5a4855 100644\n--- a/drivers/net/ethernet/realtek/r8169_main.c\n+++ b/drivers/net/ethernet/realtek/r8169_main.c\n@@ -26,12 +26,12 @@\n #include \u003clinux/dma-mapping.h\u003e\n #include \u003clinux/pm_runtime.h\u003e\n #include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/phylink.h\u003e\n #include \u003clinux/prefetch.h\u003e\n #include \u003clinux/ipv6.h\u003e\n #include \u003clinux/unaligned.h\u003e\n #include \u003cnet/ip6_checksum.h\u003e\n #include \u003cnet/netdev_queues.h\u003e\n-#include \u003cnet/phy/realtek_phy.h\u003e\n \n #include \"r8169.h\"\n #include \"r8169_firmware.h\"\n@@ -96,6 +96,25 @@\n #define JUMBO_9K\t(9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)\n #define JUMBO_16K\t(SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN)\n \n+#define R8127_SDS_CMD\t\t0x2348\n+#define R8127_SDS_ADDR\t\t0x234a\n+#define R8127_SDS_DATA_IN\t0x234c\n+#define R8127_SDS_DATA_OUT\t0x234e\n+#define R8127_SDS_CMD_EXEC\tBIT(0)\n+#define R8127_SDS_CMD_WE\tBIT(1)\n+#define OCP_SDS_ADDR_REG\t0xeb10\n+#define OCP_SDS_CMD_REG\t\t0xeb0e\n+#define OCP_SDS_DATA_REG\t0xeb14\n+#define SDS_CMD_READ\t\t0x0001\n+#define RTL_SDS_C22_BASE\t0x40\n+#define RTL_SDS_C45_BASE\t0x0080\n+#define RTL_PKG_DETECT\t\t0xdc00\n+#define RTL_PKG_DETECT_MASK\t0x0078\n+#define RTL_PKG_DETECT_8116AF\t0x0030\n+#define RTL_INT_HW_ID\t\t0xd006\n+#define RTL_INT_HW_ID_MASK\t0x00ff\n+#define RTL_INT_HW_ID_8116AF\t0x0000\n+\n static const struct rtl_chip_info {\n \tu32 mask;\n \tu32 val;\n@@ -334,11 +353,13 @@ enum rtl_registers {\n \tALDPS_LTR\t= 0xe0a2,\n \tLTR_OBFF_LOCK\t= 0xe032,\n \tLTR_SNOOP\t= 0xe034,\n+\tSEND_LTR_MSG\t= 0xe038,\n \n #define ALDPS_LTR_EN\t\t\tBIT(0)\n #define LTR_OBFF_LOCK_EN\t\tBIT(0)\n #define LINK_SPEED_CHANGE_EN\t\tBIT(14)\n #define LTR_SNOOP_EN\t\t\tGENMASK(15, 14)\n+#define LTR_MSG_EN\t\t\tBIT(0)\n };\n \n enum rtl8168_8101_registers {\n@@ -728,6 +749,12 @@ enum rtl_dash_type {\n \tRTL_DASH_25_BP,\n };\n \n+enum rtl_sfp_mode {\n+\tRTL_SFP_NONE,\n+\tRTL_SFP_8168_AF,\n+\tRTL_SFP_8127_ATF,\n+};\n+\n struct rtl8169_private {\n \tvoid __iomem *mmio_addr;\t/* memory map physical address */\n \tstruct pci_dev *pci_dev;\n@@ -736,6 +763,7 @@ struct rtl8169_private {\n \tstruct napi_struct napi;\n \tenum mac_version mac_version;\n \tenum rtl_dash_type dash_type;\n+\tenum rtl_sfp_mode sfp_mode;\n \tu32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */\n \tu32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */\n \tu32 dirty_tx;\n@@ -750,6 +778,7 @@ struct rtl8169_private {\n \tu32 irq_mask;\n \tint irq;\n \tstruct clk *clk;\n+\tint speed;\n \n \tstruct {\n \t\tDECLARE_BITMAP(flags, RTL_FLAG_MAX);\n@@ -762,7 +791,6 @@ struct rtl8169_private {\n \tunsigned supports_gmii:1;\n \tunsigned aspm_manageable:1;\n \tunsigned dash_enabled:1;\n-\tbool sfp_mode:1;\n \tdma_addr_t counters_phys_addr;\n \tstruct rtl8169_counters *counters;\n \tstruct rtl8169_tc_offsets tc_offset;\n@@ -774,6 +802,9 @@ struct rtl8169_private {\n \tstruct r8169_led_classdev *leds;\n \n \tu32 ocp_base;\n+\tstruct phylink *phylink;\n+\tstruct phylink_config phylink_config;\n+\tstruct phylink_pcs pcs;\n };\n \n typedef void (*rtl_generic_fct)(struct rtl8169_private *tp);\n@@ -1128,10 +1159,6 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)\n \tif (rtl_ocp_reg_failure(reg))\n \t\treturn 0;\n \n-\t/* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */\n-\tif (tp-\u003esfp_mode \u0026\u0026 reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))\n-\t\treturn PHY_ID_RTL_DUMMY_SFP \u0026 0xffff;\n-\n \tRTL_W32(tp, GPHY_OCP, reg \u003c\u003c 15);\n \n \treturn rtl_loop_wait_high(tp, \u0026rtl_ocp_gphy_cond, 25, 10) ?\n@@ -1199,6 +1226,73 @@ static void r8127_sfp_sds_phy_reset(struct rtl8169_private *tp)\n \tusleep_range(10, 20);\n }\n \n+DECLARE_RTL_COND(r8127_sds_cmd_cond)\n+{\n+\treturn RTL_R16(tp, R8127_SDS_CMD) \u0026 R8127_SDS_CMD_EXEC;\n+}\n+\n+static int r8127_sds_read(struct rtl8169_private *tp, u16 index, u16 page, u16 reg)\n+{\n+\tu16 addr = (index \u003c\u003c 11) | (page \u003c\u003c 5) | reg;\n+\n+\tRTL_W16(tp, R8127_SDS_ADDR, addr);\n+\tRTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_EXEC);\n+\n+\tif (rtl_loop_wait_low(tp, \u0026r8127_sds_cmd_cond, 10, 100))\n+\t\treturn RTL_R16(tp, R8127_SDS_DATA_OUT);\n+\n+\treturn -ETIMEDOUT;\n+}\n+\n+static int r8127_sds_write(struct rtl8169_private *tp, u16 index, u16 page,\n+\t\t\t u16 reg, u16 val)\n+{\n+\tu16 addr = (index \u003c\u003c 11) | (page \u003c\u003c 5) | reg;\n+\n+\tRTL_W16(tp, R8127_SDS_DATA_IN, val);\n+\tRTL_W16(tp, R8127_SDS_ADDR, addr);\n+\tRTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_EXEC | R8127_SDS_CMD_WE);\n+\n+\tif (rtl_loop_wait_low(tp, \u0026r8127_sds_cmd_cond, 10, 100))\n+\t\treturn 0;\n+\n+\treturn -ETIMEDOUT;\n+}\n+\n+static void r8127_sds_modify(struct rtl8169_private *tp, u16 index, u16 page,\n+\t\t\t u16 reg, u16 clearmask, u16 setmask)\n+{\n+\tint val = r8127_sds_read(tp, index, page, reg);\n+\n+\tif (val \u003c 0)\n+\t\treturn;\n+\n+\tval = (val \u0026 ~clearmask) | setmask;\n+\tr8127_sds_write(tp, index, page, reg, val);\n+}\n+\n+static void r8127_sfp_init_1g(struct rtl8169_private *tp)\n+{\n+\tint val;\n+\n+\tr8127_sfp_sds_phy_reset(tp);\n+\n+\tr8127_sds_modify(tp, 0, 1, 31, 0, BIT(3));\n+\tr8127_sds_modify(tp, 0, 2, 0, BIT(13) | BIT(12) | BIT(6), BIT(12) | BIT(6));\n+\tr8127_sds_modify(tp, 0, 0, 4, 0, BIT(2));\n+\n+\tRTL_W16(tp, 0x233a, 0x8004);\n+\tRTL_W16(tp, 0x233e, (RTL_R16(tp, 0x233e) \u0026 ~0x3003) | 0x0002);\n+\n+\tr8168_phy_ocp_write(tp, 0xc40a, 0x0000);\n+\tr8168_phy_ocp_write(tp, 0xc466, 0x0000);\n+\tr8168_phy_ocp_write(tp, 0xc808, 0x0000);\n+\tr8168_phy_ocp_write(tp, 0xc80a, 0x0000);\n+\n+\tval = r8168_phy_ocp_read(tp, 0xc804);\n+\tr8168_phy_ocp_write(tp, 0xc804, (val \u0026 ~0x000f) | 0x000c);\n+}\n+\n static void r8127_sfp_init_10g(struct rtl8169_private *tp)\n {\n \tint val;\n@@ -1217,12 +1311,6 @@ static void r8127_sfp_init_10g(struct rtl8169_private *tp)\n \tr8168_phy_ocp_write(tp, 0xc804, (val \u0026 ~0x000f) | 0x000c);\n }\n \n-static void rtl_sfp_init(struct rtl8169_private *tp)\n-{\n-\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n-\t\tr8127_sfp_init_10g(tp);\n-}\n-\n static void rtl_sfp_reset(struct rtl8169_private *tp)\n {\n \tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n@@ -1283,6 +1371,15 @@ static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)\n \tr8168_mac_ocp_write(tp, tp-\u003eocp_base + reg, value);\n }\n \n+static bool rtl_is_8116af(struct rtl8169_private *tp)\n+{\n+\treturn tp-\u003emac_version == RTL_GIGA_MAC_VER_52 \u0026\u0026\n+\t\t(r8168_mac_ocp_read(tp, RTL_PKG_DETECT) \u0026 RTL_PKG_DETECT_MASK) ==\n+\t\tRTL_PKG_DETECT_8116AF \u0026\u0026\n+\t\t(r8168_mac_ocp_read(tp, RTL_INT_HW_ID) \u0026 RTL_INT_HW_ID_MASK) ==\n+\t\tRTL_INT_HW_ID_8116AF;\n+}\n+\n static int mac_mcu_read(struct rtl8169_private *tp, int reg)\n {\n \treturn r8168_mac_ocp_read(tp, tp-\u003eocp_base + reg);\n@@ -1578,6 +1675,20 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp)\n \t}\n }\n \n+static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)\n+{\n+\tif (rtl_is_8125(tp)) {\n+\t\tu16 data = r8168_mac_ocp_read(tp, RTL_INT_HW_ID);\n+\n+\t\tif ((data \u0026 0xff) == 0x07)\n+\t\t\treturn RTL_SFP_8127_ATF;\n+\t} else if (rtl_is_8116af(tp)) {\n+\t\treturn RTL_SFP_8168_AF;\n+\t}\n+\n+\treturn RTL_SFP_NONE;\n+}\n+\n static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)\n {\n \tswitch (tp-\u003emac_version) {\n@@ -1673,16 +1784,14 @@ static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)\n \trtl_pci_commit(tp);\n }\n \n-static void rtl_link_chg_patch(struct rtl8169_private *tp)\n+static void rtl_link_chg_patch(struct rtl8169_private *tp, int speed)\n {\n-\tstruct phy_device *phydev = tp-\u003ephydev;\n-\n \tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_34 ||\n \t tp-\u003emac_version == RTL_GIGA_MAC_VER_38) {\n-\t\tif (phydev-\u003espeed == SPEED_1000) {\n+\t\tif (speed == SPEED_1000) {\n \t\t\trtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011);\n \t\t\trtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);\n-\t\t} else if (phydev-\u003espeed == SPEED_100) {\n+\t\t} else if (speed == SPEED_100) {\n \t\t\trtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f);\n \t\t\trtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);\n \t\t} else {\n@@ -1692,7 +1801,7 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)\n \t\trtl_reset_packet_filter(tp);\n \t} else if (tp-\u003emac_version == RTL_GIGA_MAC_VER_35 ||\n \t\t tp-\u003emac_version == RTL_GIGA_MAC_VER_36) {\n-\t\tif (phydev-\u003espeed == SPEED_1000) {\n+\t\tif (speed == SPEED_1000) {\n \t\t\trtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011);\n \t\t\trtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);\n \t\t} else {\n@@ -1700,7 +1809,7 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)\n \t\t\trtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f);\n \t\t}\n \t} else if (tp-\u003emac_version == RTL_GIGA_MAC_VER_37) {\n-\t\tif (phydev-\u003espeed == SPEED_10) {\n+\t\tif (speed == SPEED_10) {\n \t\t\trtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02);\n \t\t\trtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060a);\n \t\t} else {\n@@ -2074,11 +2183,11 @@ rtl_coalesce_info(struct rtl8169_private *tp)\n \t\tci = rtl_coalesce_info_8168_8136;\n \n \t/* if speed is unknown assume highest one */\n-\tif (tp-\u003ephydev-\u003espeed == SPEED_UNKNOWN)\n+\tif (tp-\u003espeed == SPEED_UNKNOWN)\n \t\treturn ci;\n \n \tfor (; ci-\u003espeed; ci++) {\n-\t\tif (tp-\u003ephydev-\u003espeed == ci-\u003espeed)\n+\t\tif (tp-\u003espeed == ci-\u003espeed)\n \t\t\treturn ci;\n \t}\n \n@@ -2236,7 +2345,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp)\n \n static unsigned int r8169_get_tx_lpi_timer_us(struct rtl8169_private *tp)\n {\n-\tunsigned int speed = tp-\u003ephydev-\u003espeed;\n+\tunsigned int speed = tp-\u003espeed;\n \tunsigned int timer = tp-\u003etx_lpi_timer;\n \n \tif (!timer || speed == SPEED_UNKNOWN)\n@@ -2254,7 +2363,7 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data)\n \tif (!rtl_supports_eee(tp))\n \t\treturn -EOPNOTSUPP;\n \n-\tret = phy_ethtool_get_eee(tp-\u003ephydev, data);\n+\tret = phylink_ethtool_get_eee(tp-\u003ephylink, data);\n \tif (ret)\n \t\treturn ret;\n \n@@ -2270,7 +2379,7 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data)\n \tif (!rtl_supports_eee(tp))\n \t\treturn -EOPNOTSUPP;\n \n-\treturn phy_ethtool_set_eee(tp-\u003ephydev, data);\n+\treturn phylink_ethtool_set_eee(tp-\u003ephylink, data);\n }\n \n static void rtl8169_get_ringparam(struct net_device *dev,\n@@ -2301,13 +2410,8 @@ static void rtl8169_get_pauseparam(struct net_device *dev,\n \t\t\t\t struct ethtool_pauseparam *data)\n {\n \tstruct rtl8169_private *tp = netdev_priv(dev);\n-\tbool tx_pause, rx_pause;\n-\n-\tphy_get_pause(tp-\u003ephydev, \u0026tx_pause, \u0026rx_pause);\n \n-\tdata-\u003eautoneg = tp-\u003ephydev-\u003eautoneg;\n-\tdata-\u003etx_pause = tx_pause ? 1 : 0;\n-\tdata-\u003erx_pause = rx_pause ? 1 : 0;\n+\tphylink_ethtool_get_pauseparam(tp-\u003ephylink, data);\n }\n \n static int rtl8169_set_pauseparam(struct net_device *dev,\n@@ -2318,9 +2422,7 @@ static int rtl8169_set_pauseparam(struct net_device *dev,\n \tif (dev-\u003emtu \u003e ETH_DATA_LEN)\n \t\treturn -EOPNOTSUPP;\n \n-\tphy_set_asym_pause(tp-\u003ephydev, data-\u003erx_pause, data-\u003etx_pause);\n-\n-\treturn 0;\n+\treturn phylink_ethtool_set_pauseparam(tp-\u003ephylink, data);\n }\n \n static void rtl8169_get_eth_mac_stats(struct net_device *dev,\n@@ -2386,34 +2488,27 @@ static void rtl8169_get_eth_ctrl_stats(struct net_device *dev,\n \t\tle32_to_cpu(tp-\u003ecounters-\u003erx_unknown_opcode);\n }\n \n-static int rtl8169_set_link_ksettings(struct net_device *ndev,\n-\t\t\t\t const struct ethtool_link_ksettings *cmd)\n+static int rtl8169_get_link_ksettings(struct net_device *ndev,\n+\t\t\t\t struct ethtool_link_ksettings *cmd)\n {\n \tstruct rtl8169_private *tp = netdev_priv(ndev);\n-\tstruct phy_device *phydev = tp-\u003ephydev;\n-\tint duplex = cmd-\u003ebase.duplex;\n-\tint speed = cmd-\u003ebase.speed;\n-\n-\tif (!tp-\u003esfp_mode)\n-\t\treturn phy_ethtool_ksettings_set(phydev, cmd);\n-\n-\tif (cmd-\u003ebase.autoneg != AUTONEG_DISABLE)\n-\t\treturn -EINVAL;\n-\n-\tif (!phy_check_valid(speed, duplex, phydev-\u003esupported))\n-\t\treturn -EINVAL;\n \n-\tmutex_lock(\u0026phydev-\u003elock);\n+\treturn phylink_ethtool_ksettings_get(tp-\u003ephylink, cmd);\n+}\n \n-\tphydev-\u003eautoneg = AUTONEG_DISABLE;\n-\tphydev-\u003espeed = speed;\n-\tphydev-\u003eduplex = duplex;\n+static int rtl8169_set_link_ksettings(struct net_device *ndev,\n+\t\t\t\t const struct ethtool_link_ksettings *cmd)\n+{\n+\tstruct rtl8169_private *tp = netdev_priv(ndev);\n \n-\trtl_sfp_init(tp);\n+\treturn phylink_ethtool_ksettings_set(tp-\u003ephylink, cmd);\n+}\n \n-\tmutex_unlock(\u0026phydev-\u003elock);\n+static int rtl8169_nway_reset(struct net_device *dev)\n+{\n+\tstruct rtl8169_private *tp = netdev_priv(dev);\n \n-\treturn 0;\n+\treturn phylink_ethtool_nway_reset(tp-\u003ephylink);\n }\n \n static const struct ethtool_ops rtl8169_ethtool_ops = {\n@@ -2431,10 +2526,10 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {\n \t.get_sset_count\t\t= rtl8169_get_sset_count,\n \t.get_ethtool_stats\t= rtl8169_get_ethtool_stats,\n \t.get_ts_info\t\t= ethtool_op_get_ts_info,\n-\t.nway_reset\t\t= phy_ethtool_nway_reset,\n+\t.nway_reset\t\t= rtl8169_nway_reset,\n \t.get_eee\t\t= rtl8169_get_eee,\n \t.set_eee\t\t= rtl8169_set_eee,\n-\t.get_link_ksettings\t= phy_ethtool_get_link_ksettings,\n+\t.get_link_ksettings\t= rtl8169_get_link_ksettings,\n \t.set_link_ksettings\t= rtl8169_set_link_ksettings,\n \t.get_ringparam\t\t= rtl8169_get_ringparam,\n \t.get_pause_stats\t= rtl8169_get_pause_stats,\n@@ -2499,9 +2594,10 @@ void r8169_apply_firmware(struct rtl8169_private *tp)\n \t\ttp-\u003eocp_base = OCP_STD_PHY_BASE;\n \n \t\t/* PHY soft reset may still be in progress */\n-\t\tphy_read_poll_timeout(tp-\u003ephydev, MII_BMCR, val,\n-\t\t\t\t !(val \u0026 BMCR_RESET),\n-\t\t\t\t 50000, 600000, true);\n+\t\tif (tp-\u003ephydev)\n+\t\t\tphy_read_poll_timeout(tp-\u003ephydev, MII_BMCR, val,\n+\t\t\t\t\t !(val \u0026 BMCR_RESET),\n+\t\t\t\t\t 50000, 600000, true);\n \t}\n }\n \n@@ -2538,6 +2634,8 @@ static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)\n \n static void rtl8169_init_phy(struct rtl8169_private *tp)\n {\n+\tphy_init_hw(tp-\u003ephydev);\n+\tphy_resume(tp-\u003ephydev);\n \tr8169_hw_phy_config(tp, tp-\u003ephydev, tp-\u003emac_version);\n \n \tif (tp-\u003emac_version \u003c= RTL_GIGA_MAC_VER_06) {\n@@ -2552,9 +2650,6 @@ static void rtl8169_init_phy(struct rtl8169_private *tp)\n \t tp-\u003epci_dev-\u003esubsystem_device == 0xe000)\n \t\tphy_write_paged(tp-\u003ephydev, 0x0001, 0x10, 0xf01b);\n \n-\tif (tp-\u003esfp_mode)\n-\t\trtl_sfp_init(tp);\n-\n \t/* We may have called phy_speed_down before */\n \tphy_speed_up(tp-\u003ephydev);\n \n@@ -2657,15 +2752,6 @@ static void rtl_jumbo_config(struct rtl8169_private *tp)\n \n \tif (pci_is_pcie(tp-\u003epci_dev) \u0026\u0026 tp-\u003esupports_gmii)\n \t\tpcie_set_readrq(tp-\u003epci_dev, readrq);\n-\n-\t/* Chip doesn't support pause in jumbo mode */\n-\tif (jumbo) {\n-\t\tlinkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,\n-\t\t\t\t tp-\u003ephydev-\u003eadvertising);\n-\t\tlinkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,\n-\t\t\t\t tp-\u003ephydev-\u003eadvertising);\n-\t\tphy_start_aneg(tp-\u003ephydev);\n-\t}\n }\n \n DECLARE_RTL_COND(rtl_chipcmd_cond)\n@@ -2780,7 +2866,7 @@ static void rtl_prepare_power_down(struct rtl8169_private *tp)\n \t\trtl_ephy_write(tp, 0x19, 0xff64);\n \n \tif (device_may_wakeup(tp_to_dev(tp))) {\n-\t\tphy_speed_down(tp-\u003ephydev, false);\n+\t\tphylink_speed_down(tp-\u003ephylink, false);\n \t\trtl_wol_enable_rx(tp);\n \t}\n }\n@@ -2832,6 +2918,16 @@ static void rtl8169_set_magic_reg(struct rtl8169_private *tp)\n \tRTL_W32(tp, 0x7c, val);\n }\n \n+static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)\n+{\n+\tstruct rtl8169_private *tp = netdev_priv(dev);\n+\n+\tif (!netif_running(dev))\n+\t\treturn -ENODEV;\n+\n+\treturn phylink_mii_ioctl(tp-\u003ephylink, ifr, cmd);\n+}\n+\n static void rtl_set_rx_mode(struct net_device *dev)\n {\n \tu32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;\n@@ -3098,8 +3194,23 @@ static void rtl_enable_ltr(struct rtl8169_private *tp)\n \t\tr8168_mac_ocp_write(tp, 0xcdf2, 0x9003);\n \t\tr8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN);\n \t\tbreak;\n-\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\n \tcase RTL_GIGA_MAC_VER_52:\n+\t\tr8168_mac_ocp_write(tp, 0xcdd0, 0x9003);\n+\t\tr8168_mac_ocp_modify(tp, LTR_SNOOP, 0x0000, LTR_SNOOP_EN);\n+\t\tr8168_mac_ocp_write(tp, 0xe02c, 0x1880);\n+\t\tr8168_mac_ocp_write(tp, 0xe02e, 0x4880);\n+\t\tr8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);\n+\t\tr8168_mac_ocp_write(tp, 0xcdd8, 0x9003);\n+\t\tr8168_mac_ocp_write(tp, 0xcdda, 0x9003);\n+\t\tr8168_mac_ocp_write(tp, 0xcddc, 0x9003);\n+\t\tr8168_mac_ocp_write(tp, 0xcdd2, 0x883c);\n+\t\tr8168_mac_ocp_write(tp, 0xcdd4, 0x8c12);\n+\t\tr8168_mac_ocp_write(tp, 0xcdd6, 0x9003);\n+\t\tr8168_mac_ocp_write(tp, 0xe0a6, 0x9003);\n+\t\tr8168_mac_ocp_write(tp, 0xe0a8, 0x9003);\n+\t\tr8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN);\n+\t\tbreak;\n+\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\n \t\tr8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);\n \t\tRTL_W8(tp, COMBO_LTR_EXTEND, RTL_R8(tp, COMBO_LTR_EXTEND) | COMBO_LTR_EXTEND_EN);\n \t\tfallthrough;\n@@ -3119,6 +3230,7 @@ static void rtl_enable_ltr(struct rtl8169_private *tp)\n \t}\n \t/* chip can trigger LTR */\n \tr8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0003, LTR_OBFF_LOCK_EN);\n+\tr8168_mac_ocp_modify(tp, SEND_LTR_MSG, 0x0000, LTR_MSG_EN);\n }\n \n static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)\n@@ -3152,6 +3264,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)\n \t\trtl_enable_ltr(tp);\n \t\tswitch (tp-\u003emac_version) {\n \t\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\n+\t\tcase RTL_GIGA_MAC_VER_52:\n \t\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:\n \t\t\t/* reset ephy tx/rx disable timer */\n \t\t\tr8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);\n@@ -3164,6 +3277,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)\n \t} else {\n \t\tswitch (tp-\u003emac_version) {\n \t\tcase RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:\n+\t\tcase RTL_GIGA_MAC_VER_52:\n \t\tcase RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:\n \t\t\tr8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);\n \t\t\tbreak;\n@@ -3657,6 +3771,42 @@ static void rtl_hw_start_8168ep_3(struct rtl8169_private *tp)\n \tr8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080);\n }\n \n+static void rtl_lowpower_hidden_functions(struct pci_dev *pdev)\n+{\n+\tunsigned int slot = PCI_SLOT(pdev-\u003edevfn);\n+\tstruct pci_bus *bus = pdev-\u003ebus;\n+\tint func, pos;\n+\tu16 val;\n+\n+\tfor (func = 2; func \u003c 8; func++) {\n+\t\tunsigned int devfn = PCI_DEVFN(slot, func);\n+\n+\t\tpos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_EXP);\n+\t\tif (pos) {\n+\t\t\tpci_bus_read_config_word(bus, devfn, pos + PCI_EXP_LNKCTL, \u0026val);\n+\n+\t\t\tif (PCI_POSSIBLE_ERROR(val))\n+\t\t\t\tcontinue;\n+\n+\t\t\tval |= (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);\n+\t\t\tpci_bus_write_config_word(bus, devfn, pos + PCI_EXP_LNKCTL, val);\n+\t\t}\n+\n+\t\tpos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_PM);\n+\t\tif (pos) {\n+\t\t\tpci_bus_read_config_word(bus, devfn, pos + PCI_PM_CTRL, \u0026val);\n+\n+\t\t\tif (PCI_POSSIBLE_ERROR(val))\n+\t\t\t\tcontinue;\n+\n+\t\t\tval \u0026= ~PCI_PM_CTRL_STATE_MASK;\n+\t\t\tval |= PCI_D3hot;\n+\t\t\tval |= PCI_PM_CTRL_PME_STATUS;\n+\t\t\tpci_bus_write_config_word(bus, devfn, pos + PCI_PM_CTRL, val);\n+\t\t}\n+\t}\n+}\n+\n static void rtl_hw_start_8117(struct rtl8169_private *tp)\n {\n \tstatic const struct ephy_info e_info_8117[] = {\n@@ -3693,12 +3843,14 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp)\n \n \trtl_pcie_state_l2l3_disable(tp);\n \n-\trg_saw_cnt = phy_read_paged(tp-\u003ephydev, 0x0c42, 0x13) \u0026 0x3fff;\n-\tif (rg_saw_cnt \u003e 0) {\n-\t\tu16 sw_cnt_1ms_ini;\n+\tif (tp-\u003ephydev) {\n+\t\trg_saw_cnt = phy_read_paged(tp-\u003ephydev, 0x0c42, 0x13) \u0026 0x3fff;\n+\t\tif (rg_saw_cnt \u003e 0) {\n+\t\t\tu16 sw_cnt_1ms_ini;\n \n-\t\tsw_cnt_1ms_ini = (16000000 / rg_saw_cnt) \u0026 0x0fff;\n-\t\tr8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);\n+\t\t\tsw_cnt_1ms_ini = (16000000 / rg_saw_cnt) \u0026 0x0fff;\n+\t\t\tr8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);\n+\t\t}\n \t}\n \n \tr8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);\n@@ -4139,12 +4291,25 @@ static void rtl_hw_start(struct rtl8169_private *tp)\n static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)\n {\n \tstruct rtl8169_private *tp = netdev_priv(dev);\n+\tbool jumbo_before = dev-\u003emtu \u003e ETH_DATA_LEN;\n+\tbool jumbo_after = new_mtu \u003e ETH_DATA_LEN;\n \n \tWRITE_ONCE(dev-\u003emtu, new_mtu);\n \tnetdev_update_features(dev);\n \trtl_jumbo_config(tp);\n \trtl_set_eee_txidle_timer(tp);\n \n+\tif (jumbo_before != jumbo_after) {\n+\t\tunsigned long caps = tp-\u003ephylink_config.mac_capabilities;\n+\n+\t\tif (jumbo_after)\n+\t\t\tcaps \u0026= ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);\n+\t\telse\n+\t\t\tcaps |= (MAC_SYM_PAUSE | MAC_ASYM_PAUSE);\n+\n+\t\tphylink_update_mac_pause_capabilities(tp-\u003ephylink, caps);\n+\t}\n+\n \treturn 0;\n }\n \n@@ -4869,8 +5034,13 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)\n \t\tgoto out;\n \t}\n \n-\tif (status \u0026 LinkChg)\n-\t\tphy_mac_interrupt(tp-\u003ephydev);\n+\tif (status \u0026 LinkChg) {\n+\t\tif (tp-\u003ephydev)\n+\t\t\tphy_mac_interrupt(tp-\u003ephydev);\n+\t\telse if (tp-\u003esfp_mode)\n+\t\t\tphylink_mac_change(tp-\u003ephylink,\n+\t\t\t\t\t !!(RTL_R8(tp, PHYstatus) \u0026 LinkStatus));\n+\t}\n \n \trtl_irq_disable(tp);\n \tnapi_schedule(\u0026tp-\u003enapi);\n@@ -4930,9 +5100,6 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)\n \n static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)\n {\n-\tif (!rtl_supports_eee(tp))\n-\t\treturn;\n-\n \tswitch (tp-\u003emac_version) {\n \tcase RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_52:\n \t\t/* Adjust EEE LED frequency */\n@@ -4963,40 +5130,15 @@ static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)\n \t}\n }\n \n-static void r8169_phylink_handler(struct net_device *ndev)\n-{\n-\tstruct rtl8169_private *tp = netdev_priv(ndev);\n-\tstruct device *d = tp_to_dev(tp);\n-\n-\tif (netif_carrier_ok(ndev)) {\n-\t\trtl_link_chg_patch(tp);\n-\t\trtl_enable_tx_lpi(tp, tp-\u003ephydev-\u003eenable_tx_lpi);\n-\t\tpm_request_resume(d);\n-\t} else {\n-\t\tpm_runtime_idle(d);\n-\t}\n-\n-\tphy_print_status(tp-\u003ephydev);\n-}\n-\n static int r8169_phy_connect(struct rtl8169_private *tp)\n {\n-\tstruct phy_device *phydev = tp-\u003ephydev;\n-\tphy_interface_t phy_mode;\n \tint ret;\n \n-\tphy_mode = tp-\u003esupports_gmii ? PHY_INTERFACE_MODE_GMII :\n-\t\t PHY_INTERFACE_MODE_MII;\n-\n-\tret = phy_connect_direct(tp-\u003edev, phydev, r8169_phylink_handler,\n-\t\t\t\t phy_mode);\n-\tif (ret)\n+\tret = phylink_connect_phy(tp-\u003ephylink, tp-\u003ephydev);\n+\tif (ret) {\n+\t\tnetdev_err(tp-\u003edev, \"failed to connect phy\\n\");\n \t\treturn ret;\n-\n-\tif (!tp-\u003esupports_gmii)\n-\t\tphy_set_max_speed(phydev, SPEED_100);\n-\n-\tphy_attached_info(phydev);\n+\t}\n \n \treturn 0;\n }\n@@ -5007,10 +5149,8 @@ static void rtl8169_down(struct rtl8169_private *tp)\n \t/* Clear all task flags */\n \tbitmap_zero(tp-\u003ewk.flags, RTL_FLAG_MAX);\n \n-\tphy_stop(tp-\u003ephydev);\n-\n \t/* Reset SerDes PHY to bring down fiber link */\n-\tif (tp-\u003esfp_mode)\n+\tif (tp-\u003esfp_mode == RTL_SFP_8127_ATF)\n \t\trtl_sfp_reset(tp);\n \n \trtl8169_update_counters(tp);\n@@ -5032,14 +5172,12 @@ static void rtl8169_up(struct rtl8169_private *tp)\n \t\trtl8168_driver_start(tp);\n \n \tpci_set_master(tp-\u003epci_dev);\n-\tphy_init_hw(tp-\u003ephydev);\n-\tphy_resume(tp-\u003ephydev);\n-\trtl8169_init_phy(tp);\n+\tif (tp-\u003ephydev)\n+\t\trtl8169_init_phy(tp);\n+\n \tnapi_enable(\u0026tp-\u003enapi);\n \tenable_work(\u0026tp-\u003ewk.work);\n \trtl_reset_work(tp);\n-\n-\tphy_start(tp-\u003ephydev);\n }\n \n static int rtl8169_close(struct net_device *dev)\n@@ -5049,13 +5187,14 @@ static int rtl8169_close(struct net_device *dev)\n \n \tpm_runtime_get_sync(\u0026pdev-\u003edev);\n \n+\tphylink_stop(tp-\u003ephylink);\n \tnetif_stop_queue(dev);\n \trtl8169_down(tp);\n \trtl8169_rx_clear(tp);\n \n \tfree_irq(tp-\u003eirq, tp);\n \n-\tphy_disconnect(tp-\u003ephydev);\n+\tphylink_disconnect_phy(tp-\u003ephylink);\n \n \tdma_free_coherent(\u0026pdev-\u003edev, R8169_RX_RING_BYTES, tp-\u003eRxDescArray,\n \t\t\t tp-\u003eRxPhyAddr);\n@@ -5112,11 +5251,13 @@ static int rtl_open(struct net_device *dev)\n \tif (retval \u003c 0)\n \t\tgoto err_release_fw_2;\n \n-\tretval = r8169_phy_connect(tp);\n-\tif (retval)\n-\t\tgoto err_free_irq;\n-\n+\tif (tp-\u003ephydev) {\n+\t\tretval = r8169_phy_connect(tp);\n+\t\tif (retval)\n+\t\t\tgoto err_free_irq;\n+\t}\n \trtl8169_up(tp);\n+\tphylink_start(tp-\u003ephylink);\n \trtl8169_init_counter_offsets(tp);\n \tnetif_start_queue(dev);\n out:\n@@ -5221,6 +5362,9 @@ static int rtl8169_resume(struct device *device)\n \t/* Some chip versions may truncate packets without this initialization */\n \trtl_init_rxcfg(tp);\n \n+\tif (rtl_is_8116af(tp))\n+\t\trtl_lowpower_hidden_functions(tp-\u003epci_dev);\n+\n \treturn rtl8169_runtime_resume(device);\n }\n \n@@ -5288,6 +5432,7 @@ static void rtl_remove_one(struct pci_dev *pdev)\n \t\tr8169_remove_leds(tp-\u003eleds);\n \n \tunregister_netdev(tp-\u003edev);\n+\tphylink_destroy(tp-\u003ephylink);\n \n \tif (tp-\u003edash_type != RTL_DASH_NONE)\n \t\trtl8168_driver_stop(tp);\n@@ -5310,7 +5455,7 @@ static const struct net_device_ops rtl_netdev_ops = {\n \t.ndo_fix_features\t= rtl8169_fix_features,\n \t.ndo_set_features\t= rtl8169_set_features,\n \t.ndo_set_mac_address\t= rtl_set_mac_address,\n-\t.ndo_eth_ioctl\t\t= phy_do_ioctl_running,\n+\t.ndo_eth_ioctl\t\t= rtl8169_ioctl,\n \t.ndo_set_rx_mode\t= rtl_set_rx_mode,\n #ifdef CONFIG_NET_POLL_CONTROLLER\n \t.ndo_poll_controller\t= rtl8169_netpoll,\n@@ -5474,16 +5619,6 @@ static int r8169_mdio_register(struct rtl8169_private *tp)\n \t\treturn -EUNATCH;\n \t}\n \n-\ttp-\u003ephydev-\u003emac_managed_pm = true;\n-\tif (rtl_supports_eee(tp))\n-\t\tphy_support_eee(tp-\u003ephydev);\n-\tphy_support_asym_pause(tp-\u003ephydev);\n-\n-\t/* mimic behavior of r8125/r8126 vendor drivers */\n-\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_61)\n-\t\tphy_disable_eee_mode(tp-\u003ephydev,\n-\t\t\t\t ETHTOOL_LINK_MODE_2500baseT_Full_BIT);\n-\n \t/* PHY will be woken up in rtl_open() */\n \tphy_suspend(tp-\u003ephydev);\n \n@@ -5599,6 +5734,247 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp)\n \treturn false;\n }\n \n+static void rtl_mac_link_down(struct phylink_config *config, unsigned int mode,\n+\t\t\t phy_interface_t interface)\n+{\n+\tstruct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);\n+\n+\ttp-\u003espeed = SPEED_UNKNOWN;\n+\tpm_runtime_idle(tp_to_dev(tp));\n+}\n+\n+static void rtl_mac_link_up(struct phylink_config *config, struct phy_device *phydev,\n+\t\t\t unsigned int mode, phy_interface_t interface,\n+\t\t\t int speed, int duplex, bool tx_pause, bool rx_pause)\n+{\n+\tstruct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);\n+\tstruct device *d = tp_to_dev(tp);\n+\n+\ttp-\u003espeed = speed;\n+\trtl_link_chg_patch(tp, speed);\n+\n+\tpm_request_resume(d);\n+}\n+\n+static struct phylink_pcs *rtl_mac_select_pcs(struct phylink_config *config,\n+\t\t\t\t\t phy_interface_t interface)\n+{\n+\tstruct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);\n+\n+\tif (!tp-\u003epcs.ops)\n+\t\treturn NULL;\n+\n+\tif (interface == PHY_INTERFACE_MODE_1000BASEX ||\n+\t interface == PHY_INTERFACE_MODE_10GBASER)\n+\t\treturn \u0026tp-\u003epcs;\n+\n+\treturn NULL;\n+}\n+\n+static void rtl_mac_config(struct phylink_config *config, unsigned int mode,\n+\t\t\t const struct phylink_link_state *state)\n+{\n+}\n+\n+static u16 rtl8169_sds_read(struct rtl8169_private *tp, u16 sds_reg)\n+{\n+\tunsigned long flags;\n+\tu16 val = 0;\n+\n+\traw_spin_lock_irqsave(\u0026tp-\u003emac_ocp_lock, flags);\n+\t__r8168_mac_ocp_write(tp, OCP_SDS_ADDR_REG, sds_reg);\n+\t__r8168_mac_ocp_write(tp, OCP_SDS_CMD_REG, SDS_CMD_READ);\n+\tval = __r8168_mac_ocp_read(tp, OCP_SDS_DATA_REG);\n+\traw_spin_unlock_irqrestore(\u0026tp-\u003emac_ocp_lock, flags);\n+\n+\treturn val;\n+}\n+\n+static void rtl8169_pcs_get_state(struct phylink_pcs *pcs,\n+\t\t\t\t unsigned int neg_mode,\n+\t\t\t\t struct phylink_link_state *state)\n+{\n+\tstruct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, pcs);\n+\n+\tif (tp-\u003esfp_mode == RTL_SFP_8127_ATF) {\n+\t\tu16 stat1;\n+\n+\t\tstat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1);\n+\n+\t\tif (!(stat1 \u0026 MDIO_STAT1_LSTATUS))\n+\t\t\tstat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1);\n+\n+\t\tstate-\u003elink = !!(stat1 \u0026 MDIO_STAT1_LSTATUS);\n+\t\tif (!state-\u003elink)\n+\t\t\treturn;\n+\n+\t\tif (state-\u003einterface == PHY_INTERFACE_MODE_1000BASEX)\n+\t\t\tstate-\u003espeed = SPEED_1000;\n+\t\telse\n+\t\t\tstate-\u003espeed = SPEED_10000;\n+\n+\t\tstate-\u003eduplex = DUPLEX_FULL;\n+\t} else {\n+\t\tu16 bmsr, lpa;\n+\n+\t\tbmsr = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_BMSR);\n+\t\tlpa = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_LPA);\n+\t\tphylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);\n+\t}\n+}\n+\n+static int rtl8169_pcs_config(struct phylink_pcs *pcs, unsigned int mode,\n+\t\t\t phy_interface_t interface,\n+\t\t\t const unsigned long *advertising,\n+\t\t\t bool permit_pause_to_mac)\n+{\n+\tstruct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, pcs);\n+\n+\tif (tp-\u003esfp_mode == RTL_SFP_8127_ATF) {\n+\t\tswitch (interface) {\n+\t\tcase PHY_INTERFACE_MODE_10GBASER:\n+\t\t\tr8127_sfp_init_10g(tp);\n+\t\t\tbreak;\n+\t\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\t\t\tr8127_sfp_init_1g(tp);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tnetdev_err(tp-\u003edev, \"Unsupported SFP interface mode: %s\\n\",\n+\t\t\t\t phy_modes(interface));\n+\t\t\treturn -EOPNOTSUPP;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int rtl8169_pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,\n+\t\t\t\tconst struct phylink_link_state *state)\n+{\n+\treturn 0;\n+}\n+\n+static void rtl8169_pcs_an_restart(struct phylink_pcs *pcs)\n+{\n+}\n+\n+static void rtl_mac_disable_tx_lpi(struct phylink_config *config)\n+{\n+\tstruct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);\n+\n+\trtl_enable_tx_lpi(tp, false);\n+}\n+\n+static int rtl_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, bool tx_clk_stop)\n+{\n+\tstruct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);\n+\n+\trtl_enable_tx_lpi(tp, true);\n+\n+\treturn 0;\n+}\n+\n+static const struct phylink_mac_ops rtl_phylink_mac_ops = {\n+\t.mac_select_pcs = rtl_mac_select_pcs,\n+\t.mac_config = rtl_mac_config,\n+\t.mac_link_down = rtl_mac_link_down,\n+\t.mac_link_up = rtl_mac_link_up,\n+\t.mac_disable_tx_lpi = rtl_mac_disable_tx_lpi,\n+\t.mac_enable_tx_lpi = rtl_mac_enable_tx_lpi,\n+};\n+\n+static unsigned long rtl8169_get_lpi_caps(struct rtl8169_private *tp)\n+{\n+\tunsigned long caps = 0;\n+\n+\tif (!rtl_supports_eee(tp) || tp-\u003esfp_mode == RTL_SFP_8127_ATF)\n+\t\treturn 0;\n+\n+\tcaps |= MAC_100FD | MAC_1000FD;\n+\n+\t/* mimic behavior of r8125/r8126 vendor drivers\n+\t * RTL_GIGA_MAC_VER_61 doesn't support 2.5G eee\n+\t */\n+\tif (tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_63)\n+\t\tcaps |= MAC_2500FD;\n+\tif (tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_70)\n+\t\tcaps |= MAC_5000FD;\n+\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n+\t\tcaps |= MAC_10000FD;\n+\n+\treturn caps;\n+}\n+\n+static const struct phylink_pcs_ops r8169_pcs_ops = {\n+\t.pcs_validate = rtl8169_pcs_validate,\n+\t.pcs_get_state = rtl8169_pcs_get_state,\n+\t.pcs_config = rtl8169_pcs_config,\n+\t.pcs_an_restart = rtl8169_pcs_an_restart,\n+};\n+\n+static int rtl_init_phylink(struct rtl8169_private *tp)\n+{\n+\tstruct phylink *pl;\n+\tphy_interface_t phy_mode;\n+\n+\ttp-\u003ephylink_config.dev = \u0026tp-\u003edev-\u003edev;\n+\ttp-\u003ephylink_config.type = PHYLINK_NETDEV;\n+\ttp-\u003ephylink_config.mac_managed_pm = true;\n+\ttp-\u003ephylink_config.lpi_capabilities = rtl8169_get_lpi_caps(tp);\n+\ttp-\u003ephylink_config.mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE;\n+\n+\tswitch (tp-\u003esfp_mode) {\n+\tcase RTL_SFP_8168_AF:\n+\t\ttp-\u003epcs.ops = \u0026r8169_pcs_ops;\n+\t\ttp-\u003ephylink_config.default_an_inband = true;\n+\t\tphy_mode = PHY_INTERFACE_MODE_1000BASEX;\n+\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_1000FD;\n+\t\tbreak;\n+\tcase RTL_SFP_8127_ATF:\n+\t\ttp-\u003epcs.ops = \u0026r8169_pcs_ops;\n+\t\tphy_mode = PHY_INTERFACE_MODE_10GBASER;\n+\t\ttp-\u003ephylink_config.default_an_inband = true;\n+\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_1000FD | MAC_10000FD;\n+\t\t__set_bit(PHY_INTERFACE_MODE_10GBASER, tp-\u003ephylink_config.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX, tp-\u003ephylink_config.supported_interfaces);\n+\t\tbreak;\n+\tdefault:\n+\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_10 | MAC_100;\n+\n+\t\tif (tp-\u003emac_version == RTL_GIGA_MAC_VER_80)\n+\t\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_1000FD | MAC_2500FD |\n+\t\t\t\t\t\t\t MAC_5000FD | MAC_10000FD;\n+\t\telse if (tp-\u003emac_version == RTL_GIGA_MAC_VER_70)\n+\t\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_1000FD |\n+\t\t\t\t\t\t\t MAC_2500FD | MAC_5000FD;\n+\t\telse if (tp-\u003emac_version \u003e= RTL_GIGA_MAC_VER_61)\n+\t\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_1000FD | MAC_2500FD;\n+\t\telse\n+\t\t\tif (tp-\u003esupports_gmii)\n+\t\t\t\ttp-\u003ephylink_config.mac_capabilities |= MAC_1000FD;\n+\n+\t\tif (tp-\u003emac_version \u003c RTL_GIGA_MAC_VER_61)\n+\t\t\tphy_mode = tp-\u003esupports_gmii ? PHY_INTERFACE_MODE_GMII :\n+\t\t\t\t PHY_INTERFACE_MODE_MII;\n+\t\telse\n+\t\t\tphy_mode = PHY_INTERFACE_MODE_INTERNAL;\n+\t\tbreak;\n+\t}\n+\n+\t__set_bit(phy_mode, tp-\u003ephylink_config.supported_interfaces);\n+\tif (tp-\u003ephylink_config.lpi_capabilities)\n+\t\t__set_bit(phy_mode, tp-\u003ephylink_config.lpi_interfaces);\n+\n+\tpl = phylink_create(\u0026tp-\u003ephylink_config, tp_to_dev(tp)-\u003efwnode,\n+\t\t\t phy_mode, \u0026rtl_phylink_mac_ops);\n+\tif (IS_ERR(pl))\n+\t\treturn PTR_ERR(pl);\n+\n+\ttp-\u003ephylink = pl;\n+\n+\treturn 0;\n+}\n+\n static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n {\n \tconst struct rtl_chip_info *chip;\n@@ -5667,6 +6043,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\t\t\t ext_xid_str, xid);\n \ttp-\u003emac_version = chip-\u003emac_version;\n \ttp-\u003efw_name = chip-\u003efw_name;\n+\ttp-\u003espeed = SPEED_UNKNOWN;\n \n \t/* Disable ASPM L1 as that cause random device stop working\n \t * problems as well as full system hangs for some PCIe devices users.\n@@ -5679,12 +6056,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t}\n \ttp-\u003easpm_manageable = !rc;\n \n-\tif (rtl_is_8125(tp)) {\n-\t\tu16 data = r8168_mac_ocp_read(tp, 0xd006);\n-\n-\t\tif ((data \u0026 0xff) == 0x07)\n-\t\t\ttp-\u003esfp_mode = true;\n-\t}\n+\ttp-\u003esfp_mode = rtl_get_sfp_mode(tp);\n \n \ttp-\u003edash_type = rtl_get_dash_type(tp);\n \ttp-\u003edash_enabled = rtl_dash_is_enabled(tp);\n@@ -5788,13 +6160,23 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \n \tpci_set_drvdata(pdev, tp);\n \n-\trc = r8169_mdio_register(tp);\n+\trc = rtl_init_phylink(tp);\n \tif (rc)\n \t\treturn rc;\n \n+\tif (tp-\u003esfp_mode == RTL_SFP_NONE) {\n+\t\trc = r8169_mdio_register(tp);\n+\t\tif (rc) {\n+\t\t\tphylink_destroy(tp-\u003ephylink);\n+\t\t\treturn rc;\n+\t\t}\n+\t}\n+\n \trc = register_netdev(dev);\n-\tif (rc)\n+\tif (rc) {\n+\t\tphylink_destroy(tp-\u003ephylink);\n \t\treturn rc;\n+\t}\n \n \tif (IS_ENABLED(CONFIG_R8169_LEDS)) {\n \t\tif (rtl_is_8125(tp))\n@@ -5817,6 +6199,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)\n \t\trtl8168_driver_start(tp);\n \t}\n \n+\tif (rtl_is_8116af(tp))\n+\t\trtl_lowpower_hidden_functions(tp-\u003epci_dev);\n+\n \tif (pci_dev_run_wake(pdev))\n \t\tpm_runtime_put_sync(\u0026pdev-\u003edev);\n \ndiff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c\nindex 59dfe35afa54fc..9e9cd79301d66c 100644\n--- a/drivers/net/phy/phylink.c\n+++ b/drivers/net/phy/phylink.c\n@@ -1828,6 +1828,93 @@ int phylink_set_fixed_link(struct phylink *pl,\n }\n EXPORT_SYMBOL_GPL(phylink_set_fixed_link);\n \n+/**\n+ * phylink_update_mac_pause_capabilities() - Dynamically update MAC pause\n+ * @pl: a pointer to a \u0026struct phylink returned from phylink_create()\n+ * @mac_pause: the new MAC pause capabilities mask\n+ *\n+ * This function allows a MAC driver to dynamically change its pause state,\n+ * such as losing/gaining Pause frame support based on MTU size.\n+ * It recalculates supported link modes and triggers renegotiation if needed.\n+ */\n+void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause)\n+{\n+\tstruct phylink_link_state *config = \u0026pl-\u003elink_config;\n+\tunsigned long old_pause, caps_added, caps_removed;\n+\tbool pause_adv, asym_adv;\n+\n+\tASSERT_RTNL();\n+\n+\tif (mac_pause \u0026 ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE)) {\n+\t\tphylink_err(pl, \"Attempted to dynamically change non-pause MAC capabilities\\n\");\n+\t\treturn;\n+\t}\n+\n+\told_pause = pl-\u003econfig-\u003emac_capabilities \u0026 (MAC_SYM_PAUSE | MAC_ASYM_PAUSE);\n+\tcaps_added = mac_pause \u0026 ~old_pause;\n+\tcaps_removed = old_pause \u0026 ~mac_pause;\n+\n+\tif (!caps_added \u0026\u0026 !caps_removed)\n+\t\treturn;\n+\n+\tmutex_lock(\u0026pl-\u003estate_mutex);\n+\n+\tpl-\u003econfig-\u003emac_capabilities \u0026= ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);\n+\tpl-\u003econfig-\u003emac_capabilities |= mac_pause;\n+\n+\tif (caps_removed \u0026 MAC_SYM_PAUSE)\n+\t\tlinkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, pl-\u003esupported);\n+\tif (caps_removed \u0026 MAC_ASYM_PAUSE)\n+\t\tlinkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, pl-\u003esupported);\n+\n+\tlinkmode_and(config-\u003eadvertising, config-\u003eadvertising, pl-\u003esupported);\n+\n+\tif (caps_added \u0026 MAC_SYM_PAUSE) {\n+\t\tlinkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, pl-\u003esupported);\n+\t\tif (pl-\u003ephydev \u0026\u0026 !phylink_test(pl-\u003ephydev-\u003esupported, Pause))\n+\t\t\tlinkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, pl-\u003esupported);\n+\t}\n+\tif (caps_added \u0026 MAC_ASYM_PAUSE) {\n+\t\tlinkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, pl-\u003esupported);\n+\t\tif (pl-\u003ephydev \u0026\u0026 !phylink_test(pl-\u003ephydev-\u003esupported, Asym_Pause))\n+\t\t\tlinkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, pl-\u003esupported);\n+\t}\n+\n+\tlinkmode_and(config-\u003eadvertising, config-\u003eadvertising, pl-\u003esupported);\n+\n+\tif (config-\u003epause \u0026 MLO_PAUSE_AN) {\n+\t\tif (phylink_test(pl-\u003esupported, Pause) \u0026\u0026\n+\t\t (config-\u003epause \u0026 MLO_PAUSE_RX) \u0026\u0026 (config-\u003epause \u0026 MLO_PAUSE_TX))\n+\t\t\tlinkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, config-\u003eadvertising);\n+\n+\t\tif (phylink_test(pl-\u003esupported, Asym_Pause) \u0026\u0026\n+\t\t ((config-\u003epause \u0026 MLO_PAUSE_RX) ^ (config-\u003epause \u0026 MLO_PAUSE_TX)))\n+\t\t\tlinkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, config-\u003eadvertising);\n+\t}\n+\n+\tif (!pl-\u003ephydev)\n+\t\tphylink_change_inband_advert(pl);\n+\n+\tmutex_unlock(\u0026pl-\u003estate_mutex);\n+\n+\tif (pl-\u003ephydev) {\n+\t\tpause_adv = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,\n+\t\t\t\t\t config-\u003eadvertising);\n+\t\tasym_adv = linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,\n+\t\t\t\t\t config-\u003eadvertising);\n+\n+\t\tmutex_lock(\u0026pl-\u003ephydev-\u003elock);\n+\t\tlinkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,\n+\t\t\t\t pl-\u003ephydev-\u003eadvertising, pause_adv);\n+\t\tlinkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,\n+\t\t\t\t pl-\u003ephydev-\u003eadvertising, asym_adv);\n+\t\tmutex_unlock(\u0026pl-\u003ephydev-\u003elock);\n+\n+\t\tphy_start_aneg(pl-\u003ephydev);\n+\t}\n+}\n+EXPORT_SYMBOL_GPL(phylink_update_mac_pause_capabilities);\n+\n /**\n * phylink_create() - create a phylink instance\n * @config: a pointer to the target \u0026struct phylink_config\ndiff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c\nindex b65d0f5fa1a014..4721ba071cbbe4 100644\n--- a/drivers/net/phy/realtek/realtek_main.c\n+++ b/drivers/net/phy/realtek/realtek_main.c\n@@ -17,7 +17,6 @@\n #include \u003clinux/delay.h\u003e\n #include \u003clinux/clk.h\u003e\n #include \u003clinux/string_choices.h\u003e\n-#include \u003cnet/phy/realtek_phy.h\u003e\n \n #include \"../phylib.h\"\n #include \"realtek.h\"\n@@ -2646,45 +2645,6 @@ static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)\n \treturn IRQ_HANDLED;\n }\n \n-static int rtlgen_sfp_get_features(struct phy_device *phydev)\n-{\n-\tlinkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,\n-\t\t\t phydev-\u003esupported);\n-\n-\t/* set default mode */\n-\tphydev-\u003espeed = SPEED_10000;\n-\tphydev-\u003eduplex = DUPLEX_FULL;\n-\n-\tphydev-\u003eport = PORT_FIBRE;\n-\n-\treturn 0;\n-}\n-\n-static int rtlgen_sfp_read_status(struct phy_device *phydev)\n-{\n-\tint val, err;\n-\n-\terr = genphy_update_link(phydev);\n-\tif (err)\n-\t\treturn err;\n-\n-\tif (!phydev-\u003elink)\n-\t\treturn 0;\n-\n-\tval = phy_read(phydev, RTL_PHYSR);\n-\tif (val \u003c 0)\n-\t\treturn val;\n-\n-\trtlgen_decode_physr(phydev, val);\n-\n-\treturn 0;\n-}\n-\n-static int rtlgen_sfp_config_aneg(struct phy_device *phydev)\n-{\n-\treturn 0;\n-}\n-\n static struct phy_driver realtek_drvs[] = {\n \t{\n \t\tPHY_ID_MATCH_EXACT(0x00008201),\n@@ -2934,20 +2894,6 @@ static struct phy_driver realtek_drvs[] = {\n \t\t.write_page\t= rtl821x_write_page,\n \t\t.read_mmd\t= rtl822x_read_mmd,\n \t\t.write_mmd\t= rtl822x_write_mmd,\n-\t}, {\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_RTL_DUMMY_SFP),\n-\t\t.name\t\t= \"Realtek SFP PHY Mode\",\n-\t\t.flags\t\t= PHY_IS_INTERNAL,\n-\t\t.probe\t\t= rtl822x_probe,\n-\t\t.get_features\t= rtlgen_sfp_get_features,\n-\t\t.config_aneg\t= rtlgen_sfp_config_aneg,\n-\t\t.read_status\t= rtlgen_sfp_read_status,\n-\t\t.suspend\t= genphy_suspend,\n-\t\t.resume\t\t= rtlgen_resume,\n-\t\t.read_page\t= rtl821x_read_page,\n-\t\t.write_page\t= rtl821x_write_page,\n-\t\t.read_mmd\t= rtl822x_read_mmd,\n-\t\t.write_mmd\t= rtl822x_write_mmd,\n \t}, {\n \t\tPHY_ID_MATCH_EXACT(0x001ccad0),\n \t\t.name\t\t= \"RTL8224 2.5Gbps PHY\",\ndiff --git a/include/linux/phylink.h b/include/linux/phylink.h\nindex 2bc0db3d52ac8d..e3c7822100aba6 100644\n--- a/include/linux/phylink.h\n+++ b/include/linux/phylink.h\n@@ -842,4 +842,6 @@ void phylink_replay_link_begin(struct phylink *pl);\n \n void phylink_replay_link_end(struct phylink *pl);\n \n+void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause);\n+\n #endif\ndiff --git a/include/net/phy/realtek_phy.h b/include/net/phy/realtek_phy.h\ndeleted file mode 100644\nindex d683bc1b0659cd..00000000000000\n--- a/include/net/phy/realtek_phy.h\n+++ /dev/null\n@@ -1,7 +0,0 @@\n-/* SPDX-License-Identifier: GPL-2.0 */\n-#ifndef _REALTEK_PHY_H\n-#define _REALTEK_PHY_H\n-\n-#define\tPHY_ID_RTL_DUMMY_SFP\t0x001ccbff\n-\n-#endif /* _REALTEK_PHY_H */\n"
} |
| 2/1 | 2026/07/10 05:33 | agent | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"R8169"
],
"FocusSymbols": [
"phylink_update_mac_pause_capabilities",
"rtl8169_change_mtu",
"rtl_init_phylink",
"rtl8169_pcs_config",
"rtl8169_pcs_get_state",
"rtl_mac_link_up",
"rtl_mac_link_down",
"rtl_mac_select_pcs",
"rtl_mac_disable_tx_lpi",
"rtl_mac_enable_tx_lpi",
"rtl8169_sds_read",
"r8127_sds_read",
"r8127_sds_write",
"r8127_sds_modify",
"r8127_sfp_init_1g",
"r8127_sfp_init_10g",
"rtl_get_sfp_mode",
"rtl_is_8116af",
"rtl_lowpower_hidden_functions",
"rtl8169_get_link_ksettings",
"rtl8169_set_link_ksettings",
"rtl8169_nway_reset",
"rtl8169_ioctl"
],
"Reasoning": "The patch converts the Realtek r8169 driver to use the phylink API and introduces a new phylink function to dynamically update MAC pause capabilities. These are functional changes to reachable core networking and driver code.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit 76a29616490114f3862fa4207a87afc66786d9be
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Jul 10 05:33:57 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index 9b0f4f9631dbaa..5818a9a500a86d 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -86,8 +86,8 @@ config R8169
depends on PCI
select FW_LOADER
select CRC32
- select PHYLIB
select REALTEK_PHY
+ select PHYLINK
help
Say Y here if you have a Realtek Ethernet adapter belonging to
the following families:
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index ec4fc21fa21fb0..c0b0c2bc5a4855 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -26,12 +26,12 @@
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/bitfield.h>
+#include <linux/phylink.h>
#include <linux/prefetch.h>
#include <linux/ipv6.h>
#include <linux/unaligned.h>
#include <net/ip6_checksum.h>
#include <net/netdev_queues.h>
-#include <net/phy/realtek_phy.h>
#include "r8169.h"
#include "r8169_firmware.h"
@@ -96,6 +96,25 @@
#define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
#define JUMBO_16K (SZ_16K - VLAN_ETH_HLEN - ETH_FCS_LEN)
+#define R8127_SDS_CMD 0x2348
+#define R8127_SDS_ADDR 0x234a
+#define R8127_SDS_DATA_IN 0x234c
+#define R8127_SDS_DATA_OUT 0x234e
+#define R8127_SDS_CMD_EXEC BIT(0)
+#define R8127_SDS_CMD_WE BIT(1)
+#define OCP_SDS_ADDR_REG 0xeb10
+#define OCP_SDS_CMD_REG 0xeb0e
+#define OCP_SDS_DATA_REG 0xeb14
+#define SDS_CMD_READ 0x0001
+#define RTL_SDS_C22_BASE 0x40
+#define RTL_SDS_C45_BASE 0x0080
+#define RTL_PKG_DETECT 0xdc00
+#define RTL_PKG_DETECT_MASK 0x0078
+#define RTL_PKG_DETECT_8116AF 0x0030
+#define RTL_INT_HW_ID 0xd006
+#define RTL_INT_HW_ID_MASK 0x00ff
+#define RTL_INT_HW_ID_8116AF 0x0000
+
static const struct rtl_chip_info {
u32 mask;
u32 val;
@@ -334,11 +353,13 @@ enum rtl_registers {
ALDPS_LTR = 0xe0a2,
LTR_OBFF_LOCK = 0xe032,
LTR_SNOOP = 0xe034,
+ SEND_LTR_MSG = 0xe038,
#define ALDPS_LTR_EN BIT(0)
#define LTR_OBFF_LOCK_EN BIT(0)
#define LINK_SPEED_CHANGE_EN BIT(14)
#define LTR_SNOOP_EN GENMASK(15, 14)
+#define LTR_MSG_EN BIT(0)
};
enum rtl8168_8101_registers {
@@ -728,6 +749,12 @@ enum rtl_dash_type {
RTL_DASH_25_BP,
};
+enum rtl_sfp_mode {
+ RTL_SFP_NONE,
+ RTL_SFP_8168_AF,
+ RTL_SFP_8127_ATF,
+};
+
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev;
@@ -736,6 +763,7 @@ struct rtl8169_private {
struct napi_struct napi;
enum mac_version mac_version;
enum rtl_dash_type dash_type;
+ enum rtl_sfp_mode sfp_mode;
u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
u32 dirty_tx;
@@ -750,6 +778,7 @@ struct rtl8169_private {
u32 irq_mask;
int irq;
struct clk *clk;
+ int speed;
struct {
DECLARE_BITMAP(flags, RTL_FLAG_MAX);
@@ -762,7 +791,6 @@ struct rtl8169_private {
unsigned supports_gmii:1;
unsigned aspm_manageable:1;
unsigned dash_enabled:1;
- bool sfp_mode:1;
dma_addr_t counters_phys_addr;
struct rtl8169_counters *counters;
struct rtl8169_tc_offsets tc_offset;
@@ -774,6 +802,9 @@ struct rtl8169_private {
struct r8169_led_classdev *leds;
u32 ocp_base;
+ struct phylink *phylink;
+ struct phylink_config phylink_config;
+ struct phylink_pcs pcs;
};
typedef void (*rtl_generic_fct)(struct rtl8169_private *tp);
@@ -1128,10 +1159,6 @@ static int r8168_phy_ocp_read(struct rtl8169_private *tp, u32 reg)
if (rtl_ocp_reg_failure(reg))
return 0;
- /* Return dummy MII_PHYSID2 in SFP mode to match SFP PHY driver */
- if (tp->sfp_mode && reg == (OCP_STD_PHY_BASE + 2 * MII_PHYSID2))
- return PHY_ID_RTL_DUMMY_SFP & 0xffff;
-
RTL_W32(tp, GPHY_OCP, reg << 15);
return rtl_loop_wait_high(tp, &rtl_ocp_gphy_cond, 25, 10) ?
@@ -1199,6 +1226,73 @@ static void r8127_sfp_sds_phy_reset(struct rtl8169_private *tp)
usleep_range(10, 20);
}
+DECLARE_RTL_COND(r8127_sds_cmd_cond)
+{
+ return RTL_R16(tp, R8127_SDS_CMD) & R8127_SDS_CMD_EXEC;
+}
+
+static int r8127_sds_read(struct rtl8169_private *tp, u16 index, u16 page, u16 reg)
+{
+ u16 addr = (index << 11) | (page << 5) | reg;
+
+ RTL_W16(tp, R8127_SDS_ADDR, addr);
+ RTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_EXEC);
+
+ if (rtl_loop_wait_low(tp, &r8127_sds_cmd_cond, 10, 100))
+ return RTL_R16(tp, R8127_SDS_DATA_OUT);
+
+ return -ETIMEDOUT;
+}
+
+static int r8127_sds_write(struct rtl8169_private *tp, u16 index, u16 page,
+ u16 reg, u16 val)
+{
+ u16 addr = (index << 11) | (page << 5) | reg;
+
+ RTL_W16(tp, R8127_SDS_DATA_IN, val);
+ RTL_W16(tp, R8127_SDS_ADDR, addr);
+ RTL_W16(tp, R8127_SDS_CMD, R8127_SDS_CMD_EXEC | R8127_SDS_CMD_WE);
+
+ if (rtl_loop_wait_low(tp, &r8127_sds_cmd_cond, 10, 100))
+ return 0;
+
+ return -ETIMEDOUT;
+}
+
+static void r8127_sds_modify(struct rtl8169_private *tp, u16 index, u16 page,
+ u16 reg, u16 clearmask, u16 setmask)
+{
+ int val = r8127_sds_read(tp, index, page, reg);
+
+ if (val < 0)
+ return;
+
+ val = (val & ~clearmask) | setmask;
+ r8127_sds_write(tp, index, page, reg, val);
+}
+
+static void r8127_sfp_init_1g(struct rtl8169_private *tp)
+{
+ int val;
+
+ r8127_sfp_sds_phy_reset(tp);
+
+ r8127_sds_modify(tp, 0, 1, 31, 0, BIT(3));
+ r8127_sds_modify(tp, 0, 2, 0, BIT(13) | BIT(12) | BIT(6), BIT(12) | BIT(6));
+ r8127_sds_modify(tp, 0, 0, 4, 0, BIT(2));
+
+ RTL_W16(tp, 0x233a, 0x8004);
+ RTL_W16(tp, 0x233e, (RTL_R16(tp, 0x233e) & ~0x3003) | 0x0002);
+
+ r8168_phy_ocp_write(tp, 0xc40a, 0x0000);
+ r8168_phy_ocp_write(tp, 0xc466, 0x0000);
+ r8168_phy_ocp_write(tp, 0xc808, 0x0000);
+ r8168_phy_ocp_write(tp, 0xc80a, 0x0000);
+
+ val = r8168_phy_ocp_read(tp, 0xc804);
+ r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c);
+}
+
static void r8127_sfp_init_10g(struct rtl8169_private *tp)
{
int val;
@@ -1217,12 +1311,6 @@ static void r8127_sfp_init_10g(struct rtl8169_private *tp)
r8168_phy_ocp_write(tp, 0xc804, (val & ~0x000f) | 0x000c);
}
-static void rtl_sfp_init(struct rtl8169_private *tp)
-{
- if (tp->mac_version == RTL_GIGA_MAC_VER_80)
- r8127_sfp_init_10g(tp);
-}
-
static void rtl_sfp_reset(struct rtl8169_private *tp)
{
if (tp->mac_version == RTL_GIGA_MAC_VER_80)
@@ -1283,6 +1371,15 @@ static void mac_mcu_write(struct rtl8169_private *tp, int reg, int value)
r8168_mac_ocp_write(tp, tp->ocp_base + reg, value);
}
+static bool rtl_is_8116af(struct rtl8169_private *tp)
+{
+ return tp->mac_version == RTL_GIGA_MAC_VER_52 &&
+ (r8168_mac_ocp_read(tp, RTL_PKG_DETECT) & RTL_PKG_DETECT_MASK) ==
+ RTL_PKG_DETECT_8116AF &&
+ (r8168_mac_ocp_read(tp, RTL_INT_HW_ID) & RTL_INT_HW_ID_MASK) ==
+ RTL_INT_HW_ID_8116AF;
+}
+
static int mac_mcu_read(struct rtl8169_private *tp, int reg)
{
return r8168_mac_ocp_read(tp, tp->ocp_base + reg);
@@ -1578,6 +1675,20 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp)
}
}
+static enum rtl_sfp_mode rtl_get_sfp_mode(struct rtl8169_private *tp)
+{
+ if (rtl_is_8125(tp)) {
+ u16 data = r8168_mac_ocp_read(tp, RTL_INT_HW_ID);
+
+ if ((data & 0xff) == 0x07)
+ return RTL_SFP_8127_ATF;
+ } else if (rtl_is_8116af(tp)) {
+ return RTL_SFP_8168_AF;
+ }
+
+ return RTL_SFP_NONE;
+}
+
static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
@@ -1673,16 +1784,14 @@ static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp)
rtl_pci_commit(tp);
}
-static void rtl_link_chg_patch(struct rtl8169_private *tp)
+static void rtl_link_chg_patch(struct rtl8169_private *tp, int speed)
{
- struct phy_device *phydev = tp->phydev;
-
if (tp->mac_version == RTL_GIGA_MAC_VER_34 ||
tp->mac_version == RTL_GIGA_MAC_VER_38) {
- if (phydev->speed == SPEED_1000) {
+ if (speed == SPEED_1000) {
rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011);
rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);
- } else if (phydev->speed == SPEED_100) {
+ } else if (speed == SPEED_100) {
rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x0000001f);
rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);
} else {
@@ -1692,7 +1801,7 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)
rtl_reset_packet_filter(tp);
} else if (tp->mac_version == RTL_GIGA_MAC_VER_35 ||
tp->mac_version == RTL_GIGA_MAC_VER_36) {
- if (phydev->speed == SPEED_1000) {
+ if (speed == SPEED_1000) {
rtl_eri_write(tp, 0x1bc, ERIAR_MASK_1111, 0x00000011);
rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x00000005);
} else {
@@ -1700,7 +1809,7 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)
rtl_eri_write(tp, 0x1dc, ERIAR_MASK_1111, 0x0000003f);
}
} else if (tp->mac_version == RTL_GIGA_MAC_VER_37) {
- if (phydev->speed == SPEED_10) {
+ if (speed == SPEED_10) {
rtl_eri_write(tp, 0x1d0, ERIAR_MASK_0011, 0x4d02);
rtl_eri_write(tp, 0x1dc, ERIAR_MASK_0011, 0x0060a);
} else {
@@ -2074,11 +2183,11 @@ rtl_coalesce_info(struct rtl8169_private *tp)
ci = rtl_coalesce_info_8168_8136;
/* if speed is unknown assume highest one */
- if (tp->phydev->speed == SPEED_UNKNOWN)
+ if (tp->speed == SPEED_UNKNOWN)
return ci;
for (; ci->speed; ci++) {
- if (tp->phydev->speed == ci->speed)
+ if (tp->speed == ci->speed)
return ci;
}
@@ -2236,7 +2345,7 @@ static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp)
static unsigned int r8169_get_tx_lpi_timer_us(struct rtl8169_private *tp)
{
- unsigned int speed = tp->phydev->speed;
+ unsigned int speed = tp->speed;
unsigned int timer = tp->tx_lpi_timer;
if (!timer || speed == SPEED_UNKNOWN)
@@ -2254,7 +2363,7 @@ static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data)
if (!rtl_supports_eee(tp))
return -EOPNOTSUPP;
- ret = phy_ethtool_get_eee(tp->phydev, data);
+ ret = phylink_ethtool_get_eee(tp->phylink, data);
if (ret)
return ret;
@@ -2270,7 +2379,7 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data)
if (!rtl_supports_eee(tp))
return -EOPNOTSUPP;
- return phy_ethtool_set_eee(tp->phydev, data);
+ return phylink_ethtool_set_eee(tp->phylink, data);
}
static void rtl8169_get_ringparam(struct net_device *dev,
@@ -2301,13 +2410,8 @@ static void rtl8169_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *data)
{
struct rtl8169_private *tp = netdev_priv(dev);
- bool tx_pause, rx_pause;
-
- phy_get_pause(tp->phydev, &tx_pause, &rx_pause);
- data->autoneg = tp->phydev->autoneg;
- data->tx_pause = tx_pause ? 1 : 0;
- data->rx_pause = rx_pause ? 1 : 0;
+ phylink_ethtool_get_pauseparam(tp->phylink, data);
}
static int rtl8169_set_pauseparam(struct net_device *dev,
@@ -2318,9 +2422,7 @@ static int rtl8169_set_pauseparam(struct net_device *dev,
if (dev->mtu > ETH_DATA_LEN)
return -EOPNOTSUPP;
- phy_set_asym_pause(tp->phydev, data->rx_pause, data->tx_pause);
-
- return 0;
+ return phylink_ethtool_set_pauseparam(tp->phylink, data);
}
static void rtl8169_get_eth_mac_stats(struct net_device *dev,
@@ -2386,34 +2488,27 @@ static void rtl8169_get_eth_ctrl_stats(struct net_device *dev,
le32_to_cpu(tp->counters->rx_unknown_opcode);
}
-static int rtl8169_set_link_ksettings(struct net_device *ndev,
- const struct ethtool_link_ksettings *cmd)
+static int rtl8169_get_link_ksettings(struct net_device *ndev,
+ struct ethtool_link_ksettings *cmd)
{
struct rtl8169_private *tp = netdev_priv(ndev);
- struct phy_device *phydev = tp->phydev;
- int duplex = cmd->base.duplex;
- int speed = cmd->base.speed;
-
- if (!tp->sfp_mode)
- return phy_ethtool_ksettings_set(phydev, cmd);
-
- if (cmd->base.autoneg != AUTONEG_DISABLE)
- return -EINVAL;
-
- if (!phy_check_valid(speed, duplex, phydev->supported))
- return -EINVAL;
- mutex_lock(&phydev->lock);
+ return phylink_ethtool_ksettings_get(tp->phylink, cmd);
+}
- phydev->autoneg = AUTONEG_DISABLE;
- phydev->speed = speed;
- phydev->duplex = duplex;
+static int rtl8169_set_link_ksettings(struct net_device *ndev,
+ const struct ethtool_link_ksettings *cmd)
+{
+ struct rtl8169_private *tp = netdev_priv(ndev);
- rtl_sfp_init(tp);
+ return phylink_ethtool_ksettings_set(tp->phylink, cmd);
+}
- mutex_unlock(&phydev->lock);
+static int rtl8169_nway_reset(struct net_device *dev)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
- return 0;
+ return phylink_ethtool_nway_reset(tp->phylink);
}
static const struct ethtool_ops rtl8169_ethtool_ops = {
@@ -2431,10 +2526,10 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_sset_count = rtl8169_get_sset_count,
.get_ethtool_stats = rtl8169_get_ethtool_stats,
.get_ts_info = ethtool_op_get_ts_info,
- .nway_reset = phy_ethtool_nway_reset,
+ .nway_reset = rtl8169_nway_reset,
.get_eee = rtl8169_get_eee,
.set_eee = rtl8169_set_eee,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
+ .get_link_ksettings = rtl8169_get_link_ksettings,
.set_link_ksettings = rtl8169_set_link_ksettings,
.get_ringparam = rtl8169_get_ringparam,
.get_pause_stats = rtl8169_get_pause_stats,
@@ -2499,9 +2594,10 @@ void r8169_apply_firmware(struct rtl8169_private *tp)
tp->ocp_base = OCP_STD_PHY_BASE;
/* PHY soft reset may still be in progress */
- phy_read_poll_timeout(tp->phydev, MII_BMCR, val,
- !(val & BMCR_RESET),
- 50000, 600000, true);
+ if (tp->phydev)
+ phy_read_poll_timeout(tp->phydev, MII_BMCR, val,
+ !(val & BMCR_RESET),
+ 50000, 600000, true);
}
}
@@ -2538,6 +2634,8 @@ static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag)
static void rtl8169_init_phy(struct rtl8169_private *tp)
{
+ phy_init_hw(tp->phydev);
+ phy_resume(tp->phydev);
r8169_hw_phy_config(tp, tp->phydev, tp->mac_version);
if (tp->mac_version <= RTL_GIGA_MAC_VER_06) {
@@ -2552,9 +2650,6 @@ static void rtl8169_init_phy(struct rtl8169_private *tp)
tp->pci_dev->subsystem_device == 0xe000)
phy_write_paged(tp->phydev, 0x0001, 0x10, 0xf01b);
- if (tp->sfp_mode)
- rtl_sfp_init(tp);
-
/* We may have called phy_speed_down before */
phy_speed_up(tp->phydev);
@@ -2657,15 +2752,6 @@ static void rtl_jumbo_config(struct rtl8169_private *tp)
if (pci_is_pcie(tp->pci_dev) && tp->supports_gmii)
pcie_set_readrq(tp->pci_dev, readrq);
-
- /* Chip doesn't support pause in jumbo mode */
- if (jumbo) {
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT,
- tp->phydev->advertising);
- linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
- tp->phydev->advertising);
- phy_start_aneg(tp->phydev);
- }
}
DECLARE_RTL_COND(rtl_chipcmd_cond)
@@ -2780,7 +2866,7 @@ static void rtl_prepare_power_down(struct rtl8169_private *tp)
rtl_ephy_write(tp, 0x19, 0xff64);
if (device_may_wakeup(tp_to_dev(tp))) {
- phy_speed_down(tp->phydev, false);
+ phylink_speed_down(tp->phylink, false);
rtl_wol_enable_rx(tp);
}
}
@@ -2832,6 +2918,16 @@ static void rtl8169_set_magic_reg(struct rtl8169_private *tp)
RTL_W32(tp, 0x7c, val);
}
+static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+
+ if (!netif_running(dev))
+ return -ENODEV;
+
+ return phylink_mii_ioctl(tp->phylink, ifr, cmd);
+}
+
static void rtl_set_rx_mode(struct net_device *dev)
{
u32 rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast;
@@ -3098,8 +3194,23 @@ static void rtl_enable_ltr(struct rtl8169_private *tp)
r8168_mac_ocp_write(tp, 0xcdf2, 0x9003);
r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN);
break;
- case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
case RTL_GIGA_MAC_VER_52:
+ r8168_mac_ocp_write(tp, 0xcdd0, 0x9003);
+ r8168_mac_ocp_modify(tp, LTR_SNOOP, 0x0000, LTR_SNOOP_EN);
+ r8168_mac_ocp_write(tp, 0xe02c, 0x1880);
+ r8168_mac_ocp_write(tp, 0xe02e, 0x4880);
+ r8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);
+ r8168_mac_ocp_write(tp, 0xcdd8, 0x9003);
+ r8168_mac_ocp_write(tp, 0xcdda, 0x9003);
+ r8168_mac_ocp_write(tp, 0xcddc, 0x9003);
+ r8168_mac_ocp_write(tp, 0xcdd2, 0x883c);
+ r8168_mac_ocp_write(tp, 0xcdd4, 0x8c12);
+ r8168_mac_ocp_write(tp, 0xcdd6, 0x9003);
+ r8168_mac_ocp_write(tp, 0xe0a6, 0x9003);
+ r8168_mac_ocp_write(tp, 0xe0a8, 0x9003);
+ r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0000, LINK_SPEED_CHANGE_EN);
+ break;
+ case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
r8168_mac_ocp_modify(tp, ALDPS_LTR, 0x0000, ALDPS_LTR_EN);
RTL_W8(tp, COMBO_LTR_EXTEND, RTL_R8(tp, COMBO_LTR_EXTEND) | COMBO_LTR_EXTEND_EN);
fallthrough;
@@ -3119,6 +3230,7 @@ static void rtl_enable_ltr(struct rtl8169_private *tp)
}
/* chip can trigger LTR */
r8168_mac_ocp_modify(tp, LTR_OBFF_LOCK, 0x0003, LTR_OBFF_LOCK_EN);
+ r8168_mac_ocp_modify(tp, SEND_LTR_MSG, 0x0000, LTR_MSG_EN);
}
static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
@@ -3152,6 +3264,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
rtl_enable_ltr(tp);
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
+ case RTL_GIGA_MAC_VER_52:
case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
/* reset ephy tx/rx disable timer */
r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0);
@@ -3164,6 +3277,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable)
} else {
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48:
+ case RTL_GIGA_MAC_VER_52:
case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_LAST:
r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0);
break;
@@ -3657,6 +3771,42 @@ static void rtl_hw_start_8168ep_3(struct rtl8169_private *tp)
r8168_mac_ocp_modify(tp, 0xe860, 0x0000, 0x0080);
}
+static void rtl_lowpower_hidden_functions(struct pci_dev *pdev)
+{
+ unsigned int slot = PCI_SLOT(pdev->devfn);
+ struct pci_bus *bus = pdev->bus;
+ int func, pos;
+ u16 val;
+
+ for (func = 2; func < 8; func++) {
+ unsigned int devfn = PCI_DEVFN(slot, func);
+
+ pos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_EXP);
+ if (pos) {
+ pci_bus_read_config_word(bus, devfn, pos + PCI_EXP_LNKCTL, &val);
+
+ if (PCI_POSSIBLE_ERROR(val))
+ continue;
+
+ val |= (PCI_EXP_LNKCTL_ASPMC | PCI_EXP_LNKCTL_CLKREQ_EN);
+ pci_bus_write_config_word(bus, devfn, pos + PCI_EXP_LNKCTL, val);
+ }
+
+ pos = pci_bus_find_capability(bus, devfn, PCI_CAP_ID_PM);
+ if (pos) {
+ pci_bus_read_config_word(bus, devfn, pos + PCI_PM_CTRL, &val);
+
+ if (PCI_POSSIBLE_ERROR(val))
+ continue;
+
+ val &= ~PCI_PM_CTRL_STATE_MASK;
+ val |= PCI_D3hot;
+ val |= PCI_PM_CTRL_PME_STATUS;
+ pci_bus_write_config_word(bus, devfn, pos + PCI_PM_CTRL, val);
+ }
+ }
+}
+
static void rtl_hw_start_8117(struct rtl8169_private *tp)
{
static const struct ephy_info e_info_8117[] = {
@@ -3693,12 +3843,14 @@ static void rtl_hw_start_8117(struct rtl8169_private *tp)
rtl_pcie_state_l2l3_disable(tp);
- rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff;
- if (rg_saw_cnt > 0) {
- u16 sw_cnt_1ms_ini;
+ if (tp->phydev) {
+ rg_saw_cnt = phy_read_paged(tp->phydev, 0x0c42, 0x13) & 0x3fff;
+ if (rg_saw_cnt > 0) {
+ u16 sw_cnt_1ms_ini;
- sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff;
- r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);
+ sw_cnt_1ms_ini = (16000000 / rg_saw_cnt) & 0x0fff;
+ r8168_mac_ocp_modify(tp, 0xd412, 0x0fff, sw_cnt_1ms_ini);
+ }
}
r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0000);
@@ -4139,12 +4291,25 @@ static void rtl_hw_start(struct rtl8169_private *tp)
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
{
struct rtl8169_private *tp = netdev_priv(dev);
+ bool jumbo_before = dev->mtu > ETH_DATA_LEN;
+ bool jumbo_after = new_mtu > ETH_DATA_LEN;
WRITE_ONCE(dev->mtu, new_mtu);
netdev_update_features(dev);
rtl_jumbo_config(tp);
rtl_set_eee_txidle_timer(tp);
+ if (jumbo_before != jumbo_after) {
+ unsigned long caps = tp->phylink_config.mac_capabilities;
+
+ if (jumbo_after)
+ caps &= ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
+ else
+ caps |= (MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
+
+ phylink_update_mac_pause_capabilities(tp->phylink, caps);
+ }
+
return 0;
}
@@ -4869,8 +5034,13 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
goto out;
}
- if (status & LinkChg)
- phy_mac_interrupt(tp->phydev);
+ if (status & LinkChg) {
+ if (tp->phydev)
+ phy_mac_interrupt(tp->phydev);
+ else if (tp->sfp_mode)
+ phylink_mac_change(tp->phylink,
+ !!(RTL_R8(tp, PHYstatus) & LinkStatus));
+ }
rtl_irq_disable(tp);
napi_schedule(&tp->napi);
@@ -4930,9 +5100,6 @@ static int rtl8169_poll(struct napi_struct *napi, int budget)
static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)
{
- if (!rtl_supports_eee(tp))
- return;
-
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_52:
/* Adjust EEE LED frequency */
@@ -4963,40 +5130,15 @@ static void rtl_enable_tx_lpi(struct rtl8169_private *tp, bool enable)
}
}
-static void r8169_phylink_handler(struct net_device *ndev)
-{
- struct rtl8169_private *tp = netdev_priv(ndev);
- struct device *d = tp_to_dev(tp);
-
- if (netif_carrier_ok(ndev)) {
- rtl_link_chg_patch(tp);
- rtl_enable_tx_lpi(tp, tp->phydev->enable_tx_lpi);
- pm_request_resume(d);
- } else {
- pm_runtime_idle(d);
- }
-
- phy_print_status(tp->phydev);
-}
-
static int r8169_phy_connect(struct rtl8169_private *tp)
{
- struct phy_device *phydev = tp->phydev;
- phy_interface_t phy_mode;
int ret;
- phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII :
- PHY_INTERFACE_MODE_MII;
-
- ret = phy_connect_direct(tp->dev, phydev, r8169_phylink_handler,
- phy_mode);
- if (ret)
+ ret = phylink_connect_phy(tp->phylink, tp->phydev);
+ if (ret) {
+ netdev_err(tp->dev, "failed to connect phy\n");
return ret;
-
- if (!tp->supports_gmii)
- phy_set_max_speed(phydev, SPEED_100);
-
- phy_attached_info(phydev);
+ }
return 0;
}
@@ -5007,10 +5149,8 @@ static void rtl8169_down(struct rtl8169_private *tp)
/* Clear all task flags */
bitmap_zero(tp->wk.flags, RTL_FLAG_MAX);
- phy_stop(tp->phydev);
-
/* Reset SerDes PHY to bring down fiber link */
- if (tp->sfp_mode)
+ if (tp->sfp_mode == RTL_SFP_8127_ATF)
rtl_sfp_reset(tp);
rtl8169_update_counters(tp);
@@ -5032,14 +5172,12 @@ static void rtl8169_up(struct rtl8169_private *tp)
rtl8168_driver_start(tp);
pci_set_master(tp->pci_dev);
- phy_init_hw(tp->phydev);
- phy_resume(tp->phydev);
- rtl8169_init_phy(tp);
+ if (tp->phydev)
+ rtl8169_init_phy(tp);
+
napi_enable(&tp->napi);
enable_work(&tp->wk.work);
rtl_reset_work(tp);
-
- phy_start(tp->phydev);
}
static int rtl8169_close(struct net_device *dev)
@@ -5049,13 +5187,14 @@ static int rtl8169_close(struct net_device *dev)
pm_runtime_get_sync(&pdev->dev);
+ phylink_stop(tp->phylink);
netif_stop_queue(dev);
rtl8169_down(tp);
rtl8169_rx_clear(tp);
free_irq(tp->irq, tp);
- phy_disconnect(tp->phydev);
+ phylink_disconnect_phy(tp->phylink);
dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
tp->RxPhyAddr);
@@ -5112,11 +5251,13 @@ static int rtl_open(struct net_device *dev)
if (retval < 0)
goto err_release_fw_2;
- retval = r8169_phy_connect(tp);
- if (retval)
- goto err_free_irq;
-
+ if (tp->phydev) {
+ retval = r8169_phy_connect(tp);
+ if (retval)
+ goto err_free_irq;
+ }
rtl8169_up(tp);
+ phylink_start(tp->phylink);
rtl8169_init_counter_offsets(tp);
netif_start_queue(dev);
out:
@@ -5221,6 +5362,9 @@ static int rtl8169_resume(struct device *device)
/* Some chip versions may truncate packets without this initialization */
rtl_init_rxcfg(tp);
+ if (rtl_is_8116af(tp))
+ rtl_lowpower_hidden_functions(tp->pci_dev);
+
return rtl8169_runtime_resume(device);
}
@@ -5288,6 +5432,7 @@ static void rtl_remove_one(struct pci_dev *pdev)
r8169_remove_leds(tp->leds);
unregister_netdev(tp->dev);
+ phylink_destroy(tp->phylink);
if (tp->dash_type != RTL_DASH_NONE)
rtl8168_driver_stop(tp);
@@ -5310,7 +5455,7 @@ static const struct net_device_ops rtl_netdev_ops = {
.ndo_fix_features = rtl8169_fix_features,
.ndo_set_features = rtl8169_set_features,
.ndo_set_mac_address = rtl_set_mac_address,
- .ndo_eth_ioctl = phy_do_ioctl_running,
+ .ndo_eth_ioctl = rtl8169_ioctl,
.ndo_set_rx_mode = rtl_set_rx_mode,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = rtl8169_netpoll,
@@ -5474,16 +5619,6 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
return -EUNATCH;
}
- tp->phydev->mac_managed_pm = true;
- if (rtl_supports_eee(tp))
- phy_support_eee(tp->phydev);
- phy_support_asym_pause(tp->phydev);
-
- /* mimic behavior of r8125/r8126 vendor drivers */
- if (tp->mac_version == RTL_GIGA_MAC_VER_61)
- phy_disable_eee_mode(tp->phydev,
- ETHTOOL_LINK_MODE_2500baseT_Full_BIT);
-
/* PHY will be woken up in rtl_open() */
phy_suspend(tp->phydev);
@@ -5599,6 +5734,247 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp)
return false;
}
+static void rtl_mac_link_down(struct phylink_config *config, unsigned int mode,
+ phy_interface_t interface)
+{
+ struct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);
+
+ tp->speed = SPEED_UNKNOWN;
+ pm_runtime_idle(tp_to_dev(tp));
+}
+
+static void rtl_mac_link_up(struct phylink_config *config, struct phy_device *phydev,
+ unsigned int mode, phy_interface_t interface,
+ int speed, int duplex, bool tx_pause, bool rx_pause)
+{
+ struct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);
+ struct device *d = tp_to_dev(tp);
+
+ tp->speed = speed;
+ rtl_link_chg_patch(tp, speed);
+
+ pm_request_resume(d);
+}
+
+static struct phylink_pcs *rtl_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
+{
+ struct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);
+
+ if (!tp->pcs.ops)
+ return NULL;
+
+ if (interface == PHY_INTERFACE_MODE_1000BASEX ||
+ interface == PHY_INTERFACE_MODE_10GBASER)
+ return &tp->pcs;
+
+ return NULL;
+}
+
+static void rtl_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+}
+
+static u16 rtl8169_sds_read(struct rtl8169_private *tp, u16 sds_reg)
+{
+ unsigned long flags;
+ u16 val = 0;
+
+ raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
+ __r8168_mac_ocp_write(tp, OCP_SDS_ADDR_REG, sds_reg);
+ __r8168_mac_ocp_write(tp, OCP_SDS_CMD_REG, SDS_CMD_READ);
+ val = __r8168_mac_ocp_read(tp, OCP_SDS_DATA_REG);
+ raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
+
+ return val;
+}
+
+static void rtl8169_pcs_get_state(struct phylink_pcs *pcs,
+ unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, pcs);
+
+ if (tp->sfp_mode == RTL_SFP_8127_ATF) {
+ u16 stat1;
+
+ stat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1);
+
+ if (!(stat1 & MDIO_STAT1_LSTATUS))
+ stat1 = rtl8169_sds_read(tp, RTL_SDS_C45_BASE + MDIO_STAT1);
+
+ state->link = !!(stat1 & MDIO_STAT1_LSTATUS);
+ if (!state->link)
+ return;
+
+ if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
+ state->speed = SPEED_1000;
+ else
+ state->speed = SPEED_10000;
+
+ state->duplex = DUPLEX_FULL;
+ } else {
+ u16 bmsr, lpa;
+
+ bmsr = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_BMSR);
+ lpa = rtl8169_sds_read(tp, RTL_SDS_C22_BASE + MII_LPA);
+ phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);
+ }
+}
+
+static int rtl8169_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ struct rtl8169_private *tp = container_of(pcs, struct rtl8169_private, pcs);
+
+ if (tp->sfp_mode == RTL_SFP_8127_ATF) {
+ switch (interface) {
+ case PHY_INTERFACE_MODE_10GBASER:
+ r8127_sfp_init_10g(tp);
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ r8127_sfp_init_1g(tp);
+ break;
+ default:
+ netdev_err(tp->dev, "Unsupported SFP interface mode: %s\n",
+ phy_modes(interface));
+ return -EOPNOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int rtl8169_pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
+ const struct phylink_link_state *state)
+{
+ return 0;
+}
+
+static void rtl8169_pcs_an_restart(struct phylink_pcs *pcs)
+{
+}
+
+static void rtl_mac_disable_tx_lpi(struct phylink_config *config)
+{
+ struct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);
+
+ rtl_enable_tx_lpi(tp, false);
+}
+
+static int rtl_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, bool tx_clk_stop)
+{
+ struct rtl8169_private *tp = container_of(config, struct rtl8169_private, phylink_config);
+
+ rtl_enable_tx_lpi(tp, true);
+
+ return 0;
+}
+
+static const struct phylink_mac_ops rtl_phylink_mac_ops = {
+ .mac_select_pcs = rtl_mac_select_pcs,
+ .mac_config = rtl_mac_config,
+ .mac_link_down = rtl_mac_link_down,
+ .mac_link_up = rtl_mac_link_up,
+ .mac_disable_tx_lpi = rtl_mac_disable_tx_lpi,
+ .mac_enable_tx_lpi = rtl_mac_enable_tx_lpi,
+};
+
+static unsigned long rtl8169_get_lpi_caps(struct rtl8169_private *tp)
+{
+ unsigned long caps = 0;
+
+ if (!rtl_supports_eee(tp) || tp->sfp_mode == RTL_SFP_8127_ATF)
+ return 0;
+
+ caps |= MAC_100FD | MAC_1000FD;
+
+ /* mimic behavior of r8125/r8126 vendor drivers
+ * RTL_GIGA_MAC_VER_61 doesn't support 2.5G eee
+ */
+ if (tp->mac_version >= RTL_GIGA_MAC_VER_63)
+ caps |= MAC_2500FD;
+ if (tp->mac_version >= RTL_GIGA_MAC_VER_70)
+ caps |= MAC_5000FD;
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ caps |= MAC_10000FD;
+
+ return caps;
+}
+
+static const struct phylink_pcs_ops r8169_pcs_ops = {
+ .pcs_validate = rtl8169_pcs_validate,
+ .pcs_get_state = rtl8169_pcs_get_state,
+ .pcs_config = rtl8169_pcs_config,
+ .pcs_an_restart = rtl8169_pcs_an_restart,
+};
+
+static int rtl_init_phylink(struct rtl8169_private *tp)
+{
+ struct phylink *pl;
+ phy_interface_t phy_mode;
+
+ tp->phylink_config.dev = &tp->dev->dev;
+ tp->phylink_config.type = PHYLINK_NETDEV;
+ tp->phylink_config.mac_managed_pm = true;
+ tp->phylink_config.lpi_capabilities = rtl8169_get_lpi_caps(tp);
+ tp->phylink_config.mac_capabilities |= MAC_ASYM_PAUSE | MAC_SYM_PAUSE;
+
+ switch (tp->sfp_mode) {
+ case RTL_SFP_8168_AF:
+ tp->pcs.ops = &r8169_pcs_ops;
+ tp->phylink_config.default_an_inband = true;
+ phy_mode = PHY_INTERFACE_MODE_1000BASEX;
+ tp->phylink_config.mac_capabilities |= MAC_1000FD;
+ break;
+ case RTL_SFP_8127_ATF:
+ tp->pcs.ops = &r8169_pcs_ops;
+ phy_mode = PHY_INTERFACE_MODE_10GBASER;
+ tp->phylink_config.default_an_inband = true;
+ tp->phylink_config.mac_capabilities |= MAC_1000FD | MAC_10000FD;
+ __set_bit(PHY_INTERFACE_MODE_10GBASER, tp->phylink_config.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX, tp->phylink_config.supported_interfaces);
+ break;
+ default:
+ tp->phylink_config.mac_capabilities |= MAC_10 | MAC_100;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_80)
+ tp->phylink_config.mac_capabilities |= MAC_1000FD | MAC_2500FD |
+ MAC_5000FD | MAC_10000FD;
+ else if (tp->mac_version == RTL_GIGA_MAC_VER_70)
+ tp->phylink_config.mac_capabilities |= MAC_1000FD |
+ MAC_2500FD | MAC_5000FD;
+ else if (tp->mac_version >= RTL_GIGA_MAC_VER_61)
+ tp->phylink_config.mac_capabilities |= MAC_1000FD | MAC_2500FD;
+ else
+ if (tp->supports_gmii)
+ tp->phylink_config.mac_capabilities |= MAC_1000FD;
+
+ if (tp->mac_version < RTL_GIGA_MAC_VER_61)
+ phy_mode = tp->supports_gmii ? PHY_INTERFACE_MODE_GMII :
+ PHY_INTERFACE_MODE_MII;
+ else
+ phy_mode = PHY_INTERFACE_MODE_INTERNAL;
+ break;
+ }
+
+ __set_bit(phy_mode, tp->phylink_config.supported_interfaces);
+ if (tp->phylink_config.lpi_capabilities)
+ __set_bit(phy_mode, tp->phylink_config.lpi_interfaces);
+
+ pl = phylink_create(&tp->phylink_config, tp_to_dev(tp)->fwnode,
+ phy_mode, &rtl_phylink_mac_ops);
+ if (IS_ERR(pl))
+ return PTR_ERR(pl);
+
+ tp->phylink = pl;
+
+ return 0;
+}
+
static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
const struct rtl_chip_info *chip;
@@ -5667,6 +6043,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ext_xid_str, xid);
tp->mac_version = chip->mac_version;
tp->fw_name = chip->fw_name;
+ tp->speed = SPEED_UNKNOWN;
/* Disable ASPM L1 as that cause random device stop working
* problems as well as full system hangs for some PCIe devices users.
@@ -5679,12 +6056,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
tp->aspm_manageable = !rc;
- if (rtl_is_8125(tp)) {
- u16 data = r8168_mac_ocp_read(tp, 0xd006);
-
- if ((data & 0xff) == 0x07)
- tp->sfp_mode = true;
- }
+ tp->sfp_mode = rtl_get_sfp_mode(tp);
tp->dash_type = rtl_get_dash_type(tp);
tp->dash_enabled = rtl_dash_is_enabled(tp);
@@ -5788,13 +6160,23 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, tp);
- rc = r8169_mdio_register(tp);
+ rc = rtl_init_phylink(tp);
if (rc)
return rc;
+ if (tp->sfp_mode == RTL_SFP_NONE) {
+ rc = r8169_mdio_register(tp);
+ if (rc) {
+ phylink_destroy(tp->phylink);
+ return rc;
+ }
+ }
+
rc = register_netdev(dev);
- if (rc)
+ if (rc) {
+ phylink_destroy(tp->phylink);
return rc;
+ }
if (IS_ENABLED(CONFIG_R8169_LEDS)) {
if (rtl_is_8125(tp))
@@ -5817,6 +6199,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8168_driver_start(tp);
}
+ if (rtl_is_8116af(tp))
+ rtl_lowpower_hidden_functions(tp->pci_dev);
+
if (pci_dev_run_wake(pdev))
pm_runtime_put_sync(&pdev->dev);
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 59dfe35afa54fc..9e9cd79301d66c 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1828,6 +1828,93 @@ int phylink_set_fixed_link(struct phylink *pl,
}
EXPORT_SYMBOL_GPL(phylink_set_fixed_link);
+/**
+ * phylink_update_mac_pause_capabilities() - Dynamically update MAC pause
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ * @mac_pause: the new MAC pause capabilities mask
+ *
+ * This function allows a MAC driver to dynamically change its pause state,
+ * such as losing/gaining Pause frame support based on MTU size.
+ * It recalculates supported link modes and triggers renegotiation if needed.
+ */
+void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause)
+{
+ struct phylink_link_state *config = &pl->link_config;
+ unsigned long old_pause, caps_added, caps_removed;
+ bool pause_adv, asym_adv;
+
+ ASSERT_RTNL();
+
+ if (mac_pause & ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE)) {
+ phylink_err(pl, "Attempted to dynamically change non-pause MAC capabilities\n");
+ return;
+ }
+
+ old_pause = pl->config->mac_capabilities & (MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
+ caps_added = mac_pause & ~old_pause;
+ caps_removed = old_pause & ~mac_pause;
+
+ if (!caps_added && !caps_removed)
+ return;
+
+ mutex_lock(&pl->state_mutex);
+
+ pl->config->mac_capabilities &= ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
+ pl->config->mac_capabilities |= mac_pause;
+
+ if (caps_removed & MAC_SYM_PAUSE)
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, pl->supported);
+ if (caps_removed & MAC_ASYM_PAUSE)
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, pl->supported);
+
+ linkmode_and(config->advertising, config->advertising, pl->supported);
+
+ if (caps_added & MAC_SYM_PAUSE) {
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, pl->supported);
+ if (pl->phydev && !phylink_test(pl->phydev->supported, Pause))
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, pl->supported);
+ }
+ if (caps_added & MAC_ASYM_PAUSE) {
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, pl->supported);
+ if (pl->phydev && !phylink_test(pl->phydev->supported, Asym_Pause))
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, pl->supported);
+ }
+
+ linkmode_and(config->advertising, config->advertising, pl->supported);
+
+ if (config->pause & MLO_PAUSE_AN) {
+ if (phylink_test(pl->supported, Pause) &&
+ (config->pause & MLO_PAUSE_RX) && (config->pause & MLO_PAUSE_TX))
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, config->advertising);
+
+ if (phylink_test(pl->supported, Asym_Pause) &&
+ ((config->pause & MLO_PAUSE_RX) ^ (config->pause & MLO_PAUSE_TX)))
+ linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, config->advertising);
+ }
+
+ if (!pl->phydev)
+ phylink_change_inband_advert(pl);
+
+ mutex_unlock(&pl->state_mutex);
+
+ if (pl->phydev) {
+ pause_adv = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
+ config->advertising);
+ asym_adv = linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ config->advertising);
+
+ mutex_lock(&pl->phydev->lock);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
+ pl->phydev->advertising, pause_adv);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
+ pl->phydev->advertising, asym_adv);
+ mutex_unlock(&pl->phydev->lock);
+
+ phy_start_aneg(pl->phydev);
+ }
+}
+EXPORT_SYMBOL_GPL(phylink_update_mac_pause_capabilities);
+
/**
* phylink_create() - create a phylink instance
* @config: a pointer to the target &struct phylink_config
diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index b65d0f5fa1a014..4721ba071cbbe4 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -17,7 +17,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/string_choices.h>
-#include <net/phy/realtek_phy.h>
#include "../phylib.h"
#include "realtek.h"
@@ -2646,45 +2645,6 @@ static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
return IRQ_HANDLED;
}
-static int rtlgen_sfp_get_features(struct phy_device *phydev)
-{
- linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
- phydev->supported);
-
- /* set default mode */
- phydev->speed = SPEED_10000;
- phydev->duplex = DUPLEX_FULL;
-
- phydev->port = PORT_FIBRE;
-
- return 0;
-}
-
-static int rtlgen_sfp_read_status(struct phy_device *phydev)
-{
- int val, err;
-
- err = genphy_update_link(phydev);
- if (err)
- return err;
-
- if (!phydev->link)
- return 0;
-
- val = phy_read(phydev, RTL_PHYSR);
- if (val < 0)
- return val;
-
- rtlgen_decode_physr(phydev, val);
-
- return 0;
-}
-
-static int rtlgen_sfp_config_aneg(struct phy_device *phydev)
-{
- return 0;
-}
-
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -2934,20 +2894,6 @@ static struct phy_driver realtek_drvs[] = {
.write_page = rtl821x_write_page,
.read_mmd = rtl822x_read_mmd,
.write_mmd = rtl822x_write_mmd,
- }, {
- PHY_ID_MATCH_EXACT(PHY_ID_RTL_DUMMY_SFP),
- .name = "Realtek SFP PHY Mode",
- .flags = PHY_IS_INTERNAL,
- .probe = rtl822x_probe,
- .get_features = rtlgen_sfp_get_features,
- .config_aneg = rtlgen_sfp_config_aneg,
- .read_status = rtlgen_sfp_read_status,
- .suspend = genphy_suspend,
- .resume = rtlgen_resume,
- .read_page = rtl821x_read_page,
- .write_page = rtl821x_write_page,
- .read_mmd = rtl822x_read_mmd,
- .write_mmd = rtl822x_write_mmd,
}, {
PHY_ID_MATCH_EXACT(0x001ccad0),
.name = "RTL8224 2.5Gbps PHY",
diff --git a/include/linux/phylink.h b/include/linux/phylink.h
index 2bc0db3d52ac8d..e3c7822100aba6 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -842,4 +842,6 @@ void phylink_replay_link_begin(struct phylink *pl);
void phylink_replay_link_end(struct phylink *pl);
+void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause);
+
#endif
diff --git a/include/net/phy/realtek_phy.h b/include/net/phy/realtek_phy.h
deleted file mode 100644
index d683bc1b0659cd..00000000000000
--- a/include/net/phy/realtek_phy.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _REALTEK_PHY_H
-#define _REALTEK_PHY_H
-
-#define PHY_ID_RTL_DUMMY_SFP 0x001ccbff
-
-#endif /* _REALTEK_PHY_H */
|
| 3/2 | 2026/07/10 05:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 20925 output: 24 thoughts: 800 Thoughts: **Fuzzing Target Identification: r8169 Driver and phylink Integration** Okay, so we have this patch series that refactors the Realtek r8169 driver to use phylink. That means a functional change to the driver itself and the phylink core, which, for a networking expert like myself, immediately screams potential fuzzing targets. The patch touches `drivers/net/ethernet/realtek/r8169_main.c`, `drivers/net/phy/phylink.c`, and potentially `drivers/net/phy/realtek/realtek_main.c`. First things first: reachability. The r8169 driver is for Realtek PCI Ethernet adapters. Can we actually hit this in a virtualized environment? QEMU is the obvious candidate. My initial thought was that it might emulate `rtl8139`, but does it support `rtl8169` directly? A quick check of the documentation or source confirms... no, natively, it doesn't. However, the `syz_pci_device` primitive in syzkaller is my saving grace. This pseudo-device allows us to fuzz *any* PCI driver by emulating the PCI device itself. Excellent. This means the r8169 is indeed reachable and fuzzable. This `phylink.c` modification, with the addition of `phylink_update_mac_pause_capabilities`, immediately catches my eye. Phylink is a central networking component, so changes there have broader implications. It's used by many drivers, and that new function needs to be checked. Let's see if that's reachable - `phylink_update_mac_pause_capabilities` is called from `rtl8169_change_mtu`. Good. Now for the configurations. I know we'll be looking at `CONFIG_R8169` (which, from the looks of it, selects `CONFIG_PHYLINK`) and `CONFIG_PCI`. Time to verify that `CONFIG_R8169` depends on `PCI` in the `Kconfig` files. Confirmed. Finally, let's nail down our fuzzing targets. In `drivers/net/phy/phylink.c`, `phylink_update_mac_pause_capabilities` is the new kid on the block. Then, in the Realtek driver (`drivers/net/ethernet/realtek/r8169_main.c`), we have `rtl8169_change_mtu`, along with a whole list of functions that need to be tested, like `rtl_init_phylink`, `rtl8169_pcs_config`, `rtl8169_pcs_get_state`, `rtl_mac_link_up`, `rtl_mac_link_down`, `rtl_mac_select_pcs`, `rtl_mac_config`, `rtl_mac_disable_tx_lpi`, `rtl_mac_enable_tx_lpi`, the SDS and SFP functions. Time to start digging in. |
| 4/2 | 2026/07/10 05:34 | tool | grepper |
0mArgs:{
"Expression": "phylink_update_mac_pause_capabilities"
}Results: {
"Output": "drivers/net/ethernet/realtek/r8169_main.c=4291=static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)\n--\ndrivers/net/ethernet/realtek/r8169_main.c-4309-\ndrivers/net/ethernet/realtek/r8169_main.c:4310:\t\tphylink_update_mac_pause_capabilities(tp-\u003ephylink, caps);\ndrivers/net/ethernet/realtek/r8169_main.c-4311-\t}\n--\ndrivers/net/phy/phylink.c=1829=EXPORT_SYMBOL_GPL(phylink_set_fixed_link);\n--\ndrivers/net/phy/phylink.c-1831-/**\ndrivers/net/phy/phylink.c:1832: * phylink_update_mac_pause_capabilities() - Dynamically update MAC pause\ndrivers/net/phy/phylink.c-1833- * @pl: a pointer to a \u0026struct phylink returned from phylink_create()\n--\ndrivers/net/phy/phylink.c-1839- */\ndrivers/net/phy/phylink.c:1840:void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause)\ndrivers/net/phy/phylink.c-1841-{\n--\ndrivers/net/phy/phylink.c-1915-}\ndrivers/net/phy/phylink.c:1916:EXPORT_SYMBOL_GPL(phylink_update_mac_pause_capabilities);\ndrivers/net/phy/phylink.c-1917-\n--\ninclude/linux/phylink.h=843=void phylink_replay_link_end(struct phylink *pl);\ninclude/linux/phylink.h-844-\ninclude/linux/phylink.h:845:void phylink_update_mac_pause_capabilities(struct phylink *pl, unsigned long mac_pause);\ninclude/linux/phylink.h-846-\n"
} |
| 5/2 | 2026/07/10 05:34 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 22951 output: 18 thoughts: 340 Thoughts: **Fuzzing Target Identification: Networking PHY and Realtek Driver Changes** Okay, so this patch is making some pretty fundamental changes to the way we handle PHY link management in the kernel, specifically by introducing `phylink_update_mac_pause_capabilities` and integrating `phylink` with the `r8169` Realtek Ethernet driver. Given my experience, I see this as a prime candidate for fuzzing. Any changes this deep into the network stack, touching both core PHY functionality and a widely used driver like `r8169`, deserve a thorough examination. Let's nail down the critical functions that need immediate attention during fuzzing. I'm focusing on the integration points and the core MAC/PHY interaction functions: * `phylink_update_mac_pause_capabilities`: This is obviously the central new function, so it's a priority. * `rtl8169_change_mtu`: MTU changes can reveal interesting edge cases in networking. * `rtl_init_phylink`: Since it's interacting with the phylink framework, definitely needs a look. * `rtl8169_pcs_config` and `rtl8169_pcs_get_state`: PHY Control Signals. * `rtl_mac_link_up` and `rtl_mac_link_down`: Link state transitions are always interesting. * `rtl_mac_select_pcs`: Another PCS function, making decisions. * `rtl_mac_disable_tx_lpi` and `rtl_mac_enable_tx_lpi`: These are likely related to power management and should be reviewed. * `rtl8169_sds_read`, `r8127_sds_read`, `r8127_sds_write`, and `r8127_sds_modify`: These related to Shadow Data Structure and should be fuzz-tested. * `r8127_sfp_init_1g` and `r8127_sfp_init_10g`: These are worth checking in the context of SFP, which could have some edge cases. * `rtl_get_sfp_mode`: Also related to SFP configurations. * `rtl_is_8116af`: Feature identification. We also have a couple of configurations: `R8169` I need to quickly double-check that `PHYLINK` is indeed a config option, just to be sure. After that, I'll set up my fuzzing harnesses, and start looking for the weak points. |
| 6/2 | 2026/07/10 05:34 | tool | grepper |
0mArgs:{
"Expression": "config PHYLINK"
}Results: {
"Output": "drivers/net/phy/Kconfig-5-\ndrivers/net/phy/Kconfig:6:config PHYLINK\ndrivers/net/phy/Kconfig-7-\ttristate\n"
} |
| 7/2 | 2026/07/10 05:34 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 23940 output: 370 thoughts: 1003 Thoughts: **Refining the Phylink Focus for the R8169 Driver** Okay, so `PHYLINK` is a tristate config, but the `R8169` driver actually selects it. Therefore, we only need to enable `R8169`. That simplifies the configuration, which is good. Now, let's nail down the core functions we need to focus on. Based on the changes, I've identified the following as prime candidates: `phylink_update_mac_pause_capabilities`, `rtl8169_change_mtu`, `rtl_init_phylink`, `rtl8169_pcs_config`, `rtl8169_pcs_get_state`, `rtl_mac_link_up`, `rtl_mac_link_down`, `rtl_mac_select_pcs`, `rtl_mac_disable_tx_lpi`, `rtl_mac_enable_tx_lpi`, `rtl8169_sds_read`, `r8127_sds_read`, `r8127_sds_write`, `r8127_sds_modify`, `r8127_sfp_init_1g`, `r8127_sfp_init_10g`, `rtl_get_sfp_mode`, and `rtl_is_8116af`. Those should capture the essence of the phylink integration and its interaction with the MAC. Hold on a second... Let me double-check a couple of things. Ah, the `rtl_mac_config` function is empty. And `rtl8169_pcs_validate` and `rtl8169_pcs_an_restart` are also empty. It's always worth verifying that these are actually doing something of interest, and because they're empty, they're not. We can safely exclude them from the list. Let's do a quick scan of the code for any other potential relevant functions. Okay, here are a few more: `rtl_lowpower_hidden_functions`, `rtl8169_get_link_ksettings`, `rtl8169_set_link_ksettings`, `rtl8169_nway_reset`, and `rtl8169_ioctl`. Those seem relevant, especially `ksettings`, so I'll add them to the list. They definitely should be included, for they would probably be interacting with the link state of the device. So, the updated list of focus symbols is what I have now. I'll include it with the reasoning that this patch involves functional changes to reachable core networking and driver code, specifically the r8169 driver's phylink API usage, and the new pause capability function. |
| 8/2 | 2026/07/10 05:34 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"R8169"
],
"FocusSymbols": [
"phylink_update_mac_pause_capabilities",
"rtl8169_change_mtu",
"rtl_init_phylink",
"rtl8169_pcs_config",
"rtl8169_pcs_get_state",
"rtl_mac_link_up",
"rtl_mac_link_down",
"rtl_mac_select_pcs",
"rtl_mac_disable_tx_lpi",
"rtl_mac_enable_tx_lpi",
"rtl8169_sds_read",
"r8127_sds_read",
"r8127_sds_write",
"r8127_sds_modify",
"r8127_sfp_init_1g",
"r8127_sfp_init_10g",
"rtl_get_sfp_mode",
"rtl_is_8116af",
"rtl_lowpower_hidden_functions",
"rtl8169_get_link_ksettings",
"rtl8169_set_link_ksettings",
"rtl8169_nway_reset",
"rtl8169_ioctl"
],
"Reasoning": "The patch converts the Realtek r8169 driver to use the phylink API and introduces a new phylink function to dynamically update MAC pause capabilities. These are functional changes to reachable core networking and driver code.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"R8169"
],
"FocusSymbols": [
"phylink_update_mac_pause_capabilities",
"rtl8169_change_mtu",
"rtl_init_phylink",
"rtl8169_pcs_config",
"rtl8169_pcs_get_state",
"rtl_mac_link_up",
"rtl_mac_link_down",
"rtl_mac_select_pcs",
"rtl_mac_disable_tx_lpi",
"rtl_mac_enable_tx_lpi",
"rtl8169_sds_read",
"r8127_sds_read",
"r8127_sds_write",
"r8127_sds_modify",
"r8127_sfp_init_1g",
"r8127_sfp_init_10g",
"rtl_get_sfp_mode",
"rtl_is_8116af",
"rtl_lowpower_hidden_functions",
"rtl8169_get_link_ksettings",
"rtl8169_set_link_ksettings",
"rtl8169_nway_reset",
"rtl8169_ioctl"
],
"Reasoning": "The patch converts the Realtek r8169 driver to use the phylink API and introduces a new phylink function to dynamically update MAC pause capabilities. These are functional changes to reachable core networking and driver code.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|