| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/06/29 07:18 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"REALTEK_PHY"
],
"FocusSymbols": [
"genphy_c45_soft_reset",
"genphy_c45_an_setup_master_slave",
"genphy_c45_read_master_slave",
"rtl8261x_probe",
"rtl8261x_get_features",
"rtl8261x_read_status",
"rtl8261x_verify_firmware",
"rtl8261x_fw_execute_entry",
"rtl8261x_fw_load",
"rtl8261x_config_intr",
"rtl8261x_handle_interrupt",
"rtl8261x_config_aneg",
"rtl8261x_config_init"
],
"Reasoning": "The patch adds new Master/Slave configuration logic for Clause 45 PHYs and introduces a new Realtek PHY driver (RTL8261C) with firmware loading capabilities. These features are reachable via MDIO bus emulation (e.g., through USB network device emulation) and contain complex logic that should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/06/29 07:18 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 62314e504a92ecba59ca55e4fd0ebc559e4590bc\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jun 29 07:18:43 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c\nindex 1269517414288f..df682d3ebd5a1d 100644\n--- a/drivers/net/phy/phy-c45.c\n+++ b/drivers/net/phy/phy-c45.c\n@@ -384,6 +384,119 @@ int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)\n }\n EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);\n \n+/**\n+ * genphy_c45_soft_reset - software reset the PHY via Clause 45 PMA/PMD control register\n+ * @phydev: target phy_device struct\n+ *\n+ * Return: 0 on success, negative errno on failure.\n+ */\n+int genphy_c45_soft_reset(struct phy_device *phydev)\n+{\n+\tint ret, val;\n+\n+\tret = phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,\n+\t\t\t MDIO_CTRL1_RESET);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD,\n+\t\t\t\t\t MDIO_CTRL1, val,\n+\t\t\t\t\t !(val \u0026 MDIO_CTRL1_RESET),\n+\t\t\t\t\t 5000, 600000, true);\n+}\n+EXPORT_SYMBOL_GPL(genphy_c45_soft_reset);\n+\n+/**\n+ * genphy_c45_an_setup_master_slave - Configure Master/Slave setting for C45 PHYs\n+ * @phydev: target phy_device struct\n+ *\n+ * Description: Configure the forced or preferred Master/Slave role\n+ * 10GBASE-T control register (MMD 7, Register 0x0020) according to\n+ * IEEE 802.3 standards.\n+ *\n+ * Return: negative errno code on failure, 0 if Master/Slave didn't change,\n+ * or 1 if Master/Slave modes changed.\n+ */\n+static int genphy_c45_an_setup_master_slave(struct phy_device *phydev)\n+{\n+\tu16 ctl = 0;\n+\n+\tswitch (phydev-\u003emaster_slave_set) {\n+\tcase MASTER_SLAVE_CFG_MASTER_PREFERRED:\n+\t\tctl = MDIO_AN_10GBT_CTRL_MS_PORT_TYPE;\n+\t\tbreak;\n+\tcase MASTER_SLAVE_CFG_SLAVE_PREFERRED:\n+\t\tbreak;\n+\tcase MASTER_SLAVE_CFG_MASTER_FORCE:\n+\t\tctl = MDIO_AN_10GBT_CTRL_MS_ENABLE | MDIO_AN_10GBT_CTRL_MS_VALUE;\n+\t\tbreak;\n+\tcase MASTER_SLAVE_CFG_SLAVE_FORCE:\n+\t\tctl = MDIO_AN_10GBT_CTRL_MS_ENABLE;\n+\t\tbreak;\n+\tcase MASTER_SLAVE_CFG_UNKNOWN:\n+\tcase MASTER_SLAVE_CFG_UNSUPPORTED:\n+\t\treturn 0;\n+\tdefault:\n+\t\tphydev_warn(phydev, \"Unsupported Master/Slave mode\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\treturn phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,\n+\t\t\t\t MDIO_AN_10GBT_CTRL_MS_ENABLE |\n+\t\t\t\t MDIO_AN_10GBT_CTRL_MS_VALUE |\n+\t\t\t\t MDIO_AN_10GBT_CTRL_MS_PORT_TYPE, ctl);\n+}\n+\n+/**\n+ * genphy_c45_read_master_slave - read master/slave status\n+ * @phydev: target phy_device struct\n+ *\n+ * Description: Read the Master/Slave configuration and status\n+ * from 10GBASE-T control/status registers (MMD 7, Reg 0x0020 and 0x0021).\n+ *\n+ * Return: 0 on success, or a negative error code on failure.\n+ */\n+static int genphy_c45_read_master_slave(struct phy_device *phydev)\n+{\n+\tint val;\n+\n+\tphydev-\u003emaster_slave_get = MASTER_SLAVE_CFG_UNKNOWN;\n+\tphydev-\u003emaster_slave_state = MASTER_SLAVE_STATE_UNKNOWN;\n+\n+\tval = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);\n+\tif (val \u003c 0)\n+\t\treturn val;\n+\n+\tif (val \u0026 MDIO_AN_10GBT_CTRL_MS_ENABLE) {\n+\t\tif (val \u0026 MDIO_AN_10GBT_CTRL_MS_VALUE)\n+\t\t\tphydev-\u003emaster_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;\n+\t\telse\n+\t\t\tphydev-\u003emaster_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;\n+\t} else {\n+\t\tif (val \u0026 MDIO_AN_10GBT_CTRL_MS_PORT_TYPE)\n+\t\t\tphydev-\u003emaster_slave_get = MASTER_SLAVE_CFG_MASTER_PREFERRED;\n+\t\telse\n+\t\t\tphydev-\u003emaster_slave_get = MASTER_SLAVE_CFG_SLAVE_PREFERRED;\n+\t}\n+\n+\tval = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);\n+\tif (val \u003c 0)\n+\t\treturn val;\n+\n+\tif (val \u0026 MDIO_AN_10GBT_STAT_MS_FAULT) {\n+\t\tphydev-\u003emaster_slave_state = MASTER_SLAVE_STATE_ERR;\n+\t} else if (phydev-\u003elink) {\n+\t\tif (val \u0026 MDIO_AN_10GBT_STAT_MS_RES)\n+\t\t\tphydev-\u003emaster_slave_state = MASTER_SLAVE_STATE_MASTER;\n+\t\telse\n+\t\t\tphydev-\u003emaster_slave_state = MASTER_SLAVE_STATE_SLAVE;\n+\t} else {\n+\t\tphydev-\u003emaster_slave_state = MASTER_SLAVE_STATE_UNKNOWN;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /**\n * genphy_c45_aneg_done - return auto-negotiation complete status\n * @phydev: target phy_device struct\n@@ -1192,6 +1305,10 @@ int genphy_c45_read_status(struct phy_device *phydev)\n \t\t\tret = genphy_c45_baset1_read_status(phydev);\n \t\t\tif (ret \u003c 0)\n \t\t\t\treturn ret;\n+\t\t} else {\n+\t\t\tret = genphy_c45_read_master_slave(phydev);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\treturn ret;\n \t\t}\n \n \t\tphy_resolve_aneg_linkmode(phydev);\n@@ -1225,6 +1342,14 @@ int genphy_c45_config_aneg(struct phy_device *phydev)\n \tif (ret \u003e 0)\n \t\tchanged = true;\n \n+\tif (!genphy_c45_baset1_able(phydev)) {\n+\t\tret = genphy_c45_an_setup_master_slave(phydev);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\tif (ret \u003e 0)\n+\t\t\tchanged = true;\n+\t}\n+\n \treturn genphy_c45_check_and_restart_aneg(phydev, changed);\n }\n EXPORT_SYMBOL_GPL(genphy_c45_config_aneg);\ndiff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c\nindex 27268811f564f2..bf7bc19fb44cd2 100644\n--- a/drivers/net/phy/realtek/realtek_main.c\n+++ b/drivers/net/phy/realtek/realtek_main.c\n@@ -8,7 +8,9 @@\n * Copyright (c) 2004 Freescale Semiconductor, Inc.\n */\n #include \u003clinux/bitops.h\u003e\n+#include \u003clinux/crc32.h\u003e\n #include \u003clinux/ethtool_netlink.h\u003e\n+#include \u003clinux/firmware.h\u003e\n #include \u003clinux/of.h\u003e\n #include \u003clinux/phy.h\u003e\n #include \u003clinux/pm_wakeirq.h\u003e\n@@ -141,6 +143,10 @@\n #define RTL8211F_PHYSICAL_ADDR_WORD1\t\t17\n #define RTL8211F_PHYSICAL_ADDR_WORD2\t\t18\n \n+#define RTL8261X_EXT_ADDR_REG\t\t\t0xa436\n+#define RTL8261X_EXT_DATA_REG\t\t\t0xa438\n+#define RTL_8261X_SUB_PHY_ID_ADDR\t\t0x801d\n+\n #define RTL822X_VND1_SERDES_OPTION\t\t\t0x697a\n #define RTL822X_VND1_SERDES_OPTION_MODE_MASK\t\tGENMASK(5, 0)\n #define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII\t\t0\n@@ -251,6 +257,68 @@\n #define RTL_8221B_VM_CG\t\t\t\t0x001cc84a\n #define RTL_8251B\t\t\t\t0x001cc862\n #define RTL_8261C\t\t\t\t0x001cc890\n+#define RTL_8261C_CG\t\t\t\t0x001cc898\n+\n+#define RTL8261C_CE_MODEL\t\t0x00\n+#define RTL8261X_INT_AUTONEG_ERROR\tBIT(0)\n+#define RTL8261X_INT_PAGE_RECV\t\tBIT(2)\n+#define RTL8261X_INT_AUTONEG_DONE\tBIT(3)\n+#define RTL8261X_INT_LINK_CHG\t\tBIT(4)\n+#define RTL8261X_INT_PHY_REG_ACCESS\tBIT(5)\n+#define RTL8261X_INT_PME\t\tBIT(7)\n+#define RTL8261X_INT_ALDPS_CHG\t\tBIT(9)\n+#define RTL8261X_INT_JABBER\t\tBIT(10)\n+\n+#define RTL8261X_INT_MASK_DEFAULT\t(RTL8261X_INT_AUTONEG_DONE | \\\n+\t\t\t\t\t RTL8261X_INT_LINK_CHG | \\\n+\t\t\t\t\t RTL8261X_INT_AUTONEG_ERROR | \\\n+\t\t\t\t\t RTL8261X_INT_JABBER)\n+\n+#define RTL8261X_INT_MASK_ALL\t\t(RTL8261X_INT_AUTONEG_ERROR | \\\n+\t\t\t\t\t RTL8261X_INT_PAGE_RECV | \\\n+\t\t\t\t\t RTL8261X_INT_AUTONEG_DONE | \\\n+\t\t\t\t\t RTL8261X_INT_LINK_CHG | \\\n+\t\t\t\t\t RTL8261X_INT_PHY_REG_ACCESS | \\\n+\t\t\t\t\t RTL8261X_INT_PME | \\\n+\t\t\t\t\t RTL8261X_INT_ALDPS_CHG | \\\n+\t\t\t\t\t RTL8261X_INT_JABBER)\n+\n+#define FW_MAIN_MAGIC\t\t\t0x52544C38\n+#define FW_SUB_MAGIC_8261C\t\t0x32363143\n+#define RTL8261X_POLL_TIMEOUT_MS\t100\n+\n+#define RTL8261C_CE_FW_NAME\t\"rtl_nic/rtl8261c.bin\"\n+MODULE_FIRMWARE(RTL8261C_CE_FW_NAME);\n+\n+enum rtl8261x_fw_op {\n+\tOP_WRITE = 0x00,\t/* Write */\n+\tOP_POLL = 0x02,\t/* Polling */\n+};\n+\n+struct rtl8261x_fw_header {\n+\t__le32 main_magic;\t/* Main magic number 0x52544C38 (\"RTL8\") */\n+\t__le32 sub_magic;\t/* Sub magic number */\n+\t__le16 version_major;\t/* Major version */\n+\t__le16 version_minor;\t/* Minor version */\n+\t__le16 num_entries;\t/* Number of entries */\n+\t__le16 reserved;\t/* Reserved */\n+\t__le32 crc32;\t\t/* CRC32 checksum */\n+};\n+\n+struct rtl8261x_fw_entry {\n+\t__u8 type;\t\t/* Operation type (OP_*) */\n+\t__u8 dev;\t\t/* MMD device */\n+\t__le16 addr;\t\t/* Register address */\n+\t__u8 msb;\t\t/* MSB bit position */\n+\t__u8 lsb;\t\t/* LSB bit position */\n+\t__le16 value;\t\t/* Value to write/compare */\n+\t__le16 timeout_ms;\t/* Poll timeout in milliseconds */\n+\t__u8 poll_set;\t\t/* Poll for set (1) or clear (0) */\n+\t__u8 reserved;\t\t/* Reserved */\n+};\n+\n+#define FW_HEADER_SIZE\t\tsizeof(struct rtl8261x_fw_header)\n+#define FW_ENTRY_SIZE\t\tsizeof(struct rtl8261x_fw_entry)\n \n /* RTL8211E and RTL8211F support up to three LEDs */\n #define RTL8211x_LED_COUNT\t\t\t3\n@@ -270,6 +338,11 @@ struct rtl821x_priv {\n \tu16 iner;\n };\n \n+struct rtl8261x_priv {\n+\tconst char *fw_name;\n+\tbool fw_loaded;\n+};\n+\n static int rtl821x_read_page(struct phy_device *phydev)\n {\n \treturn __phy_read(phydev, RTL821x_PAGE_SELECT);\n@@ -310,6 +383,326 @@ static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page,\n \treturn phy_restore_page(phydev, oldpage, ret);\n }\n \n+static int rtl8261x_probe(struct phy_device *phydev)\n+{\n+\tstruct device *dev = \u0026phydev-\u003emdio.dev;\n+\tstruct rtl8261x_priv *priv;\n+\tint sub_phy_id, ret;\n+\n+\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tphydev-\u003epriv = priv;\n+\n+\tret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_ADDR_REG,\n+\t\t\t RTL_8261X_SUB_PHY_ID_ADDR);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_DATA_REG);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tsub_phy_id = (ret \u003e\u003e 8) \u0026 0xff;\n+\n+\tswitch (sub_phy_id) {\n+\tcase RTL8261C_CE_MODEL:\n+\t\tpriv-\u003efw_name = RTL8261C_CE_FW_NAME;\n+\t\tphydev_info(phydev, \"RTL8261C detected (sub_id 0x%02x)\\n\", sub_phy_id);\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tphydev_warn(phydev, \"Unknown sub_id 0x%02x, default behavior\\n\", sub_phy_id);\n+\t\treturn -ENODEV;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int rtl8261x_get_features(struct phy_device *phydev)\n+{\n+\tint ret;\n+\n+\tret = genphy_c45_pma_read_abilities(phydev);\n+\tif (ret)\n+\t\treturn ret;\n+\t/*\n+\t * Supplement Multi-Gig speeds that may not be automatically detected\n+\t * RTL8261X supports 2.5G/5G in addition to standard 10G\n+\t */\n+\tlinkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,\n+\t\t\t phydev-\u003esupported);\n+\tlinkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,\n+\t\t\t phydev-\u003esupported);\n+\n+\treturn 0;\n+}\n+\n+static int rtl8261x_read_status(struct phy_device *phydev)\n+{\n+\tint ret, val;\n+\n+\tif (phydev-\u003eautoneg == AUTONEG_ENABLE \u0026\u0026 phydev-\u003eautoneg_complete) {\n+\t\tval = phy_read_mmd(phydev, MDIO_MMD_VEND2,\n+\t\t\t\t RTL822X_VND2_C22_REG(MII_STAT1000));\n+\t\tif (val \u003c 0)\n+\t\t\treturn val;\n+\n+\t\tmii_stat1000_mod_linkmode_lpa_t(phydev-\u003elp_advertising, val);\n+\t}\n+\n+\tret = genphy_c45_read_status(phydev);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+static int rtl8261x_verify_firmware(struct phy_device *phydev, const struct firmware *fw)\n+{\n+\tconst struct rtl8261x_fw_header *hdr;\n+\tu32 main_magic, sub_magic;\n+\tu32 calc_crc, file_crc;\n+\tsize_t data_len;\n+\tu16 num_entries;\n+\n+\tif (fw-\u003esize \u003c FW_HEADER_SIZE) {\n+\t\tphydev_err(phydev, \"Firmware too small: %zu bytes\\n\", fw-\u003esize);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\thdr = (const struct rtl8261x_fw_header *)fw-\u003edata;\n+\n+\tmain_magic = le32_to_cpu(hdr-\u003emain_magic);\n+\tif (main_magic != FW_MAIN_MAGIC) {\n+\t\tphydev_err(phydev, \"Invalid firmware magic: 0x%08x\\n\", main_magic);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tsub_magic = le32_to_cpu(hdr-\u003esub_magic);\n+\tif (sub_magic != FW_SUB_MAGIC_8261C) {\n+\t\tphydev_err(phydev, \"Invalid sub magic: 0x%08x\\n\", sub_magic);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tnum_entries = le16_to_cpu(hdr-\u003enum_entries);\n+\tdata_len = num_entries * FW_ENTRY_SIZE;\n+\n+\tif (fw-\u003esize != sizeof(*hdr) + data_len) {\n+\t\tphydev_err(phydev, \"Firmware size mismatch\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tcalc_crc = crc32(~0, fw-\u003edata + FW_HEADER_SIZE, data_len) ^ ~0;\n+\tfile_crc = le32_to_cpu(hdr-\u003ecrc32);\n+\n+\tif (calc_crc != file_crc) {\n+\t\tphydev_err(phydev, \"CRC32 mismatch: calculated=0x%08x file=0x%08x\\n\",\n+\t\t\t calc_crc, file_crc);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int rtl8261x_fw_execute_entry(struct phy_device *phydev,\n+\t\t\t\t const struct rtl8261x_fw_entry *entry)\n+{\n+\tu16 addr, value, timeout_ms;\n+\tu8 dev, msb, lsb, poll_set;\n+\tu32 bits, expect_val;\n+\tint ret = 0;\n+\tint val;\n+\n+\tdev = entry-\u003edev;\n+\taddr = le16_to_cpu(entry-\u003eaddr);\n+\tmsb = entry-\u003emsb;\n+\tlsb = entry-\u003elsb;\n+\tvalue = le16_to_cpu(entry-\u003evalue);\n+\ttimeout_ms = le16_to_cpu(entry-\u003etimeout_ms);\n+\tpoll_set = entry-\u003epoll_set;\n+\n+\tif (timeout_ms == 0)\n+\t\ttimeout_ms = RTL8261X_POLL_TIMEOUT_MS;\n+\n+\tif (msb \u003e 15 || lsb \u003e msb) {\n+\t\tphydev_err(phydev, \"Invalid firmware bits: msb=%d, lsb=%d\\n\", msb, lsb);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tswitch (entry-\u003etype) {\n+\tcase OP_WRITE:\n+\t\tret = phy_modify_mmd(phydev, dev, addr,\n+\t\t\t\t GENMASK(msb, lsb), (value \u003c\u003c lsb) \u0026 GENMASK(msb, lsb));\n+\t\tif (ret) {\n+\t\t\tphydev_err(phydev, \"WRITE failed: dev=%d addr=0x%04x\\n\", dev, addr);\n+\t\t\treturn ret;\n+\t\t}\n+\t\tbreak;\n+\n+\tcase OP_POLL: {\n+\t\tbits = GENMASK(msb, lsb);\n+\t\texpect_val = (value \u003c\u003c lsb) \u0026 bits;\n+\n+\t\tif (poll_set)\n+\t\t\tret = phy_read_mmd_poll_timeout(phydev, dev, addr, val,\n+\t\t\t\t\t\t\t(val \u0026 bits) == expect_val,\n+\t\t\t\t\t\t\t1000, timeout_ms * 1000, false);\n+\t\telse\n+\t\t\tret = phy_read_mmd_poll_timeout(phydev, dev, addr, val,\n+\t\t\t\t\t\t\t(val \u0026 bits) != expect_val,\n+\t\t\t\t\t\t\t1000, timeout_ms * 1000, false);\n+\t\tif (ret)\n+\t\t\tphydev_err(phydev, \"POLL timeout: dev=%d addr=0x%04x\\n\",\n+\t\t\t\t dev, addr);\n+\t\tbreak;\n+\t}\n+\tdefault:\n+\t\tphydev_err(phydev, \"Unknown firmware operation: %d\\n\", entry-\u003etype);\n+\t\tret = -EINVAL;\n+\t\tbreak;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int rtl8261x_fw_load(struct phy_device *phydev)\n+{\n+\tstruct rtl8261x_priv *priv = phydev-\u003epriv;\n+\tconst struct rtl8261x_fw_entry *entry;\n+\tconst struct rtl8261x_fw_header *hdr;\n+\tconst struct firmware *fw;\n+\tint ret, i;\n+\n+\tif (!priv-\u003efw_name)\n+\t\treturn 0;\n+\n+\tret = request_firmware(\u0026fw, priv-\u003efw_name, \u0026phydev-\u003emdio.dev);\n+\tif (ret) {\n+\t\tphydev_err(phydev, \"Failed to load firmware %s: %d\\n\", priv-\u003efw_name, ret);\n+\t\treturn ret;\n+\t}\n+\n+\tret = rtl8261x_verify_firmware(phydev, fw);\n+\tif (ret)\n+\t\tgoto release_fw;\n+\n+\thdr = (const struct rtl8261x_fw_header *)fw-\u003edata;\n+\n+\tentry = (const struct rtl8261x_fw_entry *)(fw-\u003edata + FW_HEADER_SIZE);\n+\tfor (i = 0; i \u003c le16_to_cpu(hdr-\u003enum_entries); i++, entry++) {\n+\t\tret = rtl8261x_fw_execute_entry(phydev, entry);\n+\t\tif (ret) {\n+\t\t\tphydev_err(phydev, \"Entry %d failed: %d\\n\", i, ret);\n+\t\t\tgoto release_fw;\n+\t\t}\n+\t}\n+\n+\tpriv-\u003efw_loaded = true;\n+\n+release_fw:\n+\trelease_firmware(fw);\n+\treturn ret;\n+}\n+\n+static int rtl8261x_config_intr(struct phy_device *phydev)\n+{\n+\tint ret;\n+\n+\tif (phydev-\u003einterrupts == PHY_INTERRUPT_ENABLED) {\n+\t\tret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\tret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER,\n+\t\t\t\t RTL8261X_INT_MASK_DEFAULT);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t} else {\n+\t\tret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER, 0);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\tret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static irqreturn_t rtl8261x_handle_interrupt(struct phy_device *phydev)\n+{\n+\tint irq_status;\n+\n+\tirq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);\n+\tif (irq_status \u003c 0) {\n+\t\tphy_error(phydev);\n+\t\treturn IRQ_NONE;\n+\t}\n+\n+\tif (!(irq_status \u0026 RTL8261X_INT_MASK_ALL))\n+\t\treturn IRQ_NONE;\n+\n+\tif (irq_status \u0026 (RTL8261X_INT_LINK_CHG | RTL8261X_INT_AUTONEG_DONE |\n+\t RTL8261X_INT_AUTONEG_ERROR | RTL8261X_INT_JABBER))\n+\t\tphy_trigger_machine(phydev);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int rtl8261x_config_aneg(struct phy_device *phydev)\n+{\n+\tu16 adv_1g = 0;\n+\tint ret;\n+\n+\tret = genphy_c45_config_aneg(phydev);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tif (phydev-\u003eautoneg == AUTONEG_DISABLE)\n+\t\treturn 0;\n+\n+\tif (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,\n+\t\t\t phydev-\u003eadvertising))\n+\t\tadv_1g = ADVERTISE_1000FULL;\n+\tif (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,\n+\t\t\t phydev-\u003eadvertising))\n+\t\tadv_1g |= ADVERTISE_1000HALF;\n+\n+\tret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2,\n+\t\t\t\t RTL822X_VND2_C22_REG(MII_CTRL1000),\n+\t\t\t\t ADVERTISE_1000FULL | ADVERTISE_1000HALF,\n+\t\t\t\t adv_1g);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\tif (ret \u003e 0)\n+\t\treturn genphy_c45_restart_aneg(phydev);\n+\n+\treturn 0;\n+}\n+\n+static int rtl8261x_config_init(struct phy_device *phydev)\n+{\n+\tstruct rtl8261x_priv *priv = phydev-\u003epriv;\n+\tint ret = 0;\n+\n+\t/* The firmware parameters are preserved across IEEE soft resets and\n+\t * suspend/resume cycles. Reloading is only necessary after a power\n+\t * cycle or hard reset.\n+\t */\n+\tif (priv-\u003efw_name \u0026\u0026 !priv-\u003efw_loaded) {\n+\t\tret = rtl8261x_fw_load(phydev);\n+\t\tif (ret) {\n+\t\t\tphydev_err(phydev, \"Firmware loading failed: %d\\n\", ret);\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n static int rtl821x_probe(struct phy_device *phydev)\n {\n \tstruct device *dev = \u0026phydev-\u003emdio.dev;\n@@ -3001,6 +3394,19 @@ static struct phy_driver realtek_drvs[] = {\n \t\t.resume\t\t= genphy_resume,\n \t\t.read_mmd\t= genphy_read_mmd_unsupported,\n \t\t.write_mmd\t= genphy_write_mmd_unsupported,\n+\t}, {\n+\t\tPHY_ID_MATCH_EXACT(RTL_8261C_CG),\n+\t\t.name\t\t\t= \"Realtek RTL8261C 10Gbps PHY\",\n+\t\t.probe\t\t\t= rtl8261x_probe,\n+\t\t.config_init\t\t= rtl8261x_config_init,\n+\t\t.get_features\t\t= rtl8261x_get_features,\n+\t\t.config_aneg\t\t= rtl8261x_config_aneg,\n+\t\t.read_status\t\t= rtl8261x_read_status,\n+\t\t.config_intr\t\t= rtl8261x_config_intr,\n+\t\t.handle_interrupt\t= rtl8261x_handle_interrupt,\n+\t\t.soft_reset\t\t= genphy_c45_soft_reset,\n+\t\t.suspend\t\t= genphy_c45_pma_suspend,\n+\t\t.resume\t\t\t= genphy_c45_pma_resume,\n \t},\n };\n \ndiff --git a/include/linux/phy.h b/include/linux/phy.h\nindex 199a7aaa341bfd..25a66320df56ea 100644\n--- a/include/linux/phy.h\n+++ b/include/linux/phy.h\n@@ -2309,6 +2309,7 @@ int genphy_c37_read_status(struct phy_device *phydev, bool *changed);\n /* Clause 45 PHY */\n int genphy_c45_restart_aneg(struct phy_device *phydev);\n int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart);\n+int genphy_c45_soft_reset(struct phy_device *phydev);\n int genphy_c45_aneg_done(struct phy_device *phydev);\n int genphy_c45_read_link(struct phy_device *phydev);\n int genphy_c45_read_lpa(struct phy_device *phydev);\ndiff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h\nindex b2541c948fc1eb..06f4bc3c20c717 100644\n--- a/include/uapi/linux/mdio.h\n+++ b/include/uapi/linux/mdio.h\n@@ -332,8 +332,13 @@\n #define MDIO_AN_10GBT_CTRL_ADV2_5G\t0x0080\t/* Advertise 2.5GBASE-T */\n #define MDIO_AN_10GBT_CTRL_ADV5G\t0x0100\t/* Advertise 5GBASE-T */\n #define MDIO_AN_10GBT_CTRL_ADV10G\t0x1000\t/* Advertise 10GBASE-T */\n+#define MDIO_AN_10GBT_CTRL_MS_ENABLE\t0x8000\t/* Master/slave manual config enable */\n+#define MDIO_AN_10GBT_CTRL_MS_VALUE\t0x4000\t/* Master/slave config value (1=Master) */\n+#define MDIO_AN_10GBT_CTRL_MS_PORT_TYPE\t0x2000\t/* Master Preferred Type */\n \n /* AN 10GBASE-T status register. */\n+#define MDIO_AN_10GBT_STAT_MS_FAULT\t0x8000\t/* Master/slave fault */\n+#define MDIO_AN_10GBT_STAT_MS_RES\t0x4000\t/* Master/slave resolution (1=Master) */\n #define MDIO_AN_10GBT_STAT_LP2_5G\t0x0020 /* LP is 2.5GBT capable */\n #define MDIO_AN_10GBT_STAT_LP5G\t\t0x0040 /* LP is 5GBT capable */\n #define MDIO_AN_10GBT_STAT_LPTRR\t0x0200\t/* LP training reset req. */\n"
} |
| 2/1 | 2026/06/29 07:18 | agent | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"REALTEK_PHY"
],
"FocusSymbols": [
"genphy_c45_soft_reset",
"genphy_c45_an_setup_master_slave",
"genphy_c45_read_master_slave",
"rtl8261x_probe",
"rtl8261x_get_features",
"rtl8261x_read_status",
"rtl8261x_verify_firmware",
"rtl8261x_fw_execute_entry",
"rtl8261x_fw_load",
"rtl8261x_config_intr",
"rtl8261x_handle_interrupt",
"rtl8261x_config_aneg",
"rtl8261x_config_init"
],
"Reasoning": "The patch adds new Master/Slave configuration logic for Clause 45 PHYs and introduces a new Realtek PHY driver (RTL8261C) with firmware loading capabilities. These features are reachable via MDIO bus emulation (e.g., through USB network device emulation) and contain complex logic that should be fuzzed.",
"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 62314e504a92ecba59ca55e4fd0ebc559e4590bc
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jun 29 07:18:43 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 1269517414288f..df682d3ebd5a1d 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -384,6 +384,119 @@ int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
}
EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
+/**
+ * genphy_c45_soft_reset - software reset the PHY via Clause 45 PMA/PMD control register
+ * @phydev: target phy_device struct
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int genphy_c45_soft_reset(struct phy_device *phydev)
+{
+ int ret, val;
+
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+ MDIO_CTRL1_RESET);
+ if (ret < 0)
+ return ret;
+
+ return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_PMAPMD,
+ MDIO_CTRL1, val,
+ !(val & MDIO_CTRL1_RESET),
+ 5000, 600000, true);
+}
+EXPORT_SYMBOL_GPL(genphy_c45_soft_reset);
+
+/**
+ * genphy_c45_an_setup_master_slave - Configure Master/Slave setting for C45 PHYs
+ * @phydev: target phy_device struct
+ *
+ * Description: Configure the forced or preferred Master/Slave role
+ * 10GBASE-T control register (MMD 7, Register 0x0020) according to
+ * IEEE 802.3 standards.
+ *
+ * Return: negative errno code on failure, 0 if Master/Slave didn't change,
+ * or 1 if Master/Slave modes changed.
+ */
+static int genphy_c45_an_setup_master_slave(struct phy_device *phydev)
+{
+ u16 ctl = 0;
+
+ switch (phydev->master_slave_set) {
+ case MASTER_SLAVE_CFG_MASTER_PREFERRED:
+ ctl = MDIO_AN_10GBT_CTRL_MS_PORT_TYPE;
+ break;
+ case MASTER_SLAVE_CFG_SLAVE_PREFERRED:
+ break;
+ case MASTER_SLAVE_CFG_MASTER_FORCE:
+ ctl = MDIO_AN_10GBT_CTRL_MS_ENABLE | MDIO_AN_10GBT_CTRL_MS_VALUE;
+ break;
+ case MASTER_SLAVE_CFG_SLAVE_FORCE:
+ ctl = MDIO_AN_10GBT_CTRL_MS_ENABLE;
+ break;
+ case MASTER_SLAVE_CFG_UNKNOWN:
+ case MASTER_SLAVE_CFG_UNSUPPORTED:
+ return 0;
+ default:
+ phydev_warn(phydev, "Unsupported Master/Slave mode\n");
+ return -EOPNOTSUPP;
+ }
+
+ return phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
+ MDIO_AN_10GBT_CTRL_MS_ENABLE |
+ MDIO_AN_10GBT_CTRL_MS_VALUE |
+ MDIO_AN_10GBT_CTRL_MS_PORT_TYPE, ctl);
+}
+
+/**
+ * genphy_c45_read_master_slave - read master/slave status
+ * @phydev: target phy_device struct
+ *
+ * Description: Read the Master/Slave configuration and status
+ * from 10GBASE-T control/status registers (MMD 7, Reg 0x0020 and 0x0021).
+ *
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int genphy_c45_read_master_slave(struct phy_device *phydev)
+{
+ int val;
+
+ phydev->master_slave_get = MASTER_SLAVE_CFG_UNKNOWN;
+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL);
+ if (val < 0)
+ return val;
+
+ if (val & MDIO_AN_10GBT_CTRL_MS_ENABLE) {
+ if (val & MDIO_AN_10GBT_CTRL_MS_VALUE)
+ phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_FORCE;
+ else
+ phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_FORCE;
+ } else {
+ if (val & MDIO_AN_10GBT_CTRL_MS_PORT_TYPE)
+ phydev->master_slave_get = MASTER_SLAVE_CFG_MASTER_PREFERRED;
+ else
+ phydev->master_slave_get = MASTER_SLAVE_CFG_SLAVE_PREFERRED;
+ }
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_STAT);
+ if (val < 0)
+ return val;
+
+ if (val & MDIO_AN_10GBT_STAT_MS_FAULT) {
+ phydev->master_slave_state = MASTER_SLAVE_STATE_ERR;
+ } else if (phydev->link) {
+ if (val & MDIO_AN_10GBT_STAT_MS_RES)
+ phydev->master_slave_state = MASTER_SLAVE_STATE_MASTER;
+ else
+ phydev->master_slave_state = MASTER_SLAVE_STATE_SLAVE;
+ } else {
+ phydev->master_slave_state = MASTER_SLAVE_STATE_UNKNOWN;
+ }
+
+ return 0;
+}
+
/**
* genphy_c45_aneg_done - return auto-negotiation complete status
* @phydev: target phy_device struct
@@ -1192,6 +1305,10 @@ int genphy_c45_read_status(struct phy_device *phydev)
ret = genphy_c45_baset1_read_status(phydev);
if (ret < 0)
return ret;
+ } else {
+ ret = genphy_c45_read_master_slave(phydev);
+ if (ret < 0)
+ return ret;
}
phy_resolve_aneg_linkmode(phydev);
@@ -1225,6 +1342,14 @@ int genphy_c45_config_aneg(struct phy_device *phydev)
if (ret > 0)
changed = true;
+ if (!genphy_c45_baset1_able(phydev)) {
+ ret = genphy_c45_an_setup_master_slave(phydev);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ changed = true;
+ }
+
return genphy_c45_check_and_restart_aneg(phydev, changed);
}
EXPORT_SYMBOL_GPL(genphy_c45_config_aneg);
diff --git a/drivers/net/phy/realtek/realtek_main.c b/drivers/net/phy/realtek/realtek_main.c
index 27268811f564f2..bf7bc19fb44cd2 100644
--- a/drivers/net/phy/realtek/realtek_main.c
+++ b/drivers/net/phy/realtek/realtek_main.c
@@ -8,7 +8,9 @@
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*/
#include <linux/bitops.h>
+#include <linux/crc32.h>
#include <linux/ethtool_netlink.h>
+#include <linux/firmware.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/pm_wakeirq.h>
@@ -141,6 +143,10 @@
#define RTL8211F_PHYSICAL_ADDR_WORD1 17
#define RTL8211F_PHYSICAL_ADDR_WORD2 18
+#define RTL8261X_EXT_ADDR_REG 0xa436
+#define RTL8261X_EXT_DATA_REG 0xa438
+#define RTL_8261X_SUB_PHY_ID_ADDR 0x801d
+
#define RTL822X_VND1_SERDES_OPTION 0x697a
#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0
@@ -251,6 +257,68 @@
#define RTL_8221B_VM_CG 0x001cc84a
#define RTL_8251B 0x001cc862
#define RTL_8261C 0x001cc890
+#define RTL_8261C_CG 0x001cc898
+
+#define RTL8261C_CE_MODEL 0x00
+#define RTL8261X_INT_AUTONEG_ERROR BIT(0)
+#define RTL8261X_INT_PAGE_RECV BIT(2)
+#define RTL8261X_INT_AUTONEG_DONE BIT(3)
+#define RTL8261X_INT_LINK_CHG BIT(4)
+#define RTL8261X_INT_PHY_REG_ACCESS BIT(5)
+#define RTL8261X_INT_PME BIT(7)
+#define RTL8261X_INT_ALDPS_CHG BIT(9)
+#define RTL8261X_INT_JABBER BIT(10)
+
+#define RTL8261X_INT_MASK_DEFAULT (RTL8261X_INT_AUTONEG_DONE | \
+ RTL8261X_INT_LINK_CHG | \
+ RTL8261X_INT_AUTONEG_ERROR | \
+ RTL8261X_INT_JABBER)
+
+#define RTL8261X_INT_MASK_ALL (RTL8261X_INT_AUTONEG_ERROR | \
+ RTL8261X_INT_PAGE_RECV | \
+ RTL8261X_INT_AUTONEG_DONE | \
+ RTL8261X_INT_LINK_CHG | \
+ RTL8261X_INT_PHY_REG_ACCESS | \
+ RTL8261X_INT_PME | \
+ RTL8261X_INT_ALDPS_CHG | \
+ RTL8261X_INT_JABBER)
+
+#define FW_MAIN_MAGIC 0x52544C38
+#define FW_SUB_MAGIC_8261C 0x32363143
+#define RTL8261X_POLL_TIMEOUT_MS 100
+
+#define RTL8261C_CE_FW_NAME "rtl_nic/rtl8261c.bin"
+MODULE_FIRMWARE(RTL8261C_CE_FW_NAME);
+
+enum rtl8261x_fw_op {
+ OP_WRITE = 0x00, /* Write */
+ OP_POLL = 0x02, /* Polling */
+};
+
+struct rtl8261x_fw_header {
+ __le32 main_magic; /* Main magic number 0x52544C38 ("RTL8") */
+ __le32 sub_magic; /* Sub magic number */
+ __le16 version_major; /* Major version */
+ __le16 version_minor; /* Minor version */
+ __le16 num_entries; /* Number of entries */
+ __le16 reserved; /* Reserved */
+ __le32 crc32; /* CRC32 checksum */
+};
+
+struct rtl8261x_fw_entry {
+ __u8 type; /* Operation type (OP_*) */
+ __u8 dev; /* MMD device */
+ __le16 addr; /* Register address */
+ __u8 msb; /* MSB bit position */
+ __u8 lsb; /* LSB bit position */
+ __le16 value; /* Value to write/compare */
+ __le16 timeout_ms; /* Poll timeout in milliseconds */
+ __u8 poll_set; /* Poll for set (1) or clear (0) */
+ __u8 reserved; /* Reserved */
+};
+
+#define FW_HEADER_SIZE sizeof(struct rtl8261x_fw_header)
+#define FW_ENTRY_SIZE sizeof(struct rtl8261x_fw_entry)
/* RTL8211E and RTL8211F support up to three LEDs */
#define RTL8211x_LED_COUNT 3
@@ -270,6 +338,11 @@ struct rtl821x_priv {
u16 iner;
};
+struct rtl8261x_priv {
+ const char *fw_name;
+ bool fw_loaded;
+};
+
static int rtl821x_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, RTL821x_PAGE_SELECT);
@@ -310,6 +383,326 @@ static int rtl821x_modify_ext_page(struct phy_device *phydev, u16 ext_page,
return phy_restore_page(phydev, oldpage, ret);
}
+static int rtl8261x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct rtl8261x_priv *priv;
+ int sub_phy_id, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_ADDR_REG,
+ RTL_8261X_SUB_PHY_ID_ADDR);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_DATA_REG);
+ if (ret < 0)
+ return ret;
+
+ sub_phy_id = (ret >> 8) & 0xff;
+
+ switch (sub_phy_id) {
+ case RTL8261C_CE_MODEL:
+ priv->fw_name = RTL8261C_CE_FW_NAME;
+ phydev_info(phydev, "RTL8261C detected (sub_id 0x%02x)\n", sub_phy_id);
+ break;
+
+ default:
+ phydev_warn(phydev, "Unknown sub_id 0x%02x, default behavior\n", sub_phy_id);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int rtl8261x_get_features(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = genphy_c45_pma_read_abilities(phydev);
+ if (ret)
+ return ret;
+ /*
+ * Supplement Multi-Gig speeds that may not be automatically detected
+ * RTL8261X supports 2.5G/5G in addition to standard 10G
+ */
+ linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ phydev->supported);
+
+ return 0;
+}
+
+static int rtl8261x_read_status(struct phy_device *phydev)
+{
+ int ret, val;
+
+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ RTL822X_VND2_C22_REG(MII_STAT1000));
+ if (val < 0)
+ return val;
+
+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
+ }
+
+ ret = genphy_c45_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rtl8261x_verify_firmware(struct phy_device *phydev, const struct firmware *fw)
+{
+ const struct rtl8261x_fw_header *hdr;
+ u32 main_magic, sub_magic;
+ u32 calc_crc, file_crc;
+ size_t data_len;
+ u16 num_entries;
+
+ if (fw->size < FW_HEADER_SIZE) {
+ phydev_err(phydev, "Firmware too small: %zu bytes\n", fw->size);
+ return -EINVAL;
+ }
+
+ hdr = (const struct rtl8261x_fw_header *)fw->data;
+
+ main_magic = le32_to_cpu(hdr->main_magic);
+ if (main_magic != FW_MAIN_MAGIC) {
+ phydev_err(phydev, "Invalid firmware magic: 0x%08x\n", main_magic);
+ return -EINVAL;
+ }
+
+ sub_magic = le32_to_cpu(hdr->sub_magic);
+ if (sub_magic != FW_SUB_MAGIC_8261C) {
+ phydev_err(phydev, "Invalid sub magic: 0x%08x\n", sub_magic);
+ return -EINVAL;
+ }
+
+ num_entries = le16_to_cpu(hdr->num_entries);
+ data_len = num_entries * FW_ENTRY_SIZE;
+
+ if (fw->size != sizeof(*hdr) + data_len) {
+ phydev_err(phydev, "Firmware size mismatch\n");
+ return -EINVAL;
+ }
+
+ calc_crc = crc32(~0, fw->data + FW_HEADER_SIZE, data_len) ^ ~0;
+ file_crc = le32_to_cpu(hdr->crc32);
+
+ if (calc_crc != file_crc) {
+ phydev_err(phydev, "CRC32 mismatch: calculated=0x%08x file=0x%08x\n",
+ calc_crc, file_crc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rtl8261x_fw_execute_entry(struct phy_device *phydev,
+ const struct rtl8261x_fw_entry *entry)
+{
+ u16 addr, value, timeout_ms;
+ u8 dev, msb, lsb, poll_set;
+ u32 bits, expect_val;
+ int ret = 0;
+ int val;
+
+ dev = entry->dev;
+ addr = le16_to_cpu(entry->addr);
+ msb = entry->msb;
+ lsb = entry->lsb;
+ value = le16_to_cpu(entry->value);
+ timeout_ms = le16_to_cpu(entry->timeout_ms);
+ poll_set = entry->poll_set;
+
+ if (timeout_ms == 0)
+ timeout_ms = RTL8261X_POLL_TIMEOUT_MS;
+
+ if (msb > 15 || lsb > msb) {
+ phydev_err(phydev, "Invalid firmware bits: msb=%d, lsb=%d\n", msb, lsb);
+ return -EINVAL;
+ }
+
+ switch (entry->type) {
+ case OP_WRITE:
+ ret = phy_modify_mmd(phydev, dev, addr,
+ GENMASK(msb, lsb), (value << lsb) & GENMASK(msb, lsb));
+ if (ret) {
+ phydev_err(phydev, "WRITE failed: dev=%d addr=0x%04x\n", dev, addr);
+ return ret;
+ }
+ break;
+
+ case OP_POLL: {
+ bits = GENMASK(msb, lsb);
+ expect_val = (value << lsb) & bits;
+
+ if (poll_set)
+ ret = phy_read_mmd_poll_timeout(phydev, dev, addr, val,
+ (val & bits) == expect_val,
+ 1000, timeout_ms * 1000, false);
+ else
+ ret = phy_read_mmd_poll_timeout(phydev, dev, addr, val,
+ (val & bits) != expect_val,
+ 1000, timeout_ms * 1000, false);
+ if (ret)
+ phydev_err(phydev, "POLL timeout: dev=%d addr=0x%04x\n",
+ dev, addr);
+ break;
+ }
+ default:
+ phydev_err(phydev, "Unknown firmware operation: %d\n", entry->type);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int rtl8261x_fw_load(struct phy_device *phydev)
+{
+ struct rtl8261x_priv *priv = phydev->priv;
+ const struct rtl8261x_fw_entry *entry;
+ const struct rtl8261x_fw_header *hdr;
+ const struct firmware *fw;
+ int ret, i;
+
+ if (!priv->fw_name)
+ return 0;
+
+ ret = request_firmware(&fw, priv->fw_name, &phydev->mdio.dev);
+ if (ret) {
+ phydev_err(phydev, "Failed to load firmware %s: %d\n", priv->fw_name, ret);
+ return ret;
+ }
+
+ ret = rtl8261x_verify_firmware(phydev, fw);
+ if (ret)
+ goto release_fw;
+
+ hdr = (const struct rtl8261x_fw_header *)fw->data;
+
+ entry = (const struct rtl8261x_fw_entry *)(fw->data + FW_HEADER_SIZE);
+ for (i = 0; i < le16_to_cpu(hdr->num_entries); i++, entry++) {
+ ret = rtl8261x_fw_execute_entry(phydev, entry);
+ if (ret) {
+ phydev_err(phydev, "Entry %d failed: %d\n", i, ret);
+ goto release_fw;
+ }
+ }
+
+ priv->fw_loaded = true;
+
+release_fw:
+ release_firmware(fw);
+ return ret;
+}
+
+static int rtl8261x_config_intr(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER,
+ RTL8261X_INT_MASK_DEFAULT);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INER, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t rtl8261x_handle_interrupt(struct phy_device *phydev)
+{
+ int irq_status;
+
+ irq_status = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8221B_VND2_INSR);
+ if (irq_status < 0) {
+ phy_error(phydev);
+ return IRQ_NONE;
+ }
+
+ if (!(irq_status & RTL8261X_INT_MASK_ALL))
+ return IRQ_NONE;
+
+ if (irq_status & (RTL8261X_INT_LINK_CHG | RTL8261X_INT_AUTONEG_DONE |
+ RTL8261X_INT_AUTONEG_ERROR | RTL8261X_INT_JABBER))
+ phy_trigger_machine(phydev);
+
+ return IRQ_HANDLED;
+}
+
+static int rtl8261x_config_aneg(struct phy_device *phydev)
+{
+ u16 adv_1g = 0;
+ int ret;
+
+ ret = genphy_c45_config_aneg(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_DISABLE)
+ return 0;
+
+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+ phydev->advertising))
+ adv_1g = ADVERTISE_1000FULL;
+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
+ phydev->advertising))
+ adv_1g |= ADVERTISE_1000HALF;
+
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2,
+ RTL822X_VND2_C22_REG(MII_CTRL1000),
+ ADVERTISE_1000FULL | ADVERTISE_1000HALF,
+ adv_1g);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ return genphy_c45_restart_aneg(phydev);
+
+ return 0;
+}
+
+static int rtl8261x_config_init(struct phy_device *phydev)
+{
+ struct rtl8261x_priv *priv = phydev->priv;
+ int ret = 0;
+
+ /* The firmware parameters are preserved across IEEE soft resets and
+ * suspend/resume cycles. Reloading is only necessary after a power
+ * cycle or hard reset.
+ */
+ if (priv->fw_name && !priv->fw_loaded) {
+ ret = rtl8261x_fw_load(phydev);
+ if (ret) {
+ phydev_err(phydev, "Firmware loading failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
static int rtl821x_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -3001,6 +3394,19 @@ static struct phy_driver realtek_drvs[] = {
.resume = genphy_resume,
.read_mmd = genphy_read_mmd_unsupported,
.write_mmd = genphy_write_mmd_unsupported,
+ }, {
+ PHY_ID_MATCH_EXACT(RTL_8261C_CG),
+ .name = "Realtek RTL8261C 10Gbps PHY",
+ .probe = rtl8261x_probe,
+ .config_init = rtl8261x_config_init,
+ .get_features = rtl8261x_get_features,
+ .config_aneg = rtl8261x_config_aneg,
+ .read_status = rtl8261x_read_status,
+ .config_intr = rtl8261x_config_intr,
+ .handle_interrupt = rtl8261x_handle_interrupt,
+ .soft_reset = genphy_c45_soft_reset,
+ .suspend = genphy_c45_pma_suspend,
+ .resume = genphy_c45_pma_resume,
},
};
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 199a7aaa341bfd..25a66320df56ea 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -2309,6 +2309,7 @@ int genphy_c37_read_status(struct phy_device *phydev, bool *changed);
/* Clause 45 PHY */
int genphy_c45_restart_aneg(struct phy_device *phydev);
int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart);
+int genphy_c45_soft_reset(struct phy_device *phydev);
int genphy_c45_aneg_done(struct phy_device *phydev);
int genphy_c45_read_link(struct phy_device *phydev);
int genphy_c45_read_lpa(struct phy_device *phydev);
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index b2541c948fc1eb..06f4bc3c20c717 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -332,8 +332,13 @@
#define MDIO_AN_10GBT_CTRL_ADV2_5G 0x0080 /* Advertise 2.5GBASE-T */
#define MDIO_AN_10GBT_CTRL_ADV5G 0x0100 /* Advertise 5GBASE-T */
#define MDIO_AN_10GBT_CTRL_ADV10G 0x1000 /* Advertise 10GBASE-T */
+#define MDIO_AN_10GBT_CTRL_MS_ENABLE 0x8000 /* Master/slave manual config enable */
+#define MDIO_AN_10GBT_CTRL_MS_VALUE 0x4000 /* Master/slave config value (1=Master) */
+#define MDIO_AN_10GBT_CTRL_MS_PORT_TYPE 0x2000 /* Master Preferred Type */
/* AN 10GBASE-T status register. */
+#define MDIO_AN_10GBT_STAT_MS_FAULT 0x8000 /* Master/slave fault */
+#define MDIO_AN_10GBT_STAT_MS_RES 0x4000 /* Master/slave resolution (1=Master) */
#define MDIO_AN_10GBT_STAT_LP2_5G 0x0020 /* LP is 2.5GBT capable */
#define MDIO_AN_10GBT_STAT_LP5G 0x0040 /* LP is 5GBT capable */
#define MDIO_AN_10GBT_STAT_LPTRR 0x0200 /* LP training reset req. */
|
| 3/2 | 2026/06/29 07:18 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10269 output: 19 thoughts: 542 Thoughts: **Analyzing the RTL8261C PHY Patch for Fuzzing Potential** Okay, so we have this patch adding support for the Realtek RTL8261C 10Gbps PHY. It looks like it's touching `drivers/net/phy/phy-c45.c` and `drivers/net/phy/realtek/realtek_main.c`, adding functions like `genphy_c45_soft_reset`, `rtl8261x_probe`, `rtl8261x_fw_load`, and driver registration for `RTL_8261C_CG`. My immediate thought is, can this be fuzzed? That's the key question. Given my experience, I know PHY drivers are typically probed via an MDIO bus. So, the first thing I need to figure out is, can we emulate this PHY somehow in a virtualized environment, like with QEMU? Syzkaller is the obvious choice for fuzzing, but how do we get it to reach this code? I need to remember how syzkaller handles PHY drivers. Does it natively support MDIO injection? I don't *think* it does. Perhaps through some netlink interface or another indirect approach? Wait, is there something like `mdio-mockup` or maybe something like `mac80211_hwsim` that could be leveraged? No, that's more for wireless. This is an Ethernet PHY. Right. So, syzkaller *can* fuzz PHYs, but only if there's a way to instantiate them. Okay, let's see if syzkaller has *any* MDIO bus fuzzing capabilities. I don't recall seeing anything specific. Can userspace instantiate a PHY? Usually, it's the MAC driver or the device tree, that's what I've seen. Hold on. Let's see... the `rtl8261x_fw_load` function looks interesting. It uses `request_firmware`, and if that's reachable, then this code is definitely worth fuzzing. Reaching firmware loading often involves some interesting attack surfaces. Right, time to check if `REALTEK_PHY` is even enabled in the syzkaller configs. Gotta start there. Let's do a search for `REALTEK_PHY`. |
| 4/2 | 2026/06/29 07:18 | tool | grepper |
0mArgs:{
"Expression": "REALTEK_PHY"
}Results: {
"Output": "Documentation/networking/device_drivers/ethernet/freescale/dpaa.rst=119=To enable the DPAA Ethernet driver, the following Kconfig options are required::\n--\nDocumentation/networking/device_drivers/ethernet/freescale/dpaa.rst-131- CONFIG_VITESSE_PHY=y\nDocumentation/networking/device_drivers/ethernet/freescale/dpaa.rst:132: CONFIG_REALTEK_PHY=y\nDocumentation/networking/device_drivers/ethernet/freescale/dpaa.rst-133- CONFIG_AQUANTIA_PHY=y\n--\narch/arm/configs/aspeed_g4_defconfig=107=CONFIG_BROADCOM_PHY=y\narch/arm/configs/aspeed_g4_defconfig:108:CONFIG_REALTEK_PHY=y\narch/arm/configs/aspeed_g4_defconfig-109-# CONFIG_USB_NET_DRIVERS is not set\n--\narch/arm/configs/aspeed_g5_defconfig=124=CONFIG_BROADCOM_PHY=y\narch/arm/configs/aspeed_g5_defconfig:125:CONFIG_REALTEK_PHY=y\narch/arm/configs/aspeed_g5_defconfig-126-CONFIG_MCTP_SERIAL=y\n--\narch/arm/configs/moxart_defconfig=63=CONFIG_ARM_MOXART_ETHER=y\n--\narch/arm/configs/moxart_defconfig-69-# CONFIG_NET_VENDOR_WIZNET is not set\narch/arm/configs/moxart_defconfig:70:CONFIG_REALTEK_PHY=y\narch/arm/configs/moxart_defconfig-71-CONFIG_MDIO_MOXART=y\n--\narch/arm/configs/mxs_defconfig=57=CONFIG_MICREL_PHY=y\narch/arm/configs/mxs_defconfig:58:CONFIG_REALTEK_PHY=y\narch/arm/configs/mxs_defconfig-59-CONFIG_CAN_FLEXCAN=m\n--\narch/arm/configs/sunxi_defconfig=52=CONFIG_MICREL_PHY=y\narch/arm/configs/sunxi_defconfig:53:CONFIG_REALTEK_PHY=y\narch/arm/configs/sunxi_defconfig-54-CONFIG_CAN_SUN4I=y\n--\narch/arm/configs/wpcm450_defconfig=57=CONFIG_NETDEVICES=y\n--\narch/arm/configs/wpcm450_defconfig-94-# CONFIG_NET_VENDOR_XILINX is not set\narch/arm/configs/wpcm450_defconfig:95:CONFIG_REALTEK_PHY=y\narch/arm/configs/wpcm450_defconfig-96-# CONFIG_WLAN is not set\n--\narch/arm64/configs/defconfig=469=CONFIG_QCA808X_PHY=m\narch/arm64/configs/defconfig:470:CONFIG_REALTEK_PHY=y\narch/arm64/configs/defconfig-471-CONFIG_ROCKCHIP_PHY=y\n--\narch/mips/configs/ip22_defconfig=207=CONFIG_QSEMI_PHY=m\narch/mips/configs/ip22_defconfig:208:CONFIG_REALTEK_PHY=m\narch/mips/configs/ip22_defconfig-209-CONFIG_HOSTAP=m\n--\narch/mips/configs/ip27_defconfig=174=CONFIG_QSEMI_PHY=m\narch/mips/configs/ip27_defconfig:175:CONFIG_REALTEK_PHY=m\narch/mips/configs/ip27_defconfig-176-CONFIG_SMSC_PHY=m\n--\narch/mips/configs/loongson1_defconfig=97=CONFIG_DAVICOM_PHY=y\narch/mips/configs/loongson1_defconfig:98:CONFIG_REALTEK_PHY=y\narch/mips/configs/loongson1_defconfig-99-# CONFIG_USB_NET_DRIVERS is not set\n--\narch/mips/configs/malta_defconfig=282=CONFIG_QSEMI_PHY=m\narch/mips/configs/malta_defconfig:283:CONFIG_REALTEK_PHY=m\narch/mips/configs/malta_defconfig-284-CONFIG_SMSC_PHY=m\n--\narch/mips/configs/malta_kvm_defconfig=289=CONFIG_QSEMI_PHY=m\narch/mips/configs/malta_kvm_defconfig:290:CONFIG_REALTEK_PHY=m\narch/mips/configs/malta_kvm_defconfig-291-CONFIG_SMSC_PHY=m\n--\narch/mips/configs/maltaup_xpa_defconfig=288=CONFIG_QSEMI_PHY=m\narch/mips/configs/maltaup_xpa_defconfig:289:CONFIG_REALTEK_PHY=m\narch/mips/configs/maltaup_xpa_defconfig-290-CONFIG_SMSC_PHY=m\n--\narch/parisc/configs/generic-64bit_defconfig=142=CONFIG_QSEMI_PHY=m\narch/parisc/configs/generic-64bit_defconfig:143:CONFIG_REALTEK_PHY=m\narch/parisc/configs/generic-64bit_defconfig-144-CONFIG_SMSC_PHY=m\n--\narch/powerpc/configs/mpc512x_defconfig=66=CONFIG_QSEMI_PHY=y\narch/powerpc/configs/mpc512x_defconfig:67:CONFIG_REALTEK_PHY=y\narch/powerpc/configs/mpc512x_defconfig-68-CONFIG_SMSC_PHY=y\n--\narch/powerpc/configs/ppc6xx_defconfig=467=CONFIG_QSEMI_PHY=m\narch/powerpc/configs/ppc6xx_defconfig:468:CONFIG_REALTEK_PHY=m\narch/powerpc/configs/ppc6xx_defconfig-469-CONFIG_SMSC_PHY=m\n--\ndrivers/net/dsa/realtek/Kconfig=2=menuconfig NET_DSA_REALTEK\n--\ndrivers/net/dsa/realtek/Kconfig-6-\tselect IRQ_DOMAIN\ndrivers/net/dsa/realtek/Kconfig:7:\tselect REALTEK_PHY\ndrivers/net/dsa/realtek/Kconfig-8-\tselect REGMAP\n--\ndrivers/net/ethernet/hisilicon/Kconfig=147=config HIBMCGE\n--\ndrivers/net/ethernet/hisilicon/Kconfig-152-\tselect MOTORCOMM_PHY\ndrivers/net/ethernet/hisilicon/Kconfig:153:\tselect REALTEK_PHY\ndrivers/net/ethernet/hisilicon/Kconfig-154-\tselect PAGE_POOL\n--\ndrivers/net/ethernet/realtek/Kconfig=84=config R8169\n--\ndrivers/net/ethernet/realtek/Kconfig-89-\tselect PHYLIB\ndrivers/net/ethernet/realtek/Kconfig:90:\tselect REALTEK_PHY\ndrivers/net/ethernet/realtek/Kconfig-91-\thelp\n--\ndrivers/net/phy/Makefile=94=obj-$(CONFIG_QSEMI_PHY)\t\t+= qsemi.o\ndrivers/net/phy/Makefile:95:obj-$(CONFIG_REALTEK_PHY)\t+= realtek/\ndrivers/net/phy/Makefile-96-obj-$(CONFIG_RENESAS_PHY)\t+= uPD60620.o\n--\ndrivers/net/phy/realtek/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/net/phy/realtek/Kconfig:2:config REALTEK_PHY\ndrivers/net/phy/realtek/Kconfig-3-\ttristate \"Realtek PHYs\"\n--\ndrivers/net/phy/realtek/Kconfig-7-\ndrivers/net/phy/realtek/Kconfig:8:if REALTEK_PHY\ndrivers/net/phy/realtek/Kconfig-9-\ndrivers/net/phy/realtek/Kconfig:10:config REALTEK_PHY_HWMON\ndrivers/net/phy/realtek/Kconfig-11-\tbool \"HWMON support for Realtek PHYs\"\ndrivers/net/phy/realtek/Kconfig:12:\tdepends on HWMON \u0026\u0026 !(REALTEK_PHY=y \u0026\u0026 HWMON=m)\ndrivers/net/phy/realtek/Kconfig-13-\thelp\n--\ndrivers/net/phy/realtek/Kconfig-15-\ndrivers/net/phy/realtek/Kconfig:16:endif # REALTEK_PHY\n--\ndrivers/net/phy/realtek/Makefile=2=realtek-y\t\t\t+= realtek_main.o\ndrivers/net/phy/realtek/Makefile:3:realtek-$(CONFIG_REALTEK_PHY_HWMON) += realtek_hwmon.o\ndrivers/net/phy/realtek/Makefile:4:obj-$(CONFIG_REALTEK_PHY)\t+= realtek.o\n--\ndrivers/net/phy/realtek/realtek_main.c=1804=static int rtl822x_probe(struct phy_device *phydev)\ndrivers/net/phy/realtek/realtek_main.c-1805-{\ndrivers/net/phy/realtek/realtek_main.c:1806:\tif (IS_ENABLED(CONFIG_REALTEK_PHY_HWMON) \u0026\u0026\ndrivers/net/phy/realtek/realtek_main.c-1807-\t phydev-\u003ephy_id != RTL_GENERIC_PHYID)\n--\ninclude/net/phy/realtek_phy.h-1-/* SPDX-License-Identifier: GPL-2.0 */\ninclude/net/phy/realtek_phy.h:2:#ifndef _REALTEK_PHY_H\ninclude/net/phy/realtek_phy.h:3:#define _REALTEK_PHY_H\ninclude/net/phy/realtek_phy.h-4-\n--\ninclude/net/phy/realtek_phy.h-6-\ninclude/net/phy/realtek_phy.h:7:#endif /* _REALTEK_PHY_H */\n"
} |
| 5/2 | 2026/06/29 07:18 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13979 output: 19 thoughts: 77 Thoughts: **PHY Driver Instantiation Thoughts** Okay, so the core question is whether we can get this PHY driver code running, specifically the one for the `RTL_8261C_CG`. The key seems to be successfully instantiating a PHY device with that specific ID. I need to figure out if that's possible from userspace, which is where things usually get interesting. My initial instinct is to go down the path of creating a virtual MDIO bus. That's usually the easiest route in these kinds of situations. Hmm, wait, wasn't there something called `mdio-mockup`? I vaguely recall that, need to confirm if that's actually a viable option here. It would be great if it exists, as that would make things much simpler. Let me check the documentation and see if that's a valid approach. |
| 6/2 | 2026/06/29 07:19 | tool | grepper |
0mError:no matches Args: {
"Expression": "mdio-mockup"
}Results: {
"error": "no matches"
} |
| 7/2 | 2026/06/29 07:19 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14268 output: 29 thoughts: 116 Thoughts: **MDIO Fuzzing Dilemma** Okay, so I'm trying to figure out how to approach fuzzing MDIO interfaces with syzkaller. The initial thought is, "Wait, syzkaller doesn't seem to have any built-in MDIO fuzzing capabilities." That's a bit of a setback. Then I think, "Hang on, `mac80211_hwsim` is specifically for WiFi, it's not going to help me with MDIO directly." So I'm back to square one. But then I start to think more broadly, "Is there a mechanism to simulate or instantiate a PHY within the existing syzkaller framework?" Then it dawns on me, "If a driver is structured as a PHY driver, it normally registers itself with `phy_driver_register`." From there, it typically waits for a PHY device to show up on an MDIO bus before binding. Now, the crucial question becomes, "Can I leverage userspace to create an MDIO bus?" And almost immediately, I think "No, that's not how it typically works." The system usually handles the MDIO bus creation. However, the gears begin to turn again. "But what about `netdevsim`?" it asks. "Does `netdevsim`, that network device simulator, provide an MDIO bus?" I need to investigate that avenue further. This seems like a reasonable avenue for a solution. |
| 8/2 | 2026/06/29 07:19 | tool | grepper |
0mError:no matches Args: {
"Expression": "mdio",
"PathPrefix": "drivers/net/netdevsim"
}Results: {
"error": "no matches"
} |
| 9/2 | 2026/06/29 07:19 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14731 output: 27 thoughts: 86 Thoughts: **MDIO Bus Investigation** Okay, so I'm thinking about where an MDIO bus might pop up in the kernel. `dummy` and `veth` are out – definitely not there. What about `tun` and `tap`? Nah, those are layer 3, no physical interface. Hmm... how about `usbnet`? Ah, now we're getting somewhere. Some USB network devices *do* have MDIO buses, interesting. If I'm thinking about fuzzing, this is perfect! I can build an emulation of a USB network device with an MDIO bus and, crucially, a reported PHY ID. This could be a really solid approach. Now, the next logical step: let me check the existing USB network drivers and see which ones actually make use of PHYs. I need to understand what the existing landscape looks like before I go any further with this concept. |
| 10/2 | 2026/06/29 07:19 | tool | grepper |
0mArgs:{
"Expression": "mdio",
"PathPrefix": "drivers/net/usb"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 1105 lines.\nUse more precise expression if possible.\n\ndrivers/net/usb/aqc111.c=266=static int aqc111_get_link_ksettings(struct net_device *net,\n--\ndrivers/net/usb/aqc111.c-290-\ndrivers/net/usb/aqc111.c:291:\telk-\u003ebase.mdio_support = 0x00; /*Not supported*/\ndrivers/net/usb/aqc111.c-292-\n--\ndrivers/net/usb/asix.h=178=struct asix_common_private {\n--\ndrivers/net/usb/asix.h-184-\tstruct asix_rx_fixup_info rx_fixup_info;\ndrivers/net/usb/asix.h:185:\tstruct mii_bus *mdio;\ndrivers/net/usb/asix.h-186-\tstruct phy_device *phydev;\n--\ndrivers/net/usb/asix.h=229=void asix_set_multicast(struct net_device *net);\ndrivers/net/usb/asix.h-230-\ndrivers/net/usb/asix.h:231:int asix_mdio_read(struct net_device *netdev, int phy_id, int loc);\ndrivers/net/usb/asix.h:232:void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val);\ndrivers/net/usb/asix.h-233-\ndrivers/net/usb/asix.h:234:int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum);\ndrivers/net/usb/asix.h:235:int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val);\ndrivers/net/usb/asix.h-236-\ndrivers/net/usb/asix.h:237:int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc);\ndrivers/net/usb/asix.h:238:void asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc,\ndrivers/net/usb/asix.h-239-\t\t\t int val);\n--\ndrivers/net/usb/asix_common.c=441=void asix_set_multicast(struct net_device *net)\n--\ndrivers/net/usb/asix_common.c-479-\ndrivers/net/usb/asix_common.c:480:static int __asix_mdio_read(struct net_device *netdev, int phy_id, int loc,\ndrivers/net/usb/asix_common.c-481-\t\t\t bool in_pm)\n--\ndrivers/net/usb/asix_common.c-503-\ndrivers/net/usb/asix_common.c:504:\tnetdev_dbg(dev-\u003enet, \"asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\\n\",\ndrivers/net/usb/asix_common.c-505-\t\t\tphy_id, loc, le16_to_cpu(res));\n--\ndrivers/net/usb/asix_common.c-509-\ndrivers/net/usb/asix_common.c:510:int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)\ndrivers/net/usb/asix_common.c-511-{\ndrivers/net/usb/asix_common.c:512:\treturn __asix_mdio_read(netdev, phy_id, loc, false);\ndrivers/net/usb/asix_common.c-513-}\ndrivers/net/usb/asix_common.c-514-\ndrivers/net/usb/asix_common.c:515:static int __asix_mdio_write(struct net_device *netdev, int phy_id, int loc,\ndrivers/net/usb/asix_common.c-516-\t\t\t int val, bool in_pm)\n--\ndrivers/net/usb/asix_common.c-521-\ndrivers/net/usb/asix_common.c:522:\tnetdev_dbg(dev-\u003enet, \"asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\\n\",\ndrivers/net/usb/asix_common.c-523-\t\t\tphy_id, loc, val);\n--\ndrivers/net/usb/asix_common.c-542-\ndrivers/net/usb/asix_common.c:543:void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)\ndrivers/net/usb/asix_common.c-544-{\ndrivers/net/usb/asix_common.c:545:\t__asix_mdio_write(netdev, phy_id, loc, val, false);\ndrivers/net/usb/asix_common.c-546-}\n--\ndrivers/net/usb/asix_common.c-548-/* MDIO read and write wrappers for phylib */\ndrivers/net/usb/asix_common.c:549:int asix_mdio_bus_read(struct mii_bus *bus, int phy_id, int regnum)\ndrivers/net/usb/asix_common.c-550-{\n--\ndrivers/net/usb/asix_common.c-552-\ndrivers/net/usb/asix_common.c:553:\treturn __asix_mdio_read(priv-\u003enet, phy_id, regnum, false);\ndrivers/net/usb/asix_common.c-554-}\ndrivers/net/usb/asix_common.c-555-\ndrivers/net/usb/asix_common.c:556:int asix_mdio_bus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)\ndrivers/net/usb/asix_common.c-557-{\n--\ndrivers/net/usb/asix_common.c-559-\ndrivers/net/usb/asix_common.c:560:\treturn __asix_mdio_write(priv-\u003enet, phy_id, regnum, val, false);\ndrivers/net/usb/asix_common.c-561-}\ndrivers/net/usb/asix_common.c-562-\ndrivers/net/usb/asix_common.c:563:int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)\ndrivers/net/usb/asix_common.c-564-{\ndrivers/net/usb/asix_common.c:565:\treturn __asix_mdio_read(netdev, phy_id, loc, true);\ndrivers/net/usb/asix_common.c-566-}\n--\ndrivers/net/usb/asix_common.c=568=void\ndrivers/net/usb/asix_common.c:569:asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc, int val)\ndrivers/net/usb/asix_common.c-570-{\ndrivers/net/usb/asix_common.c:571:\t__asix_mdio_write(netdev, phy_id, loc, val, true);\ndrivers/net/usb/asix_common.c-572-}\n--\ndrivers/net/usb/asix_devices.c=70=static u32 asix_get_phyid(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-77-\tfor (i = 0; i \u003c 100; i++) {\ndrivers/net/usb/asix_devices.c:78:\t\tphy_reg = asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id, MII_PHYSID1);\ndrivers/net/usb/asix_devices.c-79-\t\tif (phy_reg \u003c 0)\n--\ndrivers/net/usb/asix_devices.c-90-\ndrivers/net/usb/asix_devices.c:91:\tphy_reg = asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id, MII_PHYSID2);\ndrivers/net/usb/asix_devices.c-92-\tif (phy_reg \u003c 0)\n--\ndrivers/net/usb/asix_devices.c=190=static void asix_phy_reset(struct usbnet *dev, unsigned int reset_bits)\n--\ndrivers/net/usb/asix_devices.c-193-\ndrivers/net/usb/asix_devices.c:194:\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_BMCR, reset_bits);\ndrivers/net/usb/asix_devices.c-195-\n--\ndrivers/net/usb/asix_devices.c-200-\twhile (timeout--) {\ndrivers/net/usb/asix_devices.c:201:\t\tif (asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id, MII_BMCR)\ndrivers/net/usb/asix_devices.c-202-\t\t\t\t\t\t\t\u0026 BMCR_RESET)\n--\ndrivers/net/usb/asix_devices.c=212=static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/asix_devices.c-248-\tdev-\u003emii.dev = dev-\u003enet;\ndrivers/net/usb/asix_devices.c:249:\tdev-\u003emii.mdio_read = asix_mdio_read;\ndrivers/net/usb/asix_devices.c:250:\tdev-\u003emii.mdio_write = asix_mdio_write;\ndrivers/net/usb/asix_devices.c-251-\tdev-\u003emii.phy_id_mask = 0x3f;\n--\ndrivers/net/usb/asix_devices.c-263-\tasix_phy_reset(dev, BMCR_RESET);\ndrivers/net/usb/asix_devices.c:264:\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_ADVERTISE,\ndrivers/net/usb/asix_devices.c-265-\t\tADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);\n--\ndrivers/net/usb/asix_devices.c=362=static int ax88772_hw_reset(struct usbnet *dev, int in_pm)\n--\ndrivers/net/usb/asix_devices.c-406-\ndrivers/net/usb/asix_devices.c:407:\tif (in_pm \u0026\u0026 (!asix_mdio_read_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-408-\t\t\t\t\t MII_PHYSID1))){\n--\ndrivers/net/usb/asix_devices.c=456=static int ax88772a_hw_reset(struct usbnet *dev, int in_pm)\n--\ndrivers/net/usb/asix_devices.c-496-\ndrivers/net/usb/asix_devices.c:497:\tif (in_pm \u0026\u0026 (!asix_mdio_read_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-498-\t\t\t\t\t MII_PHYSID1))) {\n--\ndrivers/net/usb/asix_devices.c-512-\t\t/* Check if the PHY registers have default settings */\ndrivers/net/usb/asix_devices.c:513:\t\tphy14h = asix_mdio_read_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-514-\t\t\t\t\t AX88772A_PHY14H);\ndrivers/net/usb/asix_devices.c:515:\t\tphy15h = asix_mdio_read_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-516-\t\t\t\t\t AX88772A_PHY15H);\ndrivers/net/usb/asix_devices.c:517:\t\tphy16h = asix_mdio_read_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-518-\t\t\t\t\t AX88772A_PHY16H);\n--\ndrivers/net/usb/asix_devices.c-525-\t\tif (phy14h != AX88772A_PHY14H_DEFAULT)\ndrivers/net/usb/asix_devices.c:526:\t\t\tasix_mdio_write_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-527-\t\t\t\t\t AX88772A_PHY14H,\n--\ndrivers/net/usb/asix_devices.c-529-\t\tif (phy15h != AX88772A_PHY15H_DEFAULT)\ndrivers/net/usb/asix_devices.c:530:\t\t\tasix_mdio_write_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-531-\t\t\t\t\t AX88772A_PHY15H,\n--\ndrivers/net/usb/asix_devices.c-533-\t\tif (phy16h != AX88772A_PHY16H_DEFAULT)\ndrivers/net/usb/asix_devices.c:534:\t\t\tasix_mdio_write_nopm(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-535-\t\t\t\t\t AX88772A_PHY16H,\n--\ndrivers/net/usb/asix_devices.c=658=static int asix_resume(struct usb_interface *intf)\n--\ndrivers/net/usb/asix_devices.c-668-\ndrivers/net/usb/asix_devices.c:669:static int ax88772_init_mdio(struct usbnet *dev)\ndrivers/net/usb/asix_devices.c-670-{\n--\ndrivers/net/usb/asix_devices.c-673-\ndrivers/net/usb/asix_devices.c:674:\tpriv-\u003emdio = mdiobus_alloc();\ndrivers/net/usb/asix_devices.c:675:\tif (!priv-\u003emdio)\ndrivers/net/usb/asix_devices.c-676-\t\treturn -ENOMEM;\ndrivers/net/usb/asix_devices.c-677-\ndrivers/net/usb/asix_devices.c:678:\tpriv-\u003emdio-\u003epriv = dev;\ndrivers/net/usb/asix_devices.c:679:\tpriv-\u003emdio-\u003eread = \u0026asix_mdio_bus_read;\ndrivers/net/usb/asix_devices.c:680:\tpriv-\u003emdio-\u003ewrite = \u0026asix_mdio_bus_write;\ndrivers/net/usb/asix_devices.c:681:\tpriv-\u003emdio-\u003ename = \"Asix MDIO Bus\";\ndrivers/net/usb/asix_devices.c:682:\tpriv-\u003emdio-\u003ephy_mask = ~(BIT(priv-\u003ephy_addr \u0026 0x1f) | BIT(AX_EMBD_PHY_ADDR));\ndrivers/net/usb/asix_devices.c-683-\t/* mii bus name is usb-\u003cusb bus number\u003e-\u003cusb device number\u003e */\ndrivers/net/usb/asix_devices.c:684:\tsnprintf(priv-\u003emdio-\u003eid, MII_BUS_ID_SIZE, \"usb-%03d:%03d\",\ndrivers/net/usb/asix_devices.c-685-\t\t dev-\u003eudev-\u003ebus-\u003ebusnum, dev-\u003eudev-\u003edevnum);\ndrivers/net/usb/asix_devices.c-686-\ndrivers/net/usb/asix_devices.c:687:\tret = mdiobus_register(priv-\u003emdio);\ndrivers/net/usb/asix_devices.c-688-\tif (ret) {\ndrivers/net/usb/asix_devices.c-689-\t\tnetdev_err(dev-\u003enet, \"Could not register MDIO bus (err %d)\\n\", ret);\ndrivers/net/usb/asix_devices.c:690:\t\tmdiobus_free(priv-\u003emdio);\ndrivers/net/usb/asix_devices.c:691:\t\tpriv-\u003emdio = NULL;\ndrivers/net/usb/asix_devices.c-692-\t}\n--\ndrivers/net/usb/asix_devices.c-696-\ndrivers/net/usb/asix_devices.c:697:static void ax88772_mdio_unregister(struct asix_common_private *priv)\ndrivers/net/usb/asix_devices.c-698-{\ndrivers/net/usb/asix_devices.c:699:\tmdiobus_unregister(priv-\u003emdio);\ndrivers/net/usb/asix_devices.c:700:\tmdiobus_free(priv-\u003emdio);\ndrivers/net/usb/asix_devices.c-701-}\n--\ndrivers/net/usb/asix_devices.c=703=static int ax88772_init_phy(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-707-\ndrivers/net/usb/asix_devices.c:708:\tpriv-\u003ephydev = mdiobus_get_phy(priv-\u003emdio, priv-\u003ephy_addr);\ndrivers/net/usb/asix_devices.c-709-\tif (!priv-\u003ephydev) {\n--\ndrivers/net/usb/asix_devices.c-731-\t */\ndrivers/net/usb/asix_devices.c:732:\tpriv-\u003ephydev_int = mdiobus_get_phy(priv-\u003emdio, AX_EMBD_PHY_ADDR);\ndrivers/net/usb/asix_devices.c-733-\tif (!priv-\u003ephydev_int) {\n--\ndrivers/net/usb/asix_devices.c=829=static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/asix_devices.c-916-\ndrivers/net/usb/asix_devices.c:917:\tret = ax88772_init_mdio(dev);\ndrivers/net/usb/asix_devices.c-918-\tif (ret)\ndrivers/net/usb/asix_devices.c:919:\t\tgoto mdio_err;\ndrivers/net/usb/asix_devices.c-920-\n--\ndrivers/net/usb/asix_devices.c-940-phylink_err:\ndrivers/net/usb/asix_devices.c:941:\tax88772_mdio_unregister(priv);\ndrivers/net/usb/asix_devices.c:942:mdio_err:\ndrivers/net/usb/asix_devices.c-943-\treturn ret;\n--\ndrivers/net/usb/asix_devices.c=955=static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/asix_devices.c-962-\tphylink_destroy(priv-\u003ephylink);\ndrivers/net/usb/asix_devices.c:963:\tax88772_mdio_unregister(priv);\ndrivers/net/usb/asix_devices.c-964-\tasix_rx_fixup_common_free(dev-\u003edriver_priv);\n--\ndrivers/net/usb/asix_devices.c=990=static int marvell_phy_init(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-996-\ndrivers/net/usb/asix_devices.c:997:\treg = asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id, MII_MARVELL_STATUS);\ndrivers/net/usb/asix_devices.c-998-\tnetdev_dbg(dev-\u003enet, \"MII_MARVELL_STATUS = 0x%04x\\n\", reg);\ndrivers/net/usb/asix_devices.c-999-\ndrivers/net/usb/asix_devices.c:1000:\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_MARVELL_CTRL,\ndrivers/net/usb/asix_devices.c-1001-\t\t\tMARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);\n--\ndrivers/net/usb/asix_devices.c-1003-\tif (data-\u003eledmode) {\ndrivers/net/usb/asix_devices.c:1004:\t\treg = asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-1005-\t\t\tMII_MARVELL_LED_CTRL);\n--\ndrivers/net/usb/asix_devices.c-1009-\t\treg |= (1 + 0x0100);\ndrivers/net/usb/asix_devices.c:1010:\t\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-1011-\t\t\tMII_MARVELL_LED_CTRL, reg);\ndrivers/net/usb/asix_devices.c-1012-\ndrivers/net/usb/asix_devices.c:1013:\t\treg = asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id,\ndrivers/net/usb/asix_devices.c-1014-\t\t\tMII_MARVELL_LED_CTRL);\n--\ndrivers/net/usb/asix_devices.c=1021=static int rtl8211cl_phy_init(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-1026-\ndrivers/net/usb/asix_devices.c:1027:\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x1f, 0x0005);\ndrivers/net/usb/asix_devices.c:1028:\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x0c, 0);\ndrivers/net/usb/asix_devices.c:1029:\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x01,\ndrivers/net/usb/asix_devices.c:1030:\t\tasix_mdio_read (dev-\u003enet, dev-\u003emii.phy_id, 0x01) | 0x0080);\ndrivers/net/usb/asix_devices.c:1031:\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x1f, 0);\ndrivers/net/usb/asix_devices.c-1032-\ndrivers/net/usb/asix_devices.c-1033-\tif (data-\u003eledmode == 12) {\ndrivers/net/usb/asix_devices.c:1034:\t\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x1f, 0x0002);\ndrivers/net/usb/asix_devices.c:1035:\t\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x1a, 0x00cb);\ndrivers/net/usb/asix_devices.c:1036:\t\tasix_mdio_write (dev-\u003enet, dev-\u003emii.phy_id, 0x1f, 0);\ndrivers/net/usb/asix_devices.c-1037-\t}\n--\ndrivers/net/usb/asix_devices.c=1042=static int marvell_led_status(struct usbnet *dev, u16 speed)\ndrivers/net/usb/asix_devices.c-1043-{\ndrivers/net/usb/asix_devices.c:1044:\tu16 reg = asix_mdio_read(dev-\u003enet, dev-\u003emii.phy_id, MARVELL_LED_MANUAL);\ndrivers/net/usb/asix_devices.c-1045-\n--\ndrivers/net/usb/asix_devices.c-1062-\tnetdev_dbg(dev-\u003enet, \"marvell_led_status() writing 0x%04x\\n\", reg);\ndrivers/net/usb/asix_devices.c:1063:\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MARVELL_LED_MANUAL, reg);\ndrivers/net/usb/asix_devices.c-1064-\n--\ndrivers/net/usb/asix_devices.c=1068=static int ax88178_reset(struct usbnet *dev)\n--\ndrivers/net/usb/asix_devices.c-1141-\tasix_phy_reset(dev, BMCR_RESET | BMCR_ANENABLE);\ndrivers/net/usb/asix_devices.c:1142:\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_ADVERTISE,\ndrivers/net/usb/asix_devices.c-1143-\t\t\tADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);\ndrivers/net/usb/asix_devices.c:1144:\tasix_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_CTRL1000,\ndrivers/net/usb/asix_devices.c-1145-\t\t\tADVERTISE_1000FULL);\n--\ndrivers/net/usb/asix_devices.c=1271=static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/asix_devices.c-1290-\tdev-\u003emii.dev = dev-\u003enet;\ndrivers/net/usb/asix_devices.c:1291:\tdev-\u003emii.mdio_read = asix_mdio_read;\ndrivers/net/usb/asix_devices.c:1292:\tdev-\u003emii.mdio_write = asix_mdio_write;\ndrivers/net/usb/asix_devices.c-1293-\tdev-\u003emii.phy_id_mask = 0x1f;\n--\ndrivers/net/usb/ax88172a.c=18=struct ax88172a_private {\ndrivers/net/usb/ax88172a.c:19:\tstruct mii_bus *mdio;\ndrivers/net/usb/ax88172a.c-20-\tstruct phy_device *phydev;\n--\ndrivers/net/usb/ax88172a.c=55=static void ax88172a_status(struct usbnet *dev, struct urb *urb)\n--\ndrivers/net/usb/ax88172a.c-60-/* use phylib infrastructure */\ndrivers/net/usb/ax88172a.c:61:static int ax88172a_init_mdio(struct usbnet *dev)\ndrivers/net/usb/ax88172a.c-62-{\n--\ndrivers/net/usb/ax88172a.c-65-\ndrivers/net/usb/ax88172a.c:66:\tpriv-\u003emdio = mdiobus_alloc();\ndrivers/net/usb/ax88172a.c:67:\tif (!priv-\u003emdio) {\ndrivers/net/usb/ax88172a.c-68-\t\tnetdev_err(dev-\u003enet, \"Could not allocate MDIO bus\\n\");\n--\ndrivers/net/usb/ax88172a.c-71-\ndrivers/net/usb/ax88172a.c:72:\tpriv-\u003emdio-\u003epriv = (void *)dev;\ndrivers/net/usb/ax88172a.c:73:\tpriv-\u003emdio-\u003eread = \u0026asix_mdio_bus_read;\ndrivers/net/usb/ax88172a.c:74:\tpriv-\u003emdio-\u003ewrite = \u0026asix_mdio_bus_write;\ndrivers/net/usb/ax88172a.c:75:\tpriv-\u003emdio-\u003ename = \"Asix MDIO Bus\";\ndrivers/net/usb/ax88172a.c-76-\t/* mii bus name is usb-\u003cusb bus number\u003e-\u003cusb device number\u003e */\ndrivers/net/usb/ax88172a.c:77:\tsnprintf(priv-\u003emdio-\u003eid, MII_BUS_ID_SIZE, \"usb-%03d:%03d\",\ndrivers/net/usb/ax88172a.c-78-\t\t dev-\u003eudev-\u003ebus-\u003ebusnum, dev-\u003eudev-\u003edevnum);\ndrivers/net/usb/ax88172a.c-79-\ndrivers/net/usb/ax88172a.c:80:\tret = mdiobus_register(priv-\u003emdio);\ndrivers/net/usb/ax88172a.c-81-\tif (ret) {\n--\ndrivers/net/usb/ax88172a.c-85-\ndrivers/net/usb/ax88172a.c:86:\tnetdev_info(dev-\u003enet, \"registered mdio bus %s\\n\", priv-\u003emdio-\u003eid);\ndrivers/net/usb/ax88172a.c-87-\treturn 0;\n--\ndrivers/net/usb/ax88172a.c-89-mfree:\ndrivers/net/usb/ax88172a.c:90:\tmdiobus_free(priv-\u003emdio);\ndrivers/net/usb/ax88172a.c-91-\treturn ret;\n--\ndrivers/net/usb/ax88172a.c-93-\ndrivers/net/usb/ax88172a.c:94:static void ax88172a_remove_mdio(struct usbnet *dev)\ndrivers/net/usb/ax88172a.c-95-{\n--\ndrivers/net/usb/ax88172a.c-97-\ndrivers/net/usb/ax88172a.c:98:\tnetdev_info(dev-\u003enet, \"deregistering mdio bus %s\\n\", priv-\u003emdio-\u003eid);\ndrivers/net/usb/ax88172a.c:99:\tmdiobus_unregister(priv-\u003emdio);\ndrivers/net/usb/ax88172a.c:100:\tmdiobus_free(priv-\u003emdio);\ndrivers/net/usb/ax88172a.c-101-}\n--\ndrivers/net/usb/ax88172a.c=158=static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/ax88172a.c-225-\t/* init MDIO bus */\ndrivers/net/usb/ax88172a.c:226:\tret = ax88172a_init_mdio(dev);\ndrivers/net/usb/ax88172a.c-227-\tif (ret)\n--\ndrivers/net/usb/ax88172a.c=253=static void ax88172a_unbind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/ax88172a.c-256-\ndrivers/net/usb/ax88172a.c:257:\tax88172a_remove_mdio(dev);\ndrivers/net/usb/ax88172a.c-258-\tkfree(priv);\n--\ndrivers/net/usb/ax88172a.c=261=static int ax88172a_reset(struct usbnet *dev)\n--\ndrivers/net/usb/ax88172a.c-311-\tsnprintf(priv-\u003ephy_name, sizeof(priv-\u003ephy_name), PHY_ID_FMT,\ndrivers/net/usb/ax88172a.c:312:\t\t priv-\u003emdio-\u003eid, priv-\u003ephy_addr);\ndrivers/net/usb/ax88172a.c-313-\n--\ndrivers/net/usb/ax88179_178a.c-13-#include \u003clinux/usb/usbnet.h\u003e\ndrivers/net/usb/ax88179_178a.c:14:#include \u003cuapi/linux/mdio.h\u003e\ndrivers/net/usb/ax88179_178a.c:15:#include \u003clinux/mdio.h\u003e\ndrivers/net/usb/ax88179_178a.c-16-\n--\ndrivers/net/usb/ax88179_178a.c=314=static void ax88179_status(struct usbnet *dev, struct urb *urb)\n--\ndrivers/net/usb/ax88179_178a.c-333-\ndrivers/net/usb/ax88179_178a.c:334:static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc)\ndrivers/net/usb/ax88179_178a.c-335-{\n--\ndrivers/net/usb/ax88179_178a.c-342-\ndrivers/net/usb/ax88179_178a.c:343:static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc,\ndrivers/net/usb/ax88179_178a.c-344-\t\t\t int val)\n--\ndrivers/net/usb/ax88179_178a.c=1281=static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/ax88179_178a.c-1302-\tdev-\u003emii.dev = dev-\u003enet;\ndrivers/net/usb/ax88179_178a.c:1303:\tdev-\u003emii.mdio_read = ax88179_mdio_read;\ndrivers/net/usb/ax88179_178a.c:1304:\tdev-\u003emii.mdio_write = ax88179_mdio_write;\ndrivers/net/usb/ax88179_178a.c-1305-\tdev-\u003emii.phy_id_mask = 0xff;\n--\ndrivers/net/usb/ch9200.c=137=static int control_write(struct usbnet *dev, unsigned char request,\n--\ndrivers/net/usb/ch9200.c-176-\ndrivers/net/usb/ch9200.c:177:static int ch9200_mdio_read(struct net_device *netdev, int phy_id, int loc)\ndrivers/net/usb/ch9200.c-178-{\n--\ndrivers/net/usb/ch9200.c-196-\ndrivers/net/usb/ch9200.c:197:static void ch9200_mdio_write(struct net_device *netdev,\ndrivers/net/usb/ch9200.c-198-\t\t\t int phy_id, int loc, int val)\n--\ndrivers/net/usb/ch9200.c=338=static int ch9200_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/ch9200.c-348-\tdev-\u003emii.dev = dev-\u003enet;\ndrivers/net/usb/ch9200.c:349:\tdev-\u003emii.mdio_read = ch9200_mdio_read;\ndrivers/net/usb/ch9200.c:350:\tdev-\u003emii.mdio_write = ch9200_mdio_write;\ndrivers/net/usb/ch9200.c-351-\tdev-\u003emii.reg_num_mask = 0x1f;\n--\ndrivers/net/usb/dm9601.c=201=static int dm9601_get_eeprom(struct net_device *net,\n--\ndrivers/net/usb/dm9601.c-219-\ndrivers/net/usb/dm9601.c:220:static int dm9601_mdio_read(struct net_device *netdev, int phy_id, int loc)\ndrivers/net/usb/dm9601.c-221-{\n--\ndrivers/net/usb/dm9601.c-238-\tnetdev_dbg(dev-\u003enet,\ndrivers/net/usb/dm9601.c:239:\t\t \"dm9601_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\\n\",\ndrivers/net/usb/dm9601.c-240-\t\t phy_id, loc, le16_to_cpu(res));\n--\ndrivers/net/usb/dm9601.c-244-\ndrivers/net/usb/dm9601.c:245:static void dm9601_mdio_write(struct net_device *netdev, int phy_id, int loc,\ndrivers/net/usb/dm9601.c-246-\t\t\t int val)\n--\ndrivers/net/usb/dm9601.c-255-\ndrivers/net/usb/dm9601.c:256:\tnetdev_dbg(dev-\u003enet, \"dm9601_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\\n\",\ndrivers/net/usb/dm9601.c-257-\t\t phy_id, loc, val);\n--\ndrivers/net/usb/dm9601.c=338=static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/dm9601.c-358-\tdev-\u003emii.dev = dev-\u003enet;\ndrivers/net/usb/dm9601.c:359:\tdev-\u003emii.mdio_read = dm9601_mdio_read;\ndrivers/net/usb/dm9601.c:360:\tdev-\u003emii.mdio_write = dm9601_mdio_write;\ndrivers/net/usb/dm9601.c-361-\tdev-\u003emii.phy_id_mask = 0x1f;\n--\ndrivers/net/usb/dm9601.c-411-\ndrivers/net/usb/dm9601.c:412:\tdm9601_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_BMCR, BMCR_RESET);\ndrivers/net/usb/dm9601.c:413:\tdm9601_mdio_write(dev-\u003enet, dev-\u003emii.phy_id, MII_ADVERTISE,\ndrivers/net/usb/dm9601.c-414-\t\t\t ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);\n--\ndrivers/net/usb/lan78xx.c-19-#include \u003clinux/ipv6.h\u003e\ndrivers/net/usb/lan78xx.c:20:#include \u003clinux/mdio.h\u003e\ndrivers/net/usb/lan78xx.c-21-#include \u003clinux/phy.h\u003e\n--\ndrivers/net/usb/lan78xx.c-29-#include \u003clinux/microchipphy.h\u003e\ndrivers/net/usb/lan78xx.c:30:#include \u003clinux/of_mdio.h\u003e\ndrivers/net/usb/lan78xx.c-31-#include \u003clinux/of_net.h\u003e\n--\ndrivers/net/usb/lan78xx.c=413=struct lan78xx_net {\n--\ndrivers/net/usb/lan78xx.c-441-\tstruct mutex\t\tdev_mutex; /* serialise open/stop wrt suspend/resume */\ndrivers/net/usb/lan78xx.c:442:\tstruct mutex\t\tmdiobus_mutex; /* for MDIO bus access */\ndrivers/net/usb/lan78xx.c-443-\tunsigned int\t\tpipe_in, pipe_out, pipe_intr;\n--\ndrivers/net/usb/lan78xx.c-458-\tu32\t\t\tchiprev;\ndrivers/net/usb/lan78xx.c:459:\tstruct mii_bus\t\t*mdiobus;\ndrivers/net/usb/lan78xx.c-460-\tphy_interface_t\t\tinterface;\n--\ndrivers/net/usb/lan78xx.c=946=static int lan78xx_flush_rx_fifo(struct lan78xx_net *dev)\n--\ndrivers/net/usb/lan78xx.c-950-\ndrivers/net/usb/lan78xx.c:951:/* Loop until the read is completed with timeout called with mdiobus_mutex held */\ndrivers/net/usb/lan78xx.c:952:static int lan78xx_mdiobus_wait_not_busy(struct lan78xx_net *dev)\ndrivers/net/usb/lan78xx.c-953-{\n--\ndrivers/net/usb/lan78xx.c=1561=static int lan78xx_mac_reset(struct lan78xx_net *dev)\n--\ndrivers/net/usb/lan78xx.c-1566-\ndrivers/net/usb/lan78xx.c:1567:\tmutex_lock(\u0026dev-\u003emdiobus_mutex);\ndrivers/net/usb/lan78xx.c-1568-\n--\ndrivers/net/usb/lan78xx.c-1572-\t */\ndrivers/net/usb/lan78xx.c:1573:\tret = lan78xx_mdiobus_wait_not_busy(dev);\ndrivers/net/usb/lan78xx.c-1574-\tif (ret \u003c 0)\n--\ndrivers/net/usb/lan78xx.c-1601-exit_unlock:\ndrivers/net/usb/lan78xx.c:1602:\tmutex_unlock(\u0026dev-\u003emdiobus_mutex);\ndrivers/net/usb/lan78xx.c-1603-\n--\ndrivers/net/usb/lan78xx.c=1923=static int lan78xx_init_mac_address(struct lan78xx_net *dev)\n--\ndrivers/net/usb/lan78xx.c-1990-/* MDIO read and write wrappers for phylib */\ndrivers/net/usb/lan78xx.c:1991:static int lan78xx_mdiobus_read(struct mii_bus *bus, int phy_id, int idx)\ndrivers/net/usb/lan78xx.c-1992-{\n--\ndrivers/net/usb/lan78xx.c-2000-\ndrivers/net/usb/lan78xx.c:2001:\tmutex_lock(\u0026dev-\u003emdiobus_mutex);\ndrivers/net/usb/lan78xx.c-2002-\ndrivers/net/usb/lan78xx.c-2003-\t/* confirm MII not busy */\ndrivers/net/usb/lan78xx.c:2004:\tret = lan78xx_mdiobus_wait_not_busy(dev);\ndrivers/net/usb/lan78xx.c-2005-\tif (ret \u003c 0)\n--\ndrivers/net/usb/lan78xx.c-2013-\ndrivers/net/usb/lan78xx.c:2014:\tret = lan78xx_mdiobus_wait_not_busy(dev);\ndrivers/net/usb/lan78xx.c-2015-\tif (ret \u003c 0)\n--\ndrivers/net/usb/lan78xx.c-2024-done:\ndrivers/net/usb/lan78xx.c:2025:\tmutex_unlock(\u0026dev-\u003emdiobus_mutex);\ndrivers/net/usb/lan78xx.c-2026-\tusb_autopm_put_interface(dev-\u003eintf);\n--\ndrivers/net/usb/lan78xx.c-2030-\ndrivers/net/usb/lan78xx.c:2031:static int lan78xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,\ndrivers/net/usb/lan78xx.c-2032-\t\t\t\t u16 regval)\n--\ndrivers/net/usb/lan78xx.c-2041-\ndrivers/net/usb/lan78xx.c:2042:\tmutex_lock(\u0026dev-\u003emdiobus_mutex);\ndrivers/net/usb/lan78xx.c-2043-\ndrivers/net/usb/lan78xx.c-2044-\t/* confirm MII not busy */\ndrivers/net/usb/lan78xx.c:2045:\tret = lan78xx_mdiobus_wait_not_busy(dev);\ndrivers/net/usb/lan78xx.c-2046-\tif (ret \u003c 0)\n--\ndrivers/net/usb/lan78xx.c-2059-\ndrivers/net/usb/lan78xx.c:2060:\tret = lan78xx_mdiobus_wait_not_busy(dev);\ndrivers/net/usb/lan78xx.c-2061-\tif (ret \u003c 0)\n--\ndrivers/net/usb/lan78xx.c-2064-done:\ndrivers/net/usb/lan78xx.c:2065:\tmutex_unlock(\u0026dev-\u003emdiobus_mutex);\ndrivers/net/usb/lan78xx.c-2066-\tusb_autopm_put_interface(dev-\u003eintf);\n--\ndrivers/net/usb/lan78xx.c-2069-\ndrivers/net/usb/lan78xx.c:2070:static int lan78xx_mdio_init(struct lan78xx_net *dev)\ndrivers/net/usb/lan78xx.c-2071-{\n--\ndrivers/net/usb/lan78xx.c-2074-\ndrivers/net/usb/lan78xx.c:2075:\tdev-\u003emdiobus = mdiobus_alloc();\ndrivers/net/usb/lan78xx.c:2076:\tif (!dev-\u003emdiobus) {\ndrivers/net/usb/lan78xx.c-2077-\t\tnetdev_err(dev-\u003enet, \"can't allocate MDIO bus\\n\");\n--\ndrivers/net/usb/lan78xx.c-2080-\ndrivers/net/usb/lan78xx.c:2081:\tdev-\u003emdiobus-\u003epriv = (void *)dev;\ndrivers/net/usb/lan78xx.c:2082:\tdev-\u003emdiobus-\u003eread = lan78xx_mdiobus_read;\ndrivers/net/usb/lan78xx.c:2083:\tdev-\u003emdiobus-\u003ewrite = lan78xx_mdiobus_write;\ndrivers/net/usb/lan78xx.c:2084:\tdev-\u003emdiobus-\u003ename = \"lan78xx-mdiobus\";\ndrivers/net/usb/lan78xx.c:2085:\tdev-\u003emdiobus-\u003eparent = \u0026dev-\u003eudev-\u003edev;\ndrivers/net/usb/lan78xx.c-2086-\ndrivers/net/usb/lan78xx.c:2087:\tsnprintf(dev-\u003emdiobus-\u003eid, MII_BUS_ID_SIZE, \"usb-%03d:%03d\",\ndrivers/net/usb/lan78xx.c-2088-\t\t dev-\u003eudev-\u003ebus-\u003ebusnum, dev-\u003eudev-\u003edevnum);\n--\ndrivers/net/usb/lan78xx.c-2093-\t\t/* set to internal PHY id */\ndrivers/net/usb/lan78xx.c:2094:\t\tdev-\u003emdiobus-\u003ephy_mask = ~(1 \u003c\u003c 1);\ndrivers/net/usb/lan78xx.c-2095-\t\tbreak;\n--\ndrivers/net/usb/lan78xx.c-2099-\ndrivers/net/usb/lan78xx.c:2100:\tnode = of_get_child_by_name(dev-\u003eudev-\u003edev.of_node, \"mdio\");\n\n"
} |
| 11/2 | 2026/06/29 07:19 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27898 output: 43 thoughts: 204 Thoughts: **Fuzzing for PHY Instantiation** Okay, here's the plan. It looks like `asix`, `ax88172a`, `ax88179_178a`, and `lan78xx` all rely on MDIO buses. If I fuzz the USB interface and emulate either an ASIX or LAN78xx device, when the driver probes, it will automatically register an MDIO bus. Then that MDIO bus will go off and scan for PHYs. Now, if my emulated USB device can respond to MDIO read commands – which will be translated into USB control messages – and it *claims* the PHY ID is `RTL_8261C_CG`, which is represented by `0x001cc898`, the PHY subsystem will instantiate the Realtek PHY driver and call `rtl8261x_probe`. Just confirming, `RTL_8261C_CG` is definitely `0x001cc898`. Right, time to dissect `rtl8261x_probe`. Let's see what that looks like. |
| 12/2 | 2026/06/29 07:19 | tool | read-file |
0mArgs:{
"File": "drivers/net/phy/realtek/realtek_main.c",
"FirstLine": 386,
"LineCount": 50
}Results: {
"Contents": " 386:\tstatic int rtl8261x_probe(struct phy_device *phydev)\n 387:\t{\n 388:\t\tstruct device *dev = \u0026phydev-\u003emdio.dev;\n 389:\t\tstruct rtl8261x_priv *priv;\n 390:\t\tint sub_phy_id, ret;\n 391:\t\n 392:\t\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n 393:\t\tif (!priv)\n 394:\t\t\treturn -ENOMEM;\n 395:\t\n 396:\t\tphydev-\u003epriv = priv;\n 397:\t\n 398:\t\tret = phy_write_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_ADDR_REG,\n 399:\t\t\t\t RTL_8261X_SUB_PHY_ID_ADDR);\n 400:\t\tif (ret \u003c 0)\n 401:\t\t\treturn ret;\n 402:\t\n 403:\t\tret = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL8261X_EXT_DATA_REG);\n 404:\t\tif (ret \u003c 0)\n 405:\t\t\treturn ret;\n 406:\t\n 407:\t\tsub_phy_id = (ret \u003e\u003e 8) \u0026 0xff;\n 408:\t\n 409:\t\tswitch (sub_phy_id) {\n 410:\t\tcase RTL8261C_CE_MODEL:\n 411:\t\t\tpriv-\u003efw_name = RTL8261C_CE_FW_NAME;\n 412:\t\t\tphydev_info(phydev, \"RTL8261C detected (sub_id 0x%02x)\\n\", sub_phy_id);\n 413:\t\t\tbreak;\n 414:\t\n 415:\t\tdefault:\n 416:\t\t\tphydev_warn(phydev, \"Unknown sub_id 0x%02x, default behavior\\n\", sub_phy_id);\n 417:\t\t\treturn -ENODEV;\n 418:\t\t}\n 419:\t\n 420:\t\treturn 0;\n 421:\t}\n 422:\t\n 423:\tstatic int rtl8261x_get_features(struct phy_device *phydev)\n 424:\t{\n 425:\t\tint ret;\n 426:\t\n 427:\t\tret = genphy_c45_pma_read_abilities(phydev);\n 428:\t\tif (ret)\n 429:\t\t\treturn ret;\n 430:\t\t/*\n 431:\t\t * Supplement Multi-Gig speeds that may not be automatically detected\n 432:\t\t * RTL8261X supports 2.5G/5G in addition to standard 10G\n 433:\t\t */\n 434:\t\tlinkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,\n 435:\t\t\t\t phydev-\u003esupported);\n"
} |
| 13/2 | 2026/06/29 07:19 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 29214 output: 42 thoughts: 348 Thoughts: **Analyzing the RTL8261x PHY Initialization Path** Alright, let's break this down. My initial thought is that `rtl8261x_probe` is querying the MMD registers. If the emulated USB device plays along and provides `RTL8261C_CE_MODEL` in `sub_phy_id` in response to those MMD reads, then we'll proceed to `rtl8261x_config_init`. Now, within `rtl8261x_config_init`, the function `rtl8261x_fw_load` gets called. Here's where things get interesting: `rtl8261x_fw_load` relies on `request_firmware`. The critical path then hinges on firmware availability. Assuming it's present (or that we can set up a mock environment, which might be tricky with syzkaller if the firmware isn't in the rootfs), we'll wait for the load. If `request_firmware` fails – which is what we are after, it returns an error, and the entire `rtl8261x_config_init` process blows up. This causes the PHY initialization to fail, but, critically, we've demonstrated that we've reached the code paths in `rtl8261x_probe` and `rtl8261x_config_init`. On a side note, I see that generic Clause 45 PHY functions like `genphy_c45_soft_reset`, `genphy_c45_an_setup_master_slave`, and `genphy_c45_read_master_slave` have been added to `drivers/net/phy/phy-c45.c`. They're now available to any C45 PHY. The next point to analyze is that `genphy_c45_read_status` and `genphy_c45_config_aneg` have been updated to use these new functions. My next step is to examine `genphy_c45_read_status` to see how it calls the new helper functions. |
| 14/2 | 2026/06/29 07:19 | tool | read-file |
0mArgs:{
"File": "drivers/net/phy/phy-c45.c",
"FirstLine": 1290,
"LineCount": 50
}Results: {
"Contents": "1290:\t\tret = genphy_c45_read_link(phydev);\n1291:\t\tif (ret)\n1292:\t\t\treturn ret;\n1293:\t\n1294:\t\tphydev-\u003espeed = SPEED_UNKNOWN;\n1295:\t\tphydev-\u003eduplex = DUPLEX_UNKNOWN;\n1296:\t\tphydev-\u003epause = false;\n1297:\t\tphydev-\u003easym_pause = false;\n1298:\t\n1299:\t\tif (phydev-\u003eautoneg == AUTONEG_ENABLE) {\n1300:\t\t\tret = genphy_c45_read_lpa(phydev);\n1301:\t\t\tif (ret)\n1302:\t\t\t\treturn ret;\n1303:\t\n1304:\t\t\tif (genphy_c45_baset1_able(phydev)) {\n1305:\t\t\t\tret = genphy_c45_baset1_read_status(phydev);\n1306:\t\t\t\tif (ret \u003c 0)\n1307:\t\t\t\t\treturn ret;\n1308:\t\t\t} else {\n1309:\t\t\t\tret = genphy_c45_read_master_slave(phydev);\n1310:\t\t\t\tif (ret \u003c 0)\n1311:\t\t\t\t\treturn ret;\n1312:\t\t\t}\n1313:\t\n1314:\t\t\tphy_resolve_aneg_linkmode(phydev);\n1315:\t\t} else {\n1316:\t\t\tret = genphy_c45_read_pma(phydev);\n1317:\t\t}\n1318:\t\n1319:\t\treturn ret;\n1320:\t}\n1321:\tEXPORT_SYMBOL_GPL(genphy_c45_read_status);\n1322:\t\n1323:\t/**\n1324:\t * genphy_c45_config_aneg - restart auto-negotiation or forced setup\n1325:\t * @phydev: target phy_device struct\n1326:\t *\n1327:\t * Description: If auto-negotiation is enabled, we configure the\n1328:\t * advertising, and then restart auto-negotiation. If it is not\n1329:\t * enabled, then we force a configuration.\n1330:\t */\n1331:\tint genphy_c45_config_aneg(struct phy_device *phydev)\n1332:\t{\n1333:\t\tbool changed = false;\n1334:\t\tint ret;\n1335:\t\n1336:\t\tif (phydev-\u003eautoneg == AUTONEG_DISABLE)\n1337:\t\t\treturn genphy_c45_pma_setup_forced(phydev);\n1338:\t\n1339:\t\tret = genphy_c45_an_config_aneg(phydev);\n"
} |
| 15/2 | 2026/06/29 07:19 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30826 output: 32 thoughts: 460 Thoughts: **Analyzing the C45 PHY Master/Slave Configuration Patch** Okay, so I've been looking at this patch and, from what I can tell, `genphy_c45_read_status` and `genphy_c45_config_aneg` are the key functions that have been updated. They now call `genphy_c45_read_master_slave` and `genphy_c45_an_setup_master_slave`, respectively. This is targeted at C45 PHYs with autonegotiation enabled, excluding BaseT1 PHYs. Seems like a straightforward, functional change, and clearly reachable within the existing driver structure. This patch introduces new logic for Master/Slave configuration in C45 PHYs, and also adds a new Realtek PHY driver. Worth a closer look, especially for fuzzing potential. Now, let's identify the specific symbols we need to focus on. Looks like we have a good set: `genphy_c45_soft_reset`, `genphy_c45_an_setup_master_slave`, `genphy_c45_read_master_slave`, and then the Realtek-specific functions: `rtl8261x_probe`, `rtl8261x_get_features`, `rtl8261x_read_status`, `rtl8261x_verify_firmware`, `rtl8261x_fw_execute_entry`, `rtl8261x_fw_load`, `rtl8261x_config_intr`, `rtl8261x_handle_interrupt`, `rtl8261x_config_aneg`, and `rtl8261x_config_init`. Next, I need to make sure I understand the configuration dependencies. Let's see... is `CONFIG_REALTEK_PHY` the only config needed? Yes, it seems to be. But wait, `genphy_c45_soft_reset` and others are in `phy-c45.c`, which compiles with `CONFIG_PHYLIB`. And `CONFIG_REALTEK_PHY` depends on `CONFIG_PHYLIB`. So, `CONFIG_REALTEK_PHY` should be sufficient for activating the new logic. Just need to double-check that `drivers/net/phy/phy-c45.c` is compiled under those conditions. |
| 16/2 | 2026/06/29 07:19 | tool | grepper |
0mArgs:{
"Expression": "phy-c45",
"PathPrefix": "drivers/net/phy/Makefile"
}Results: {
"Output": "drivers/net/phy/Makefile-3-\ndrivers/net/phy/Makefile:4:libphy-y\t\t\t:= phy.o phy-c45.o phy-core.o phy_device.o \\\ndrivers/net/phy/Makefile-5-\t\t\t\t linkmode.o phy_link_topology.o \\\n"
} |
| 17/2 | 2026/06/29 07:19 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 31929 output: 283 thoughts: 310 Thoughts: **Analyzing PHY Driver Configuration for Fuzzing** Okay, so I'm looking at `phy-c45.o` and my immediate thought is "That's part of `libphy`". Naturally, it's only built when `CONFIG_PHYLIB` is enabled. That seems straightforward enough. Now, let's see about `rtl8261x_fw_load`. It's using `request_firmware`, so I need to make sure that `CONFIG_FW_LOADER` is enabled, which it usually is. Time to refine that list of focus symbols for fuzzing. I've got a pretty good starting point, but I want to make sure I cover all the critical functions. Thinking this through, I'm leaning toward these: `genphy_c45_soft_reset`, `genphy_c45_an_setup_master_slave`, `genphy_c45_read_master_slave`, and then the `rtl8261x` functions: `rtl8261x_probe`, `rtl8261x_get_features`, `rtl8261x_read_status`, `rtl8261x_verify_firmware`, `rtl8261x_fw_execute_entry`, `rtl8261x_fw_load`, `rtl8261x_config_intr`, `rtl8261x_handle_interrupt`, `rtl8261x_config_aneg`, and `rtl8261x_config_init`. Yeah, these all look like excellent candidates for fuzzing. They touch different aspects of the driver's operation, from hardware interaction to firmware loading and interrupt handling. I'd better double-check to make sure there aren't any other crucial configs that need to be in place. I think `REALTEK_PHY` is the main one to keep an eye on. I should be covered there. Alright, that's enough for now. Let's call `set-results`. |
| 18/2 | 2026/06/29 07:19 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"REALTEK_PHY"
],
"FocusSymbols": [
"genphy_c45_soft_reset",
"genphy_c45_an_setup_master_slave",
"genphy_c45_read_master_slave",
"rtl8261x_probe",
"rtl8261x_get_features",
"rtl8261x_read_status",
"rtl8261x_verify_firmware",
"rtl8261x_fw_execute_entry",
"rtl8261x_fw_load",
"rtl8261x_config_intr",
"rtl8261x_handle_interrupt",
"rtl8261x_config_aneg",
"rtl8261x_config_init"
],
"Reasoning": "The patch adds new Master/Slave configuration logic for Clause 45 PHYs and introduces a new Realtek PHY driver (RTL8261C) with firmware loading capabilities. These features are reachable via MDIO bus emulation (e.g., through USB network device emulation) and contain complex logic that should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"REALTEK_PHY"
],
"FocusSymbols": [
"genphy_c45_soft_reset",
"genphy_c45_an_setup_master_slave",
"genphy_c45_read_master_slave",
"rtl8261x_probe",
"rtl8261x_get_features",
"rtl8261x_read_status",
"rtl8261x_verify_firmware",
"rtl8261x_fw_execute_entry",
"rtl8261x_fw_load",
"rtl8261x_config_intr",
"rtl8261x_handle_interrupt",
"rtl8261x_config_aneg",
"rtl8261x_config_init"
],
"Reasoning": "The patch adds new Master/Slave configuration logic for Clause 45 PHYs and introduces a new Realtek PHY driver (RTL8261C) with firmware loading capabilities. These features are reachable via MDIO bus emulation (e.g., through USB network device emulation) and contain complex logic that should be fuzzed.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|