| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/22 18:24 | flow | patch-triage |
4mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch series introduces a Rockchip RK3568 XPCS platform driver, updates the Rockchip DWMAC and Combphy drivers, refactors PCS setup across STMMAC platform drivers (including Intel, Renesas, and SoCFPGA), and adjusts auto-negotiation in the Synopsys DW XPCS driver. All modified code is either non-kernel documentation, architecture-specific device trees (arm64), or belongs to drivers for physical SoC platform devices and vendor-specific Ethernet controllers (Rockchip, Renesas, SoCFPGA, Intel DWMAC PCI) that require physical hardware not emulated in standard QEMU/GCE amd64 virtual machines. Consequently, the modified code is structurally unreachable for fuzzing.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/22 18:24 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 98cf1b3cbe99cf2d7987670f9546115a8d91c9e0\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Sep 22 18:24:48 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/net/pcs/rockchip,rk3568-xpcs.yaml b/Documentation/devicetree/bindings/net/pcs/rockchip,rk3568-xpcs.yaml\nnew file mode 100644\nindex 0000000000000..703fcff0e3f70\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/net/pcs/rockchip,rk3568-xpcs.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,rk3568-xpcs.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+ \"^ethernet-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+ ethernet-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+ ethernet-pcs-mii@0 {\n+ reg = \u003c0\u003e;\n+ };\n+ };\ndiff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml\nindex 80c252845349c..bb7540e838033 100644\n--- a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml\n+++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml\n@@ -120,6 +120,12 @@ properties:\n maximum: 0x7F\n default: 0x10\n \n+ pcs-handle:\n+ description:\n+ Specifies a reference to a node representing the PCS device\n+ connected to this GMAC. Required when phy-mode is \"sgmii\".\n+ maxItems: 1\n+\n phy-supply:\n description: PHY regulator\n \n@@ -159,6 +165,18 @@ allOf:\n clocks:\n minItems: 5\n \n+ - if:\n+ properties:\n+ compatible:\n+ contains:\n+ const: rockchip,rk3568-gmac\n+ phy-mode:\n+ contains:\n+ const: sgmii\n+ then:\n+ required:\n+ - pcs-handle\n+\n unevaluatedProperties: false\n \n examples:\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 cc3cae2e378b3..085589b8ba65e 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -23740,6 +23740,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,rk3568-xpcs.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..fdaa4a2a4328b 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@@ -241,6 +242,7 @@ \u0026combphy1 {\n };\n \n \u0026combphy2 {\n+\trockchip,sgmii-mac-sel = \u003c0\u003e;\n \tstatus = \"okay\";\n };\n \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\u0026clk_gmac0_xpcs_mii\u003e;\n+\tmanaged = \"in-band-status\";\n+\tpcs-handle = \u003c\u0026xpcs_mii0\u003e;\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+\tphys = \u003c\u0026combphy2 PHY_TYPE_SGMII\u003e;\n+\tphy-names = \"serdes\";\n+\tstatus = \"okay\";\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..227d03e336043 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: ethernet-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: ethernet-pcs-mii@0 {\n+\t\t\treg = \u003c0\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\n+\t\txpcs_mii1: ethernet-pcs-mii@1 {\n+\t\t\treg = \u003c1\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\n+\t\txpcs_mii2: ethernet-pcs-mii@2 {\n+\t\t\treg = \u003c2\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\n+\t\txpcs_mii3: ethernet-pcs-mii@3 {\n+\t\t\treg = \u003c3\u003e;\n+\t\t\tstatus = \"disabled\";\n+\t\t};\n+\t};\n+\n+\tclk_gmac0_xpcs_mii: clock-xpcs-gmac0 {\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+\tclk_gmac1_xpcs_mii: clock-xpcs-gmac1 {\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..4308dccbf2570 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;\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..88f09014e3a69 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@@ -836,6 +842,16 @@ static int rk3568_init(struct rk_priv_data *bsp_priv)\n \t}\n }\n \n+static void rk3568_set_to_rmii(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_RMII_RGMII);\n+}\n+\n static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,\n \t\t\t\tint tx_delay, int rx_delay)\n {\n@@ -851,19 +867,31 @@ 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_rmii = rk3568_set_to_rmii,\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-\n \t.regs_valid = true,\n \t.regs = {\n \t\t0xfe2a0000, /* gmac0 */\n@@ -1208,6 +1236,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 +1395,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 +1427,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 +1449,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 +1472,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 +1481,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 +1517,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 +1538,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@@ -1602,6 +1681,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..7396b68899c66 100644\n--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c\n+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c\n@@ -426,35 +426,14 @@ 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+\t\treturn dev_err_probe(priv-\u003edevice, ret, \"Failed to initialize PCS\\n\");\n \n \treturn 0;\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..5382afcf95748 100644\n--- a/drivers/net/pcs/Kconfig\n+++ b/drivers/net/pcs/Kconfig\n@@ -12,6 +12,31 @@ 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+\tselect GENERIC_PHY\n+\tselect PM_GENERIC_DOMAINS if PM\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..91e76733267e0\n--- /dev/null\n+++ b/drivers/net/pcs/pcs-xpcs-rk.c\n@@ -0,0 +1,599 @@\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/math.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+#include \u003clinux/time.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+\tu8 eee_mult_fact;\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/*\n+\t * Reads are redirected by hardware to the port's read-only mirror;\n+\t * only writes have to be targeted at MII (see the write path).\n+\t */\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/*\n+\t * These registers physically live only in MII (the management port).\n+\t * Ports 1-3 expose read-only mirrors of these bits, so writes must\n+\t * always target MII; the read path remaps per address and the\n+\t * hardware redirects to the port's mirror.\n+\t */\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+\tpm_runtime_force_suspend(dev);\n+\tclk_disable_unprepare(pxpcs-\u003eeee_clk);\n+}\n+\n+static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)\n+{\n+\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n+\tunsigned long rate;\n+\tu64 mult;\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+\t/*\n+\t * Compute the multiplier for the EEE clock so that\n+\t * clk_eee_period * (mult_fact + 1) falls within 80..120 ns.\n+\t *\n+\t * On RK3568, clk_xpcs_eee is muxed between gpll200 (200 MHz, 5 ns)\n+\t * and cpll125 (125 MHz, 8 ns), selected by CRU_CLKSEL_CON29 bit 13.\n+\t * The reset value is 0 (200 MHz), but derive the value at runtime to\n+\t * stay correct if the mux is changed by a board.\n+\t *\n+\t * Use a 64-bit intermediate: on 32-bit builds, 100 * 200000000\n+\t * does not fit in unsigned long. Clamp to the 4-bit\n+\t * DW_VR_MII_EEE_MULT_FACT_100NS field. The mux only provides\n+\t * 125 MHz or 200 MHz, so the rate cannot drop below the 5 MHz\n+\t * threshold where DIV_ROUND_CLOSEST_ULL() would return 0 and the\n+\t * subtraction below would underflow.\n+\t */\n+\trate = clk_get_rate(pxpcs-\u003eeee_clk);\n+\tif (!rate)\n+\t\treturn dev_err_probe(dev, -EINVAL, \"Invalid EEE clock rate\\n\");\n+\n+\tmult = DIV_ROUND_CLOSEST_ULL(100ULL * rate, NSEC_PER_SEC) - 1;\n+\tpxpcs-\u003eeee_mult_fact = min_t(u64, mult, 15);\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 device_link *link;\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+\t/*\n+\t * Establish the device link before reading the supplier's drvdata.\n+\t * device_link_add() does not fail on a supplier that is unbinding:\n+\t * it creates the link in DL_STATE_SUPPLIER_UNBIND. Whether the link\n+\t * actually protects the drvdata depends on the supplier's state at\n+\t * creation time.\n+\t *\n+\t * Check link-\u003esupplier-\u003elinks.status right after creation. If the\n+\t * supplier was DL_DEV_DRIVER_BOUND, the link is in\n+\t * DL_STATE_CONSUMER_PROBE and device_links_unbind_consumers() will\n+\t * wait for this probe to finish before unbinding the supplier, so\n+\t * the drvdata stays valid for the rest of the function. Any other\n+\t * state means the supplier is not usable yet; defer and retry.\n+\t *\n+\t * The link is released automatically when the consumer device is\n+\t * destroyed (DL_FLAG_AUTOREMOVE_CONSUMER), so no explicit\n+\t * device_link_remove() is needed on the failure paths.\n+\t */\n+\tlink = device_link_add(dev, \u0026pdev-\u003edev, DL_FLAG_AUTOREMOVE_CONSUMER);\n+\tif (!link) {\n+\t\tput_device(\u0026pdev-\u003edev);\n+\t\treturn ERR_PTR(-EPROBE_DEFER);\n+\t}\n+\n+\tif (READ_ONCE(link-\u003esupplier-\u003elinks.status) != DL_DEV_DRIVER_BOUND) {\n+\t\tput_device(\u0026pdev-\u003edev);\n+\t\treturn ERR_PTR(-EPROBE_DEFER);\n+\t}\n+\n+\tpxpcs = platform_get_drvdata(pdev);\n+\tif (!pxpcs || !pxpcs-\u003ebus) {\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+\tif (IS_ERR(xpcs)) {\n+\t\tput_device(\u0026pdev-\u003edev);\n+\t\treturn xpcs;\n+\t}\n+\n+\txpcs_config_eee_mult_fact(xpcs, pxpcs-\u003eeee_mult_fact);\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..8c3875b6985b9 100644\n--- a/drivers/net/pcs/pcs-xpcs.c\n+++ b/drivers/net/pcs/pcs-xpcs.c\n@@ -761,7 +761,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,\n \t * DW xPCS used with DW EQoS MAC is always MAC side SGMII.\n \t * 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic\n \t * speed/duplex mode change by HW after SGMII AN complete)\n-\t * 5) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)\n+\t * 5) VR_MII_AN_INTR_STS = 0x0 (Clear CL37 AN complete status)\n+\t * 6) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)\n+\t * VR_MII_MMD_CTRL Bit(9) [AN_RESTART] = 1b (Restart SGMII AN)\n \t *\n \t * Note that VR_MII_MMD_CTRL is MII_BMCR.\n \t *\n@@ -769,7 +771,14 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,\n \t *\t SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from\n \t *\t PHY about the link state change after C28 AN is completed\n \t *\t between PHY and Link Partner. There is also no need to\n-\t *\t trigger AN restart for MAC-side SGMII.\n+\t *\t trigger AN restart for MAC-side SGMII on most devices.\n+\t *\n+\t * Note: While the DesignWare databook states that AN restart is\n+\t *\t not needed for MAC side SGMII, some implementations (e.g.\n+\t *\t Rockchip RK3568) exhibit a timing quirk when integrated with\n+\t *\t phylink and do not restart AN automatically when the link\n+\t *\t comes back up. An explicit AN restart is required on those\n+\t *\t parts to recover the link after a disconnect.\n \t */\n \tmdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);\n \tif (mdio_ctrl \u003c 0)\n@@ -816,9 +825,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,9 +1107,18 @@ 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-\t\txpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);\n+\tif (state-\u003ean_complete) {\n+\t\t/* Clear AN complete status or interrupt */\n+\t\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\n+\t\t/* Initiate the next round of AN */\n+\t\tret = xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART,\n+\t\t\t\t BMCR_ANRESTART);\n+\t\tif (ret \u003c 0)\n+\t\t\treturn ret;\n+\t}\n \n \treturn 0;\n }\ndiff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c\nindex 7843356a4dd47..7b867e7520064 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\t priv-\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/22 18:24 | agent | patch-evaluator |
4mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series introduces a Rockchip RK3568 XPCS platform driver, updates the Rockchip DWMAC and Combphy drivers, refactors PCS setup across STMMAC platform drivers (including Intel, Renesas, and SoCFPGA), and adjusts auto-negotiation in the Synopsys DW XPCS driver. All modified code is either non-kernel documentation, architecture-specific device trees (arm64), or belongs to drivers for physical SoC platform devices and vendor-specific Ethernet controllers (Rockchip, Renesas, SoCFPGA, Intel DWMAC PCI) that require physical hardware not emulated in standard QEMU/GCE amd64 virtual machines. Consequently, the modified code is structurally unreachable for fuzzing.",
"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 98cf1b3cbe99cf2d7987670f9546115a8d91c9e0
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 22 18:24:48 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/devicetree/bindings/net/pcs/rockchip,rk3568-xpcs.yaml b/Documentation/devicetree/bindings/net/pcs/rockchip,rk3568-xpcs.yaml
new file mode 100644
index 0000000000000..703fcff0e3f70
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/pcs/rockchip,rk3568-xpcs.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,rk3568-xpcs.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:
+ "^ethernet-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>
+
+ ethernet-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>;
+
+ ethernet-pcs-mii@0 {
+ reg = <0>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
index 80c252845349c..bb7540e838033 100644
--- a/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/rockchip-dwmac.yaml
@@ -120,6 +120,12 @@ properties:
maximum: 0x7F
default: 0x10
+ pcs-handle:
+ description:
+ Specifies a reference to a node representing the PCS device
+ connected to this GMAC. Required when phy-mode is "sgmii".
+ maxItems: 1
+
phy-supply:
description: PHY regulator
@@ -159,6 +165,18 @@ allOf:
clocks:
minItems: 5
+ - if:
+ properties:
+ compatible:
+ contains:
+ const: rockchip,rk3568-gmac
+ phy-mode:
+ contains:
+ const: sgmii
+ then:
+ required:
+ - pcs-handle
+
unevaluatedProperties: false
examples:
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 cc3cae2e378b3..085589b8ba65e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23740,6 +23740,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,rk3568-xpcs.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..fdaa4a2a4328b 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"
@@ -241,6 +242,7 @@ &combphy1 {
};
&combphy2 {
+ rockchip,sgmii-mac-sel = <0>;
status = "okay";
};
@@ -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 = <&clk_gmac0_xpcs_mii>;
+ managed = "in-band-status";
+ pcs-handle = <&xpcs_mii0>;
+ 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 {
+ phys = <&combphy2 PHY_TYPE_SGMII>;
+ phy-names = "serdes";
+ status = "okay";
+};
+
+&xpcs_mii0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi
index 3bc653f027f1f..227d03e336043 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: ethernet-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: ethernet-pcs-mii@0 {
+ reg = <0>;
+ status = "disabled";
+ };
+
+ xpcs_mii1: ethernet-pcs-mii@1 {
+ reg = <1>;
+ status = "disabled";
+ };
+
+ xpcs_mii2: ethernet-pcs-mii@2 {
+ reg = <2>;
+ status = "disabled";
+ };
+
+ xpcs_mii3: ethernet-pcs-mii@3 {
+ reg = <3>;
+ status = "disabled";
+ };
+ };
+
+ clk_gmac0_xpcs_mii: clock-xpcs-gmac0 {
+ compatible = "fixed-clock";
+ clock-frequency = <125000000>;
+ clock-output-names = "clk_gmac0_xpcs_mii";
+ #clock-cells = <0>;
+ };
+
+ clk_gmac1_xpcs_mii: clock-xpcs-gmac1 {
+ 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..4308dccbf2570 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;
+ 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..88f09014e3a69 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)
@@ -836,6 +842,16 @@ static int rk3568_init(struct rk_priv_data *bsp_priv)
}
}
+static void rk3568_set_to_rmii(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_RMII_RGMII);
+}
+
static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv,
int tx_delay, int rx_delay)
{
@@ -851,19 +867,31 @@ 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_rmii = rk3568_set_to_rmii,
.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,
-
.regs_valid = true,
.regs = {
0xfe2a0000, /* gmac0 */
@@ -1208,6 +1236,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 +1395,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 +1427,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 +1449,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 +1472,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 +1481,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 +1517,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 +1538,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)
@@ -1602,6 +1681,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..7396b68899c66 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -426,35 +426,14 @@ 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 dev_err_probe(priv->device, ret, "Failed to initialize PCS\n");
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..5382afcf95748 100644
--- a/drivers/net/pcs/Kconfig
+++ b/drivers/net/pcs/Kconfig
@@ -12,6 +12,31 @@ 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)
+ select GENERIC_PHY
+ select PM_GENERIC_DOMAINS if PM
+ 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..91e76733267e0
--- /dev/null
+++ b/drivers/net/pcs/pcs-xpcs-rk.c
@@ -0,0 +1,599 @@
+// 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/math.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 <linux/time.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;
+ u8 eee_mult_fact;
+};
+
+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;
+ }
+
+ /*
+ * Reads are redirected by hardware to the port's read-only mirror;
+ * only writes have to be targeted at MII (see the write path).
+ */
+ 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;
+ }
+
+ /*
+ * These registers physically live only in MII (the management port).
+ * Ports 1-3 expose read-only mirrors of these bits, so writes must
+ * always target MII; the read path remaps per address and the
+ * hardware redirects to the port's mirror.
+ */
+ 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;
+
+ pm_runtime_force_suspend(dev);
+ clk_disable_unprepare(pxpcs->eee_clk);
+}
+
+static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)
+{
+ struct device *dev = &pxpcs->pdev->dev;
+ unsigned long rate;
+ u64 mult;
+ 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;
+ }
+
+ /*
+ * Compute the multiplier for the EEE clock so that
+ * clk_eee_period * (mult_fact + 1) falls within 80..120 ns.
+ *
+ * On RK3568, clk_xpcs_eee is muxed between gpll200 (200 MHz, 5 ns)
+ * and cpll125 (125 MHz, 8 ns), selected by CRU_CLKSEL_CON29 bit 13.
+ * The reset value is 0 (200 MHz), but derive the value at runtime to
+ * stay correct if the mux is changed by a board.
+ *
+ * Use a 64-bit intermediate: on 32-bit builds, 100 * 200000000
+ * does not fit in unsigned long. Clamp to the 4-bit
+ * DW_VR_MII_EEE_MULT_FACT_100NS field. The mux only provides
+ * 125 MHz or 200 MHz, so the rate cannot drop below the 5 MHz
+ * threshold where DIV_ROUND_CLOSEST_ULL() would return 0 and the
+ * subtraction below would underflow.
+ */
+ rate = clk_get_rate(pxpcs->eee_clk);
+ if (!rate)
+ return dev_err_probe(dev, -EINVAL, "Invalid EEE clock rate\n");
+
+ mult = DIV_ROUND_CLOSEST_ULL(100ULL * rate, NSEC_PER_SEC) - 1;
+ pxpcs->eee_mult_fact = min_t(u64, mult, 15);
+ 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 device_link *link;
+ 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);
+
+ /*
+ * Establish the device link before reading the supplier's drvdata.
+ * device_link_add() does not fail on a supplier that is unbinding:
+ * it creates the link in DL_STATE_SUPPLIER_UNBIND. Whether the link
+ * actually protects the drvdata depends on the supplier's state at
+ * creation time.
+ *
+ * Check link->supplier->links.status right after creation. If the
+ * supplier was DL_DEV_DRIVER_BOUND, the link is in
+ * DL_STATE_CONSUMER_PROBE and device_links_unbind_consumers() will
+ * wait for this probe to finish before unbinding the supplier, so
+ * the drvdata stays valid for the rest of the function. Any other
+ * state means the supplier is not usable yet; defer and retry.
+ *
+ * The link is released automatically when the consumer device is
+ * destroyed (DL_FLAG_AUTOREMOVE_CONSUMER), so no explicit
+ * device_link_remove() is needed on the failure paths.
+ */
+ link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!link) {
+ put_device(&pdev->dev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ if (READ_ONCE(link->supplier->links.status) != DL_DEV_DRIVER_BOUND) {
+ put_device(&pdev->dev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ pxpcs = platform_get_drvdata(pdev);
+ if (!pxpcs || !pxpcs->bus) {
+ put_device(&pdev->dev);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ xpcs = xpcs_create_mdiodev(pxpcs->bus, (int)port);
+ if (IS_ERR(xpcs)) {
+ put_device(&pdev->dev);
+ return xpcs;
+ }
+
+ xpcs_config_eee_mult_fact(xpcs, pxpcs->eee_mult_fact);
+ 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..8c3875b6985b9 100644
--- a/drivers/net/pcs/pcs-xpcs.c
+++ b/drivers/net/pcs/pcs-xpcs.c
@@ -761,7 +761,9 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
* DW xPCS used with DW EQoS MAC is always MAC side SGMII.
* 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
* speed/duplex mode change by HW after SGMII AN complete)
- * 5) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)
+ * 5) VR_MII_AN_INTR_STS = 0x0 (Clear CL37 AN complete status)
+ * 6) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)
+ * VR_MII_MMD_CTRL Bit(9) [AN_RESTART] = 1b (Restart SGMII AN)
*
* Note that VR_MII_MMD_CTRL is MII_BMCR.
*
@@ -769,7 +771,14 @@ static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
* SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from
* PHY about the link state change after C28 AN is completed
* between PHY and Link Partner. There is also no need to
- * trigger AN restart for MAC-side SGMII.
+ * trigger AN restart for MAC-side SGMII on most devices.
+ *
+ * Note: While the DesignWare databook states that AN restart is
+ * not needed for MAC side SGMII, some implementations (e.g.
+ * Rockchip RK3568) exhibit a timing quirk when integrated with
+ * phylink and do not restart AN automatically when the link
+ * comes back up. An explicit AN restart is required on those
+ * parts to recover the link after a disconnect.
*/
mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
if (mdio_ctrl < 0)
@@ -816,9 +825,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,9 +1107,18 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
return 0;
}
- /* Clear AN complete status or interrupt */
- if (state->an_complete)
- xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+ if (state->an_complete) {
+ /* Clear AN complete status or interrupt */
+ ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+ if (ret < 0)
+ return ret;
+
+ /* Initiate the next round of AN */
+ ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART,
+ BMCR_ANRESTART);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 7843356a4dd47..7b867e7520064 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/22 18:24 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 23334 output: 25 thoughts: 985 Thoughts: **Analyzing the Patch Series for Fuzzing Reachability** Okay, let's dive into this patch series. My initial thought is to figure out if this code is even *reachable* in a standard fuzzing environment, given the target architecture is amd64. First, I need to understand the scope of the changes. I see a lot of Device Tree bindings (rockchip, PHYs), some MAINTAINERS updates, and a sprinkling of ARM64 DTS files. More importantly, I'm spotting changes in the `drivers/net/ethernet/stmicro/stmmac/` directory and `drivers/net/pcs/` directory, along with a PHY driver. I immediately need to investigate the *reachability* of these drivers under amd64, considering they seem to primarily support Rockchip SoCs and potentially other hardware specific to embedded systems. My concern flares: are things like `dwmac-intel.c`, `stmmac_mdio.c`, `pcs-xpcs.c` relevant to amd64, especially in the fuzzing context? This becomes my primary concern. I need to know if these are even executed in a standard QEMU or GCE environment or if these drivers rely on physical hardware or specialized PCI devices that aren't emulated. I remember the fuzzing guidelines state clearly: "Fuzzing can only discover bugs in code that can actually execute in standard virtualized environments... If the modified code is structurally unreachable... it MUST NOT be fuzzed." Then, I recall the examples of "structurally unreachable hardware": vendor-specific PCIe switches, SmartNICs, GPU drivers requiring physical cards, and code paths exclusive to architectures other than the target architecture. This has now become my priority. I need to understand what this code *does*. So, I'll need to dig into the drivers themselves: `dwmac-intel.c`, `stmmac_mdio.c`, `pcs-xpcs.c`, and other relevant files in the patch. I'll search the kernel source tree for all stmmac drivers and how they're used. I need to verify how `stmmac` or `dwmac-intel` or `dw_xpcs` are instantiated. Does QEMU emulate the stmmac or dwmac-intel devices? I'm going to look for any PCI IDs that `dwmac-intel` might bind to. And specifically, where is `stmmac_pcs_setup` called in `stmmac_mdio.c`? My gut tells me this is going to be the lynchpin. Ultimately, the question is: is this code reachable in my fuzzing environment? If not, the fuzzing task is off the table. |
| 4/2 | 2026/09/22 18:25 | tool | grepper |
0mArgs:{
"Expression": "INTEL_MGBE_XPCS_ADDR"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=650=static int intel_mgbe_common_data(struct pci_dev *pdev,\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-767-\t plat-\u003ephy_interface == PHY_INTERFACE_MODE_1000BASEX) {\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:768:\t\tplat-\u003emdio_bus_data-\u003epcs_mask = BIT_U32(INTEL_MGBE_XPCS_ADDR);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-769-\t\tplat-\u003edefault_an_inband = true;\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-776-\tplat-\u003emdio_bus_data-\u003ephy_mask = 1 \u003c\u003c INTEL_MGBE_ADHOC_ADDR;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:777:\tplat-\u003emdio_bus_data-\u003ephy_mask |= 1 \u003c\u003c INTEL_MGBE_XPCS_ADDR;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-778-\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.h-36-#define INTEL_MGBE_ADHOC_ADDR\t0x15\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.h:37:#define INTEL_MGBE_XPCS_ADDR\t0x16\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.h-38-\n"
} |
| 5/2 | 2026/09/22 18:25 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 25375 output: 46 thoughts: 67 Thoughts: Okay, let's dive into this. **Examining `dwmac-intel.c`** Alright, my first thought is to understand the scope of `dwmac-intel.c`. I need to figure out what it's responsible for. Is this a PCI driver? My initial check confirms that. I see `struct pci_dev *pdev` in the code, which is a key indicator. Now, I need to know exactly *which* PCI devices this driver supports. My next step will be a deep dive into `dwmac-intel.c` to identify the supported device IDs and any associated configuration specifics. Let's get to it. |
| 6/2 | 2026/09/22 18:25 | tool | grepper |
0mArgs:{
"Expression": "pci_device_id",
"PathPrefix": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=1299=static int intel_eth_pci_probe(struct pci_dev *pdev,\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:1300:\t\t\t const struct pci_device_id *id)\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1301-{\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c=1398=static void intel_eth_pci_remove(struct pci_dev *pdev)\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1430-\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:1431:static const struct pci_device_id intel_eth_pci_id_table[] = {\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-1432-\t{ PCI_DEVICE_DATA(INTEL, QUARK, \u0026quark_info) },\n"
} |
| 7/2 | 2026/09/22 18:25 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 25929 output: 49 thoughts: 37 Thoughts: Here's my analysis of what I'm looking at, from a technical perspective: **Investigating Network Card Identification and Driver Configuration** Okay, first things first, I need to understand how the system identifies the Intel Ethernet PCI devices. My initial thought is to dive into the `intel_eth_pci_id_table` to get a handle on the PCI IDs used. Knowing these IDs is crucial; they're the fingerprints the driver uses to recognize the hardware. Next, I'll need to see how these IDs are used within the driver's code. Line 1431 in `dwmac-intel.c` is a pretty good place to start. I'm expecting to find the device ID matching logic or the driver probe function, or something else that will help me understand how the driver initializes. Looking at the surrounding code will likely provide additional context. I need to trace the flow from device identification to driver initialization, and then to configuration. |
| 8/2 | 2026/09/22 18:25 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c",
"FirstLine": 1430,
"LineCount": 50
}Results: {
"Contents": "1430:\t\n1431:\tstatic const struct pci_device_id intel_eth_pci_id_table[] = {\n1432:\t\t{ PCI_DEVICE_DATA(INTEL, QUARK, \u0026quark_info) },\n1433:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_RGMII1G, \u0026ehl_rgmii1g_info) },\n1434:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_SGMII1G, \u0026ehl_sgmii1g_info) },\n1435:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_SGMII2G5, \u0026ehl_sgmii1g_info) },\n1436:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_PSE0_RGMII1G, \u0026ehl_pse0_rgmii1g_info) },\n1437:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_PSE0_SGMII1G, \u0026ehl_pse0_sgmii1g_info) },\n1438:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_PSE0_SGMII2G5, \u0026ehl_pse0_sgmii1g_info) },\n1439:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_PSE1_RGMII1G, \u0026ehl_pse1_rgmii1g_info) },\n1440:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_PSE1_SGMII1G, \u0026ehl_pse1_sgmii1g_info) },\n1441:\t\t{ PCI_DEVICE_DATA(INTEL, EHL_PSE1_SGMII2G5, \u0026ehl_pse1_sgmii1g_info) },\n1442:\t\t{ PCI_DEVICE_DATA(INTEL, TGL_SGMII1G, \u0026tgl_sgmii1g_phy0_info) },\n1443:\t\t{ PCI_DEVICE_DATA(INTEL, TGLH_SGMII1G_0, \u0026tgl_sgmii1g_phy0_info) },\n1444:\t\t{ PCI_DEVICE_DATA(INTEL, TGLH_SGMII1G_1, \u0026tgl_sgmii1g_phy1_info) },\n1445:\t\t{ PCI_DEVICE_DATA(INTEL, ADLS_SGMII1G_0, \u0026adls_sgmii1g_phy0_info) },\n1446:\t\t{ PCI_DEVICE_DATA(INTEL, ADLS_SGMII1G_1, \u0026adls_sgmii1g_phy1_info) },\n1447:\t\t{ PCI_DEVICE_DATA(INTEL, ADLN_SGMII1G, \u0026adln_sgmii1g_phy0_info) },\n1448:\t\t{ PCI_DEVICE_DATA(INTEL, RPLP_SGMII1G, \u0026adln_sgmii1g_phy0_info) },\n1449:\t\t{}\n1450:\t};\n1451:\tMODULE_DEVICE_TABLE(pci, intel_eth_pci_id_table);\n1452:\t\n1453:\tstatic struct pci_driver intel_eth_pci_driver = {\n1454:\t\t.name = \"intel-eth-pci\",\n1455:\t\t.id_table = intel_eth_pci_id_table,\n1456:\t\t.probe = intel_eth_pci_probe,\n1457:\t\t.remove = intel_eth_pci_remove,\n1458:\t\t.driver = {\n1459:\t\t\t.pm = \u0026stmmac_simple_pm_ops,\n1460:\t\t},\n1461:\t};\n1462:\t\n1463:\tmodule_pci_driver(intel_eth_pci_driver);\n1464:\t\n1465:\tMODULE_DESCRIPTION(\"INTEL 10/100/1000 Ethernet PCI driver\");\n1466:\tMODULE_AUTHOR(\"Voon Weifeng \u003cweifeng.voon@intel.com\u003e\");\n1467:\tMODULE_LICENSE(\"GPL v2\");\n"
} |
| 9/2 | 2026/09/22 18:25 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 27272 output: 49 thoughts: 300 Thoughts: **My Initial Assessment of the Ethernet Controllers** Okay, so I'm looking at these Ethernet controllers – Intel Quark, Elkhart Lake, Tiger Lake, Alder Lake, all using the DW MAC. My initial thought is, these aren't the typical QEMU or Google Compute Engine devices I'm used to. QEMU generally uses emulated devices like e1000, e1000e, igb, vmxnet3, virtio-net, rtl8139, pcnet – nothing like this specific Intel Elkhart Lake DWMAC. Hmm... wait a minute, let's not jump to conclusions. I need to be thorough. Let's carefully examine the context – I'll check every single modified file. First up: 1. `Documentation/...` – Okay, documentation, not directly relevant to *this* particular issue. 2. `MAINTAINERS` – Non-executable, information only. Moving on... 3. `arch/arm64/boot/dts/rockchip/...` – ARM64 DTS, not compiled on AMD64, and anyway, it's specific to Rockchip boards. Irrelevant. 4. `drivers/net/ethernet/stmicro/stmmac/Kconfig` – Configuration file, so potentially relevant, I'll keep that in mind. 5. `drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c` – This one's interesting, Intel Quark/EHL/TGL/ADL PCI driver, sounds like the one. 6. `drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c` – Renesas platform driver – ARM/ARM64 / R-Car / RZ/G, also not quite what I am looking for. I'm starting to zero in now, I'm going to take a closer look at that `dwmac-renesas-gbeth.c` file. |
| 10/2 | 2026/09/22 18:25 | tool | grepper |
0mArgs:{
"Expression": "module_platform_driver",
"PathPrefix": "drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c=227=static struct platform_driver renesas_gbeth_driver = {\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c-234-};\ndrivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c:235:module_platform_driver(renesas_gbeth_driver);\ndrivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c-236-\n"
} |
| 11/2 | 2026/09/22 18:25 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 28226 output: 21 thoughts: 226 Thoughts: **Analyzing Recent Changes in the STMMAC Driver Ecosystem** Okay, let's take a look at what's been happening in the `stmmac` driver landscape. I see a few files that are clearly relevant: `dwmac-rk.c` for Rockchip SoCs, `dwmac-rzn1.c` for Renesas RZ/N1, and `dwmac-socfpga.c` which handles Altera/Intel SoCFPGA on ARM/ARM64. The helper file, `stmmac_mdio.c`, is always a point of interest for shared functionality. My immediate focus, however, is on that `stmmac_mdio.c` file. Specifically, I'm drawn to changes in `stmmac_pcs_setup()` and `stmmac_pcs_clean()`. These functions are critical for Physical Coding Sublayer (PCS) configuration and cleanup, so changes here likely indicate something significant in how the drivers interact with the PHY. Now, the next logical question to answer here: Who is using those functions? I need to understand the call structure to evaluate the scope of these changes. Time to whip out grepper and get a full picture of the call sites. |
| 12/2 | 2026/09/22 18:25 | tool | grepper |
0mArgs:{
"Expression": "stmmac_pcs_setup"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/stmmac.h=399=void stmmac_mdio_unlock(struct stmmac_priv *priv);\ndrivers/net/ethernet/stmicro/stmmac/stmmac.h:400:int stmmac_pcs_setup(struct net_device *ndev);\ndrivers/net/ethernet/stmicro/stmmac/stmmac.h-401-void stmmac_pcs_clean(struct net_device *ndev);\n--\ndrivers/net/ethernet/stmicro/stmmac/stmmac_main.c=7816=static int __stmmac_dvr_probe(struct device *device,\n--\ndrivers/net/ethernet/stmicro/stmmac/stmmac_main.c-8065-\ndrivers/net/ethernet/stmicro/stmmac/stmmac_main.c:8066:\tret = stmmac_pcs_setup(ndev);\ndrivers/net/ethernet/stmicro/stmmac/stmmac_main.c-8067-\tif (ret)\n--\ndrivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c=381=int stmmac_mdio_reset(struct mii_bus *bus)\n--\ndrivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c-425-\ndrivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c:426:int stmmac_pcs_setup(struct net_device *ndev)\ndrivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c-427-{\n"
} |
| 13/2 | 2026/09/22 18:25 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 29179 output: 19 thoughts: 548 Thoughts: **Analyzing Recent Changes: Focus on XPCS Drivers** Okay, let's break down these changes. It looks like we've got updates to `drivers/net/pcs/Kconfig`, `drivers/net/pcs/Makefile`, and the addition of two new XPCS drivers: one for Rockchip's XPCS (`rockchip,rk3568-xpcs`) and another using Synopsys DesignWare technology. Good, always interesting to see new hardware support. My interest is immediately piqued by the modifications to `pcs-xpcs.c`. Let's dig into that code. It appears the changes are focused around handling Clause 37 (C37) auto-negotiation, particularly for SGMII. Specifically, I see code to clear the AN complete status, and initiate auto-negotiation. It also looks like they are clearing AN complete status or interrupt, and then initiating the next round of AN. That suggests a retry mechanism or a specific handling of AN completion. Now I have to figure out the context of those methods. And there's also an update to `drivers/phy/rockchip/phy-rockchip-naneng-combphy.c`, a Rockchip SoC combphy driver. Intriguing. Since I'm curious about the dependency, now I need to figure out who is using `pcs-xpcs.c`. I'll run a quick search through the kernel sources for any references to `xpcs_` or `pcs-xpcs` to understand the drivers, and figure out how these pieces fit together. |
| 14/2 | 2026/09/22 18:26 | 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=481=struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np)\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-553-\ndrivers/net/pcs/pcs-xpcs-rk.c:554:\txpcs = xpcs_create_mdiodev(pxpcs-\u003ebus, (int)port);\ndrivers/net/pcs/pcs-xpcs-rk.c-555-\tif (IS_ERR(xpcs)) {\n--\ndrivers/net/pcs/pcs-xpcs.c=1512=static int xpcs_identify(struct dw_xpcs *xpcs)\n--\ndrivers/net/pcs/pcs-xpcs.c-1531-\ndrivers/net/pcs/pcs-xpcs.c:1532:static struct dw_xpcs *xpcs_create_data(struct mdio_device *mdiodev)\ndrivers/net/pcs/pcs-xpcs.c-1533-{\n--\ndrivers/net/pcs/pcs-xpcs.c=1599=static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev)\n--\ndrivers/net/pcs/pcs-xpcs.c-1603-\ndrivers/net/pcs/pcs-xpcs.c:1604:\txpcs = xpcs_create_data(mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1605-\tif (IS_ERR(xpcs))\n--\ndrivers/net/pcs/pcs-xpcs.c-1635-/**\ndrivers/net/pcs/pcs-xpcs.c:1636: * xpcs_create_mdiodev() - create a DW xPCS instance with the MDIO @addr\ndrivers/net/pcs/pcs-xpcs.c-1637- * @bus: pointer to the MDIO-bus descriptor for the device to be looked at\n--\ndrivers/net/pcs/pcs-xpcs.c-1643- */\ndrivers/net/pcs/pcs-xpcs.c:1644:struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr)\ndrivers/net/pcs/pcs-xpcs.c-1645-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1664-}\ndrivers/net/pcs/pcs-xpcs.c:1665:EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1666-\ndrivers/net/pcs/pcs-xpcs.c:1667:struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr)\ndrivers/net/pcs/pcs-xpcs.c-1668-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1670-\ndrivers/net/pcs/pcs-xpcs.c:1671:\txpcs = xpcs_create_mdiodev(bus, addr);\ndrivers/net/pcs/pcs-xpcs.c-1672-\tif (IS_ERR(xpcs))\n--\ndrivers/net/pcs/pcs-xpcs.c-1676-}\ndrivers/net/pcs/pcs-xpcs.c:1677:EXPORT_SYMBOL_GPL(xpcs_create_pcs_mdiodev);\ndrivers/net/pcs/pcs-xpcs.c-1678-\ndrivers/net/pcs/pcs-xpcs.c-1679-/**\ndrivers/net/pcs/pcs-xpcs.c:1680: * xpcs_create_fwnode() - Create a DW xPCS instance from @fwnode\ndrivers/net/pcs/pcs-xpcs.c-1681- * @fwnode: fwnode handle poining to the DW XPCS device\n--\ndrivers/net/pcs/pcs-xpcs.c-1688- */\ndrivers/net/pcs/pcs-xpcs.c:1689:struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode)\ndrivers/net/pcs/pcs-xpcs.c-1690-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1712-}\ndrivers/net/pcs/pcs-xpcs.c:1713:EXPORT_SYMBOL_GPL(xpcs_create_fwnode);\ndrivers/net/pcs/pcs-xpcs.c-1714-\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"
} |
| 15/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 32448 output: 28 thoughts: 528 Thoughts: **Investigating `dw_xpcs` Driver Usage and QEMU Compatibility** Okay, so I'm looking at this `dw_xpcs` function and where it's used. Right off the bat, I see a list of drivers that utilize it: Microchip, NXP, Meta, Intel, Wangxun, and Rockchip. That's a pretty diverse set of hardware, and my initial thought is, "Can any of these actually be meaningfully tested or interacted with in a standard QEMU environment on x86_64?" Well, based on my understanding of how QEMU does its thing, none of these seem to have a readily available QEMU emulation. Let's recap what these chips *are*: SPI/I2C hardware switches, automotive Ethernet switches, PCIe NICs (like the Facebook ASIC and Wangxun), and SoC MACs. I know QEMU doesn't directly emulate these particular hardware configurations as part of its standard x86 or ARM/RISC-V PC emulation. Wait a second, what about the `stmmac` family of drivers? They're used in the Intel SoC and the Rockchip SoC. Are those ever *emulated* in QEMU, specifically on x86_64 (PC/Q35)? Nope! QEMU's got `dwc-eqos` for *other* architectures, ARM/RISC-V boards. But not for the standard x86 PC emulation. That makes sense. We've got standard QEMU devices like e1000, rtl8139, virtio-net for x86 platforms. So, let me check again: does QEMU x86 have any `stmmac` or `dwmac` device? No! Nothing there. And just to be completely thorough, let's look for any kind of virtual bus or software-emulated device or even mock devices that might use `XPCS` or `stmmac`, or the related `combphy` drivers. Also, let's hunt down other callers or users of `dw_xpcs` or the specific `xpcs_config_aneg_c37_sgmii` function. |
| 16/2 | 2026/09/22 18:26 | tool | grepper |
0mArgs:{
"Expression": "xpcs_config_aneg_c37_sgmii"
}Results: {
"Output": "drivers/net/pcs/pcs-xpcs.c=721=static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface)\n--\ndrivers/net/pcs/pcs-xpcs.c-749-\ndrivers/net/pcs/pcs-xpcs.c:750:static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-751-\t\t\t\t unsigned int neg_mode)\n--\ndrivers/net/pcs/pcs-xpcs.c=925=static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,\n--\ndrivers/net/pcs/pcs-xpcs.c-956-\tcase DW_AN_C37_SGMII:\ndrivers/net/pcs/pcs-xpcs.c:957:\t\tret = xpcs_config_aneg_c37_sgmii(xpcs, neg_mode);\ndrivers/net/pcs/pcs-xpcs.c-958-\t\tif (ret)\n"
} |
| 17/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 33769 output: 32 thoughts: 1722 Thoughts: **WorthFuzzing=false: Deep Dive into a Rockchip XPCS Patch** Okay, let's break this down. First, I need to understand where `xpcs_do_config` and `xpcs_get_state_c37_sgmii` fit into the larger picture. It looks like they're related to phylink operations, specifically the `.pcs_config` and `.pcs_get_state` callbacks. Now, what does this patch actually *do*? The commit message is unhelpful, so let's dig into the diffs. From the changes, it's clear we're dealing with Rockchip hardware, specifically an RK3568. The patch introduces new device tree bindings, a `MAINTAINERS` entry, Kconfig options, and new driver files. It's also touching existing drivers like `dwmac-rk.c` and `phy-rockchip-naneng-combphy.c` to add SGMII support for the RK3568. Furthermore, `stmmac` is being refactored to move PCS creation into platform drivers. The key question is: does any of this code path lead to a "WorthFuzzing=true" situation? According to the instructions, I need to identify if any modified code falls strictly into the "WorthFuzzing=false" categories. The target architecture is amd64. Let's carefully examine each modified file: 1. **Documentation:** The DT bindings modifications are purely documentation and don't affect the compiled kernel logic. WorthFuzzing=false 2. **MAINTAINERS:** This is a non-executable file. WorthFuzzing=false 3. **DTS Files (rk3568.dtsi, rk3568-photonicat.dts):** These are ARM64 device tree files, and the target is amd64. WorthFuzzing=false 4. **`pcs-xpcs-rk.c` (Rockchip XPCS Platform Driver):** This driver is specific to Rockchip ARM64 SoCs, triggered by a compatible string, `rockchip,rk3568-xpcs`. It is structurally unreachable on the amd64 architecture. WorthFuzzing=false 5. **`dwmac-rk.c` (Rockchip GMAC Driver):** This driver is also specific to Rockchip SoCs and is structurally unreachable, because it requires Rockchip hardware. WorthFuzzing=false 6. **`phy-rockchip-naneng-combphy.c` (Rockchip Combphy Driver):** Similarly, this driver is for a specific Rockchip platform. Structurally unreachable. WorthFuzzing=false 7. **`dwmac-renesas-gbeth.c` (Renesas Gigabit Ethernet MAC Driver):** This is for Renesas SoCs. Structurally unreachable. WorthFuzzing=false 8. **`dwmac-rzn1.c` (Renesas RZ/N1 GMAC Driver):** This is for a Renesas architecture. Structurally unreachable. WorthFuzzing=false 9. **`dwmac-socfpga.c` (Intel/Altera SoCFPGA GMAC Driver):** This driver is for Intel SoCFPGA hardware. Structurally unreachable. WorthFuzzing=false 10. **`dwmac-intel.c` (Intel Gigabit Ethernet PCI Driver):** This is for *Intel* hardware! Requires physical PCI cards, or specific SoC hardware not emulated in standard QEMU. Structurally unreachable. WorthFuzzing=false 11. **`stmmac_mdio.c` (Helper Functions for STMMAC):** These helper functions in `stmmac_mdio.c` are called by `stmmac_main.c` . Can `stmmac` be probed on amd64 in QEMU? We need to look for that and see if that can probe in QEMU. Let's do a search! Therefore, based on my analysis of the modified files and the "WorthFuzzing=false" criteria, this patch series should not be considered for fuzzing, unless the `stmmac` can be probed in QEMU for amd64 architecture. |
| 18/2 | 2026/09/22 18:26 | tool | codesearch-dir-index |
0mArgs:{
"Dir": "drivers/net/ethernet/stmicro/stmmac/"
}Results: {
"Files": [
"chain_mode.c",
"common.h",
"descs.h",
"descs_com.h",
"dwmac-anarion.c",
"dwmac-dwc-qos-eth.c",
"dwmac-eic7700.c",
"dwmac-generic.c",
"dwmac-imx.c",
"dwmac-ingenic.c",
"dwmac-intel-plat.c",
"dwmac-intel.c",
"dwmac-intel.h",
"dwmac-ipq806x.c",
"dwmac-loongson.c",
"dwmac-loongson1.c",
"dwmac-lpc18xx.c",
"dwmac-mediatek.c",
"dwmac-meson.c",
"dwmac-meson8b.c",
"dwmac-motorcomm.c",
"dwmac-nuvoton.c",
"dwmac-qcom-ethqos.c",
"dwmac-renesas-gbeth.c",
"dwmac-rk.c",
"dwmac-rzn1.c",
"dwmac-s32.c",
"dwmac-socfpga.c",
"dwmac-sophgo.c",
"dwmac-spacemit.c",
"dwmac-starfive.c",
"dwmac-sti.c",
"dwmac-stm32.c",
"dwmac-sun55i.c",
"dwmac-sun8i.c",
"dwmac-sunxi.c",
"dwmac-tegra.c",
"dwmac-thead.c",
"dwmac-visconti.c",
"dwmac100.h",
"dwmac1000.h",
"dwmac1000_core.c",
"dwmac1000_dma.c",
"dwmac100_core.c",
"dwmac100_dma.c",
"dwmac4.h",
"dwmac4_core.c",
"dwmac4_descs.c",
"dwmac4_descs.h",
"dwmac4_dma.c",
"dwmac4_dma.h",
"dwmac4_lib.c",
"dwmac5.c",
"dwmac5.h",
"dwmac_dma.h",
"dwmac_lib.c",
"dwxgmac2.h",
"dwxgmac2_core.c",
"dwxgmac2_descs.c",
"dwxgmac2_dma.c",
"dwxlgmac2.h",
"enh_desc.c",
"hwif.c",
"hwif.h",
"mmc.h",
"mmc_core.c",
"norm_desc.c",
"ring_mode.c",
"stmmac.h",
"stmmac_est.c",
"stmmac_est.h",
"stmmac_ethtool.c",
"stmmac_fpe.c",
"stmmac_fpe.h",
"stmmac_hwtstamp.c",
"stmmac_libpci.c",
"stmmac_libpci.h",
"stmmac_main.c",
"stmmac_mdio.c",
"stmmac_pci.c",
"stmmac_pcs.c",
"stmmac_pcs.h",
"stmmac_platform.c",
"stmmac_platform.h",
"stmmac_ptp.c",
"stmmac_ptp.h",
"stmmac_selftests.c",
"stmmac_tc.c",
"stmmac_vlan.c",
"stmmac_vlan.h",
"stmmac_xdp.c",
"stmmac_xdp.h"
],
"Subdirs": null
} |
| 19/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 37428 output: 48 thoughts: 278 Thoughts: **Analyzing the STMMAC Driver Landscape** Okay, here's the deal. I need to get a handle on the STMMAC Ethernet driver implementations. First, I'm taking a good look at all the available platform-specific drivers within `drivers/net/ethernet/stmicro/stmmac/`. The sheer number is a good sign, showing the breadth of support for this core driver: `dwmac-anarion`, `dwmac-dwc-qos-eth`, `dwmac-eic7700`, `dwmac-generic`, `dwmac-imx`, `dwmac-ingenic`, `dwmac-intel-plat`, `dwmac-intel`, `dwmac-ipq806x`, `dwmac-loongson`, `dwmac-loongson1`, `dwmac-lpc18xx`, `dwmac-mediatek`, `dwmac-meson`, `dwmac-meson8b`, `dwmac-motorcomm`, `dwmac-nuvoton`, `dwmac-qcom-ethqos`, `dwmac-renesas-gbeth`, `dwmac-rk`, `dwmac-rzn1`, `dwmac-s32`, `dwmac-socfpga`, `dwmac-sophgo`, `dwmac-spacemit`, `dwmac-starfive`, `dwmac-sti`, `dwmac-stm32`, `dwmac-sun55i`, `dwmac-sun8i`, `dwmac-sunxi`, `dwmac-tegra`, `dwmac-thead`, `dwmac-visconti`, and the PCI-specific `stmmac_pci.c`. Since I'm interested in PCI specifically, I think the next logical step is to delve into `stmmac_pci.c`. That file is where the PCI interaction will be handled. Let's see what we can find. |
| 20/2 | 2026/09/22 18:26 | tool | grepper |
0mArgs:{
"Expression": "pci_device_id",
"PathPrefix": "drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c"
}Results: {
"Output": "drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c=118=static int stmmac_pci_probe(struct pci_dev *pdev,\ndrivers/net/ethernet/stmicro/stmmac/stmmac_pci.c:119:\t\t\t const struct pci_device_id *id)\ndrivers/net/ethernet/stmicro/stmmac/stmmac_pci.c-120-{\n--\ndrivers/net/ethernet/stmicro/stmmac/stmmac_pci.c=192=static void stmmac_pci_remove(struct pci_dev *pdev)\n--\ndrivers/net/ethernet/stmicro/stmmac/stmmac_pci.c-202-\ndrivers/net/ethernet/stmicro/stmmac/stmmac_pci.c:203:static const struct pci_device_id stmmac_id_table[] = {\ndrivers/net/ethernet/stmicro/stmmac/stmmac_pci.c-204-\t{ PCI_DEVICE_DATA(STMMAC, STMMAC, \u0026stmmac_pci_info) },\n"
} |
| 21/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 38483 output: 40 thoughts: 194 Thoughts: **Investigating Potential STMMAC PCI and PCS-XPCS Interactions** Okay, so I'm looking at this code and trying to figure out the potential interactions, particularly regarding `STMMAC` and PCI configurations. I see `PCI_DEVICE_DATA(STMMAC, STMMAC, &stmmac_pci_info)` which immediately tells me this is about Synopsys prototype PCI boards. The problem is, and this is a significant gotcha, none of these PCI IDs are actually emulated by QEMU. QEMU flat-out doesn't simulate stmmac PCI boards. This is definitely a road block I need to keep in mind. Next, I'm pivoting to `drivers/net/pcs/pcs-xpcs.c`. I need to figure out how reachable this code is and in what context it's being used. Specifically, I'm interested in how `xpcs_config_aneg_c37_sgmii` and `xpcs_get_state_c37_sgmii` are called. This points me to the crux of the issue: where are these functions actually being *invoked* within this driver? The next step is to examine the callers of those functions within `drivers/net/pcs/pcs-xpcs.c` to understand the flow and logic surrounding them. Understanding the call stack is key. |
| 22/2 | 2026/09/22 18:26 | tool | read-file |
0mArgs:{
"File": "drivers/net/pcs/pcs-xpcs.c",
"FirstLine": 945,
"LineCount": 40
}Results: {
"Contents": " 945:\t\n 946:\t\tswitch (compat-\u003ean_mode) {\n 947:\t\tcase DW_10GBASER:\n 948:\t\t\tbreak;\n 949:\t\tcase DW_AN_C73:\n 950:\t\t\tif (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {\n 951:\t\t\t\tret = xpcs_config_aneg_c73(xpcs, compat);\n 952:\t\t\t\tif (ret)\n 953:\t\t\t\t\treturn ret;\n 954:\t\t\t}\n 955:\t\t\tbreak;\n 956:\t\tcase DW_AN_C37_SGMII:\n 957:\t\t\tret = xpcs_config_aneg_c37_sgmii(xpcs, neg_mode);\n 958:\t\t\tif (ret)\n 959:\t\t\t\treturn ret;\n 960:\t\t\tbreak;\n 961:\t\tcase DW_AN_C37_1000BASEX:\n 962:\t\t\tret = xpcs_config_aneg_c37_1000basex(xpcs, neg_mode,\n 963:\t\t\t\t\t\t\t advertising);\n 964:\t\t\tif (ret)\n 965:\t\t\t\treturn ret;\n 966:\t\t\tbreak;\n 967:\t\tcase DW_2500BASEX:\n 968:\t\t\tret = xpcs_config_2500basex(xpcs);\n 969:\t\t\tif (ret)\n 970:\t\t\t\treturn ret;\n 971:\t\t\tbreak;\n 972:\t\tdefault:\n 973:\t\t\treturn -EINVAL;\n 974:\t\t}\n 975:\t\n 976:\t\tif (compat-\u003epma_config) {\n 977:\t\t\tret = compat-\u003epma_config(xpcs);\n 978:\t\t\tif (ret)\n 979:\t\t\t\treturn ret;\n 980:\t\t}\n 981:\t\n 982:\t\treturn 0;\n 983:\t}\n 984:\t\n"
} |
| 23/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 39562 output: 45 thoughts: 23 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person: **Analyzing the Caller of `xpcs_get_state_c37_sgmii`** Right, so we're diving into this `xpcs_get_state_c37_sgmii` function. My initial thought is, before we go any further, *let's* pinpoint where this function is being called from. Understanding the caller is key. It immediately frames the context. What's driving the need to check this state? What assumptions are being made about the environment or conditions? Knowing the calling function provides critical clues to the overall design. What does it tell us about how the system is organized, and where the potential bottlenecks might lie? A deep understanding of the context will likely influence any further steps of my investigation. It's time to follow the trail back and trace the calling function. |
| 24/2 | 2026/09/22 18:26 | tool | grepper |
0mArgs:{
"Expression": "xpcs_get_state_c37_sgmii",
"PathPrefix": "drivers/net/pcs/pcs-xpcs.c"
}Results: {
"Output": "drivers/net/pcs/pcs-xpcs.c=995=static int xpcs_get_state_c73(struct dw_xpcs *xpcs,\n--\ndrivers/net/pcs/pcs-xpcs.c-1067-\ndrivers/net/pcs/pcs-xpcs.c:1068:static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-1069-\t\t\t\t struct phylink_link_state *state)\n--\ndrivers/net/pcs/pcs-xpcs.c=1184=static void xpcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c-1205-\tcase DW_AN_C37_SGMII:\ndrivers/net/pcs/pcs-xpcs.c:1206:\t\tret = xpcs_get_state_c37_sgmii(xpcs, state);\ndrivers/net/pcs/pcs-xpcs.c-1207-\t\tif (ret)\ndrivers/net/pcs/pcs-xpcs.c-1208-\t\t\tdev_err(\u0026xpcs-\u003emdiodev-\u003edev, \"%s returned %pe\\n\",\ndrivers/net/pcs/pcs-xpcs.c:1209:\t\t\t\t\"xpcs_get_state_c37_sgmii\", ERR_PTR(ret));\ndrivers/net/pcs/pcs-xpcs.c-1210-\t\tbreak;\n"
} |
| 25/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 40223 output: 37 thoughts: 679 Thoughts: **Analyzing the XPCS Phylink Operations** Okay, let's break this down. My initial observation is that `xpcs_get_state` is definitely part of the `xpcs_phylink_ops` structure. This is a crucial link, and now I need to trace how a `phylink_pcs` using this `xpcs` module gets created. I've already identified several callers of `xpcs_create*` functions, and a list is in front of me: * `ksz9477_pcs_create` – dealing with a Microchip KSZ9477 Ethernet switch. * `sja1105_mdiobus_pcs_register` – for an NXP SJA1105 Ethernet switch. * `fbnic_phylink_create` – this is associated with a Meta ASIC NIC. * `intel_mgbe_pcs_init` – for Intel SoC PCI MACs. * `txgbe_mdio_pcs_init` – dealing with a Wangxun 10G PCIe NIC. * `xpcs_rk_create` – this is Rockchip specific, part of a Rockchip RK3568 SoC XPCS. Now, a key question hits me: are any of these drivers or devices actually used in standard virtualized environments like QEMU/KVM or Google Compute Engine on amd64 architecture? I need to quickly assess their underlying hardware dependencies to ascertain this. Let's step through each one: 1. `ksz9477` – It's a DSA switch on SPI/I2C. This requires a physical SPI/I2C connection to KSZ9477 hardware. Not virtualized. 2. `sja1105` – Another DSA switch, but this time on SPI. Again, a physical SPI connection to the SJA1105 hardware is necessary. Not virtualized. 3. `fbnic` – This is a Meta ASIC PCIe NIC. Physical PCIe hardware. Not virtualized. 4. `dwmac-intel` – An Intel SoC PCIe DWMAC (from Quark, Elkhart Lake, Tiger Lake, and the like). Physical PCIe hardware. Not virtualized. 5. `txgbe` – This is a Wangxun 10G PCIe NIC. Requires physical PCIe hardware. Not virtualized. 6. `pcs-xpcs-rk` – This is a Rockchip XPCS platform device. This is a physical ARM64 SoC. Not virtualized. Hmm... all of them appear to be tied to specific physical hardware. No obvious candidates for virtualized environments so far. Wait! I almost missed it. What about `pcs-xpcs-plat.c`? I need to check whether that one creates an xpcs, or if I've overlooked something important. |
| 26/2 | 2026/09/22 18:26 | tool | grepper |
0mArgs:{
"Expression": "xpcs_",
"PathPrefix": "drivers/net/pcs/pcs-xpcs-plat.c"
}Results: {
"Output": "drivers/net/pcs/pcs-xpcs-plat.c-26-\ndrivers/net/pcs/pcs-xpcs-plat.c:27:struct dw_xpcs_plat {\ndrivers/net/pcs/pcs-xpcs-plat.c-28-\tstruct platform_device *pdev;\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-35-\ndrivers/net/pcs/pcs-xpcs-plat.c:36:static ptrdiff_t xpcs_mmio_addr_format(int dev, int reg)\ndrivers/net/pcs/pcs-xpcs-plat.c-37-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-40-\ndrivers/net/pcs/pcs-xpcs-plat.c:41:static u16 xpcs_mmio_addr_page(ptrdiff_t csr)\ndrivers/net/pcs/pcs-xpcs-plat.c-42-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-45-\ndrivers/net/pcs/pcs-xpcs-plat.c:46:static ptrdiff_t xpcs_mmio_addr_offset(ptrdiff_t csr)\ndrivers/net/pcs/pcs-xpcs-plat.c-47-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-50-\ndrivers/net/pcs/pcs-xpcs-plat.c:51:static int xpcs_mmio_read_reg_indirect(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-52-\t\t\t\t int dev, int reg)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-57-\ndrivers/net/pcs/pcs-xpcs-plat.c:58:\tcsr = xpcs_mmio_addr_format(dev, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c:59:\tpage = xpcs_mmio_addr_page(csr);\ndrivers/net/pcs/pcs-xpcs-plat.c:60:\tofs = xpcs_mmio_addr_offset(csr);\ndrivers/net/pcs/pcs-xpcs-plat.c-61-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-81-\ndrivers/net/pcs/pcs-xpcs-plat.c:82:static int xpcs_mmio_write_reg_indirect(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-83-\t\t\t\t\tint dev, int reg, u16 val)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-88-\ndrivers/net/pcs/pcs-xpcs-plat.c:89:\tcsr = xpcs_mmio_addr_format(dev, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c:90:\tpage = xpcs_mmio_addr_page(csr);\ndrivers/net/pcs/pcs-xpcs-plat.c:91:\tofs = xpcs_mmio_addr_offset(csr);\ndrivers/net/pcs/pcs-xpcs-plat.c-92-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-112-\ndrivers/net/pcs/pcs-xpcs-plat.c:113:static int xpcs_mmio_read_reg_direct(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-114-\t\t\t\t int dev, int reg)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-118-\ndrivers/net/pcs/pcs-xpcs-plat.c:119:\tcsr = xpcs_mmio_addr_format(dev, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c-120-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-138-\ndrivers/net/pcs/pcs-xpcs-plat.c:139:static int xpcs_mmio_write_reg_direct(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-140-\t\t\t\t int dev, int reg, u16 val)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-144-\ndrivers/net/pcs/pcs-xpcs-plat.c:145:\tcsr = xpcs_mmio_addr_format(dev, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c-146-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-164-\ndrivers/net/pcs/pcs-xpcs-plat.c:165:static int xpcs_mmio_read_c22(struct mii_bus *bus, int addr, int reg)\ndrivers/net/pcs/pcs-xpcs-plat.c-166-{\ndrivers/net/pcs/pcs-xpcs-plat.c:167:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-168-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-172-\tif (pxpcs-\u003ereg_indir)\ndrivers/net/pcs/pcs-xpcs-plat.c:173:\t\treturn xpcs_mmio_read_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c-174-\telse\ndrivers/net/pcs/pcs-xpcs-plat.c:175:\t\treturn xpcs_mmio_read_reg_direct(pxpcs, MDIO_MMD_VEND2, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c-176-}\ndrivers/net/pcs/pcs-xpcs-plat.c-177-\ndrivers/net/pcs/pcs-xpcs-plat.c:178:static int xpcs_mmio_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-plat.c-179-{\ndrivers/net/pcs/pcs-xpcs-plat.c:180:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-181-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-185-\tif (pxpcs-\u003ereg_indir)\ndrivers/net/pcs/pcs-xpcs-plat.c:186:\t\treturn xpcs_mmio_write_reg_indirect(pxpcs, MDIO_MMD_VEND2, reg, val);\ndrivers/net/pcs/pcs-xpcs-plat.c-187-\telse\ndrivers/net/pcs/pcs-xpcs-plat.c:188:\t\treturn xpcs_mmio_write_reg_direct(pxpcs, MDIO_MMD_VEND2, reg, val);\ndrivers/net/pcs/pcs-xpcs-plat.c-189-}\ndrivers/net/pcs/pcs-xpcs-plat.c-190-\ndrivers/net/pcs/pcs-xpcs-plat.c:191:static int xpcs_mmio_read_c45(struct mii_bus *bus, int addr, int dev, int reg)\ndrivers/net/pcs/pcs-xpcs-plat.c-192-{\ndrivers/net/pcs/pcs-xpcs-plat.c:193:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-194-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-198-\tif (pxpcs-\u003ereg_indir)\ndrivers/net/pcs/pcs-xpcs-plat.c:199:\t\treturn xpcs_mmio_read_reg_indirect(pxpcs, dev, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c-200-\telse\ndrivers/net/pcs/pcs-xpcs-plat.c:201:\t\treturn xpcs_mmio_read_reg_direct(pxpcs, dev, reg);\ndrivers/net/pcs/pcs-xpcs-plat.c-202-}\ndrivers/net/pcs/pcs-xpcs-plat.c-203-\ndrivers/net/pcs/pcs-xpcs-plat.c:204:static int xpcs_mmio_write_c45(struct mii_bus *bus, int addr, int dev,\ndrivers/net/pcs/pcs-xpcs-plat.c-205-\t\t\t int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-plat.c-206-{\ndrivers/net/pcs/pcs-xpcs-plat.c:207:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-208-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-212-\tif (pxpcs-\u003ereg_indir)\ndrivers/net/pcs/pcs-xpcs-plat.c:213:\t\treturn xpcs_mmio_write_reg_indirect(pxpcs, dev, reg, val);\ndrivers/net/pcs/pcs-xpcs-plat.c-214-\telse\ndrivers/net/pcs/pcs-xpcs-plat.c:215:\t\treturn xpcs_mmio_write_reg_direct(pxpcs, dev, reg, val);\ndrivers/net/pcs/pcs-xpcs-plat.c-216-}\ndrivers/net/pcs/pcs-xpcs-plat.c-217-\ndrivers/net/pcs/pcs-xpcs-plat.c:218:static struct dw_xpcs_plat *xpcs_plat_create_data(struct platform_device *pdev)\ndrivers/net/pcs/pcs-xpcs-plat.c-219-{\ndrivers/net/pcs/pcs-xpcs-plat.c:220:\tstruct dw_xpcs_plat *pxpcs;\ndrivers/net/pcs/pcs-xpcs-plat.c-221-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-232-\ndrivers/net/pcs/pcs-xpcs-plat.c:233:static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-234-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-277-\ndrivers/net/pcs/pcs-xpcs-plat.c:278:static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-279-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-297-\ndrivers/net/pcs/pcs-xpcs-plat.c:298:static int xpcs_plat_init_bus(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-299-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-308-\tpxpcs-\u003ebus-\u003ename = \"DW XPCS MCI/APB3\";\ndrivers/net/pcs/pcs-xpcs-plat.c:309:\tpxpcs-\u003ebus-\u003eread = xpcs_mmio_read_c22;\ndrivers/net/pcs/pcs-xpcs-plat.c:310:\tpxpcs-\u003ebus-\u003ewrite = xpcs_mmio_write_c22;\ndrivers/net/pcs/pcs-xpcs-plat.c:311:\tpxpcs-\u003ebus-\u003eread_c45 = xpcs_mmio_read_c45;\ndrivers/net/pcs/pcs-xpcs-plat.c:312:\tpxpcs-\u003ebus-\u003ewrite_c45 = xpcs_mmio_write_c45;\ndrivers/net/pcs/pcs-xpcs-plat.c-313-\tpxpcs-\u003ebus-\u003ephy_mask = ~0;\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-336- */\ndrivers/net/pcs/pcs-xpcs-plat.c:337:static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-338-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-372-\ndrivers/net/pcs/pcs-xpcs-plat.c:373:static int xpcs_plat_probe(struct platform_device *pdev)\ndrivers/net/pcs/pcs-xpcs-plat.c-374-{\ndrivers/net/pcs/pcs-xpcs-plat.c:375:\tstruct dw_xpcs_plat *pxpcs;\ndrivers/net/pcs/pcs-xpcs-plat.c-376-\tint ret;\ndrivers/net/pcs/pcs-xpcs-plat.c-377-\ndrivers/net/pcs/pcs-xpcs-plat.c:378:\tpxpcs = xpcs_plat_create_data(pdev);\ndrivers/net/pcs/pcs-xpcs-plat.c-379-\tif (IS_ERR(pxpcs))\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-381-\ndrivers/net/pcs/pcs-xpcs-plat.c:382:\tret = xpcs_plat_init_res(pxpcs);\ndrivers/net/pcs/pcs-xpcs-plat.c-383-\tif (ret)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-385-\ndrivers/net/pcs/pcs-xpcs-plat.c:386:\tret = xpcs_plat_init_clk(pxpcs);\ndrivers/net/pcs/pcs-xpcs-plat.c-387-\tif (ret)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-389-\ndrivers/net/pcs/pcs-xpcs-plat.c:390:\tret = xpcs_plat_init_bus(pxpcs);\ndrivers/net/pcs/pcs-xpcs-plat.c-391-\tif (ret)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-393-\ndrivers/net/pcs/pcs-xpcs-plat.c:394:\tret = xpcs_plat_init_dev(pxpcs);\ndrivers/net/pcs/pcs-xpcs-plat.c-395-\tif (ret)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-400-\ndrivers/net/pcs/pcs-xpcs-plat.c:401:static int __maybe_unused xpcs_plat_pm_runtime_suspend(struct device *dev)\ndrivers/net/pcs/pcs-xpcs-plat.c-402-{\ndrivers/net/pcs/pcs-xpcs-plat.c:403:\tstruct dw_xpcs_plat *pxpcs = dev_get_drvdata(dev);\ndrivers/net/pcs/pcs-xpcs-plat.c-404-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-409-\ndrivers/net/pcs/pcs-xpcs-plat.c:410:static int __maybe_unused xpcs_plat_pm_runtime_resume(struct device *dev)\ndrivers/net/pcs/pcs-xpcs-plat.c-411-{\ndrivers/net/pcs/pcs-xpcs-plat.c:412:\tstruct dw_xpcs_plat *pxpcs = dev_get_drvdata(dev);\ndrivers/net/pcs/pcs-xpcs-plat.c-413-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-416-\ndrivers/net/pcs/pcs-xpcs-plat.c:417:static const struct dev_pm_ops xpcs_plat_pm_ops = {\ndrivers/net/pcs/pcs-xpcs-plat.c:418:\tSET_RUNTIME_PM_OPS(xpcs_plat_pm_runtime_suspend,\ndrivers/net/pcs/pcs-xpcs-plat.c:419:\t\t\t xpcs_plat_pm_runtime_resume,\ndrivers/net/pcs/pcs-xpcs-plat.c-420-\t\t\t NULL)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-422-\ndrivers/net/pcs/pcs-xpcs-plat.c:423:DW_XPCS_INFO_DECLARE(xpcs_generic, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_ID_NATIVE);\ndrivers/net/pcs/pcs-xpcs-plat.c:424:DW_XPCS_INFO_DECLARE(xpcs_pma_gen1_3g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN1_3G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c:425:DW_XPCS_INFO_DECLARE(xpcs_pma_gen2_3g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN2_3G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c:426:DW_XPCS_INFO_DECLARE(xpcs_pma_gen2_6g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN2_6G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c:427:DW_XPCS_INFO_DECLARE(xpcs_pma_gen4_3g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN4_3G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c:428:DW_XPCS_INFO_DECLARE(xpcs_pma_gen4_6g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN4_6G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c:429:DW_XPCS_INFO_DECLARE(xpcs_pma_gen5_10g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN5_10G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c:430:DW_XPCS_INFO_DECLARE(xpcs_pma_gen5_12g, DW_XPCS_ID_NATIVE, DW_XPCS_PMA_GEN5_12G_ID);\ndrivers/net/pcs/pcs-xpcs-plat.c-431-\ndrivers/net/pcs/pcs-xpcs-plat.c:432:static const struct of_device_id xpcs_of_ids[] = {\ndrivers/net/pcs/pcs-xpcs-plat.c:433:\t{ .compatible = \"snps,dw-xpcs\", .data = \u0026xpcs_generic },\ndrivers/net/pcs/pcs-xpcs-plat.c:434:\t{ .compatible = \"snps,dw-xpcs-gen1-3g\", .data = \u0026xpcs_pma_gen1_3g },\ndrivers/net/pcs/pcs-xpcs-plat.c:435:\t{ .compatible = \"snps,dw-xpcs-gen2-3g\", .data = \u0026xpcs_pma_gen2_3g },\ndrivers/net/pcs/pcs-xpcs-plat.c:436:\t{ .compatible = \"snps,dw-xpcs-gen2-6g\", .data = \u0026xpcs_pma_gen2_6g },\ndrivers/net/pcs/pcs-xpcs-plat.c:437:\t{ .compatible = \"snps,dw-xpcs-gen4-3g\", .data = \u0026xpcs_pma_gen4_3g },\ndrivers/net/pcs/pcs-xpcs-plat.c:438:\t{ .compatible = \"snps,dw-xpcs-gen4-6g\", .data = \u0026xpcs_pma_gen4_6g },\ndrivers/net/pcs/pcs-xpcs-plat.c:439:\t{ .compatible = \"snps,dw-xpcs-gen5-10g\", .data = \u0026xpcs_pma_gen5_10g },\ndrivers/net/pcs/pcs-xpcs-plat.c:440:\t{ .compatible = \"snps,dw-xpcs-gen5-12g\", .data = \u0026xpcs_pma_gen5_12g },\ndrivers/net/pcs/pcs-xpcs-plat.c-441-\t{ /* sentinel */ },\ndrivers/net/pcs/pcs-xpcs-plat.c-442-};\ndrivers/net/pcs/pcs-xpcs-plat.c:443:MODULE_DEVICE_TABLE(of, xpcs_of_ids);\ndrivers/net/pcs/pcs-xpcs-plat.c-444-\ndrivers/net/pcs/pcs-xpcs-plat.c:445:static struct platform_driver xpcs_plat_driver = {\ndrivers/net/pcs/pcs-xpcs-plat.c:446:\t.probe = xpcs_plat_probe,\ndrivers/net/pcs/pcs-xpcs-plat.c-447-\t.driver = {\ndrivers/net/pcs/pcs-xpcs-plat.c-448-\t\t.name = \"dwxpcs\",\ndrivers/net/pcs/pcs-xpcs-plat.c:449:\t\t.pm = \u0026xpcs_plat_pm_ops,\ndrivers/net/pcs/pcs-xpcs-plat.c:450:\t\t.of_match_table = xpcs_of_ids,\ndrivers/net/pcs/pcs-xpcs-plat.c-451-\t},\ndrivers/net/pcs/pcs-xpcs-plat.c-452-};\ndrivers/net/pcs/pcs-xpcs-plat.c:453:module_platform_driver(xpcs_plat_driver);\ndrivers/net/pcs/pcs-xpcs-plat.c-454-\n"
} |
| 27/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 47147 output: 37 thoughts: 79 Thoughts: Okay, let's break this down. **Investigating the xpcs Driver Landscape** Right, so `pcs-xpcs-plat.c` clearly handles the platform-specific aspects of this `xpcs` device, keyed to the `snps,dw-xpcs` OF device tree compatible string. I'm now curious about the broader ecosystem – who else might be using this `xpcs` designation? It's important to understand the overall picture to avoid any conflicts or redundant code. My initial thought is to check if we have any other similarly named drivers, specifically `pcs-xpcs-nxp.c` or `pcs-xpcs-wx.c`. I need to review these other modules to get a handle on the full scope of `xpcs` driver implementations. |
| 28/2 | 2026/09/22 18:26 | tool | grepper |
0mArgs:{
"Expression": "xpcs",
"PathPrefix": "drivers/net/pcs/pcs-xpcs-nxp.c"
}Results: {
"Output": "drivers/net/pcs/pcs-xpcs-nxp.c-3- */\ndrivers/net/pcs/pcs-xpcs-nxp.c:4:#include \u003clinux/pcs/pcs-xpcs.h\u003e\ndrivers/net/pcs/pcs-xpcs-nxp.c:5:#include \"pcs-xpcs.h\"\ndrivers/net/pcs/pcs-xpcs-nxp.c-6-\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-71- */\ndrivers/net/pcs/pcs-xpcs-nxp.c:72:int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-nxp.c-73-{\ndrivers/net/pcs/pcs-xpcs-nxp.c:74:\treturn xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL2,\ndrivers/net/pcs/pcs-xpcs-nxp.c-75-\t\t\t DW_VR_MII_DIG_CTRL2_TX_POL_INV);\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-77-\ndrivers/net/pcs/pcs-xpcs-nxp.c:78:static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs-nxp.c-79-\t\t\t\t u16 txpll_fbdiv, u16 txpll_refdiv,\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-88-\t */\ndrivers/net/pcs/pcs-xpcs-nxp.c:89:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL0,\ndrivers/net/pcs/pcs-xpcs-nxp.c-90-\t\t\t SJA1110_TXPLL_FBDIV(txpll_fbdiv));\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-93-\ndrivers/net/pcs/pcs-xpcs-nxp.c:94:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_TXPLL_CTRL1,\ndrivers/net/pcs/pcs-xpcs-nxp.c-95-\t\t\t SJA1110_TXPLL_REFDIV(txpll_refdiv));\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-99-\t/* Program transmitter amplitude and disable amplitude trimming */\ndrivers/net/pcs/pcs-xpcs-nxp.c:100:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER1_0,\ndrivers/net/pcs/pcs-xpcs-nxp.c-101-\t\t\t SJA1110_TXDRV(0x5));\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-106-\ndrivers/net/pcs/pcs-xpcs-nxp.c:107:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_0, val);\ndrivers/net/pcs/pcs-xpcs-nxp.c-108-\tif (ret \u003c 0)\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-112-\ndrivers/net/pcs/pcs-xpcs-nxp.c:113:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DRIVER2_1, val);\ndrivers/net/pcs/pcs-xpcs-nxp.c-114-\tif (ret \u003c 0)\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-121-\ndrivers/net/pcs/pcs-xpcs-nxp.c:122:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_TRIM, val);\ndrivers/net/pcs/pcs-xpcs-nxp.c-123-\tif (ret \u003c 0)\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-126-\t/* Select PCS as transmitter data source. */\ndrivers/net/pcs/pcs-xpcs-nxp.c:127:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_LANE_DATAPATH_1, 0);\ndrivers/net/pcs/pcs-xpcs-nxp.c-128-\tif (ret \u003c 0)\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-133-\t */\ndrivers/net/pcs/pcs-xpcs-nxp.c:134:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL0,\ndrivers/net/pcs/pcs-xpcs-nxp.c-135-\t\t\t SJA1110_RXPLL_FBDIV(rxpll_fbdiv));\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-138-\ndrivers/net/pcs/pcs-xpcs-nxp.c:139:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RXPLL_CTRL1,\ndrivers/net/pcs/pcs-xpcs-nxp.c-140-\t\t\t SJA1110_RXPLL_REFDIV(rxpll_refdiv));\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-147-\t */\ndrivers/net/pcs/pcs-xpcs-nxp.c:148:\tret = xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_DATA_DETECT, 0x0005);\ndrivers/net/pcs/pcs-xpcs-nxp.c-149-\tif (ret \u003c 0)\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-154-\t */\ndrivers/net/pcs/pcs-xpcs-nxp.c:155:\tret = xpcs_modify(xpcs, MDIO_MMD_VEND2, SJA1110_POWERDOWN_ENABLE,\ndrivers/net/pcs/pcs-xpcs-nxp.c-156-\t\t\t SJA1110_TXPLL_PD | SJA1110_TXPD | SJA1110_RXCH_PD |\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-164-\t/* Program continuous-time linear equalizer (CTLE) settings. */\ndrivers/net/pcs/pcs-xpcs-nxp.c:165:\treturn xpcs_write(xpcs, MDIO_MMD_VEND2, SJA1110_RX_CDR_CTLE,\ndrivers/net/pcs/pcs-xpcs-nxp.c-166-\t\t\t rx_cdr_ctle);\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-168-\ndrivers/net/pcs/pcs-xpcs-nxp.c:169:int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-nxp.c-170-{\ndrivers/net/pcs/pcs-xpcs-nxp.c:171:\treturn nxp_sja1110_pma_config(xpcs, 0x19, 0x1, 0x19, 0x1, 0x212a);\ndrivers/net/pcs/pcs-xpcs-nxp.c-172-}\ndrivers/net/pcs/pcs-xpcs-nxp.c-173-\ndrivers/net/pcs/pcs-xpcs-nxp.c:174:int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-nxp.c-175-{\ndrivers/net/pcs/pcs-xpcs-nxp.c:176:\treturn nxp_sja1110_pma_config(xpcs, 0x7d, 0x2, 0x7d, 0x2, 0x732a);\ndrivers/net/pcs/pcs-xpcs-nxp.c-177-}\n"
} |
| 29/2 | 2026/09/22 18:26 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 49648 output: 36 thoughts: 15 Thoughts: Okay, let's dive into this `pcs-xpcs-wx.c` file. Here's what's going through my mind: **Analyzing `pcs-xpcs-wx.c`** Alright, I see this is the place where the PCS (presumably a Performance Counter Set or similar) interacts with, or is part of, the XPCS (likely eXternal Performance Counter Set) and WX (Watchpoint Extensions) components. Immediately, I'm thinking about the implications. What's the target platform? Is this embedded, a server, or something else entirely? What's the performance monitoring architecture at play? Are we talking hardware counters, software-defined events, or a hybrid approach? I need context. I'm mentally running through the typical areas where these components would intersect. Is this about counter aggregation? Control of watchpoint triggers? Resource allocation for performance monitoring? Are we dealing with kernel-level or user-space interaction? The naming convention suggests a level of low-level access – potentially interacting directly with hardware or OS internals. I need to understand how the data flows between each component. Are there locking mechanisms involved? What kind of data structures are we using to store performance data or watchpoint configurations? The "wx" extension, specifically, raises questions. Is this about advanced debug techniques? Real-time analysis of memory access patterns? Performance profiling with specific focus on memory-related bottlenecks? I need to look for where the WX components are hooked in. I'll need to scrutinize how it gets configured or initialized within the PCS/XPCS framework. I'll search for things like 'watchpoint_init', 'wx_register', 'pcs_wx_enable', etc. I'm also wondering about potential race conditions or synchronization issues. Performance counters and watchpoints are often tightly coupled with the execution of code. Concurrent access and modifications to the counter state or the watchpoint setup could lead to data corruption or incorrect analysis results. I'll be looking for any signs of careful locking or atomic operations. I expect a careful consideration of interrupt handling in this module. Finally, error handling is something I need to keep in mind. Performance monitoring, especially at the level this file likely deals with, can fail in numerous ways. Invalid counter configurations, unsupported watchpoint settings, memory allocation failures, or even hardware malfunctions could all lead to issues. I need to understand how these errors are detected, reported, and handled. I'm looking for a robust handling strategy. |
| 30/2 | 2026/09/22 18:27 | tool | grepper |
0mArgs:{
"Expression": "xpcs",
"PathPrefix": "drivers/net/pcs/pcs-xpcs-wx.c"
}Results: {
"Output": "drivers/net/pcs/pcs-xpcs-wx.c-3-\ndrivers/net/pcs/pcs-xpcs-wx.c:4:#include \u003clinux/pcs/pcs-xpcs.h\u003e\ndrivers/net/pcs/pcs-xpcs-wx.c-5-#include \u003clinux/mdio.h\u003e\ndrivers/net/pcs/pcs-xpcs-wx.c:6:#include \"pcs-xpcs.h\"\ndrivers/net/pcs/pcs-xpcs-wx.c-7-\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-48-\ndrivers/net/pcs/pcs-xpcs-wx.c:49:static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-wx.c-50-{\ndrivers/net/pcs/pcs-xpcs-wx.c:51:\treturn xpcs_write(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val);\ndrivers/net/pcs/pcs-xpcs-wx.c-52-}\ndrivers/net/pcs/pcs-xpcs-wx.c-53-\ndrivers/net/pcs/pcs-xpcs-wx.c:54:static int txgbe_modify_pma(struct dw_xpcs *xpcs, int reg, u16 mask, u16 set)\ndrivers/net/pcs/pcs-xpcs-wx.c-55-{\ndrivers/net/pcs/pcs-xpcs-wx.c:56:\treturn xpcs_modify(xpcs, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, mask,\ndrivers/net/pcs/pcs-xpcs-wx.c-57-\t\t\t set);\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-59-\ndrivers/net/pcs/pcs-xpcs-wx.c:60:static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-61-{\ndrivers/net/pcs/pcs-xpcs-wx.c:62:\ttxgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x21);\ndrivers/net/pcs/pcs-xpcs-wx.c:63:\ttxgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:64:\ttxgbe_modify_pma(xpcs, TXGBE_TX_GENCTL1, TXGBE_TX_GENCTL1_VBOOST_LVL,\ndrivers/net/pcs/pcs-xpcs-wx.c-65-\t\t\t FIELD_PREP(TXGBE_TX_GENCTL1_VBOOST_LVL, 0x5));\ndrivers/net/pcs/pcs-xpcs-wx.c:66:\ttxgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |\ndrivers/net/pcs/pcs-xpcs-wx.c-67-\t\t\tTXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));\ndrivers/net/pcs/pcs-xpcs-wx.c:68:\ttxgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x549);\ndrivers/net/pcs/pcs-xpcs-wx.c:69:\ttxgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x29);\ndrivers/net/pcs/pcs-xpcs-wx.c:70:\ttxgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:71:\ttxgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:72:\ttxgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(3));\ndrivers/net/pcs/pcs-xpcs-wx.c:73:\ttxgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(3));\ndrivers/net/pcs/pcs-xpcs-wx.c:74:\ttxgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV16P5_CLK_EN |\ndrivers/net/pcs/pcs-xpcs-wx.c-75-\t\t\tTXGBE_MPLLA_CTL2_DIV10_CLK_EN);\ndrivers/net/pcs/pcs-xpcs-wx.c-76-\ndrivers/net/pcs/pcs-xpcs-wx.c:77:\ttxgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_CTLE_POLE(2) |\ndrivers/net/pcs/pcs-xpcs-wx.c-78-\t\t\tTXGBE_RX_EQ_CTL0_CTLE_BOOST(5));\ndrivers/net/pcs/pcs-xpcs-wx.c:79:\ttxgbe_modify_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, TXGBE_RX_EQ_ATTN_LVL0, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:80:\ttxgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0xBE);\ndrivers/net/pcs/pcs-xpcs-wx.c:81:\ttxgbe_modify_pma(xpcs, TXGBE_AFE_DFE_ENABLE,\ndrivers/net/pcs/pcs-xpcs-wx.c-82-\t\t\t TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:83:\ttxgbe_modify_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_ADAPT0,\ndrivers/net/pcs/pcs-xpcs-wx.c-84-\t\t\t 0);\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-86-\ndrivers/net/pcs/pcs-xpcs-wx.c:87:static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-88-{\ndrivers/net/pcs/pcs-xpcs-wx.c:89:\ttxgbe_modify_pma(xpcs, TXGBE_TX_GENCTL1,\ndrivers/net/pcs/pcs-xpcs-wx.c-90-\t\t\t TXGBE_TX_GENCTL1_VBOOST_LVL |\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-92-\t\t\t FIELD_PREP(TXGBE_TX_GENCTL1_VBOOST_LVL, 0x5));\ndrivers/net/pcs/pcs-xpcs-wx.c:93:\ttxgbe_write_pma(xpcs, TXGBE_MISC_CTL0, TXGBE_MISC_CTL0_PLL |\ndrivers/net/pcs/pcs-xpcs-wx.c-94-\t\t\tTXGBE_MISC_CTL0_CR_PARA_SEL | TXGBE_MISC_CTL0_RX_VREF(0xF));\ndrivers/net/pcs/pcs-xpcs-wx.c-95-\ndrivers/net/pcs/pcs-xpcs-wx.c:96:\ttxgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL0, TXGBE_RX_EQ_CTL0_VGA1_GAIN(7) |\ndrivers/net/pcs/pcs-xpcs-wx.c-97-\t\t\tTXGBE_RX_EQ_CTL0_VGA2_GAIN(7) | TXGBE_RX_EQ_CTL0_CTLE_BOOST(6));\ndrivers/net/pcs/pcs-xpcs-wx.c:98:\ttxgbe_modify_pma(xpcs, TXGBE_RX_EQ_ATTN_CTL, TXGBE_RX_EQ_ATTN_LVL0, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:99:\ttxgbe_write_pma(xpcs, TXGBE_DFE_TAP_CTL0, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:100:\ttxgbe_modify_pma(xpcs, TXGBE_RX_GEN_CTL3, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0,\ndrivers/net/pcs/pcs-xpcs-wx.c-101-\t\t\t FIELD_PREP(TXGBE_RX_GEN_CTL3_LOS_TRSHLD0, 0x4));\ndrivers/net/pcs/pcs-xpcs-wx.c-102-\ndrivers/net/pcs/pcs-xpcs-wx.c:103:\ttxgbe_write_pma(xpcs, TXGBE_MPLLA_CTL0, 0x20);\ndrivers/net/pcs/pcs-xpcs-wx.c:104:\ttxgbe_write_pma(xpcs, TXGBE_MPLLA_CTL3, 0x46);\ndrivers/net/pcs/pcs-xpcs-wx.c:105:\ttxgbe_write_pma(xpcs, TXGBE_VCO_CAL_LD0, 0x540);\ndrivers/net/pcs/pcs-xpcs-wx.c:106:\ttxgbe_write_pma(xpcs, TXGBE_VCO_CAL_REF0, 0x2A);\ndrivers/net/pcs/pcs-xpcs-wx.c:107:\ttxgbe_write_pma(xpcs, TXGBE_AFE_DFE_ENABLE, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:108:\ttxgbe_write_pma(xpcs, TXGBE_RX_EQ_CTL4, TXGBE_RX_EQ_CTL4_CONT_OFF_CAN0);\ndrivers/net/pcs/pcs-xpcs-wx.c:109:\ttxgbe_write_pma(xpcs, TXGBE_TX_RATE_CTL, TXGBE_TX_RATE_CTL_TX0_RATE(3));\ndrivers/net/pcs/pcs-xpcs-wx.c:110:\ttxgbe_write_pma(xpcs, TXGBE_RX_RATE_CTL, TXGBE_RX_RATE_CTL_RX0_RATE(3));\ndrivers/net/pcs/pcs-xpcs-wx.c:111:\ttxgbe_write_pma(xpcs, TXGBE_TX_GEN_CTL2, TXGBE_TX_GEN_CTL2_TX0_WIDTH(1));\ndrivers/net/pcs/pcs-xpcs-wx.c:112:\ttxgbe_write_pma(xpcs, TXGBE_RX_GEN_CTL2, TXGBE_RX_GEN_CTL2_RX0_WIDTH(1));\ndrivers/net/pcs/pcs-xpcs-wx.c:113:\ttxgbe_write_pma(xpcs, TXGBE_MPLLA_CTL2, TXGBE_MPLLA_CTL2_DIV10_CLK_EN);\ndrivers/net/pcs/pcs-xpcs-wx.c-114-}\ndrivers/net/pcs/pcs-xpcs-wx.c-115-\ndrivers/net/pcs/pcs-xpcs-wx.c:116:static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-117-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-119-\ndrivers/net/pcs/pcs-xpcs-wx.c:120:\t/* Wait xpcs power-up good */\ndrivers/net/pcs/pcs-xpcs-wx.c:121:\tret = read_poll_timeout(xpcs_read_vpcs, val,\ndrivers/net/pcs/pcs-xpcs-wx.c-122-\t\t\t\t(val \u0026 DW_PSEQ_ST) == DW_PSEQ_ST_GOOD,\ndrivers/net/pcs/pcs-xpcs-wx.c-123-\t\t\t\t10000, 1000000, false,\ndrivers/net/pcs/pcs-xpcs-wx.c:124:\t\t\t\txpcs, DW_VR_XS_PCS_DIG_STS);\ndrivers/net/pcs/pcs-xpcs-wx.c-125-\tif (ret \u003c 0)\ndrivers/net/pcs/pcs-xpcs-wx.c:126:\t\tdev_err(\u0026xpcs-\u003emdiodev-\u003edev, \"xpcs power-up timeout\\n\");\ndrivers/net/pcs/pcs-xpcs-wx.c-127-\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-130-\ndrivers/net/pcs/pcs-xpcs-wx.c:131:static int txgbe_pma_init_done(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-132-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-134-\ndrivers/net/pcs/pcs-xpcs-wx.c:135:\txpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1, DW_VR_RST | DW_EN_VSMMD1);\ndrivers/net/pcs/pcs-xpcs-wx.c-136-\ndrivers/net/pcs/pcs-xpcs-wx.c-137-\t/* wait pma initialization done */\ndrivers/net/pcs/pcs-xpcs-wx.c:138:\tret = read_poll_timeout(xpcs_read_vpcs, val, !(val \u0026 DW_VR_RST),\ndrivers/net/pcs/pcs-xpcs-wx.c-139-\t\t\t\t100000, 10000000, false,\ndrivers/net/pcs/pcs-xpcs-wx.c:140:\t\t\t\txpcs, DW_VR_XS_PCS_DIG_CTRL1);\ndrivers/net/pcs/pcs-xpcs-wx.c-141-\tif (ret \u003c 0)\ndrivers/net/pcs/pcs-xpcs-wx.c:142:\t\tdev_err(\u0026xpcs-\u003emdiodev-\u003edev, \"xpcs pma initialization timeout\\n\");\ndrivers/net/pcs/pcs-xpcs-wx.c-143-\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-146-\ndrivers/net/pcs/pcs-xpcs-wx.c:147:static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-148-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-151-\t/* When txgbe do LAN reset, PCS will change to default 10GBASE-R mode */\ndrivers/net/pcs/pcs-xpcs-wx.c:152:\tret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL2);\ndrivers/net/pcs/pcs-xpcs-wx.c-153-\tret \u0026= MDIO_PCS_CTRL2_TYPE;\ndrivers/net/pcs/pcs-xpcs-wx.c-154-\tif ((ret == MDIO_PCS_CTRL2_10GBR \u0026\u0026\ndrivers/net/pcs/pcs-xpcs-wx.c:155:\t xpcs-\u003einterface != PHY_INTERFACE_MODE_10GBASER) ||\ndrivers/net/pcs/pcs-xpcs-wx.c:156:\t xpcs-\u003einterface == PHY_INTERFACE_MODE_SGMII)\ndrivers/net/pcs/pcs-xpcs-wx.c-157-\t\treturn true;\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-161-\ndrivers/net/pcs/pcs-xpcs-wx.c:162:int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)\ndrivers/net/pcs/pcs-xpcs-wx.c-163-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-174-\ndrivers/net/pcs/pcs-xpcs-wx.c:175:\tif (xpcs-\u003einterface == interface \u0026\u0026 !txgbe_xpcs_mode_quirk(xpcs))\ndrivers/net/pcs/pcs-xpcs-wx.c-176-\t\treturn 0;\ndrivers/net/pcs/pcs-xpcs-wx.c-177-\ndrivers/net/pcs/pcs-xpcs-wx.c:178:\txpcs-\u003einterface = interface;\ndrivers/net/pcs/pcs-xpcs-wx.c-179-\ndrivers/net/pcs/pcs-xpcs-wx.c:180:\tret = txgbe_pcs_poll_power_up(xpcs);\ndrivers/net/pcs/pcs-xpcs-wx.c-181-\tif (ret \u003c 0)\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-184-\tif (interface == PHY_INTERFACE_MODE_10GBASER) {\ndrivers/net/pcs/pcs-xpcs-wx.c:185:\t\txpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR);\ndrivers/net/pcs/pcs-xpcs-wx.c:186:\t\txpcs_modify(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1,\ndrivers/net/pcs/pcs-xpcs-wx.c-187-\t\t\t MDIO_CTRL1_SPEED10G, MDIO_CTRL1_SPEED10G);\ndrivers/net/pcs/pcs-xpcs-wx.c:188:\t\ttxgbe_pma_config_10gbaser(xpcs);\ndrivers/net/pcs/pcs-xpcs-wx.c-189-\t} else {\ndrivers/net/pcs/pcs-xpcs-wx.c:190:\t\txpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX);\ndrivers/net/pcs/pcs-xpcs-wx.c:191:\t\txpcs_write(xpcs, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:192:\t\txpcs_write(xpcs, MDIO_MMD_PCS, MDIO_CTRL1, 0);\ndrivers/net/pcs/pcs-xpcs-wx.c:193:\t\ttxgbe_pma_config_1g(xpcs);\ndrivers/net/pcs/pcs-xpcs-wx.c-194-\t}\ndrivers/net/pcs/pcs-xpcs-wx.c-195-\ndrivers/net/pcs/pcs-xpcs-wx.c:196:\treturn txgbe_pma_init_done(xpcs);\ndrivers/net/pcs/pcs-xpcs-wx.c-197-}\n"
} |
| 31/2 | 2026/09/22 18:27 | llm | patch-evaluator |
2mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 55232 output: 28 thoughts: 314 Thoughts: **My Initial Assessment and Broadening Search** Okay, so I'm looking at `txgbe_xpcs_switch_mode`, and the first thing that jumps out is that it's only setting the mode for `10GBASER` or `10GBX`, and not the `DW_AN_C37_SGMII` configuration. But hold on, the real issue is more fundamental than that. I need to take a step back and make sure I'm not barking up the wrong tree. The core question is whether any of these network devices are actually *emulated* within QEMU. If they aren't emulated, then digging into their specific switch modes is likely a complete waste of time in this context. Let me quickly run through the list: `txgbe`? No, that's a Wangxun PCIe card. `sja1105` or `sja1110`? No, those are NXP automotive switches. `ksz9477`? Nope, Microchip ethernet switch. `fbnic`? Nope, that's Meta's NIC ASIC. `dwmac-intel`? No, that's Intel SoC Ethernet MAC. `dwmac-rk` or `pcs-xpcs-rk`? No, those are Rockchip SoC ethernet devices. I see no emulation in QEMU. Neither for `dwmac-renesas-gbeth`, `dwmac-rzn1`, or `dwmac-socfpga`. Okay, so none of those are emulated. That seems... restrictive! I wonder if there are *any* other users of `pcs-xpcs` at all! Let's be meticulous: I need to do a full kernel search, across the entire codebase, and find any other places where `xpcs_` is referenced. Just to be absolutely certain I'm not missing something critical. |
| 32/2 | 2026/09/22 18:29 | tool | grepper |
0mArgs:{
"Expression": "xpcs_init|xpcs_create|dw_xpcs"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 706 lines.\nUse more precise expression if possible.\n\ndrivers/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/common.h=613=struct mac_device_info {\n--\ndrivers/net/ethernet/stmicro/stmmac/common.h-622-\tconst struct stmmac_vlan_ops *vlan;\ndrivers/net/ethernet/stmicro/stmmac/common.h:623:\tstruct dw_xpcs *xpcs;\ndrivers/net/ethernet/stmicro/stmmac/common.h-624-\tstruct phylink_pcs *phylink_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-608-\tstruct fwnode_handle *devnode, *pcsnode;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c:609:\tstruct dw_xpcs *xpcs;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-intel.c-610-\tint addr;\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/stmicro/stmmac/dwmac-rk.c=1239=static int rk_pcs_init(struct stmmac_priv *priv)\n--\ndrivers/net/ethernet/stmicro/stmmac/dwmac-rk.c-1242-\tstruct device_node *pcs_node;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-rk.c:1243:\tstruct dw_xpcs *xpcs;\ndrivers/net/ethernet/stmicro/stmmac/dwmac-rk.c-1244-\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-nxp.c-71- */\ndrivers/net/pcs/pcs-xpcs-nxp.c:72:int nxp_sja1105_sgmii_pma_config(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-nxp.c-73-{\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-77-\ndrivers/net/pcs/pcs-xpcs-nxp.c:78:static int nxp_sja1110_pma_config(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs-nxp.c-79-\t\t\t\t u16 txpll_fbdiv, u16 txpll_refdiv,\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-168-\ndrivers/net/pcs/pcs-xpcs-nxp.c:169:int nxp_sja1110_sgmii_pma_config(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-nxp.c-170-{\n--\ndrivers/net/pcs/pcs-xpcs-nxp.c-173-\ndrivers/net/pcs/pcs-xpcs-nxp.c:174:int nxp_sja1110_2500basex_pma_config(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-nxp.c-175-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-26-\ndrivers/net/pcs/pcs-xpcs-plat.c:27:struct dw_xpcs_plat {\ndrivers/net/pcs/pcs-xpcs-plat.c-28-\tstruct platform_device *pdev;\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=46=static ptrdiff_t xpcs_mmio_addr_offset(ptrdiff_t csr)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-50-\ndrivers/net/pcs/pcs-xpcs-plat.c:51:static int xpcs_mmio_read_reg_indirect(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-52-\t\t\t\t int dev, int reg)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-81-\ndrivers/net/pcs/pcs-xpcs-plat.c:82:static int xpcs_mmio_write_reg_indirect(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-83-\t\t\t\t\tint dev, int reg, u16 val)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-112-\ndrivers/net/pcs/pcs-xpcs-plat.c:113:static int xpcs_mmio_read_reg_direct(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-114-\t\t\t\t int dev, int reg)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-138-\ndrivers/net/pcs/pcs-xpcs-plat.c:139:static int xpcs_mmio_write_reg_direct(struct dw_xpcs_plat *pxpcs,\ndrivers/net/pcs/pcs-xpcs-plat.c-140-\t\t\t\t int dev, int reg, u16 val)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=165=static int xpcs_mmio_read_c22(struct mii_bus *bus, int addr, int reg)\ndrivers/net/pcs/pcs-xpcs-plat.c-166-{\ndrivers/net/pcs/pcs-xpcs-plat.c:167:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-168-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=178=static int xpcs_mmio_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-plat.c-179-{\ndrivers/net/pcs/pcs-xpcs-plat.c:180:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-181-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=191=static int xpcs_mmio_read_c45(struct mii_bus *bus, int addr, int dev, int reg)\ndrivers/net/pcs/pcs-xpcs-plat.c-192-{\ndrivers/net/pcs/pcs-xpcs-plat.c:193:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-194-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=204=static int xpcs_mmio_write_c45(struct mii_bus *bus, int addr, int dev,\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-206-{\ndrivers/net/pcs/pcs-xpcs-plat.c:207:\tstruct dw_xpcs_plat *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-plat.c-208-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-217-\ndrivers/net/pcs/pcs-xpcs-plat.c:218:static struct dw_xpcs_plat *xpcs_plat_create_data(struct platform_device *pdev)\ndrivers/net/pcs/pcs-xpcs-plat.c-219-{\ndrivers/net/pcs/pcs-xpcs-plat.c:220:\tstruct dw_xpcs_plat *pxpcs;\ndrivers/net/pcs/pcs-xpcs-plat.c-221-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-232-\ndrivers/net/pcs/pcs-xpcs-plat.c:233:static int xpcs_plat_init_res(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-234-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-277-\ndrivers/net/pcs/pcs-xpcs-plat.c:278:static int xpcs_plat_init_clk(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-279-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-297-\ndrivers/net/pcs/pcs-xpcs-plat.c:298:static int xpcs_plat_init_bus(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-299-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-336- */\ndrivers/net/pcs/pcs-xpcs-plat.c:337:static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)\ndrivers/net/pcs/pcs-xpcs-plat.c-338-{\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=373=static int xpcs_plat_probe(struct platform_device *pdev)\ndrivers/net/pcs/pcs-xpcs-plat.c-374-{\ndrivers/net/pcs/pcs-xpcs-plat.c:375:\tstruct dw_xpcs_plat *pxpcs;\ndrivers/net/pcs/pcs-xpcs-plat.c-376-\tint ret;\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=401=static int __maybe_unused xpcs_plat_pm_runtime_suspend(struct device *dev)\ndrivers/net/pcs/pcs-xpcs-plat.c-402-{\ndrivers/net/pcs/pcs-xpcs-plat.c:403:\tstruct dw_xpcs_plat *pxpcs = dev_get_drvdata(dev);\ndrivers/net/pcs/pcs-xpcs-plat.c-404-\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=410=static int __maybe_unused xpcs_plat_pm_runtime_resume(struct device *dev)\ndrivers/net/pcs/pcs-xpcs-plat.c-411-{\ndrivers/net/pcs/pcs-xpcs-plat.c:412:\tstruct dw_xpcs_plat *pxpcs = dev_get_drvdata(dev);\ndrivers/net/pcs/pcs-xpcs-plat.c-413-\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-34-\ndrivers/net/pcs/pcs-xpcs-rk.c:35:struct dw_xpcs_rk {\ndrivers/net/pcs/pcs-xpcs-rk.c-36-\tstruct platform_device *pdev;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=45=static ptrdiff_t xpcs_rk_addr_format(int dev, int reg)\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-49-\ndrivers/net/pcs/pcs-xpcs-rk.c:50:static int xpcs_rk_read_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg)\ndrivers/net/pcs/pcs-xpcs-rk.c-51-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-66-\ndrivers/net/pcs/pcs-xpcs-rk.c:67:static int xpcs_rk_write_reg(struct dw_xpcs_rk *pxpcs, int dev, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-rk.c-68-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=166=static int xpcs_rk_read_c22(struct mii_bus *bus, int addr, int reg)\ndrivers/net/pcs/pcs-xpcs-rk.c-167-{\ndrivers/net/pcs/pcs-xpcs-rk.c:168:\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-rk.c-169-\tint dev;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=181=static int xpcs_rk_write_c22(struct mii_bus *bus, int addr, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-rk.c-182-{\ndrivers/net/pcs/pcs-xpcs-rk.c:183:\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-rk.c-184-\tint dev;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=196=static int xpcs_rk_read_c45(struct mii_bus *bus, int addr, int dev, int reg)\ndrivers/net/pcs/pcs-xpcs-rk.c-197-{\ndrivers/net/pcs/pcs-xpcs-rk.c:198:\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-rk.c-199-\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=210=static int xpcs_rk_write_c45(struct mii_bus *bus, int addr, int dev, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-rk.c-211-{\ndrivers/net/pcs/pcs-xpcs-rk.c:212:\tstruct dw_xpcs_rk *pxpcs = bus-\u003epriv;\ndrivers/net/pcs/pcs-xpcs-rk.c-213-\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-223-\ndrivers/net/pcs/pcs-xpcs-rk.c:224:static struct dw_xpcs_rk *xpcs_rk_create_data(struct platform_device *pdev)\ndrivers/net/pcs/pcs-xpcs-rk.c-225-{\ndrivers/net/pcs/pcs-xpcs-rk.c:226:\tstruct dw_xpcs_rk *pxpcs;\ndrivers/net/pcs/pcs-xpcs-rk.c-227-\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-238-\ndrivers/net/pcs/pcs-xpcs-rk.c:239:static int xpcs_rk_serdes_phy_init(struct dw_xpcs_rk *pxpcs)\ndrivers/net/pcs/pcs-xpcs-rk.c-240-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=251=static void xpcs_rk_serdes_phy_poweroff(void *data)\ndrivers/net/pcs/pcs-xpcs-rk.c-252-{\ndrivers/net/pcs/pcs-xpcs-rk.c:253:\tstruct dw_xpcs_rk *pxpcs = data;\ndrivers/net/pcs/pcs-xpcs-rk.c-254-\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-261-\ndrivers/net/pcs/pcs-xpcs-rk.c:262:static int xpcs_rk_serdes_phy_poweron(struct dw_xpcs_rk *pxpcs)\ndrivers/net/pcs/pcs-xpcs-rk.c-263-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-304-\ndrivers/net/pcs/pcs-xpcs-rk.c:305:static int xpcs_rk_init_res(struct dw_xpcs_rk *pxpcs)\ndrivers/net/pcs/pcs-xpcs-rk.c-306-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=331=static void xpcs_rk_exit_clk(void *data)\ndrivers/net/pcs/pcs-xpcs-rk.c-332-{\ndrivers/net/pcs/pcs-xpcs-rk.c:333:\tstruct dw_xpcs_rk *pxpcs = data;\ndrivers/net/pcs/pcs-xpcs-rk.c-334-\tstruct device *dev = \u0026pxpcs-\u003epdev-\u003edev;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-339-\ndrivers/net/pcs/pcs-xpcs-rk.c:340:static int xpcs_rk_init_clk(struct dw_xpcs_rk *pxpcs)\ndrivers/net/pcs/pcs-xpcs-rk.c-341-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-396-\ndrivers/net/pcs/pcs-xpcs-rk.c:397:static int xpcs_rk_init_bus(struct dw_xpcs_rk *pxpcs)\ndrivers/net/pcs/pcs-xpcs-rk.c-398-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=435=static int xpcs_rk_probe(struct platform_device *pdev)\ndrivers/net/pcs/pcs-xpcs-rk.c-436-{\ndrivers/net/pcs/pcs-xpcs-rk.c:437:\tstruct dw_xpcs_rk *pxpcs;\ndrivers/net/pcs/pcs-xpcs-rk.c-438-\tint ret;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=479=MODULE_DEVICE_TABLE(of, xpcs_rk_of_ids);\ndrivers/net/pcs/pcs-xpcs-rk.c-480-\ndrivers/net/pcs/pcs-xpcs-rk.c:481:struct dw_xpcs *xpcs_rk_create(struct device *dev, struct device_node *np)\ndrivers/net/pcs/pcs-xpcs-rk.c-482-{\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-485-\tstruct device_link *link;\ndrivers/net/pcs/pcs-xpcs-rk.c:486:\tstruct dw_xpcs_rk *pxpcs;\ndrivers/net/pcs/pcs-xpcs-rk.c:487:\tstruct dw_xpcs *xpcs;\ndrivers/net/pcs/pcs-xpcs-rk.c-488-\tu32 port;\n--\ndrivers/net/pcs/pcs-xpcs-rk.c-553-\ndrivers/net/pcs/pcs-xpcs-rk.c:554:\txpcs = xpcs_create_mdiodev(pxpcs-\u003ebus, (int)port);\ndrivers/net/pcs/pcs-xpcs-rk.c-555-\tif (IS_ERR(xpcs)) {\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=566=static int xpcs_rk_pm_runtime_suspend(struct device *dev)\ndrivers/net/pcs/pcs-xpcs-rk.c-567-{\ndrivers/net/pcs/pcs-xpcs-rk.c:568:\tstruct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);\ndrivers/net/pcs/pcs-xpcs-rk.c-569-\n--\ndrivers/net/pcs/pcs-xpcs-rk.c=575=static int xpcs_rk_pm_runtime_resume(struct device *dev)\ndrivers/net/pcs/pcs-xpcs-rk.c-576-{\ndrivers/net/pcs/pcs-xpcs-rk.c:577:\tstruct dw_xpcs_rk *pxpcs = dev_get_drvdata(dev);\ndrivers/net/pcs/pcs-xpcs-rk.c-578-\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-48-\ndrivers/net/pcs/pcs-xpcs-wx.c:49:static int txgbe_write_pma(struct dw_xpcs *xpcs, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs-wx.c-50-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-53-\ndrivers/net/pcs/pcs-xpcs-wx.c:54:static int txgbe_modify_pma(struct dw_xpcs *xpcs, int reg, u16 mask, u16 set)\ndrivers/net/pcs/pcs-xpcs-wx.c-55-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-59-\ndrivers/net/pcs/pcs-xpcs-wx.c:60:static void txgbe_pma_config_10gbaser(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-61-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-86-\ndrivers/net/pcs/pcs-xpcs-wx.c:87:static void txgbe_pma_config_1g(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-88-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-115-\ndrivers/net/pcs/pcs-xpcs-wx.c:116:static int txgbe_pcs_poll_power_up(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-117-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-130-\ndrivers/net/pcs/pcs-xpcs-wx.c:131:static int txgbe_pma_init_done(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-132-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-146-\ndrivers/net/pcs/pcs-xpcs-wx.c:147:static bool txgbe_xpcs_mode_quirk(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs-wx.c-148-{\n--\ndrivers/net/pcs/pcs-xpcs-wx.c-161-\ndrivers/net/pcs/pcs-xpcs-wx.c:162:int txgbe_xpcs_switch_mode(struct dw_xpcs *xpcs, phy_interface_t interface)\ndrivers/net/pcs/pcs-xpcs-wx.c-163-{\n--\ndrivers/net/pcs/pcs-xpcs.c-19-#define phylink_pcs_to_xpcs(pl_pcs) \\\ndrivers/net/pcs/pcs-xpcs.c:20:\tcontainer_of((pl_pcs), struct dw_xpcs, pcs)\ndrivers/net/pcs/pcs-xpcs.c-21-\n--\ndrivers/net/pcs/pcs-xpcs.c=145=static const int xpcs_2500basex_features[] = {\n--\ndrivers/net/pcs/pcs-xpcs.c-153-\ndrivers/net/pcs/pcs-xpcs.c:154:struct dw_xpcs_compat {\ndrivers/net/pcs/pcs-xpcs.c-155-\tphy_interface_t interface;\n--\ndrivers/net/pcs/pcs-xpcs.c-157-\tint an_mode;\ndrivers/net/pcs/pcs-xpcs.c:158:\tint (*pma_config)(struct dw_xpcs *xpcs);\ndrivers/net/pcs/pcs-xpcs.c-159-};\ndrivers/net/pcs/pcs-xpcs.c-160-\ndrivers/net/pcs/pcs-xpcs.c:161:struct dw_xpcs_desc {\ndrivers/net/pcs/pcs-xpcs.c-162-\tu32 id;\ndrivers/net/pcs/pcs-xpcs.c-163-\tu32 mask;\ndrivers/net/pcs/pcs-xpcs.c:164:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-165-};\ndrivers/net/pcs/pcs-xpcs.c-166-\ndrivers/net/pcs/pcs-xpcs.c:167:static const struct dw_xpcs_compat *\ndrivers/net/pcs/pcs-xpcs.c:168:xpcs_find_compat(struct dw_xpcs *xpcs, phy_interface_t interface)\ndrivers/net/pcs/pcs-xpcs.c-169-{\ndrivers/net/pcs/pcs-xpcs.c:170:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-171-\n--\ndrivers/net/pcs/pcs-xpcs.c-178-\ndrivers/net/pcs/pcs-xpcs.c:179:struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs.c-180-{\n--\ndrivers/net/pcs/pcs-xpcs.c=183=EXPORT_SYMBOL_GPL(xpcs_to_phylink_pcs);\ndrivers/net/pcs/pcs-xpcs.c-184-\ndrivers/net/pcs/pcs-xpcs.c:185:int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface)\ndrivers/net/pcs/pcs-xpcs.c-186-{\ndrivers/net/pcs/pcs-xpcs.c:187:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-188-\n--\ndrivers/net/pcs/pcs-xpcs.c=195=EXPORT_SYMBOL_GPL(xpcs_get_an_mode);\ndrivers/net/pcs/pcs-xpcs.c-196-\ndrivers/net/pcs/pcs-xpcs.c:197:static bool __xpcs_linkmode_supported(const struct dw_xpcs_compat *compat,\ndrivers/net/pcs/pcs-xpcs.c-198-\t\t\t\t enum ethtool_link_mode_bit_indices linkmode)\n--\ndrivers/net/pcs/pcs-xpcs.c-211-\ndrivers/net/pcs/pcs-xpcs.c:212:int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)\ndrivers/net/pcs/pcs-xpcs.c-213-{\n--\ndrivers/net/pcs/pcs-xpcs.c-216-\ndrivers/net/pcs/pcs-xpcs.c:217:int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)\ndrivers/net/pcs/pcs-xpcs.c-218-{\n--\ndrivers/net/pcs/pcs-xpcs.c-221-\ndrivers/net/pcs/pcs-xpcs.c:222:int xpcs_modify(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set)\ndrivers/net/pcs/pcs-xpcs.c-223-{\n--\ndrivers/net/pcs/pcs-xpcs.c-226-\ndrivers/net/pcs/pcs-xpcs.c:227:static int xpcs_modify_changed(struct dw_xpcs *xpcs, int dev, u32 reg,\ndrivers/net/pcs/pcs-xpcs.c-228-\t\t\t u16 mask, u16 set)\n--\ndrivers/net/pcs/pcs-xpcs.c-232-\ndrivers/net/pcs/pcs-xpcs.c:233:static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)\ndrivers/net/pcs/pcs-xpcs.c-234-{\n--\ndrivers/net/pcs/pcs-xpcs.c-237-\ndrivers/net/pcs/pcs-xpcs.c:238:static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,\ndrivers/net/pcs/pcs-xpcs.c-239-\t\t\t u16 val)\n--\ndrivers/net/pcs/pcs-xpcs.c-243-\ndrivers/net/pcs/pcs-xpcs.c:244:static int xpcs_modify_vendor(struct dw_xpcs *xpcs, int dev, int reg, u16 mask,\ndrivers/net/pcs/pcs-xpcs.c-245-\t\t\t u16 set)\n--\ndrivers/net/pcs/pcs-xpcs.c-249-\ndrivers/net/pcs/pcs-xpcs.c:250:int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)\ndrivers/net/pcs/pcs-xpcs.c-251-{\n--\ndrivers/net/pcs/pcs-xpcs.c-254-\ndrivers/net/pcs/pcs-xpcs.c:255:int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)\ndrivers/net/pcs/pcs-xpcs.c-256-{\n--\ndrivers/net/pcs/pcs-xpcs.c-259-\ndrivers/net/pcs/pcs-xpcs.c:260:static int xpcs_modify_vpcs(struct dw_xpcs *xpcs, int reg, u16 mask, u16 val)\ndrivers/net/pcs/pcs-xpcs.c-261-{\n--\ndrivers/net/pcs/pcs-xpcs.c-264-\ndrivers/net/pcs/pcs-xpcs.c:265:static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)\ndrivers/net/pcs/pcs-xpcs.c-266-{\n--\ndrivers/net/pcs/pcs-xpcs.c-277-\ndrivers/net/pcs/pcs-xpcs.c:278:static int xpcs_soft_reset(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c:279:\t\t\t const struct dw_xpcs_compat *compat)\ndrivers/net/pcs/pcs-xpcs.c-280-{\n--\ndrivers/net/pcs/pcs-xpcs.c-309-\ndrivers/net/pcs/pcs-xpcs.c:310:static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-311-\t\t\t struct phylink_link_state *state,\n--\ndrivers/net/pcs/pcs-xpcs.c-357-\ndrivers/net/pcs/pcs-xpcs.c:358:static void xpcs_link_up_usxgmii(struct dw_xpcs *xpcs, int speed)\ndrivers/net/pcs/pcs-xpcs.c-359-{\n--\ndrivers/net/pcs/pcs-xpcs.c-406-\ndrivers/net/pcs/pcs-xpcs.c:407:static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c:408:\t\t\t\t const struct dw_xpcs_compat *compat)\ndrivers/net/pcs/pcs-xpcs.c-409-{\n--\ndrivers/net/pcs/pcs-xpcs.c-451-\ndrivers/net/pcs/pcs-xpcs.c:452:static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c:453:\t\t\t\tconst struct dw_xpcs_compat *compat)\ndrivers/net/pcs/pcs-xpcs.c-454-{\n--\ndrivers/net/pcs/pcs-xpcs.c-465-\ndrivers/net/pcs/pcs-xpcs.c:466:static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-467-\t\t\t struct phylink_link_state *state,\ndrivers/net/pcs/pcs-xpcs.c:468:\t\t\t const struct dw_xpcs_compat *compat, u16 an_stat1)\ndrivers/net/pcs/pcs-xpcs.c-469-{\n--\ndrivers/net/pcs/pcs-xpcs.c-488-\ndrivers/net/pcs/pcs-xpcs.c:489:static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-490-\t\t\t struct phylink_link_state *state, u16 an_stat1)\n--\ndrivers/net/pcs/pcs-xpcs.c-515-\ndrivers/net/pcs/pcs-xpcs.c:516:static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-517-\t\t\t\t struct phylink_link_state *state)\n--\ndrivers/net/pcs/pcs-xpcs.c-569-\ndrivers/net/pcs/pcs-xpcs.c:570:static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-571-\t\t\t\t struct phylink_link_state *state)\n--\ndrivers/net/pcs/pcs-xpcs.c-596-\ndrivers/net/pcs/pcs-xpcs.c:597:static int xpcs_resolve_pma(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-598-\t\t\t struct phylink_link_state *state)\n--\ndrivers/net/pcs/pcs-xpcs.c=645=static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,\n--\ndrivers/net/pcs/pcs-xpcs.c-648-\t__ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };\ndrivers/net/pcs/pcs-xpcs.c:649:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c:650:\tstruct dw_xpcs *xpcs;\ndrivers/net/pcs/pcs-xpcs.c-651-\tint i;\n--\ndrivers/net/pcs/pcs-xpcs.c=670=static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,\n--\ndrivers/net/pcs/pcs-xpcs.c-672-{\ndrivers/net/pcs/pcs-xpcs.c:673:\tstruct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);\ndrivers/net/pcs/pcs-xpcs.c:674:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-675-\n--\ndrivers/net/pcs/pcs-xpcs.c-696-\ndrivers/net/pcs/pcs-xpcs.c:697:static void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)\ndrivers/net/pcs/pcs-xpcs.c-698-{\ndrivers/net/pcs/pcs-xpcs.c:699:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-700-\n--\ndrivers/net/pcs/pcs-xpcs.c-704-\ndrivers/net/pcs/pcs-xpcs.c:705:static int xpcs_switch_interface_mode(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-706-\t\t\t\t phy_interface_t interface)\n--\ndrivers/net/pcs/pcs-xpcs.c=721=static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface)\ndrivers/net/pcs/pcs-xpcs.c-722-{\ndrivers/net/pcs/pcs-xpcs.c:723:\tstruct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);\ndrivers/net/pcs/pcs-xpcs.c:724:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-725-\tint ret;\n--\ndrivers/net/pcs/pcs-xpcs.c-749-\ndrivers/net/pcs/pcs-xpcs.c:750:static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-751-\t\t\t\t unsigned int neg_mode)\n--\ndrivers/net/pcs/pcs-xpcs.c-839-\ndrivers/net/pcs/pcs-xpcs.c:840:static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-841-\t\t\t\t\t unsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c-908-\ndrivers/net/pcs/pcs-xpcs.c:909:static int xpcs_config_2500basex(struct dw_xpcs *xpcs)\ndrivers/net/pcs/pcs-xpcs.c-910-{\n--\ndrivers/net/pcs/pcs-xpcs.c-924-\ndrivers/net/pcs/pcs-xpcs.c:925:static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,\ndrivers/net/pcs/pcs-xpcs.c-926-\t\t\t const unsigned long *advertising,\n--\ndrivers/net/pcs/pcs-xpcs.c-928-{\ndrivers/net/pcs/pcs-xpcs.c:929:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-930-\tint ret;\n--\ndrivers/net/pcs/pcs-xpcs.c=985=static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c-989-{\ndrivers/net/pcs/pcs-xpcs.c:990:\tstruct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);\ndrivers/net/pcs/pcs-xpcs.c-991-\n--\ndrivers/net/pcs/pcs-xpcs.c-994-\ndrivers/net/pcs/pcs-xpcs.c:995:static int xpcs_get_state_c73(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-996-\t\t\t struct phylink_link_state *state,\ndrivers/net/pcs/pcs-xpcs.c:997:\t\t\t const struct dw_xpcs_compat *compat)\ndrivers/net/pcs/pcs-xpcs.c-998-{\n--\ndrivers/net/pcs/pcs-xpcs.c-1067-\ndrivers/net/pcs/pcs-xpcs.c:1068:static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-1069-\t\t\t\t struct phylink_link_state *state)\n--\ndrivers/net/pcs/pcs-xpcs.c-1125-\ndrivers/net/pcs/pcs-xpcs.c:1126:static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-1127-\t\t\t\t\tunsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c-1161-\ndrivers/net/pcs/pcs-xpcs.c:1162:static int xpcs_get_state_2500basex(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-1163-\t\t\t\t struct phylink_link_state *state)\n--\ndrivers/net/pcs/pcs-xpcs.c=1184=static void xpcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c-1186-{\ndrivers/net/pcs/pcs-xpcs.c:1187:\tstruct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);\ndrivers/net/pcs/pcs-xpcs.c:1188:\tconst struct dw_xpcs_compat *compat;\ndrivers/net/pcs/pcs-xpcs.c-1189-\tint ret;\n--\ndrivers/net/pcs/pcs-xpcs.c-1227-\ndrivers/net/pcs/pcs-xpcs.c:1228:static void xpcs_link_up_sgmii_1000basex(struct dw_xpcs *xpcs,\ndrivers/net/pcs/pcs-xpcs.c-1229-\t\t\t\t\t unsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c=1259=static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,\n--\ndrivers/net/pcs/pcs-xpcs.c-1261-{\ndrivers/net/pcs/pcs-xpcs.c:1262:\tstruct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);\ndrivers/net/pcs/pcs-xpcs.c-1263-\n--\ndrivers/net/pcs/pcs-xpcs.c=1280=static void xpcs_an_restart(struct phylink_pcs *pcs)\n\n"
} |
| 33/2 | 2026/09/22 18:29 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 67610 output: 185 thoughts: 1485 Thoughts: **Fuzzing Verdict: Not Worthy** Okay, this is pretty straightforward. I've broken down the code affected by this patch and it's clear it's not worth fuzzing. The patch touches several areas, let's go through it step by step. First, we have drivers like `pcs-xpcs-rk.c`, `dwmac-rk.c`, `dwmac-renesas-gbeth.c`, `dwmac-rzn1.c`, `dwmac-socfpga.c`, `dwmac-intel.c`, `phy-rockchip-naneng-combphy.c`, and related device tree bindings and helper functions in `stmmac_mdio.c` and `pcs-xpcs.c`. These include drivers for Rockchip, Renesas, Intel SoCFPGA, and Intel Ethernet controllers. Now, considering the target architecture and environment, we're dealing with amd64 and standard virtualized setups like QEMU and GCE. I know these environments intimately. Looking at the device emulation in QEMU, we have various virtual network interfaces, disks, and USB devices, but *none* of the aforementioned drivers are emulated in this setup. Crucially, none of the XPCS hardware controllers, Rockchip, Renesas, or Intel SoCFPGA are emulated in QEMU on x86_64, as their drivers are platform-specific. I double-checked if there was some platform driver emulation or a mock bus that might probe any of these, but no dice. The Rockchip drivers, for instance, depend on `ARCH_ROCKCHIP`. The Intel drivers need specific PCI IDs. The Renesas and Intel SoCFPGA drivers are clearly platform-specific. And, importantly, STMMAC and XPCS are used by hardware that isn't emulated in QEMU. Given the criteria for *not* fuzzing, this patch hits all the marks. The modified code falls into three categories: documentation and MAINTAINERS changes, architecture-exclusive code (ARM64 device tree sources specifically), and, most importantly, structurally unreachable hardware. We have Rockchip, Renesas, and Intel SoCFPGA platform drivers that are SoC-specific and not present in QEMU. The Intel PCI driver requires specific Intel SoC hardware. Then there are the XPCS drivers. The STMMAC helpers are exclusively used by physical Ethernet controllers and switches that aren't emulated. Therefore, `WorthFuzzing` has to be `false` here, no question. The reasoning is solid. The `FocusSymbols` and `EnableConfigs` are empty, as expected. I've double-checked all requirements. This is a clear call. I'm satisfied. I'll now call `set-results`. |
| 34/2 | 2026/09/22 18:29 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch series introduces a Rockchip RK3568 XPCS platform driver, updates the Rockchip DWMAC and Combphy drivers, refactors PCS setup across STMMAC platform drivers (including Intel, Renesas, and SoCFPGA), and adjusts auto-negotiation in the Synopsys DW XPCS driver. All modified code is either non-kernel documentation, architecture-specific device trees (arm64), or belongs to drivers for physical SoC platform devices and vendor-specific Ethernet controllers (Rockchip, Renesas, SoCFPGA, Intel DWMAC PCI) that require physical hardware not emulated in standard QEMU/GCE amd64 virtual machines. Consequently, the modified code is structurally unreachable for fuzzing.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series introduces a Rockchip RK3568 XPCS platform driver, updates the Rockchip DWMAC and Combphy drivers, refactors PCS setup across STMMAC platform drivers (including Intel, Renesas, and SoCFPGA), and adjusts auto-negotiation in the Synopsys DW XPCS driver. All modified code is either non-kernel documentation, architecture-specific device trees (arm64), or belongs to drivers for physical SoC platform devices and vendor-specific Ethernet controllers (Rockchip, Renesas, SoCFPGA, Intel DWMAC PCI) that require physical hardware not emulated in standard QEMU/GCE amd64 virtual machines. Consequently, the modified code is structurally unreachable for fuzzing.",
"WorthFuzzing": false
} |
| 35/1 | 2026/09/22 18:29 | 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) |
|---|