| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/07 19:56 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch series adds support for the Synopsys DesignWare Ethernet Physical Coding Sublayer (XPCS) on Rockchip RK3568 SoCs, including a new platform driver (pcs-xpcs-rk), combphy updates, device tree bindings and DTS nodes, and related stmmac/pcs-xpcs plumbing across dwmac-rk, dwmac-intel, dwmac-renesas-gbeth, dwmac-rzn1, and dwmac-socfpga. All modified code resides in drivers for physical SoC platform devices and vendor-specific MACs/PHYs (Rockchip RK3568, Intel SoC MACs, Renesas, SoC FPGA) that are not emulated in standard virtualized fuzzing environments (QEMU / GCE on amd64). Consequently, the modified code is structurally unreachable.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/07 19:56 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit e007c70e7143628de9c5fd8c6332a0874fd810af\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Sep 7 19:55:59 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml b/Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml\nnew file mode 100644\nindex 0000000000000..0852d0bcb66a2\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml\n@@ -0,0 +1,110 @@\n+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)\n+%YAML 1.2\n+---\n+$id: http://devicetree.org/schemas/net/pcs/rockchip-dwxpcs.yaml#\n+$schema: http://devicetree.org/meta-schemas/core.yaml#\n+\n+title: Rockchip RK3568 Synopsys DesignWare Ethernet PCS\n+\n+maintainers:\n+ - Coia Prant \u003ccoiaprant@gmail.com\u003e\n+\n+description: |\n+ Rockchip RK3568 SoC integrates a Synopsys DesignWare Ethernet Physical\n+ Coding Sublayer (XPCS).\n+ The PCS provides an interface between the Media Access Control (MAC)\n+ and the Physical Medium Attachment (PMA) sublayer through a Media\n+ Independent Interface (GMII).\n+\n+ The XPCS is accessed over the APB3 bus and internally connected to a\n+ Naneng Combo SerDes PHY.\n+ It supports 1000BASE-X, SGMII and QSGMII modes.\n+\n+ The block contains four MII ports that can be individually enabled and\n+ routed to one of the Ethernet GMAC controllers via the pcs-handle\n+ property in the MAC device tree node.\n+\n+properties:\n+ compatible:\n+ const: rockchip,rk3568-xpcs\n+\n+ reg:\n+ maxItems: 1\n+\n+ \"#address-cells\":\n+ const: 1\n+\n+ \"#size-cells\":\n+ const: 0\n+\n+ clocks:\n+ items:\n+ - description: APB3 bus interface clock (clk_csr_i), required for register access\n+ - description: EEE clock (clk_eee_i), required for Energy Efficient Ethernet operation\n+\n+ clock-names:\n+ items:\n+ - const: csr\n+ - const: eee\n+\n+ phys:\n+ maxItems: 1\n+\n+ phy-names:\n+ const: serdes\n+\n+ power-domains:\n+ maxItems: 1\n+\n+patternProperties:\n+ \"^pcs-mii@[0-3]$\":\n+ type: object\n+ description:\n+ One of the four MII ports of the XPCS. The port is linked to an\n+ Ethernet MAC controller via the pcs-handle property in the MAC's\n+ device tree node.\n+\n+ properties:\n+ reg:\n+ description: MII port number.\n+ enum: [0, 1, 2, 3]\n+\n+ required:\n+ - reg\n+\n+ additionalProperties: false\n+\n+required:\n+ - compatible\n+ - reg\n+ - \"#address-cells\"\n+ - \"#size-cells\"\n+ - clocks\n+ - clock-names\n+ - phys\n+ - phy-names\n+ - power-domains\n+\n+additionalProperties: false\n+\n+examples:\n+ - |\n+ #include \u003cdt-bindings/clock/rk3568-cru.h\u003e\n+ #include \u003cdt-bindings/power/rk3568-power.h\u003e\n+ #include \u003cdt-bindings/phy/phy.h\u003e\n+\n+ pcs@fda00000 {\n+ compatible = \"rockchip,rk3568-xpcs\";\n+ reg = \u003c0xfda00000 0x200000\u003e;\n+ #address-cells = \u003c1\u003e;\n+ #size-cells = \u003c0\u003e;\n+ clocks = \u003c\u0026cru PCLK_XPCS\u003e, \u003c\u0026cru CLK_XPCS_EEE\u003e;\n+ clock-names = \"csr\", \"eee\";\n+ phys = \u003c\u0026combphy2 PHY_TYPE_SGMII\u003e;\n+ phy-names = \"serdes\";\n+ power-domains = \u003c\u0026power RK3568_PD_PIPE\u003e;\n+\n+ pcs-mii@0 {\n+ reg = \u003c0\u003e;\n+ };\n+ };\ndiff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml\nindex 379b08bd9e97a..8e898bce9af73 100644\n--- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml\n+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml\n@@ -80,6 +80,15 @@ properties:\n description:\n Some additional pipe settings are accessed through GRF regs.\n \n+ rockchip,sgmii-mac-sel:\n+ $ref: /schemas/types.yaml#/definitions/uint32\n+ enum: [0, 1]\n+ default: 1\n+ description:\n+ Select gmac0 or gmac1 to be used as SGMII controller.\n+ The hardware reset value is GMAC1 (1). Set this to 0 to route\n+ SGMII to GMAC0.\n+\n \"#phy-cells\":\n const: 1\n \n@@ -105,6 +114,10 @@ allOf:\n maxItems: 1\n reset-names:\n maxItems: 1\n+ rockchip,sgmii-mac-sel: true\n+ else:\n+ properties:\n+ rockchip,sgmii-mac-sel: false\n - if:\n properties:\n compatible:\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex fc320b373656f..dda4d211b7db4 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -23738,6 +23738,15 @@ S:\tMaintained\n F:\tDocumentation/devicetree/bindings/sound/rockchip,rk3576-sai.yaml\n F:\tsound/soc/rockchip/rockchip_sai.*\n \n+ROCKCHIP XPCS DRIVER\n+M:\tCoia Prant \u003ccoiaprant@gmail.com\u003e\n+L:\tnetdev@vger.kernel.org\n+L:\tlinux-rockchip@lists.infradead.org\n+S:\tMaintained\n+F:\tDocumentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml\n+F:\tdrivers/net/pcs/pcs-xpcs-rk.c\n+F:\tinclude/linux/pcs/pcs-xpcs-rk.h\n+\n ROCKER DRIVER\n M:\tJiri Pirko \u003cjiri@resnulli.us\u003e\n L:\tnetdev@vger.kernel.org\ndiff --git a/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts b/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts\nindex 58c1052ba8ef3..25caa44198843 100644\n--- a/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts\n+++ b/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts\n@@ -3,6 +3,7 @@\n /dts-v1/;\n \n #include \u003cdt-bindings/gpio/gpio.h\u003e\n+#include \u003cdt-bindings/leds/common.h\u003e\n #include \u003cdt-bindings/pinctrl/rockchip.h\u003e\n #include \u003cdt-bindings/soc/rockchip,vop2.h\u003e\n #include \"rk3568.dtsi\"\n@@ -242,6 +243,7 @@ \u0026combphy1 {\n \n \u0026combphy2 {\n \tstatus = \"okay\";\n+\trockchip,sgmii-mac-sel = \u003c0\u003e;\n };\n \n \u0026cpu0 {\n@@ -260,9 +262,18 @@ \u0026cpu3 {\n \tcpu-supply = \u003c\u0026vdd_cpu\u003e;\n };\n \n-/* Motorcomm YT8521SC LAN port (require SGMII) */\n+/* Motorcomm YT8521SC LAN port */\n \u0026gmac0 {\n-\tstatus = \"disabled\";\n+\tassigned-clocks = \u003c\u0026cru SCLK_GMAC0_RX_TX\u003e;\n+\tassigned-clock-parents = \u003c\u0026xpcs_gmac0_clk\u003e;\n+\tpcs-handle = \u003c\u0026xpcs_mii0\u003e;\n+\tmanaged = \"in-band-status\";\n+\tphy-handle = \u003c\u0026sgmii_phy\u003e;\n+\tphy-mode = \"sgmii\";\n+\tphy-supply = \u003c\u0026vcc_3v3\u003e;\n+\tpinctrl-names = \"default\";\n+\tpinctrl-0 = \u003c\u0026gmac0_miim\u003e;\n+\tstatus = \"okay\";\n };\n \n /* Motorcomm YT8521SC WAN port */\n@@ -341,6 +352,36 @@ \u0026i2s0_8ch {\n \tstatus = \"okay\";\n };\n \n+\u0026mdio0 {\n+\tsgmii_phy: ethernet-phy@3 {\n+\t\tcompatible = \"ethernet-phy-ieee802.3-c22\";\n+\t\treg = \u003c0x3\u003e;\n+\t\tmax-speed = \u003c1000\u003e;\n+\t\treset-assert-us = \u003c20000\u003e;\n+\t\treset-deassert-us = \u003c100000\u003e;\n+\t\treset-gpios = \u003c\u0026gpio3 RK_PC6 GPIO_ACTIVE_LOW\u003e;\n+\n+\t\tleds {\n+\t\t\t#address-cells = \u003c1\u003e;\n+\t\t\t#size-cells = \u003c0\u003e;\n+\n+\t\t\tled@1 {\n+\t\t\t\treg = \u003c1\u003e;\n+\t\t\t\tcolor = \u003cLED_COLOR_ID_AMBER\u003e;\n+\t\t\t\tfunction = LED_FUNCTION_LAN;\n+\t\t\t\tdefault-state = \"keep\";\n+\t\t\t};\n+\n+\t\t\tled@2 {\n+\t\t\t\treg = \u003c2\u003e;\n+\t\t\t\tcolor = \u003cLED_COLOR_ID_GREEN\u003e;\n+\t\t\t\tfunction = LED_FUNCTION_LAN;\n+\t\t\t\tdefault-state = \"keep\";\n+\t\t\t};\n+\t\t};\n+\t};\n+};\n+\n \u0026mdio1 {\n \trgmii_phy: ethernet-phy@3 {\n \t\tcompatible = \"ethernet-phy-ieee802.3-c22\";\n@@ -350,6 +391,25 @@ rgmii_phy: ethernet-phy@3 {\n \t\treset-gpios = \u003c\u0026gpio4 RK_PC0 GPIO_ACTIVE_LOW\u003e;\n \t\trx-internal-delay-ps = \u003c1500\u003e;\n \t\ttx-internal-delay-ps = \u003c1500\u003e;\n+\n+\t\tleds {\n+\t\t\t#address-cells = \u003c1\u003e;\n+\t\t\t#size-cells = \u003c0\u003e;\n+\n+\t\t\tled@1 {\n+\t\t\t\treg = \u003c1\u003e;\n+\t\t\t\tcolor = \u003cLED_COLOR_ID_AMBER\u003e;\n+\t\t\t\tfunction = LED_FUNCTION_WAN;\n+\t\t\t\tdefault-state = \"keep\";\n+\t\t\t};\n+\n+\t\t\tled@2 {\n+\t\t\t\treg = \u003c2\u003e;\n+\t\t\t\tcolor = \u003cLED_COLOR_ID_GREEN\u003e;\n+\t\t\t\tfunction = LED_FUNCTION_WAN;\n+\t\t\t\tdefault-state = \"keep\";\n+\t\t\t};\n+\t\t};\n \t};\n };\n \n@@ -586,3 +646,13 @@ \u0026xin32k {\n \tpinctrl-names = \"default\";\n \tpinctrl-0 = \u003c\u0026clk32k_out1\u003e;\n };\n+\n+\u0026xpcs {\n+\tstatus = \"okay\";\n+\tphys = \u003c\u0026combphy2 PHY_TYPE_SGMII\u003e;\n+\tphy-names = \"serdes\";\n+};\n+\n+\u0026xpcs_mii0 {\n+\tstatus = \"okay\";\n+};\ndiff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi\nindex 3bc653f027f1f..989e164c0eb39 100644\n--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi\n+++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi\n@@ -110,6 +110,51 @@ sata0: sata@fc000000 {\n \t\tstatus = \"disabled\";\n \t};\n \n+\txpcs: pcs@fda00000 {\n+\t\tcompatible = \"rockchip,rk3568-xpcs\";\n+\t\t#address-cells = \u003c1\u003e;\n+\t\t#size-cells = \u003c0\u003e;\n+\t\treg = \u003c0x0 0xfda00000 0x0 0x200000\u003e;\n+\t\tclocks = \u003c\u0026cru PCLK_XPCS\u003e, \u003c\u0026cru CLK_XPCS_EEE\u003e;\n+\t\tclock-names = \"csr\", \"eee\";\n+\t\tpower-domains = \u003c\u0026power RK3568_PD_PIPE\u003e;\n+\t\tstatus = \"disabled\";\n+\n+\t\txpcs_mii0: pcs-mii@0 {\n+\t\t\treg = \u003c0\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\n+\t\txpcs_mii1: pcs-mii@1 {\n+\t\t\treg = \u003c1\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\n+\t\txpcs_mii2: pcs-mii@2 {\n+\t\t\treg = \u003c2\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\n+\t\txpcs_mii3: pcs-mii@3 {\n+\t\t\treg = \u003c3\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\t};\n+\n+\txpcs_gmac0_clk: xpcs-gmac0-clock {\n+\t\tcompatible = \"fixed-clock\";\n+\t\tclock-frequency = \u003c125000000\u003e;\n+\t\tclock-output-names = \"clk_gmac0_xpcs_mii\";\n+\t\t#clock-cells = \u003c0\u003e;\n+\t};\n+\n+\txpcs_gmac1_clk: xpcs-gmac1-clock {\n+\t\tcompatible = \"fixed-clock\";\n+\t\tclock-frequency = \u003c125000000\u003e;\n+\t\tclock-output-names = \"clk_gmac1_xpcs_mii\";\n+\t\t#clock-cells = \u003c0\u003e;\n+\t};\n+\n \tpipe_phy_grf0: syscon@fdc70000 {\n \t\tcompatible = \"rockchip,rk3568-pipe-phy-grf\", \"syscon\";\n \t\treg = \u003c0x0 0xfdc70000 0x0 0x1000\u003e;\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig\nindex e3dd5adda5aca..5088acc06982e 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig\n+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig\n@@ -170,6 +170,7 @@ config DWMAC_ROCKCHIP\n \tdefault ARCH_ROCKCHIP\n \tdepends on OF \u0026\u0026 (ARCH_ROCKCHIP || COMPILE_TEST)\n \tselect MFD_SYSCON\n+\tselect PCS_XPCS_ROCKCHIP\n \thelp\n \t Support for Ethernet controller on Rockchip RK3288 SoC.\n \ndiff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c\nindex f5f9fa67ecd77..fd5f01c8941c1 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c\n@@ -603,13 +603,47 @@ static void common_default_data(struct plat_stmmacenet_data *plat)\n \tplat-\u003emdio_bus_data-\u003eneeds_reset = true;\n }\n \n+static int intel_mgbe_pcs_init(struct stmmac_priv *priv)\n+{\n+\tstruct fwnode_handle *devnode, *pcsnode;\n+\tstruct dw_xpcs *xpcs = NULL;\n+\tint addr;\n+\n+\tdevnode = dev_fwnode(priv-\u003edevice);\n+\n+\tif (fwnode_property_present(devnode, \"pcs-handle\")) {\n+\t\tpcsnode = fwnode_find_reference(devnode, \"pcs-handle\", 0);\n+\t\txpcs = xpcs_create_fwnode(pcsnode);\n+\t\tfwnode_handle_put(pcsnode);\n+\t} else {\n+\t\taddr = ffs(priv-\u003eplat-\u003emdio_bus_data-\u003epcs_mask) - 1;\n+\t\txpcs = xpcs_create_mdiodev(priv-\u003emii, addr);\n+\t}\n+\n+\tif (IS_ERR(xpcs))\n+\t\treturn PTR_ERR(xpcs);\n+\n+\txpcs_config_eee_mult_fact(xpcs, priv-\u003eplat-\u003emult_fact_100ns);\n+\n+\tpriv-\u003ehw-\u003expcs = xpcs;\n+\treturn 0;\n+}\n+\n+static void intel_mgbe_pcs_exit(struct stmmac_priv *priv)\n+{\n+\tif (!priv-\u003ehw-\u003expcs)\n+\t\treturn;\n+\n+\txpcs_destroy(priv-\u003ehw-\u003expcs);\n+\tpriv-\u003ehw-\u003expcs = NULL;\n+}\n+\n static struct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv,\n \t\t\t\t\t\t phy_interface_t interface)\n {\n-\t/* plat-\u003emdio_bus_data-\u003ehas_xpcs has been set true, so there\n-\t * should always be an XPCS. The original code would always\n-\t * return this if present.\n-\t */\n+\tif (!priv-\u003ehw-\u003expcs)\n+\t\treturn NULL;\n+\n \treturn xpcs_to_phylink_pcs(priv-\u003ehw-\u003expcs);\n }\n \n@@ -733,6 +767,8 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,\n \t plat-\u003ephy_interface == PHY_INTERFACE_MODE_1000BASEX) {\n \t\tplat-\u003emdio_bus_data-\u003epcs_mask = BIT_U32(INTEL_MGBE_XPCS_ADDR);\n \t\tplat-\u003edefault_an_inband = true;\n+\t\tplat-\u003epcs_init = intel_mgbe_pcs_init;\n+\t\tplat-\u003epcs_exit = intel_mgbe_pcs_exit;\n \t\tplat-\u003eselect_pcs = intel_mgbe_select_pcs;\n \t}\n \ndiff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c\nindex 19f34e18bfef2..9af32c26f9c14 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c\n@@ -81,8 +81,11 @@ static int renesas_gmac_pcs_init(struct stmmac_priv *priv)\n \n static void renesas_gmac_pcs_exit(struct stmmac_priv *priv)\n {\n-\tif (priv-\u003ehw-\u003ephylink_pcs)\n-\t\tmiic_destroy(priv-\u003ehw-\u003ephylink_pcs);\n+\tif (!priv-\u003ehw-\u003ephylink_pcs)\n+\t\treturn;\n+\n+\tmiic_destroy(priv-\u003ehw-\u003ephylink_pcs);\n+\tpriv-\u003ehw-\u003ephylink_pcs = NULL;\n }\n \n static struct phylink_pcs *renesas_gmac_select_pcs(struct stmmac_priv *priv,\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c\nindex 8d7042e689261..e47ca1bec5b8b 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c\n@@ -20,6 +20,7 @@\n #include \u003clinux/delay.h\u003e\n #include \u003clinux/mfd/syscon.h\u003e\n #include \u003clinux/regmap.h\u003e\n+#include \u003clinux/pcs/pcs-xpcs-rk.h\u003e\n #include \u003clinux/pm_runtime.h\u003e\n \n #include \"stmmac_platform.h\"\n@@ -47,6 +48,7 @@ struct rk_gmac_ops {\n \tvoid (*set_to_rgmii)(struct rk_priv_data *bsp_priv,\n \t\t\t int tx_delay, int rx_delay);\n \tvoid (*set_to_rmii)(struct rk_priv_data *bsp_priv);\n+\tvoid (*set_to_sgmii)(struct rk_priv_data *bsp_priv);\n \tint (*set_speed)(struct rk_priv_data *bsp_priv,\n \t\t\t phy_interface_t interface, int speed);\n \tvoid (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);\n@@ -63,6 +65,7 @@ struct rk_gmac_ops {\n \tbool clock_grf_reg_in_php;\n \tbool supports_rgmii;\n \tbool supports_rmii;\n+\tbool supports_sgmii;\n \tbool php_grf_required;\n \tbool regs_valid;\n \tu32 regs[];\n@@ -98,6 +101,7 @@ struct rk_priv_data {\n \tbool integrated_phy;\n \tbool supports_rgmii;\n \tbool supports_rmii;\n+\tbool supports_sgmii;\n \n \tstruct clk_bulk_data *clks;\n \tint num_clks;\n@@ -809,6 +813,8 @@ static const struct rk_gmac_ops rk3528_ops = {\n #define RK3568_GRF_GMAC1_CON1\t\t0x038c\n \n /* RK3568_GRF_GMAC0_CON1 \u0026\u0026 RK3568_GRF_GMAC1_CON1 */\n+#define RK3568_GMAC_MODE_RMII_RGMII\t\tGRF_CLR_BIT(7)\n+#define RK3568_GMAC_MODE_SGMII_QSGMII\t\tGRF_BIT(7)\n #define RK3568_GMAC_FLOW_CTRL\t\t\tGRF_BIT(3)\n #define RK3568_GMAC_FLOW_CTRL_CLR\t\tGRF_CLR_BIT(3)\n #define RK3568_GMAC_RXCLK_DLY_ENABLE\t\tGRF_BIT(1)\n@@ -851,18 +857,32 @@ static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,\n \t\t RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));\n \n \tregmap_write(bsp_priv-\u003egrf, con1,\n+\t\t RK3568_GMAC_MODE_RMII_RGMII |\n \t\t RK3568_GMAC_RXCLK_DLY_ENABLE |\n \t\t RK3568_GMAC_TXCLK_DLY_ENABLE);\n }\n \n+static void rk3568_set_to_sgmii(struct rk_priv_data *bsp_priv)\n+{\n+\tu32 con1;\n+\n+\tcon1 = (bsp_priv-\u003eid == 1) ? RK3568_GRF_GMAC1_CON1 :\n+\t\t\t\t RK3568_GRF_GMAC0_CON1;\n+\n+\tregmap_write(bsp_priv-\u003egrf, con1, RK3568_GMAC_MODE_SGMII_QSGMII);\n+}\n+\n static const struct rk_gmac_ops rk3568_ops = {\n \t.init = rk3568_init,\n \t.set_to_rgmii = rk3568_set_to_rgmii,\n+\t.set_to_sgmii = rk3568_set_to_sgmii,\n+\n \t.set_speed = rk_set_clk_mac_speed,\n \n \t.gmac_phy_intf_sel_mask = GENMASK_U16(6, 4),\n \n \t.supports_rmii = true,\n+\t.supports_sgmii = true,\n \n \t.regs_valid = true,\n \t.regs = {\n@@ -1208,6 +1228,43 @@ static void rk_phy_powerdown(struct rk_priv_data *bsp_priv)\n \t\tdev_err(bsp_priv-\u003edev, \"fail to disable phy-supply\\n\");\n }\n \n+static int rk_pcs_init(struct stmmac_priv *priv)\n+{\n+\tstruct device_node *np = priv-\u003edevice-\u003eof_node;\n+\tstruct device_node *pcs_node;\n+\tstruct dw_xpcs *xpcs;\n+\n+\tpcs_node = of_parse_phandle(np, \"pcs-handle\", 0);\n+\tif (!pcs_node)\n+\t\treturn -ENODEV;\n+\n+\txpcs = xpcs_rk_create(priv-\u003edevice, pcs_node);\n+\tof_node_put(pcs_node);\n+\tif (IS_ERR(xpcs))\n+\t\treturn PTR_ERR(xpcs);\n+\n+\tpriv-\u003ehw-\u003expcs = xpcs;\n+\treturn 0;\n+}\n+\n+static void rk_pcs_exit(struct stmmac_priv *priv)\n+{\n+\tif (!priv-\u003ehw-\u003expcs)\n+\t\treturn;\n+\n+\txpcs_destroy(priv-\u003ehw-\u003expcs);\n+\tpriv-\u003ehw-\u003expcs = NULL;\n+}\n+\n+static struct phylink_pcs *rk_select_pcs(struct stmmac_priv *priv,\n+\t\t\t\t\t phy_interface_t interface)\n+{\n+\tif (!priv-\u003ehw-\u003expcs)\n+\t\treturn NULL;\n+\n+\treturn xpcs_to_phylink_pcs(priv-\u003ehw-\u003expcs);\n+}\n+\n static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,\n \t\t\t\t\t struct plat_stmmacenet_data *plat,\n \t\t\t\t\t const struct rk_gmac_ops *ops)\n@@ -1330,6 +1387,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,\n \n \tbsp_priv-\u003esupports_rgmii = ops-\u003esupports_rgmii || !!ops-\u003eset_to_rgmii;\n \tbsp_priv-\u003esupports_rmii = ops-\u003esupports_rmii || !!ops-\u003eset_to_rmii;\n+\tbsp_priv-\u003esupports_sgmii = ops-\u003esupports_sgmii || !!ops-\u003eset_to_sgmii;\n \n \tif (ops-\u003einit) {\n \t\tret = ops-\u003einit(bsp_priv);\n@@ -1361,6 +1419,10 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)\n \t\tif (!bsp_priv-\u003esupports_rmii)\n \t\t\treturn -EINVAL;\n \t\tbreak;\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\t\tif (!bsp_priv-\u003esupports_sgmii)\n+\t\t\treturn -EINVAL;\n+\t\tbreak;\n \tdefault:\n \t\tdev_err(bsp_priv-\u003edev,\n \t\t\t\"unsupported interface %d\", bsp_priv-\u003ephy_iface);\n@@ -1379,16 +1441,19 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)\n \tif (ret)\n \t\treturn ret;\n \n+\tret = gmac_clk_enable(bsp_priv, true);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tif (bsp_priv-\u003ephy_iface == PHY_INTERFACE_MODE_SGMII)\n+\t\tgoto set_mode;\n+\n \tret = rk_get_phy_intf_sel(bsp_priv-\u003ephy_iface);\n \tif (ret \u003c 0)\n-\t\treturn ret;\n+\t\tgoto clk_disable;\n \n \tintf = ret;\n \n-\tret = gmac_clk_enable(bsp_priv, true);\n-\tif (ret)\n-\t\treturn ret;\n-\n \tif (bsp_priv-\u003egmac_phy_intf_sel_mask ||\n \t bsp_priv-\u003egmac_rmii_mode_mask) {\n \t\t/* If defined, encode the phy_intf_sel value */\n@@ -1399,10 +1464,8 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)\n \t\t\t\t bsp_priv-\u003egmac_rmii_mode_mask);\n \n \t\tret = rk_write_gmac_grf_reg(bsp_priv, val);\n-\t\tif (ret \u003c 0) {\n-\t\t\tgmac_clk_enable(bsp_priv, false);\n-\t\t\treturn ret;\n-\t\t}\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto clk_disable;\n \t}\n \n \tif (bsp_priv-\u003eclock.rmii_mode_mask) {\n@@ -1410,13 +1473,12 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)\n \t\t\t\t bsp_priv-\u003eclock.rmii_mode_mask);\n \n \t\tret = rk_write_clock_grf_reg(bsp_priv, val);\n-\t\tif (ret \u003c 0) {\n-\t\t\tgmac_clk_enable(bsp_priv, false);\n-\t\t\treturn ret;\n-\t\t}\n+\t\tif (ret \u003c 0)\n+\t\t\tgoto clk_disable;\n \t}\n \n-\t/*rmii or rgmii*/\n+set_mode:\n+\t/* rmii, rgmii, sgmii */\n \tswitch (bsp_priv-\u003ephy_iface) {\n \tcase PHY_INTERFACE_MODE_RGMII:\n \t\tdev_info(dev, \"init for RGMII\\n\");\n@@ -1447,15 +1509,20 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)\n \t\tif (bsp_priv-\u003eops-\u003eset_to_rmii)\n \t\t\tbsp_priv-\u003eops-\u003eset_to_rmii(bsp_priv);\n \t\tbreak;\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\t\tdev_info(dev, \"init for SGMII\\n\");\n+\t\tif (bsp_priv-\u003eops-\u003eset_to_sgmii)\n+\t\t\tbsp_priv-\u003eops-\u003eset_to_sgmii(bsp_priv);\n+\t\tbreak;\n \tdefault:\n \t\tdev_err(dev, \"NO interface defined!\\n\");\n+\t\tret = -EINVAL;\n+\t\tgoto clk_disable;\n \t}\n \n \tret = rk_phy_powerup(bsp_priv);\n-\tif (ret) {\n-\t\tgmac_clk_enable(bsp_priv, false);\n-\t\treturn ret;\n-\t}\n+\tif (ret)\n+\t\tgoto clk_disable;\n \n \tpm_runtime_get_sync(dev);\n \n@@ -1463,6 +1530,10 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)\n \t\tbsp_priv-\u003eops-\u003eintegrated_phy_powerup(bsp_priv);\n \n \treturn 0;\n+\n+clk_disable:\n+\tgmac_clk_enable(bsp_priv, false);\n+\treturn ret;\n }\n \n static void rk_gmac_powerdown(struct rk_priv_data *gmac)\n@@ -1486,6 +1557,9 @@ static void rk_get_interfaces(struct stmmac_priv *priv, void *bsp_priv,\n \n \tif (rk-\u003esupports_rmii)\n \t\t__set_bit(PHY_INTERFACE_MODE_RMII, interfaces);\n+\n+\tif (rk-\u003esupports_sgmii)\n+\t\t__set_bit(PHY_INTERFACE_MODE_SGMII, interfaces);\n }\n \n static int rk_set_clk_tx_rate(void *bsp_priv_, struct clk *clk_tx_i,\n@@ -1602,6 +1676,17 @@ static int rk_gmac_probe(struct platform_device *pdev)\n \tplat_dat-\u003esuspend = rk_gmac_suspend;\n \tplat_dat-\u003eresume = rk_gmac_resume;\n \n+\tif (plat_dat-\u003ephy_interface == PHY_INTERFACE_MODE_SGMII) {\n+\t\t/* SGMII clock always runs at 125 MHz */\n+\t\tplat_dat-\u003eset_clk_tx_rate = NULL;\n+\n+\t\t/* SGMII requires a PCS */\n+\t\tplat_dat-\u003edefault_an_inband = true;\n+\t\tplat_dat-\u003epcs_init = rk_pcs_init;\n+\t\tplat_dat-\u003epcs_exit = rk_pcs_exit;\n+\t\tplat_dat-\u003eselect_pcs = rk_select_pcs;\n+\t}\n+\n \tplat_dat-\u003ebsp_priv = rk_gmac_setup(pdev, plat_dat, data);\n \tif (IS_ERR(plat_dat-\u003ebsp_priv))\n \t\treturn PTR_ERR(plat_dat-\u003ebsp_priv);\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c\nindex 13634965bc19a..01df4776edb3f 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c\n@@ -35,8 +35,11 @@ static int rzn1_dwmac_pcs_init(struct stmmac_priv *priv)\n \n static void rzn1_dwmac_pcs_exit(struct stmmac_priv *priv)\n {\n-\tif (priv-\u003ehw-\u003ephylink_pcs)\n-\t\tmiic_destroy(priv-\u003ehw-\u003ephylink_pcs);\n+\tif (!priv-\u003ehw-\u003ephylink_pcs)\n+\t\treturn;\n+\n+\tmiic_destroy(priv-\u003ehw-\u003ephylink_pcs);\n+\tpriv-\u003ehw-\u003ephylink_pcs = NULL;\n }\n \n static struct phylink_pcs *rzn1_dwmac_select_pcs(struct stmmac_priv *priv,\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c\nindex 1d7f0a57d2889..6d4bc1fe8f751 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c\n@@ -539,8 +539,11 @@ static int socfpga_dwmac_pcs_init(struct stmmac_priv *priv)\n \n static void socfpga_dwmac_pcs_exit(struct stmmac_priv *priv)\n {\n-\tif (priv-\u003ehw-\u003ephylink_pcs)\n-\t\tlynx_pcs_destroy(priv-\u003ehw-\u003ephylink_pcs);\n+\tif (!priv-\u003ehw-\u003ephylink_pcs)\n+\t\treturn;\n+\n+\tlynx_pcs_destroy(priv-\u003ehw-\u003ephylink_pcs);\n+\tpriv-\u003ehw-\u003ephylink_pcs = NULL;\n }\n \n static struct phylink_pcs *socfpga_dwmac_select_pcs(struct stmmac_priv *priv,\ndiff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c\nindex afe98ff5bdcb0..d2f77f0c223a7 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c\n@@ -426,36 +426,15 @@ int stmmac_mdio_reset(struct mii_bus *bus)\n int stmmac_pcs_setup(struct net_device *ndev)\n {\n \tstruct stmmac_priv *priv = netdev_priv(ndev);\n-\tstruct fwnode_handle *devnode, *pcsnode;\n-\tstruct dw_xpcs *xpcs = NULL;\n-\tint addr, ret;\n-\n-\tdevnode = dev_fwnode(priv-\u003edevice);\n-\n-\tif (priv-\u003eplat-\u003epcs_init) {\n-\t\tret = priv-\u003eplat-\u003epcs_init(priv);\n-\t} else if (fwnode_property_present(devnode, \"pcs-handle\")) {\n-\t\tpcsnode = fwnode_find_reference(devnode, \"pcs-handle\", 0);\n-\t\txpcs = xpcs_create_fwnode(pcsnode);\n-\t\tfwnode_handle_put(pcsnode);\n-\t\tret = PTR_ERR_OR_ZERO(xpcs);\n-\t} else if (priv-\u003eplat-\u003emdio_bus_data \u0026\u0026\n-\t\t priv-\u003eplat-\u003emdio_bus_data-\u003epcs_mask) {\n-\t\taddr = ffs(priv-\u003eplat-\u003emdio_bus_data-\u003epcs_mask) - 1;\n-\t\txpcs = xpcs_create_mdiodev(priv-\u003emii, addr);\n-\t\tret = PTR_ERR_OR_ZERO(xpcs);\n-\t} else {\n+\tint ret;\n+\n+\tif (!priv-\u003eplat-\u003epcs_init)\n \t\treturn 0;\n-\t}\n \n+\tret = priv-\u003eplat-\u003epcs_init(priv);\n \tif (ret)\n \t\treturn dev_err_probe(priv-\u003edevice, ret, \"No xPCS found\\n\");\n \n-\tif (xpcs)\n-\t\txpcs_config_eee_mult_fact(xpcs, priv-\u003eplat-\u003emult_fact_100ns);\n-\n-\tpriv-\u003ehw-\u003expcs = xpcs;\n-\n \treturn 0;\n }\n \n@@ -463,14 +442,10 @@ void stmmac_pcs_clean(struct net_device *ndev)\n {\n \tstruct stmmac_priv *priv = netdev_priv(ndev);\n \n-\tif (priv-\u003eplat-\u003epcs_exit)\n-\t\tpriv-\u003eplat-\u003epcs_exit(priv);\n-\n-\tif (!priv-\u003ehw-\u003expcs)\n+\tif (!priv-\u003eplat-\u003epcs_exit)\n \t\treturn;\n \n-\txpcs_destroy(priv-\u003ehw-\u003expcs);\n-\tpriv-\u003ehw-\u003expcs = NULL;\n+\tpriv-\u003eplat-\u003epcs_exit(priv);\n }\n \n struct stmmac_clk_rate {\ndiff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig\nindex e417fd66f660a..88bc40791e69f 100644\n--- a/drivers/net/pcs/Kconfig\n+++ b/drivers/net/pcs/Kconfig\n@@ -12,6 +12,29 @@ config PCS_XPCS\n \t This module provides a driver and helper functions for Synopsys\n \t DesignWare XPCS controllers.\n \n+if PCS_XPCS\n+\n+config PCS_XPCS_PLATFORM\n+\ttristate \"Generic XPCS controller support\"\n+\tdefault PCS_XPCS\n+\thelp\n+\t Generic DWXPCS driver for platforms that don't require any\n+\t platform specific code to function or is using platform\n+\t data for setup.\n+\n+\t If you have a controller with this interface, say Y or M here.\n+\n+config PCS_XPCS_ROCKCHIP\n+\ttristate \"Rockchip XPCS controller support\"\n+\tdefault ARCH_ROCKCHIP\n+\tdepends on OF \u0026\u0026 (ARCH_ROCKCHIP || COMPILE_TEST)\n+\thelp\n+\t Support for XPCS controller on Rockchip RK356x SoC.\n+\n+\t If you have a Rockchip SoC with this interface, say Y or M here.\n+\n+endif # PCS_XPCS\n+\n config PCS_LYNX\n \ttristate\n \thelp\ndiff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile\nindex 4f7920618b900..f9f6cf2578d72 100644\n--- a/drivers/net/pcs/Makefile\n+++ b/drivers/net/pcs/Makefile\n@@ -1,10 +1,11 @@\n # SPDX-License-Identifier: GPL-2.0\n # Makefile for Linux PCS drivers\n \n-pcs_xpcs-$(CONFIG_PCS_XPCS)\t:= pcs-xpcs.o pcs-xpcs-plat.o \\\n-\t\t\t\t pcs-xpcs-nxp.o pcs-xpcs-wx.o\n+pcs_xpcs-$(CONFIG_PCS_XPCS)\t:= pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o\n \n obj-$(CONFIG_PCS_XPCS)\t\t+= pcs_xpcs.o\n+obj-$(CONFIG_PCS_XPCS_PLATFORM) += pcs-xpcs-plat.o\n+obj-$(CONFIG_PCS_XPCS_ROCKCHIP) += pcs-xpcs-rk.o\n obj-$(CONFIG_PCS_LYNX)\t\t+= pcs-lynx.o\n obj-$(CONFIG_PCS_MTK_LYNXI)\t+= pcs-mtk-lynxi.o\n obj-$(CONFIG_PCS_RZN1_MIIC)\t+= pcs-rzn1-miic.o\ndiff --git a/drivers/net/pcs/pcs-xpcs-rk.c b/drivers/net/pcs/pcs-xpcs-rk.c\nnew file mode 100644\nindex 0000000000000..68bcaa1a5cbbf\n--- /dev/null\n+++ b/drivers/net/pcs/pcs-xpcs-rk.c\n@@ -0,0 +1,543 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Rockchip XPCS platform device driver\n+ *\n+ * Based on the Synopsys DesignWare XPCS platform driver.\n+ * Copyright (C) 2024 Serge Semin\n+ *\n+ * Adapted for Rockchip SoCs, with reference to the Rockchip OEM driver.\n+ * Copyright (C) 2026 Coia Prant\n+ */\n+\n+#include \u003clinux/atomic.h\u003e\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/clk.h\u003e\n+#include \u003clinux/device.h\u003e\n+#include \u003clinux/io.h\u003e\n+#include \u003clinux/iopoll.h\u003e\n+#include \u003clinux/mdio.h\u003e\n+#include \u003clinux/module.h\u003e\n+#include \u003clinux/of.h\u003e\n+#include \u003clinux/of_platform.h\u003e\n+#include \u003clinux/pcs/pcs-xpcs-rk.h\u003e\n+#include \u003clinux/phy.h\u003e\n+#include \u003clinux/phy/phy.h\u003e\n+#include \u003clinux/platform_device.h\u003e\n+#include \u003clinux/pm_domain.h\u003e\n+#include \u003clinux/pm_runtime.h\u003e\n+#include \u003clinux/property.h\u003e\n+#include \u003clinux/sizes.h\u003e\n+\n+#include \"pcs-xpcs.h\"\n+\n+struct dw_xpcs_rk {\n+\tstruct platform_device *pdev;\n+\tstruct mii_bus *bus;\n+\tvoid __iomem *reg_base;\n+\tstruct phy *serdes_phy;\n+\tstruct clk *csr_clk;\n+\tstruct clk *eee_clk;\n+};\n+\n+static ptrdiff_t xpcs_rk_addr_format(int dev, int reg)\n+{\n+\treturn FIELD_PREP(0x70000, dev) | FIELD_PREP(0xffff, reg);\n+}\n+\n+static int xpcs_rk_read_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg)\n+{\n+\tptrdiff_t csr;\n+\tint ret;\n+\n+\tcsr = xpcs_rk_addr_format(dev, reg);\n+\n+\tret = pm_runtime_resume_and_get(\u0026pxpcs-\u003epdev-\u003edev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = readl(pxpcs-\u003ereg_base + (csr \u003c\u003c 2)) \u0026 0xffff;\n+\n+\tpm_runtime_put(\u0026pxpcs-\u003epdev-\u003edev);\n+\treturn ret;\n+}\n+\n+static int xpcs_rk_write_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg, u16 val)\n+{\n+\tptrdiff_t csr;\n+\tint ret;\n+\n+\tcsr = xpcs_rk_addr_format(dev, reg);\n+\n+\tret = pm_runtime_resume_and_get(\u0026pxpcs-\u003epdev-\u003edev);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\twritel(val, pxpcs-\u003ereg_base + (csr \u003c\u003c 2));\n+\n+\tpm_runtime_put(\u0026pxpcs-\u003epdev-\u003edev);\n+\treturn 0;\n+}\n+\n+#define ROCKCHIP_MMD_MII1\t2\n+#define ROCKCHIP_MMD_MII2\t3\n+#define ROCKCHIP_MMD_MII3\t4\n+#define ROCKCHIP_MMD_PMAPMD\t6\n+#define ROCKCHIP_MMD_MII\t7\n+\n+static bool xpcs_rk_mdio_addr_validate(int addr)\n+{\n+\treturn !(addr \u003c 0 || addr \u003e 3);\n+}\n+\n+static int xpcs_rk_mdio_read_remapping(int addr, int dev, int reg)\n+{\n+\tswitch (dev) {\n+\tcase MDIO_MMD_PMAPMD:\n+\t\treturn ROCKCHIP_MMD_PMAPMD;\n+\tcase MDIO_MMD_VEND2:\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -ENXIO;\n+\t}\n+\n+\t/* read remapping to MII is performed by HW */\n+\tswitch (addr) {\n+\tcase 0:\n+\t\treturn ROCKCHIP_MMD_MII;\n+\tcase 1:\n+\t\treturn ROCKCHIP_MMD_MII1;\n+\tcase 2:\n+\t\treturn ROCKCHIP_MMD_MII2;\n+\tcase 3:\n+\t\treturn ROCKCHIP_MMD_MII3;\n+\tdefault:\n+\t\treturn -ENODEV;\n+\t}\n+}\n+\n+static int xpcs_rk_mdio_write_remapping(int addr, int dev, int reg)\n+{\n+\tswitch (dev) {\n+\tcase MDIO_MMD_PMAPMD:\n+\t\treturn ROCKCHIP_MMD_PMAPMD;\n+\tcase MDIO_MMD_VEND2:\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -ENXIO;\n+\t}\n+\n+\t/* Writable only on MII */\n+\tswitch (reg) {\n+\tcase DW_VR_MII_AN_CTRL:\n+\tcase DW_VR_MII_AN_INTR_STS:\n+\tcase DW_VR_MII_EEE_MCTRL0:\n+\tcase DW_VR_MII_EEE_MCTRL1:\n+\tcase DW_VR_MII_DIG_CTRL2:\n+\t\treturn ROCKCHIP_MMD_MII;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tswitch (addr) {\n+\tcase 0:\n+\t\treturn ROCKCHIP_MMD_MII;\n+\tcase 1:\n+\t\treturn ROCKCHIP_MMD_MII1;\n+\tcase 2:\n+\t\treturn ROCKCHIP_MMD_MII2;\n+\tcase 3:\n+\t\treturn ROCKCHIP_MMD_MII3;\n+\tdefault:\n+\t\treturn -ENODEV;\n+\t}\n+}\n+\n+static int xpcs_rk_read_c22(struct mii_bus *bus, int addr, int reg)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\n+\tint dev;\n+\n+\tif (!xpcs_rk_mdio_addr_validate(addr))\n+\t\treturn -ENODEV;\n+\n+\tdev = xpcs_rk_mdio_read_remapping(addr, MDIO_MMD_VEND2, reg);\n+\tif (dev \u003c 0)\n+\t\treturn 0xffff;\n+\n+\treturn xpcs_rk_read_reg(pxpcs, dev, reg);\n+}\n+\n+static int xpcs_rk_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\n+\tint dev;\n+\n+\tif (!xpcs_rk_mdio_addr_validate(addr))\n+\t\treturn -ENODEV;\n+\n+\tdev = xpcs_rk_mdio_write_remapping(addr, MDIO_MMD_VEND2, reg);\n+\tif (dev \u003c 0)\n+\t\treturn 0;\n+\n+\treturn xpcs_rk_write_reg(pxpcs, dev, reg, val);\n+}\n+\n+static int xpcs_rk_read_c45(struct mii_bus *bus, int addr, int dev, int reg)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\n+\n+\tif (!xpcs_rk_mdio_addr_validate(addr))\n+\t\treturn -ENODEV;\n+\n+\tdev = xpcs_rk_mdio_read_remapping(addr, dev, reg);\n+\tif (dev \u003c 0)\n+\t\treturn 0xffff;\n+\n+\treturn xpcs_rk_read_reg(pxpcs, dev, reg);\n+}\n+\n+static int xpcs_rk_write_c45(struct mii_bus *bus, int addr, int dev, int reg, u16 val)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\n+\n+\tif (!xpcs_rk_mdio_addr_validate(addr))\n+\t\treturn -ENODEV;\n+\n+\tdev = xpcs_rk_mdio_write_remapping(addr, dev, reg);\n+\tif (dev \u003c 0)\n+\t\treturn 0;\n+\n+\treturn xpcs_rk_write_reg(pxpcs, dev, reg, val);\n+}\n+\n+static struct dw_xpcs_rk *xpcs_rk_create_data(struct platform_device *pdev)\n+{\n+\tstruct dw_xpcs_rk *pxpcs;\n+\n+\tpxpcs = devm_kzalloc(\u0026pdev-\u003edev, sizeof(*pxpcs), GFP_KERNEL);\n+\tif (!pxpcs)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tpxpcs-\u003epdev = pdev;\n+\n+\tdev_set_drvdata(\u0026pdev-\u003edev, pxpcs);\n+\n+\treturn pxpcs;\n+}\n+\n+static int xpcs_rk_serdes_phy_init(struct dw_xpcs_rk *pxpcs)\n+{\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\n+\tpxpcs-\u003eserdes_phy = devm_phy_get(dev, \"serdes\");\n+\tif (IS_ERR(pxpcs-\u003eserdes_phy))\n+\t\treturn dev_err_probe(dev, PTR_ERR(pxpcs-\u003eserdes_phy),\n+\t\t\t\t\t\"Failed to get SerDes PHY\\n\");\n+\n+\treturn 0;\n+}\n+\n+static void xpcs_rk_serdes_phy_poweroff(void *data)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = data;\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\n+\tphy_power_off(pxpcs-\u003eserdes_phy);\n+\tphy_exit(pxpcs-\u003eserdes_phy);\n+\n+\tdev_pm_genpd_rpm_always_on(dev, false);\n+}\n+\n+static int xpcs_rk_serdes_phy_poweron(struct dw_xpcs_rk *pxpcs)\n+{\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\tint ret;\n+\n+\t/*\n+\t * The power domain is required and must be enabled, which allows us to\n+\t * dynamically turn the CSR clock on/off using PM while keeping the PCS\n+\t * powered on.\n+\t */\n+\tret = dev_pm_genpd_rpm_always_on(dev, true);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to power on power-domains\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = phy_init(pxpcs-\u003eserdes_phy);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to init SerDes PHY\\n\");\n+\t\tgoto pm_domain;\n+\t}\n+\n+\tret = phy_power_on(pxpcs-\u003eserdes_phy);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to power on SerDes PHY\\n\");\n+\t\tgoto serdes_phy;\n+\t}\n+\n+\tret = devm_add_action_or_reset(dev, xpcs_rk_serdes_phy_poweroff, pxpcs);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to register devm for SerDes PHY: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+\n+serdes_phy:\n+\tphy_exit(pxpcs-\u003eserdes_phy);\n+pm_domain:\n+\tdev_pm_genpd_rpm_always_on(dev, false);\n+\treturn ret;\n+}\n+\n+static int xpcs_rk_init_res(struct dw_xpcs_rk *pxpcs)\n+{\n+\tstruct platform_device *pdev = pxpcs-\u003epdev;\n+\tstruct device *dev = \u0026pdev-\u003edev;\n+\tstruct resource *res;\n+\n+\tres = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n+\tif (!res) {\n+\t\tdev_err(dev, \"No reg-space found\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (resource_size(res) \u003c SZ_2M) {\n+\t\tdev_err(dev, \"Invalid reg-space size\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tpxpcs-\u003ereg_base = devm_ioremap_resource(dev, res);\n+\tif (IS_ERR(pxpcs-\u003ereg_base)) {\n+\t\tdev_err(dev, \"Failed to map reg-space\\n\");\n+\t\treturn PTR_ERR(pxpcs-\u003ereg_base);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void xpcs_rk_exit_clk(void *data)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = data;\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\n+\tclk_disable_unprepare(pxpcs-\u003eeee_clk);\n+\n+\tpm_runtime_force_suspend(dev);\n+}\n+\n+static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)\n+{\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\tint ret;\n+\n+\tpxpcs-\u003ecsr_clk = devm_clk_get(dev, \"csr\");\n+\tif (IS_ERR(pxpcs-\u003ecsr_clk))\n+\t\treturn dev_err_probe(dev, PTR_ERR(pxpcs-\u003ecsr_clk),\n+\t\t\t\t\t \"Failed to get CSR clock\\n\");\n+\n+\tpxpcs-\u003eeee_clk = devm_clk_get(dev, \"eee\");\n+\tif (IS_ERR(pxpcs-\u003eeee_clk))\n+\t\treturn dev_err_probe(dev, PTR_ERR(pxpcs-\u003eeee_clk),\n+\t\t\t\t\t \"Failed to get EEE clock\\n\");\n+\n+\tret = clk_prepare_enable(pxpcs-\u003eeee_clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to enable EEE clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tpm_runtime_set_suspended(dev);\n+\tpm_runtime_enable(dev);\n+\n+\tret = devm_add_action_or_reset(dev, xpcs_rk_exit_clk, pxpcs);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to register devm for EEE clock: %d\\n\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int xpcs_rk_init_bus(struct dw_xpcs_rk *pxpcs)\n+{\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\tstatic atomic_t id = ATOMIC_INIT(-1);\n+\tstruct mii_bus *bus;\n+\tint ret;\n+\n+\tbus = devm_mdiobus_alloc_size(dev, 0);\n+\tif (!bus)\n+\t\treturn -ENOMEM;\n+\n+\tbus-\u003ename = \"Rockchip DW XPCS MCI/APB3\";\n+\tbus-\u003eread = xpcs_rk_read_c22;\n+\tbus-\u003ewrite = xpcs_rk_write_c22;\n+\tbus-\u003eread_c45 = xpcs_rk_read_c45;\n+\tbus-\u003ewrite_c45 = xpcs_rk_write_c45;\n+\tbus-\u003ephy_mask = ~0;\n+\tbus-\u003eparent = dev;\n+\tbus-\u003epriv = pxpcs;\n+\n+\tsnprintf(bus-\u003eid, MII_BUS_ID_SIZE,\n+\t\t \"rockchip_dwxpcs-%x\", atomic_inc_return(\u0026id));\n+\n+\t/*\n+\t * MDIO-bus here serves as just a back-end engine abstracting out\n+\t * the MDIO and MCI/APB3 IO interfaces utilized for the Rockchip DWXPCS CSRs\n+\t * access.\n+\t */\n+\tret = devm_mdiobus_register(dev, bus);\n+\tif (ret) {\n+\t\tdev_err(dev, \"Failed to create MDIO bus\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tpxpcs-\u003ebus = bus;\n+\treturn 0;\n+}\n+\n+static int xpcs_rk_probe(struct platform_device *pdev)\n+{\n+\tstruct dw_xpcs_rk *pxpcs;\n+\tint ret;\n+\n+\tpxpcs = xpcs_rk_create_data(pdev);\n+\tif (IS_ERR(pxpcs))\n+\t\treturn PTR_ERR(pxpcs);\n+\n+\t/*\n+\t * The XPCS may be attached to a power domain (e.g. PD_PIPE). The domain\n+\t * must be powered on before any register access, otherwise the SoC will\n+\t * trigger a synchronous external abort (SError).\n+\t *\n+\t * Accessing the XPCS registers also requires a TX clock from the SerDes,\n+\t * which is needed for the soft reset.\n+\t */\n+\tret = xpcs_rk_serdes_phy_init(pxpcs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = xpcs_rk_serdes_phy_poweron(pxpcs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = xpcs_rk_init_res(pxpcs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = xpcs_rk_init_clk(pxpcs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = xpcs_rk_init_bus(pxpcs);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\treturn 0;\n+}\n+\n+static const struct of_device_id xpcs_rk_of_ids[] = {\n+\t{ .compatible = \"rockchip,rk3568-xpcs\" },\n+\t{ /* sentinel */ },\n+};\n+MODULE_DEVICE_TABLE(of, xpcs_rk_of_ids);\n+\n+struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np)\n+{\n+\tstruct platform_device *pdev;\n+\tstruct device_node *pcs_np;\n+\tstruct dw_xpcs_rk *pxpcs;\n+\tstruct dw_xpcs *xpcs;\n+\tu32 port;\n+\n+\tif (!of_device_is_available(np))\n+\t\treturn ERR_PTR(-ENODEV);\n+\n+\tif (of_property_read_u32(np, \"reg\", \u0026port))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\tif (!xpcs_rk_mdio_addr_validate((int)port))\n+\t\treturn ERR_PTR(-EINVAL);\n+\n+\t/* The XPCS pdev is attached to the parent node */\n+\tpcs_np = of_get_parent(np);\n+\tif (!pcs_np)\n+\t\treturn ERR_PTR(-ENODEV);\n+\n+\tif (!of_device_is_available(pcs_np)) {\n+\t\tof_node_put(pcs_np);\n+\t\treturn ERR_PTR(-ENODEV);\n+\t}\n+\n+\tif (!of_match_node(xpcs_rk_of_ids, pcs_np)) {\n+\t\tof_node_put(pcs_np);\n+\t\treturn ERR_PTR(-EINVAL);\n+\t}\n+\n+\tpdev = of_find_device_by_node(pcs_np);\n+\tof_node_put(pcs_np);\n+\tif (!pdev)\n+\t\treturn ERR_PTR(-EPROBE_DEFER);\n+\n+\tdevice_lock(\u0026pdev-\u003edev);\n+\tpxpcs = platform_get_drvdata(pdev);\n+\tif (!pxpcs || !pxpcs-\u003ebus) {\n+\t\tdevice_unlock(\u0026pdev-\u003edev);\n+\t\tput_device(\u0026pdev-\u003edev);\n+\t\treturn ERR_PTR(-EPROBE_DEFER);\n+\t}\n+\n+\txpcs = xpcs_create_mdiodev(pxpcs-\u003ebus, (int)port);\n+\tdevice_unlock(\u0026pdev-\u003edev);\n+\tif (IS_ERR(xpcs)) {\n+\t\tput_device(\u0026pdev-\u003edev);\n+\t\treturn xpcs;\n+\t}\n+\n+\tif (!device_link_add(dev, \u0026pdev-\u003edev, DL_FLAG_AUTOREMOVE_CONSUMER)) {\n+\t\txpcs_destroy(xpcs);\n+\t\tput_device(\u0026pdev-\u003edev);\n+\t\treturn ERR_PTR(-ENOMEM);\n+\t}\n+\n+\tput_device(\u0026pdev-\u003edev);\n+\treturn xpcs;\n+}\n+EXPORT_SYMBOL_GPL(xpcs_rk_create);\n+\n+static int xpcs_rk_pm_runtime_suspend(struct device *dev)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);\n+\n+\tclk_disable_unprepare(pxpcs-\u003ecsr_clk);\n+\n+\treturn 0;\n+}\n+\n+static int xpcs_rk_pm_runtime_resume(struct device *dev)\n+{\n+\tstruct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);\n+\n+\treturn clk_prepare_enable(pxpcs-\u003ecsr_clk);\n+}\n+\n+static DEFINE_RUNTIME_DEV_PM_OPS(xpcs_rk_pm_ops,\n+\t\t\t xpcs_rk_pm_runtime_suspend,\n+\t\t\t xpcs_rk_pm_runtime_resume,\n+\t\t\t NULL);\n+\n+static struct platform_driver xpcs_rk_driver = {\n+\t.probe = xpcs_rk_probe,\n+\t.driver = {\n+\t\t.name = \"rk_xpcs-dwxpcs\",\n+\t\t.pm = pm_ptr(\u0026xpcs_rk_pm_ops),\n+\t\t.of_match_table = xpcs_rk_of_ids,\n+\t},\n+};\n+module_platform_driver(xpcs_rk_driver);\n+\n+MODULE_DESCRIPTION(\"Rockchip XPCS platform device driver\");\n+MODULE_AUTHOR(\"Coia Prant \u003ccoiaprant@gmail.com\u003e\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c\nindex 0337e2bcc0125..50b9cdf94fdaa 100644\n--- a/drivers/net/pcs/pcs-xpcs.c\n+++ b/drivers/net/pcs/pcs-xpcs.c\n@@ -816,9 +816,14 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,\n \tif (ret \u003c 0)\n \t\treturn ret;\n \n+\t/* Clear CL37 AN complete status */\n+\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);\n+\tif (ret \u003c 0)\n+\t\treturn ret;\n+\n \tif (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)\n \t\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,\n-\t\t\t\t mdio_ctrl | BMCR_ANENABLE);\n+\t\t\t\t mdio_ctrl | BMCR_ANENABLE | BMCR_ANRESTART);\n \n \treturn ret;\n }\n@@ -1093,10 +1098,15 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,\n \t\treturn 0;\n \t}\n \n-\t/* Clear AN complete status or interrupt */\n-\tif (state-\u003ean_complete)\n+\tif (state-\u003ean_complete) {\n+\t\t/* Clear AN complete status or interrupt */\n \t\txpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);\n \n+\t\t/* Initiate the next round of AN */\n+\t\txpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART,\n+\t\t\t BMCR_ANRESTART);\n+\t}\n+\n \treturn 0;\n }\n \ndiff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c\nindex 7843356a4dd47..919bb97a4b182 100644\n--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c\n+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c\n@@ -186,6 +186,7 @@ struct rockchip_combphy_grfcfg {\n \tstruct combphy_reg pipe_xpcs_phy_ready;\n \tstruct combphy_reg pipe_pcie1l0_sel;\n \tstruct combphy_reg pipe_pcie1l1_sel;\n+\tstruct combphy_reg pipe_sgmii_mac_sel;\n \tstruct combphy_reg u3otg0_port_en;\n \tstruct combphy_reg u3otg1_port_en;\n };\n@@ -212,6 +213,7 @@ struct rockchip_combphy_priv {\n \tbool enable_ssc;\n \tbool ext_refclk;\n \tstruct clk *refclk;\n+\tu32 sgmii_mac_sel;\n };\n \n static void rockchip_combphy_updatel(struct rockchip_combphy_priv *priv,\n@@ -375,6 +377,9 @@ static int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy\n \n \tpriv-\u003eext_refclk = device_property_present(dev, \"rockchip,ext-refclk\");\n \n+\tpriv-\u003esgmii_mac_sel = 1;\n+\tdevice_property_read_u32(dev, \"rockchip,sgmii-mac-sel\", \u0026priv-\u003esgmii_mac_sel);\n+\n \tpriv-\u003ephy_rst = devm_reset_control_get_exclusive(dev, \"phy\");\n \t/* fallback to old behaviour */\n \tif (PTR_ERR(priv-\u003ephy_rst) == -ENOENT)\n@@ -873,6 +878,8 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)\n \t\tbreak;\n \n \tcase PHY_TYPE_SGMII:\n+\t\trockchip_combphy_param_write(priv-\u003epipe_grf, \u0026cfg-\u003epipe_sgmii_mac_sel,\n+\t\t\t\t\tpriv-\u003esgmii_mac_sel \u003e 0);\n \t\trockchip_combphy_param_write(priv-\u003epipe_grf, \u0026cfg-\u003epipe_xpcs_phy_ready, true);\n \t\trockchip_combphy_param_write(priv-\u003ephy_grf, \u0026cfg-\u003epipe_phymode_sel, true);\n \t\trockchip_combphy_param_write(priv-\u003ephy_grf, \u0026cfg-\u003epipe_sel_qsgmii, true);\n@@ -984,6 +991,7 @@ static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = {\n \t.con3_for_sata\t\t= { 0x000c, 15, 0, 0x00, 0x4407 },\n \t/* pipe-grf */\n \t.pipe_con0_for_sata\t= { 0x0000, 15, 0, 0x00, 0x2220 },\n+\t.pipe_sgmii_mac_sel\t= { 0x0040, 1, 1, 0x00, 0x01 },\n \t.pipe_xpcs_phy_ready\t= { 0x0040, 2, 2, 0x00, 0x01 },\n \t.u3otg0_port_en\t\t= { 0x0104, 15, 0, 0x0181, 0x1100 },\n \t.u3otg1_port_en\t\t= { 0x0144, 15, 0, 0x0181, 0x1100 },\ndiff --git a/include/linux/pcs/pcs-xpcs-rk.h b/include/linux/pcs/pcs-xpcs-rk.h\nnew file mode 100644\nindex 0000000000000..28723d5bd75cc\n--- /dev/null\n+++ b/include/linux/pcs/pcs-xpcs-rk.h\n@@ -0,0 +1,11 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef __LINUX_PCS_XPCS_ROCKCHIP_H\n+#define __LINUX_PCS_XPCS_ROCKCHIP_H\n+\n+#include \u003clinux/device.h\u003e\n+#include \u003clinux/of.h\u003e\n+#include \u003clinux/pcs/pcs-xpcs.h\u003e\n+\n+struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np);\n+\n+#endif /* __LINUX_PCS_XPCS_ROCKCHIP_H */\n"
} |
| 2/1 | 2026/09/07 19:56 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series adds support for the Synopsys DesignWare Ethernet Physical Coding Sublayer (XPCS) on Rockchip RK3568 SoCs, including a new platform driver (pcs-xpcs-rk), combphy updates, device tree bindings and DTS nodes, and related stmmac/pcs-xpcs plumbing across dwmac-rk, dwmac-intel, dwmac-renesas-gbeth, dwmac-rzn1, and dwmac-socfpga. All modified code resides in drivers for physical SoC platform devices and vendor-specific MACs/PHYs (Rockchip RK3568, Intel SoC MACs, Renesas, SoC FPGA) that are not emulated in standard virtualized fuzzing environments (QEMU / GCE on amd64). Consequently, the modified code is structurally unreachable.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any '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: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit e007c70e7143628de9c5fd8c6332a0874fd810af
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Sep 7 19:55:59 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml b/Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml
new file mode 100644
index 0000000000000..0852d0bcb66a2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml
@@ -0,0 +1,110 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/pcs/rockchip-dwxpcs.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Rockchip RK3568 Synopsys DesignWare Ethernet PCS
+
+maintainers:
+ - Coia Prant <coiaprant@gmail.com>
+
+description: |
+ Rockchip RK3568 SoC integrates a Synopsys DesignWare Ethernet Physical
+ Coding Sublayer (XPCS).
+ The PCS provides an interface between the Media Access Control (MAC)
+ and the Physical Medium Attachment (PMA) sublayer through a Media
+ Independent Interface (GMII).
+
+ The XPCS is accessed over the APB3 bus and internally connected to a
+ Naneng Combo SerDes PHY.
+ It supports 1000BASE-X, SGMII and QSGMII modes.
+
+ The block contains four MII ports that can be individually enabled and
+ routed to one of the Ethernet GMAC controllers via the pcs-handle
+ property in the MAC device tree node.
+
+properties:
+ compatible:
+ const: rockchip,rk3568-xpcs
+
+ reg:
+ maxItems: 1
+
+ "#address-cells":
+ const: 1
+
+ "#size-cells":
+ const: 0
+
+ clocks:
+ items:
+ - description: APB3 bus interface clock (clk_csr_i), required for register access
+ - description: EEE clock (clk_eee_i), required for Energy Efficient Ethernet operation
+
+ clock-names:
+ items:
+ - const: csr
+ - const: eee
+
+ phys:
+ maxItems: 1
+
+ phy-names:
+ const: serdes
+
+ power-domains:
+ maxItems: 1
+
+patternProperties:
+ "^pcs-mii@[0-3]$":
+ type: object
+ description:
+ One of the four MII ports of the XPCS. The port is linked to an
+ Ethernet MAC controller via the pcs-handle property in the MAC's
+ device tree node.
+
+ properties:
+ reg:
+ description: MII port number.
+ enum: [0, 1, 2, 3]
+
+ required:
+ - reg
+
+ additionalProperties: false
+
+required:
+ - compatible
+ - reg
+ - "#address-cells"
+ - "#size-cells"
+ - clocks
+ - clock-names
+ - phys
+ - phy-names
+ - power-domains
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/rk3568-cru.h>
+ #include <dt-bindings/power/rk3568-power.h>
+ #include <dt-bindings/phy/phy.h>
+
+ pcs@fda00000 {
+ compatible = "rockchip,rk3568-xpcs";
+ reg = <0xfda00000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&cru PCLK_XPCS>, <&cru CLK_XPCS_EEE>;
+ clock-names = "csr", "eee";
+ phys = <&combphy2 PHY_TYPE_SGMII>;
+ phy-names = "serdes";
+ power-domains = <&power RK3568_PD_PIPE>;
+
+ pcs-mii@0 {
+ reg = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml
index 379b08bd9e97a..8e898bce9af73 100644
--- a/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-naneng-combphy.yaml
@@ -80,6 +80,15 @@ properties:
description:
Some additional pipe settings are accessed through GRF regs.
+ rockchip,sgmii-mac-sel:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1]
+ default: 1
+ description:
+ Select gmac0 or gmac1 to be used as SGMII controller.
+ The hardware reset value is GMAC1 (1). Set this to 0 to route
+ SGMII to GMAC0.
+
"#phy-cells":
const: 1
@@ -105,6 +114,10 @@ allOf:
maxItems: 1
reset-names:
maxItems: 1
+ rockchip,sgmii-mac-sel: true
+ else:
+ properties:
+ rockchip,sgmii-mac-sel: false
- if:
properties:
compatible:
diff --git a/MAINTAINERS b/MAINTAINERS
index fc320b373656f..dda4d211b7db4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23738,6 +23738,15 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/rockchip,rk3576-sai.yaml
F: sound/soc/rockchip/rockchip_sai.*
+ROCKCHIP XPCS DRIVER
+M: Coia Prant <coiaprant@gmail.com>
+L: netdev@vger.kernel.org
+L: linux-rockchip@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/net/pcs/rockchip-dwxpcs.yaml
+F: drivers/net/pcs/pcs-xpcs-rk.c
+F: include/linux/pcs/pcs-xpcs-rk.h
+
ROCKER DRIVER
M: Jiri Pirko <jiri@resnulli.us>
L: netdev@vger.kernel.org
diff --git a/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts b/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts
index 58c1052ba8ef3..25caa44198843 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3568-photonicat.dts
@@ -3,6 +3,7 @@
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/leds/common.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/soc/rockchip,vop2.h>
#include "rk3568.dtsi"
@@ -242,6 +243,7 @@ &combphy1 {
&combphy2 {
status = "okay";
+ rockchip,sgmii-mac-sel = <0>;
};
&cpu0 {
@@ -260,9 +262,18 @@ &cpu3 {
cpu-supply = <&vdd_cpu>;
};
-/* Motorcomm YT8521SC LAN port (require SGMII) */
+/* Motorcomm YT8521SC LAN port */
&gmac0 {
- status = "disabled";
+ assigned-clocks = <&cru SCLK_GMAC0_RX_TX>;
+ assigned-clock-parents = <&xpcs_gmac0_clk>;
+ pcs-handle = <&xpcs_mii0>;
+ managed = "in-band-status";
+ phy-handle = <&sgmii_phy>;
+ phy-mode = "sgmii";
+ phy-supply = <&vcc_3v3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac0_miim>;
+ status = "okay";
};
/* Motorcomm YT8521SC WAN port */
@@ -341,6 +352,36 @@ &i2s0_8ch {
status = "okay";
};
+&mdio0 {
+ sgmii_phy: ethernet-phy@3 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0x3>;
+ max-speed = <1000>;
+ reset-assert-us = <20000>;
+ reset-deassert-us = <100000>;
+ reset-gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_LOW>;
+
+ leds {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@1 {
+ reg = <1>;
+ color = <LED_COLOR_ID_AMBER>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+
+ led@2 {
+ reg = <2>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+ };
+ };
+};
+
&mdio1 {
rgmii_phy: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
@@ -350,6 +391,25 @@ rgmii_phy: ethernet-phy@3 {
reset-gpios = <&gpio4 RK_PC0 GPIO_ACTIVE_LOW>;
rx-internal-delay-ps = <1500>;
tx-internal-delay-ps = <1500>;
+
+ leds {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@1 {
+ reg = <1>;
+ color = <LED_COLOR_ID_AMBER>;
+ function = LED_FUNCTION_WAN;
+ default-state = "keep";
+ };
+
+ led@2 {
+ reg = <2>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_WAN;
+ default-state = "keep";
+ };
+ };
};
};
@@ -586,3 +646,13 @@ &xin32k {
pinctrl-names = "default";
pinctrl-0 = <&clk32k_out1>;
};
+
+&xpcs {
+ status = "okay";
+ phys = <&combphy2 PHY_TYPE_SGMII>;
+ phy-names = "serdes";
+};
+
+&xpcs_mii0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 3bc653f027f1f..989e164c0eb39 100644
--- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
@@ -110,6 +110,51 @@ sata0: sata@fc000000 {
status = "disabled";
};
+ xpcs: pcs@fda00000 {
+ compatible = "rockchip,rk3568-xpcs";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0xfda00000 0x0 0x200000>;
+ clocks = <&cru PCLK_XPCS>, <&cru CLK_XPCS_EEE>;
+ clock-names = "csr", "eee";
+ power-domains = <&power RK3568_PD_PIPE>;
+ status = "disabled";
+
+ xpcs_mii0: pcs-mii@0 {
+ reg = <0>;
+ status = "disabled";
+ };
+
+ xpcs_mii1: pcs-mii@1 {
+ reg = <1>;
+ status = "disabled";
+ };
+
+ xpcs_mii2: pcs-mii@2 {
+ reg = <2>;
+ status = "disabled";
+ };
+
+ xpcs_mii3: pcs-mii@3 {
+ reg = <3>;
+ status = "disabled";
+ };
+ };
+
+ xpcs_gmac0_clk: xpcs-gmac0-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "clk_gmac0_xpcs_mii";
+ #clock-cells = <0>;
+ };
+
+ xpcs_gmac1_clk: xpcs-gmac1-clock {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "clk_gmac1_xpcs_mii";
+ #clock-cells = <0>;
+ };
+
pipe_phy_grf0: syscon@fdc70000 {
compatible = "rockchip,rk3568-pipe-phy-grf", "syscon";
reg = <0x0 0xfdc70000 0x0 0x1000>;
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index e3dd5adda5aca..5088acc06982e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -170,6 +170,7 @@ config DWMAC_ROCKCHIP
default ARCH_ROCKCHIP
depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
select MFD_SYSCON
+ select PCS_XPCS_ROCKCHIP
help
Support for Ethernet controller on Rockchip RK3288 SoC.
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
index f5f9fa67ecd77..fd5f01c8941c1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c
@@ -603,13 +603,47 @@ static void common_default_data(struct plat_stmmacenet_data *plat)
plat->mdio_bus_data->needs_reset = true;
}
+static int intel_mgbe_pcs_init(struct stmmac_priv *priv)
+{
+ struct fwnode_handle *devnode, *pcsnode;
+ struct dw_xpcs *xpcs = NULL;
+ int addr;
+
+ devnode = dev_fwnode(priv->device);
+
+ if (fwnode_property_present(devnode, "pcs-handle")) {
+ pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0);
+ xpcs = xpcs_create_fwnode(pcsnode);
+ fwnode_handle_put(pcsnode);
+ } else {
+ addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1;
+ xpcs = xpcs_create_mdiodev(priv->mii, addr);
+ }
+
+ if (IS_ERR(xpcs))
+ return PTR_ERR(xpcs);
+
+ xpcs_config_eee_mult_fact(xpcs, priv->plat->mult_fact_100ns);
+
+ priv->hw->xpcs = xpcs;
+ return 0;
+}
+
+static void intel_mgbe_pcs_exit(struct stmmac_priv *priv)
+{
+ if (!priv->hw->xpcs)
+ return;
+
+ xpcs_destroy(priv->hw->xpcs);
+ priv->hw->xpcs = NULL;
+}
+
static struct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv,
phy_interface_t interface)
{
- /* plat->mdio_bus_data->has_xpcs has been set true, so there
- * should always be an XPCS. The original code would always
- * return this if present.
- */
+ if (!priv->hw->xpcs)
+ return NULL;
+
return xpcs_to_phylink_pcs(priv->hw->xpcs);
}
@@ -733,6 +767,8 @@ static int intel_mgbe_common_data(struct pci_dev *pdev,
plat->phy_interface == PHY_INTERFACE_MODE_1000BASEX) {
plat->mdio_bus_data->pcs_mask = BIT_U32(INTEL_MGBE_XPCS_ADDR);
plat->default_an_inband = true;
+ plat->pcs_init = intel_mgbe_pcs_init;
+ plat->pcs_exit = intel_mgbe_pcs_exit;
plat->select_pcs = intel_mgbe_select_pcs;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c
index 19f34e18bfef2..9af32c26f9c14 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c
@@ -81,8 +81,11 @@ static int renesas_gmac_pcs_init(struct stmmac_priv *priv)
static void renesas_gmac_pcs_exit(struct stmmac_priv *priv)
{
- if (priv->hw->phylink_pcs)
- miic_destroy(priv->hw->phylink_pcs);
+ if (!priv->hw->phylink_pcs)
+ return;
+
+ miic_destroy(priv->hw->phylink_pcs);
+ priv->hw->phylink_pcs = NULL;
}
static struct phylink_pcs *renesas_gmac_select_pcs(struct stmmac_priv *priv,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 8d7042e689261..e47ca1bec5b8b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
+#include <linux/pcs/pcs-xpcs-rk.h>
#include <linux/pm_runtime.h>
#include "stmmac_platform.h"
@@ -47,6 +48,7 @@ struct rk_gmac_ops {
void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
int tx_delay, int rx_delay);
void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
+ void (*set_to_sgmii)(struct rk_priv_data *bsp_priv);
int (*set_speed)(struct rk_priv_data *bsp_priv,
phy_interface_t interface, int speed);
void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv);
@@ -63,6 +65,7 @@ struct rk_gmac_ops {
bool clock_grf_reg_in_php;
bool supports_rgmii;
bool supports_rmii;
+ bool supports_sgmii;
bool php_grf_required;
bool regs_valid;
u32 regs[];
@@ -98,6 +101,7 @@ struct rk_priv_data {
bool integrated_phy;
bool supports_rgmii;
bool supports_rmii;
+ bool supports_sgmii;
struct clk_bulk_data *clks;
int num_clks;
@@ -809,6 +813,8 @@ static const struct rk_gmac_ops rk3528_ops = {
#define RK3568_GRF_GMAC1_CON1 0x038c
/* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */
+#define RK3568_GMAC_MODE_RMII_RGMII GRF_CLR_BIT(7)
+#define RK3568_GMAC_MODE_SGMII_QSGMII GRF_BIT(7)
#define RK3568_GMAC_FLOW_CTRL GRF_BIT(3)
#define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3)
#define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1)
@@ -851,18 +857,32 @@ static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
RK3568_GMAC_CLK_TX_DL_CFG(tx_delay));
regmap_write(bsp_priv->grf, con1,
+ RK3568_GMAC_MODE_RMII_RGMII |
RK3568_GMAC_RXCLK_DLY_ENABLE |
RK3568_GMAC_TXCLK_DLY_ENABLE);
}
+static void rk3568_set_to_sgmii(struct rk_priv_data *bsp_priv)
+{
+ u32 con1;
+
+ con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 :
+ RK3568_GRF_GMAC0_CON1;
+
+ regmap_write(bsp_priv->grf, con1, RK3568_GMAC_MODE_SGMII_QSGMII);
+}
+
static const struct rk_gmac_ops rk3568_ops = {
.init = rk3568_init,
.set_to_rgmii = rk3568_set_to_rgmii,
+ .set_to_sgmii = rk3568_set_to_sgmii,
+
.set_speed = rk_set_clk_mac_speed,
.gmac_phy_intf_sel_mask = GENMASK_U16(6, 4),
.supports_rmii = true,
+ .supports_sgmii = true,
.regs_valid = true,
.regs = {
@@ -1208,6 +1228,43 @@ static void rk_phy_powerdown(struct rk_priv_data *bsp_priv)
dev_err(bsp_priv->dev, "fail to disable phy-supply\n");
}
+static int rk_pcs_init(struct stmmac_priv *priv)
+{
+ struct device_node *np = priv->device->of_node;
+ struct device_node *pcs_node;
+ struct dw_xpcs *xpcs;
+
+ pcs_node = of_parse_phandle(np, "pcs-handle", 0);
+ if (!pcs_node)
+ return -ENODEV;
+
+ xpcs = xpcs_rk_create(priv->device, pcs_node);
+ of_node_put(pcs_node);
+ if (IS_ERR(xpcs))
+ return PTR_ERR(xpcs);
+
+ priv->hw->xpcs = xpcs;
+ return 0;
+}
+
+static void rk_pcs_exit(struct stmmac_priv *priv)
+{
+ if (!priv->hw->xpcs)
+ return;
+
+ xpcs_destroy(priv->hw->xpcs);
+ priv->hw->xpcs = NULL;
+}
+
+static struct phylink_pcs *rk_select_pcs(struct stmmac_priv *priv,
+ phy_interface_t interface)
+{
+ if (!priv->hw->xpcs)
+ return NULL;
+
+ return xpcs_to_phylink_pcs(priv->hw->xpcs);
+}
+
static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
struct plat_stmmacenet_data *plat,
const struct rk_gmac_ops *ops)
@@ -1330,6 +1387,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
bsp_priv->supports_rgmii = ops->supports_rgmii || !!ops->set_to_rgmii;
bsp_priv->supports_rmii = ops->supports_rmii || !!ops->set_to_rmii;
+ bsp_priv->supports_sgmii = ops->supports_sgmii || !!ops->set_to_sgmii;
if (ops->init) {
ret = ops->init(bsp_priv);
@@ -1361,6 +1419,10 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv)
if (!bsp_priv->supports_rmii)
return -EINVAL;
break;
+ case PHY_INTERFACE_MODE_SGMII:
+ if (!bsp_priv->supports_sgmii)
+ return -EINVAL;
+ break;
default:
dev_err(bsp_priv->dev,
"unsupported interface %d", bsp_priv->phy_iface);
@@ -1379,16 +1441,19 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
if (ret)
return ret;
+ ret = gmac_clk_enable(bsp_priv, true);
+ if (ret)
+ return ret;
+
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_SGMII)
+ goto set_mode;
+
ret = rk_get_phy_intf_sel(bsp_priv->phy_iface);
if (ret < 0)
- return ret;
+ goto clk_disable;
intf = ret;
- ret = gmac_clk_enable(bsp_priv, true);
- if (ret)
- return ret;
-
if (bsp_priv->gmac_phy_intf_sel_mask ||
bsp_priv->gmac_rmii_mode_mask) {
/* If defined, encode the phy_intf_sel value */
@@ -1399,10 +1464,8 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
bsp_priv->gmac_rmii_mode_mask);
ret = rk_write_gmac_grf_reg(bsp_priv, val);
- if (ret < 0) {
- gmac_clk_enable(bsp_priv, false);
- return ret;
- }
+ if (ret < 0)
+ goto clk_disable;
}
if (bsp_priv->clock.rmii_mode_mask) {
@@ -1410,13 +1473,12 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
bsp_priv->clock.rmii_mode_mask);
ret = rk_write_clock_grf_reg(bsp_priv, val);
- if (ret < 0) {
- gmac_clk_enable(bsp_priv, false);
- return ret;
- }
+ if (ret < 0)
+ goto clk_disable;
}
- /*rmii or rgmii*/
+set_mode:
+ /* rmii, rgmii, sgmii */
switch (bsp_priv->phy_iface) {
case PHY_INTERFACE_MODE_RGMII:
dev_info(dev, "init for RGMII\n");
@@ -1447,15 +1509,20 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
if (bsp_priv->ops->set_to_rmii)
bsp_priv->ops->set_to_rmii(bsp_priv);
break;
+ case PHY_INTERFACE_MODE_SGMII:
+ dev_info(dev, "init for SGMII\n");
+ if (bsp_priv->ops->set_to_sgmii)
+ bsp_priv->ops->set_to_sgmii(bsp_priv);
+ break;
default:
dev_err(dev, "NO interface defined!\n");
+ ret = -EINVAL;
+ goto clk_disable;
}
ret = rk_phy_powerup(bsp_priv);
- if (ret) {
- gmac_clk_enable(bsp_priv, false);
- return ret;
- }
+ if (ret)
+ goto clk_disable;
pm_runtime_get_sync(dev);
@@ -1463,6 +1530,10 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv)
bsp_priv->ops->integrated_phy_powerup(bsp_priv);
return 0;
+
+clk_disable:
+ gmac_clk_enable(bsp_priv, false);
+ return ret;
}
static void rk_gmac_powerdown(struct rk_priv_data *gmac)
@@ -1486,6 +1557,9 @@ static void rk_get_interfaces(struct stmmac_priv *priv, void *bsp_priv,
if (rk->supports_rmii)
__set_bit(PHY_INTERFACE_MODE_RMII, interfaces);
+
+ if (rk->supports_sgmii)
+ __set_bit(PHY_INTERFACE_MODE_SGMII, interfaces);
}
static int rk_set_clk_tx_rate(void *bsp_priv_, struct clk *clk_tx_i,
@@ -1602,6 +1676,17 @@ static int rk_gmac_probe(struct platform_device *pdev)
plat_dat->suspend = rk_gmac_suspend;
plat_dat->resume = rk_gmac_resume;
+ if (plat_dat->phy_interface == PHY_INTERFACE_MODE_SGMII) {
+ /* SGMII clock always runs at 125 MHz */
+ plat_dat->set_clk_tx_rate = NULL;
+
+ /* SGMII requires a PCS */
+ plat_dat->default_an_inband = true;
+ plat_dat->pcs_init = rk_pcs_init;
+ plat_dat->pcs_exit = rk_pcs_exit;
+ plat_dat->select_pcs = rk_select_pcs;
+ }
+
plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data);
if (IS_ERR(plat_dat->bsp_priv))
return PTR_ERR(plat_dat->bsp_priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
index 13634965bc19a..01df4776edb3f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
@@ -35,8 +35,11 @@ static int rzn1_dwmac_pcs_init(struct stmmac_priv *priv)
static void rzn1_dwmac_pcs_exit(struct stmmac_priv *priv)
{
- if (priv->hw->phylink_pcs)
- miic_destroy(priv->hw->phylink_pcs);
+ if (!priv->hw->phylink_pcs)
+ return;
+
+ miic_destroy(priv->hw->phylink_pcs);
+ priv->hw->phylink_pcs = NULL;
}
static struct phylink_pcs *rzn1_dwmac_select_pcs(struct stmmac_priv *priv,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 1d7f0a57d2889..6d4bc1fe8f751 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -539,8 +539,11 @@ static int socfpga_dwmac_pcs_init(struct stmmac_priv *priv)
static void socfpga_dwmac_pcs_exit(struct stmmac_priv *priv)
{
- if (priv->hw->phylink_pcs)
- lynx_pcs_destroy(priv->hw->phylink_pcs);
+ if (!priv->hw->phylink_pcs)
+ return;
+
+ lynx_pcs_destroy(priv->hw->phylink_pcs);
+ priv->hw->phylink_pcs = NULL;
}
static struct phylink_pcs *socfpga_dwmac_select_pcs(struct stmmac_priv *priv,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index afe98ff5bdcb0..d2f77f0c223a7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -426,36 +426,15 @@ int stmmac_mdio_reset(struct mii_bus *bus)
int stmmac_pcs_setup(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
- struct fwnode_handle *devnode, *pcsnode;
- struct dw_xpcs *xpcs = NULL;
- int addr, ret;
-
- devnode = dev_fwnode(priv->device);
-
- if (priv->plat->pcs_init) {
- ret = priv->plat->pcs_init(priv);
- } else if (fwnode_property_present(devnode, "pcs-handle")) {
- pcsnode = fwnode_find_reference(devnode, "pcs-handle", 0);
- xpcs = xpcs_create_fwnode(pcsnode);
- fwnode_handle_put(pcsnode);
- ret = PTR_ERR_OR_ZERO(xpcs);
- } else if (priv->plat->mdio_bus_data &&
- priv->plat->mdio_bus_data->pcs_mask) {
- addr = ffs(priv->plat->mdio_bus_data->pcs_mask) - 1;
- xpcs = xpcs_create_mdiodev(priv->mii, addr);
- ret = PTR_ERR_OR_ZERO(xpcs);
- } else {
+ int ret;
+
+ if (!priv->plat->pcs_init)
return 0;
- }
+ ret = priv->plat->pcs_init(priv);
if (ret)
return dev_err_probe(priv->device, ret, "No xPCS found\n");
- if (xpcs)
- xpcs_config_eee_mult_fact(xpcs, priv->plat->mult_fact_100ns);
-
- priv->hw->xpcs = xpcs;
-
return 0;
}
@@ -463,14 +442,10 @@ void stmmac_pcs_clean(struct net_device *ndev)
{
struct stmmac_priv *priv = netdev_priv(ndev);
- if (priv->plat->pcs_exit)
- priv->plat->pcs_exit(priv);
-
- if (!priv->hw->xpcs)
+ if (!priv->plat->pcs_exit)
return;
- xpcs_destroy(priv->hw->xpcs);
- priv->hw->xpcs = NULL;
+ priv->plat->pcs_exit(priv);
}
struct stmmac_clk_rate {
diff --git a/drivers/net/pcs/Kconfig b/drivers/net/pcs/Kconfig
index e417fd66f660a..88bc40791e69f 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -12,6 +12,29 @@ config PCS_XPCS
This module provides a driver and helper functions for Synopsys
DesignWare XPCS controllers.
+if PCS_XPCS
+
+config PCS_XPCS_PLATFORM
+ tristate "Generic XPCS controller support"
+ default PCS_XPCS
+ help
+ Generic DWXPCS driver for platforms that don't require any
+ platform specific code to function or is using platform
+ data for setup.
+
+ If you have a controller with this interface, say Y or M here.
+
+config PCS_XPCS_ROCKCHIP
+ tristate "Rockchip XPCS controller support"
+ default ARCH_ROCKCHIP
+ depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST)
+ help
+ Support for XPCS controller on Rockchip RK356x SoC.
+
+ If you have a Rockchip SoC with this interface, say Y or M here.
+
+endif # PCS_XPCS
+
config PCS_LYNX
tristate
help
diff --git a/drivers/net/pcs/Makefile b/drivers/net/pcs/Makefile
index 4f7920618b900..f9f6cf2578d72 100644
--- a/drivers/net/pcs/Makefile
+++ b/drivers/net/pcs/Makefile
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Linux PCS drivers
-pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-plat.o \
- pcs-xpcs-nxp.o pcs-xpcs-wx.o
+pcs_xpcs-$(CONFIG_PCS_XPCS) := pcs-xpcs.o pcs-xpcs-nxp.o pcs-xpcs-wx.o
obj-$(CONFIG_PCS_XPCS) += pcs_xpcs.o
+obj-$(CONFIG_PCS_XPCS_PLATFORM) += pcs-xpcs-plat.o
+obj-$(CONFIG_PCS_XPCS_ROCKCHIP) += pcs-xpcs-rk.o
obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o
obj-$(CONFIG_PCS_MTK_LYNXI) += pcs-mtk-lynxi.o
obj-$(CONFIG_PCS_RZN1_MIIC) += pcs-rzn1-miic.o
diff --git a/drivers/net/pcs/pcs-xpcs-rk.c b/drivers/net/pcs/pcs-xpcs-rk.c
new file mode 100644
index 0000000000000..68bcaa1a5cbbf
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-rk.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Rockchip XPCS platform device driver
+ *
+ * Based on the Synopsys DesignWare XPCS platform driver.
+ * Copyright (C) 2024 Serge Semin
+ *
+ * Adapted for Rockchip SoCs, with reference to the Rockchip OEM driver.
+ * Copyright (C) 2026 Coia Prant
+ */
+
+#include <linux/atomic.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/pcs/pcs-xpcs-rk.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/sizes.h>
+
+#include "pcs-xpcs.h"
+
+struct dw_xpcs_rk {
+ struct platform_device *pdev;
+ struct mii_bus *bus;
+ void __iomem *reg_base;
+ struct phy *serdes_phy;
+ struct clk *csr_clk;
+ struct clk *eee_clk;
+};
+
+static ptrdiff_t xpcs_rk_addr_format(int dev, int reg)
+{
+ return FIELD_PREP(0x70000, dev) | FIELD_PREP(0xffff, reg);
+}
+
+static int xpcs_rk_read_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg)
+{
+ ptrdiff_t csr;
+ int ret;
+
+ csr = xpcs_rk_addr_format(dev, reg);
+
+ ret = pm_runtime_resume_and_get(&pxpcs->pdev->dev);
+ if (ret)
+ return ret;
+
+ ret = readl(pxpcs->reg_base + (csr << 2)) & 0xffff;
+
+ pm_runtime_put(&pxpcs->pdev->dev);
+ return ret;
+}
+
+static int xpcs_rk_write_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg, u16 val)
+{
+ ptrdiff_t csr;
+ int ret;
+
+ csr = xpcs_rk_addr_format(dev, reg);
+
+ ret = pm_runtime_resume_and_get(&pxpcs->pdev->dev);
+ if (ret)
+ return ret;
+
+ writel(val, pxpcs->reg_base + (csr << 2));
+
+ pm_runtime_put(&pxpcs->pdev->dev);
+ return 0;
+}
+
+#define ROCKCHIP_MMD_MII1 2
+#define ROCKCHIP_MMD_MII2 3
+#define ROCKCHIP_MMD_MII3 4
+#define ROCKCHIP_MMD_PMAPMD 6
+#define ROCKCHIP_MMD_MII 7
+
+static bool xpcs_rk_mdio_addr_validate(int addr)
+{
+ return !(addr < 0 || addr > 3);
+}
+
+static int xpcs_rk_mdio_read_remapping(int addr, int dev, int reg)
+{
+ switch (dev) {
+ case MDIO_MMD_PMAPMD:
+ return ROCKCHIP_MMD_PMAPMD;
+ case MDIO_MMD_VEND2:
+ break;
+ default:
+ return -ENXIO;
+ }
+
+ /* read remapping to MII is performed by HW */
+ switch (addr) {
+ case 0:
+ return ROCKCHIP_MMD_MII;
+ case 1:
+ return ROCKCHIP_MMD_MII1;
+ case 2:
+ return ROCKCHIP_MMD_MII2;
+ case 3:
+ return ROCKCHIP_MMD_MII3;
+ default:
+ return -ENODEV;
+ }
+}
+
+static int xpcs_rk_mdio_write_remapping(int addr, int dev, int reg)
+{
+ switch (dev) {
+ case MDIO_MMD_PMAPMD:
+ return ROCKCHIP_MMD_PMAPMD;
+ case MDIO_MMD_VEND2:
+ break;
+ default:
+ return -ENXIO;
+ }
+
+ /* Writable only on MII */
+ switch (reg) {
+ case DW_VR_MII_AN_CTRL:
+ case DW_VR_MII_AN_INTR_STS:
+ case DW_VR_MII_EEE_MCTRL0:
+ case DW_VR_MII_EEE_MCTRL1:
+ case DW_VR_MII_DIG_CTRL2:
+ return ROCKCHIP_MMD_MII;
+ default:
+ break;
+ }
+
+ switch (addr) {
+ case 0:
+ return ROCKCHIP_MMD_MII;
+ case 1:
+ return ROCKCHIP_MMD_MII1;
+ case 2:
+ return ROCKCHIP_MMD_MII2;
+ case 3:
+ return ROCKCHIP_MMD_MII3;
+ default:
+ return -ENODEV;
+ }
+}
+
+static int xpcs_rk_read_c22(struct mii_bus *bus, int addr, int reg)
+{
+ struct dw_xpcs_rk *pxpcs = bus->priv;
+ int dev;
+
+ if (!xpcs_rk_mdio_addr_validate(addr))
+ return -ENODEV;
+
+ dev = xpcs_rk_mdio_read_remapping(addr, MDIO_MMD_VEND2, reg);
+ if (dev < 0)
+ return 0xffff;
+
+ return xpcs_rk_read_reg(pxpcs, dev, reg);
+}
+
+static int xpcs_rk_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)
+{
+ struct dw_xpcs_rk *pxpcs = bus->priv;
+ int dev;
+
+ if (!xpcs_rk_mdio_addr_validate(addr))
+ return -ENODEV;
+
+ dev = xpcs_rk_mdio_write_remapping(addr, MDIO_MMD_VEND2, reg);
+ if (dev < 0)
+ return 0;
+
+ return xpcs_rk_write_reg(pxpcs, dev, reg, val);
+}
+
+static int xpcs_rk_read_c45(struct mii_bus *bus, int addr, int dev, int reg)
+{
+ struct dw_xpcs_rk *pxpcs = bus->priv;
+
+ if (!xpcs_rk_mdio_addr_validate(addr))
+ return -ENODEV;
+
+ dev = xpcs_rk_mdio_read_remapping(addr, dev, reg);
+ if (dev < 0)
+ return 0xffff;
+
+ return xpcs_rk_read_reg(pxpcs, dev, reg);
+}
+
+static int xpcs_rk_write_c45(struct mii_bus *bus, int addr, int dev, int reg, u16 val)
+{
+ struct dw_xpcs_rk *pxpcs = bus->priv;
+
+ if (!xpcs_rk_mdio_addr_validate(addr))
+ return -ENODEV;
+
+ dev = xpcs_rk_mdio_write_remapping(addr, dev, reg);
+ if (dev < 0)
+ return 0;
+
+ return xpcs_rk_write_reg(pxpcs, dev, reg, val);
+}
+
+static struct dw_xpcs_rk *xpcs_rk_create_data(struct platform_device *pdev)
+{
+ struct dw_xpcs_rk *pxpcs;
+
+ pxpcs = devm_kzalloc(&pdev->dev, sizeof(*pxpcs), GFP_KERNEL);
+ if (!pxpcs)
+ return ERR_PTR(-ENOMEM);
+
+ pxpcs->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, pxpcs);
+
+ return pxpcs;
+}
+
+static int xpcs_rk_serdes_phy_init(struct dw_xpcs_rk *pxpcs)
+{
+ struct device *dev = &pxpcs->pdev->dev;
+
+ pxpcs->serdes_phy = devm_phy_get(dev, "serdes");
+ if (IS_ERR(pxpcs->serdes_phy))
+ return dev_err_probe(dev, PTR_ERR(pxpcs->serdes_phy),
+ "Failed to get SerDes PHY\n");
+
+ return 0;
+}
+
+static void xpcs_rk_serdes_phy_poweroff(void *data)
+{
+ struct dw_xpcs_rk *pxpcs = data;
+ struct device *dev = &pxpcs->pdev->dev;
+
+ phy_power_off(pxpcs->serdes_phy);
+ phy_exit(pxpcs->serdes_phy);
+
+ dev_pm_genpd_rpm_always_on(dev, false);
+}
+
+static int xpcs_rk_serdes_phy_poweron(struct dw_xpcs_rk *pxpcs)
+{
+ struct device *dev = &pxpcs->pdev->dev;
+ int ret;
+
+ /*
+ * The power domain is required and must be enabled, which allows us to
+ * dynamically turn the CSR clock on/off using PM while keeping the PCS
+ * powered on.
+ */
+ ret = dev_pm_genpd_rpm_always_on(dev, true);
+ if (ret) {
+ dev_err(dev, "Failed to power on power-domains\n");
+ return ret;
+ }
+
+ ret = phy_init(pxpcs->serdes_phy);
+ if (ret) {
+ dev_err(dev, "Failed to init SerDes PHY\n");
+ goto pm_domain;
+ }
+
+ ret = phy_power_on(pxpcs->serdes_phy);
+ if (ret) {
+ dev_err(dev, "Failed to power on SerDes PHY\n");
+ goto serdes_phy;
+ }
+
+ ret = devm_add_action_or_reset(dev, xpcs_rk_serdes_phy_poweroff, pxpcs);
+ if (ret) {
+ dev_err(dev, "Failed to register devm for SerDes PHY: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+
+serdes_phy:
+ phy_exit(pxpcs->serdes_phy);
+pm_domain:
+ dev_pm_genpd_rpm_always_on(dev, false);
+ return ret;
+}
+
+static int xpcs_rk_init_res(struct dw_xpcs_rk *pxpcs)
+{
+ struct platform_device *pdev = pxpcs->pdev;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "No reg-space found\n");
+ return -EINVAL;
+ }
+
+ if (resource_size(res) < SZ_2M) {
+ dev_err(dev, "Invalid reg-space size\n");
+ return -EINVAL;
+ }
+
+ pxpcs->reg_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pxpcs->reg_base)) {
+ dev_err(dev, "Failed to map reg-space\n");
+ return PTR_ERR(pxpcs->reg_base);
+ }
+
+ return 0;
+}
+
+static void xpcs_rk_exit_clk(void *data)
+{
+ struct dw_xpcs_rk *pxpcs = data;
+ struct device *dev = &pxpcs->pdev->dev;
+
+ clk_disable_unprepare(pxpcs->eee_clk);
+
+ pm_runtime_force_suspend(dev);
+}
+
+static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)
+{
+ struct device *dev = &pxpcs->pdev->dev;
+ int ret;
+
+ pxpcs->csr_clk = devm_clk_get(dev, "csr");
+ if (IS_ERR(pxpcs->csr_clk))
+ return dev_err_probe(dev, PTR_ERR(pxpcs->csr_clk),
+ "Failed to get CSR clock\n");
+
+ pxpcs->eee_clk = devm_clk_get(dev, "eee");
+ if (IS_ERR(pxpcs->eee_clk))
+ return dev_err_probe(dev, PTR_ERR(pxpcs->eee_clk),
+ "Failed to get EEE clock\n");
+
+ ret = clk_prepare_enable(pxpcs->eee_clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable EEE clock\n");
+ return ret;
+ }
+
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+
+ ret = devm_add_action_or_reset(dev, xpcs_rk_exit_clk, pxpcs);
+ if (ret) {
+ dev_err(dev, "Failed to register devm for EEE clock: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int xpcs_rk_init_bus(struct dw_xpcs_rk *pxpcs)
+{
+ struct device *dev = &pxpcs->pdev->dev;
+ static atomic_t id = ATOMIC_INIT(-1);
+ struct mii_bus *bus;
+ int ret;
+
+ bus = devm_mdiobus_alloc_size(dev, 0);
+ if (!bus)
+ return -ENOMEM;
+
+ bus->name = "Rockchip DW XPCS MCI/APB3";
+ bus->read = xpcs_rk_read_c22;
+ bus->write = xpcs_rk_write_c22;
+ bus->read_c45 = xpcs_rk_read_c45;
+ bus->write_c45 = xpcs_rk_write_c45;
+ bus->phy_mask = ~0;
+ bus->parent = dev;
+ bus->priv = pxpcs;
+
+ snprintf(bus->id, MII_BUS_ID_SIZE,
+ "rockchip_dwxpcs-%x", atomic_inc_return(&id));
+
+ /*
+ * MDIO-bus here serves as just a back-end engine abstracting out
+ * the MDIO and MCI/APB3 IO interfaces utilized for the Rockchip DWXPCS CSRs
+ * access.
+ */
+ ret = devm_mdiobus_register(dev, bus);
+ if (ret) {
+ dev_err(dev, "Failed to create MDIO bus\n");
+ return ret;
+ }
+
+ pxpcs->bus = bus;
+ return 0;
+}
+
+static int xpcs_rk_probe(struct platform_device *pdev)
+{
+ struct dw_xpcs_rk *pxpcs;
+ int ret;
+
+ pxpcs = xpcs_rk_create_data(pdev);
+ if (IS_ERR(pxpcs))
+ return PTR_ERR(pxpcs);
+
+ /*
+ * The XPCS may be attached to a power domain (e.g. PD_PIPE). The domain
+ * must be powered on before any register access, otherwise the SoC will
+ * trigger a synchronous external abort (SError).
+ *
+ * Accessing the XPCS registers also requires a TX clock from the SerDes,
+ * which is needed for the soft reset.
+ */
+ ret = xpcs_rk_serdes_phy_init(pxpcs);
+ if (ret)
+ return ret;
+
+ ret = xpcs_rk_serdes_phy_poweron(pxpcs);
+ if (ret)
+ return ret;
+
+ ret = xpcs_rk_init_res(pxpcs);
+ if (ret)
+ return ret;
+
+ ret = xpcs_rk_init_clk(pxpcs);
+ if (ret)
+ return ret;
+
+ ret = xpcs_rk_init_bus(pxpcs);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct of_device_id xpcs_rk_of_ids[] = {
+ { .compatible = "rockchip,rk3568-xpcs" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, xpcs_rk_of_ids);
+
+struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np)
+{
+ struct platform_device *pdev;
+ struct device_node *pcs_np;
+ struct dw_xpcs_rk *pxpcs;
+ struct dw_xpcs *xpcs;
+ u32 port;
+
+ if (!of_device_is_available(np))
+ return ERR_PTR(-ENODEV);
+
+ if (of_property_read_u32(np, "reg", &port))
+ return ERR_PTR(-EINVAL);
+
+ if (!xpcs_rk_mdio_addr_validate((int)port))
+ return ERR_PTR(-EINVAL);
+
+ /* The XPCS pdev is attached to the parent node */
+ pcs_np = of_get_parent(np);
+ if (!pcs_np)
+ return ERR_PTR(-ENODEV);
+
+ if (!of_device_is_available(pcs_np)) {
+ of_node_put(pcs_np);
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (!of_match_node(xpcs_rk_of_ids, pcs_np)) {
+ of_node_put(pcs_np);
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdev = of_find_device_by_node(pcs_np);
+ of_node_put(pcs_np);
+ if (!pdev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ device_lock(&pdev->dev);
+ pxpcs = platform_get_drvdata(pdev);
+ if (!pxpcs || !pxpcs->bus) {
+ device_unlock(&pdev->dev);
+ put_device(&pdev->dev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ xpcs = xpcs_create_mdiodev(pxpcs->bus, (int)port);
+ device_unlock(&pdev->dev);
+ if (IS_ERR(xpcs)) {
+ put_device(&pdev->dev);
+ return xpcs;
+ }
+
+ if (!device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER)) {
+ xpcs_destroy(xpcs);
+ put_device(&pdev->dev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ put_device(&pdev->dev);
+ return xpcs;
+}
+EXPORT_SYMBOL_GPL(xpcs_rk_create);
+
+static int xpcs_rk_pm_runtime_suspend(struct device *dev)
+{
+ struct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(pxpcs->csr_clk);
+
+ return 0;
+}
+
+static int xpcs_rk_pm_runtime_resume(struct device *dev)
+{
+ struct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(pxpcs->csr_clk);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(xpcs_rk_pm_ops,
+ xpcs_rk_pm_runtime_suspend,
+ xpcs_rk_pm_runtime_resume,
+ NULL);
+
+static struct platform_driver xpcs_rk_driver = {
+ .probe = xpcs_rk_probe,
+ .driver = {
+ .name = "rk_xpcs-dwxpcs",
+ .pm = pm_ptr(&xpcs_rk_pm_ops),
+ .of_match_table = xpcs_rk_of_ids,
+ },
+};
+module_platform_driver(xpcs_rk_driver);
+
+MODULE_DESCRIPTION("Rockchip XPCS platform device driver");
+MODULE_AUTHOR("Coia Prant <coiaprant@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
index 0337e2bcc0125..50b9cdf94fdaa 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -816,9 +816,14 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
if (ret < 0)
return ret;
+ /* Clear CL37 AN complete status */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+ if (ret < 0)
+ return ret;
+
if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
- mdio_ctrl | BMCR_ANENABLE);
+ mdio_ctrl | BMCR_ANENABLE | BMCR_ANRESTART);
return ret;
}
@@ -1093,10 +1098,15 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
return 0;
}
- /* Clear AN complete status or interrupt */
- if (state->an_complete)
+ if (state->an_complete) {
+ /* Clear AN complete status or interrupt */
xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+ /* Initiate the next round of AN */
+ xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART,
+ BMCR_ANRESTART);
+ }
+
return 0;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 7843356a4dd47..919bb97a4b182 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -186,6 +186,7 @@ struct rockchip_combphy_grfcfg {
struct combphy_reg pipe_xpcs_phy_ready;
struct combphy_reg pipe_pcie1l0_sel;
struct combphy_reg pipe_pcie1l1_sel;
+ struct combphy_reg pipe_sgmii_mac_sel;
struct combphy_reg u3otg0_port_en;
struct combphy_reg u3otg1_port_en;
};
@@ -212,6 +213,7 @@ struct rockchip_combphy_priv {
bool enable_ssc;
bool ext_refclk;
struct clk *refclk;
+ u32 sgmii_mac_sel;
};
static void rockchip_combphy_updatel(struct rockchip_combphy_priv *priv,
@@ -375,6 +377,9 @@ static int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy
priv->ext_refclk = device_property_present(dev, "rockchip,ext-refclk");
+ priv->sgmii_mac_sel = 1;
+ device_property_read_u32(dev, "rockchip,sgmii-mac-sel", &priv->sgmii_mac_sel);
+
priv->phy_rst = devm_reset_control_get_exclusive(dev, "phy");
/* fallback to old behaviour */
if (PTR_ERR(priv->phy_rst) == -ENOENT)
@@ -873,6 +878,8 @@ static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
break;
case PHY_TYPE_SGMII:
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_sgmii_mac_sel,
+ priv->sgmii_mac_sel > 0);
rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
@@ -984,6 +991,7 @@ static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = {
.con3_for_sata = { 0x000c, 15, 0, 0x00, 0x4407 },
/* pipe-grf */
.pipe_con0_for_sata = { 0x0000, 15, 0, 0x00, 0x2220 },
+ .pipe_sgmii_mac_sel = { 0x0040, 1, 1, 0x00, 0x01 },
.pipe_xpcs_phy_ready = { 0x0040, 2, 2, 0x00, 0x01 },
.u3otg0_port_en = { 0x0104, 15, 0, 0x0181, 0x1100 },
.u3otg1_port_en = { 0x0144, 15, 0, 0x0181, 0x1100 },
diff --git a/include/linux/pcs/pcs-xpcs-rk.h b/include/linux/pcs/pcs-xpcs-rk.h
new file mode 100644
index 0000000000000..28723d5bd75cc
--- /dev/null
+++ b/include/linux/pcs/pcs-xpcs-rk.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __LINUX_PCS_XPCS_ROCKCHIP_H
+#define __LINUX_PCS_XPCS_ROCKCHIP_H
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/pcs/pcs-xpcs.h>
+
+struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np);
+
+#endif /* __LINUX_PCS_XPCS_ROCKCHIP_H */
|
| 3/2 | 2026/09/07 19:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 21215 output: 41 thoughts: 811 Thoughts: **Analyzing the Patch Series: A Deep Dive** Okay, so I need to get a handle on this patch series, focusing on the `amd64` architecture. My initial step is to lay out the changes, right? I'm seeing a bunch of files: documentation bindings, the `MAINTAINERS` file (always important!), several DTS files for Rockchip SoCs (`rk3568`), some `Kconfig` and `Makefile` updates in network drivers, and then a slew of driver files: Rockchip-specific ones for PCS and PHY (`pcs-xpcs-rk.c`, `phy-rockchip-naneng-combphy.c`, `dwmac-rk.c`), plus a set of `stmmac` refactoring touches for various `dwmac` drivers (`dwmac-intel.c`, `dwmac-renesas-gbeth.c`, `dwmac-rzn1.c`, `dwmac-socfpga.c`) and associated functions. Aha! This breaks down nicely. We've got distinct areas of concern: the Rockchip SoC-specific code, targeting ARM/ARM64 platforms, and then the more generic `stmmac` updates, some of which seem to involve Intel hardware (`dwmac-intel.c`). I need to pay close attention to the `stmmac_mdio.c` modifications, especially `stmmac_pcs_setup()` and `stmmac_pcs_clean()`. And of course the PCS-related functions like `xpcs_config_aneg_c37_sgmii()` and `xpcs_get_state_c37_sgmii()` in `pcs-xpcs.c`. Now, the crucial question for `amd64` is this: can I even reach `stmmac`, `dwmac-intel`, or the `pcs-xpcs` components through syzkaller, standard QEMU setups, or will this require very specific physical PCI devices or hardware configurations? I need to know if these are even viable targets for fuzzing on `amd64`. I'm going to dig into `dwmac-intel.c`, the `stmmac` code, and `pcs-xpcs` specifically. I need to figure out if there's any emulation support in QEMU or if these can be reached through some virtual bus or standard fuzzing techniques. Time to search! Let's get the grepper or search tools going and see what we can uncover about the accessibility of these components on an `amd64` system. |
| 4/2 | 2026/09/07 19:56 | tool | grepper |
0mArgs:{
"Expression": "intel_mgbe_common_data",
"PathPrefix": "drivers/net/ethernet/stmicro/stmmac"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=641=static struct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv,\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-649-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:650:static int intel_mgbe_common_data(struct pci_dev *pdev,\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-651-\t\t\t\t struct plat_stmmacenet_data *plat)\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=796=static int ehl_common_data(struct pci_dev *pdev,\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-818-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:819:\treturn intel_mgbe_common_data(pdev, plat);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-820-}\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=959=static int tgl_common_data(struct pci_dev *pdev,\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-976-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:977:\treturn intel_mgbe_common_data(pdev, plat);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-978-}\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=1034=static int adln_common_data(struct pci_dev *pdev,\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1055-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:1056:\treturn intel_mgbe_common_data(pdev, plat);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1057-}\n"
} |
| 5/2 | 2026/09/07 19:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 23223 output: 44 thoughts: 56 Thoughts: Okay, let's dive into this. **Examining the dwmac-intel Driver** Right, so I'm looking at `dwmac-intel.c`. From the name alone, it's pretty clear this is the driver for the Intel Ethernet MAC controllers, specifically those found in Elkhart Lake (EHL), Tiger Lake (TGL), and Alder Lake-N (ADLN) platforms. That's a good starting point. Now, the key question is, precisely *which* devices does this driver intend to probe and manage? Understanding the specific PCI device IDs, or perhaps even vendor IDs, that this driver supports is crucial for troubleshooting and, frankly, for ensuring I'm even looking at the right piece of code for the task at hand. Let's see what the driver actually probes for. Time to dig in and find those device IDs. |
| 6/2 | 2026/09/07 19:56 | tool | grepper |
0mArgs:{
"Expression": "pci_driver",
"PathPrefix": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=1451=MODULE_DEVICE_TABLE(pci, intel_eth_pci_id_table);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1452-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:1453:static struct pci_driver intel_eth_pci_driver = {\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1454-\t.name = \"intel-eth-pci\",\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1462-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:1463:module_pci_driver(intel_eth_pci_driver);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1464-\n"
} |
| 7/2 | 2026/09/07 19:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 23771 output: 18 thoughts: 1389 Thoughts: **Fuzzing Feasibility Assessment** Okay, let's break this down systematically. My initial thought is to determine if this patch introduces code that's even *reachable* within a standard fuzzing environment, specifically GCE or QEMU on an amd64 architecture. That's the baseline. First, I need to understand the scope of the changes. The patch touches several hardware driver files: `drivers/net/pcs/pcs-xpcs-rk.c`, `drivers/phy/rockchip/phy-rockchip-naneng-combphy.c`, and several `stmmac` variants (`dwmac-rk`, `dwmac-renesas-gbeth`, `dwmac-rzn1`, `dwmac-socfpga`, `dwmac-intel`, `stmmac_mdio.c`, and `pcs-xpcs.c`). I need to quickly assess each file against the "NEGATIVE CRITERIA" outlined. My immediate thought is, are these drivers for hardware that's *emulated* in QEMU? Based on my understanding, `dwmac-intel` is specific to Intel SoCs like Elkhart Lake, Tiger Lake, and Alder Lake-N. Those are *physical* SoCs; not standard QEMU material. Same for `pcs-xpcs-rk` and `dwmac-rk`, which are Rockchip RK3568 SoC platform devices. They're DT-based ARM64 hardware, so definitely not in a standard x86 QEMU setup. `dwmac-renesas-gbeth`, `dwmac-rzn1`, and `dwmac-socfpga` are platform drivers for Renesas and Intel SoC FPGA ARM/RISC-V boards. They don't appear in x86/amd64 emulation. `stmmac_mdio.c` is part of the Synopsys DesignWare MAC driver. It only runs on stmmac hardware, and none of those are emulated in my standard environments. The same applies to `pcs-xpcs.c`, which is the Synopsys DesignWare XPCS driver, instantiated by stmmac or dwc xpcs devices. Now, I'm thinking, could *any* virtual bus or software emulation layer instantiate `stmmac` or `pcs-xpcs`? I'm thinking USB gadget, loopback, netlink, binder, sockets, virtio, etc. None of those I can think of do. They have their own network devices and don't rely on stmmac or pcs-xpcs. Just to be absolutely sure, I'll double-check: Do *any* virtual drivers, like `mac80211_hwsim`, `netkit`, `veth`, `dummy`, `team`, `bond`, or `usbnet`, utilize `stmmac` or, more specifically, `phylink` with `pcs-xpcs`? Phylink *is* used by Ethernet drivers, but `pcs-xpcs` is a PCS driver for Synopsys DW XPCS, which is used by *physical* Ethernet MACs, not virtual ones. I'm going to grep for `xpcs_create` across the kernel to be certain, but so far the path to fuzzing looks blocked. |
| 8/2 | 2026/09/07 19:56 | tool | grepper |
0mArgs:{
"Expression": "xpcs_create"
}Results: {
"Output": "drivers/net/dsa/microchip/ksz9477.c=321=static int ksz9477_pcs_create(struct ksz_device *dev)\n--\ndrivers/net/dsa/microchip/ksz9477.c-345-\ndrivers/net/dsa/microchip/ksz9477.c:346:\tpcs = xpcs_create_pcs_mdiodev(bus, 0);\ndrivers/net/dsa/microchip/ksz9477.c-347-\tif (IS_ERR(pcs))\n--\ndrivers/net/dsa/sja1105/sja1105_mdio.c=368=static int sja1105_mdiobus_pcs_register(struct sja1105_private *priv)\n--\ndrivers/net/dsa/sja1105/sja1105_mdio.c-411-\ndrivers/net/dsa/sja1105/sja1105_mdio.c:412:\t\tpcs = xpcs_create_pcs_mdiodev(bus, port);\ndrivers/net/dsa/sja1105/sja1105_mdio.c-413-\t\tif (IS_ERR(pcs)) {\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_phylink.c=197=int fbnic_phylink_create(struct net_device *netdev)\n--\ndrivers/net/ethernet/meta/fbnic/fbnic_phylink.c-204-\ndrivers/net/ethernet/meta/fbnic/fbnic_phylink.c:205:\tpcs = xpcs_create_pcs_mdiodev(fbd-\u003emdio_bus, 0);\ndrivers/net/ethernet/meta/fbnic/fbnic_phylink.c-206-\tif (IS_ERR(pcs)) {\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=606=static int intel_mgbe_pcs_init(struct stmmac_priv *priv)\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-615-\t\tpcsnode = fwnode_find_reference(devnode, \"pcs-handle\", 0);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:616:\t\txpcs = xpcs_create_fwnode(pcsnode);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-617-\t\tfwnode_handle_put(pcsnode);\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-619-\t\taddr = ffs(priv-\u003eplat-\u003emdio_bus_data-\u003epcs_mask) - 1;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:620:\t\txpcs = xpcs_create_mdiodev(priv-\u003emii, addr);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-621-\t}\n--\ndrivers/net/ethernet/wangxun/txgbe/txgbe_phy.c=126=static int txgbe_mdio_pcs_init(struct txgbe *txgbe)\n--\ndrivers/net/ethernet/wangxun/txgbe/txgbe_phy.c-153-\ndrivers/net/ethernet/wangxun/txgbe/txgbe_phy.c:154:\tpcs = xpcs_create_pcs_mdiodev(mii_bus, 0);\ndrivers/net/ethernet/wangxun/txgbe/txgbe_phy.c-155-\tif (IS_ERR(pcs))\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=447=struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np)\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-491-\ndrivers/net/pcs/pcs-xpcs-rk.c:492:\txpcs = xpcs_create_mdiodev(pxpcs-\u003ebus, (int)port);\ndrivers/net/pcs/pcs-xpcs-rk.c-493-\tdevice_unlock(\u0026pdev-\u003edev);\n--\ndrivers/net/pcs/pcs-xpcs.c=1499=static int xpcs_identify(struct dw_xpcs *xpcs)\n--\ndrivers/net/pcs/pcs-xpcs.c-1518-\ndrivers/net/pcs/pcs-xpcs.c:1519:static struct dw_xpcs *xpcs_create_data(struct mdio_device *mdiodev)\ndrivers/net/pcs/pcs-xpcs.c-1520-{\n--\ndrivers/net/pcs/pcs-xpcs.c=1571=static int xpcs_init_id(struct dw_xpcs *xpcs)\n--\ndrivers/net/pcs/pcs-xpcs.c-1585-\ndrivers/net/pcs/pcs-xpcs.c:1586:static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev)\ndrivers/net/pcs/pcs-xpcs.c-1587-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1590-\ndrivers/net/pcs/pcs-xpcs.c:1591:\txpcs = xpcs_create_data(mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1592-\tif (IS_ERR(xpcs))\n--\ndrivers/net/pcs/pcs-xpcs.c-1622-/**\ndrivers/net/pcs/pcs-xpcs.c:1623: * xpcs_create_mdiodev() - create a DW xPCS instance with the MDIO @addr\ndrivers/net/pcs/pcs-xpcs.c-1624- * @bus: pointer to the MDIO-bus descriptor for the device to be looked at\n--\ndrivers/net/pcs/pcs-xpcs.c-1630- */\ndrivers/net/pcs/pcs-xpcs.c:1631:struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr)\ndrivers/net/pcs/pcs-xpcs.c-1632-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1639-\ndrivers/net/pcs/pcs-xpcs.c:1640:\txpcs = xpcs_create(mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1641-\ndrivers/net/pcs/pcs-xpcs.c:1642:\t/* xpcs_create() has taken a refcount on the mdiodev if it was\ndrivers/net/pcs/pcs-xpcs.c:1643:\t * successful. If xpcs_create() fails, this will free the mdio\ndrivers/net/pcs/pcs-xpcs.c-1644-\t * device here. In any case, we don't need to hold our reference\n--\ndrivers/net/pcs/pcs-xpcs.c-1651-}\ndrivers/net/pcs/pcs-xpcs.c:1652:EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1653-\ndrivers/net/pcs/pcs-xpcs.c:1654:struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr)\ndrivers/net/pcs/pcs-xpcs.c-1655-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1657-\ndrivers/net/pcs/pcs-xpcs.c:1658:\txpcs = xpcs_create_mdiodev(bus, addr);\ndrivers/net/pcs/pcs-xpcs.c-1659-\tif (IS_ERR(xpcs))\n--\ndrivers/net/pcs/pcs-xpcs.c-1663-}\ndrivers/net/pcs/pcs-xpcs.c:1664:EXPORT_SYMBOL_GPL(xpcs_create_pcs_mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1665-\ndrivers/net/pcs/pcs-xpcs.c-1666-/**\ndrivers/net/pcs/pcs-xpcs.c:1667: * xpcs_create_fwnode() - Create a DW xPCS instance from @fwnode\ndrivers/net/pcs/pcs-xpcs.c-1668- * @fwnode: fwnode handle poining to the DW XPCS device\n--\ndrivers/net/pcs/pcs-xpcs.c-1675- */\ndrivers/net/pcs/pcs-xpcs.c:1676:struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode)\ndrivers/net/pcs/pcs-xpcs.c-1677-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1687-\ndrivers/net/pcs/pcs-xpcs.c:1688:\txpcs = xpcs_create(mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1689-\ndrivers/net/pcs/pcs-xpcs.c:1690:\t/* xpcs_create() has taken a refcount on the mdiodev if it was\ndrivers/net/pcs/pcs-xpcs.c:1691:\t * successful. If xpcs_create() fails, this will free the mdio\ndrivers/net/pcs/pcs-xpcs.c-1692-\t * device here. In any case, we don't need to hold our reference\n--\ndrivers/net/pcs/pcs-xpcs.c-1699-}\ndrivers/net/pcs/pcs-xpcs.c:1700:EXPORT_SYMBOL_GPL(xpcs_create_fwnode);\ndrivers/net/pcs/pcs-xpcs.c-1701-\n--\ninclude/linux/pcs/pcs-xpcs.h=55=void xpcs_config_eee_mult_fact(struct dw_xpcs *xpcs, u8 mult_fact);\ninclude/linux/pcs/pcs-xpcs.h:56:struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr);\ninclude/linux/pcs/pcs-xpcs.h:57:struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode);\ninclude/linux/pcs/pcs-xpcs.h-58-void xpcs_destroy(struct dw_xpcs *xpcs);\ninclude/linux/pcs/pcs-xpcs.h-59-\ninclude/linux/pcs/pcs-xpcs.h:60:struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr);\ninclude/linux/pcs/pcs-xpcs.h-61-void xpcs_destroy_pcs(struct phylink_pcs *pcs);\n"
} |
| 9/2 | 2026/09/07 19:56 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 28702 output: 206 thoughts: 708 Thoughts: **My Assessment of Fuzzing Reachability** Okay, so I've looked at this patch series, and here's my take: It's all about adding support for specific, physical hardware. We're talking about drivers for the Rockchip RK3568 XPCS Ethernet PCS, some accompanying Rockchip naneng combphy and dwmac-rk drivers, and various stmmac/pcs-xpcs modifications related to this, including Intel/Renesas/Altera stmmac glue. The problem, as I see it, is that *all* of this code fundamentally relies on physical hardware that's *not* present in standard virtualized environments like QEMU or GCE on amd64. The drivers are tailored for specific SoCs (Rockchip RK3568, Intel SoCs, Renesas SoCs, etc.) and vendor-specific controllers. This includes modifications in the device trees too. Essentially, there's no way syzkaller, running in a standard virtualized setup, is going to be able to even *touch* this code. It's structurally unreachable. The hardware dependencies are just too tight. Therefore, `WorthFuzzing` should be `false`, and the `EnableConfigs` and `FocusSymbols` should be empty. I'm going to set these results accordingly. |
| 10/2 | 2026/09/07 19:56 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch series adds support for the Synopsys DesignWare Ethernet Physical Coding Sublayer (XPCS) on Rockchip RK3568 SoCs, including a new platform driver (pcs-xpcs-rk), combphy updates, device tree bindings and DTS nodes, and related stmmac/pcs-xpcs plumbing across dwmac-rk, dwmac-intel, dwmac-renesas-gbeth, dwmac-rzn1, and dwmac-socfpga. All modified code resides in drivers for physical SoC platform devices and vendor-specific MACs/PHYs (Rockchip RK3568, Intel SoC MACs, Renesas, SoC FPGA) that are not emulated in standard virtualized fuzzing environments (QEMU / GCE on amd64). Consequently, the modified code is structurally unreachable.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series adds support for the Synopsys DesignWare Ethernet Physical Coding Sublayer (XPCS) on Rockchip RK3568 SoCs, including a new platform driver (pcs-xpcs-rk), combphy updates, device tree bindings and DTS nodes, and related stmmac/pcs-xpcs plumbing across dwmac-rk, dwmac-intel, dwmac-renesas-gbeth, dwmac-rzn1, and dwmac-socfpga. All modified code resides in drivers for physical SoC platform devices and vendor-specific MACs/PHYs (Rockchip RK3568, Intel SoC MACs, Renesas, SoC FPGA) that are not emulated in standard virtualized fuzzing environments (QEMU / GCE on amd64). Consequently, the modified code is structurally unreachable.",
"WorthFuzzing": false
} |
| 11/1 | 2026/09/07 19:56 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|