| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/14 16:37 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"MOTORCOMM_PHY"
],
"FocusSymbols": [
"yt8824_probe",
"yt8824_config_init",
"yt8824_config_aneg",
"yt8824_read_status",
"yt8824_soft_reset",
"yt8824_suspend",
"yt8824_resume",
"yt8824_config_intr",
"yt8824_handle_interrupt",
"yt8824_aneg_done",
"yt8824_read_page",
"yt8824_write_page"
],
"Reasoning": "The patch adds support for the Motorcomm YT8824 PHY. This code can be reached in a virtualized environment by emulating a USB network adapter (e.g., smsc95xx or lan78xx) that registers an MDIO bus, and responding to MDIO reads with the YT8824 PHY ID. This will cause the kernel to bind the new PHY driver and execute its initialization and state machine logic.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/14 16:37 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 9c1a8c3e13f0f7dae507e535de880196845ed664\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Jul 14 16:37:01 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c\nindex 5071605a1a117a..e6f93ed4349cab 100644\n--- a/drivers/net/phy/motorcomm.c\n+++ b/drivers/net/phy/motorcomm.c\n@@ -1,9 +1,10 @@\n // SPDX-License-Identifier: GPL-2.0+\n /*\n- * Motorcomm 8511/8521/8522/8531/8531S/8821 PHY driver.\n+ * Motorcomm 8511/8521/8522/8531/8531S/8821/8824 PHY driver.\n *\n * Author: Peter Geis \u003cpgwipeout@gmail.com\u003e\n * Author: Frank \u003cFrank.Sae@motor-comm.com\u003e\n+ * Author: Kyle \u003ckyle.switch@motor-comm.com\u003e\n */\n \n #include \u003clinux/etherdevice.h\u003e\n@@ -12,12 +13,16 @@\n #include \u003clinux/phy.h\u003e\n #include \u003clinux/property.h\u003e\n \n+/* used for phy8824 baseaddr */\n+#define PHY_BASE_ADDR (1)\n+\n #define PHY_ID_YT8511\t\t0x0000010a\n #define PHY_ID_YT8521\t\t0x0000011a\n #define PHY_ID_YT8522\t\t0x4f51e928\n #define PHY_ID_YT8531\t\t0x4f51e91b\n #define PHY_ID_YT8531S\t\t0x4f51e91a\n #define PHY_ID_YT8821\t\t0x4f51ea19\n+#define PHY_ID_YT8824\t\t0x4f51e8b8\n /* YT8521/YT8531S/YT8821 Register Overview\n *\tUTP Register space\t|\tFIBER Register space\n * ------------------------------------------------------------\n@@ -29,6 +34,18 @@\n * ------------------------------------------------------------\n */\n \n+/* YT8824 Register Overview\n+ *\tUTP Register space\t|\tFIBER Register space\n+ * ------------------------------------------------------------\n+ * |\tUTP MII\t\t\t|\tFIBER MII\t |\n+ * |\tUTP MMD\t\t\t|\t\t\t\t|\n+ * |\tUTP Extended\t\t|\tFIBER Extended\t\t|\n+ * |\tUTP Top Extended\t|\tFIBER Top Extended\t|\n+ * ------------------------------------------------------------\n+ * |\t\t\tCommon Top Extended\t\t\t|\n+ * ------------------------------------------------------------\n+ */\n+\n /* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */\n \n /* Specific Function Control Register */\n@@ -375,6 +392,12 @@\n #define YT8821_CHIP_MODE_AUTO_BX2500_SGMII\t0\n #define YT8821_CHIP_MODE_FORCE_BX2500\t\t1\n \n+#define YT8824_RSSR_SPACE_MASK\t\t\tBIT(0)\n+#define YT8824_RSSR_FIBER_SPACE\t\t\t(0x1)\n+#define YT8824_RSSR_UTP_SPACE\t\t\t(0x0)\n+#define REG_MII_MMD_CTRL\t\t\t0x0D\n+#define REG_MII_MMD_DATA\t\t\t0x0E\n+\n struct yt8521_priv {\n \t/* combo_advertising is used for case of YT8521 in combo mode,\n \t * this means that yt8521 may work in utp or fiber mode which depends\n@@ -391,8 +414,29 @@ struct yt8521_priv {\n \t * YT8521_RSSR_TO_BE_ARBITRATED\n \t */\n \tu8 reg_page;\n+\t/* YT8824 reg space addr */\n+\tu8 phy_base_addr;\n+\t/* top extend reg addr */\n+\tu8 top_phy_addr;\n };\n \n+static inline int ytphy_top_write(struct phy_device *phydev, u32 regnum,\n+\t\t\t\t u16 val)\n+{\n+\tstruct yt8521_priv *priv = phydev-\u003epriv;\n+\tstruct mii_bus *bus = phydev-\u003emdio.bus;\n+\n+\treturn bus-\u003ewrite(bus, priv-\u003etop_phy_addr, regnum, val);\n+}\n+\n+static inline int ytphy_top_read(struct phy_device *phydev, u32 regnum)\n+{\n+\tstruct yt8521_priv *priv = phydev-\u003epriv;\n+\tstruct mii_bus *bus = phydev-\u003emdio.bus;\n+\n+\treturn bus-\u003eread(bus, priv-\u003etop_phy_addr, regnum);\n+}\n+\n /**\n * ytphy_read_ext() - read a PHY's extended register\n * @phydev: a pointer to a \u0026struct phy_device\n@@ -431,6 +475,70 @@ static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum)\n \treturn ret;\n }\n \n+/**\n+ * ytphy_read_top_ext() - read a PHY's top extended register for YT8824\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @regnum: register number to read\n+ *\n+ * NOTE:The caller must have taken the MDIO bus lock.\n+ *\n+ * returns the value of regnum reg or negative error code\n+ */\n+static int ytphy_read_top_ext(struct phy_device *phydev, u16 regnum)\n+{\n+\tint ret;\n+\n+\tret = ytphy_top_write(phydev, YTPHY_PAGE_SELECT, regnum);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn ytphy_top_read(phydev, YTPHY_PAGE_DATA);\n+}\n+\n+static int ytphy_read_top_ext_with_lock(struct phy_device *phydev, u16 regnum)\n+{\n+\tint ret;\n+\n+\tphy_lock_mdio_bus(phydev);\n+\tret = ytphy_read_top_ext(phydev, regnum);\n+\tphy_unlock_mdio_bus(phydev);\n+\n+\treturn ret;\n+}\n+\n+/**\n+ * ytphy_write_top_ext() - read a PHY's top extended register for YT8824\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @regnum: register number to read\n+ *\n+ * NOTE:The caller must have taken the MDIO bus lock.\n+ *\n+ * returns the value of regnum reg or negative error code\n+ */\n+static int ytphy_write_top_ext(struct phy_device *phydev, u16 regnum,\n+\t\t\t u16 val)\n+{\n+\tint ret;\n+\n+\tret = ytphy_top_write(phydev, YTPHY_PAGE_SELECT, regnum);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\treturn ytphy_top_write(phydev, YTPHY_PAGE_DATA, val);\n+}\n+\n+static int ytphy_write_top_ext_with_lock(struct phy_device *phydev, u16 regnum,\n+\t\t\t\t\t u16 val)\n+{\n+\tint ret;\n+\n+\tphy_lock_mdio_bus(phydev);\n+\tret = ytphy_write_top_ext(phydev, regnum, val);\n+\tphy_unlock_mdio_bus(phydev);\n+\n+\treturn ret;\n+}\n+\n /**\n * ytphy_write_ext() - write a PHY's extended register\n * @phydev: a pointer to a \u0026struct phy_device\n@@ -521,6 +629,26 @@ static int ytphy_modify_ext_with_lock(struct phy_device *phydev, u16 regnum,\n \treturn ret;\n }\n \n+static int ytphy_write_mmd(struct phy_device *phydev,\n+\t\t\t u16 device, u16 reg,\n+\t\t\t u16 value)\n+{\n+\tint ret;\n+\n+\tret = __phy_write(phydev, REG_MII_MMD_CTRL, device);\n+\tif (ret)\n+\t\treturn ret;\n+\tret = __phy_write(phydev, REG_MII_MMD_DATA, reg);\n+\tif (ret)\n+\t\treturn ret;\n+\tret = __phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);\n+\tif (ret)\n+\t\treturn ret;\n+\tret = __phy_write(phydev, REG_MII_MMD_DATA, value);\n+\n+\treturn ret;\n+}\n+\n /**\n * ytphy_get_wol() - report whether wake-on-lan is enabled\n * @phydev: a pointer to a \u0026struct phy_device\n@@ -3059,99 +3187,1620 @@ static int yt8821_resume(struct phy_device *phydev)\n \treturn yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);\n }\n \n-static struct phy_driver motorcomm_phy_drvs[] = {\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8511),\n-\t\t.name\t\t= \"YT8511 Gigabit Ethernet\",\n-\t\t.config_init\t= yt8511_config_init,\n-\t\t.suspend\t= genphy_suspend,\n-\t\t.resume\t\t= genphy_resume,\n-\t\t.read_page\t= yt8511_read_page,\n-\t\t.write_page\t= yt8511_write_page,\n-\t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8521),\n-\t\t.name\t\t= \"YT8521 Gigabit Ethernet\",\n-\t\t.get_features\t= yt8521_get_features,\n-\t\t.probe\t\t= yt8521_probe,\n-\t\t.read_page\t= yt8521_read_page,\n-\t\t.write_page\t= yt8521_write_page,\n-\t\t.get_wol\t= ytphy_get_wol,\n-\t\t.set_wol\t= ytphy_set_wol,\n-\t\t.config_aneg\t= yt8521_config_aneg,\n-\t\t.aneg_done\t= yt8521_aneg_done,\n-\t\t.config_init\t= yt8521_config_init,\n-\t\t.read_status\t= yt8521_read_status,\n-\t\t.soft_reset\t= yt8521_soft_reset,\n-\t\t.suspend\t= yt8521_suspend,\n-\t\t.resume\t\t= yt8521_resume,\n-\t\t.led_hw_is_supported = yt8521_led_hw_is_supported,\n-\t\t.led_hw_control_set = yt8521_led_hw_control_set,\n-\t\t.led_hw_control_get = yt8521_led_hw_control_get,\n-\t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8522),\n-\t\t.name\t\t= \"YT8522 100 Megabit Ethernet\",\n-\t\t.config_aneg\t= genphy_config_aneg,\n-\t\t.config_init\t= yt8522_config_init,\n-\t\t.suspend\t= genphy_suspend,\n-\t\t.resume\t\t= genphy_resume,\n-\t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8531),\n-\t\t.name\t\t= \"YT8531 Gigabit Ethernet\",\n-\t\t.probe\t\t= yt8531_probe,\n-\t\t.config_init\t= yt8531_config_init,\n-\t\t.suspend\t= genphy_suspend,\n-\t\t.resume\t\t= genphy_resume,\n-\t\t.get_wol\t= ytphy_get_wol,\n-\t\t.set_wol\t= yt8531_set_wol,\n-\t\t.link_change_notify = yt8531_link_change_notify,\n-\t\t.led_hw_is_supported = yt8521_led_hw_is_supported,\n-\t\t.led_hw_control_set = yt8521_led_hw_control_set,\n-\t\t.led_hw_control_get = yt8521_led_hw_control_get,\n-\t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8531S),\n-\t\t.name\t\t= \"YT8531S Gigabit Ethernet\",\n-\t\t.get_features\t= yt8521_get_features,\n-\t\t.probe\t\t= yt8521_probe,\n-\t\t.read_page\t= yt8521_read_page,\n-\t\t.write_page\t= yt8521_write_page,\n-\t\t.get_wol\t= ytphy_get_wol,\n-\t\t.set_wol\t= ytphy_set_wol,\n-\t\t.config_aneg\t= yt8521_config_aneg,\n-\t\t.aneg_done\t= yt8521_aneg_done,\n-\t\t.config_init\t= yt8521_config_init,\n-\t\t.read_status\t= yt8521_read_status,\n-\t\t.soft_reset\t= yt8521_soft_reset,\n-\t\t.suspend\t= yt8521_suspend,\n-\t\t.resume\t\t= yt8521_resume,\n-\t},\n-\t{\n-\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8821),\n-\t\t.name\t\t\t= \"YT8821 2.5Gbps PHY\",\n-\t\t.get_features\t\t= yt8821_get_features,\n-\t\t.read_page\t\t= yt8521_read_page,\n-\t\t.write_page\t\t= yt8521_write_page,\n-\t\t.get_wol\t\t= ytphy_get_wol,\n-\t\t.set_wol\t\t= ytphy_set_wol,\n-\t\t.config_aneg\t\t= genphy_config_aneg,\n-\t\t.aneg_done\t\t= yt8821_aneg_done,\n-\t\t.config_init\t\t= yt8821_config_init,\n-\t\t.get_rate_matching\t= yt8821_get_rate_matching,\n-\t\t.read_status\t\t= yt8821_read_status,\n-\t\t.soft_reset\t\t= yt8821_soft_reset,\n-\t\t.suspend\t\t= yt8821_suspend,\n-\t\t.resume\t\t\t= yt8821_resume,\n+/**\n+ * yt8824_read_page() - read reg page\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns current reg space of yt8824 (YT8824_RSSR_FIBER_SPACE/\n+ * YT8824_RSSR_UTP_SPACE) or negative errno code\n+ */\n+static int yt8824_read_page(struct phy_device *phydev)\n+{\n+\tint old_page;\n+\n+\told_page = ytphy_read_top_ext_with_lock(phydev, YT8521_REG_SPACE_SELECT_REG);\n+\tif (old_page \u003c 0)\n+\t\treturn old_page;\n+\n+\tif ((old_page \u0026 YT8824_RSSR_SPACE_MASK) == YT8824_RSSR_FIBER_SPACE)\n+\t\treturn YT8824_RSSR_FIBER_SPACE;\n+\n+\treturn YT8824_RSSR_UTP_SPACE;\n+};\n+\n+/**\n+ * yt8824_write_page() - write reg page\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @page: The reg page(YT8824_RSSR_FIBER_SPACE/YT8824_RSSR_UTP_SPACE) to write.\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_write_page(struct phy_device *phydev, int page)\n+{\n+\tint old_page;\n+\tu16 data;\n+\n+\told_page = ytphy_read_top_ext_with_lock(phydev, YT8521_REG_SPACE_SELECT_REG);\n+\tdata = old_page \u0026 (~(0x1));\n+\tdata |= page;\n+\n+\treturn ytphy_write_top_ext_with_lock(phydev, YT8521_REG_SPACE_SELECT_REG, data);\n+};\n+\n+/**\n+ * configuration YT8824 to one template test mode.\n+ */\n+static int yt8824_soft_reset_step1_paged(struct phy_device *phydev,\n+\t\t\t\t\t int reg_space)\n+{\n+\tint old_page;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tif (old_page \u003e= 0) {\n+\t\tif (reg_space == YT8824_RSSR_UTP_SPACE) {\n+\t\t\tret = ytphy_write_mmd(phydev, 0x1, 0x0084, 0x2000);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t}\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * enable YT8824 serdes isolate.\n+ */\n+static int yt8824_soft_reset_step2_paged(struct phy_device *phydev,\n+\t\t\t\t\t int reg_space)\n+{\n+\tint old_page;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\tif (old_page \u003e= 0) {\n+\t\tif (reg_space == YT8824_RSSR_FIBER_SPACE) {\n+\t\t\tret = __phy_read(phydev, MII_BMCR);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t\t/* isolation */\n+\t\t\tret |= BIT(10);\n+\t\t\tret = __phy_write(phydev, MII_BMCR, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t}\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * do YT8824 UTP softreset.\n+ */\n+static int yt8824_soft_reset_step3_paged(struct phy_device *phydev,\n+\t\t\t\t\t int reg_space)\n+{\n+\tunsigned int retry = 12;\n+\tint old_page;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\tif (old_page \u003e= 0) {\n+\t\tif (reg_space == YT8824_RSSR_UTP_SPACE) {\n+\t\t\tret = __phy_read(phydev, MII_BMCR);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t\tret |= BMCR_RESET;\n+\t\t\tret = __phy_write(phydev, MII_BMCR, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t\tdo {\n+\t\t\t\tmsleep(50);\n+\t\t\t\tret = __phy_read(phydev, MII_BMCR);\n+\t\t\t\tif (ret \u003c 0)\n+\t\t\t\t\tgoto err_restore_page;\n+\t\t\t} while ((ret \u0026 BMCR_RESET) \u0026\u0026 --retry);\n+\t\t\tif (ret \u0026 BMCR_RESET)\n+\t\t\t\tgoto err_restore_page;\n+\t\t}\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * disable YT8824 template test mode.\n+ */\n+static int yt8824_soft_reset_step4_paged(struct phy_device *phydev,\n+\t\t\t\t\t int reg_space)\n+{\n+\tint old_page;\n+\tint port;\n+\tint ret;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tif (old_page \u003e= 0) {\n+\t\tif (reg_space == YT8824_RSSR_UTP_SPACE) {\n+\t\t\t/* normal mode */\n+\t\t\tret = ytphy_write_mmd(phydev, 0x1, 0x0084, 0x0000);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t\tif (port == 0 || port == 2) {\n+\t\t\t\t/* read the calibration val of band after power on,\n+\t\t\t\t * * only for recording.\n+\t\t\t\t */\n+\t\t\t\tret = ytphy_read_ext(phydev, 0x043e);\n+\t\t\t\tif (ret \u003c 0)\n+\t\t\t\t\tgoto err_restore_page;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * disable YT8824 serdes isolate.\n+ */\n+static int yt8824_soft_reset_step5_paged(struct phy_device *phydev,\n+\t\t\t\t\t int reg_space)\n+{\n+\tunsigned int retry = 12;\n+\tint old_page;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\tif (old_page \u003e= 0) {\n+\t\tif (reg_space == YT8824_RSSR_FIBER_SPACE) {\n+\t\t\tret = __phy_read(phydev, MII_BMCR);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t\t/* disable isolation */\n+\t\t\tret \u0026= ~BIT(10);\n+\t\t\t/* soft reset */\n+\t\t\tret |= BMCR_RESET;\n+\t\t\tret = __phy_write(phydev, MII_BMCR, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\treturn ret;\n+\t\t\tdo {\n+\t\t\t\tmsleep(50);\n+\t\t\t\tret = __phy_read(phydev, MII_BMCR);\n+\t\t\t\tif (ret \u003c 0)\n+\t\t\t\t\tgoto err_restore_page;\n+\t\t\t} while ((ret \u0026 BMCR_RESET) \u0026\u0026 --retry);\n+\t\t\tif (ret \u0026 BMCR_RESET)\n+\t\t\t\tgoto err_restore_page;\n+\t\t}\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_soft_reset() - called to issue a PHY software reset\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * for internal YT8824\n+ * 1) set utp template test mode\n+ * 2) utp restart\n+ * 3) disable utp template test mode\n+ * for external YT8824\n+ * 1) set utp template test mode\n+ * 2) enable serdes isolate\n+ * 3) utp restart\n+ * 4) disable utp template test mode\n+ * 5) disable serdes isolate\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_soft_reset(struct phy_device *phydev)\n+{\n+\tint ret;\n+\n+\tif (phydev-\u003einterface == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\t/* invalid test mode */\n+\t\tret = yt8824_soft_reset_step1_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\tret = yt8824_soft_reset_step3_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\t/* normal mode */\n+\t\tret = yt8824_soft_reset_step4_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t} else {\n+\t\t/* invalid test mode */\n+\t\tret = yt8824_soft_reset_step1_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* sds isolation */\n+\t\tret = yt8824_soft_reset_step2_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* utp soft reset */\n+\t\tret = yt8824_soft_reset_step3_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* normal mode */\n+\t\tret = yt8824_soft_reset_step4_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* sds soft reset and disable isolation */\n+\t\tret = yt8824_soft_reset_step5_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+/**\n+ * external YT8824 init\n+ */\n+static int yt8824_config_init_paged(struct phy_device *phydev, int reg_space)\n+{\n+\tstruct yt8521_priv *priv = phydev-\u003epriv;\n+\tint ret = 0, old_page;\n+\tu16 val_1, val_2, val_3, tmp;\n+\tint port;\n+\n+\tport = phydev-\u003emdio.addr - priv-\u003ephy_base_addr;\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tif (reg_space == YT8824_RSSR_FIBER_SPACE) {\n+\t\t/* read efuse */\n+\t\tval_1 = ytphy_read_top_ext_with_lock(phydev, 0xa13e);\n+\t\tif (val_1 \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tval_2 = ytphy_read_top_ext_with_lock(phydev, 0xa13f);\n+\t\tif (val_2 \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tval_3 = ytphy_read_top_ext_with_lock(phydev, 0xa140);\n+\t\tif (val_3 \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tif (port == 0) {\n+\t\t\t/* Serdes optimization */\n+\t\t\tret = ytphy_write_ext(phydev, 0x04be, 0x000d);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x049f, 0x7ded);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x04a9, 0x009f);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* analog CDR */\n+\t\t\tret = ytphy_write_ext(phydev, 0x0406, 0x0800);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* optimized VCO */\n+\t\t\tret = ytphy_write_ext(phydev, 0x0438, 0x9024);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x0439, 0x00c0);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* optimized PLL lock */\n+\t\t\tret = ytphy_read_ext(phydev, 0x0429);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret \u0026= ~(BIT(13) | BIT(12));\n+\t\t\ttmp = (val_1 \u0026 (BIT(7) | BIT(6)) \u003e\u003e 6);\n+\t\t\tret |= (tmp \u003c\u003c 12);\n+\t\t\tret = ytphy_write_ext(phydev, 0x0429, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_read_ext(phydev, 0x0441);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret \u0026= ~(BIT(1) | BIT(0));\n+\t\t\ttmp = (val_1 \u0026 (BIT(5) | BIT(4)) \u003e\u003e 4);\n+\t\t\tret |= tmp;\n+\t\t\tret = ytphy_write_ext(phydev, 0x0441, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_read_ext(phydev, 0x042b);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret \u0026= ~(BIT(13) | BIT(12));\n+\t\t\ttmp = (val_3 \u0026 (BIT(1) | BIT(0)));\n+\t\t\tret |= (tmp \u003c\u003c 12);\n+\t\t\tret = ytphy_write_ext(phydev, 0x042b, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x043a, 0x1006);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x042a, 0xf070);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* cable length threshold */\n+\t\t\tret = ytphy_write_ext(phydev, 0x0491, 0x007f);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x0492, 0x7f7f);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* Serdes training threshold */\n+\t\t\tret = ytphy_write_ext(phydev, 0x0454, 0x0f14);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x0497, 0x0a44);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* digital eye diagram of SerDes */\n+\t\t\tret = ytphy_write_ext(phydev, 0x04cd, 0x0000);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* Serdes LDO */\n+\t\t\tret = ytphy_read_ext(phydev, 0x04b5);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret \u0026= ~(BIT(6) | BIT(5) | BIT(4));\n+\t\t\ttmp = (val_2 \u0026 (BIT(4) | BIT(3) | BIT(2)) \u003e\u003e 2);\n+\t\t\tret |= (tmp \u003c\u003c 4);\n+\t\t\tret = ytphy_write_ext(phydev, 0x04b5, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_read_ext(phydev, 0x04b4);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret \u0026= ~(BIT(10) | BIT(9) | BIT(8));\n+\t\t\ttmp = (val_2 \u0026 (BIT(7) | BIT(6) | BIT(5)) \u003e\u003e 5);\n+\t\t\tret |= (tmp \u003c\u003c 8);\n+\t\t\tret = ytphy_write_ext(phydev, 0x04b4, ret);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* optimized Serdes RX */\n+\t\t\tret = ytphy_write_ext(phydev, 0x04af, 0x45e3);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x048a, 0x0fff);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x0408, 0x7c00);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x04d6, 0x007f);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x044f, 0xff08);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* optimized Serdes TX */\n+\t\t\tret = ytphy_write_ext(phydev, 0x048e, 0x7d00);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x000d, 0x0606);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* Serdes manual config */\n+\t\t\tret = ytphy_write_ext(phydev, 0x04b0, 0x0804);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x04b1, 0x7074);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x04af, 0x45e7);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\t/* restart calibration */\n+\t\t\tret = ytphy_write_ext(phydev, 0x0003, 0x5603);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x0492, 0x7fff);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x0492, 0x7f7f);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x2000, 0x0040);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\n+\t\t\tret = ytphy_write_ext(phydev, 0x2000, 0x0000);\n+\t\t\tif (ret \u003c 0)\n+\t\t\t\tgoto err_restore_page;\n+\t\t}\n+\n+\t\t/* TX preamble padded to 8; RX IPG always \u003e 8 */\n+\t\tret = __phy_write(phydev, 0x0017, 0x2007);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = __phy_write(phydev, 0x0000, 0x9000);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t} else if (reg_space == YT8824_RSSR_UTP_SPACE) {\n+\t\t/* power down */\n+\t\tret = __phy_write(phydev, 0x0000, 0x1900);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* pll calibration */\n+\t\tret = ytphy_write_ext(phydev, 0x0001, 0x0003);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa20e, 0x0cba);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa20a, 0xc3f1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa20c, 0x1620);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa2b6, 0x0a00);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa2b6, 0x0e00);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimization utp */\n+\t\tret = ytphy_write_ext(phydev, 0x0001, 0x0003);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* enable nibble */\n+\t\tret = ytphy_write_ext(phydev, 0xa003, 0x0003);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* idle err detect enable */\n+\t\tret = ytphy_write_ext(phydev, 0x03d0, 0x5210);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized 2.5G long cable performance */\n+\t\tret = ytphy_write_ext(phydev, 0x0372, 0x5038);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x037c, 0x6068);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0388, 0x00a0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized fast retrain */\n+\t\tret = ytphy_write_ext(phydev, 0x0359, 0x2140);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x000c, 0xc1a0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* 2.5G template tone */\n+\t\tret = ytphy_write_ext(phydev, 0xa2fa, 0x0083);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x04e2, 0x0149);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized 2.5G template */\n+\t\tret = ytphy_write_ext(phydev, 0x047e, 0x3939);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x047f, 0x3939);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0480, 0x3939);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0481, 0x3939);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized 1000M cable length threshold */\n+\t\tret = ytphy_write_ext(phydev, 0x0336, 0xab0a);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0340, 0x301d);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* 100M template amplitude */\n+\t\tret = ytphy_write_ext(phydev, 0x046e, 0x4545);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x046f, 0x4545);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0470, 0x4545);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0471, 0x4545);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized 100M cable length threshold */\n+\t\tret = ytphy_write_ext(phydev, 0x030b, 0xaa1d);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x071f, 0x0036);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* 10M template amplitude */\n+\t\tret = ytphy_write_ext(phydev, 0x046b, 0x1818);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x046c, 0x1818);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized 10M cable length threshold */\n+\t\tret = ytphy_write_ext(phydev, 0x0466, 0x6c6c);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0467, 0x6c6c);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0468, 0x6c6c);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0469, 0x6c6c);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimize utp 1000M performance */\n+\t\tret = ytphy_write_ext(phydev, 0x034a, 0xff03);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x00f8, 0xb3ff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0059, 0x4040);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x032c, 0x5094);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x032d, 0xd094);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x032e, 0x5308);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x0322, 0x6440);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x04d3, 0x5220);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x04d2, 0x5220);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized EMC CS */\n+\t\tret = ytphy_write_ext(phydev, 0x00c8, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x00be, 0x6406);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0x037a, 0x40ff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* optimized EMC RE */\n+\t\tret = ytphy_write_ext(phydev, 0x0482, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa2d5, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa2d6, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa2d7, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa2d8, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa218, 0x006e);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa01d, 0xfff0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa01e, 0xfff0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa01d, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_write_ext(phydev, 0xa01e, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * internal YT8824 init\n+ */\n+static int yt8824_internal_config_init_paged(struct phy_device *phydev,\n+\t\t\t\t\t int reg_space)\n+{\n+\tstruct yt8521_priv *priv = phydev-\u003epriv;\n+\tint old_page;\n+\tint port = 0;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tport = phydev-\u003emdio.addr - priv-\u003ephy_base_addr;\n+\tret = ytphy_write_ext(phydev, 0x1, 0x3);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = __phy_write(phydev, MII_BMCR, 0x1900);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tif (port == 0 || port == 2) {\n+\t\tret = ytphy_write_ext(phydev, 0xa20e, 0xcba);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa20a, 0xc3f1);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa20c, 0x1620);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa2b6, 0xa00);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa2b6, 0xe00);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa003, 0x3);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t}\n+\tret = ytphy_write_ext(phydev, 0x3d0, 0x5210);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x372, 0x5038);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x37c, 0x6068);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x388, 0xa0);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x359, 0x2140);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_top_ext(phydev, 0xa2fa, 0x83);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x4e2, 0x149);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 2.5G tempate */\n+\tret = ytphy_write_ext(phydev, 0x47e, 0x3939);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x47f, 0x3939);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x480, 0x3939);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x481, 0x3939);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 1000 cable length threshold */\n+\tret = ytphy_write_ext(phydev, 0x336, 0xab0a);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x340, 0x301d);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 1000 performance */\n+\tret = ytphy_write_ext(phydev, 0x34a, 0xff03);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0xf8, 0xb3ff);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x32c, 0x5094);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x32d, 0xd094);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x32e, 0x5308);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x322, 0x6440);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x4d3, 0x5220);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x4d2, 0x5220);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 100 tempate */\n+\tret = ytphy_write_ext(phydev, 0x46e, 0x4545);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x46f, 0x4545);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x470, 0x4545);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x471, 0x4545);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 100 cable length threshold */\n+\tret = ytphy_write_ext(phydev, 0x30b, 0xaa1d);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x71f, 0x36);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 10 tempate */\n+\tret = ytphy_write_ext(phydev, 0x46b, 0x1818);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x46c, 0x1818);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* 10 tempate MAU*/\n+\tret = ytphy_write_ext(phydev, 0x466, 0x6c6c);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x467, 0x6c6c);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x468, 0x6c6c);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x469, 0x6c6c);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* EMC CS */\n+\tret = ytphy_write_ext(phydev, 0xc8, 0xfff);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0xbe, 0x6406);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_ext(phydev, 0x37a, 0x40ff);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\t/* EMC RE*/\n+\tret = ytphy_write_ext(phydev, 0x482, 0xffff);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tif (port == 0 || port == 2) {\n+\t\tret = ytphy_write_ext(phydev, 0x482, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa2d5, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa2d6, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa2d7, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa2d8, 0x1f1f);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa218, 0x6e);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa01d, 0xfff0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa01e, 0xfff0);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa01d, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t\tret = ytphy_write_ext(phydev, 0xa01e, 0xffff);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t}\n+\tret = ytphy_write_ext(phydev, 0xc, 0x41a1);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_mmd(phydev, 0x1, 0x84, 0x2000);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = __phy_write(phydev, MII_BMCR, 0x9140);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\tret = ytphy_write_mmd(phydev, 0x1, 0x84, 0x0);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_config_init() - phy initializatioin\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * Returns: 0 or negative errno code\n+ */\n+static int yt8824_config_init(struct phy_device *phydev)\n+{\n+\tstruct yt8521_priv *priv = phydev-\u003epriv;\n+\tint ret;\n+\n+\tif (phydev-\u003einterface == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\t/* base addr and top addr update for internal YT8824*/\n+\t\tpriv-\u003ephy_base_addr = 0x4;\n+\t\tpriv-\u003etop_phy_addr = 0x9;\n+\t\tret = yt8824_internal_config_init_paged(phydev,\n+\t\t\t\t\t\t\tYT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t} else {\n+\t\tret = yt8824_config_init_paged(phydev, YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\tret = yt8824_config_init_paged(phydev, YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n+\tret = yt8824_soft_reset(phydev);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n+\tnetdev_info(phydev-\u003eattached_dev,\n+\t\t \"%s done, phy addr: %d, phy base addr = %d\\n\",\n+\t\t __func__, phydev-\u003emdio.addr, priv-\u003ephy_base_addr);\n+\n+\treturn 0;\n+}\n+\n+static int yt8824_config_intr(struct phy_device *phydev)\n+{\n+\tstruct yt8521_priv *priv = phydev-\u003epriv;\n+\tint ret = 0, old_page;\n+\tint port;\n+\n+\tport = phydev-\u003emdio.addr - priv-\u003ephy_base_addr;\n+\told_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tif (phydev-\u003einterrupts == PHY_INTERRUPT_ENABLED) {\n+\t\t/* top ext reg 0xa000\n+\t\t * bit6 int_polarity 1'b0 low active, 1'b1 high active\n+\t\t */\n+\t\tret = ytphy_top_read(phydev, YT8521_REG_SPACE_SELECT_REG);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_top_write(phydev, YT8521_REG_SPACE_SELECT_REG, ret \u0026 (~BIT(6)));\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* top ext reg 0xa019\n+\t\t * bit5 intr_phy_pulse_en 1'b0 level, 1'b1 pulse\n+\t\t */\n+\t\tret = ytphy_top_read(phydev, 0xa019);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_top_write(phydev, 0xa019, ret | BIT(5));\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* top ext reg 0xa018 phy_pulse_lth bit14:8\n+\t\t * top ext reg 0xa019 timer_tick_sel bit8:7\n+\t\t * bit14:8 phy_pulse_lth bit8:7 timer_tick_sel pulse width\n+\t\t * 0x007a\t\t 0x0002\t\t 10ms pulse width\n+\t\t * 0x0064\t\t 0x0001\t\t 1ms pulse width\n+\t\t * 0x004e\t\t 0x0000\t\t 100ms pulse width\n+\t\t * 0x0009\t\t 0x0000\t\t 10ms pulse width(default)\n+\t\t */\n+\t\tret = ytphy_top_read(phydev, 0xa018);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret \u0026= ~0x7f00;\n+\t\tret |= (0x0009 \u003c\u003c 8);\n+\t\tret = ytphy_top_write(phydev, 0xa018, ret);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret = ytphy_top_read(phydev, 0xa019);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret \u0026= ~0x180;\n+\t\tret |= (0x0000 \u003c\u003c 7);\n+\t\tret = ytphy_top_write(phydev, 0xa019, ret);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* top ext reg 0xa01c interrupt state(Read Clear)\n+\t\t * bit11 PHY3 interrupt 1: phy3 link up/down interrupt happened, 0: interrupt not happened\n+\t\t * bit10 PHY2 interrupt 1: phy2 link up/down interrupt happened, 0: interrupt not happened\n+\t\t * bit9 PHY1 interrupt 1: phy1 link up/down interrupt happened, 0: interrupt not happened\n+\t\t * bit8 PHY0 interrupt 1: phy0 link up/down interrupt happened, 0: interrupt not happened\n+\t\t *\n+\t\t * bit7 PHY3 link down 1: phy3 link down interrupt happened, 0: interrupt not happened\n+\t\t * bit6 PHY2 link down 1: phy2 link down interrupt happened, 0: interrupt not happened\n+\t\t * bit5 PHY1 link down 1: phy1 link down interrupt happened, 0: interrupt not happened\n+\t\t * bit4 PHY0 link down 1: phy0 link down interrupt happened, 0: interrupt not happened\n+\t\t *\n+\t\t * bit3 PHY3 link up 1: phy3 link up interrupt happened, 0: interrupt not happened\n+\t\t * bit2 PHY2 link up 1: phy2 link up interrupt happened, 0: interrupt not happened\n+\t\t * bit1 PHY1 link up 1: phy1 link up interrupt happened, 0: interrupt not happened\n+\t\t * bit0 PHY0 link up 1: phy0 link up interrupt happened, 0: interrupt not happened\n+\t\t */\n+\t\tret = ytphy_top_read(phydev, 0xa01c);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* top ext reg 0xa01a\n+\t\t * bit5 intn_wol_mode 1'b1 enable intn_wol pin output\n+\t\t * bit4 intn_mode 1'b1 enable intn pin output\n+\t\t */\n+\t\tret = ytphy_top_read(phydev, 0xa01a);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret \u0026= ~BIT(5);\n+\t\tret |= BIT(4);\n+\t\tret = ytphy_top_write(phydev, 0xa01a, ret);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\t/* top ext reg 0xa01b interrupt mask\n+\t\t * bit11 1'b1 enable interrupt signal(link up/down) output to interrupt pin\n+\t\t * bit7 1'b1 enable interrupt signal(link down) output to interrupt pin\n+\t\t * bit3 1'b1 enable interrupt signal(link up) output to interrupt pin\n+\t\t *\n+\t\t * bit10 1'b1 enable interrupt signal(link up/down) output to interrupt pin\n+\t\t * bit6 1'b1 enable interrupt signal(link down) output to interrupt pin\n+\t\t * bit2 1'b1 enable interrupt signal(link up) output to interrupt pin\n+\t\t *\n+\t\t * bit9 1'b1 enable interrupt signal(link up/down) output to interrupt pin\n+\t\t * bit5 1'b1 enable interrupt signal(link down) output to interrupt pin\n+\t\t * bit1 1'b1 enable interrupt signal(link up) output to interrupt pin\n+\t\t *\n+\t\t * bit8 1'b1 enable interrupt signal(link up/down) output to interrupt pin\n+\t\t * bit4 1'b1 enable interrupt signal(link down) output to interrupt pin\n+\t\t * bit0 1'b1 enable interrupt signal(link up) output to interrupt pin\n+\t\t */\n+\t\tret = ytphy_top_read(phydev, 0xa01b);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\n+\t\tret |= (BIT(port + 8) | BIT(port + 4) | BIT(port));\n+\t\tret = ytphy_top_write(phydev, 0xa01b, ret);\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto err_restore_page;\n+\t}\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+static irqreturn_t yt8824_handle_interrupt(struct phy_device *phydev)\n+{\n+\tint ret = 0, old_page;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\t/* top ext reg 0xa01c interrupt state(Read Clear)\n+\t * bit11 PHY3 interrupt 1: phy3 link up/down interrupt happened, 0: interrupt not happened\n+\t * bit10 PHY2 interrupt 1: phy2 link up/down interrupt happened, 0: interrupt not happened\n+\t * bit9 PHY1 interrupt 1: phy1 link up/down interrupt happened, 0: interrupt not happened\n+\t * bit8 PHY0 interrupt 1: phy0 link up/down interrupt happened, 0: interrupt not happened\n+\t * bit7 PHY3 link down 1: phy3 link down interrupt happened, 0: interrupt not happened\n+\t * bit6 PHY2 link down 1: phy2 link down interrupt happened, 0: interrupt not happened\n+\t * bit5 PHY1 link down 1: phy1 link down interrupt happened, 0: interrupt not happened\n+\t * bit4 PHY0 link down 1: phy0 link down interrupt happened, 0: interrupt not happened\n+\t * bit3 PHY3 link up 1: phy3 link up interrupt happened, 0: interrupt not happened\n+\t * bit2 PHY2 link up 1: phy2 link up interrupt happened, 0: interrupt not happened\n+\t * bit1 PHY1 link up 1: phy1 link up interrupt happened, 0: interrupt not happened\n+\t * bit0 PHY0 link up 1: phy0 link up interrupt happened, 0: interrupt not happened\n+\t */\n+\tret = ytphy_read_top_ext(phydev, 0xa01c);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tphy_trigger_machine(phydev);\n+\n+err_restore_page:\n+\tphy_restore_page(phydev, old_page, ret);\n+\tif (ret \u003e 0)\n+\t\treturn IRQ_HANDLED;\n+\telse\n+\t\treturn IRQ_NONE;\n+}\n+\n+/**\n+ * yt8824_config_aneg()\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_aneg_done(struct phy_device *phydev)\n+{\n+\tint link = 0;\n+\tint old_page;\n+\tint ret = 0;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tlink = !!(__phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG) \u0026\n+\t\t\t YTPHY_SSR_LINK);\n+\n+\tnetdev_info(phydev-\u003eattached_dev, \"%s, phy addr: %d, link_utp: %d\\n\",\n+\t\t __func__, phydev-\u003emdio.addr, link);\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_read_status_paged() - determines the speed and duplex of one page\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ * @page: The reg page(YT8824_RSSR_FIBER_SPACE/YT8824_RSSR_UTP_SPACE) to\n+ * operate.\n+ *\n+ * returns 1 (utp or fiber link),0 (no link) or negative errno code\n+ */\n+static int yt8824_read_status_paged(struct phy_device *phydev, int page,\n+\t\t\t\t int *status, int *lpa)\n+{\n+\tint old_page;\n+\tint ret = 0;\n+\n+\tpage \u0026= YT8824_RSSR_SPACE_MASK;\n+\told_page = phy_select_page(phydev, page);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = __phy_read(phydev, MII_LPA);\n+\t*lpa = ret;\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);\n+\t*status = ret;\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = !!(*status \u0026 YTPHY_SSR_LINK);\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_read_status() - determines the negotiated speed and duplex\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_read_status(struct phy_device *phydev)\n+{\n+\tint link;\n+\tint lpa;\n+\tint val;\n+\n+\tphydev-\u003epause = 0;\n+\tphydev-\u003easym_pause = 0;\n+\tphydev-\u003elink = 0;\n+\tphydev-\u003espeed = SPEED_UNKNOWN;\n+\tphydev-\u003eduplex = DUPLEX_UNKNOWN;\n+\n+\tlink = yt8824_read_status_paged(phydev,\n+\t\t\t\t\tYT8824_RSSR_UTP_SPACE, \u0026val, \u0026lpa);\n+\tif (link \u003c 0)\n+\t\treturn link;\n+\n+\tif (link) {\n+\t\tphydev-\u003elink = 1;\n+\t\tphydev-\u003epause = !!(lpa \u0026 BIT(10));\n+\t\tphydev-\u003easym_pause = !!(lpa \u0026 BIT(11));\n+\n+\t\t/* update speed \u0026 duplex */\n+\t\tyt8821_adjust_status(phydev, val);\n+\t} else {\n+\t\tphydev-\u003elink = 0;\n+\t\tphydev-\u003epause = 0;\n+\t\tphydev-\u003easym_pause = 0;\n+\t\tphydev-\u003espeed = SPEED_UNKNOWN;\n+\t\tphydev-\u003eduplex = DUPLEX_UNKNOWN;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * yt8824_utp_power_on()\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_utp_power_on(struct phy_device *phydev,\n+\t\t\t int reg_space)\n+{\n+\tint old_page;\n+\tint ret;\n+\n+\told_page = phy_select_page(phydev, reg_space);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = __phy_read(phydev, MII_BMCR);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret \u0026= ~BMCR_PDOWN;\n+\tret \u0026= ~BMCR_ISOLATE;\n+\n+\tret = __phy_write(phydev, MII_BMCR, ret);\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_utp_power_down()\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_utp_power_down(struct phy_device *phydev,\n+\t\t\t\t int reg_space)\n+{\n+\tint ret = 0, old_page;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = __phy_read(phydev, MII_BMCR);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tret = __phy_write(phydev, MII_BMCR, ret | BMCR_PDOWN);\n+\tif (ret \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_power_on()\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ * need WA like softreset\n+ */\n+static int yt8824_power_on(struct phy_device *phydev)\n+{\n+\tint ret;\n+\n+\tif (phydev-\u003einterface == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\t/* invalid test mode */\n+\t\tret = yt8824_soft_reset_step1_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\t/* utp power on */\n+\t\tret = yt8824_utp_power_on(phydev, YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\t/* normal mode */\n+\t\tret = yt8824_soft_reset_step4_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t} else {\n+\t\t/* invalid test mode */\n+\t\tret = yt8824_soft_reset_step1_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* sds isolation */\n+\t\tret = yt8824_soft_reset_step2_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* utp power on */\n+\t\tret = yt8824_utp_power_on(phydev, YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* normal mode */\n+\t\tret = yt8824_soft_reset_step4_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* sds soft reset and disable isolation */\n+\t\tret = yt8824_soft_reset_step5_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static int yt8824_resume(struct phy_device *phydev)\n+{\n+\treturn yt8824_power_on(phydev);\n+}\n+\n+static int yt8824_power_down(struct phy_device *phydev)\n+{\n+\tint ret;\n+\n+\tif (phydev-\u003einterface == PHY_INTERFACE_MODE_INTERNAL) {\n+\t\t/* invalid test mode */\n+\t\tret = yt8824_soft_reset_step1_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\t/* utp power down */\n+\t\tret = yt8824_utp_power_down(phydev, YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t\t/* normal mode */\n+\t\tret = yt8824_soft_reset_step4_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t} else {\n+\t\t/* invalid test mode */\n+\t\tret = yt8824_soft_reset_step1_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* sds isolation */\n+\t\tret = yt8824_soft_reset_step2_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* utp power down */\n+\t\tret = yt8824_utp_power_down(phydev, YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* normal mode */\n+\t\tret = yt8824_soft_reset_step4_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_UTP_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* sds soft reset and disable isolation */\n+\t\tret = yt8824_soft_reset_step5_paged(phydev,\n+\t\t\t\t\t\t YT8824_RSSR_FIBER_SPACE);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n+static int yt8824_suspend(struct phy_device *phydev)\n+{\n+\treturn yt8824_power_down(phydev);\n+}\n+\n+/**\n+ * yt8824_config_aneg()\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_config_aneg(struct phy_device *phydev)\n+{\n+\tint phy_ctrl = 0;\n+\tint old_page;\n+\tint ret;\n+\n+\told_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);\n+\tif (old_page \u003c 0)\n+\t\tgoto err_restore_page;\n+\n+\tif (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,\n+\t\t\t phydev-\u003eadvertising))\n+\t\tphy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;\n+\n+\tret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,\n+\t\t\t\t MDIO_AN_10GBT_CTRL,\n+\t\t\t\t MDIO_AN_10GBT_CTRL_ADV2_5G,\n+\t\t\t\t phy_ctrl);\n+\tif (ret)\n+\t\tgoto err_restore_page;\n+\n+\tret = genphy_config_aneg(phydev);\n+\tif (ret)\n+\t\tgoto err_restore_page;\n+\n+err_restore_page:\n+\treturn phy_restore_page(phydev, old_page, ret);\n+}\n+\n+/**\n+ * yt8824_probe()\n+ * @phydev: a pointer to a \u0026struct phy_device\n+ *\n+ * returns 0 or negative errno code\n+ */\n+static int yt8824_probe(struct phy_device *phydev)\n+{\n+\tstruct device *dev = \u0026phydev-\u003emdio.dev;\n+\tstruct yt8521_priv *priv;\n+\tu32 phy_base_addr;\n+\n+\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tphydev-\u003epriv = priv;\n+\n+\t/* get base addr and top addr for external YT8824 */\n+\tif (!device_property_read_u32(dev, \"motorcomm,base-address\",\n+\t\t\t\t \u0026phy_base_addr))\n+\t\tpriv-\u003ephy_base_addr = phy_base_addr;\n+\telse\n+\t\tpriv-\u003ephy_base_addr = PHY_BASE_ADDR;\n+\n+\tpriv-\u003etop_phy_addr = priv-\u003ephy_base_addr + 4;\n+\n+\treturn 0;\n+}\n+\n+static struct phy_driver motorcomm_phy_drvs[] = {\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8511),\n+\t\t.name\t\t= \"YT8511 Gigabit Ethernet\",\n+\t\t.config_init\t= yt8511_config_init,\n+\t\t.suspend\t= genphy_suspend,\n+\t\t.resume\t\t= genphy_resume,\n+\t\t.read_page\t= yt8511_read_page,\n+\t\t.write_page\t= yt8511_write_page,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8521),\n+\t\t.name\t\t= \"YT8521 Gigabit Ethernet\",\n+\t\t.get_features\t= yt8521_get_features,\n+\t\t.probe\t\t= yt8521_probe,\n+\t\t.read_page\t= yt8521_read_page,\n+\t\t.write_page\t= yt8521_write_page,\n+\t\t.get_wol\t= ytphy_get_wol,\n+\t\t.set_wol\t= ytphy_set_wol,\n+\t\t.config_aneg\t= yt8521_config_aneg,\n+\t\t.aneg_done\t= yt8521_aneg_done,\n+\t\t.config_init\t= yt8521_config_init,\n+\t\t.read_status\t= yt8521_read_status,\n+\t\t.soft_reset\t= yt8521_soft_reset,\n+\t\t.suspend\t= yt8521_suspend,\n+\t\t.resume\t\t= yt8521_resume,\n+\t\t.led_hw_is_supported = yt8521_led_hw_is_supported,\n+\t\t.led_hw_control_set = yt8521_led_hw_control_set,\n+\t\t.led_hw_control_get = yt8521_led_hw_control_get,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8522),\n+\t\t.name\t\t= \"YT8522 100 Megabit Ethernet\",\n+\t\t.config_aneg\t= genphy_config_aneg,\n+\t\t.config_init\t= yt8522_config_init,\n+\t\t.suspend\t= genphy_suspend,\n+\t\t.resume\t\t= genphy_resume,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8531),\n+\t\t.name\t\t= \"YT8531 Gigabit Ethernet\",\n+\t\t.probe\t\t= yt8531_probe,\n+\t\t.config_init\t= yt8531_config_init,\n+\t\t.suspend\t= genphy_suspend,\n+\t\t.resume\t\t= genphy_resume,\n+\t\t.get_wol\t= ytphy_get_wol,\n+\t\t.set_wol\t= yt8531_set_wol,\n+\t\t.link_change_notify = yt8531_link_change_notify,\n+\t\t.led_hw_is_supported = yt8521_led_hw_is_supported,\n+\t\t.led_hw_control_set = yt8521_led_hw_control_set,\n+\t\t.led_hw_control_get = yt8521_led_hw_control_get,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8531S),\n+\t\t.name\t\t= \"YT8531S Gigabit Ethernet\",\n+\t\t.get_features\t= yt8521_get_features,\n+\t\t.probe\t\t= yt8521_probe,\n+\t\t.read_page\t= yt8521_read_page,\n+\t\t.write_page\t= yt8521_write_page,\n+\t\t.get_wol\t= ytphy_get_wol,\n+\t\t.set_wol\t= ytphy_set_wol,\n+\t\t.config_aneg\t= yt8521_config_aneg,\n+\t\t.aneg_done\t= yt8521_aneg_done,\n+\t\t.config_init\t= yt8521_config_init,\n+\t\t.read_status\t= yt8521_read_status,\n+\t\t.soft_reset\t= yt8521_soft_reset,\n+\t\t.suspend\t= yt8521_suspend,\n+\t\t.resume\t\t= yt8521_resume,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8821),\n+\t\t.name\t\t\t= \"YT8821 2.5Gbps PHY\",\n+\t\t.get_features\t\t= yt8821_get_features,\n+\t\t.read_page\t\t= yt8521_read_page,\n+\t\t.write_page\t\t= yt8521_write_page,\n+\t\t.get_wol\t\t= ytphy_get_wol,\n+\t\t.set_wol\t\t= ytphy_set_wol,\n+\t\t.config_aneg\t\t= genphy_config_aneg,\n+\t\t.aneg_done\t\t= yt8821_aneg_done,\n+\t\t.config_init\t\t= yt8821_config_init,\n+\t\t.get_rate_matching\t= yt8821_get_rate_matching,\n+\t\t.read_status\t\t= yt8821_read_status,\n+\t\t.soft_reset\t\t= yt8821_soft_reset,\n+\t\t.suspend\t\t= yt8821_suspend,\n+\t\t.resume\t\t\t= yt8821_resume,\n+\t},\n+\t{\n+\t\tPHY_ID_MATCH_EXACT(PHY_ID_YT8824),\n+\t\t.name\t\t\t= \"YT8824 Quad Ports 2.5Gbps Ethernet\",\n+\t\t.get_features\t\t= yt8821_get_features,\n+\t\t.read_page\t\t= yt8824_read_page,\n+\t\t.write_page\t\t= yt8824_write_page,\n+\t\t.config_intr = yt8824_config_intr,\n+\t\t.handle_interrupt\t= yt8824_handle_interrupt,\n+\t\t.probe\t\t = yt8824_probe,\n+\t\t.config_aneg\t\t= yt8824_config_aneg,\n+\t\t.aneg_done\t\t= yt8824_aneg_done,\n+\t\t.config_init\t\t= yt8824_config_init,\n+\t\t.read_status\t\t= yt8824_read_status,\n+\t\t.soft_reset\t\t= yt8824_soft_reset,\n+\t\t.suspend\t\t= yt8824_suspend,\n+\t\t.resume\t\t\t= yt8824_resume,\n \t},\n };\n \n module_phy_driver(motorcomm_phy_drvs);\n \n-MODULE_DESCRIPTION(\"Motorcomm 8511/8521/8531/8531S/8821 PHY driver\");\n+MODULE_DESCRIPTION(\"Motorcomm 8511/8521/8531/8531S/8821/8824 PHY driver\");\n MODULE_AUTHOR(\"Peter Geis\");\n MODULE_AUTHOR(\"Frank\");\n+MODULE_AUTHOR(\"Kyle\");\n MODULE_LICENSE(\"GPL\");\n \n static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {\n@@ -3161,6 +4810,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {\n \t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },\n \t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },\n \t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },\n+\t{ PHY_ID_MATCH_EXACT(PHY_ID_YT8824) },\n \t{ /* sentinel */ }\n };\n \n"
} |
| 2/1 | 2026/07/14 16:37 | agent | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": [
"MOTORCOMM_PHY"
],
"FocusSymbols": [
"yt8824_probe",
"yt8824_config_init",
"yt8824_config_aneg",
"yt8824_read_status",
"yt8824_soft_reset",
"yt8824_suspend",
"yt8824_resume",
"yt8824_config_intr",
"yt8824_handle_interrupt",
"yt8824_aneg_done",
"yt8824_read_page",
"yt8824_write_page"
],
"Reasoning": "The patch adds support for the Motorcomm YT8824 PHY. This code can be reached in a virtualized environment by emulating a USB network adapter (e.g., smsc95xx or lan78xx) that registers an MDIO bus, and responding to MDIO reads with the YT8824 PHY ID. This will cause the kernel to bind the new PHY driver and execute its initialization and state machine logic.",
"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 9c1a8c3e13f0f7dae507e535de880196845ed664
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Jul 14 16:37:01 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
index 5071605a1a117a..e6f93ed4349cab 100644
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Motorcomm 8511/8521/8522/8531/8531S/8821 PHY driver.
+ * Motorcomm 8511/8521/8522/8531/8531S/8821/8824 PHY driver.
*
* Author: Peter Geis <pgwipeout@gmail.com>
* Author: Frank <Frank.Sae@motor-comm.com>
+ * Author: Kyle <kyle.switch@motor-comm.com>
*/
#include <linux/etherdevice.h>
@@ -12,12 +13,16 @@
#include <linux/phy.h>
#include <linux/property.h>
+/* used for phy8824 baseaddr */
+#define PHY_BASE_ADDR (1)
+
#define PHY_ID_YT8511 0x0000010a
#define PHY_ID_YT8521 0x0000011a
#define PHY_ID_YT8522 0x4f51e928
#define PHY_ID_YT8531 0x4f51e91b
#define PHY_ID_YT8531S 0x4f51e91a
#define PHY_ID_YT8821 0x4f51ea19
+#define PHY_ID_YT8824 0x4f51e8b8
/* YT8521/YT8531S/YT8821 Register Overview
* UTP Register space | FIBER Register space
* ------------------------------------------------------------
@@ -29,6 +34,18 @@
* ------------------------------------------------------------
*/
+/* YT8824 Register Overview
+ * UTP Register space | FIBER Register space
+ * ------------------------------------------------------------
+ * | UTP MII | FIBER MII |
+ * | UTP MMD | |
+ * | UTP Extended | FIBER Extended |
+ * | UTP Top Extended | FIBER Top Extended |
+ * ------------------------------------------------------------
+ * | Common Top Extended |
+ * ------------------------------------------------------------
+ */
+
/* 0x10 ~ 0x15 , 0x1E and 0x1F are common MII registers of yt phy */
/* Specific Function Control Register */
@@ -375,6 +392,12 @@
#define YT8821_CHIP_MODE_AUTO_BX2500_SGMII 0
#define YT8821_CHIP_MODE_FORCE_BX2500 1
+#define YT8824_RSSR_SPACE_MASK BIT(0)
+#define YT8824_RSSR_FIBER_SPACE (0x1)
+#define YT8824_RSSR_UTP_SPACE (0x0)
+#define REG_MII_MMD_CTRL 0x0D
+#define REG_MII_MMD_DATA 0x0E
+
struct yt8521_priv {
/* combo_advertising is used for case of YT8521 in combo mode,
* this means that yt8521 may work in utp or fiber mode which depends
@@ -391,8 +414,29 @@ struct yt8521_priv {
* YT8521_RSSR_TO_BE_ARBITRATED
*/
u8 reg_page;
+ /* YT8824 reg space addr */
+ u8 phy_base_addr;
+ /* top extend reg addr */
+ u8 top_phy_addr;
};
+static inline int ytphy_top_write(struct phy_device *phydev, u32 regnum,
+ u16 val)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ struct mii_bus *bus = phydev->mdio.bus;
+
+ return bus->write(bus, priv->top_phy_addr, regnum, val);
+}
+
+static inline int ytphy_top_read(struct phy_device *phydev, u32 regnum)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ struct mii_bus *bus = phydev->mdio.bus;
+
+ return bus->read(bus, priv->top_phy_addr, regnum);
+}
+
/**
* ytphy_read_ext() - read a PHY's extended register
* @phydev: a pointer to a &struct phy_device
@@ -431,6 +475,70 @@ static int ytphy_read_ext_with_lock(struct phy_device *phydev, u16 regnum)
return ret;
}
+/**
+ * ytphy_read_top_ext() - read a PHY's top extended register for YT8824
+ * @phydev: a pointer to a &struct phy_device
+ * @regnum: register number to read
+ *
+ * NOTE:The caller must have taken the MDIO bus lock.
+ *
+ * returns the value of regnum reg or negative error code
+ */
+static int ytphy_read_top_ext(struct phy_device *phydev, u16 regnum)
+{
+ int ret;
+
+ ret = ytphy_top_write(phydev, YTPHY_PAGE_SELECT, regnum);
+ if (ret < 0)
+ return ret;
+
+ return ytphy_top_read(phydev, YTPHY_PAGE_DATA);
+}
+
+static int ytphy_read_top_ext_with_lock(struct phy_device *phydev, u16 regnum)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = ytphy_read_top_ext(phydev, regnum);
+ phy_unlock_mdio_bus(phydev);
+
+ return ret;
+}
+
+/**
+ * ytphy_write_top_ext() - read a PHY's top extended register for YT8824
+ * @phydev: a pointer to a &struct phy_device
+ * @regnum: register number to read
+ *
+ * NOTE:The caller must have taken the MDIO bus lock.
+ *
+ * returns the value of regnum reg or negative error code
+ */
+static int ytphy_write_top_ext(struct phy_device *phydev, u16 regnum,
+ u16 val)
+{
+ int ret;
+
+ ret = ytphy_top_write(phydev, YTPHY_PAGE_SELECT, regnum);
+ if (ret < 0)
+ return ret;
+
+ return ytphy_top_write(phydev, YTPHY_PAGE_DATA, val);
+}
+
+static int ytphy_write_top_ext_with_lock(struct phy_device *phydev, u16 regnum,
+ u16 val)
+{
+ int ret;
+
+ phy_lock_mdio_bus(phydev);
+ ret = ytphy_write_top_ext(phydev, regnum, val);
+ phy_unlock_mdio_bus(phydev);
+
+ return ret;
+}
+
/**
* ytphy_write_ext() - write a PHY's extended register
* @phydev: a pointer to a &struct phy_device
@@ -521,6 +629,26 @@ static int ytphy_modify_ext_with_lock(struct phy_device *phydev, u16 regnum,
return ret;
}
+static int ytphy_write_mmd(struct phy_device *phydev,
+ u16 device, u16 reg,
+ u16 value)
+{
+ int ret;
+
+ ret = __phy_write(phydev, REG_MII_MMD_CTRL, device);
+ if (ret)
+ return ret;
+ ret = __phy_write(phydev, REG_MII_MMD_DATA, reg);
+ if (ret)
+ return ret;
+ ret = __phy_write(phydev, REG_MII_MMD_CTRL, device | 0x4000);
+ if (ret)
+ return ret;
+ ret = __phy_write(phydev, REG_MII_MMD_DATA, value);
+
+ return ret;
+}
+
/**
* ytphy_get_wol() - report whether wake-on-lan is enabled
* @phydev: a pointer to a &struct phy_device
@@ -3059,99 +3187,1620 @@ static int yt8821_resume(struct phy_device *phydev)
return yt8821_modify_utp_fiber_bmcr(phydev, BMCR_PDOWN, 0);
}
-static struct phy_driver motorcomm_phy_drvs[] = {
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
- .name = "YT8511 Gigabit Ethernet",
- .config_init = yt8511_config_init,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .read_page = yt8511_read_page,
- .write_page = yt8511_write_page,
- },
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8521),
- .name = "YT8521 Gigabit Ethernet",
- .get_features = yt8521_get_features,
- .probe = yt8521_probe,
- .read_page = yt8521_read_page,
- .write_page = yt8521_write_page,
- .get_wol = ytphy_get_wol,
- .set_wol = ytphy_set_wol,
- .config_aneg = yt8521_config_aneg,
- .aneg_done = yt8521_aneg_done,
- .config_init = yt8521_config_init,
- .read_status = yt8521_read_status,
- .soft_reset = yt8521_soft_reset,
- .suspend = yt8521_suspend,
- .resume = yt8521_resume,
- .led_hw_is_supported = yt8521_led_hw_is_supported,
- .led_hw_control_set = yt8521_led_hw_control_set,
- .led_hw_control_get = yt8521_led_hw_control_get,
- },
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8522),
- .name = "YT8522 100 Megabit Ethernet",
- .config_aneg = genphy_config_aneg,
- .config_init = yt8522_config_init,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- },
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
- .name = "YT8531 Gigabit Ethernet",
- .probe = yt8531_probe,
- .config_init = yt8531_config_init,
- .suspend = genphy_suspend,
- .resume = genphy_resume,
- .get_wol = ytphy_get_wol,
- .set_wol = yt8531_set_wol,
- .link_change_notify = yt8531_link_change_notify,
- .led_hw_is_supported = yt8521_led_hw_is_supported,
- .led_hw_control_set = yt8521_led_hw_control_set,
- .led_hw_control_get = yt8521_led_hw_control_get,
- },
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
- .name = "YT8531S Gigabit Ethernet",
- .get_features = yt8521_get_features,
- .probe = yt8521_probe,
- .read_page = yt8521_read_page,
- .write_page = yt8521_write_page,
- .get_wol = ytphy_get_wol,
- .set_wol = ytphy_set_wol,
- .config_aneg = yt8521_config_aneg,
- .aneg_done = yt8521_aneg_done,
- .config_init = yt8521_config_init,
- .read_status = yt8521_read_status,
- .soft_reset = yt8521_soft_reset,
- .suspend = yt8521_suspend,
- .resume = yt8521_resume,
- },
- {
- PHY_ID_MATCH_EXACT(PHY_ID_YT8821),
- .name = "YT8821 2.5Gbps PHY",
- .get_features = yt8821_get_features,
- .read_page = yt8521_read_page,
- .write_page = yt8521_write_page,
- .get_wol = ytphy_get_wol,
- .set_wol = ytphy_set_wol,
- .config_aneg = genphy_config_aneg,
- .aneg_done = yt8821_aneg_done,
- .config_init = yt8821_config_init,
- .get_rate_matching = yt8821_get_rate_matching,
- .read_status = yt8821_read_status,
- .soft_reset = yt8821_soft_reset,
- .suspend = yt8821_suspend,
- .resume = yt8821_resume,
+/**
+ * yt8824_read_page() - read reg page
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns current reg space of yt8824 (YT8824_RSSR_FIBER_SPACE/
+ * YT8824_RSSR_UTP_SPACE) or negative errno code
+ */
+static int yt8824_read_page(struct phy_device *phydev)
+{
+ int old_page;
+
+ old_page = ytphy_read_top_ext_with_lock(phydev, YT8521_REG_SPACE_SELECT_REG);
+ if (old_page < 0)
+ return old_page;
+
+ if ((old_page & YT8824_RSSR_SPACE_MASK) == YT8824_RSSR_FIBER_SPACE)
+ return YT8824_RSSR_FIBER_SPACE;
+
+ return YT8824_RSSR_UTP_SPACE;
+};
+
+/**
+ * yt8824_write_page() - write reg page
+ * @phydev: a pointer to a &struct phy_device
+ * @page: The reg page(YT8824_RSSR_FIBER_SPACE/YT8824_RSSR_UTP_SPACE) to write.
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_write_page(struct phy_device *phydev, int page)
+{
+ int old_page;
+ u16 data;
+
+ old_page = ytphy_read_top_ext_with_lock(phydev, YT8521_REG_SPACE_SELECT_REG);
+ data = old_page & (~(0x1));
+ data |= page;
+
+ return ytphy_write_top_ext_with_lock(phydev, YT8521_REG_SPACE_SELECT_REG, data);
+};
+
+/**
+ * configuration YT8824 to one template test mode.
+ */
+static int yt8824_soft_reset_step1_paged(struct phy_device *phydev,
+ int reg_space)
+{
+ int old_page;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ if (old_page >= 0) {
+ if (reg_space == YT8824_RSSR_UTP_SPACE) {
+ ret = ytphy_write_mmd(phydev, 0x1, 0x0084, 0x2000);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * enable YT8824 serdes isolate.
+ */
+static int yt8824_soft_reset_step2_paged(struct phy_device *phydev,
+ int reg_space)
+{
+ int old_page;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+ if (old_page >= 0) {
+ if (reg_space == YT8824_RSSR_FIBER_SPACE) {
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+ /* isolation */
+ ret |= BIT(10);
+ ret = __phy_write(phydev, MII_BMCR, ret);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * do YT8824 UTP softreset.
+ */
+static int yt8824_soft_reset_step3_paged(struct phy_device *phydev,
+ int reg_space)
+{
+ unsigned int retry = 12;
+ int old_page;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+ if (old_page >= 0) {
+ if (reg_space == YT8824_RSSR_UTP_SPACE) {
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+ ret |= BMCR_RESET;
+ ret = __phy_write(phydev, MII_BMCR, ret);
+ if (ret < 0)
+ goto err_restore_page;
+ do {
+ msleep(50);
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+ } while ((ret & BMCR_RESET) && --retry);
+ if (ret & BMCR_RESET)
+ goto err_restore_page;
+ }
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * disable YT8824 template test mode.
+ */
+static int yt8824_soft_reset_step4_paged(struct phy_device *phydev,
+ int reg_space)
+{
+ int old_page;
+ int port;
+ int ret;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ if (old_page >= 0) {
+ if (reg_space == YT8824_RSSR_UTP_SPACE) {
+ /* normal mode */
+ ret = ytphy_write_mmd(phydev, 0x1, 0x0084, 0x0000);
+ if (ret < 0)
+ goto err_restore_page;
+ if (port == 0 || port == 2) {
+ /* read the calibration val of band after power on,
+ * * only for recording.
+ */
+ ret = ytphy_read_ext(phydev, 0x043e);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+ }
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * disable YT8824 serdes isolate.
+ */
+static int yt8824_soft_reset_step5_paged(struct phy_device *phydev,
+ int reg_space)
+{
+ unsigned int retry = 12;
+ int old_page;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+ if (old_page >= 0) {
+ if (reg_space == YT8824_RSSR_FIBER_SPACE) {
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+ /* disable isolation */
+ ret &= ~BIT(10);
+ /* soft reset */
+ ret |= BMCR_RESET;
+ ret = __phy_write(phydev, MII_BMCR, ret);
+ if (ret < 0)
+ return ret;
+ do {
+ msleep(50);
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+ } while ((ret & BMCR_RESET) && --retry);
+ if (ret & BMCR_RESET)
+ goto err_restore_page;
+ }
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_soft_reset() - called to issue a PHY software reset
+ * @phydev: a pointer to a &struct phy_device
+ * for internal YT8824
+ * 1) set utp template test mode
+ * 2) utp restart
+ * 3) disable utp template test mode
+ * for external YT8824
+ * 1) set utp template test mode
+ * 2) enable serdes isolate
+ * 3) utp restart
+ * 4) disable utp template test mode
+ * 5) disable serdes isolate
+ * returns 0 or negative errno code
+ */
+static int yt8824_soft_reset(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_INTERNAL) {
+ /* invalid test mode */
+ ret = yt8824_soft_reset_step1_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ ret = yt8824_soft_reset_step3_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ /* normal mode */
+ ret = yt8824_soft_reset_step4_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* invalid test mode */
+ ret = yt8824_soft_reset_step1_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* sds isolation */
+ ret = yt8824_soft_reset_step2_paged(phydev,
+ YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* utp soft reset */
+ ret = yt8824_soft_reset_step3_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* normal mode */
+ ret = yt8824_soft_reset_step4_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* sds soft reset and disable isolation */
+ ret = yt8824_soft_reset_step5_paged(phydev,
+ YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+/**
+ * external YT8824 init
+ */
+static int yt8824_config_init_paged(struct phy_device *phydev, int reg_space)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ int ret = 0, old_page;
+ u16 val_1, val_2, val_3, tmp;
+ int port;
+
+ port = phydev->mdio.addr - priv->phy_base_addr;
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ if (reg_space == YT8824_RSSR_FIBER_SPACE) {
+ /* read efuse */
+ val_1 = ytphy_read_top_ext_with_lock(phydev, 0xa13e);
+ if (val_1 < 0)
+ goto err_restore_page;
+
+ val_2 = ytphy_read_top_ext_with_lock(phydev, 0xa13f);
+ if (val_2 < 0)
+ goto err_restore_page;
+
+ val_3 = ytphy_read_top_ext_with_lock(phydev, 0xa140);
+ if (val_3 < 0)
+ goto err_restore_page;
+
+ if (port == 0) {
+ /* Serdes optimization */
+ ret = ytphy_write_ext(phydev, 0x04be, 0x000d);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x049f, 0x7ded);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04a9, 0x009f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* analog CDR */
+ ret = ytphy_write_ext(phydev, 0x0406, 0x0800);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized VCO */
+ ret = ytphy_write_ext(phydev, 0x0438, 0x9024);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0439, 0x00c0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized PLL lock */
+ ret = ytphy_read_ext(phydev, 0x0429);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(13) | BIT(12));
+ tmp = (val_1 & (BIT(7) | BIT(6)) >> 6);
+ ret |= (tmp << 12);
+ ret = ytphy_write_ext(phydev, 0x0429, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, 0x0441);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(1) | BIT(0));
+ tmp = (val_1 & (BIT(5) | BIT(4)) >> 4);
+ ret |= tmp;
+ ret = ytphy_write_ext(phydev, 0x0441, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, 0x042b);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(13) | BIT(12));
+ tmp = (val_3 & (BIT(1) | BIT(0)));
+ ret |= (tmp << 12);
+ ret = ytphy_write_ext(phydev, 0x042b, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x043a, 0x1006);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x042a, 0xf070);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x0491, 0x007f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0492, 0x7f7f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes training threshold */
+ ret = ytphy_write_ext(phydev, 0x0454, 0x0f14);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0497, 0x0a44);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* digital eye diagram of SerDes */
+ ret = ytphy_write_ext(phydev, 0x04cd, 0x0000);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes LDO */
+ ret = ytphy_read_ext(phydev, 0x04b5);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(6) | BIT(5) | BIT(4));
+ tmp = (val_2 & (BIT(4) | BIT(3) | BIT(2)) >> 2);
+ ret |= (tmp << 4);
+ ret = ytphy_write_ext(phydev, 0x04b5, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_read_ext(phydev, 0x04b4);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~(BIT(10) | BIT(9) | BIT(8));
+ tmp = (val_2 & (BIT(7) | BIT(6) | BIT(5)) >> 5);
+ ret |= (tmp << 8);
+ ret = ytphy_write_ext(phydev, 0x04b4, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized Serdes RX */
+ ret = ytphy_write_ext(phydev, 0x04af, 0x45e3);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x048a, 0x0fff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0408, 0x7c00);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04d6, 0x007f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x044f, 0xff08);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized Serdes TX */
+ ret = ytphy_write_ext(phydev, 0x048e, 0x7d00);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x000d, 0x0606);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* Serdes manual config */
+ ret = ytphy_write_ext(phydev, 0x04b0, 0x0804);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04b1, 0x7074);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04af, 0x45e7);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* restart calibration */
+ ret = ytphy_write_ext(phydev, 0x0003, 0x5603);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0492, 0x7fff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0492, 0x7f7f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x2000, 0x0040);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x2000, 0x0000);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+
+ /* TX preamble padded to 8; RX IPG always > 8 */
+ ret = __phy_write(phydev, 0x0017, 0x2007);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = __phy_write(phydev, 0x0000, 0x9000);
+ if (ret < 0)
+ goto err_restore_page;
+ } else if (reg_space == YT8824_RSSR_UTP_SPACE) {
+ /* power down */
+ ret = __phy_write(phydev, 0x0000, 0x1900);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* pll calibration */
+ ret = ytphy_write_ext(phydev, 0x0001, 0x0003);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa20e, 0x0cba);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa20a, 0xc3f1);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa20c, 0x1620);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa2b6, 0x0a00);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa2b6, 0x0e00);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimization utp */
+ ret = ytphy_write_ext(phydev, 0x0001, 0x0003);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* enable nibble */
+ ret = ytphy_write_ext(phydev, 0xa003, 0x0003);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* idle err detect enable */
+ ret = ytphy_write_ext(phydev, 0x03d0, 0x5210);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized 2.5G long cable performance */
+ ret = ytphy_write_ext(phydev, 0x0372, 0x5038);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x037c, 0x6068);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0388, 0x00a0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized fast retrain */
+ ret = ytphy_write_ext(phydev, 0x0359, 0x2140);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x000c, 0xc1a0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* 2.5G template tone */
+ ret = ytphy_write_ext(phydev, 0xa2fa, 0x0083);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04e2, 0x0149);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized 2.5G template */
+ ret = ytphy_write_ext(phydev, 0x047e, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x047f, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0480, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0481, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized 1000M cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x0336, 0xab0a);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0340, 0x301d);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* 100M template amplitude */
+ ret = ytphy_write_ext(phydev, 0x046e, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x046f, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0470, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0471, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized 100M cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x030b, 0xaa1d);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x071f, 0x0036);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* 10M template amplitude */
+ ret = ytphy_write_ext(phydev, 0x046b, 0x1818);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x046c, 0x1818);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized 10M cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x0466, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0467, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0468, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0469, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimize utp 1000M performance */
+ ret = ytphy_write_ext(phydev, 0x034a, 0xff03);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x00f8, 0xb3ff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0059, 0x4040);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x032c, 0x5094);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x032d, 0xd094);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x032e, 0x5308);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x0322, 0x6440);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04d3, 0x5220);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x04d2, 0x5220);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized EMC CS */
+ ret = ytphy_write_ext(phydev, 0x00c8, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x00be, 0x6406);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0x037a, 0x40ff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* optimized EMC RE */
+ ret = ytphy_write_ext(phydev, 0x0482, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa2d5, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa2d6, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa2d7, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa2d8, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa218, 0x006e);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa01d, 0xfff0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa01e, 0xfff0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa01d, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_write_ext(phydev, 0xa01e, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * internal YT8824 init
+ */
+static int yt8824_internal_config_init_paged(struct phy_device *phydev,
+ int reg_space)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ int old_page;
+ int port = 0;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ port = phydev->mdio.addr - priv->phy_base_addr;
+ ret = ytphy_write_ext(phydev, 0x1, 0x3);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = __phy_write(phydev, MII_BMCR, 0x1900);
+ if (ret < 0)
+ goto err_restore_page;
+ if (port == 0 || port == 2) {
+ ret = ytphy_write_ext(phydev, 0xa20e, 0xcba);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa20a, 0xc3f1);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa20c, 0x1620);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa2b6, 0xa00);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa2b6, 0xe00);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa003, 0x3);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+ ret = ytphy_write_ext(phydev, 0x3d0, 0x5210);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x372, 0x5038);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x37c, 0x6068);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x388, 0xa0);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x359, 0x2140);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_top_ext(phydev, 0xa2fa, 0x83);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x4e2, 0x149);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 2.5G tempate */
+ ret = ytphy_write_ext(phydev, 0x47e, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x47f, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x480, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x481, 0x3939);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 1000 cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x336, 0xab0a);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x340, 0x301d);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 1000 performance */
+ ret = ytphy_write_ext(phydev, 0x34a, 0xff03);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xf8, 0xb3ff);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x32c, 0x5094);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x32d, 0xd094);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x32e, 0x5308);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x322, 0x6440);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x4d3, 0x5220);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x4d2, 0x5220);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 100 tempate */
+ ret = ytphy_write_ext(phydev, 0x46e, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x46f, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x470, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x471, 0x4545);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 100 cable length threshold */
+ ret = ytphy_write_ext(phydev, 0x30b, 0xaa1d);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x71f, 0x36);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 10 tempate */
+ ret = ytphy_write_ext(phydev, 0x46b, 0x1818);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x46c, 0x1818);
+ if (ret < 0)
+ goto err_restore_page;
+ /* 10 tempate MAU*/
+ ret = ytphy_write_ext(phydev, 0x466, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x467, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x468, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x469, 0x6c6c);
+ if (ret < 0)
+ goto err_restore_page;
+ /* EMC CS */
+ ret = ytphy_write_ext(phydev, 0xc8, 0xfff);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xbe, 0x6406);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0x37a, 0x40ff);
+ if (ret < 0)
+ goto err_restore_page;
+ /* EMC RE*/
+ ret = ytphy_write_ext(phydev, 0x482, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+ if (port == 0 || port == 2) {
+ ret = ytphy_write_ext(phydev, 0x482, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa2d5, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa2d6, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa2d7, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa2d8, 0x1f1f);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa218, 0x6e);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa01d, 0xfff0);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa01e, 0xfff0);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa01d, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_ext(phydev, 0xa01e, 0xffff);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+ ret = ytphy_write_ext(phydev, 0xc, 0x41a1);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_mmd(phydev, 0x1, 0x84, 0x2000);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = __phy_write(phydev, MII_BMCR, 0x9140);
+ if (ret < 0)
+ goto err_restore_page;
+ ret = ytphy_write_mmd(phydev, 0x1, 0x84, 0x0);
+ if (ret < 0)
+ goto err_restore_page;
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_config_init() - phy initializatioin
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * Returns: 0 or negative errno code
+ */
+static int yt8824_config_init(struct phy_device *phydev)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ int ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_INTERNAL) {
+ /* base addr and top addr update for internal YT8824*/
+ priv->phy_base_addr = 0x4;
+ priv->top_phy_addr = 0x9;
+ ret = yt8824_internal_config_init_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = yt8824_config_init_paged(phydev, YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+ ret = yt8824_config_init_paged(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ }
+ ret = yt8824_soft_reset(phydev);
+ if (ret < 0)
+ return ret;
+
+ netdev_info(phydev->attached_dev,
+ "%s done, phy addr: %d, phy base addr = %d\n",
+ __func__, phydev->mdio.addr, priv->phy_base_addr);
+
+ return 0;
+}
+
+static int yt8824_config_intr(struct phy_device *phydev)
+{
+ struct yt8521_priv *priv = phydev->priv;
+ int ret = 0, old_page;
+ int port;
+
+ port = phydev->mdio.addr - priv->phy_base_addr;
+ old_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ /* top ext reg 0xa000
+ * bit6 int_polarity 1'b0 low active, 1'b1 high active
+ */
+ ret = ytphy_top_read(phydev, YT8521_REG_SPACE_SELECT_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_top_write(phydev, YT8521_REG_SPACE_SELECT_REG, ret & (~BIT(6)));
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* top ext reg 0xa019
+ * bit5 intr_phy_pulse_en 1'b0 level, 1'b1 pulse
+ */
+ ret = ytphy_top_read(phydev, 0xa019);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_top_write(phydev, 0xa019, ret | BIT(5));
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* top ext reg 0xa018 phy_pulse_lth bit14:8
+ * top ext reg 0xa019 timer_tick_sel bit8:7
+ * bit14:8 phy_pulse_lth bit8:7 timer_tick_sel pulse width
+ * 0x007a 0x0002 10ms pulse width
+ * 0x0064 0x0001 1ms pulse width
+ * 0x004e 0x0000 100ms pulse width
+ * 0x0009 0x0000 10ms pulse width(default)
+ */
+ ret = ytphy_top_read(phydev, 0xa018);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~0x7f00;
+ ret |= (0x0009 << 8);
+ ret = ytphy_top_write(phydev, 0xa018, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_top_read(phydev, 0xa019);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~0x180;
+ ret |= (0x0000 << 7);
+ ret = ytphy_top_write(phydev, 0xa019, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* top ext reg 0xa01c interrupt state(Read Clear)
+ * bit11 PHY3 interrupt 1: phy3 link up/down interrupt happened, 0: interrupt not happened
+ * bit10 PHY2 interrupt 1: phy2 link up/down interrupt happened, 0: interrupt not happened
+ * bit9 PHY1 interrupt 1: phy1 link up/down interrupt happened, 0: interrupt not happened
+ * bit8 PHY0 interrupt 1: phy0 link up/down interrupt happened, 0: interrupt not happened
+ *
+ * bit7 PHY3 link down 1: phy3 link down interrupt happened, 0: interrupt not happened
+ * bit6 PHY2 link down 1: phy2 link down interrupt happened, 0: interrupt not happened
+ * bit5 PHY1 link down 1: phy1 link down interrupt happened, 0: interrupt not happened
+ * bit4 PHY0 link down 1: phy0 link down interrupt happened, 0: interrupt not happened
+ *
+ * bit3 PHY3 link up 1: phy3 link up interrupt happened, 0: interrupt not happened
+ * bit2 PHY2 link up 1: phy2 link up interrupt happened, 0: interrupt not happened
+ * bit1 PHY1 link up 1: phy1 link up interrupt happened, 0: interrupt not happened
+ * bit0 PHY0 link up 1: phy0 link up interrupt happened, 0: interrupt not happened
+ */
+ ret = ytphy_top_read(phydev, 0xa01c);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* top ext reg 0xa01a
+ * bit5 intn_wol_mode 1'b1 enable intn_wol pin output
+ * bit4 intn_mode 1'b1 enable intn pin output
+ */
+ ret = ytphy_top_read(phydev, 0xa01a);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~BIT(5);
+ ret |= BIT(4);
+ ret = ytphy_top_write(phydev, 0xa01a, ret);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* top ext reg 0xa01b interrupt mask
+ * bit11 1'b1 enable interrupt signal(link up/down) output to interrupt pin
+ * bit7 1'b1 enable interrupt signal(link down) output to interrupt pin
+ * bit3 1'b1 enable interrupt signal(link up) output to interrupt pin
+ *
+ * bit10 1'b1 enable interrupt signal(link up/down) output to interrupt pin
+ * bit6 1'b1 enable interrupt signal(link down) output to interrupt pin
+ * bit2 1'b1 enable interrupt signal(link up) output to interrupt pin
+ *
+ * bit9 1'b1 enable interrupt signal(link up/down) output to interrupt pin
+ * bit5 1'b1 enable interrupt signal(link down) output to interrupt pin
+ * bit1 1'b1 enable interrupt signal(link up) output to interrupt pin
+ *
+ * bit8 1'b1 enable interrupt signal(link up/down) output to interrupt pin
+ * bit4 1'b1 enable interrupt signal(link down) output to interrupt pin
+ * bit0 1'b1 enable interrupt signal(link up) output to interrupt pin
+ */
+ ret = ytphy_top_read(phydev, 0xa01b);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret |= (BIT(port + 8) | BIT(port + 4) | BIT(port));
+ ret = ytphy_top_write(phydev, 0xa01b, ret);
+ if (ret < 0)
+ goto err_restore_page;
+ }
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+static irqreturn_t yt8824_handle_interrupt(struct phy_device *phydev)
+{
+ int ret = 0, old_page;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ /* top ext reg 0xa01c interrupt state(Read Clear)
+ * bit11 PHY3 interrupt 1: phy3 link up/down interrupt happened, 0: interrupt not happened
+ * bit10 PHY2 interrupt 1: phy2 link up/down interrupt happened, 0: interrupt not happened
+ * bit9 PHY1 interrupt 1: phy1 link up/down interrupt happened, 0: interrupt not happened
+ * bit8 PHY0 interrupt 1: phy0 link up/down interrupt happened, 0: interrupt not happened
+ * bit7 PHY3 link down 1: phy3 link down interrupt happened, 0: interrupt not happened
+ * bit6 PHY2 link down 1: phy2 link down interrupt happened, 0: interrupt not happened
+ * bit5 PHY1 link down 1: phy1 link down interrupt happened, 0: interrupt not happened
+ * bit4 PHY0 link down 1: phy0 link down interrupt happened, 0: interrupt not happened
+ * bit3 PHY3 link up 1: phy3 link up interrupt happened, 0: interrupt not happened
+ * bit2 PHY2 link up 1: phy2 link up interrupt happened, 0: interrupt not happened
+ * bit1 PHY1 link up 1: phy1 link up interrupt happened, 0: interrupt not happened
+ * bit0 PHY0 link up 1: phy0 link up interrupt happened, 0: interrupt not happened
+ */
+ ret = ytphy_read_top_ext(phydev, 0xa01c);
+ if (ret < 0)
+ goto err_restore_page;
+
+ phy_trigger_machine(phydev);
+
+err_restore_page:
+ phy_restore_page(phydev, old_page, ret);
+ if (ret > 0)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+/**
+ * yt8824_config_aneg()
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_aneg_done(struct phy_device *phydev)
+{
+ int link = 0;
+ int old_page;
+ int ret = 0;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ link = !!(__phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG) &
+ YTPHY_SSR_LINK);
+
+ netdev_info(phydev->attached_dev, "%s, phy addr: %d, link_utp: %d\n",
+ __func__, phydev->mdio.addr, link);
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_read_status_paged() - determines the speed and duplex of one page
+ * @phydev: a pointer to a &struct phy_device
+ * @page: The reg page(YT8824_RSSR_FIBER_SPACE/YT8824_RSSR_UTP_SPACE) to
+ * operate.
+ *
+ * returns 1 (utp or fiber link),0 (no link) or negative errno code
+ */
+static int yt8824_read_status_paged(struct phy_device *phydev, int page,
+ int *status, int *lpa)
+{
+ int old_page;
+ int ret = 0;
+
+ page &= YT8824_RSSR_SPACE_MASK;
+ old_page = phy_select_page(phydev, page);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ ret = __phy_read(phydev, MII_LPA);
+ *lpa = ret;
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = __phy_read(phydev, YTPHY_SPECIFIC_STATUS_REG);
+ *status = ret;
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = !!(*status & YTPHY_SSR_LINK);
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_read_status() - determines the negotiated speed and duplex
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_read_status(struct phy_device *phydev)
+{
+ int link;
+ int lpa;
+ int val;
+
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+ phydev->link = 0;
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+
+ link = yt8824_read_status_paged(phydev,
+ YT8824_RSSR_UTP_SPACE, &val, &lpa);
+ if (link < 0)
+ return link;
+
+ if (link) {
+ phydev->link = 1;
+ phydev->pause = !!(lpa & BIT(10));
+ phydev->asym_pause = !!(lpa & BIT(11));
+
+ /* update speed & duplex */
+ yt8821_adjust_status(phydev, val);
+ } else {
+ phydev->link = 0;
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ }
+
+ return 0;
+}
+
+/**
+ * yt8824_utp_power_on()
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_utp_power_on(struct phy_device *phydev,
+ int reg_space)
+{
+ int old_page;
+ int ret;
+
+ old_page = phy_select_page(phydev, reg_space);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret &= ~BMCR_PDOWN;
+ ret &= ~BMCR_ISOLATE;
+
+ ret = __phy_write(phydev, MII_BMCR, ret);
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_utp_power_down()
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_utp_power_down(struct phy_device *phydev,
+ int reg_space)
+{
+ int ret = 0, old_page;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ ret = __phy_read(phydev, MII_BMCR);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = __phy_write(phydev, MII_BMCR, ret | BMCR_PDOWN);
+ if (ret < 0)
+ goto err_restore_page;
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_power_on()
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ * need WA like softreset
+ */
+static int yt8824_power_on(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_INTERNAL) {
+ /* invalid test mode */
+ ret = yt8824_soft_reset_step1_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ /* utp power on */
+ ret = yt8824_utp_power_on(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ /* normal mode */
+ ret = yt8824_soft_reset_step4_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* invalid test mode */
+ ret = yt8824_soft_reset_step1_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* sds isolation */
+ ret = yt8824_soft_reset_step2_paged(phydev,
+ YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* utp power on */
+ ret = yt8824_utp_power_on(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* normal mode */
+ ret = yt8824_soft_reset_step4_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* sds soft reset and disable isolation */
+ ret = yt8824_soft_reset_step5_paged(phydev,
+ YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int yt8824_resume(struct phy_device *phydev)
+{
+ return yt8824_power_on(phydev);
+}
+
+static int yt8824_power_down(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_INTERNAL) {
+ /* invalid test mode */
+ ret = yt8824_soft_reset_step1_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ /* utp power down */
+ ret = yt8824_utp_power_down(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ /* normal mode */
+ ret = yt8824_soft_reset_step4_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* invalid test mode */
+ ret = yt8824_soft_reset_step1_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* sds isolation */
+ ret = yt8824_soft_reset_step2_paged(phydev,
+ YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* utp power down */
+ ret = yt8824_utp_power_down(phydev, YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* normal mode */
+ ret = yt8824_soft_reset_step4_paged(phydev,
+ YT8824_RSSR_UTP_SPACE);
+ if (ret < 0)
+ return ret;
+
+ /* sds soft reset and disable isolation */
+ ret = yt8824_soft_reset_step5_paged(phydev,
+ YT8824_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int yt8824_suspend(struct phy_device *phydev)
+{
+ return yt8824_power_down(phydev);
+}
+
+/**
+ * yt8824_config_aneg()
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_config_aneg(struct phy_device *phydev)
+{
+ int phy_ctrl = 0;
+ int old_page;
+ int ret;
+
+ old_page = phy_select_page(phydev, YT8824_RSSR_UTP_SPACE);
+ if (old_page < 0)
+ goto err_restore_page;
+
+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ phydev->advertising))
+ phy_ctrl = MDIO_AN_10GBT_CTRL_ADV2_5G;
+
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN,
+ MDIO_AN_10GBT_CTRL,
+ MDIO_AN_10GBT_CTRL_ADV2_5G,
+ phy_ctrl);
+ if (ret)
+ goto err_restore_page;
+
+ ret = genphy_config_aneg(phydev);
+ if (ret)
+ goto err_restore_page;
+
+err_restore_page:
+ return phy_restore_page(phydev, old_page, ret);
+}
+
+/**
+ * yt8824_probe()
+ * @phydev: a pointer to a &struct phy_device
+ *
+ * returns 0 or negative errno code
+ */
+static int yt8824_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct yt8521_priv *priv;
+ u32 phy_base_addr;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ /* get base addr and top addr for external YT8824 */
+ if (!device_property_read_u32(dev, "motorcomm,base-address",
+ &phy_base_addr))
+ priv->phy_base_addr = phy_base_addr;
+ else
+ priv->phy_base_addr = PHY_BASE_ADDR;
+
+ priv->top_phy_addr = priv->phy_base_addr + 4;
+
+ return 0;
+}
+
+static struct phy_driver motorcomm_phy_drvs[] = {
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
+ .name = "YT8511 Gigabit Ethernet",
+ .config_init = yt8511_config_init,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .read_page = yt8511_read_page,
+ .write_page = yt8511_write_page,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8521),
+ .name = "YT8521 Gigabit Ethernet",
+ .get_features = yt8521_get_features,
+ .probe = yt8521_probe,
+ .read_page = yt8521_read_page,
+ .write_page = yt8521_write_page,
+ .get_wol = ytphy_get_wol,
+ .set_wol = ytphy_set_wol,
+ .config_aneg = yt8521_config_aneg,
+ .aneg_done = yt8521_aneg_done,
+ .config_init = yt8521_config_init,
+ .read_status = yt8521_read_status,
+ .soft_reset = yt8521_soft_reset,
+ .suspend = yt8521_suspend,
+ .resume = yt8521_resume,
+ .led_hw_is_supported = yt8521_led_hw_is_supported,
+ .led_hw_control_set = yt8521_led_hw_control_set,
+ .led_hw_control_get = yt8521_led_hw_control_get,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8522),
+ .name = "YT8522 100 Megabit Ethernet",
+ .config_aneg = genphy_config_aneg,
+ .config_init = yt8522_config_init,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8531),
+ .name = "YT8531 Gigabit Ethernet",
+ .probe = yt8531_probe,
+ .config_init = yt8531_config_init,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .get_wol = ytphy_get_wol,
+ .set_wol = yt8531_set_wol,
+ .link_change_notify = yt8531_link_change_notify,
+ .led_hw_is_supported = yt8521_led_hw_is_supported,
+ .led_hw_control_set = yt8521_led_hw_control_set,
+ .led_hw_control_get = yt8521_led_hw_control_get,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S),
+ .name = "YT8531S Gigabit Ethernet",
+ .get_features = yt8521_get_features,
+ .probe = yt8521_probe,
+ .read_page = yt8521_read_page,
+ .write_page = yt8521_write_page,
+ .get_wol = ytphy_get_wol,
+ .set_wol = ytphy_set_wol,
+ .config_aneg = yt8521_config_aneg,
+ .aneg_done = yt8521_aneg_done,
+ .config_init = yt8521_config_init,
+ .read_status = yt8521_read_status,
+ .soft_reset = yt8521_soft_reset,
+ .suspend = yt8521_suspend,
+ .resume = yt8521_resume,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8821),
+ .name = "YT8821 2.5Gbps PHY",
+ .get_features = yt8821_get_features,
+ .read_page = yt8521_read_page,
+ .write_page = yt8521_write_page,
+ .get_wol = ytphy_get_wol,
+ .set_wol = ytphy_set_wol,
+ .config_aneg = genphy_config_aneg,
+ .aneg_done = yt8821_aneg_done,
+ .config_init = yt8821_config_init,
+ .get_rate_matching = yt8821_get_rate_matching,
+ .read_status = yt8821_read_status,
+ .soft_reset = yt8821_soft_reset,
+ .suspend = yt8821_suspend,
+ .resume = yt8821_resume,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_YT8824),
+ .name = "YT8824 Quad Ports 2.5Gbps Ethernet",
+ .get_features = yt8821_get_features,
+ .read_page = yt8824_read_page,
+ .write_page = yt8824_write_page,
+ .config_intr = yt8824_config_intr,
+ .handle_interrupt = yt8824_handle_interrupt,
+ .probe = yt8824_probe,
+ .config_aneg = yt8824_config_aneg,
+ .aneg_done = yt8824_aneg_done,
+ .config_init = yt8824_config_init,
+ .read_status = yt8824_read_status,
+ .soft_reset = yt8824_soft_reset,
+ .suspend = yt8824_suspend,
+ .resume = yt8824_resume,
},
};
module_phy_driver(motorcomm_phy_drvs);
-MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821 PHY driver");
+MODULE_DESCRIPTION("Motorcomm 8511/8521/8531/8531S/8821/8824 PHY driver");
MODULE_AUTHOR("Peter Geis");
MODULE_AUTHOR("Frank");
+MODULE_AUTHOR("Kyle");
MODULE_LICENSE("GPL");
static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
@@ -3161,6 +4810,7 @@ static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) },
{ PHY_ID_MATCH_EXACT(PHY_ID_YT8821) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_YT8824) },
{ /* sentinel */ }
};
|
| 3/2 | 2026/07/14 16:37 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 26319 output: 19 thoughts: 265 Thoughts: **Analyzing the Reachability of a New PHY Driver** Okay, so I'm looking at this patch. It introduces support for the YT8824 PHY driver within `drivers/net/phy/motorcomm.c`. Clearly, this is a fairly substantial addition, with a lot of code for register manipulation, reset, and initialization – the usual suspects for a PHY driver. The YT8824 is a Motorcomm quad-port 2.5Gbps Ethernet PHY, hardware-specific, of course. My immediate question, as always, is: can this code *actually* be executed in a virtualized environment? Think QEMU or Google Compute Engine, which is where a lot of my debugging happens. Normally, with PHY drivers, you’re stuck with the hardware, or you need some kind of MDIO bus emulation to even get the driver loaded. You'd need a way to emulate the physical hardware. Linux PHY drivers bind to MDIO devices based on their PHY ID. Can I instantiate this driver through software, without the actual YT8824 present? Most likely not directly. I've used `macb` and other emulated NICs before, but they usually come with their own pre-configured or generic PHYs. I start thinking of ways to get at this code... Wait, doesn't syzkaller have some trick up its sleeve for injecting MDIO devices, or maybe it can use `fakedev` for something like this? Nah, syzkaller’s not usually in the business of full MDIO PHY emulation, unless there is a custom virtual MDIO driver. Okay, back to basics. I need to see if there's an existing virtual MDIO driver somewhere in the kernel. Maybe something like `drivers/net/phy/mdio-mockup.c` or something similar? I'd better check for that. |
| 4/2 | 2026/07/14 16:37 | tool | grepper |
0mError:no matches Args: {
"Expression": "mdio.*mockup"
}Results: {
"error": "no matches"
} |
| 5/2 | 2026/07/14 16:37 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 27013 output: 18 thoughts: 121 Thoughts: **Exploring Userspace Control of PHY Drivers** Okay, let's dive into this. My initial thought is to investigate whether there's a practical method to interact with PHY drivers directly from userspace. It's something I've considered before, and I seem to recall certain scenarios where userspace can instantiate MDIO devices. I think there might be cases using drivers like `mdio-bcm-unimac`, or similar ones, right? However, that's not quite what I am looking for. Now that I think about it, I should probably check the `drivers/net/phy/phy_device.c` file. Perhaps there's a sysfs or netlink interface exposed there, although PHYs are typically detected during boot through the device tree, or by PCI devices registering MDIO buses. I'm wondering... Is there such a thing as a virtual MDIO bus? If so, that could be a significant enabler. To get a definitive answer, I'll search the `drivers/net/` directory for any occurrences of "mdio" and see what comes up. That should give me some direction. |
| 6/2 | 2026/07/14 16:37 | tool | grepper |
0mArgs:{
"Expression": "virtual.*mdio"
}Results: {
"Output": "Documentation/devicetree/bindings/net/mdio-gpio.yaml=17=properties:\n--\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml-19- enum:\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml:20: - virtual,mdio-gpio\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml-21- - microchip,mdio-smi0\n--\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml=41=examples:\n--\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml-47- mdio0: mdio {\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml:48: compatible = \"virtual,mdio-gpio\";\nDocumentation/devicetree/bindings/net/mdio-gpio.yaml-49- #address-cells = \u003c1\u003e;\n--\narch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts=152=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts:153:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-dlink-dns-313.dts-154-\t\t/* Uses MDC and MDIO */\n--\narch/arm/boot/dts/gemini/gemini-nas4210b.dts=67=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-nas4210b.dts:68:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-nas4210b.dts-69-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/gemini/gemini-nas4220b.dts=66=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-nas4220b.dts:67:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-nas4220b.dts-68-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/gemini/gemini-ns2502.dts=32=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-ns2502.dts:33:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-ns2502.dts-34-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/gemini/gemini-rut1xx.dts=59=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-rut1xx.dts:60:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-rut1xx.dts-61-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/gemini/gemini-sl93512r.dts=71=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-sl93512r.dts:72:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-sl93512r.dts-73-\t\t/* Uses MDC and MDIO */\n--\narch/arm/boot/dts/gemini/gemini-sq201.dts=56=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-sq201.dts:57:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-sq201.dts-58-\t\t/* Uses MDC and MDIO */\n--\narch/arm/boot/dts/gemini/gemini-ssi1328.dts=32=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-ssi1328.dts:33:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-ssi1328.dts-34-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/gemini/gemini-verbatim-s08v1901-d1.dts=57=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-verbatim-s08v1901-d1.dts:58:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-verbatim-s08v1901-d1.dts-59-\t\t/* Uses MDC and MDIO */\n--\narch/arm/boot/dts/gemini/gemini-wbd111.dts=71=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-wbd111.dts:72:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-wbd111.dts-73-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/gemini/gemini-wbd222.dts=70=\tmdio0: mdio {\narch/arm/boot/dts/gemini/gemini-wbd222.dts:71:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/gemini/gemini-wbd222.dts-72-\t\tgpios = \u003c\u0026gpio0 22 GPIO_ACTIVE_HIGH\u003e, /* MDC */\n--\narch/arm/boot/dts/nxp/imx/imx51-zii-rdu1.dts=163=\tmdio_gpio: mdio {\narch/arm/boot/dts/nxp/imx/imx51-zii-rdu1.dts:164:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/nxp/imx/imx51-zii-rdu1.dts-165-\t\tpinctrl-names = \"default\";\n--\narch/arm/boot/dts/nxp/imx/imx51-zii-scu2-mezz.dts=40=\tmdio_gpio: mdio {\narch/arm/boot/dts/nxp/imx/imx51-zii-scu2-mezz.dts:41:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/nxp/imx/imx51-zii-scu2-mezz.dts-42-\t\tpinctrl-names = \"default\";\n--\narch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi=97=\tmdio0: mdio {\narch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi:98:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/nxp/imx/imx6q-bx50v3.dtsi-99-\t\tgpios = \u003c\u0026gpio2 5 GPIO_ACTIVE_HIGH\u003e, /* mdc */\n--\narch/arm/boot/dts/nxp/imx/imx6qdl-zii-rdu2.dtsi=19=\tmdio1: mdio {\narch/arm/boot/dts/nxp/imx/imx6qdl-zii-rdu2.dtsi:20:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/nxp/imx/imx6qdl-zii-rdu2.dtsi-21-\t\t#address-cells = \u003c1\u003e;\n--\narch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts=53=\tmdio {\narch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts:54:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/nxp/imx/imx6qp-prtwd3.dts-55-\t\tpinctrl-names = \"default\";\n--\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts=55=\tmdio0: mdio-0 {\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts-56-\t\tstatus = \"okay\";\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts:57:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts-58-\t\tgpios = \u003c\u0026qcom_pinmux 1 GPIO_ACTIVE_HIGH\u003e,\n--\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts=180=\tmdio1: mdio-1 {\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts-181-\t\tstatus = \"okay\";\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts:182:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/qcom/qcom-ipq8064-rb3011.dts-183-\t\tgpios = \u003c\u0026qcom_pinmux 11 GPIO_ACTIVE_HIGH\u003e,\n--\narch/arm/boot/dts/st/stm32mp133c-prihmb.dts=118=\tmdio0: mdio {\narch/arm/boot/dts/st/stm32mp133c-prihmb.dts:119:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/st/stm32mp133c-prihmb.dts-120-\t\t#address-cells = \u003c1\u003e;\n--\narch/arm/boot/dts/st/stm32mp151a-prtt1c.dts=38=\tmdio0: mdio {\narch/arm/boot/dts/st/stm32mp151a-prtt1c.dts:39:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/st/stm32mp151a-prtt1c.dts-40-\t\t#address-cells = \u003c1\u003e;\n--\narch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi=44=\tmdio0: mdio {\narch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi:45:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm/boot/dts/st/stm32mp151a-prtt1l.dtsi-46-\t\t#address-cells = \u003c1\u003e;\n--\narch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi=18=\tmdio0: mdio {\narch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi:19:\t\tcompatible = \"virtual,mdio-gpio\";\narch/arm64/boot/dts/freescale/imx8mq-zii-ultra.dtsi-20-\t\tpinctrl-names = \"default\";\n--\ndrivers/net/mdio/mdio-gpio.c=197=static const struct of_device_id mdio_gpio_of_match[] = {\ndrivers/net/mdio/mdio-gpio.c:198:\t{ .compatible = \"virtual,mdio-gpio\", },\ndrivers/net/mdio/mdio-gpio.c-199-\t{ .compatible = \"microchip,mdio-smi0\" },\n"
} |
| 7/2 | 2026/07/14 16:37 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 30682 output: 31 thoughts: 486 Thoughts: **Emulating a PHY Device with Syzkaller** Okay, so I'm thinking about how to test the `motorcomm` PHY driver. The challenge is, how do I get the kernel to load it without an actual PHY device? Hmm, `mdio-gpio` is a bit-banging driver, so that's out. Can I somehow emulate a PHY in software? `mac80211_hwsim`, `dummy`, `netdevsim`, `tun`/`tap`, `veth` – none of those seem to have anything PHY-related. But wait, what about `usbnet`? Some USB network adapters *do* have PHYs! And, crucial point, syzkaller *can* emulate USB devices using `dummy_hcd`. The idea is: if syzkaller emulates a USB network adapter that *exposes* an MDIO bus, then it can provide arbitrary PHY IDs. The kernel should then bind the corresponding PHY driver – specifically, the `motorcomm` driver! Let's see. Are there any USB network drivers that register an MDIO bus and let the device specify the PHY ID, or at least scan the bus? Bingo! Looks like `smsc95xx`, `asix`, `r8152`, `lan78xx`, maybe even `cdc_ether`, and `ax88179_178a`. Aha! So, if a USB device exposes an MDIO bus, the kernel will probe that bus. The USB device (which syzkaller will emulate) can then *respond* to those MDIO read requests – specifically, for registers 2 and 3, which contain the PHY ID – with the Motorcomm PHY ID (`0x4f51e8b8`). That's the key. The kernel *should* load the `motorcomm` PHY driver and call its `probe`, `config_init`, and so on. Now, can syzkaller actually *reach* MDIO through USB? Syzkaller has USB fuzzing (`syz_usb_connect`). It can definitely emulate a USB device. If I make it emulate a USB device that uses a driver like `smsc95xx`, `lan78xx`, or `asix`, those drivers *register* an MDIO bus. When the MDIO bus gets scanned, the driver has to translate MDIO reads into USB control messages. Syzkaller should intercept those USB control messages, and that's the perfect opportunity to return the custom PHY ID. Okay, now let's just confirm that `lan78xx` or `smsc95xx` *does* register an MDIO bus and we're in business. |
| 8/2 | 2026/07/14 16:37 | tool | grepper |
0mArgs:{
"Expression": "mdiobus_register",
"PathPrefix": "drivers/net/usb/"
}Results: {
"Output": "drivers/net/usb/asix_devices.c=669=static int ax88772_init_mdio(struct usbnet *dev)\n--\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) {\n--\ndrivers/net/usb/ax88172a.c=61=static int ax88172a_init_mdio(struct usbnet *dev)\n--\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/lan78xx.c=2091=static int lan78xx_mdio_init(struct lan78xx_net *dev)\n--\ndrivers/net/usb/lan78xx.c-2121-\tnode = of_get_child_by_name(dev-\u003eudev-\u003edev.of_node, \"mdio\");\ndrivers/net/usb/lan78xx.c:2122:\tret = of_mdiobus_register(dev-\u003emdiobus, node);\ndrivers/net/usb/lan78xx.c-2123-\tof_node_put(node);\n--\ndrivers/net/usb/smsc95xx.c=1147=static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)\n--\ndrivers/net/usb/smsc95xx.c-1241-\ndrivers/net/usb/smsc95xx.c:1242:\tret = mdiobus_register(pdata-\u003emdiobus);\ndrivers/net/usb/smsc95xx.c-1243-\tif (ret) {\n"
} |
| 9/2 | 2026/07/14 16:37 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 32316 output: 30 thoughts: 808 Thoughts: **Reaching the YT8824 PHY Driver via USB Fuzzing** Okay, so this is exciting. I've got this figured out: `smsc95xx`, `lan78xx`, `asix`, and `ax88172a` – they all register an MDIO bus. That MDIO bus, when registered, gets scanned by the kernel, which reads PHY registers 2 and 3 to grab the PHY ID. The USB driver cleverly translates those MDIO reads into USB control transfers. This means that Syzkaller's USB fuzzer *can* respond to those control transfers with the Motorcomm PHY ID (`0x4f51e8b8`). If that happens, then the kernel will, no question, instantiate the Motorcomm PHY driver and call its methods. This code is absolutely reachable in a virtualized environment with some targeted USB fuzzing. Now, let's take a look at this patch to get a handle on what's actually being introduced, and what we should focus our fuzzing efforts on. The patch adds support for the `YT8824` PHY. I can see the following functions were added: * `yt8824_read_page` * `yt8824_write_page` * `yt8824_soft_reset_step1_paged` * `yt8824_soft_reset_step2_paged` * `yt8824_soft_reset_step3_paged` * `yt8824_soft_reset_step4_paged` * `yt8824_soft_reset_step5_paged` * `yt8824_soft_reset` * `yt8824_config_init_paged` * `yt8824_internal_config_init_paged` * `yt8824_config_init` * `yt8824_config_intr` * `yt8824_handle_interrupt` * `yt8824_aneg_done` * `yt8824_read_status_paged` * `yt8824_read_status` * `yt8824_utp_power_on` * `yt8824_utp_power_down` * `yt8824_power_on` * `yt8824_resume` * `yt8824_power_down` * `yt8824_suspend` * `yt8824_config_aneg` * `yt8824_probe` Also, some helper functions got added: * `ytphy_top_write` * `ytphy_top_read` * `ytphy_read_top_ext` * `ytphy_read_top_ext_with_lock` * `ytphy_write_top_ext` * `ytphy_write_top_ext_with_lock` * `ytphy_write_mmd` Based on my experience, the main entry points for this PHY driver are the ones to focus on for fuzzing: * `yt8824_probe` * `yt8824_config_init` * `yt8824_config_aneg` * `yt8824_read_status` * `yt8824_soft_reset` * `yt8824_suspend` * `yt8824_resume` * `yt8824_config_intr` * `yt8824_handle_interrupt` * `yt8824_aneg_done` Now, the next logical step is to check the required configs. I'll need to know the specific config options to make sure it's enabled. The file is `drivers/net/phy/motorcomm.c`. Time to see what enables this! |
| 10/2 | 2026/07/14 16:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "motorcomm",
"PathPrefix": "drivers/net/phy/Kconfig"
}Results: {
"error": "no matches"
} |
| 11/2 | 2026/07/14 16:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34116 output: 29 thoughts: 17 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Potential Location: Investigating the PHY Makefile** Okay, so I'm trying to track down something related to the network PHY configuration. I initially had a hunch, but it's not quite working out the way I thought. Instead of going down a rabbit hole, I'm thinking I should take a look at the `drivers/net/phy/Makefile` file. It makes the most sense. This directory is the canonical location for PHY drivers, and the Makefile should, at a minimum, give me clues about how those drivers are built and potentially configured. I'm expecting to find either the answer directly in the Makefile or at least a pointer to the relevant source files or Kconfig options that control the inclusion of the functionality I'm looking for. Let's see what's in there. |
| 12/2 | 2026/07/14 16:38 | tool | grepper |
0mArgs:{
"Expression": "motorcomm",
"PathPrefix": "drivers/net/phy/Makefile"
}Results: {
"Output": "drivers/net/phy/Makefile=82=obj-$(CONFIG_MICROSEMI_PHY)\t+= mscc/\ndrivers/net/phy/Makefile:83:obj-$(CONFIG_MOTORCOMM_PHY)\t+= motorcomm.o\ndrivers/net/phy/Makefile-84-obj-$(CONFIG_NATIONAL_PHY)\t+= national.o\n"
} |
| 13/2 | 2026/07/14 16:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34441 output: 33 thoughts: 34 Thoughts: Okay, let's see, the system's highlighting `CONFIG_MOTORCOMM_PHY`. Right, that suggests we're dealing with a MotorComm PHY, likely a driver for a specific physical layer interface. Given that, my first instinct is to dig into the kernel's Kconfig files, specifically the one related to network PHY drivers. I'll need to check `drivers/net/phy/Kconfig` to confirm this assumption and locate the definition for `MOTORCOMM_PHY`. I'm expecting to find details about the hardware itself or possibly related dependencies in this file. This should give me a solid foundation for understanding the intended functionality and how this particular configuration option ties into the broader network subsystem. |
| 14/2 | 2026/07/14 16:38 | tool | grepper |
0mArgs:{
"Expression": "config MOTORCOMM_PHY",
"PathPrefix": "drivers/net/phy/Kconfig"
}Results: {
"Output": "drivers/net/phy/Kconfig=338=config MICROSEMI_PHY\n--\ndrivers/net/phy/Kconfig-346-\ndrivers/net/phy/Kconfig:347:config MOTORCOMM_PHY\ndrivers/net/phy/Kconfig-348-\ttristate \"Motorcomm PHYs\"\n"
} |
| 15/2 | 2026/07/14 16:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 34746 output: 268 thoughts: 917 Thoughts: **My Analysis of the YT8824 PHY Driver for Fuzzing** Okay, let's break this down. First, I need to figure out the minimal configuration required to reach this new Motorcomm YT8824 PHY driver code. The patch itself only touches `motorcomm.c`, so I'm thinking the `MOTORCOMM_PHY` config option is the only new one needed. Since the goal is to reach this through USB network drivers, like `USB_LAN78XX` or `USB_NET_SMSC95XX`, I think those are probably already enabled in syzkaller's defaults. So, I'll start with just specifying `MOTORCOMM_PHY`. Now, the important part: identifying reachable functions. I need to make sure `yt8824_handle_interrupt` is accessible. Looking at the code, it's registered as `.handle_interrupt`. The PHY framework calls this when there's an interrupt. If I can trigger PHY interrupts – maybe through fakedev or USB interrupt endpoints – then I should be able to hit that function. Even if that proves tricky, the other functions – `probe`, `config_init`, `read_status`, `soft_reset`, `config_aneg`, `suspend`, and `resume` – are *definitely* reachable during the normal PHY state machine transitions. So, let's list out all the focus symbols, making sure I don't miss anything. I've got: * `yt8824_probe` * `yt8824_config_init` * `yt8824_config_aneg` * `yt8824_read_status` * `yt8824_soft_reset` * `yt8824_suspend` * `yt8824_resume` * `yt8824_config_intr` * `yt8824_handle_interrupt` * `yt8824_aneg_done` * `yt8824_read_page` * `yt8824_write_page` Looking at the `phy_driver` struct definition, I can confirm that these are all the relevant entry points. I'm going to want to make sure I can reach all of these during fuzzing. My reasoning is this: The patch enables support for the YT8824 PHY. This code can be hit in a virtualized environment by emulating a USB network adapter (e.g., smsc95xx or lan78xx). This registers an MDIO bus. Then responding to MDIO reads with the YT8824 PHY ID will cause the kernel to bind the new PHY driver and execute its initialization and state machine logic. So, to summarize: * **Config:** `MOTORCOMM_PHY` * **Focus Symbols:** (listed above) Okay, let's quickly double-check – I don't see any other config options that are necessary. I'm going to call `set-results` now. |
| 16/2 | 2026/07/14 16:38 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MOTORCOMM_PHY"
],
"FocusSymbols": [
"yt8824_probe",
"yt8824_config_init",
"yt8824_config_aneg",
"yt8824_read_status",
"yt8824_soft_reset",
"yt8824_suspend",
"yt8824_resume",
"yt8824_config_intr",
"yt8824_handle_interrupt",
"yt8824_aneg_done",
"yt8824_read_page",
"yt8824_write_page"
],
"Reasoning": "The patch adds support for the Motorcomm YT8824 PHY. This code can be reached in a virtualized environment by emulating a USB network adapter (e.g., smsc95xx or lan78xx) that registers an MDIO bus, and responding to MDIO reads with the YT8824 PHY ID. This will cause the kernel to bind the new PHY driver and execute its initialization and state machine logic.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MOTORCOMM_PHY"
],
"FocusSymbols": [
"yt8824_probe",
"yt8824_config_init",
"yt8824_config_aneg",
"yt8824_read_status",
"yt8824_soft_reset",
"yt8824_suspend",
"yt8824_resume",
"yt8824_config_intr",
"yt8824_handle_interrupt",
"yt8824_aneg_done",
"yt8824_read_page",
"yt8824_write_page"
],
"Reasoning": "The patch adds support for the Motorcomm YT8824 PHY. This code can be reached in a virtualized environment by emulating a USB network adapter (e.g., smsc95xx or lan78xx) that registers an MDIO bus, and responding to MDIO reads with the YT8824 PHY ID. This will cause the kernel to bind the new PHY driver and execute its initialization and state machine logic.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|