| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/10/20 15:55 | flow | patch-triage |
2mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch series adds support for the Motorcomm YT9224 Ethernet switch chip and its associated DSA tagging protocol (DSA_TAG_PROTO_YT922X). The switch is a physical ASIC connected via an MDIO bus with Device Tree probing (motorcomm,yt9224), which is not present or emulated in standard QEMU amd64 virtualized fuzzing environments. Furthermore, the new tagging protocol tag_yt922x cannot be bound or exercised by any virtual or alternate switch. Therefore, the modified code is structurally unreachable.",
"WorthFuzzing": false
} |
| 1/1 | 2026/10/20 15:55 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit e3e6475d2e8a1f243bce39588991bbadb8419a32\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Oct 20 15:55:28 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 23e9194483d9b..f10a2e4edae71 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -18431,11 +18431,13 @@ F:\tdrivers/net/phy/motorcomm.c\n \n MOTORCOMM YT921X ETHERNET SWITCH DRIVER\n M:\tDavid Yang \u003cmmyangfl@gmail.com\u003e\n+M:\tKyle Switch \u003ckyle.switch@motor-comm.com\u003e\n L:\tnetdev@vger.kernel.org\n S:\tMaintained\n F:\tDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml\n F:\tdrivers/net/dsa/motorcomm/\n F:\tnet/dsa/tag_yt921x.c\n+F:\tnet/dsa/tag_yt922x.c\n \n MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD\n M:\tJiri Slaby \u003cjirislaby@kernel.org\u003e\ndiff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig\nindex 79cdd79a1fd25..648c49d6c5271 100644\n--- a/drivers/net/dsa/motorcomm/Kconfig\n+++ b/drivers/net/dsa/motorcomm/Kconfig\n@@ -1,11 +1,12 @@\n # SPDX-License-Identifier: GPL-2.0-only\n config NET_DSA_YT921X\n-\ttristate \"Motorcomm YT9215 ethernet switch chip support\"\n+\ttristate \"Motorcomm YT9215 and YT9224 ethernet switch chip support\"\n \tselect NET_DSA_TAG_YT921X\n+\tselect NET_DSA_TAG_YT922X\n \tselect NET_IEEE8021Q_HELPERS if DCB\n \thelp\n-\t This enables support for the Motorcomm YT9215 ethernet switch\n-\t chip.\n+\t This enables support for the Motorcomm YT9215 and YT9224\n+\t ethernet switch chip.\n \n config NET_DSA_YT921X_LEDS\n \tbool \"LED support for Motorcomm YT9215\"\ndiff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile\nindex 9eaa59f699e8a..3ca151358d194 100644\n--- a/drivers/net/dsa/motorcomm/Makefile\n+++ b/drivers/net/dsa/motorcomm/Makefile\n@@ -4,6 +4,7 @@ yt921x-objs := chip.o\n yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o\n yt921x-objs += mdio_bus.o\n yt921x-objs += mib.o\n+yt921x-objs += pcs-922x.o\n yt921x-objs += pcs-921x.o\n yt921x-objs += smi.o\n yt921x-objs += tc.o\ndiff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c\nindex e2b5c89f7e774..74b5e341213d3 100644\n--- a/drivers/net/dsa/motorcomm/chip.c\n+++ b/drivers/net/dsa/motorcomm/chip.c\n@@ -1,6 +1,6 @@\n // SPDX-License-Identifier: GPL-2.0-or-later\n /*\n- * Driver for Motorcomm YT921x Switch\n+ * Driver for Motorcomm YT921x and YT922x Switch\n *\n * Should work on YT9213/YT9214/YT9215/YT9218, but only tested on YT9215+SGMII,\n * be sure to do your own checks before porting to another chip.\n@@ -76,6 +76,12 @@ static const struct yt921x_info yt921x_infos[] = {\n \t\tBIT(8) | BIT(9),\n \t\tBIT(8) | BIT(9),\n \t},\n+\t{\n+\t\t\"YT9224\", YT9224_MAJOR, 0, 0,\n+\t\tGENMASK(7, 4),\n+\t\t0,\n+\t\tBIT(8) | BIT(0),\n+\t},\n \t{}\n };\n \n@@ -2150,6 +2156,11 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds)\n #endif\n }\n \n+static bool yt921x_needs_extmode_check(u32 major)\n+{\n+\treturn (major == YT9224_MAJOR) ? false : true;\n+}\n+\n static int yt921x_chip_detect(struct yt921x_priv *priv)\n {\n \tstruct device *dev = yt921x_priv_to_device(priv);\n@@ -2175,6 +2186,14 @@ static int yt921x_chip_detect(struct yt921x_priv *priv)\n \t\treturn -ENODEV;\n \t}\n \n+\tif (!yt921x_needs_extmode_check(major)) {\n+\t\tdev_info(dev,\n+\t\t\t \"Motorcomm %s ethernet switch, chipid: 0x%x\\n\",\n+\t\t\t info-\u003ename, chipid);\n+\t\tpriv-\u003einfo = info;\n+\t\treturn 0;\n+\t}\n+\n \tres = yt921x_reg_read(priv, YT921X_CHIP_MODE, \u0026mode);\n \tif (res)\n \t\treturn res;\n@@ -2285,7 +2304,7 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)\n \tif (res)\n \t\treturn res;\n \n-\tctrl = GENMASK(10, 0);\n+\tctrl = GENMASK_U32(10, 0);\n \tres = yt921x_reg_write(priv, YT921X_FILTER_UNK_UCAST, ctrl);\n \tif (res)\n \t\treturn res;\n@@ -2580,6 +2599,542 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {\n \t.setup\t\t\t= yt921x_dsa_setup,\n };\n \n+static int yt922x_port_down(struct yt921x_priv *priv, int port)\n+{\n+\tu32 mask;\n+\tint res;\n+\n+\t/* mac force down */\n+\tmask = YT922X_PORT_LINK | YT922X_PORT_RX_MAC_EN |\n+\tYT922X_PORT_TX_MAC_EN | YT922X_PORT_LINK_AN;\n+\tres = yt921x_reg_clear_bits(priv, YT922X_PORTn_CTRL(port), mask);\n+\tif (res)\n+\t\treturn res;\n+\t/* Need force op to make soft configuration effective */\n+\tmask = YT922X_PORT_FORCE_OP;\n+\tres = yt921x_reg_set_bits(priv, YT922X_PORTn_CTRL(port), mask);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* disable en_phy */\n+\tres = yt921x_reg_clear_bits(priv, YT922X_EN_PHY_VALUE, BIT(port));\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_set_bits(priv, YT922X_EN_PHY_OVERWRITE, BIT(port));\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n+static void\n+yt922x_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,\n+\t\t\t phy_interface_t interface)\n+{\n+\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(dp-\u003eds);\n+\tint port = dp-\u003eindex;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_port_down(priv, port);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dp-\u003eds-\u003edev, \"Failed to %s port %d: %i\\n\", \"bring down\",\n+\t\t\tport, res);\n+}\n+\n+static int\n+yt922x_port_up(struct yt921x_priv *priv, int port, unsigned int mode,\n+\t phy_interface_t interface, int speed, int duplex,\n+\t bool tx_pause, bool rx_pause)\n+{\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tint ps = ethtool_speed_to_yt921x(speed);\n+\tu32 ctrl = 0;\n+\tu32 mask;\n+\tint res;\n+\n+\tif (ps == YT921X_SPEED_INVALID)\n+\t\treturn -EINVAL;\n+\n+\tmask = YT922X_PORT_SPEED_M | YT922X_PORT_TX_MAC_EN |\n+\t YT922X_PORT_RX_MAC_EN | YT922X_PORT_TX_PAUSE |\n+\t YT922X_PORT_RX_PAUSE | YT922X_PORT_DUPLEX_FULL |\n+\t YT922X_PORT_LINK_AN | YT922X_PORT_CFG_RX_EN |\n+\t YT922X_PORT_CFG_TX_EN | YT922X_PORT_FC_AN |\n+\t YT922X_PORT_LINK;\n+\n+\tctrl |= ps;\n+\n+\tif (duplex == DUPLEX_FULL)\n+\t\tctrl |= YT922X_PORT_DUPLEX_FULL;\n+\tif (tx_pause)\n+\t\tctrl |= YT922X_PORT_TX_PAUSE;\n+\tif (rx_pause)\n+\t\tctrl |= YT922X_PORT_RX_PAUSE;\n+\tctrl |= YT922X_PORT_RX_MAC_EN | YT922X_PORT_TX_MAC_EN |\n+\t\t\tYT922X_PORT_CFG_TX_EN | YT922X_PORT_CFG_RX_EN;\n+\n+\t/*\n+\t * Self-negotiation: the LINK/AN bits in ctrl are set based to inband.\n+\t * Forced mode: set LINK, keep the AN bit at 0 and clear it via the mask\n+\t */\n+\tif (pp-\u003einband)\n+\t\tctrl |= (YT922X_PORT_FC_AN | YT922X_PORT_LINK_AN);\n+\telse\n+\t\tctrl |= YT922X_PORT_LINK;\n+\n+\tres = yt921x_reg_update_bits(priv, YT922X_PORTn_CTRL(port), mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* force op */\n+\tmask = YT922X_PORT_FORCE_OP;\n+\tres = yt921x_reg_set_bits(priv, YT922X_PORTn_CTRL(port), mask);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* enable en_phy */\n+\tres = yt921x_reg_set_bits(priv, YT922X_EN_PHY_VALUE, BIT(port));\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_set_bits(priv, YT922X_EN_PHY_OVERWRITE, BIT(port));\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n+static void\n+yt922x_phylink_mac_link_up(struct phylink_config *config,\n+\t\t\t struct phy_device *phydev, unsigned int mode,\n+\t\t\t phy_interface_t interface, int speed, int duplex,\n+\t\t\t bool tx_pause, bool rx_pause)\n+{\n+\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(dp-\u003eds);\n+\tint port = dp-\u003eindex;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_port_up(priv, port, mode, interface, speed, duplex,\n+\t\t\t tx_pause, rx_pause);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dp-\u003eds-\u003edev, \"Failed to %s port %d: %i\\n\", \"bring up\",\n+\t\t\tport, res);\n+}\n+\n+static int\n+yt922x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,\n+\t\t phy_interface_t interface)\n+{\n+\tstruct device *dev = yt921x_priv_to_device(priv);\n+\tconst struct yt921x_info *info = priv-\u003einfo;\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\n+\tif (BIT(port) \u0026 info-\u003einternal_mask) {\n+\t\tif (interface != PHY_INTERFACE_MODE_INTERNAL)\n+\t\t\tgoto err;\n+\t\treturn 0;\n+\t}\n+\n+\tswitch (interface) {\n+\t/* SERDES */\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\tcase PHY_INTERFACE_MODE_USXGMII:\n+\t\tif (!(BIT(port) \u0026 info-\u003eserdes_mask))\n+\t\t\tgoto err;\n+\t\tpp-\u003eserdes = true;\n+\t\tbreak;\n+\tdefault:\n+\t\tgoto err;\n+\t}\n+\n+\treturn 0;\n+\n+err:\n+\tdev_err(dev, \"Wrong mode %d on port %d\\n\", interface, port);\n+\treturn -EINVAL;\n+}\n+\n+static void\n+yt922x_phylink_mac_config(struct phylink_config *config, unsigned int mode,\n+\t\t\t const struct phylink_link_state *state)\n+{\n+\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(dp-\u003eds);\n+\tint port = dp-\u003eindex;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_port_config(priv, port, mode, state-\u003einterface);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dp-\u003eds-\u003edev, \"Failed to %s port %d: %i\\n\", \"config\",\n+\t\t\tport, res);\n+}\n+\n+static struct phylink_pcs *\n+yt922x_phylink_mac_select_pcs(struct phylink_config *config,\n+\t\t\t phy_interface_t interface)\n+{\n+\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(dp-\u003eds);\n+\n+\tswitch (interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\tcase PHY_INTERFACE_MODE_USXGMII:\n+\t\treturn \u0026priv-\u003eports[dp-\u003eindex].pcs;\n+\n+\tdefault:\n+\t\treturn NULL;\n+\t}\n+}\n+\n+static const struct phylink_mac_ops yt922x_phylink_mac_ops = {\n+\t.mac_select_pcs = yt922x_phylink_mac_select_pcs,\n+\t.mac_link_down = yt922x_phylink_mac_link_down,\n+\t.mac_link_up = yt922x_phylink_mac_link_up,\n+\t.mac_config = yt922x_phylink_mac_config,\n+};\n+\n+static enum dsa_tag_protocol\n+yt922x_dsa_get_tag_protocol(struct dsa_switch *ds, int port,\n+\t\t\t enum dsa_tag_protocol m)\n+{\n+\treturn DSA_TAG_PROTO_YT922X;\n+}\n+\n+static void\n+yt922x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,\n+\t\t\t struct phylink_config *config)\n+{\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(ds);\n+\tconst struct yt921x_info *info = priv-\u003einfo;\n+\n+\tconfig-\u003emac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |\n+\t\t\t\t MAC_10 | MAC_100 | MAC_1000;\n+\n+\tif (info-\u003einternal_mask \u0026 BIT(port)) {\n+\t\t/* port 4 to port 7, internal utp */\n+\t\t__set_bit(PHY_INTERFACE_MODE_INTERNAL,\n+\t\t\t config-\u003esupported_interfaces);\n+\t\tconfig-\u003emac_capabilities |= MAC_2500FD;\n+\t}\n+\tif (info-\u003eserdes_mask \u0026 BIT(port)) {\n+\t\t/* serdes */\n+\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n+\t\t\t config-\u003esupported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n+\t\t\t config-\u003esupported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_2500BASEX,\n+\t\t\t config-\u003esupported_interfaces);\n+\t\tconfig-\u003emac_capabilities |= MAC_2500FD;\n+\t\t__set_bit(PHY_INTERFACE_MODE_USXGMII,\n+\t\t\t config-\u003esupported_interfaces);\n+\t\tconfig-\u003emac_capabilities |= MAC_5000FD;\n+\t\tconfig-\u003emac_capabilities |= MAC_10000FD;\n+\t}\n+}\n+\n+static int yt922x_port_setup(struct yt921x_priv *priv, int port)\n+{\n+\tstruct dsa_switch *ds = \u0026priv-\u003eds;\n+\tu32 mask;\n+\tu32 ctrl;\n+\tint res;\n+\n+\t/* enable user port isolation and disable fdb learning */\n+\tctrl = ~priv-\u003ecpu_ports_mask;\n+\tres = yt921x_reg_write(priv, YT922X_PORTn_ISOLATION(port), ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmask = YT922X_PORT_LEARN_DIS;\n+\tres = yt921x_reg_set_bits(priv, YT922X_PORTn_LEARN(port), mask);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif (dsa_is_cpu_port(ds, port)) {\n+\t\tctrl = ~(u32)0;\n+\t\tres = yt921x_reg_write(priv, YT922X_PORTn_ISOLATION(port),\n+\t\t\t\t ctrl);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int yt922x_dsa_port_setup(struct dsa_switch *ds, int port)\n+{\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(ds);\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_port_setup(priv, port);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static int yt922x_cpu_tag_mode_set_8b(struct yt921x_priv *priv)\n+{\n+\tu32 val;\n+\tu32 val1;\n+\tint res;\n+\n+\t/* cpu tag mode set to 8b */\n+\tres = yt921x_reg_read(priv, YT922X_CPU_TAG_RX_CTRL, \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_read(priv, YT922X_CPU_TAG_TX_CTRL, \u0026val1);\n+\tif (res)\n+\t\treturn res;\n+\tval \u0026= ~YT922X_CPU_TAG_RX_MODE;\n+\tval1 \u0026= ~YT922X_CPU_TAG_TX_MODE;\n+\tval1 \u0026= ~YT922X_CPU_TAG_TX_TYPE;\n+\tres = yt921x_reg_write(priv, YT922X_CPU_TAG_RX_CTRL, val);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT922X_CPU_TAG_TX_CTRL, val1);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n+static int yt922x_cpu_port_set(struct yt921x_priv *priv)\n+{\n+\tstruct dsa_switch *ds = \u0026priv-\u003eds;\n+\tu32 ctrl;\n+\tint res;\n+\n+\t/* cpu tag mode */\n+\tres = yt922x_cpu_tag_mode_set_8b(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* Enable DSA */\n+\tpriv-\u003ecpu_ports_mask = dsa_cpu_ports(ds);\n+\tctrl = YT921X_EXT_CPU_PORT_TAG_EN | YT921X_EXT_CPU_PORT_PORT_EN |\n+\t YT921X_EXT_CPU_PORT_PORT(__ffs(priv-\u003ecpu_ports_mask));\n+\tres = yt921x_reg_write(priv, YT921X_EXT_CPU_PORT, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* Setup software switch */\n+\tctrl = YT922X_CPU_COPY_TO_EXT_CPU;\n+\tres = yt921x_reg_write(priv, YT922X_CPU_COPY, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn res;\n+}\n+\n+static int yt922x_chip_setup_dsa(struct yt921x_priv *priv)\n+{\n+\tunsigned long cpu_ports_mask;\n+\tu32 ctrl;\n+\tint port;\n+\tint res;\n+\n+\t/* cpu port set */\n+\tres = yt922x_cpu_port_set(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\tctrl = GENMASK_U32(8, 0);\n+\tres = yt921x_reg_write(priv, YT922X_FILTER_UNK_UCAST, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tctrl = 0;\n+\tfor (int i = 0; i \u003c priv-\u003eseries-\u003emax_ports; i++)\n+\t\tctrl |= YT922X_ACT_UNK_ACTn_TRAP(i);\n+\tcpu_ports_mask = priv-\u003ecpu_ports_mask;\n+\tfor_each_set_bit(port, \u0026cpu_ports_mask, priv-\u003eseries-\u003emax_ports) {\n+\t\tctrl \u0026= ~YT922X_ACT_UNK_ACTn_M(port);\n+\t\tctrl |= YT922X_ACT_UNK_ACTn_DROP(port);\n+\t}\n+\tres = yt921x_reg_write(priv, YT922X_ACT_UNK_UCAST, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT922X_ACT_UNK_MCAST, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n+static int yt922x_chip_setup(struct yt921x_priv *priv)\n+{\n+\tu32 ctrl;\n+\tint res;\n+\n+\tctrl = YT922X_FUNC_MIB | YT922X_FUNC_ACL;\n+\tres = yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tres = yt922x_chip_setup_dsa(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n+static void yt922x_pcs_setup(struct dsa_switch *ds)\n+{\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(ds);\n+\tconst struct yt921x_info *info = priv-\u003einfo;\n+\tunsigned long mask;\n+\tint port;\n+\n+\tmask = info-\u003eserdes_mask;\n+\tfor_each_set_bit(port, \u0026mask, priv-\u003eseries-\u003emax_ports) {\n+\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\n+\t\tpp-\u003epcs.ops = \u0026yt922x_phylink_pcs_ops;\n+\t\tpp-\u003epcs.poll = true;\n+\n+\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n+\t\t\t pp-\u003epcs.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n+\t\t\t pp-\u003epcs.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_2500BASEX,\n+\t\t\t pp-\u003epcs.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_USXGMII,\n+\t\t\t pp-\u003epcs.supported_interfaces);\n+\t}\n+}\n+\n+static int yt922x_dsa_setup(struct dsa_switch *ds)\n+{\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(ds);\n+\tstruct device *dev = yt921x_priv_to_device(priv);\n+\tstruct device_node *np = dev-\u003eof_node;\n+\tstruct device_node *child;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_chip_reset(priv);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* Register the internal mdio bus. */\n+\tchild = of_get_child_by_name(np, \"mdio\");\n+\tif (child) {\n+\t\tres = yt921x_mbus_int_init(priv, child);\n+\t\tof_node_put(child);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_chip_setup(priv);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* switch sds pcs setup */\n+\tyt922x_pcs_setup(ds);\n+\n+\treturn 0;\n+}\n+\n+static const struct dsa_switch_ops yt922x_dsa_switch_ops = {\n+\t/* port */\n+\t.get_tag_protocol = yt922x_dsa_get_tag_protocol,\n+\t.phylink_get_caps = yt922x_dsa_phylink_get_caps,\n+\t.port_setup = yt922x_dsa_port_setup,\n+\t/* chip */\n+\t.setup = yt922x_dsa_setup,\n+};\n+\n+static const struct yt92xx_series yt92xx_series_table[] = {\n+\t[YT92XX_MODE_YT921X] = {\n+\t\t.name = \"YT921x\",\n+\t\t.max_ports = YT921X_PORT_NUM,\n+\t\t.num_lag_ids = YT921X_LAG_NUM,\n+\t\t.ageing_time_min = 1 * 5000,\n+\t\t.ageing_time_max = U16_MAX * 5000,\n+\t\t.dscp_prio_mapping_is_global = true,\n+\t\t.assisted_learning_on_cpu_port = true,\n+\t\t.switch_ops = \u0026yt921x_dsa_switch_ops,\n+\t\t.mac_ops = \u0026yt921x_phylink_mac_ops\n+\t},\n+\t[YT92XX_MODE_YT922X] = {\n+\t\t.name = \"YT922x\",\n+\t\t.max_ports = YT922X_PORT_NUM,\n+\t\t.num_lag_ids = YT922X_LAG_NUM,\n+\t\t.ageing_time_min = 1 * 6000,\n+\t\t.ageing_time_max = U16_MAX * 6000,\n+\t\t.dscp_prio_mapping_is_global = true,\n+\t\t.assisted_learning_on_cpu_port = true,\n+\t\t.switch_ops = \u0026yt922x_dsa_switch_ops,\n+\t\t.mac_ops = \u0026yt922x_phylink_mac_ops,\n+\t},\n+};\n+\n+static const struct yt92xx_series *yt92xx_series_lookup(u32 major)\n+{\n+\tif (major == YT9215_MAJOR || major == YT9218_MAJOR)\n+\t\treturn \u0026yt92xx_series_table[YT92XX_MODE_YT921X];\n+\telse if (major == YT9224_MAJOR)\n+\t\treturn \u0026yt92xx_series_table[YT92XX_MODE_YT922X];\n+\telse\n+\t\treturn NULL;\n+}\n+\n+static int yt92xx_register_switch(struct dsa_switch *ds)\n+{\n+\tstruct yt921x_priv *priv = dsa_to_yt921x_priv(ds);\n+\tstruct device *dev = yt921x_priv_to_device(priv);\n+\tconst struct yt92xx_series *series;\n+\tu32 chipid;\n+\tu32 major;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_reg_read(priv, YT921X_CHIP_ID, \u0026chipid);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmajor = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);\n+\tseries = yt92xx_series_lookup(major);\n+\tif (!series) {\n+\t\tdev_err(dev, \"Chip ID: 0x%x, and Unknown major.\\n\", chipid);\n+\t\treturn -ENODEV;\n+\t}\n+\tpriv-\u003eseries = series;\n+\n+\tds-\u003eassisted_learning_on_cpu_port =\n+\t\tpriv-\u003eseries-\u003eassisted_learning_on_cpu_port;\n+\tds-\u003edscp_prio_mapping_is_global =\n+\t\tpriv-\u003eseries-\u003edscp_prio_mapping_is_global;\n+\tds-\u003eageing_time_min = priv-\u003eseries-\u003eageing_time_min;\n+\tds-\u003eageing_time_max = priv-\u003eseries-\u003eageing_time_max;\n+\tds-\u003enum_lag_ids = priv-\u003eseries-\u003enum_lag_ids;\n+\tds-\u003enum_ports = priv-\u003eseries-\u003emax_ports;\n+\tds-\u003eops = priv-\u003eseries-\u003eswitch_ops;\n+\tds-\u003ephylink_mac_ops = priv-\u003eseries-\u003emac_ops;\n+\n+\treturn 0;\n+}\n+\n static void yt921x_mdio_shutdown(struct mdio_device *mdiodev)\n {\n \tstruct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);\n@@ -2622,6 +3177,7 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)\n \tstruct yt921x_reg_mdio *mdio;\n \tstruct yt921x_priv *priv;\n \tstruct dsa_switch *ds;\n+\tint res;\n \n \tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n \tif (!priv)\n@@ -2648,15 +3204,10 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)\n \n \tds = \u0026priv-\u003eds;\n \tds-\u003edev = dev;\n-\tds-\u003eassisted_learning_on_cpu_port = true;\n-\tds-\u003edscp_prio_mapping_is_global = true;\n \tds-\u003epriv = priv;\n-\tds-\u003eops = \u0026yt921x_dsa_switch_ops;\n-\tds-\u003eageing_time_min = 1 * 5000;\n-\tds-\u003eageing_time_max = U16_MAX * 5000;\n-\tds-\u003ephylink_mac_ops = \u0026yt921x_phylink_mac_ops;\n-\tds-\u003enum_lag_ids = YT921X_LAG_NUM;\n-\tds-\u003enum_ports = YT921X_PORT_NUM;\n+\tres = yt92xx_register_switch(ds);\n+\tif (res)\n+\t\treturn res;\n \n \tmdiodev_set_drvdata(mdiodev, priv);\n \n@@ -2665,6 +3216,7 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)\n \n static const struct of_device_id yt921x_of_match[] = {\n \t{ .compatible = \"motorcomm,yt9215\" },\n+\t{ .compatible = \"motorcomm,yt9224\" },\n \t{}\n };\n MODULE_DEVICE_TABLE(of, yt921x_of_match);\n@@ -2682,5 +3234,6 @@ static struct mdio_driver yt921x_mdio_driver = {\n mdio_module_driver(yt921x_mdio_driver);\n \n MODULE_AUTHOR(\"David Yang \u003cmmyangfl@gmail.com\u003e\");\n-MODULE_DESCRIPTION(\"Driver for Motorcomm YT921x Switch\");\n+MODULE_AUTHOR(\"Kyle Switch \u003ckyle.switch@motor-comm.com\u003e\");\n+MODULE_DESCRIPTION(\"Driver for Motorcomm YT921x and YT922x Switch\");\n MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h\nindex 7047ad98f4317..cc35dec2e52f1 100644\n--- a/drivers/net/dsa/motorcomm/chip.h\n+++ b/drivers/net/dsa/motorcomm/chip.h\n@@ -119,6 +119,7 @@ enum yt921x_speed {\n \tYT921X_SPEED_1000,\n \tYT921X_SPEED_10000,\n \tYT921X_SPEED_2500,\n+\tYT921X_SPEED_5000,\n \tYT921X_SPEED_INVALID\n };\n \n@@ -431,6 +432,7 @@ enum yt921x_fdb_entry_status {\n \n #define YT9215_MAJOR\t0x9002\n #define YT9218_MAJOR\t0x9001\n+#define YT9224_MAJOR\t0x9004\n \n /* required for a hard reset */\n #define YT921X_RST_DELAY_US\t10000\n@@ -450,6 +452,84 @@ enum yt921x_fdb_entry_status {\n \n #define YT921X_NAME\t\"yt921x\"\n \n+/* yt922x register lists */\n+#define YT92XX_PAGE_SELECT\t0x1e\n+#define YT92XX_PAGE\t\t0x1f\n+#define YT922X_EN_PHY_OVERWRITE\t\t(0x80040)\n+#define YT922X_EN_PHY_VALUE\t\t(0x8003c)\n+/* CTRL: force op to make soft configuration effective */\n+#define YT922X_PORTn_CTRL(port)\t\t(0x80080 + 4 * (port))\n+#define YT922X_PORT_FORCE_OP\t\t\tBIT(14)\n+#define YT922X_PORT_CFG_TX_EN\t\t\tBIT(13)\n+#define YT922X_PORT_CFG_RX_EN\t\t\tBIT(12)\n+#define YT922X_PORT_FC_AN\t\t\tBIT(11)\n+#define YT922X_PORT_LINK_AN\t\t\tBIT(10) /* CTRL: auto negotiation */\n+#define YT922X_PORT_LINK\t\t\tBIT(9) /* CTRL: link status */\n+#define YT922X_PORT_HALF_PAUSE\t\t\tBIT(8) /* Half-duplex back pressure mode */\n+#define YT922X_PORT_DUPLEX_FULL\t\tBIT(7)\n+#define YT922X_PORT_RX_PAUSE\t\t\tBIT(6)\n+#define YT922X_PORT_TX_PAUSE\t\t\tBIT(5)\n+#define YT922X_PORT_RX_MAC_EN\t\t\tBIT(4)\n+#define YT922X_PORT_TX_MAC_EN\t\t\tBIT(3)\n+#define YT922X_PORT_SPEED_M\t\t\tGENMASK(2, 0)\n+#define YT922X_PORT_SDSn\t\t0x400\n+#define YT922X_SERDES_MODE_M\t\t\tGENMASK(6, 4)\n+#define YT922X_SERDES_MODE(x)\t\t\t\tFIELD_PREP(YT922X_SERDES_MODE_M, (x))\n+#define YT922X_SERDES_MODE_SGMII\tYT922X_SERDES_MODE(0)\n+#define YT922X_SERDES_MODE_REVSGMII\tYT922X_SERDES_MODE(1)\n+#define YT922X_SERDES_MODE_1000BASEX\tYT922X_SERDES_MODE(2)\n+#define YT922X_SERDES_MODE_100BASEX\tYT922X_SERDES_MODE(3)\n+#define YT922X_SERDES_MODE_2500BASEX\tYT922X_SERDES_MODE(4)\n+#define YT922X_SERDES_MODE_USXGMII\tYT922X_SERDES_MODE(6)\n+#define YT922X_PORT_NUM\t\t\t9\n+#define YT922X_PCS_LINK_CTRL\t\t0x11\n+#define YT922X_PCS_LINK_STATUS\t\tBIT(10)\n+#define YT922X_PCS_AN_COMPLETE\t\tBIT(11)\n+#define YT922X_PCS_WRITE_PROTECT 0x4be\n+\n+#define YT922X_LAG_NUM\t\t\t4\n+\n+#define YT922X_PORTn_ISOLATION(port)\t(0x180d80 + 0x4 * (port))\n+\n+#define YT922X_PORTn_LEARN(port)\t(0x180300 + 4 * (port))\n+#define YT922X_PORT_LEARN_DIS\t\t\tBIT(18)\n+\n+#define YT922X_FUNC_ACL\t\t\tBIT(5)\n+#define YT922X_FUNC_MIB\t\t\tBIT(4)\n+\n+#define YT922X_FILTER_UNK_UCAST\t\t0x180ec8\n+#define YT922X_ACT_UNK_UCAST\t\t0x180ed8\n+#define YT922X_ACT_UNK_MCAST\t\t0x180ee0\n+#define YT922X_ACT_UNK_MCAST_BYPASS_DROP_PIM\tBIT(22)\n+#define YT922X_ACT_UNK_MCAST_BYPASS_DROP_MLD\tBIT(21)\n+#define YT922X_ACT_UNK_MCAST_BYPASS_DROP_IGMP\tBIT(20)\n+#define YT922X_ACT_UNK_ACTn_M(port)\t\t\tGENMASK(2 * (port) + 1, 2 * (port))\n+#define YT922X_ACT_UNK_ACTn(port, x)\t\t\t((x) \u003c\u003c (2 * (port)))\n+#define YT922X_ACT_UNK_ACTn_FORWARD(port)\t\tYT922X_ACT_UNK_ACTn(port, 0) /* flood */\n+#define YT922X_ACT_UNK_ACTn_DROP(port)\t\t\tYT922X_ACT_UNK_ACTn(port, 1) /* discard */\n+#define YT922X_ACT_UNK_ACTn_TRAP(port)\t\t\tYT922X_ACT_UNK_ACTn(port, 3) /* steer to CPU */\n+\n+#define YT922X_CPU_COPY\t\t\t0x181100\n+#define YT922X_CPU_COPY_TO_INT_CPU\t\tBIT(1)\n+#define YT922X_CPU_COPY_TO_EXT_CPU\t\tBIT(0)\n+#define YT922X_CPU_TAG_RX_CTRL\t\t0x80504\n+#define YT922X_CPU_TAG_RX_MODE\t\t\tBIT(0)\n+#define YT922X_CPU_TAG_TX_CTRL\t\t0x100710\n+#define YT922X_CPU_TAG_TX_TYPE\t\tBIT(0)\n+#define YT922X_CPU_TAG_TX_MODE\t\tBIT(1)\n+#define YT922X_CPU_TAG_TX_CTAG_OP\tBIT(2)\n+#define YT922X_CPU_TAG_TX_STAG_OP\tBIT(3)\n+/* Define top ext addr for yt922x */\n+#define YT922X_COMMON_EXT_PHYADDR 9\n+\n+enum yt922x_phy_reg_type {\n+\tYT922X_PHY_REG_TYPE_COMMON_EXT,\n+\tYT922X_PHY_REG_TYPE_SDS_COMMON_EXT,\n+\tYT922X_PHY_REG_TYPE_MII,\n+\tYT922X_PHY_REG_TYPE_EXT,\n+\tYT922X_PHY_REG_TYPE_MAX\n+};\n+\n struct yt921x_port {\n \tunsigned char index;\n \n@@ -503,9 +583,28 @@ static inline u16 yt921x_info_ports_mask(const struct yt921x_info *info)\n \treturn info-\u003einternal_mask | info-\u003exmii_mask | info-\u003eserdes_mask;\n }\n \n+enum yt92xx_mode {\n+\tYT92XX_MODE_YT921X,\n+\tYT92XX_MODE_YT922X,\n+\tYT92XX_MODE_MAX,\n+};\n+\n+struct yt92xx_series {\n+\tconst char *name;\n+\tunsigned int max_ports;\n+\tunsigned int num_lag_ids;\n+\tunsigned int ageing_time_min;\n+\tunsigned int ageing_time_max;\n+\tu32 dscp_prio_mapping_is_global;\n+\tu32 assisted_learning_on_cpu_port;\n+\tconst struct dsa_switch_ops *switch_ops;\n+\tconst struct phylink_mac_ops *mac_ops;\n+};\n+\n struct yt921x_priv {\n \tstruct dsa_switch ds;\n \n+\tconst struct yt92xx_series *series;\n \tconst struct yt921x_info *info;\n \tunsigned int meter_slot_ns;\n \tunsigned int port_shape_slot_ns;\n@@ -550,6 +649,8 @@ static inline int ethtool_speed_to_yt921x(int speed)\n \t\treturn YT921X_SPEED_2500;\n \tcase SPEED_10000:\n \t\treturn YT921X_SPEED_10000;\n+\tcase SPEED_5000:\n+\t\treturn YT921X_SPEED_5000;\n \tdefault:\n \t\treturn YT921X_SPEED_INVALID;\n \t}\ndiff --git a/drivers/net/dsa/motorcomm/mdio_bus.c b/drivers/net/dsa/motorcomm/mdio_bus.c\nindex dd6c52f37bbf5..d545f338bd9d3 100644\n--- a/drivers/net/dsa/motorcomm/mdio_bus.c\n+++ b/drivers/net/dsa/motorcomm/mdio_bus.c\n@@ -107,13 +107,52 @@ yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,\n \treturn 1;\n }\n \n+/* intif extend register read/write api */\n+int\n+yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg, u16 val)\n+{\n+\tint res;\n+\n+\tif (port \u003e priv-\u003eseries-\u003emax_ports)\n+\t\treturn -ENODEV;\n+\n+\tres = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);\n+\tif (res)\n+\t\treturn res;\n+\n+\tres = yt921x_intif_write(priv, port, YT92XX_PAGE, val);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n+int\n+yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\n+{\n+\tint res;\n+\n+\tif (port \u003e priv-\u003eseries-\u003emax_ports)\n+\t\treturn -ENODEV;\n+\n+\tres = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);\n+\tif (res)\n+\t\treturn res;\n+\n+\tres = yt921x_intif_read(priv, port, YT92XX_PAGE, valp);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\n+}\n+\n static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)\n {\n \tstruct yt921x_priv *priv = mbus-\u003epriv;\n \tu16 val;\n \tint res;\n \n-\tif (port \u003e= YT921X_PORT_NUM)\n+\tif (port \u003e= priv-\u003eseries-\u003emax_ports)\n \t\treturn U16_MAX;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\n@@ -131,7 +170,7 @@ yt921x_mbus_int_write(struct mii_bus *mbus, int port, int reg, u16 data)\n \tstruct yt921x_priv *priv = mbus-\u003epriv;\n \tint res;\n \n-\tif (port \u003e= YT921X_PORT_NUM)\n+\tif (port \u003e= priv-\u003eseries-\u003emax_ports)\n \t\treturn -ENODEV;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\n@@ -145,6 +184,7 @@ int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)\n {\n \tstruct device *dev = yt921x_priv_to_device(priv);\n \tstruct mii_bus *mbus;\n+\tu32 max_ports;\n \tint res;\n \n \tmbus = devm_mdiobus_alloc(dev);\n@@ -157,7 +197,8 @@ int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)\n \tmbus-\u003eread = yt921x_mbus_int_read;\n \tmbus-\u003ewrite = yt921x_mbus_int_write;\n \tmbus-\u003eparent = dev;\n-\tmbus-\u003ephy_mask = (u32)~GENMASK(YT921X_PORT_NUM - 1, 0);\n+\tmax_ports = priv-\u003eseries-\u003emax_ports;\n+\tmbus-\u003ephy_mask = ~GENMASK_U32(max_ports - 1, 0);\n \n \tres = devm_of_mdiobus_register(dev, mbus, mnp);\n \tif (res)\n@@ -297,3 +338,4 @@ int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)\n \n \treturn 0;\n }\n+\ndiff --git a/drivers/net/dsa/motorcomm/mdio_bus.h b/drivers/net/dsa/motorcomm/mdio_bus.h\nindex e79b725d435bd..238a35891cb15 100644\n--- a/drivers/net/dsa/motorcomm/mdio_bus.h\n+++ b/drivers/net/dsa/motorcomm/mdio_bus.h\n@@ -35,6 +35,10 @@ struct yt921x_priv;\n \n int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp);\n int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val);\n+int yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg,\n+\t\t\t u16 val);\n+int yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg,\n+\t\t\t u16 *valp);\n int yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,\n \t\t\t\tu16 mask, u16 val);\n \ndiff --git a/drivers/net/dsa/motorcomm/pcs-922x.c b/drivers/net/dsa/motorcomm/pcs-922x.c\nnew file mode 100644\nindex 0000000000000..5ad7873e0df7e\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/pcs-922x.c\n@@ -0,0 +1,282 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Copyright (c) 2026 Kyle Switch\n+ */\n+\n+#include \"chip.h\"\n+#include \"mdio_bus.h\"\n+#include \"pcs.h\"\n+#include \"smi.h\"\n+\n+#define to_device(priv) ((priv)-\u003eds.dev)\n+\n+static int yt922x_sds_phyaddr_get(int port,\n+\t\t\t\t enum yt922x_phy_reg_type reg_type)\n+{\n+\tif (reg_type == YT922X_PHY_REG_TYPE_COMMON_EXT)\n+\t\treturn YT922X_COMMON_EXT_PHYADDR;\n+\n+\treturn port;\n+}\n+\n+static void yt922x_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,\n+\t\t\t\t struct phylink_link_state *state)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tint port = pp-\u003eindex;\n+\tu16 link_ctrl;\n+\tint res;\n+\tu16 bmsr;\n+\tint addr;\n+\tu16 lp;\n+\n+\taddr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);\n+\tif (addr \u003c 0) {\n+\t\tstate-\u003elink = false;\n+\t\treturn;\n+\t}\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tswitch (state-\u003einterface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\tres = yt921x_intif_read(priv, addr, MII_BMSR, \u0026bmsr);\n+\t\tif (res)\n+\t\t\tgoto err;\n+\t\tres = yt921x_intif_read(priv, addr, MII_LPA, \u0026lp);\n+\t\tif (res)\n+\t\t\tgoto err;\n+\t\tphylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lp);\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\t\tres = yt921x_intif_read(priv, addr, MII_BMSR, \u0026bmsr);\n+\t\tif (res)\n+\t\t\tgoto err;\n+\t\tstate-\u003espeed = SPEED_100;\n+\t\tstate-\u003eduplex = DUPLEX_FULL;\n+\t\tstate-\u003epause |= MLO_PAUSE_TX | MLO_PAUSE_RX;\n+\t\tstate-\u003elink = !!(bmsr \u0026 BMSR_LSTATUS);\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_USXGMII:\n+\t\tres = yt921x_intif_read(priv, addr, YT922X_PCS_LINK_CTRL,\n+\t\t\t\t\t\u0026link_ctrl);\n+\t\tif (res)\n+\t\t\tgoto err;\n+\t\tstate-\u003elink = FIELD_GET(YT922X_PCS_LINK_STATUS, link_ctrl);\n+\t\tstate-\u003ean_complete = FIELD_GET(YT922X_PCS_AN_COMPLETE,\n+\t\t\t\t\t link_ctrl);\n+\t\tres = yt921x_intif_read(priv, addr, MII_LPA, \u0026lp);\n+\t\tif (res)\n+\t\t\tgoto err;\n+\t\tif (state-\u003elink)\n+\t\t\tphylink_decode_usxgmii_word(state, lp);\n+\t\tbreak;\n+\tdefault:\n+\t\tstate-\u003elink = false;\n+\t\tbreak;\n+\t}\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\treturn;\n+\n+err:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tstate-\u003elink = false;\n+}\n+\n+static void yt922x_pcs_an_restart(struct phylink_pcs *pcs)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tstruct device *dev = to_device(priv);\n+\tint port = pp-\u003eindex;\n+\tu16 bmcr;\n+\tint addr;\n+\tint res;\n+\n+\taddr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);\n+\tif (addr \u003c 0) {\n+\t\tdev_err(dev, \"Invalid SDS PHY addr for port %d\\n\", port);\n+\t\treturn;\n+\t}\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_intif_read(priv, addr, MII_BMCR, \u0026bmcr);\n+\tif (res)\n+\t\tgoto err;\n+\tbmcr |= BMCR_ANRESTART;\n+\tbmcr |= BMCR_RESET;\n+\tres = yt921x_intif_write(priv, addr, MII_BMCR, bmcr);\n+\tif (res)\n+\t\tgoto err;\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\treturn;\n+\n+err:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tdev_err(dev, \"Failed to an restart PCS port %d: %i\\n\", port, res);\n+}\n+\n+static int yt922x_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,\n+\t\t\t phy_interface_t interface,\n+\t\t\t const unsigned long *advertising,\n+\t\t\t bool permit_pause_to_mac)\n+{\n+\tbool inband = neg_mode \u0026 PHYLINK_PCS_NEG_INBAND;\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tbool changed = false;\n+\tint res, port;\n+\tu16 bmcr_old;\n+\tu16 bmcr_new;\n+\tu16 data;\n+\tu16 ctrl;\n+\tint addr;\n+\tint adv;\n+\n+\tport = pp-\u003eindex;\n+\taddr = yt922x_sds_phyaddr_get\n+\t\t(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT);\n+\tif (addr \u003c 0)\n+\t\treturn addr;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\n+\t/* write protect */\n+\tres = yt921x_intif_ext_write(priv, addr, YT922X_PCS_WRITE_PROTECT, 0xd);\n+\tif (res)\n+\t\tgoto err;\n+\tswitch (interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\t\tctrl = YT922X_SERDES_MODE_SGMII;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\t\tctrl = YT922X_SERDES_MODE_100BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\t\tctrl = YT922X_SERDES_MODE_1000BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\tctrl = YT922X_SERDES_MODE_2500BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_USXGMII:\n+\t\tctrl = YT922X_SERDES_MODE_USXGMII;\n+\t\tbreak;\n+\tdefault:\n+\t\tres = -EINVAL;\n+\t\tgoto err;\n+\t}\n+\tres = yt921x_intif_ext_read(priv, addr, YT922X_PORT_SDSn, \u0026data);\n+\tif (res)\n+\t\tgoto err;\n+\tdata \u0026= ~YT922X_SERDES_MODE_M;\n+\tdata |= ctrl;\n+\tres = yt921x_intif_ext_write(priv, addr, YT922X_PORT_SDSn, data);\n+\tif (res)\n+\t\tgoto err;\n+\n+\tif (inband) {\n+\t\tadv = phylink_mii_c22_pcs_encode_advertisement(interface,\n+\t\t\t\t\t\t\t advertising);\n+\t\tif (adv \u003e= 0) {\n+\t\t\tres = yt921x_intif_modify_changed(priv, port,\n+\t\t\t\t\t\t\t MII_ADVERTISE,\n+\t\t\t\t\t\t\t U16_MAX, adv);\n+\t\t\tif (res \u003c 0)\n+\t\t\t\tgoto err;\n+\n+\t\t\tchanged = !!res;\n+\t\t}\n+\t}\n+\n+\tres = yt921x_intif_read(priv, port, MII_BMCR, \u0026bmcr_old);\n+\tif (res)\n+\t\tgoto err;\n+\n+\tbmcr_new = bmcr_old;\n+\tif (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)\n+\t\tbmcr_new |= BMCR_ANENABLE;\n+\telse\n+\t\tbmcr_new \u0026= ~BMCR_ANENABLE;\n+\n+\tchanged |= (bmcr_new != bmcr_old);\n+\n+\tres = yt921x_intif_write(priv, port, MII_BMCR, bmcr_new);\n+\tif (res)\n+\t\tgoto err;\n+\tpp-\u003einband = inband;\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn changed;\n+\n+err:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static int yt922x_pcs_enable(struct phylink_pcs *pcs)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tstruct device *dev = yt921x_priv_to_device(priv);\n+\tint port = pp-\u003eindex;\n+\tint addr;\n+\tu16 bmcr;\n+\tint res;\n+\n+\taddr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);\n+\tif (addr \u003c 0)\n+\t\treturn addr;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\n+\tres = yt921x_intif_read(priv, addr, MII_BMCR, \u0026bmcr);\n+\tif (res)\n+\t\tgoto end;\n+\n+\tbmcr \u0026= ~BMCR_PDOWN;\n+\tbmcr |= BMCR_ANRESTART;\n+\tres = yt921x_intif_write(priv, addr, MII_BMCR, bmcr);\n+\n+end:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dev, \"Failed to enable PCS port %d: %i\\n\", port, res);\n+\n+\treturn res;\n+}\n+\n+static void yt922x_pcs_disable(struct phylink_pcs *pcs)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tstruct device *dev = yt921x_priv_to_device(priv);\n+\tint port = pp-\u003eindex;\n+\tint addr;\n+\tint res;\n+\n+\taddr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);\n+\tif (addr \u003c 0) {\n+\t\tdev_err(dev, \"Invalid SDS PHY addr for port %d\\n\", port);\n+\t\treturn;\n+\t}\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_intif_modify(priv, addr, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dev, \"Failed to power down PCS port %d: %i\\n\", port,\n+\t\t\tres);\n+}\n+\n+const struct phylink_pcs_ops yt922x_phylink_pcs_ops = {\n+\t.pcs_get_state = yt922x_pcs_get_state,\n+\t.pcs_config = yt922x_pcs_config,\n+\t.pcs_an_restart = yt922x_pcs_an_restart,\n+\t.pcs_enable = yt922x_pcs_enable,\n+\t.pcs_disable = yt922x_pcs_disable,\n+};\ndiff --git a/drivers/net/dsa/motorcomm/pcs.h b/drivers/net/dsa/motorcomm/pcs.h\nindex 42426558086af..c85caa7bf2126 100644\n--- a/drivers/net/dsa/motorcomm/pcs.h\n+++ b/drivers/net/dsa/motorcomm/pcs.h\n@@ -9,5 +9,6 @@\n #include \u003clinux/phylink.h\u003e\n \n extern const struct phylink_pcs_ops yt921x_phylink_pcs_ops;\n+extern const struct phylink_pcs_ops yt922x_phylink_pcs_ops;\n \n #endif\ndiff --git a/include/net/dsa.h b/include/net/dsa.h\nindex 5d12191b6f6f5..5a173fe2bb876 100644\n--- a/include/net/dsa.h\n+++ b/include/net/dsa.h\n@@ -62,6 +62,7 @@ struct tc_action;\n #define DSA_TAG_PROTO_KSZ8463_VALUE\t\t34\n #define DSA_TAG_PROTO_MT7628_VALUE\t\t35\n #define DSA_TAG_PROTO_KS8995_VALUE\t\t36\n+#define DSA_TAG_PROTO_YT922X_VALUE\t\t37\n \n enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_NONE\t\t= DSA_TAG_PROTO_NONE_VALUE,\n@@ -101,6 +102,7 @@ enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_KSZ8463\t\t= DSA_TAG_PROTO_KSZ8463_VALUE,\n \tDSA_TAG_PROTO_MT7628\t\t= DSA_TAG_PROTO_MT7628_VALUE,\n \tDSA_TAG_PROTO_KS8995\t\t= DSA_TAG_PROTO_KS8995_VALUE,\n+\tDSA_TAG_PROTO_YT922X\t\t= DSA_TAG_PROTO_YT922X_VALUE,\n };\n \n struct dsa_switch;\ndiff --git a/net/dsa/Kconfig b/net/dsa/Kconfig\nindex 4f44bf3ede238..06d8d65260549 100644\n--- a/net/dsa/Kconfig\n+++ b/net/dsa/Kconfig\n@@ -233,4 +233,10 @@ config NET_DSA_TAG_YT921X\n \t Say Y or M if you want to enable support for tagging frames for\n \t Motorcomm YT921x switches.\n \n+config NET_DSA_TAG_YT922X\n+\ttristate \"Tag driver for Motorcomm YT922x switches\"\n+\thelp\n+\t Say Y or M if you want to enable support for tagging frames for\n+\t Motorcomm YT922x switches.\n+\n endif\ndiff --git a/net/dsa/Makefile b/net/dsa/Makefile\nindex 1f9cc30e99886..0ef6dfce3b924 100644\n--- a/net/dsa/Makefile\n+++ b/net/dsa/Makefile\n@@ -45,6 +45,7 @@ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o\n obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) += tag_vsc73xx_8021q.o\n obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o\n obj-$(CONFIG_NET_DSA_TAG_YT921X) += tag_yt921x.o\n+obj-$(CONFIG_NET_DSA_TAG_YT922X) += tag_yt922x.o\n \n # for tracing framework to find trace.h\n CFLAGS_trace.o := -I$(src)\ndiff --git a/net/dsa/tag_yt922x.c b/net/dsa/tag_yt922x.c\nnew file mode 100644\nindex 0000000000000..b6146a9af98b3\n--- /dev/null\n+++ b/net/dsa/tag_yt922x.c\n@@ -0,0 +1,122 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Motorcomm YT922x Switch Extended CPU Port Tagging\n+ *\n+ * Copyright (c) 2026 Kyle switch \u003ckyle.switch@motor-comm.com\u003e\n+ *\n+ */\n+\n+#include \u003clinux/etherdevice.h\u003e\n+\n+#include \"tag.h\"\n+\n+#define YT922X_TAG_LEN 8\n+\n+/*\n+ * To define the from cpu tag format 8 bytes.\n+ *\n+ * To-CPU (RX) tag format, 8 bytes:\n+ *\n+ * tag[0]: TPID (default: 0x9988)\n+ * tag[1]: VID lookup\n+ * tag[2]: bit 5:2 - RX source port\n+ *\n+ * From-CPU (TX) tag format, 8 bytes:\n+ *\n+ * tag[0]: TPID (default: 0x9988)\n+ * tag[1]: bit 8:0 - Dst port mask\n+ * tag[2]: bit 15 - Dst port 0\n+ *\n+ */\n+#define YT922X_TAG_NAME\t\t\"yt922x\"\n+#define YT922X_TAG_PORTMASK_0\tBIT(15)\n+#define YT922X_TAG_PORTMASK_M\tGENMASK(8, 0)\n+#define YT922X_TAG_PORTS(x)\t\tFIELD_PREP(YT922X_TAG_PORTMASK_M, (x))\n+#define YT922X_TAG_FORCE_DST\tBIT(9)\n+#define YT922X_TAG_PRIO_M\tGENMASK(12, 10)\n+#define YT922X_TAG_PRIO_EN\tBIT(13)\n+#define YT922X_TAG_PRIO(x)\t(FIELD_PREP(YT922X_TAG_PRIO_M, (x)) | YT922X_TAG_PRIO_EN)\n+#define YT922X_TAG_RX_PORT_M\tGENMASK(5, 2)\n+\n+static struct sk_buff *\n+yt922x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)\n+{\n+\tunsigned long ports;\n+\t__be16 *tag;\n+\tu16 ctrl;\n+\n+\tskb_push(skb, YT922X_TAG_LEN);\n+\tdsa_alloc_etype_header(skb, YT922X_TAG_LEN);\n+\ttag = dsa_etype_header_pos_tx(skb);\n+\n+\ttag[0] = htons(ETH_P_YT921X);\n+\tports = dsa_xmit_port_mask(skb, netdev);\n+\t/*To fill in the case where the port index is not 0 */\n+\tctrl = YT922X_TAG_PRIO(skb-\u003epriority) | YT922X_TAG_FORCE_DST |\n+\t YT922X_TAG_PORTS(ports \u003e\u003e 1);\n+\ttag[1] = htons(ctrl);\n+\tif (ports \u0026 BIT(0)) {\n+\t\t/* To fill in the case where the port index is 0 */\n+\t\tctrl = YT922X_TAG_PORTMASK_0;\n+\t\ttag[2] = htons(ctrl);\n+\t} else {\n+\t\ttag[2] = 0;\n+\t}\n+\ttag[3] = 0;\n+\n+\treturn skb;\n+}\n+\n+static struct sk_buff *\n+yt922x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)\n+{\n+\tunsigned int port;\n+\t__be16 *tag;\n+\tu16 rx;\n+\n+\tif (unlikely(!pskb_may_pull(skb, YT922X_TAG_LEN))) {\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\n+\ttag = dsa_etype_header_pos_rx(skb);\n+\n+\tif (unlikely(tag[0] != htons(ETH_P_YT921X))) {\n+\t\tdev_warn_ratelimited(\u0026netdev-\u003edev,\n+\t\t\t\t \"Unexpected EtherType 0x%04x\\n\",\n+\t\t\t\t ntohs(tag[0]));\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Locate which port this is coming from */\n+\trx = ntohs(tag[2]);\n+\tport = FIELD_GET(YT922X_TAG_RX_PORT_M, rx);\n+\tskb-\u003edev = dsa_conduit_find_user(netdev, 0, port);\n+\tif (unlikely(!skb-\u003edev)) {\n+\t\tdev_warn_ratelimited(\u0026netdev-\u003edev,\n+\t\t\t\t \"Couldn't decode source port %u\\n\", port);\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Remove tag and update checksum */\n+\tskb_pull_rcsum(skb, YT922X_TAG_LEN);\n+\tdsa_strip_etype_header(skb, YT922X_TAG_LEN);\n+\n+\treturn skb;\n+}\n+\n+static const struct dsa_device_ops yt922x_netdev_ops = {\n+\t.name = YT922X_TAG_NAME,\n+\t.proto = DSA_TAG_PROTO_YT922X,\n+\t.xmit = yt922x_tag_xmit,\n+\t.rcv = yt922x_tag_rcv,\n+\t.needed_headroom = YT922X_TAG_LEN,\n+};\n+\n+MODULE_DESCRIPTION(\"DSA tag driver for Motorcomm YT922x switches\");\n+MODULE_LICENSE(\"GPL\");\n+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT922X, YT922X_TAG_NAME);\n+\n+module_dsa_tag_driver(yt922x_netdev_ops);\n"
} |
| 2/1 | 2026/10/20 15:55 | agent | patch-evaluator |
2mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series adds support for the Motorcomm YT9224 Ethernet switch chip and its associated DSA tagging protocol (DSA_TAG_PROTO_YT922X). The switch is a physical ASIC connected via an MDIO bus with Device Tree probing (motorcomm,yt9224), which is not present or emulated in standard QEMU amd64 virtualized fuzzing environments. Furthermore, the new tagging protocol tag_yt922x cannot be bound or exercised by any virtual or alternate switch. Therefore, the modified code is structurally unreachable.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit e3e6475d2e8a1f243bce39588991bbadb8419a32
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Oct 20 15:55:28 2026 +0000
syz-cluster: applied patch under review
diff --git a/MAINTAINERS b/MAINTAINERS
index 23e9194483d9b..f10a2e4edae71 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18431,11 +18431,13 @@ F: drivers/net/phy/motorcomm.c
MOTORCOMM YT921X ETHERNET SWITCH DRIVER
M: David Yang <mmyangfl@gmail.com>
+M: Kyle Switch <kyle.switch@motor-comm.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
F: drivers/net/dsa/motorcomm/
F: net/dsa/tag_yt921x.c
+F: net/dsa/tag_yt922x.c
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
M: Jiri Slaby <jirislaby@kernel.org>
diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
index 79cdd79a1fd25..648c49d6c5271 100644
--- a/drivers/net/dsa/motorcomm/Kconfig
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -1,11 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
config NET_DSA_YT921X
- tristate "Motorcomm YT9215 ethernet switch chip support"
+ tristate "Motorcomm YT9215 and YT9224 ethernet switch chip support"
select NET_DSA_TAG_YT921X
+ select NET_DSA_TAG_YT922X
select NET_IEEE8021Q_HELPERS if DCB
help
- This enables support for the Motorcomm YT9215 ethernet switch
- chip.
+ This enables support for the Motorcomm YT9215 and YT9224
+ ethernet switch chip.
config NET_DSA_YT921X_LEDS
bool "LED support for Motorcomm YT9215"
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index 9eaa59f699e8a..3ca151358d194 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -4,6 +4,7 @@ yt921x-objs := chip.o
yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o
yt921x-objs += mdio_bus.o
yt921x-objs += mib.o
+yt921x-objs += pcs-922x.o
yt921x-objs += pcs-921x.o
yt921x-objs += smi.o
yt921x-objs += tc.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index e2b5c89f7e774..74b5e341213d3 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Driver for Motorcomm YT921x Switch
+ * Driver for Motorcomm YT921x and YT922x Switch
*
* Should work on YT9213/YT9214/YT9215/YT9218, but only tested on YT9215+SGMII,
* be sure to do your own checks before porting to another chip.
@@ -76,6 +76,12 @@ static const struct yt921x_info yt921x_infos[] = {
BIT(8) | BIT(9),
BIT(8) | BIT(9),
},
+ {
+ "YT9224", YT9224_MAJOR, 0, 0,
+ GENMASK(7, 4),
+ 0,
+ BIT(8) | BIT(0),
+ },
{}
};
@@ -2150,6 +2156,11 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds)
#endif
}
+static bool yt921x_needs_extmode_check(u32 major)
+{
+ return (major == YT9224_MAJOR) ? false : true;
+}
+
static int yt921x_chip_detect(struct yt921x_priv *priv)
{
struct device *dev = yt921x_priv_to_device(priv);
@@ -2175,6 +2186,14 @@ static int yt921x_chip_detect(struct yt921x_priv *priv)
return -ENODEV;
}
+ if (!yt921x_needs_extmode_check(major)) {
+ dev_info(dev,
+ "Motorcomm %s ethernet switch, chipid: 0x%x\n",
+ info->name, chipid);
+ priv->info = info;
+ return 0;
+ }
+
res = yt921x_reg_read(priv, YT921X_CHIP_MODE, &mode);
if (res)
return res;
@@ -2285,7 +2304,7 @@ static int yt921x_chip_setup_dsa(struct yt921x_priv *priv)
if (res)
return res;
- ctrl = GENMASK(10, 0);
+ ctrl = GENMASK_U32(10, 0);
res = yt921x_reg_write(priv, YT921X_FILTER_UNK_UCAST, ctrl);
if (res)
return res;
@@ -2580,6 +2599,542 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
.setup = yt921x_dsa_setup,
};
+static int yt922x_port_down(struct yt921x_priv *priv, int port)
+{
+ u32 mask;
+ int res;
+
+ /* mac force down */
+ mask = YT922X_PORT_LINK | YT922X_PORT_RX_MAC_EN |
+ YT922X_PORT_TX_MAC_EN | YT922X_PORT_LINK_AN;
+ res = yt921x_reg_clear_bits(priv, YT922X_PORTn_CTRL(port), mask);
+ if (res)
+ return res;
+ /* Need force op to make soft configuration effective */
+ mask = YT922X_PORT_FORCE_OP;
+ res = yt921x_reg_set_bits(priv, YT922X_PORTn_CTRL(port), mask);
+ if (res)
+ return res;
+
+ /* disable en_phy */
+ res = yt921x_reg_clear_bits(priv, YT922X_EN_PHY_VALUE, BIT(port));
+ if (res)
+ return res;
+ res = yt921x_reg_set_bits(priv, YT922X_EN_PHY_OVERWRITE, BIT(port));
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static void
+yt922x_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
+ phy_interface_t interface)
+{
+ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(dp->ds);
+ int port = dp->index;
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt922x_port_down(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ dev_err(dp->ds->dev, "Failed to %s port %d: %i\n", "bring down",
+ port, res);
+}
+
+static int
+yt922x_port_up(struct yt921x_priv *priv, int port, unsigned int mode,
+ phy_interface_t interface, int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct yt921x_port *pp = &priv->ports[port];
+ int ps = ethtool_speed_to_yt921x(speed);
+ u32 ctrl = 0;
+ u32 mask;
+ int res;
+
+ if (ps == YT921X_SPEED_INVALID)
+ return -EINVAL;
+
+ mask = YT922X_PORT_SPEED_M | YT922X_PORT_TX_MAC_EN |
+ YT922X_PORT_RX_MAC_EN | YT922X_PORT_TX_PAUSE |
+ YT922X_PORT_RX_PAUSE | YT922X_PORT_DUPLEX_FULL |
+ YT922X_PORT_LINK_AN | YT922X_PORT_CFG_RX_EN |
+ YT922X_PORT_CFG_TX_EN | YT922X_PORT_FC_AN |
+ YT922X_PORT_LINK;
+
+ ctrl |= ps;
+
+ if (duplex == DUPLEX_FULL)
+ ctrl |= YT922X_PORT_DUPLEX_FULL;
+ if (tx_pause)
+ ctrl |= YT922X_PORT_TX_PAUSE;
+ if (rx_pause)
+ ctrl |= YT922X_PORT_RX_PAUSE;
+ ctrl |= YT922X_PORT_RX_MAC_EN | YT922X_PORT_TX_MAC_EN |
+ YT922X_PORT_CFG_TX_EN | YT922X_PORT_CFG_RX_EN;
+
+ /*
+ * Self-negotiation: the LINK/AN bits in ctrl are set based to inband.
+ * Forced mode: set LINK, keep the AN bit at 0 and clear it via the mask
+ */
+ if (pp->inband)
+ ctrl |= (YT922X_PORT_FC_AN | YT922X_PORT_LINK_AN);
+ else
+ ctrl |= YT922X_PORT_LINK;
+
+ res = yt921x_reg_update_bits(priv, YT922X_PORTn_CTRL(port), mask, ctrl);
+ if (res)
+ return res;
+
+ /* force op */
+ mask = YT922X_PORT_FORCE_OP;
+ res = yt921x_reg_set_bits(priv, YT922X_PORTn_CTRL(port), mask);
+ if (res)
+ return res;
+
+ /* enable en_phy */
+ res = yt921x_reg_set_bits(priv, YT922X_EN_PHY_VALUE, BIT(port));
+ if (res)
+ return res;
+ res = yt921x_reg_set_bits(priv, YT922X_EN_PHY_OVERWRITE, BIT(port));
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static void
+yt922x_phylink_mac_link_up(struct phylink_config *config,
+ struct phy_device *phydev, unsigned int mode,
+ phy_interface_t interface, int speed, int duplex,
+ bool tx_pause, bool rx_pause)
+{
+ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(dp->ds);
+ int port = dp->index;
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt922x_port_up(priv, port, mode, interface, speed, duplex,
+ tx_pause, rx_pause);
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ dev_err(dp->ds->dev, "Failed to %s port %d: %i\n", "bring up",
+ port, res);
+}
+
+static int
+yt922x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,
+ phy_interface_t interface)
+{
+ struct device *dev = yt921x_priv_to_device(priv);
+ const struct yt921x_info *info = priv->info;
+ struct yt921x_port *pp = &priv->ports[port];
+
+ if (BIT(port) & info->internal_mask) {
+ if (interface != PHY_INTERFACE_MODE_INTERNAL)
+ goto err;
+ return 0;
+ }
+
+ switch (interface) {
+ /* SERDES */
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_100BASEX:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ case PHY_INTERFACE_MODE_USXGMII:
+ if (!(BIT(port) & info->serdes_mask))
+ goto err;
+ pp->serdes = true;
+ break;
+ default:
+ goto err;
+ }
+
+ return 0;
+
+err:
+ dev_err(dev, "Wrong mode %d on port %d\n", interface, port);
+ return -EINVAL;
+}
+
+static void
+yt922x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
+ const struct phylink_link_state *state)
+{
+ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(dp->ds);
+ int port = dp->index;
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt922x_port_config(priv, port, mode, state->interface);
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ dev_err(dp->ds->dev, "Failed to %s port %d: %i\n", "config",
+ port, res);
+}
+
+static struct phylink_pcs *
+yt922x_phylink_mac_select_pcs(struct phylink_config *config,
+ phy_interface_t interface)
+{
+ struct dsa_port *dp = dsa_phylink_to_port(config);
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(dp->ds);
+
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ case PHY_INTERFACE_MODE_USXGMII:
+ return &priv->ports[dp->index].pcs;
+
+ default:
+ return NULL;
+ }
+}
+
+static const struct phylink_mac_ops yt922x_phylink_mac_ops = {
+ .mac_select_pcs = yt922x_phylink_mac_select_pcs,
+ .mac_link_down = yt922x_phylink_mac_link_down,
+ .mac_link_up = yt922x_phylink_mac_link_up,
+ .mac_config = yt922x_phylink_mac_config,
+};
+
+static enum dsa_tag_protocol
+yt922x_dsa_get_tag_protocol(struct dsa_switch *ds, int port,
+ enum dsa_tag_protocol m)
+{
+ return DSA_TAG_PROTO_YT922X;
+}
+
+static void
+yt922x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,
+ struct phylink_config *config)
+{
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(ds);
+ const struct yt921x_info *info = priv->info;
+
+ config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+ MAC_10 | MAC_100 | MAC_1000;
+
+ if (info->internal_mask & BIT(port)) {
+ /* port 4 to port 7, internal utp */
+ __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+ config->supported_interfaces);
+ config->mac_capabilities |= MAC_2500FD;
+ }
+ if (info->serdes_mask & BIT(port)) {
+ /* serdes */
+ __set_bit(PHY_INTERFACE_MODE_SGMII,
+ config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ config->supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX,
+ config->supported_interfaces);
+ config->mac_capabilities |= MAC_2500FD;
+ __set_bit(PHY_INTERFACE_MODE_USXGMII,
+ config->supported_interfaces);
+ config->mac_capabilities |= MAC_5000FD;
+ config->mac_capabilities |= MAC_10000FD;
+ }
+}
+
+static int yt922x_port_setup(struct yt921x_priv *priv, int port)
+{
+ struct dsa_switch *ds = &priv->ds;
+ u32 mask;
+ u32 ctrl;
+ int res;
+
+ /* enable user port isolation and disable fdb learning */
+ ctrl = ~priv->cpu_ports_mask;
+ res = yt921x_reg_write(priv, YT922X_PORTn_ISOLATION(port), ctrl);
+ if (res)
+ return res;
+
+ mask = YT922X_PORT_LEARN_DIS;
+ res = yt921x_reg_set_bits(priv, YT922X_PORTn_LEARN(port), mask);
+ if (res)
+ return res;
+
+ if (dsa_is_cpu_port(ds, port)) {
+ ctrl = ~(u32)0;
+ res = yt921x_reg_write(priv, YT922X_PORTn_ISOLATION(port),
+ ctrl);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static int yt922x_dsa_port_setup(struct dsa_switch *ds, int port)
+{
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(ds);
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt922x_port_setup(priv, port);
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static int yt922x_cpu_tag_mode_set_8b(struct yt921x_priv *priv)
+{
+ u32 val;
+ u32 val1;
+ int res;
+
+ /* cpu tag mode set to 8b */
+ res = yt921x_reg_read(priv, YT922X_CPU_TAG_RX_CTRL, &val);
+ if (res)
+ return res;
+ res = yt921x_reg_read(priv, YT922X_CPU_TAG_TX_CTRL, &val1);
+ if (res)
+ return res;
+ val &= ~YT922X_CPU_TAG_RX_MODE;
+ val1 &= ~YT922X_CPU_TAG_TX_MODE;
+ val1 &= ~YT922X_CPU_TAG_TX_TYPE;
+ res = yt921x_reg_write(priv, YT922X_CPU_TAG_RX_CTRL, val);
+ if (res)
+ return res;
+ res = yt921x_reg_write(priv, YT922X_CPU_TAG_TX_CTRL, val1);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static int yt922x_cpu_port_set(struct yt921x_priv *priv)
+{
+ struct dsa_switch *ds = &priv->ds;
+ u32 ctrl;
+ int res;
+
+ /* cpu tag mode */
+ res = yt922x_cpu_tag_mode_set_8b(priv);
+ if (res)
+ return res;
+
+ /* Enable DSA */
+ priv->cpu_ports_mask = dsa_cpu_ports(ds);
+ ctrl = YT921X_EXT_CPU_PORT_TAG_EN | YT921X_EXT_CPU_PORT_PORT_EN |
+ YT921X_EXT_CPU_PORT_PORT(__ffs(priv->cpu_ports_mask));
+ res = yt921x_reg_write(priv, YT921X_EXT_CPU_PORT, ctrl);
+ if (res)
+ return res;
+
+ /* Setup software switch */
+ ctrl = YT922X_CPU_COPY_TO_EXT_CPU;
+ res = yt921x_reg_write(priv, YT922X_CPU_COPY, ctrl);
+ if (res)
+ return res;
+
+ return res;
+}
+
+static int yt922x_chip_setup_dsa(struct yt921x_priv *priv)
+{
+ unsigned long cpu_ports_mask;
+ u32 ctrl;
+ int port;
+ int res;
+
+ /* cpu port set */
+ res = yt922x_cpu_port_set(priv);
+ if (res)
+ return res;
+
+ ctrl = GENMASK_U32(8, 0);
+ res = yt921x_reg_write(priv, YT922X_FILTER_UNK_UCAST, ctrl);
+ if (res)
+ return res;
+
+ ctrl = 0;
+ for (int i = 0; i < priv->series->max_ports; i++)
+ ctrl |= YT922X_ACT_UNK_ACTn_TRAP(i);
+ cpu_ports_mask = priv->cpu_ports_mask;
+ for_each_set_bit(port, &cpu_ports_mask, priv->series->max_ports) {
+ ctrl &= ~YT922X_ACT_UNK_ACTn_M(port);
+ ctrl |= YT922X_ACT_UNK_ACTn_DROP(port);
+ }
+ res = yt921x_reg_write(priv, YT922X_ACT_UNK_UCAST, ctrl);
+ if (res)
+ return res;
+ res = yt921x_reg_write(priv, YT922X_ACT_UNK_MCAST, ctrl);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static int yt922x_chip_setup(struct yt921x_priv *priv)
+{
+ u32 ctrl;
+ int res;
+
+ ctrl = YT922X_FUNC_MIB | YT922X_FUNC_ACL;
+ res = yt921x_reg_set_bits(priv, YT921X_FUNC, ctrl);
+ if (res)
+ return res;
+
+ res = yt922x_chip_setup_dsa(priv);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static void yt922x_pcs_setup(struct dsa_switch *ds)
+{
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(ds);
+ const struct yt921x_info *info = priv->info;
+ unsigned long mask;
+ int port;
+
+ mask = info->serdes_mask;
+ for_each_set_bit(port, &mask, priv->series->max_ports) {
+ struct yt921x_port *pp = &priv->ports[port];
+
+ pp->pcs.ops = &yt922x_phylink_pcs_ops;
+ pp->pcs.poll = true;
+
+ __set_bit(PHY_INTERFACE_MODE_SGMII,
+ pp->pcs.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_1000BASEX,
+ pp->pcs.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_2500BASEX,
+ pp->pcs.supported_interfaces);
+ __set_bit(PHY_INTERFACE_MODE_USXGMII,
+ pp->pcs.supported_interfaces);
+ }
+}
+
+static int yt922x_dsa_setup(struct dsa_switch *ds)
+{
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(ds);
+ struct device *dev = yt921x_priv_to_device(priv);
+ struct device_node *np = dev->of_node;
+ struct device_node *child;
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_chip_reset(priv);
+ mutex_unlock(&priv->reg_lock);
+ if (res)
+ return res;
+
+ /* Register the internal mdio bus. */
+ child = of_get_child_by_name(np, "mdio");
+ if (child) {
+ res = yt921x_mbus_int_init(priv, child);
+ of_node_put(child);
+ if (res)
+ return res;
+ }
+
+ mutex_lock(&priv->reg_lock);
+ res = yt922x_chip_setup(priv);
+ mutex_unlock(&priv->reg_lock);
+ if (res)
+ return res;
+
+ /* switch sds pcs setup */
+ yt922x_pcs_setup(ds);
+
+ return 0;
+}
+
+static const struct dsa_switch_ops yt922x_dsa_switch_ops = {
+ /* port */
+ .get_tag_protocol = yt922x_dsa_get_tag_protocol,
+ .phylink_get_caps = yt922x_dsa_phylink_get_caps,
+ .port_setup = yt922x_dsa_port_setup,
+ /* chip */
+ .setup = yt922x_dsa_setup,
+};
+
+static const struct yt92xx_series yt92xx_series_table[] = {
+ [YT92XX_MODE_YT921X] = {
+ .name = "YT921x",
+ .max_ports = YT921X_PORT_NUM,
+ .num_lag_ids = YT921X_LAG_NUM,
+ .ageing_time_min = 1 * 5000,
+ .ageing_time_max = U16_MAX * 5000,
+ .dscp_prio_mapping_is_global = true,
+ .assisted_learning_on_cpu_port = true,
+ .switch_ops = &yt921x_dsa_switch_ops,
+ .mac_ops = &yt921x_phylink_mac_ops
+ },
+ [YT92XX_MODE_YT922X] = {
+ .name = "YT922x",
+ .max_ports = YT922X_PORT_NUM,
+ .num_lag_ids = YT922X_LAG_NUM,
+ .ageing_time_min = 1 * 6000,
+ .ageing_time_max = U16_MAX * 6000,
+ .dscp_prio_mapping_is_global = true,
+ .assisted_learning_on_cpu_port = true,
+ .switch_ops = &yt922x_dsa_switch_ops,
+ .mac_ops = &yt922x_phylink_mac_ops,
+ },
+};
+
+static const struct yt92xx_series *yt92xx_series_lookup(u32 major)
+{
+ if (major == YT9215_MAJOR || major == YT9218_MAJOR)
+ return &yt92xx_series_table[YT92XX_MODE_YT921X];
+ else if (major == YT9224_MAJOR)
+ return &yt92xx_series_table[YT92XX_MODE_YT922X];
+ else
+ return NULL;
+}
+
+static int yt92xx_register_switch(struct dsa_switch *ds)
+{
+ struct yt921x_priv *priv = dsa_to_yt921x_priv(ds);
+ struct device *dev = yt921x_priv_to_device(priv);
+ const struct yt92xx_series *series;
+ u32 chipid;
+ u32 major;
+ int res;
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
+ mutex_unlock(&priv->reg_lock);
+ if (res)
+ return res;
+
+ major = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);
+ series = yt92xx_series_lookup(major);
+ if (!series) {
+ dev_err(dev, "Chip ID: 0x%x, and Unknown major.\n", chipid);
+ return -ENODEV;
+ }
+ priv->series = series;
+
+ ds->assisted_learning_on_cpu_port =
+ priv->series->assisted_learning_on_cpu_port;
+ ds->dscp_prio_mapping_is_global =
+ priv->series->dscp_prio_mapping_is_global;
+ ds->ageing_time_min = priv->series->ageing_time_min;
+ ds->ageing_time_max = priv->series->ageing_time_max;
+ ds->num_lag_ids = priv->series->num_lag_ids;
+ ds->num_ports = priv->series->max_ports;
+ ds->ops = priv->series->switch_ops;
+ ds->phylink_mac_ops = priv->series->mac_ops;
+
+ return 0;
+}
+
static void yt921x_mdio_shutdown(struct mdio_device *mdiodev)
{
struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
@@ -2622,6 +3177,7 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)
struct yt921x_reg_mdio *mdio;
struct yt921x_priv *priv;
struct dsa_switch *ds;
+ int res;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -2648,15 +3204,10 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)
ds = &priv->ds;
ds->dev = dev;
- ds->assisted_learning_on_cpu_port = true;
- ds->dscp_prio_mapping_is_global = true;
ds->priv = priv;
- ds->ops = &yt921x_dsa_switch_ops;
- ds->ageing_time_min = 1 * 5000;
- ds->ageing_time_max = U16_MAX * 5000;
- ds->phylink_mac_ops = &yt921x_phylink_mac_ops;
- ds->num_lag_ids = YT921X_LAG_NUM;
- ds->num_ports = YT921X_PORT_NUM;
+ res = yt92xx_register_switch(ds);
+ if (res)
+ return res;
mdiodev_set_drvdata(mdiodev, priv);
@@ -2665,6 +3216,7 @@ static int yt921x_mdio_probe(struct mdio_device *mdiodev)
static const struct of_device_id yt921x_of_match[] = {
{ .compatible = "motorcomm,yt9215" },
+ { .compatible = "motorcomm,yt9224" },
{}
};
MODULE_DEVICE_TABLE(of, yt921x_of_match);
@@ -2682,5 +3234,6 @@ static struct mdio_driver yt921x_mdio_driver = {
mdio_module_driver(yt921x_mdio_driver);
MODULE_AUTHOR("David Yang <mmyangfl@gmail.com>");
-MODULE_DESCRIPTION("Driver for Motorcomm YT921x Switch");
+MODULE_AUTHOR("Kyle Switch <kyle.switch@motor-comm.com>");
+MODULE_DESCRIPTION("Driver for Motorcomm YT921x and YT922x Switch");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index 7047ad98f4317..cc35dec2e52f1 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -119,6 +119,7 @@ enum yt921x_speed {
YT921X_SPEED_1000,
YT921X_SPEED_10000,
YT921X_SPEED_2500,
+ YT921X_SPEED_5000,
YT921X_SPEED_INVALID
};
@@ -431,6 +432,7 @@ enum yt921x_fdb_entry_status {
#define YT9215_MAJOR 0x9002
#define YT9218_MAJOR 0x9001
+#define YT9224_MAJOR 0x9004
/* required for a hard reset */
#define YT921X_RST_DELAY_US 10000
@@ -450,6 +452,84 @@ enum yt921x_fdb_entry_status {
#define YT921X_NAME "yt921x"
+/* yt922x register lists */
+#define YT92XX_PAGE_SELECT 0x1e
+#define YT92XX_PAGE 0x1f
+#define YT922X_EN_PHY_OVERWRITE (0x80040)
+#define YT922X_EN_PHY_VALUE (0x8003c)
+/* CTRL: force op to make soft configuration effective */
+#define YT922X_PORTn_CTRL(port) (0x80080 + 4 * (port))
+#define YT922X_PORT_FORCE_OP BIT(14)
+#define YT922X_PORT_CFG_TX_EN BIT(13)
+#define YT922X_PORT_CFG_RX_EN BIT(12)
+#define YT922X_PORT_FC_AN BIT(11)
+#define YT922X_PORT_LINK_AN BIT(10) /* CTRL: auto negotiation */
+#define YT922X_PORT_LINK BIT(9) /* CTRL: link status */
+#define YT922X_PORT_HALF_PAUSE BIT(8) /* Half-duplex back pressure mode */
+#define YT922X_PORT_DUPLEX_FULL BIT(7)
+#define YT922X_PORT_RX_PAUSE BIT(6)
+#define YT922X_PORT_TX_PAUSE BIT(5)
+#define YT922X_PORT_RX_MAC_EN BIT(4)
+#define YT922X_PORT_TX_MAC_EN BIT(3)
+#define YT922X_PORT_SPEED_M GENMASK(2, 0)
+#define YT922X_PORT_SDSn 0x400
+#define YT922X_SERDES_MODE_M GENMASK(6, 4)
+#define YT922X_SERDES_MODE(x) FIELD_PREP(YT922X_SERDES_MODE_M, (x))
+#define YT922X_SERDES_MODE_SGMII YT922X_SERDES_MODE(0)
+#define YT922X_SERDES_MODE_REVSGMII YT922X_SERDES_MODE(1)
+#define YT922X_SERDES_MODE_1000BASEX YT922X_SERDES_MODE(2)
+#define YT922X_SERDES_MODE_100BASEX YT922X_SERDES_MODE(3)
+#define YT922X_SERDES_MODE_2500BASEX YT922X_SERDES_MODE(4)
+#define YT922X_SERDES_MODE_USXGMII YT922X_SERDES_MODE(6)
+#define YT922X_PORT_NUM 9
+#define YT922X_PCS_LINK_CTRL 0x11
+#define YT922X_PCS_LINK_STATUS BIT(10)
+#define YT922X_PCS_AN_COMPLETE BIT(11)
+#define YT922X_PCS_WRITE_PROTECT 0x4be
+
+#define YT922X_LAG_NUM 4
+
+#define YT922X_PORTn_ISOLATION(port) (0x180d80 + 0x4 * (port))
+
+#define YT922X_PORTn_LEARN(port) (0x180300 + 4 * (port))
+#define YT922X_PORT_LEARN_DIS BIT(18)
+
+#define YT922X_FUNC_ACL BIT(5)
+#define YT922X_FUNC_MIB BIT(4)
+
+#define YT922X_FILTER_UNK_UCAST 0x180ec8
+#define YT922X_ACT_UNK_UCAST 0x180ed8
+#define YT922X_ACT_UNK_MCAST 0x180ee0
+#define YT922X_ACT_UNK_MCAST_BYPASS_DROP_PIM BIT(22)
+#define YT922X_ACT_UNK_MCAST_BYPASS_DROP_MLD BIT(21)
+#define YT922X_ACT_UNK_MCAST_BYPASS_DROP_IGMP BIT(20)
+#define YT922X_ACT_UNK_ACTn_M(port) GENMASK(2 * (port) + 1, 2 * (port))
+#define YT922X_ACT_UNK_ACTn(port, x) ((x) << (2 * (port)))
+#define YT922X_ACT_UNK_ACTn_FORWARD(port) YT922X_ACT_UNK_ACTn(port, 0) /* flood */
+#define YT922X_ACT_UNK_ACTn_DROP(port) YT922X_ACT_UNK_ACTn(port, 1) /* discard */
+#define YT922X_ACT_UNK_ACTn_TRAP(port) YT922X_ACT_UNK_ACTn(port, 3) /* steer to CPU */
+
+#define YT922X_CPU_COPY 0x181100
+#define YT922X_CPU_COPY_TO_INT_CPU BIT(1)
+#define YT922X_CPU_COPY_TO_EXT_CPU BIT(0)
+#define YT922X_CPU_TAG_RX_CTRL 0x80504
+#define YT922X_CPU_TAG_RX_MODE BIT(0)
+#define YT922X_CPU_TAG_TX_CTRL 0x100710
+#define YT922X_CPU_TAG_TX_TYPE BIT(0)
+#define YT922X_CPU_TAG_TX_MODE BIT(1)
+#define YT922X_CPU_TAG_TX_CTAG_OP BIT(2)
+#define YT922X_CPU_TAG_TX_STAG_OP BIT(3)
+/* Define top ext addr for yt922x */
+#define YT922X_COMMON_EXT_PHYADDR 9
+
+enum yt922x_phy_reg_type {
+ YT922X_PHY_REG_TYPE_COMMON_EXT,
+ YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,
+ YT922X_PHY_REG_TYPE_MII,
+ YT922X_PHY_REG_TYPE_EXT,
+ YT922X_PHY_REG_TYPE_MAX
+};
+
struct yt921x_port {
unsigned char index;
@@ -503,9 +583,28 @@ static inline u16 yt921x_info_ports_mask(const struct yt921x_info *info)
return info->internal_mask | info->xmii_mask | info->serdes_mask;
}
+enum yt92xx_mode {
+ YT92XX_MODE_YT921X,
+ YT92XX_MODE_YT922X,
+ YT92XX_MODE_MAX,
+};
+
+struct yt92xx_series {
+ const char *name;
+ unsigned int max_ports;
+ unsigned int num_lag_ids;
+ unsigned int ageing_time_min;
+ unsigned int ageing_time_max;
+ u32 dscp_prio_mapping_is_global;
+ u32 assisted_learning_on_cpu_port;
+ const struct dsa_switch_ops *switch_ops;
+ const struct phylink_mac_ops *mac_ops;
+};
+
struct yt921x_priv {
struct dsa_switch ds;
+ const struct yt92xx_series *series;
const struct yt921x_info *info;
unsigned int meter_slot_ns;
unsigned int port_shape_slot_ns;
@@ -550,6 +649,8 @@ static inline int ethtool_speed_to_yt921x(int speed)
return YT921X_SPEED_2500;
case SPEED_10000:
return YT921X_SPEED_10000;
+ case SPEED_5000:
+ return YT921X_SPEED_5000;
default:
return YT921X_SPEED_INVALID;
}
diff --git a/drivers/net/dsa/motorcomm/mdio_bus.c b/drivers/net/dsa/motorcomm/mdio_bus.c
index dd6c52f37bbf5..d545f338bd9d3 100644
--- a/drivers/net/dsa/motorcomm/mdio_bus.c
+++ b/drivers/net/dsa/motorcomm/mdio_bus.c
@@ -107,13 +107,52 @@ yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,
return 1;
}
+/* intif extend register read/write api */
+int
+yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg, u16 val)
+{
+ int res;
+
+ if (port > priv->series->max_ports)
+ return -ENODEV;
+
+ res = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);
+ if (res)
+ return res;
+
+ res = yt921x_intif_write(priv, port, YT92XX_PAGE, val);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+int
+yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
+{
+ int res;
+
+ if (port > priv->series->max_ports)
+ return -ENODEV;
+
+ res = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);
+ if (res)
+ return res;
+
+ res = yt921x_intif_read(priv, port, YT92XX_PAGE, valp);
+ if (res)
+ return res;
+
+ return 0;
+}
+
static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)
{
struct yt921x_priv *priv = mbus->priv;
u16 val;
int res;
- if (port >= YT921X_PORT_NUM)
+ if (port >= priv->series->max_ports)
return U16_MAX;
mutex_lock(&priv->reg_lock);
@@ -131,7 +170,7 @@ yt921x_mbus_int_write(struct mii_bus *mbus, int port, int reg, u16 data)
struct yt921x_priv *priv = mbus->priv;
int res;
- if (port >= YT921X_PORT_NUM)
+ if (port >= priv->series->max_ports)
return -ENODEV;
mutex_lock(&priv->reg_lock);
@@ -145,6 +184,7 @@ int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)
{
struct device *dev = yt921x_priv_to_device(priv);
struct mii_bus *mbus;
+ u32 max_ports;
int res;
mbus = devm_mdiobus_alloc(dev);
@@ -157,7 +197,8 @@ int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)
mbus->read = yt921x_mbus_int_read;
mbus->write = yt921x_mbus_int_write;
mbus->parent = dev;
- mbus->phy_mask = (u32)~GENMASK(YT921X_PORT_NUM - 1, 0);
+ max_ports = priv->series->max_ports;
+ mbus->phy_mask = ~GENMASK_U32(max_ports - 1, 0);
res = devm_of_mdiobus_register(dev, mbus, mnp);
if (res)
@@ -297,3 +338,4 @@ int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)
return 0;
}
+
diff --git a/drivers/net/dsa/motorcomm/mdio_bus.h b/drivers/net/dsa/motorcomm/mdio_bus.h
index e79b725d435bd..238a35891cb15 100644
--- a/drivers/net/dsa/motorcomm/mdio_bus.h
+++ b/drivers/net/dsa/motorcomm/mdio_bus.h
@@ -35,6 +35,10 @@ struct yt921x_priv;
int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp);
int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val);
+int yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg,
+ u16 val);
+int yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg,
+ u16 *valp);
int yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,
u16 mask, u16 val);
diff --git a/drivers/net/dsa/motorcomm/pcs-922x.c b/drivers/net/dsa/motorcomm/pcs-922x.c
new file mode 100644
index 0000000000000..5ad7873e0df7e
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/pcs-922x.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 Kyle Switch
+ */
+
+#include "chip.h"
+#include "mdio_bus.h"
+#include "pcs.h"
+#include "smi.h"
+
+#define to_device(priv) ((priv)->ds.dev)
+
+static int yt922x_sds_phyaddr_get(int port,
+ enum yt922x_phy_reg_type reg_type)
+{
+ if (reg_type == YT922X_PHY_REG_TYPE_COMMON_EXT)
+ return YT922X_COMMON_EXT_PHYADDR;
+
+ return port;
+}
+
+static void yt922x_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
+ struct phylink_link_state *state)
+{
+ struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+ struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+ int port = pp->index;
+ u16 link_ctrl;
+ int res;
+ u16 bmsr;
+ int addr;
+ u16 lp;
+
+ addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);
+ if (addr < 0) {
+ state->link = false;
+ return;
+ }
+
+ mutex_lock(&priv->reg_lock);
+ switch (state->interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ res = yt921x_intif_read(priv, addr, MII_BMSR, &bmsr);
+ if (res)
+ goto err;
+ res = yt921x_intif_read(priv, addr, MII_LPA, &lp);
+ if (res)
+ goto err;
+ phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lp);
+ break;
+ case PHY_INTERFACE_MODE_100BASEX:
+ res = yt921x_intif_read(priv, addr, MII_BMSR, &bmsr);
+ if (res)
+ goto err;
+ state->speed = SPEED_100;
+ state->duplex = DUPLEX_FULL;
+ state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX;
+ state->link = !!(bmsr & BMSR_LSTATUS);
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ res = yt921x_intif_read(priv, addr, YT922X_PCS_LINK_CTRL,
+ &link_ctrl);
+ if (res)
+ goto err;
+ state->link = FIELD_GET(YT922X_PCS_LINK_STATUS, link_ctrl);
+ state->an_complete = FIELD_GET(YT922X_PCS_AN_COMPLETE,
+ link_ctrl);
+ res = yt921x_intif_read(priv, addr, MII_LPA, &lp);
+ if (res)
+ goto err;
+ if (state->link)
+ phylink_decode_usxgmii_word(state, lp);
+ break;
+ default:
+ state->link = false;
+ break;
+ }
+ mutex_unlock(&priv->reg_lock);
+ return;
+
+err:
+ mutex_unlock(&priv->reg_lock);
+ state->link = false;
+}
+
+static void yt922x_pcs_an_restart(struct phylink_pcs *pcs)
+{
+ struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+ struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+ struct device *dev = to_device(priv);
+ int port = pp->index;
+ u16 bmcr;
+ int addr;
+ int res;
+
+ addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);
+ if (addr < 0) {
+ dev_err(dev, "Invalid SDS PHY addr for port %d\n", port);
+ return;
+ }
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_intif_read(priv, addr, MII_BMCR, &bmcr);
+ if (res)
+ goto err;
+ bmcr |= BMCR_ANRESTART;
+ bmcr |= BMCR_RESET;
+ res = yt921x_intif_write(priv, addr, MII_BMCR, bmcr);
+ if (res)
+ goto err;
+ mutex_unlock(&priv->reg_lock);
+ return;
+
+err:
+ mutex_unlock(&priv->reg_lock);
+ dev_err(dev, "Failed to an restart PCS port %d: %i\n", port, res);
+}
+
+static int yt922x_pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
+ phy_interface_t interface,
+ const unsigned long *advertising,
+ bool permit_pause_to_mac)
+{
+ bool inband = neg_mode & PHYLINK_PCS_NEG_INBAND;
+ struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+ struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+ bool changed = false;
+ int res, port;
+ u16 bmcr_old;
+ u16 bmcr_new;
+ u16 data;
+ u16 ctrl;
+ int addr;
+ int adv;
+
+ port = pp->index;
+ addr = yt922x_sds_phyaddr_get
+ (port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT);
+ if (addr < 0)
+ return addr;
+
+ mutex_lock(&priv->reg_lock);
+
+ /* write protect */
+ res = yt921x_intif_ext_write(priv, addr, YT922X_PCS_WRITE_PROTECT, 0xd);
+ if (res)
+ goto err;
+ switch (interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ ctrl = YT922X_SERDES_MODE_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_100BASEX:
+ ctrl = YT922X_SERDES_MODE_100BASEX;
+ break;
+ case PHY_INTERFACE_MODE_1000BASEX:
+ ctrl = YT922X_SERDES_MODE_1000BASEX;
+ break;
+ case PHY_INTERFACE_MODE_2500BASEX:
+ ctrl = YT922X_SERDES_MODE_2500BASEX;
+ break;
+ case PHY_INTERFACE_MODE_USXGMII:
+ ctrl = YT922X_SERDES_MODE_USXGMII;
+ break;
+ default:
+ res = -EINVAL;
+ goto err;
+ }
+ res = yt921x_intif_ext_read(priv, addr, YT922X_PORT_SDSn, &data);
+ if (res)
+ goto err;
+ data &= ~YT922X_SERDES_MODE_M;
+ data |= ctrl;
+ res = yt921x_intif_ext_write(priv, addr, YT922X_PORT_SDSn, data);
+ if (res)
+ goto err;
+
+ if (inband) {
+ adv = phylink_mii_c22_pcs_encode_advertisement(interface,
+ advertising);
+ if (adv >= 0) {
+ res = yt921x_intif_modify_changed(priv, port,
+ MII_ADVERTISE,
+ U16_MAX, adv);
+ if (res < 0)
+ goto err;
+
+ changed = !!res;
+ }
+ }
+
+ res = yt921x_intif_read(priv, port, MII_BMCR, &bmcr_old);
+ if (res)
+ goto err;
+
+ bmcr_new = bmcr_old;
+ if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+ bmcr_new |= BMCR_ANENABLE;
+ else
+ bmcr_new &= ~BMCR_ANENABLE;
+
+ changed |= (bmcr_new != bmcr_old);
+
+ res = yt921x_intif_write(priv, port, MII_BMCR, bmcr_new);
+ if (res)
+ goto err;
+ pp->inband = inband;
+ mutex_unlock(&priv->reg_lock);
+
+ return changed;
+
+err:
+ mutex_unlock(&priv->reg_lock);
+
+ return res;
+}
+
+static int yt922x_pcs_enable(struct phylink_pcs *pcs)
+{
+ struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+ struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+ struct device *dev = yt921x_priv_to_device(priv);
+ int port = pp->index;
+ int addr;
+ u16 bmcr;
+ int res;
+
+ addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);
+ if (addr < 0)
+ return addr;
+
+ mutex_lock(&priv->reg_lock);
+
+ res = yt921x_intif_read(priv, addr, MII_BMCR, &bmcr);
+ if (res)
+ goto end;
+
+ bmcr &= ~BMCR_PDOWN;
+ bmcr |= BMCR_ANRESTART;
+ res = yt921x_intif_write(priv, addr, MII_BMCR, bmcr);
+
+end:
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ dev_err(dev, "Failed to enable PCS port %d: %i\n", port, res);
+
+ return res;
+}
+
+static void yt922x_pcs_disable(struct phylink_pcs *pcs)
+{
+ struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+ struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+ struct device *dev = yt921x_priv_to_device(priv);
+ int port = pp->index;
+ int addr;
+ int res;
+
+ addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII);
+ if (addr < 0) {
+ dev_err(dev, "Invalid SDS PHY addr for port %d\n", port);
+ return;
+ }
+
+ mutex_lock(&priv->reg_lock);
+ res = yt921x_intif_modify(priv, addr, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
+ mutex_unlock(&priv->reg_lock);
+
+ if (res)
+ dev_err(dev, "Failed to power down PCS port %d: %i\n", port,
+ res);
+}
+
+const struct phylink_pcs_ops yt922x_phylink_pcs_ops = {
+ .pcs_get_state = yt922x_pcs_get_state,
+ .pcs_config = yt922x_pcs_config,
+ .pcs_an_restart = yt922x_pcs_an_restart,
+ .pcs_enable = yt922x_pcs_enable,
+ .pcs_disable = yt922x_pcs_disable,
+};
diff --git a/drivers/net/dsa/motorcomm/pcs.h b/drivers/net/dsa/motorcomm/pcs.h
index 42426558086af..c85caa7bf2126 100644
--- a/drivers/net/dsa/motorcomm/pcs.h
+++ b/drivers/net/dsa/motorcomm/pcs.h
@@ -9,5 +9,6 @@
#include <linux/phylink.h>
extern const struct phylink_pcs_ops yt921x_phylink_pcs_ops;
+extern const struct phylink_pcs_ops yt922x_phylink_pcs_ops;
#endif
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 5d12191b6f6f5..5a173fe2bb876 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -62,6 +62,7 @@ struct tc_action;
#define DSA_TAG_PROTO_KSZ8463_VALUE 34
#define DSA_TAG_PROTO_MT7628_VALUE 35
#define DSA_TAG_PROTO_KS8995_VALUE 36
+#define DSA_TAG_PROTO_YT922X_VALUE 37
enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -101,6 +102,7 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_KSZ8463 = DSA_TAG_PROTO_KSZ8463_VALUE,
DSA_TAG_PROTO_MT7628 = DSA_TAG_PROTO_MT7628_VALUE,
DSA_TAG_PROTO_KS8995 = DSA_TAG_PROTO_KS8995_VALUE,
+ DSA_TAG_PROTO_YT922X = DSA_TAG_PROTO_YT922X_VALUE,
};
struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 4f44bf3ede238..06d8d65260549 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -233,4 +233,10 @@ config NET_DSA_TAG_YT921X
Say Y or M if you want to enable support for tagging frames for
Motorcomm YT921x switches.
+config NET_DSA_TAG_YT922X
+ tristate "Tag driver for Motorcomm YT922x switches"
+ help
+ Say Y or M if you want to enable support for tagging frames for
+ Motorcomm YT922x switches.
+
endif
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index 1f9cc30e99886..0ef6dfce3b924 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
obj-$(CONFIG_NET_DSA_TAG_VSC73XX_8021Q) += tag_vsc73xx_8021q.o
obj-$(CONFIG_NET_DSA_TAG_XRS700X) += tag_xrs700x.o
obj-$(CONFIG_NET_DSA_TAG_YT921X) += tag_yt921x.o
+obj-$(CONFIG_NET_DSA_TAG_YT922X) += tag_yt922x.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)
diff --git a/net/dsa/tag_yt922x.c b/net/dsa/tag_yt922x.c
new file mode 100644
index 0000000000000..b6146a9af98b3
--- /dev/null
+++ b/net/dsa/tag_yt922x.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Motorcomm YT922x Switch Extended CPU Port Tagging
+ *
+ * Copyright (c) 2026 Kyle switch <kyle.switch@motor-comm.com>
+ *
+ */
+
+#include <linux/etherdevice.h>
+
+#include "tag.h"
+
+#define YT922X_TAG_LEN 8
+
+/*
+ * To define the from cpu tag format 8 bytes.
+ *
+ * To-CPU (RX) tag format, 8 bytes:
+ *
+ * tag[0]: TPID (default: 0x9988)
+ * tag[1]: VID lookup
+ * tag[2]: bit 5:2 - RX source port
+ *
+ * From-CPU (TX) tag format, 8 bytes:
+ *
+ * tag[0]: TPID (default: 0x9988)
+ * tag[1]: bit 8:0 - Dst port mask
+ * tag[2]: bit 15 - Dst port 0
+ *
+ */
+#define YT922X_TAG_NAME "yt922x"
+#define YT922X_TAG_PORTMASK_0 BIT(15)
+#define YT922X_TAG_PORTMASK_M GENMASK(8, 0)
+#define YT922X_TAG_PORTS(x) FIELD_PREP(YT922X_TAG_PORTMASK_M, (x))
+#define YT922X_TAG_FORCE_DST BIT(9)
+#define YT922X_TAG_PRIO_M GENMASK(12, 10)
+#define YT922X_TAG_PRIO_EN BIT(13)
+#define YT922X_TAG_PRIO(x) (FIELD_PREP(YT922X_TAG_PRIO_M, (x)) | YT922X_TAG_PRIO_EN)
+#define YT922X_TAG_RX_PORT_M GENMASK(5, 2)
+
+static struct sk_buff *
+yt922x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ unsigned long ports;
+ __be16 *tag;
+ u16 ctrl;
+
+ skb_push(skb, YT922X_TAG_LEN);
+ dsa_alloc_etype_header(skb, YT922X_TAG_LEN);
+ tag = dsa_etype_header_pos_tx(skb);
+
+ tag[0] = htons(ETH_P_YT921X);
+ ports = dsa_xmit_port_mask(skb, netdev);
+ /*To fill in the case where the port index is not 0 */
+ ctrl = YT922X_TAG_PRIO(skb->priority) | YT922X_TAG_FORCE_DST |
+ YT922X_TAG_PORTS(ports >> 1);
+ tag[1] = htons(ctrl);
+ if (ports & BIT(0)) {
+ /* To fill in the case where the port index is 0 */
+ ctrl = YT922X_TAG_PORTMASK_0;
+ tag[2] = htons(ctrl);
+ } else {
+ tag[2] = 0;
+ }
+ tag[3] = 0;
+
+ return skb;
+}
+
+static struct sk_buff *
+yt922x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)
+{
+ unsigned int port;
+ __be16 *tag;
+ u16 rx;
+
+ if (unlikely(!pskb_may_pull(skb, YT922X_TAG_LEN))) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ tag = dsa_etype_header_pos_rx(skb);
+
+ if (unlikely(tag[0] != htons(ETH_P_YT921X))) {
+ dev_warn_ratelimited(&netdev->dev,
+ "Unexpected EtherType 0x%04x\n",
+ ntohs(tag[0]));
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ /* Locate which port this is coming from */
+ rx = ntohs(tag[2]);
+ port = FIELD_GET(YT922X_TAG_RX_PORT_M, rx);
+ skb->dev = dsa_conduit_find_user(netdev, 0, port);
+ if (unlikely(!skb->dev)) {
+ dev_warn_ratelimited(&netdev->dev,
+ "Couldn't decode source port %u\n", port);
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ /* Remove tag and update checksum */
+ skb_pull_rcsum(skb, YT922X_TAG_LEN);
+ dsa_strip_etype_header(skb, YT922X_TAG_LEN);
+
+ return skb;
+}
+
+static const struct dsa_device_ops yt922x_netdev_ops = {
+ .name = YT922X_TAG_NAME,
+ .proto = DSA_TAG_PROTO_YT922X,
+ .xmit = yt922x_tag_xmit,
+ .rcv = yt922x_tag_rcv,
+ .needed_headroom = YT922X_TAG_LEN,
+};
+
+MODULE_DESCRIPTION("DSA tag driver for Motorcomm YT922x switches");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT922X, YT922X_TAG_NAME);
+
+module_dsa_tag_driver(yt922x_netdev_ops);
|
| 3/2 | 2026/10/20 15:55 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 22118 output: 30 thoughts: 445 Thoughts: **Analyzing the Addition of Motorcomm YT9224 Support** Okay, so this patch is introducing support for the Motorcomm YT9224 switch, adding both the core driver to `drivers/net/dsa/motorcomm/` and a DSA tag driver in `net/dsa/tag_yt922x.c`. My initial assessment is, let's see exactly what's being modified. I'll need to review the changes in the `MAINTAINERS` file, the `Kconfig` and `Makefile` for the `motorcomm` directory, and the core driver files: `chip.c`, `chip.h`, `mdio_bus.c`, `mdio_bus.h`, `pcs-922x.c`, and `pcs.h`. I also need to check the changes in `include/net/dsa.h` and the DSA-specific `Kconfig` and `Makefile` files. Of course, the new `tag_yt922x.c` is key. Now, the real question is: Can we effectively fuzz this new addition within a standard environment? My immediate concern is reachability within something like syzkaller. First, is the core DSA functionality and these DSA tag drivers even *reachable* in a typical fuzzing setup? Can we get at them? I need to think this through. Can DSA switches and their tagging protocols be fuzzed without needing specific hardware? That's the critical question here. I need to dig into how DSA drivers and tagging protocols are actually used in the kernel. I need to determine if we can instantiate mock or virtual DSA switches, or perhaps virtual DSA tagging. Is there a way to select the tagging protocol or inject packets without specialized hardware? I will use grepper or a similar tool to see if there are any existing syzlang descriptions, or existing fuzzing coverage of DSA, or if we are even hitting `net/dsa/tag_*.c` anywhere. This will tell me if this can be fuzzed and tested effectively. |
| 4/2 | 2026/10/20 15:55 | tool | grepper |
0mArgs:{
"Expression": "DSA_TAG_PROTO",
"PathPrefixes": [
"net/dsa"
]
}Results: {
"Output": "\nFull output is too long, showing 200 out of 352 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (27 files in total):\nnet/dsa/dsa.c:2\nnet/dsa/tag_ar9331.c:2\nnet/dsa/tag_brcm.c:10\nnet/dsa/tag_dsa.c:4\nnet/dsa/tag_gswip.c:2\nnet/dsa/tag_hellcreek.c:2\nnet/dsa/tag_ks8995.c:2\nnet/dsa/tag_ksz.c:10\nnet/dsa/tag_lan9303.c:2\nnet/dsa/tag_mt7628.c:2\nnet/dsa/tag_mtk.c:2\nnet/dsa/tag_mxl-gsw1xx.c:2\nnet/dsa/tag_mxl862xx.c:2\nnet/dsa/tag_netc.c:2\nnet/dsa/tag_none.c:2\nnet/dsa/tag_ocelot.c:4\nnet/dsa/tag_ocelot_8021q.c:2\nnet/dsa/tag_qca.c:2\nnet/dsa/tag_rtl4_a.c:2\nnet/dsa/tag_rtl8_4.c:4\nnet/dsa/tag_rzn1_a5psw.c:2\nnet/dsa/tag_sja1105.c:4\nnet/dsa/tag_trailer.c:2\nnet/dsa/tag_vsc73xx_8021q.c:2\nnet/dsa/tag_xrs700x.c:2\nnet/dsa/tag_yt921x.c:2\nnet/dsa/tag_yt922x.c:2\n\nnet/dsa/dsa.c=1129=static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp,\n--\nnet/dsa/dsa.c-1131-{\nnet/dsa/dsa.c:1132:\tenum dsa_tag_protocol tag_protocol = DSA_TAG_PROTO_NONE;\nnet/dsa/dsa.c-1133-\tstruct dsa_switch *mds, *ds = dp-\u003eds;\n--\nnet/dsa/dsa.c-1145-\t\ttag_protocol = mds-\u003eops-\u003eget_tag_protocol(mds, mdp_upstream,\nnet/dsa/dsa.c:1146:\t\t\t\t\t\t\t DSA_TAG_PROTO_NONE);\nnet/dsa/dsa.c-1147-\t}\n--\nnet/dsa/tag_ar9331.c=90=static const struct dsa_device_ops ar9331_netdev_ops = {\nnet/dsa/tag_ar9331.c-91-\t.name\t= AR9331_NAME,\nnet/dsa/tag_ar9331.c:92:\t.proto\t= DSA_TAG_PROTO_AR9331,\nnet/dsa/tag_ar9331.c-93-\t.xmit\t= ar9331_tag_xmit,\n--\nnet/dsa/tag_ar9331.c=99=MODULE_LICENSE(\"GPL v2\");\nnet/dsa/tag_ar9331.c:100:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_AR9331, AR9331_NAME);\nnet/dsa/tag_ar9331.c-101-module_dsa_tag_driver(ar9331_netdev_ops);\n--\nnet/dsa/tag_brcm.c=89=static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,\n--\nnet/dsa/tag_brcm.c-136- * -----------------------------------\nnet/dsa/tag_brcm.c:137: * | MAC DA | MAC SA | 4b tag | Type | DSA_TAG_PROTO_BRCM\nnet/dsa/tag_brcm.c-138- * -----------------------------------\nnet/dsa/tag_brcm.c-139- * -----------------------------------\nnet/dsa/tag_brcm.c:140: * | 4b tag | MAC DA | MAC SA | Type | DSA_TAG_PROTO_BRCM_PREPEND\nnet/dsa/tag_brcm.c-141- * -----------------------------------\n--\nnet/dsa/tag_brcm.c=217=static const struct dsa_device_ops brcm_netdev_ops = {\nnet/dsa/tag_brcm.c-218-\t.name\t= BRCM_NAME,\nnet/dsa/tag_brcm.c:219:\t.proto\t= DSA_TAG_PROTO_BRCM,\nnet/dsa/tag_brcm.c-220-\t.xmit\t= brcm_tag_xmit,\n--\nnet/dsa/tag_brcm.c=225=DSA_TAG_DRIVER(brcm_netdev_ops);\nnet/dsa/tag_brcm.c:226:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME);\nnet/dsa/tag_brcm.c-227-#endif\n--\nnet/dsa/tag_brcm.c=311=static const struct dsa_device_ops brcm_legacy_netdev_ops = {\nnet/dsa/tag_brcm.c-312-\t.name = BRCM_LEGACY_NAME,\nnet/dsa/tag_brcm.c:313:\t.proto = DSA_TAG_PROTO_BRCM_LEGACY,\nnet/dsa/tag_brcm.c-314-\t.xmit = brcm_leg_tag_xmit,\n--\nnet/dsa/tag_brcm.c=319=DSA_TAG_DRIVER(brcm_legacy_netdev_ops);\nnet/dsa/tag_brcm.c:320:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME);\nnet/dsa/tag_brcm.c-321-#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */\n--\nnet/dsa/tag_brcm.c=370=static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {\nnet/dsa/tag_brcm.c-371-\t.name = BRCM_LEGACY_FCS_NAME,\nnet/dsa/tag_brcm.c:372:\t.proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS,\nnet/dsa/tag_brcm.c-373-\t.xmit = brcm_leg_fcs_tag_xmit,\n--\nnet/dsa/tag_brcm.c=379=DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);\nnet/dsa/tag_brcm.c:380:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME);\nnet/dsa/tag_brcm.c-381-#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */\n--\nnet/dsa/tag_brcm.c=398=static const struct dsa_device_ops brcm_prepend_netdev_ops = {\nnet/dsa/tag_brcm.c-399-\t.name\t= BRCM_PREPEND_NAME,\nnet/dsa/tag_brcm.c:400:\t.proto\t= DSA_TAG_PROTO_BRCM_PREPEND,\nnet/dsa/tag_brcm.c-401-\t.xmit\t= brcm_tag_xmit_prepend,\n--\nnet/dsa/tag_brcm.c=406=DSA_TAG_DRIVER(brcm_prepend_netdev_ops);\nnet/dsa/tag_brcm.c:407:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND, BRCM_PREPEND_NAME);\nnet/dsa/tag_brcm.c-408-#endif\n--\nnet/dsa/tag_dsa.c=351=static const struct dsa_device_ops dsa_netdev_ops = {\nnet/dsa/tag_dsa.c-352-\t.name\t = DSA_NAME,\nnet/dsa/tag_dsa.c:353:\t.proto\t = DSA_TAG_PROTO_DSA,\nnet/dsa/tag_dsa.c-354-\t.xmit\t = dsa_xmit,\n--\nnet/dsa/tag_dsa.c=359=DSA_TAG_DRIVER(dsa_netdev_ops);\nnet/dsa/tag_dsa.c:360:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_DSA, DSA_NAME);\nnet/dsa/tag_dsa.c-361-#endif\t/* CONFIG_NET_DSA_TAG_DSA */\n--\nnet/dsa/tag_dsa.c=395=static const struct dsa_device_ops edsa_netdev_ops = {\nnet/dsa/tag_dsa.c-396-\t.name\t = EDSA_NAME,\nnet/dsa/tag_dsa.c:397:\t.proto\t = DSA_TAG_PROTO_EDSA,\nnet/dsa/tag_dsa.c-398-\t.xmit\t = edsa_xmit,\n--\nnet/dsa/tag_dsa.c=403=DSA_TAG_DRIVER(edsa_netdev_ops);\nnet/dsa/tag_dsa.c:404:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_EDSA, EDSA_NAME);\nnet/dsa/tag_dsa.c-405-#endif\t/* CONFIG_NET_DSA_TAG_EDSA */\n--\nnet/dsa/tag_gswip.c=104=static const struct dsa_device_ops gswip_netdev_ops = {\nnet/dsa/tag_gswip.c-105-\t.name = GSWIP_NAME,\nnet/dsa/tag_gswip.c:106:\t.proto\t= DSA_TAG_PROTO_GSWIP,\nnet/dsa/tag_gswip.c-107-\t.xmit = gswip_tag_xmit,\n--\nnet/dsa/tag_gswip.c=113=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_gswip.c:114:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP, GSWIP_NAME);\nnet/dsa/tag_gswip.c-115-\n--\nnet/dsa/tag_hellcreek.c=66=static const struct dsa_device_ops hellcreek_netdev_ops = {\nnet/dsa/tag_hellcreek.c-67-\t.name\t = HELLCREEK_NAME,\nnet/dsa/tag_hellcreek.c:68:\t.proto\t = DSA_TAG_PROTO_HELLCREEK,\nnet/dsa/tag_hellcreek.c-69-\t.xmit\t = hellcreek_xmit,\n--\nnet/dsa/tag_hellcreek.c=75=MODULE_LICENSE(\"Dual MIT/GPL\");\nnet/dsa/tag_hellcreek.c:76:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_HELLCREEK, HELLCREEK_NAME);\nnet/dsa/tag_hellcreek.c-77-\n--\nnet/dsa/tag_ks8995.c=167=static const struct dsa_device_ops ks8995_netdev_ops = {\nnet/dsa/tag_ks8995.c-168-\t.name = KS8995_NAME,\nnet/dsa/tag_ks8995.c:169:\t.proto\t= DSA_TAG_PROTO_KS8995,\nnet/dsa/tag_ks8995.c-170-\t.xmit = ks8995_xmit,\n--\nnet/dsa/tag_ks8995.c=177=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_ks8995.c:178:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KS8995, KS8995_NAME);\nnet/dsa/tag_ks8995.c-179-\n--\nnet/dsa/tag_ksz.c=306=static const struct dsa_device_ops ksz9477_netdev_ops = {\nnet/dsa/tag_ksz.c-307-\t.name\t= KSZ9477_NAME,\nnet/dsa/tag_ksz.c:308:\t.proto\t= DSA_TAG_PROTO_KSZ9477,\nnet/dsa/tag_ksz.c-309-\t.xmit\t= ksz9477_xmit,\n--\nnet/dsa/tag_ksz.c=316=DSA_TAG_DRIVER(ksz9477_netdev_ops);\nnet/dsa/tag_ksz.c:317:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9477, KSZ9477_NAME);\nnet/dsa/tag_ksz.c-318-\n--\nnet/dsa/tag_ksz.c=358=static const struct dsa_device_ops ksz8795_netdev_ops = {\nnet/dsa/tag_ksz.c-359-\t.name\t= KSZ8795_NAME,\nnet/dsa/tag_ksz.c:360:\t.proto\t= DSA_TAG_PROTO_KSZ8795,\nnet/dsa/tag_ksz.c-361-\t.xmit\t= ksz8795_xmit,\n--\nnet/dsa/tag_ksz.c=366=DSA_TAG_DRIVER(ksz8795_netdev_ops);\nnet/dsa/tag_ksz.c:367:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME);\nnet/dsa/tag_ksz.c-368-\n--\nnet/dsa/tag_ksz.c=384=static const struct dsa_device_ops ksz9893_netdev_ops = {\nnet/dsa/tag_ksz.c-385-\t.name\t= KSZ9893_NAME,\nnet/dsa/tag_ksz.c:386:\t.proto\t= DSA_TAG_PROTO_KSZ9893,\nnet/dsa/tag_ksz.c-387-\t.xmit\t= ksz9893_xmit,\n--\nnet/dsa/tag_ksz.c=394=DSA_TAG_DRIVER(ksz9893_netdev_ops);\nnet/dsa/tag_ksz.c:395:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893, KSZ9893_NAME);\nnet/dsa/tag_ksz.c-396-\n--\nnet/dsa/tag_ksz.c=448=static const struct dsa_device_ops ksz8463_netdev_ops = {\nnet/dsa/tag_ksz.c-449-\t.name\t= KSZ8463_NAME,\nnet/dsa/tag_ksz.c:450:\t.proto\t= DSA_TAG_PROTO_KSZ8463,\nnet/dsa/tag_ksz.c-451-\t.xmit\t= ksz8463_xmit,\n--\nnet/dsa/tag_ksz.c=458=DSA_TAG_DRIVER(ksz8463_netdev_ops);\nnet/dsa/tag_ksz.c:459:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8463, KSZ8463_NAME);\nnet/dsa/tag_ksz.c-460-\n--\nnet/dsa/tag_ksz.c=519=static const struct dsa_device_ops lan937x_netdev_ops = {\nnet/dsa/tag_ksz.c-520-\t.name\t= LAN937X_NAME,\nnet/dsa/tag_ksz.c:521:\t.proto\t= DSA_TAG_PROTO_LAN937X,\nnet/dsa/tag_ksz.c-522-\t.xmit\t= lan937x_xmit,\n--\nnet/dsa/tag_ksz.c=529=DSA_TAG_DRIVER(lan937x_netdev_ops);\nnet/dsa/tag_ksz.c:530:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X, LAN937X_NAME);\nnet/dsa/tag_ksz.c-531-\n--\nnet/dsa/tag_lan9303.c=116=static const struct dsa_device_ops lan9303_netdev_ops = {\nnet/dsa/tag_lan9303.c-117-\t.name = LAN9303_NAME,\nnet/dsa/tag_lan9303.c:118:\t.proto\t= DSA_TAG_PROTO_LAN9303,\nnet/dsa/tag_lan9303.c-119-\t.xmit = lan9303_xmit,\n--\nnet/dsa/tag_lan9303.c=125=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_lan9303.c:126:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9303, LAN9303_NAME);\nnet/dsa/tag_lan9303.c-127-\n--\nnet/dsa/tag_mt7628.c=81=static const struct dsa_device_ops mt7628_tag_ops = {\nnet/dsa/tag_mt7628.c-82-\t.name = MT7628_TAG_NAME,\nnet/dsa/tag_mt7628.c:83:\t.proto = DSA_TAG_PROTO_MT7628,\nnet/dsa/tag_mt7628.c-84-\t.xmit = mt7628_tag_xmit,\n--\nnet/dsa/tag_mt7628.c=89=module_dsa_tag_driver(mt7628_tag_ops);\nnet/dsa/tag_mt7628.c-90-\nnet/dsa/tag_mt7628.c:91:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MT7628, MT7628_TAG_NAME);\nnet/dsa/tag_mt7628.c-92-MODULE_DESCRIPTION(\"DSA tag driver for MT7628 switch\");\n--\nnet/dsa/tag_mtk.c=102=static const struct dsa_device_ops mtk_netdev_ops = {\nnet/dsa/tag_mtk.c-103-\t.name\t\t= MTK_NAME,\nnet/dsa/tag_mtk.c:104:\t.proto\t\t= DSA_TAG_PROTO_MTK,\nnet/dsa/tag_mtk.c-105-\t.xmit\t\t= mtk_tag_xmit,\n--\nnet/dsa/tag_mtk.c=111=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_mtk.c:112:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MTK, MTK_NAME);\nnet/dsa/tag_mtk.c-113-\n--\nnet/dsa/tag_mxl-gsw1xx.c=108=static const struct dsa_device_ops gsw1xx_netdev_ops = {\nnet/dsa/tag_mxl-gsw1xx.c-109-\t.name\t\t\t= GSW1XX_TAG_NAME,\nnet/dsa/tag_mxl-gsw1xx.c:110:\t.proto\t\t\t= DSA_TAG_PROTO_MXL_GSW1XX,\nnet/dsa/tag_mxl-gsw1xx.c-111-\t.xmit\t\t\t= gsw1xx_tag_xmit,\n--\nnet/dsa/tag_mxl-gsw1xx.c=117=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_mxl-gsw1xx.c:118:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL_GSW1XX, GSW1XX_TAG_NAME);\nnet/dsa/tag_mxl-gsw1xx.c-119-\n--\nnet/dsa/tag_mxl862xx.c=104=static const struct dsa_device_ops mxl862_netdev_ops = {\nnet/dsa/tag_mxl862xx.c-105-\t.name = MXL862_NAME,\nnet/dsa/tag_mxl862xx.c:106:\t.proto = DSA_TAG_PROTO_MXL862,\nnet/dsa/tag_mxl862xx.c-107-\t.xmit = mxl862_tag_xmit,\n--\nnet/dsa/tag_mxl862xx.c-111-\nnet/dsa/tag_mxl862xx.c:112:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862, MXL862_NAME);\nnet/dsa/tag_mxl862xx.c-113-MODULE_DESCRIPTION(\"DSA tag driver for MaxLinear MxL862xx switches\");\n--\n\n"
} |
| 5/2 | 2026/10/20 15:55 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 28794 output: 36 thoughts: 71 Thoughts: Here's my take on those thoughts, keeping in mind my expertise: **Deep Dive into DSA Switching and Tagging** Alright, let's get down to brass tacks. I'm thinking about how Data Switching Architecture (DSA) works, specifically focusing on the interplay between switches and tagging. I need to refresh my memory on the specifics. My immediate question is: can I manipulate DSA tagging protocols, or at least configure them on network devices using Netlink? That's the real key to programmatic control. My mental map is telling me to start digging into the Linux kernel source. I suspect the meat of the matter lies within `net/dsa/`. Specifically, I'll need to scrutinize `conduit.c` and `user.c`, as those files seem like the most likely candidates for handling DSA interactions. If it's a user-space interface that I'm after, the `netlink` interface is where I'll find my answers. |
| 6/2 | 2026/10/20 15:55 | tool | grepper |
0mArgs:{
"Expression": "change_tag_protocol|dsa_conduit",
"PathPrefixes": [
"net/dsa"
]
}Results: {
"Output": "\nFull output is too long, showing 200 out of 386 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (31 files in total):\nnet/dsa/conduit.c:37\nnet/dsa/conduit.h:5\nnet/dsa/dsa.c:6\nnet/dsa/switch.c:2\nnet/dsa/tag.c:1\nnet/dsa/tag.h:1\nnet/dsa/tag_8021q.c:1\nnet/dsa/tag_ar9331.c:1\nnet/dsa/tag_brcm.c:2\nnet/dsa/tag_dsa.c:1\nnet/dsa/tag_gswip.c:1\nnet/dsa/tag_hellcreek.c:1\nnet/dsa/tag_ks8995.c:1\nnet/dsa/tag_ksz.c:1\nnet/dsa/tag_lan9303.c:1\nnet/dsa/tag_mt7628.c:1\nnet/dsa/tag_mtk.c:1\nnet/dsa/tag_mxl-gsw1xx.c:1\nnet/dsa/tag_mxl862xx.c:1\nnet/dsa/tag_netc.c:1\nnet/dsa/tag_ocelot.c:1\nnet/dsa/tag_ocelot_8021q.c:1\nnet/dsa/tag_qca.c:1\nnet/dsa/tag_rtl4_a.c:1\nnet/dsa/tag_rtl8_4.c:1\nnet/dsa/tag_rzn1_a5psw.c:1\nnet/dsa/tag_trailer.c:1\nnet/dsa/tag_xrs700x.c:1\nnet/dsa/tag_yt921x.c:1\nnet/dsa/tag_yt922x.c:1\nnet/dsa/user.c:11\n\nnet/dsa/conduit.c-19-\nnet/dsa/conduit.c:20:static int dsa_conduit_get_regs_len(struct net_device *dev)\nnet/dsa/conduit.c-21-{\n--\nnet/dsa/conduit.c-48-\nnet/dsa/conduit.c:49:static void dsa_conduit_get_regs(struct net_device *dev,\nnet/dsa/conduit.c-50-\t\t\t\t struct ethtool_regs *regs, void *data)\n--\nnet/dsa/conduit.c-83-\nnet/dsa/conduit.c:84:static ssize_t dsa_conduit_append_port_stats(struct dsa_switch *ds, int port,\nnet/dsa/conduit.c-85-\t\t\t\t\t u64 *data, size_t start)\n--\nnet/dsa/conduit.c-101-\nnet/dsa/conduit.c:102:static void dsa_conduit_get_ethtool_stats(struct net_device *dev,\nnet/dsa/conduit.c-103-\t\t\t\t\t struct ethtool_stats *stats,\n--\nnet/dsa/conduit.c-119-\nnet/dsa/conduit.c:120:\t\tcount = dsa_conduit_append_port_stats(dp-\u003eds, dp-\u003eindex,\nnet/dsa/conduit.c-121-\t\t\t\t\t\t data, mcount);\n--\nnet/dsa/conduit.c-128-\nnet/dsa/conduit.c:129:static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev,\nnet/dsa/conduit.c-130-\t\t\t\t\t struct ethtool_stats *stats,\n--\nnet/dsa/conduit.c-154-\nnet/dsa/conduit.c:155:static void dsa_conduit_append_port_sset_count(struct dsa_switch *ds, int port,\nnet/dsa/conduit.c-156-\t\t\t\t\t int sset, int *count)\n--\nnet/dsa/conduit.c-161-\nnet/dsa/conduit.c:162:static int dsa_conduit_get_sset_count(struct net_device *dev, int sset)\nnet/dsa/conduit.c-163-{\n--\nnet/dsa/conduit.c-181-\nnet/dsa/conduit.c:182:\t\tdsa_conduit_append_port_sset_count(dp-\u003eds, dp-\u003eindex, sset,\nnet/dsa/conduit.c-183-\t\t\t\t\t\t \u0026count);\n--\nnet/dsa/conduit.c-188-\nnet/dsa/conduit.c:189:static ssize_t dsa_conduit_append_port_strings(struct dsa_switch *ds, int port,\nnet/dsa/conduit.c-190-\t\t\t\t\t u32 stringset, u8 *data,\n--\nnet/dsa/conduit.c-221-\nnet/dsa/conduit.c:222:static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,\nnet/dsa/conduit.c-223-\t\t\t\t u8 *data)\n--\nnet/dsa/conduit.c-247-\nnet/dsa/conduit.c:248:\t\tcount = dsa_conduit_append_port_strings(dp-\u003eds, dp-\u003eindex,\nnet/dsa/conduit.c-249-\t\t\t\t\t\t\tstringset, data,\n--\nnet/dsa/conduit.c-260- */\nnet/dsa/conduit.c:261:int __dsa_conduit_hwtstamp_validate(struct net_device *dev,\nnet/dsa/conduit.c-262-\t\t\t\t const struct kernel_hwtstamp_config *config,\n--\nnet/dsa/conduit.c-282-\nnet/dsa/conduit.c:283:static int dsa_conduit_ethtool_setup(struct net_device *dev)\nnet/dsa/conduit.c-284-{\n--\nnet/dsa/conduit.c-299-\nnet/dsa/conduit.c:300:\tops-\u003eget_regs_len = dsa_conduit_get_regs_len;\nnet/dsa/conduit.c:301:\tops-\u003eget_regs = dsa_conduit_get_regs;\nnet/dsa/conduit.c:302:\tops-\u003eget_sset_count = dsa_conduit_get_sset_count;\nnet/dsa/conduit.c:303:\tops-\u003eget_ethtool_stats = dsa_conduit_get_ethtool_stats;\nnet/dsa/conduit.c:304:\tops-\u003eget_strings = dsa_conduit_get_strings;\nnet/dsa/conduit.c:305:\tops-\u003eget_ethtool_phy_stats = dsa_conduit_get_ethtool_phy_stats;\nnet/dsa/conduit.c-306-\n--\nnet/dsa/conduit.c-311-\nnet/dsa/conduit.c:312:static void dsa_conduit_ethtool_teardown(struct net_device *dev)\nnet/dsa/conduit.c-313-{\n--\nnet/dsa/conduit.c-327- */\nnet/dsa/conduit.c:328:static void dsa_conduit_set_promiscuity(struct net_device *dev, int inc)\nnet/dsa/conduit.c-329-{\n--\nnet/dsa/conduit.c=404=static const struct attribute_group dsa_group = {\n--\nnet/dsa/conduit.c-408-\nnet/dsa/conduit.c:409:static void dsa_conduit_reset_mtu(struct net_device *dev)\nnet/dsa/conduit.c-410-{\n--\nnet/dsa/conduit.c-418-\nnet/dsa/conduit.c:419:int dsa_conduit_setup(struct net_device *dev, struct dsa_port *cpu_dp)\nnet/dsa/conduit.c-420-{\n--\nnet/dsa/conduit.c-454-\nnet/dsa/conduit.c:455:\tdsa_conduit_set_promiscuity(dev, 1);\nnet/dsa/conduit.c-456-\nnet/dsa/conduit.c:457:\tret = dsa_conduit_ethtool_setup(dev);\nnet/dsa/conduit.c-458-\tif (ret)\n--\nnet/dsa/conduit.c-467-out_err_ethtool_teardown:\nnet/dsa/conduit.c:468:\tdsa_conduit_ethtool_teardown(dev);\nnet/dsa/conduit.c-469-out_err_reset_promisc:\nnet/dsa/conduit.c:470:\tdsa_conduit_set_promiscuity(dev, -1);\nnet/dsa/conduit.c-471-\treturn ret;\n--\nnet/dsa/conduit.c-473-\nnet/dsa/conduit.c:474:void dsa_conduit_teardown(struct net_device *dev)\nnet/dsa/conduit.c-475-{\nnet/dsa/conduit.c-476-\tsysfs_remove_group(\u0026dev-\u003edev.kobj, \u0026dsa_group);\nnet/dsa/conduit.c:477:\tdsa_conduit_ethtool_teardown(dev);\nnet/dsa/conduit.c:478:\tdsa_conduit_reset_mtu(dev);\nnet/dsa/conduit.c:479:\tdsa_conduit_set_promiscuity(dev, -1);\nnet/dsa/conduit.c-480-\n--\nnet/dsa/conduit.c-489-\nnet/dsa/conduit.c:490:int dsa_conduit_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp,\nnet/dsa/conduit.c-491-\t\t\t struct netdev_lag_upper_info *uinfo,\n--\nnet/dsa/conduit.c-497-\tif (!netdev_uses_dsa(lag_dev)) {\nnet/dsa/conduit.c:498:\t\terr = dsa_conduit_setup(lag_dev, cpu_dp);\nnet/dsa/conduit.c-499-\t\tif (err)\n--\nnet/dsa/conduit.c-514-\tif (conduit_setup)\nnet/dsa/conduit.c:515:\t\tdsa_conduit_teardown(lag_dev);\nnet/dsa/conduit.c-516-\treturn err;\n--\nnet/dsa/conduit.c-521- */\nnet/dsa/conduit.c:522:void dsa_conduit_lag_teardown(struct net_device *lag_dev,\nnet/dsa/conduit.c-523-\t\t\t struct dsa_port *cpu_dp)\n--\nnet/dsa/conduit.c-533-\nnet/dsa/conduit.c:534:\tdsa_conduit_teardown(lag_dev);\nnet/dsa/conduit.c-535-}\n--\nnet/dsa/conduit.h=9=struct netlink_ext_ack;\nnet/dsa/conduit.h-10-\nnet/dsa/conduit.h:11:int dsa_conduit_setup(struct net_device *dev, struct dsa_port *cpu_dp);\nnet/dsa/conduit.h:12:void dsa_conduit_teardown(struct net_device *dev);\nnet/dsa/conduit.h:13:int dsa_conduit_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp,\nnet/dsa/conduit.h-14-\t\t\t struct netdev_lag_upper_info *uinfo,\nnet/dsa/conduit.h-15-\t\t\t struct netlink_ext_ack *extack);\nnet/dsa/conduit.h:16:void dsa_conduit_lag_teardown(struct net_device *lag_dev,\nnet/dsa/conduit.h-17-\t\t\t struct dsa_port *cpu_dp);\nnet/dsa/conduit.h:18:int __dsa_conduit_hwtstamp_validate(struct net_device *dev,\nnet/dsa/conduit.h-19-\t\t\t\t const struct kernel_hwtstamp_config *config,\n--\nnet/dsa/dsa.c=570=static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds)\n--\nnet/dsa/dsa.c-579-\trtnl_lock();\nnet/dsa/dsa.c:580:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/dsa.c-581-\trtnl_unlock();\n--\nnet/dsa/dsa.c=787=static int dsa_tree_setup_conduit(struct dsa_switch_tree *dst)\n--\nnet/dsa/dsa.c-798-\nnet/dsa/dsa.c:799:\t\terr = dsa_conduit_setup(conduit, cpu_dp);\nnet/dsa/dsa.c-800-\t\tif (err)\n--\nnet/dsa/dsa.c=814=static void dsa_tree_teardown_conduit(struct dsa_switch_tree *dst)\n--\nnet/dsa/dsa.c-828-\nnet/dsa/dsa.c:829:\t\tdsa_conduit_teardown(conduit);\nnet/dsa/dsa.c-830-\t}\n--\nnet/dsa/dsa.c=1155=static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *conduit,\n--\nnet/dsa/dsa.c-1176-\tif (user_protocol) {\nnet/dsa/dsa.c:1177:\t\tif (!ds-\u003eops-\u003echange_tag_protocol) {\nnet/dsa/dsa.c-1178-\t\t\tdev_err(ds-\u003edev, \"Tag protocol cannot be modified\\n\");\n--\nnet/dsa/dsa.c-1230-\t * dsa_switch_setup_tag_protocol once .setup has run and the\nnet/dsa/dsa.c:1231:\t * driver is ready to accept calls to .change_tag_protocol. If\nnet/dsa/dsa.c-1232-\t * the driver does not support the custom protocol at that\n--\nnet/dsa/dsa.c=1851=static const struct dsa_stubs __dsa_stubs = {\nnet/dsa/dsa.c:1852:\t.conduit_hwtstamp_validate = __dsa_conduit_hwtstamp_validate,\nnet/dsa/dsa.c-1853-};\n--\nnet/dsa/switch.c=873=static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-879-\nnet/dsa/switch.c:880:\tif (!ds-\u003eops-\u003echange_tag_protocol)\nnet/dsa/switch.c-881-\t\treturn -EOPNOTSUPP;\n--\nnet/dsa/switch.c-884-\nnet/dsa/switch.c:885:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/switch.c-886-\tif (err)\n--\nnet/dsa/tag.c=54=static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,\n--\nnet/dsa/tag.c-77-\nnet/dsa/tag.c:78:\t\tskb-\u003edev = dsa_conduit_find_user(dev, 0, port);\nnet/dsa/tag.c-79-\t\tif (likely(skb-\u003edev)) {\n--\nnet/dsa/tag.h=27=static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops)\n--\nnet/dsa/tag.h-31-\nnet/dsa/tag.h:32:static inline struct net_device *dsa_conduit_find_user(struct net_device *dev,\nnet/dsa/tag.h-33-\t\t\t\t\t\t int device, int port)\n--\nnet/dsa/tag_8021q.c=502=struct net_device *dsa_tag_8021q_find_user(struct net_device *conduit,\n--\nnet/dsa/tag_8021q.c-507-\tif (source_port != -1 \u0026\u0026 switch_id != -1)\nnet/dsa/tag_8021q.c:508:\t\treturn dsa_conduit_find_user(conduit, switch_id, source_port);\nnet/dsa/tag_8021q.c-509-\telse if (vbid \u003e= 1)\n--\nnet/dsa/tag_ar9331.c=48=static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,\n--\nnet/dsa/tag_ar9331.c-80-\nnet/dsa/tag_ar9331.c:81:\tskb-\u003edev = dsa_conduit_find_user(ndev, 0, port);\n\n"
} |
| 7/2 | 2026/10/20 15:55 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 33815 output: 35 thoughts: 18 Thoughts: Here's a summary of my thought process, as requested: **Deconstructing `dsa_switch_change_tag_proto`** Okay, so I need to understand what's going on with `dsa_switch_change_tag_proto`. Let's break this down. My initial instinct is to treat this as an unknown API call, potentially a function or method. I need to figure out the context of the code. Is it network-related? Hardware? What's the "DSA" likely standing for? *Device Specific Adaptations*? *Dynamic Security Association*? I'll probably need to consult documentation or source code to get the specifics, but the "switch" part makes me think it has to be about hardware, specifically a network switch. Then there's the "change" which implies modification or updating a configuration. Finally "tag_proto", this could mean some sort of protocol tag, header or identifier which could be related to encapsulation, VLAN tagging, or even security protocols. I need to trace this call, see where it's defined, who's calling it, and what data it's taking as input. That should illuminate the behavior significantly. This feels like it has something to do with the switching of data between ports with certain parameters/identifiers. Ultimately, I need to see how the tagging process within the switch is being modified, likely from the source code. |
| 8/2 | 2026/10/20 15:55 | tool | grepper |
0mArgs:{
"Expression": "dsa_switch_change_tag_proto",
"PathPrefixes": [
"net/dsa"
]
}Results: {
"Output": "net/dsa/switch.c=853=static int dsa_switch_host_vlan_del(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-872-\nnet/dsa/switch.c:873:static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\nnet/dsa/switch.c-874-\t\t\t\t struct dsa_notifier_tag_proto_info *info)\n--\nnet/dsa/switch.c=974=static int dsa_switch_event(struct notifier_block *nb,\n--\nnet/dsa/switch.c-1044-\tcase DSA_NOTIFIER_TAG_PROTO:\nnet/dsa/switch.c:1045:\t\terr = dsa_switch_change_tag_proto(ds, info);\nnet/dsa/switch.c-1046-\t\tbreak;\n"
} |
| 9/2 | 2026/10/20 15:55 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 34401 output: 22 thoughts: 16 Thoughts: Here's a summary of my thought process, as requested: **Investigating the `DSA_NOTIFIER_TAG_PROTO` Emission** Alright, let's dive in. The immediate question is, what precisely is emitting this `DSA_NOTIFIER_TAG_PROTO`? I need to understand the context. This isn't just a random string; it's likely a tag, perhaps a key identifier used within some distributed systems architecture (DSA) framework, specifically a notifier or protocol-related context. The "PROTO" part hints that it's related to some protocol designation or message format. My first thought is to use my tools – likely a debugger, a logging analysis system, or perhaps some grepping utilities across the codebase. I need to pinpoint the *where* and the *why*. Was this logged, or is it an internal message? Is this from the core of the messaging system, or a client of that core? I need to trace this back to its originating source code. Understanding the call stack would be ideal to understand the full context. I'm particularly interested in the surrounding code. What other data is being emitted alongside this tag? What function calls lead up to this event? What are the potential impacts of this tag, both intended and unintended? Could this be a symptom of a bug, or is it a perfectly legitimate and expected informational message? Essentially, I want to reconstruct the sequence of events that triggers this emission. Knowing the precise data structures, message formats, and the exact code path involved will be critical. Ultimately, I need to confirm whether it is acting as designed. |
| 10/2 | 2026/10/20 15:56 | tool | grepper |
0mArgs:{
"Expression": "DSA_NOTIFIER_TAG_PROTO"
}Results: {
"Output": "net/dsa/dsa.c=948=static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-960-\tinfo.tag_ops = tag_ops;\nnet/dsa/dsa.c:961:\terr = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_CONNECT, \u0026info);\nnet/dsa/dsa.c-962-\tif (err \u0026\u0026 err != -EOPNOTSUPP)\n--\nnet/dsa/dsa.c-966-\tinfo.tag_ops = old_tag_ops;\nnet/dsa/dsa.c:967:\tdsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, \u0026info);\nnet/dsa/dsa.c-968-\n--\nnet/dsa/dsa.c-972-\tinfo.tag_ops = tag_ops;\nnet/dsa/dsa.c:973:\tdsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO_DISCONNECT, \u0026info);\nnet/dsa/dsa.c-974-\tdst-\u003etag_ops = old_tag_ops;\n--\nnet/dsa/dsa.c=983=int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-1008-\tinfo.tag_ops = tag_ops;\nnet/dsa/dsa.c:1009:\terr = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, \u0026info);\nnet/dsa/dsa.c-1010-\tif (err)\n--\nnet/dsa/dsa.c-1022-\tinfo.tag_ops = old_tag_ops;\nnet/dsa/dsa.c:1023:\tdsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, \u0026info);\nnet/dsa/dsa.c-1024-out_unlock:\n--\nnet/dsa/switch.c=974=static int dsa_switch_event(struct notifier_block *nb,\n--\nnet/dsa/switch.c-1043-\t\tbreak;\nnet/dsa/switch.c:1044:\tcase DSA_NOTIFIER_TAG_PROTO:\nnet/dsa/switch.c-1045-\t\terr = dsa_switch_change_tag_proto(ds, info);\nnet/dsa/switch.c-1046-\t\tbreak;\nnet/dsa/switch.c:1047:\tcase DSA_NOTIFIER_TAG_PROTO_CONNECT:\nnet/dsa/switch.c-1048-\t\terr = dsa_switch_connect_tag_proto(ds, info);\nnet/dsa/switch.c-1049-\t\tbreak;\nnet/dsa/switch.c:1050:\tcase DSA_NOTIFIER_TAG_PROTO_DISCONNECT:\nnet/dsa/switch.c-1051-\t\terr = dsa_switch_disconnect_tag_proto(ds, info);\n--\nnet/dsa/switch.h=10=enum {\n--\nnet/dsa/switch.h-31-\tDSA_NOTIFIER_MTU,\nnet/dsa/switch.h:32:\tDSA_NOTIFIER_TAG_PROTO,\nnet/dsa/switch.h:33:\tDSA_NOTIFIER_TAG_PROTO_CONNECT,\nnet/dsa/switch.h:34:\tDSA_NOTIFIER_TAG_PROTO_DISCONNECT,\nnet/dsa/switch.h-35-\tDSA_NOTIFIER_TAG_8021Q_VLAN_ADD,\n--\nnet/dsa/switch.h=92=struct dsa_notifier_mtu_info {\n--\nnet/dsa/switch.h-96-\nnet/dsa/switch.h:97:/* DSA_NOTIFIER_TAG_PROTO_* */\nnet/dsa/switch.h-98-struct dsa_notifier_tag_proto_info {\n"
} |
| 11/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 35827 output: 24 thoughts: 16 Thoughts: Okay, here's my attempt at summarizing that thought process, tailored for an expert audience: **Tracing the Caller of `dsa_tree_change_tag_proto`** Right, so I'm seeing a call to `dsa_tree_change_tag_proto`. The immediate question that jumps to mind is: what's the entry point? What's the causal chain that leads *here*? Is this function called directly, or is it several layers deep within some other service or process? I need to understand the architectural context to appreciate the significance of this call, its potential impact, and how to debug any issues that might arise. A quick scan of the codebase, or a symbolic execution trace, would be the next logical step. I'm thinking about the dependency graph and the potential for unintended side effects; knowing the caller gives me the starting point for that investigation. |
| 12/2 | 2026/10/20 15:56 | tool | grepper |
0mArgs:{
"Expression": "dsa_tree_change_tag_proto"
}Results: {
"Output": "net/dsa/conduit.c=350=static ssize_t tagging_store(struct device *d, struct device_attribute *attr,\n--\nnet/dsa/conduit.c-380-\nnet/dsa/conduit.c:381:\terr = dsa_tree_change_tag_proto(cpu_dp-\u003eds-\u003edst, new_tag_ops,\nnet/dsa/conduit.c-382-\t\t\t\t\told_tag_ops);\n--\nnet/dsa/dsa.c=948=static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-982- */\nnet/dsa/dsa.c:983:int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\nnet/dsa/dsa.c-984-\t\t\t const struct dsa_device_ops *tag_ops,\n--\nnet/dsa/dsa.h=24=struct net_device *dsa_tree_find_first_conduit(struct dsa_switch_tree *dst);\nnet/dsa/dsa.h:25:int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\nnet/dsa/dsa.h-26-\t\t\t const struct dsa_device_ops *tag_ops,\n--\nnet/dsa/switch.c=873=static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-900-\nnet/dsa/switch.c:901:\t\t/* rtnl_mutex is held in dsa_tree_change_tag_proto */\nnet/dsa/switch.c-902-\t\tdsa_user_change_mtu(user, user-\u003emtu);\n"
} |
| 13/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 36534 output: 35 thoughts: 155 Thoughts: **Investigating the Conduit Switch Implementation** Okay, let's dive in. I need to understand how tagging is handled within this conduit system. My focus is the `tagging_store` function in `net/dsa/conduit.c`. The first thing that jumps out is that `cpu_dp->ds->dst` represents a switch tree specifically for the conduit device. Now, where is the `tag_yt922x` tagging protocol supported? I'll check `yt922x_dsa_get_tag_protocol`; it's clear this supports `DSA_TAG_PROTO_YT922X`. That points me to the Motorcomm DSA driver. Now, I need to know *how* this protocol is configured. Does `drivers/net/dsa/motorcomm/chip.c` implement a `change_tag_protocol` function? My next move is to examine the `change_tag_protocol` within either `yt922x_dsa_switch_ops` or `yt921x_dsa_switch_ops`. This will likely reveal the mechanism for switching between tagging methods on these Motorcomm devices. |
| 14/2 | 2026/10/20 15:56 | tool | grepper |
0mError:no matches Args: {
"Expression": "change_tag_protocol",
"PathPrefixes": [
"drivers/net/dsa/motorcomm"
]
}Results: {
"error": "no matches"
} |
| 15/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 36990 output: 47 thoughts: 56 Thoughts: Okay, here's my assessment of the situation: **Investigating a Driver Implementation Issue** Hmm, no obvious direct matches here. The `change_tag_protocol` function isn't implemented within the `motorcomm` context, that's a key piece of information. This strongly suggests that the tagging protocol modification, whatever it entails, isn't handled within the core `motorcomm` framework. Now I need to figure out *how* the `yt921x_mdio_driver` is being brought into the system and how its probing is orchestrated. Time to dive into the code. My next logical step is to examine `drivers/net/dsa/motorcomm/chip.c`. This file should contain the top-level driver instantiation and device registration logic for the `motorcomm` DSA chips. I'm hoping to find the connection between the overall DSA framework, the motorcomm specific code, and how the `yt921x_mdio_driver` gets initialized, and if there is any custom `change_tag_protocol` implementation at that point. I'll be looking for references to the mdio driver in the probing routines and related functions. |
| 16/2 | 2026/10/20 15:56 | tool | grepper |
0mArgs:{
"Expression": "mdio_module_driver|yt921x_mdio_probe",
"PathPrefixes": [
"drivers/net/dsa/motorcomm"
]
}Results: {
"Output": "drivers/net/dsa/motorcomm/chip.c=3148=static void yt921x_mdio_remove(struct mdio_device *mdiodev)\n--\ndrivers/net/dsa/motorcomm/chip.c-3173-\ndrivers/net/dsa/motorcomm/chip.c:3174:static int yt921x_mdio_probe(struct mdio_device *mdiodev)\ndrivers/net/dsa/motorcomm/chip.c-3175-{\n--\ndrivers/net/dsa/motorcomm/chip.c=3224=static struct mdio_driver yt921x_mdio_driver = {\ndrivers/net/dsa/motorcomm/chip.c:3225:\t.probe = yt921x_mdio_probe,\ndrivers/net/dsa/motorcomm/chip.c-3226-\t.remove = yt921x_mdio_remove,\n--\ndrivers/net/dsa/motorcomm/chip.c-3233-\ndrivers/net/dsa/motorcomm/chip.c:3234:mdio_module_driver(yt921x_mdio_driver);\ndrivers/net/dsa/motorcomm/chip.c-3235-\n"
} |
| 17/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 37673 output: 24 thoughts: 148 Thoughts: **My Investigation into Virtual DSA Switch Probing** Okay, so `yt921x_mdio_driver` is an `mdio_driver`. That's the starting point. My mind immediately jumps to how these `mdio` devices are probed and instantiated. I'm wondering if I can get these things – or even DSA switches – running in a standard QEMU environment. Can I create these without real hardware or a Device Tree to guide things? Are there *any* virtual MDIO buses or DSA switches implemented anywhere? That's the real question. I should check if `syzkaller` or even a standard virtualized environment has any mock DSA switches. Or, if DSA is even instantiated at all. Let's shift gears: I'll browse the DSA drivers across the kernel. How many exist, really? And can *any* DSA driver be reached or probed in a QEMU environment? It seems like a shot in the dark, but it's where I need to start. Alright, let's head straight to `drivers/net/dsa/` and see what's in there. I'm hoping to find something, *anything*, that can give me some kind of foothold. |
| 18/2 | 2026/10/20 15:56 | tool | codesearch-dir-index |
0mArgs:{
"Dir": "drivers/net/dsa"
}Results: {
"Files": [
"bcm_sf2.c",
"bcm_sf2.h",
"bcm_sf2_cfp.c",
"bcm_sf2_regs.h",
"dsa_loop.c",
"lan9303-core.c",
"lan9303.h",
"lan9303_i2c.c",
"lan9303_mdio.c",
"mt7530-mdio.c",
"mt7530-mmio.c",
"mt7530.c",
"mt7530.h",
"mt7628.c",
"mv88e6060.c",
"mv88e6060.h",
"rzn1_a5psw.c",
"rzn1_a5psw.h",
"vitesse-vsc73xx-core.c",
"vitesse-vsc73xx-platform.c",
"vitesse-vsc73xx-spi.c",
"vitesse-vsc73xx.h"
],
"Subdirs": [
"b53",
"hirschmann",
"lantiq",
"microchip",
"motorcomm",
"mv88e6xxx",
"mxl862xx",
"netc",
"ocelot",
"qca",
"realtek",
"sja1105",
"xrs700x"
]
} |
| 19/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 38473 output: 31 thoughts: 23 Thoughts: Here's my take on the thought process, from an expert's perspective: **Initial Assessment: A Focus on Code** Okay, first things first, my attention is immediately drawn to that file, `dsa_loop.c`. A loop within the realm of DSA, or Direct Sequential Access? Hmmm, interesting. This warrants a closer look. I'm going to dive into the contents of `dsa_loop.c` to see precisely what's going on within. I need to understand this implementation quickly. |
| 20/2 | 2026/10/20 15:56 | tool | grepper |
0mArgs:{
"Expression": "dsa_loop",
"PathPrefixes": [
"drivers/net/dsa"
]
}Results: {
"Output": "\nFull output is too long, showing 200 out of 265 lines.\nUse more precise expression or PathPrefixes if possible.\n\nNumber of matching lines per file (2 files in total):\ndrivers/net/dsa/Makefile:1\ndrivers/net/dsa/dsa_loop.c:93\n\ndrivers/net/dsa/Makefile=3=bcm-sf2-objs\t\t\t:= bcm_sf2.o bcm_sf2_cfp.o\ndrivers/net/dsa/Makefile:4:obj-$(CONFIG_NET_DSA_LOOP)\t+= dsa_loop.o\ndrivers/net/dsa/Makefile-5-obj-$(CONFIG_NET_DSA_MT7530)\t+= mt7530.o\n--\ndrivers/net/dsa/dsa_loop.c-24-\ndrivers/net/dsa/dsa_loop.c:25:struct dsa_loop_vlan {\ndrivers/net/dsa/dsa_loop.c-26-\tu16 members;\n--\ndrivers/net/dsa/dsa_loop.c-29-\ndrivers/net/dsa/dsa_loop.c:30:struct dsa_loop_mib_entry {\ndrivers/net/dsa/dsa_loop.c-31-\tchar name[ETH_GSTRING_LEN];\n--\ndrivers/net/dsa/dsa_loop.c-34-\ndrivers/net/dsa/dsa_loop.c:35:enum dsa_loop_mib_counters {\ndrivers/net/dsa/dsa_loop.c-36-\tDSA_LOOP_PHY_READ_OK,\n--\ndrivers/net/dsa/dsa_loop.c-42-\ndrivers/net/dsa/dsa_loop.c:43:struct dsa_loop_port {\ndrivers/net/dsa/dsa_loop.c:44:\tstruct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX];\ndrivers/net/dsa/dsa_loop.c-45-\tu16 pvid;\n--\ndrivers/net/dsa/dsa_loop.c-48-\ndrivers/net/dsa/dsa_loop.c:49:struct dsa_loop_priv {\ndrivers/net/dsa/dsa_loop.c-50-\tstruct mii_bus\t*bus;\ndrivers/net/dsa/dsa_loop.c-51-\tunsigned int\tport_base;\ndrivers/net/dsa/dsa_loop.c:52:\tstruct dsa_loop_vlan vlans[VLAN_N_VID];\ndrivers/net/dsa/dsa_loop.c-53-\tstruct net_device *netdev;\ndrivers/net/dsa/dsa_loop.c:54:\tstruct dsa_loop_port ports[DSA_MAX_PORTS];\ndrivers/net/dsa/dsa_loop.c-55-};\ndrivers/net/dsa/dsa_loop.c-56-\ndrivers/net/dsa/dsa_loop.c:57:struct dsa_loop_pdata {\ndrivers/net/dsa/dsa_loop.c-58-\t/* Must be first, such that dsa_register_switch() can access this\n--\ndrivers/net/dsa/dsa_loop.c-66-\ndrivers/net/dsa/dsa_loop.c:67:static struct dsa_loop_mib_entry dsa_loop_mibs[] = {\ndrivers/net/dsa/dsa_loop.c-68-\t[DSA_LOOP_PHY_READ_OK]\t= { \"phy_read_ok\", },\n--\ndrivers/net/dsa/dsa_loop.c=75=static struct mdio_device *switch_mdiodev;\ndrivers/net/dsa/dsa_loop.c-76-\ndrivers/net/dsa/dsa_loop.c:77:enum dsa_loop_devlink_resource_id {\ndrivers/net/dsa/dsa_loop.c-78-\tDSA_LOOP_DEVLINK_PARAM_ID_NONE, /* DEVLINK_RESOURCE_ID_PARENT_TOP */\n--\ndrivers/net/dsa/dsa_loop.c-81-\ndrivers/net/dsa/dsa_loop.c:82:static u64 dsa_loop_devlink_vtu_get(void *priv)\ndrivers/net/dsa/dsa_loop.c-83-{\ndrivers/net/dsa/dsa_loop.c:84:\tstruct dsa_loop_priv *ps = priv;\ndrivers/net/dsa/dsa_loop.c-85-\tunsigned int i, count = 0;\ndrivers/net/dsa/dsa_loop.c:86:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-87-\n--\ndrivers/net/dsa/dsa_loop.c-96-\ndrivers/net/dsa/dsa_loop.c:97:static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-98-{\ndrivers/net/dsa/dsa_loop.c-99-\tstruct devlink_resource_size_params size_params;\ndrivers/net/dsa/dsa_loop.c:100:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-101-\tint err;\n--\ndrivers/net/dsa/dsa_loop.c-115-\t\t\t\t\t DSA_LOOP_DEVLINK_PARAM_ID_VTU,\ndrivers/net/dsa/dsa_loop.c:116:\t\t\t\t\t dsa_loop_devlink_vtu_get, ps);\ndrivers/net/dsa/dsa_loop.c-117-\n--\ndrivers/net/dsa/dsa_loop.c-124-\ndrivers/net/dsa/dsa_loop.c:125:static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/dsa_loop.c-126-\t\t\t\t\t\t int port,\n--\ndrivers/net/dsa/dsa_loop.c-133-\ndrivers/net/dsa/dsa_loop.c:134:static int dsa_loop_setup(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-135-{\ndrivers/net/dsa/dsa_loop.c:136:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-137-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-139-\tfor (i = 0; i \u003c ds-\u003enum_ports; i++)\ndrivers/net/dsa/dsa_loop.c:140:\t\tmemcpy(ps-\u003eports[i].mib, dsa_loop_mibs,\ndrivers/net/dsa/dsa_loop.c:141:\t\t sizeof(dsa_loop_mibs));\ndrivers/net/dsa/dsa_loop.c-142-\n--\ndrivers/net/dsa/dsa_loop.c-144-\ndrivers/net/dsa/dsa_loop.c:145:\treturn dsa_loop_setup_devlink_resources(ds);\ndrivers/net/dsa/dsa_loop.c-146-}\ndrivers/net/dsa/dsa_loop.c-147-\ndrivers/net/dsa/dsa_loop.c:148:static void dsa_loop_teardown(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-149-{\n--\ndrivers/net/dsa/dsa_loop.c-152-\ndrivers/net/dsa/dsa_loop.c:153:static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)\ndrivers/net/dsa/dsa_loop.c-154-{\n--\ndrivers/net/dsa/dsa_loop.c-160-\ndrivers/net/dsa/dsa_loop.c:161:static void dsa_loop_get_strings(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-162-\t\t\t\t u32 stringset, uint8_t *data)\ndrivers/net/dsa/dsa_loop.c-163-{\ndrivers/net/dsa/dsa_loop.c:164:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-165-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-173-\ndrivers/net/dsa/dsa_loop.c:174:static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-175-\t\t\t\t uint64_t *data)\ndrivers/net/dsa/dsa_loop.c-176-{\ndrivers/net/dsa/dsa_loop.c:177:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-178-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-183-\ndrivers/net/dsa/dsa_loop.c:184:static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum)\ndrivers/net/dsa/dsa_loop.c-185-{\ndrivers/net/dsa/dsa_loop.c:186:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-187-\tstruct mii_bus *bus = ps-\u003ebus;\n--\ndrivers/net/dsa/dsa_loop.c-198-\ndrivers/net/dsa/dsa_loop.c:199:static int dsa_loop_phy_write(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-200-\t\t\t int regnum, u16 value)\ndrivers/net/dsa/dsa_loop.c-201-{\ndrivers/net/dsa/dsa_loop.c:202:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-203-\tstruct mii_bus *bus = ps-\u003ebus;\n--\ndrivers/net/dsa/dsa_loop.c-214-\ndrivers/net/dsa/dsa_loop.c:215:static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-216-\t\t\t\t struct dsa_bridge bridge,\n--\ndrivers/net/dsa/dsa_loop.c-225-\ndrivers/net/dsa/dsa_loop.c:226:static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-227-\t\t\t\t struct dsa_bridge bridge)\n--\ndrivers/net/dsa/dsa_loop.c-232-\ndrivers/net/dsa/dsa_loop.c:233:static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-234-\t\t\t\t\tu8 state)\n--\ndrivers/net/dsa/dsa_loop.c-239-\ndrivers/net/dsa/dsa_loop.c:240:static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-241-\t\t\t\t\tbool vlan_filtering,\n--\ndrivers/net/dsa/dsa_loop.c-249-\ndrivers/net/dsa/dsa_loop.c:250:static int dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-251-\t\t\t\t const struct switchdev_obj_port_vlan *vlan,\n--\ndrivers/net/dsa/dsa_loop.c-255-\tbool pvid = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_PVID;\ndrivers/net/dsa/dsa_loop.c:256:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-257-\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:258:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-259-\n--\ndrivers/net/dsa/dsa_loop.c-282-\ndrivers/net/dsa/dsa_loop.c:283:static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-284-\t\t\t\t const struct switchdev_obj_port_vlan *vlan)\n--\ndrivers/net/dsa/dsa_loop.c-286-\tbool untagged = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_UNTAGGED;\ndrivers/net/dsa/dsa_loop.c:287:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-288-\tu16 pvid = ps-\u003eports[port].pvid;\ndrivers/net/dsa/dsa_loop.c-289-\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:290:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-291-\n--\ndrivers/net/dsa/dsa_loop.c-310-\ndrivers/net/dsa/dsa_loop.c:311:static int dsa_loop_port_change_mtu(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-312-\t\t\t\t int new_mtu)\ndrivers/net/dsa/dsa_loop.c-313-{\ndrivers/net/dsa/dsa_loop.c:314:\tstruct dsa_loop_priv *priv = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-315-\n--\ndrivers/net/dsa/dsa_loop.c-320-\ndrivers/net/dsa/dsa_loop.c:321:static int dsa_loop_port_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/dsa_loop.c-322-{\n--\ndrivers/net/dsa/dsa_loop.c-325-\ndrivers/net/dsa/dsa_loop.c:326:static void dsa_loop_phylink_get_caps(struct dsa_switch *dsa, int port,\ndrivers/net/dsa/dsa_loop.c-327-\t\t\t\t struct phylink_config *config)\n--\ndrivers/net/dsa/dsa_loop.c-333-\ndrivers/net/dsa/dsa_loop.c:334:static const struct dsa_switch_ops dsa_loop_driver = {\ndrivers/net/dsa/dsa_loop.c:335:\t.get_tag_protocol\t= dsa_loop_get_protocol,\ndrivers/net/dsa/dsa_loop.c:336:\t.setup\t\t\t= dsa_loop_setup,\ndrivers/net/dsa/dsa_loop.c:337:\t.teardown\t\t= dsa_loop_teardown,\ndrivers/net/dsa/dsa_loop.c:338:\t.get_strings\t\t= dsa_loop_get_strings,\ndrivers/net/dsa/dsa_loop.c:339:\t.get_ethtool_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:340:\t.get_sset_count\t\t= dsa_loop_get_sset_count,\ndrivers/net/dsa/dsa_loop.c:341:\t.get_ethtool_phy_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:342:\t.phy_read\t\t= dsa_loop_phy_read,\ndrivers/net/dsa/dsa_loop.c:343:\t.phy_write\t\t= dsa_loop_phy_write,\ndrivers/net/dsa/dsa_loop.c:344:\t.port_bridge_join\t= dsa_loop_port_bridge_join,\ndrivers/net/dsa/dsa_loop.c:345:\t.port_bridge_leave\t= dsa_loop_port_bridge_leave,\ndrivers/net/dsa/dsa_loop.c:346:\t.port_stp_state_set\t= dsa_loop_port_stp_state_set,\ndrivers/net/dsa/dsa_loop.c:347:\t.port_vlan_filtering\t= dsa_loop_port_vlan_filtering,\ndrivers/net/dsa/dsa_loop.c:348:\t.port_vlan_add\t\t= dsa_loop_port_vlan_add,\ndrivers/net/dsa/dsa_loop.c:349:\t.port_vlan_del\t\t= dsa_loop_port_vlan_del,\ndrivers/net/dsa/dsa_loop.c:350:\t.port_change_mtu\t= dsa_loop_port_change_mtu,\ndrivers/net/dsa/dsa_loop.c:351:\t.port_max_mtu\t\t= dsa_loop_port_max_mtu,\ndrivers/net/dsa/dsa_loop.c:352:\t.phylink_get_caps\t= dsa_loop_phylink_get_caps,\ndrivers/net/dsa/dsa_loop.c-353-};\ndrivers/net/dsa/dsa_loop.c-354-\ndrivers/net/dsa/dsa_loop.c:355:static int dsa_loop_drv_probe(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-356-{\ndrivers/net/dsa/dsa_loop.c:357:\tstruct dsa_loop_pdata *pdata = mdiodev-\u003edev.platform_data;\ndrivers/net/dsa/dsa_loop.c:358:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c-359-\tstruct dsa_switch *ds;\n--\ndrivers/net/dsa/dsa_loop.c-382-\tds-\u003edev = \u0026mdiodev-\u003edev;\ndrivers/net/dsa/dsa_loop.c:383:\tds-\u003eops = \u0026dsa_loop_driver;\ndrivers/net/dsa/dsa_loop.c-384-\tds-\u003epriv = ps;\n--\ndrivers/net/dsa/dsa_loop.c-396-\ndrivers/net/dsa/dsa_loop.c:397:static void dsa_loop_drv_remove(struct mdio_device *mdiodev)\n\n"
} |
| 21/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 43763 output: 35 thoughts: 38 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **Dissecting `dsa_loop_get_protocol`** Right, let's dive into this. I'm focusing on `dsa_loop.c` and specifically, the `dsa_loop_get_protocol` function. I need to understand precisely what this function is doing. Let's see how it fetches or determines the network protocol in this context. I'm looking for the nitty-gritty details here – are we checking for specific bits in a register, parsing a header, or is it based on some sort of negotiation? I'm already anticipating potential gotchas with different DSA configurations or potential driver-specific quirks. Understanding this function is crucial for understanding how the system handles network traffic and how it interacts with the switch. |
| 22/2 | 2026/10/20 15:56 | tool | grepper |
0mArgs:{
"Expression": "dsa_loop_get_protocol",
"PathPrefixes": [
"drivers/net/dsa"
]
}Results: {
"Output": "drivers/net/dsa/dsa_loop.c=97=static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds)\n--\ndrivers/net/dsa/dsa_loop.c-124-\ndrivers/net/dsa/dsa_loop.c:125:static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/dsa_loop.c-126-\t\t\t\t\t\t int port,\n--\ndrivers/net/dsa/dsa_loop.c=334=static const struct dsa_switch_ops dsa_loop_driver = {\ndrivers/net/dsa/dsa_loop.c:335:\t.get_tag_protocol\t= dsa_loop_get_protocol,\ndrivers/net/dsa/dsa_loop.c-336-\t.setup\t\t\t= dsa_loop_setup,\n"
} |
| 23/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 44264 output: 41 thoughts: 19 Thoughts: Okay, let's dive into this. Here's my understanding, presented as a personal thought process, given my expertise: **Examining `dsa_loop.c` Around Line 125** Alright, I'm thinking about `dsa_loop.c`, and specifically around line 125. That likely means something critical is happening there. My experience tells me this is probably where a crucial loop is implemented, or at least a significant step within a larger process. Given the context of "dsa", I immediately jump to some key points in my mind. Is this the loop for DSA key generation, signing, or verification? It could be involved with the modular exponentiation required, the hashing process, or some aspect of the primality testing if it's new key generation. Depending on the library, it may or may not be the optimal way to write such an operation, but likely is optimized for a balance of speed and security. Let me focus and get in there to check the specifics of that critical area, because this is where the algorithm's performance is most likely. I need to understand the variables being used, any optimizations employed, potential vulnerabilities and any areas of interest that I should analyze more closely. |
| 24/2 | 2026/10/20 15:56 | tool | read-file |
0mArgs:{
"File": "drivers/net/dsa/dsa_loop.c",
"FirstLine": 120,
"LineCount": 20
}Results: {
"Contents": " 120:\tout:\n 121:\t\tdsa_devlink_resources_unregister(ds);\n 122:\t\treturn err;\n 123:\t}\n 124:\t\n 125:\tstatic enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\n 126:\t\t\t\t\t\t\t int port,\n 127:\t\t\t\t\t\t\t enum dsa_tag_protocol mp)\n 128:\t{\n 129:\t\tdev_dbg(ds-\u003edev, \"%s: port: %d\\n\", __func__, port);\n 130:\t\n 131:\t\treturn DSA_TAG_PROTO_NONE;\n 132:\t}\n 133:\t\n 134:\tstatic int dsa_loop_setup(struct dsa_switch *ds)\n 135:\t{\n 136:\t\tstruct dsa_loop_priv *ps = ds-\u003epriv;\n 137:\t\tunsigned int i;\n 138:\t\n 139:\t\tfor (i = 0; i \u003c ds-\u003enum_ports; i++)\n"
} |
| 25/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 44878 output: 37 thoughts: 95 Thoughts: Okay, here's my take on those thoughts, framed from my expert perspective: **Investigating a Potentially Unexpected DSA Protocol Behavior** Alright, that's interesting. `dsa_loop_get_protocol` is returning `DSA_TAG_PROTO_NONE`. Hmm, that's not what I'd expect if the DSA is supposed to be doing *anything* tagged. The immediate question that pops into my head is: can the DSA loop, or indeed *any* DSA device, dynamically change its tagging protocol after it's been initialized? My initial intuition is no, but given the result, I need to verify that assumption. The next logical step is to dive into the `tagging_store` mechanism within `net/dsa/conduit.c`. I need to understand how the driver manages and stores tagging configurations. I’ll focus on how `tagging_store` functions to see if there's any logic within that could lead to a protocol change under specific circumstances or any state transitions I need to be aware of. Let's get reading! |
| 26/2 | 2026/10/20 15:56 | tool | read-file |
0mArgs:{
"File": "net/dsa/conduit.c",
"FirstLine": 345,
"LineCount": 45
}Results: {
"Contents": " 345:\t\n 346:\t\treturn sysfs_emit(buf, \"%s\\n\",\n 347:\t\t\t dsa_tag_protocol_to_str(cpu_dp-\u003etag_ops));\n 348:\t}\n 349:\t\n 350:\tstatic ssize_t tagging_store(struct device *d, struct device_attribute *attr,\n 351:\t\t\t\t const char *buf, size_t count)\n 352:\t{\n 353:\t\tconst struct dsa_device_ops *new_tag_ops, *old_tag_ops;\n 354:\t\tconst char *end = strchrnul(buf, '\\n'), *name;\n 355:\t\tstruct net_device *dev = to_net_dev(d);\n 356:\t\tstruct dsa_port *cpu_dp = dev-\u003edsa_ptr;\n 357:\t\tsize_t len = end - buf;\n 358:\t\tint err;\n 359:\t\n 360:\t\t/* Empty string passed */\n 361:\t\tif (!len)\n 362:\t\t\treturn -ENOPROTOOPT;\n 363:\t\n 364:\t\tname = kstrndup(buf, len, GFP_KERNEL);\n 365:\t\tif (!name)\n 366:\t\t\treturn -ENOMEM;\n 367:\t\n 368:\t\told_tag_ops = cpu_dp-\u003etag_ops;\n 369:\t\tnew_tag_ops = dsa_tag_driver_get_by_name(name);\n 370:\t\tkfree(name);\n 371:\t\t/* Bad tagger name? */\n 372:\t\tif (IS_ERR(new_tag_ops))\n 373:\t\t\treturn PTR_ERR(new_tag_ops);\n 374:\t\n 375:\t\tif (new_tag_ops == old_tag_ops)\n 376:\t\t\t/* Drop the temporarily held duplicate reference, since\n 377:\t\t\t * the DSA switch tree uses this tagger.\n 378:\t\t\t */\n 379:\t\t\tgoto out;\n 380:\t\n 381:\t\terr = dsa_tree_change_tag_proto(cpu_dp-\u003eds-\u003edst, new_tag_ops,\n 382:\t\t\t\t\t\told_tag_ops);\n 383:\t\tif (err) {\n 384:\t\t\t/* On failure the old tagger is restored, so we don't need the\n 385:\t\t\t * driver for the new one.\n 386:\t\t\t */\n 387:\t\t\tdsa_tag_driver_put(new_tag_ops);\n 388:\t\t\treturn err;\n 389:\t\t}\n"
} |
| 27/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 45945 output: 37 thoughts: 63 Thoughts: Okay, let's dive into this `dsa_tree_change_tag_proto` function. I need to understand its control flow. **Analyzing `dsa_tree_change_tag_proto` and Its Call to `ds->ops->change_tag_protocol`** First, I'm checking if `dsa_tree_change_tag_proto` directly calls `ds->ops->change_tag_protocol`. That's the key question here, the function call I need to verify. My next step, of course, is to read the source code of `dsa_tree_change_tag_proto` which I will find in `net/dsa/dsa.c`. I expect to see the code there that will determine what happens when the function is called. Then, I can look for the actual function pointer dereference, if it exists, to the `change_tag_protocol` function. This should be a straightforward analysis. |
| 28/2 | 2026/10/20 15:56 | tool | read-file |
0mArgs:{
"File": "net/dsa/dsa.c",
"FirstLine": 980,
"LineCount": 45
}Results: {
"Contents": " 980:\t * is that all DSA switches within a tree share the same tagger, otherwise\n 981:\t * they would have formed disjoint trees (different \"dsa,member\" values).\n 982:\t */\n 983:\tint dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\n 984:\t\t\t\t const struct dsa_device_ops *tag_ops,\n 985:\t\t\t\t const struct dsa_device_ops *old_tag_ops)\n 986:\t{\n 987:\t\tstruct dsa_notifier_tag_proto_info info;\n 988:\t\tstruct dsa_port *dp;\n 989:\t\tint err = -EBUSY;\n 990:\t\n 991:\t\tif (!rtnl_trylock())\n 992:\t\t\treturn restart_syscall();\n 993:\t\n 994:\t\t/* At the moment we don't allow changing the tag protocol under\n 995:\t\t * traffic. The rtnl_mutex also happens to serialize concurrent\n 996:\t\t * attempts to change the tagging protocol. If we ever lift the IFF_UP\n 997:\t\t * restriction, there needs to be another mutex which serializes this.\n 998:\t\t */\n 999:\t\tdsa_tree_for_each_user_port(dp, dst) {\n1000:\t\t\tif (dsa_port_to_conduit(dp)-\u003eflags \u0026 IFF_UP)\n1001:\t\t\t\tgoto out_unlock;\n1002:\t\n1003:\t\t\tif (dp-\u003euser-\u003eflags \u0026 IFF_UP)\n1004:\t\t\t\tgoto out_unlock;\n1005:\t\t}\n1006:\t\n1007:\t\t/* Notify the tag protocol change */\n1008:\t\tinfo.tag_ops = tag_ops;\n1009:\t\terr = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, \u0026info);\n1010:\t\tif (err)\n1011:\t\t\tgoto out_unwind_tagger;\n1012:\t\n1013:\t\terr = dsa_tree_bind_tag_proto(dst, tag_ops);\n1014:\t\tif (err)\n1015:\t\t\tgoto out_unwind_tagger;\n1016:\t\n1017:\t\trtnl_unlock();\n1018:\t\n1019:\t\treturn 0;\n1020:\t\n1021:\tout_unwind_tagger:\n1022:\t\tinfo.tag_ops = old_tag_ops;\n1023:\t\tdsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, \u0026info);\n1024:\tout_unlock:\n"
} |
| 29/2 | 2026/10/20 15:56 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 46969 output: 20 thoughts: 171 Thoughts: **Analyzing the DSA Switch Tag Protocol Change** Okay, so I'm looking at this `dsa_switch_change_tag_proto` function, specifically within the DSA (Distributed Switch Architecture) framework. It seems like it's responsible for, as the name suggests, changing the tagging protocol used by a DSA switch. The code snippet highlights a crucial check: it immediately verifies whether the switch's operations (`ds->ops`) implement the `change_tag_protocol` function. If that function pointer is NULL, or more accurately, if `ds->ops->change_tag_protocol` evaluates to false, the function returns `-EOPNOTSUPP`. That's standard practice, indicating the operation isn't supported by this particular switch. Now, that immediately raises a question in my mind: which DSA switches actually *do* support this feature? I need to quickly identify the specific switch implementations that have implemented the `change_tag_protocol` function in their `dsa_device_ops` structure. This is a common pattern in the Linux kernel; we have generic functions and then device-specific implementations to handle the real work. I'll need to go through the DSA driver code base, probably starting with the `dsa_device_ops` structures defined for different switch chips and look for this specific function. This will tell me which hardware this code is intended for. I'll need to use my usual methods, such as `git grep` and cross-referencing datasheets, to understand which vendors and switch models would use this function. Let's dig in and figure out the landscape of supported switches. |
| 30/2 | 2026/10/20 15:57 | tool | grepper |
0mArgs:{
"Expression": "\\.change_tag_protocol"
}Results: {
"Output": "drivers/net/dsa/mv88e6xxx/chip.c=7256=static const struct dsa_switch_ops mv88e6xxx_switch_ops = {\ndrivers/net/dsa/mv88e6xxx/chip.c-7257-\t.get_tag_protocol\t= mv88e6xxx_get_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c:7258:\t.change_tag_protocol\t= mv88e6xxx_change_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c-7259-\t.setup\t\t\t= mv88e6xxx_setup,\n--\ndrivers/net/dsa/ocelot/felix.c=2306=static const struct dsa_switch_ops felix_switch_ops = {\ndrivers/net/dsa/ocelot/felix.c-2307-\t.get_tag_protocol\t\t= felix_get_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c:2308:\t.change_tag_protocol\t\t= felix_change_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c-2309-\t.connect_tag_protocol\t\t= felix_connect_tag_protocol,\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=3416=static const struct dsa_switch_ops rtl8365mb_switch_ops = {\ndrivers/net/dsa/realtek/rtl8365mb_main.c-3417-\t.get_tag_protocol = rtl8365mb_get_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c:3418:\t.change_tag_protocol = rtl8365mb_change_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c-3419-\t.setup = rtl8365mb_setup,\n--\nnet/dsa/dsa.c=1155=static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *conduit,\n--\nnet/dsa/dsa.c-1230-\t * dsa_switch_setup_tag_protocol once .setup has run and the\nnet/dsa/dsa.c:1231:\t * driver is ready to accept calls to .change_tag_protocol. If\nnet/dsa/dsa.c-1232-\t * the driver does not support the custom protocol at that\n"
} |
| 31/2 | 2026/10/20 15:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 48176 output: 35 thoughts: 482 Thoughts: **Analyzing the Ethernet Switch Tag Protocol Implementation** Okay, so none of those switch drivers – `mv88e6xxx`, `felix`, or `rtl8365mb` – are going to play ball with `DSA_TAG_PROTO_YT922X`. Time to dig deeper. Let's see what `mv88e6xxx_change_tag_protocol` or `felix_change_tag_protocol` have to offer. Hmm, `mv88e6xxx` is locked down to DSA or EDSA, and `felix` is strictly Ocelot-tagged. `rtl8365mb`, likewise, only handles RTL tagging. This is a dead end on the software side. Now, let's turn our attention to the hardware. Specifically, the Motorcomm drivers in `drivers/net/dsa/motorcomm/`. Looking at `chip.c`, I see `yt921x_mdio_driver`. That's interesting. It looks like it uses MDIO and Device Tree matching to probe the hardware: `motorcomm,yt9215` and `motorcomm,yt9224`. The question is, can `yt921x_mdio_driver` even be probed without a *real* MDIO bus and a Device Tree describing a physical chip? Given my experience, that seems unlikely. It's expecting a real MDIO bus. Hold on a second... in the x86_64/amd64 virtual machine, where Syzkaller is running QEMU, is there even a MDIO bus or OF device tree present that creates a Motorcomm YT9224 device? No, there isn't. Remember, Motorcomm YT9215/YT9224 is an Ethernet switch chip connected via an MDIO bus. Wait a moment, can an mdio_device be created from userspace? Can I trigger it via sysfs or netlink? Let me investigate whether MDIO devices can be created from userspace or sysfs or netlink, this seems to be the only available avenue. |
| 32/2 | 2026/10/20 15:57 | tool | grepper |
0mArgs:{
"Expression": "mdio_device_create|mdio_device_register|mdiobus_register_device"
}Results: {
"Output": "drivers/net/dsa/dsa_loop.c=446=static int __init dsa_loop_create_switch_mdiodev(void)\n--\ndrivers/net/dsa/dsa_loop.c-466-\ndrivers/net/dsa/dsa_loop.c:467:\tswitch_mdiodev = mdio_device_create(bus, 31);\ndrivers/net/dsa/dsa_loop.c-468-\tif (IS_ERR(switch_mdiodev))\n--\ndrivers/net/dsa/dsa_loop.c-473-\ndrivers/net/dsa/dsa_loop.c:474:\tret = mdio_device_register(switch_mdiodev);\ndrivers/net/dsa/dsa_loop.c-475-\tif (ret)\n--\ndrivers/net/mdio/of_mdio.c=46=static int of_mdiobus_register_phy(struct mii_bus *mdio,\n--\ndrivers/net/mdio/of_mdio.c-51-\ndrivers/net/mdio/of_mdio.c:52:static int of_mdiobus_register_device(struct mii_bus *mdio,\ndrivers/net/mdio/of_mdio.c-53-\t\t\t\t struct device_node *child, u32 addr)\n--\ndrivers/net/mdio/of_mdio.c-58-\ndrivers/net/mdio/of_mdio.c:59:\tmdiodev = mdio_device_create(mdio, addr);\ndrivers/net/mdio/of_mdio.c-60-\tif (IS_ERR(mdiodev))\n--\ndrivers/net/mdio/of_mdio.c-68-\t/* All data is now stored in the mdiodev struct; register it. */\ndrivers/net/mdio/of_mdio.c:69:\trc = mdio_device_register(mdiodev);\ndrivers/net/mdio/of_mdio.c-70-\tif (rc) {\n--\ndrivers/net/mdio/of_mdio.c=139=static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np,\n--\ndrivers/net/mdio/of_mdio.c-169-\t\telse\ndrivers/net/mdio/of_mdio.c:170:\t\t\trc = of_mdiobus_register_device(mdio, child, addr);\ndrivers/net/mdio/of_mdio.c-171-\n--\ndrivers/net/pcs/pcs-lynx.c=355=struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr)\n--\ndrivers/net/pcs/pcs-lynx.c-359-\ndrivers/net/pcs/pcs-lynx.c:360:\tmdio = mdio_device_create(bus, addr);\ndrivers/net/pcs/pcs-lynx.c-361-\tif (IS_ERR(mdio))\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=337=static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-343-\t/* There is a single memory-mapped DW XPCS device */\ndrivers/net/pcs/pcs-xpcs-plat.c:344:\tmdiodev = mdio_device_create(pxpcs-\u003ebus, 0);\ndrivers/net/pcs/pcs-xpcs-plat.c-345-\tif (IS_ERR(mdiodev))\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-356-\ndrivers/net/pcs/pcs-xpcs-plat.c:357:\tret = mdio_device_register(mdiodev);\ndrivers/net/pcs/pcs-xpcs-plat.c-358-\tif (ret) {\n--\ndrivers/net/pcs/pcs-xpcs.c=1623=struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr)\n--\ndrivers/net/pcs/pcs-xpcs.c-1627-\ndrivers/net/pcs/pcs-xpcs.c:1628:\tmdiodev = mdio_device_create(bus, addr);\ndrivers/net/pcs/pcs-xpcs.c-1629-\tif (IS_ERR(mdiodev))\n--\ndrivers/net/phy/air_en8811h.c=1131=static int an8811hb_probe(struct phy_device *phydev)\n--\ndrivers/net/phy/air_en8811h.c-1150-\t */\ndrivers/net/phy/air_en8811h.c:1151:\tmdiodev = mdio_device_create(phydev-\u003emdio.bus,\ndrivers/net/phy/air_en8811h.c-1152-\t\t\t\t phydev-\u003emdio.addr + EN8811H_PBUS_ADDR_OFFS);\n--\ndrivers/net/phy/air_en8811h.c-1155-\ndrivers/net/phy/air_en8811h.c:1156:\tret = mdio_device_register(mdiodev);\ndrivers/net/phy/air_en8811h.c-1157-\tif (ret)\n--\ndrivers/net/phy/mdio_device.c-26-/**\ndrivers/net/phy/mdio_device.c:27: * mdio_device_register_reset - Read and initialize the reset properties of\ndrivers/net/phy/mdio_device.c-28- *\t\t\t\tan mdio device\n--\ndrivers/net/phy/mdio_device.c-32- */\ndrivers/net/phy/mdio_device.c:33:static int mdio_device_register_reset(struct mdio_device *mdiodev)\ndrivers/net/phy/mdio_device.c-34-{\n--\ndrivers/net/phy/mdio_device.c=113=static void mdio_device_release(struct device *dev)\n--\ndrivers/net/phy/mdio_device.c-118-\ndrivers/net/phy/mdio_device.c:119:struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)\ndrivers/net/phy/mdio_device.c-120-{\n--\ndrivers/net/phy/mdio_device.c-142-}\ndrivers/net/phy/mdio_device.c:143:EXPORT_SYMBOL(mdio_device_create);\ndrivers/net/phy/mdio_device.c-144-\ndrivers/net/phy/mdio_device.c-145-/**\ndrivers/net/phy/mdio_device.c:146: * mdio_device_register - Register the mdio device on the MDIO bus\ndrivers/net/phy/mdio_device.c-147- * @mdiodev: mdio_device structure to be added to the MDIO bus\n--\ndrivers/net/phy/mdio_device.c-150- */\ndrivers/net/phy/mdio_device.c:151:int mdio_device_register(struct mdio_device *mdiodev)\ndrivers/net/phy/mdio_device.c-152-{\n--\ndrivers/net/phy/mdio_device.c-156-\ndrivers/net/phy/mdio_device.c:157:\terr = mdiobus_register_device(mdiodev);\ndrivers/net/phy/mdio_device.c-158-\tif (err)\n--\ndrivers/net/phy/mdio_device.c-172-}\ndrivers/net/phy/mdio_device.c:173:EXPORT_SYMBOL(mdio_device_register);\ndrivers/net/phy/mdio_device.c-174-\n--\ndrivers/net/phy/mdio_device.c-180- * This doesn't free the mdio_device itself, it merely reverses the effects\ndrivers/net/phy/mdio_device.c:181: * of mdio_device_register(). Use mdio_device_free() to free the device\ndrivers/net/phy/mdio_device.c-182- * after calling this function.\n--\ndrivers/net/phy/mdio_device.c=189=EXPORT_SYMBOL(mdio_device_remove);\ndrivers/net/phy/mdio_device.c-190-\ndrivers/net/phy/mdio_device.c:191:int mdiobus_register_device(struct mdio_device *mdiodev)\ndrivers/net/phy/mdio_device.c-192-{\n--\ndrivers/net/phy/mdio_device.c-198-\tif (mdiodev-\u003eflags \u0026 MDIO_DEVICE_FLAG_PHY) {\ndrivers/net/phy/mdio_device.c:199:\t\terr = mdio_device_register_reset(mdiodev);\ndrivers/net/phy/mdio_device.c-200-\t\tif (err)\n--\ndrivers/net/phy/phy_device.c=1019=int phy_device_register(struct phy_device *phydev)\n--\ndrivers/net/phy/phy_device.c-1022-\ndrivers/net/phy/phy_device.c:1023:\terr = mdiobus_register_device(\u0026phydev-\u003emdio);\ndrivers/net/phy/phy_device.c-1024-\tif (err)\n--\ndrivers/net/phy/phylib-internal.h=26=int phy_scan_fixups(struct phy_device *phydev);\ndrivers/net/phy/phylib-internal.h-27-\ndrivers/net/phy/phylib-internal.h:28:int mdiobus_register_device(struct mdio_device *mdiodev);\ndrivers/net/phy/phylib-internal.h-29-int mdiobus_unregister_device(struct mdio_device *mdiodev);\n--\ninclude/linux/mdio.h=94=void mdio_device_free(struct mdio_device *mdiodev);\ninclude/linux/mdio.h:95:struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr);\ninclude/linux/mdio.h:96:int mdio_device_register(struct mdio_device *mdiodev);\ninclude/linux/mdio.h-97-void mdio_device_remove(struct mdio_device *mdiodev);\n"
} |
| 33/2 | 2026/10/20 15:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 51871 output: 31 thoughts: 473 Thoughts: **Investigating the `mdio_device_register` Callers and DSA Tagging** Okay, let's break this down. First, I noticed `mdio_device_register` is only called from a limited set of places: `of_mdiobus_register_device`, `dsa_loop.c`, `pcs-xpcs-plat.c`, and `air_en8811h.c`. That's a pretty tight scope. Immediately, I thought, "There's no generic userspace interface to instantiate an mdio_device? That seems odd." Then, I remembered `tag_yt922x.c`. My spidey-sense was tingling, so I dove in. How is this thing registered and used? Let's see... Ah, a `dsa_device_ops` structure. It defines the name, protocol, transmit and receive functions, and the needed headroom. We register it using `module_dsa_tag_driver`. Interesting. Now, a crucial question popped into my head: can `tag_yt922x` *ever* be invoked if there isn't a switch attached that uses the `DSA_TAG_PROTO_YT922X` tag? I have to understand the interplay here. To figure this out, I have to trace how the receive (`rcv`) and transmit (`xmit`) operations are actually called within the DSA framework. So, how does DSA intercept incoming packets in the first place? When a packet hits a network interface in DSA, how does the tagging process get triggered? My next step is clear. Time to look at `net/dsa/tag.c` to see how the DSA framework handles packet reception and how these tag operations fit into the picture. |
| 34/2 | 2026/10/20 15:57 | tool | grepper |
0mArgs:{
"Expression": "rcv.*\\(skb",
"PathPrefixes": [
"net/dsa"
]
}Results: {
"Output": "net/dsa/tag.c=54=static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,\n--\nnet/dsa/tag.c-86-\t} else {\nnet/dsa/tag.c:87:\t\tnskb = cpu_dp-\u003ercv(skb, dev);\nnet/dsa/tag.c-88-\t}\n--\nnet/dsa/tag_brcm.c=203=static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_brcm.c-207-\t/* skb-\u003edata points to the EtherType, the tag is right before it */\nnet/dsa/tag_brcm.c:208:\tnskb = brcm_tag_rcv_ll(skb, dev, 2);\nnet/dsa/tag_brcm.c-209-\tif (!nskb)\n--\nnet/dsa/tag_brcm.c=391=static struct sk_buff *brcm_tag_rcv_prepend(struct sk_buff *skb,\n--\nnet/dsa/tag_brcm.c-394-\t/* tag is prepended to the packet */\nnet/dsa/tag_brcm.c:395:\treturn brcm_tag_rcv_ll(skb, dev, ETH_HLEN);\nnet/dsa/tag_brcm.c-396-}\n--\nnet/dsa/tag_dsa.c=341=static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_dsa.c-347-\nnet/dsa/tag_dsa.c:348:\treturn dsa_rcv_ll(skb, dev, 0);\nnet/dsa/tag_dsa.c-349-}\n--\nnet/dsa/tag_dsa.c=383=static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_dsa.c-391-\nnet/dsa/tag_dsa.c:392:\treturn dsa_rcv_ll(skb, dev, EDSA_HLEN - DSA_HLEN);\nnet/dsa/tag_dsa.c-393-}\n--\nnet/dsa/tag_ksz.c=282=static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_ksz.c-298-\tif (tag[0] \u0026 KSZ9477_PTP_TAG_INDICATION) {\nnet/dsa/tag_ksz.c:299:\t\tksz_rcv_timestamp(skb, tag);\nnet/dsa/tag_ksz.c-300-\t\tlen += KSZ_PTP_TAG_LEN;\n--\nnet/dsa/tag_ksz.c-302-\nnet/dsa/tag_ksz.c:303:\treturn ksz_common_rcv(skb, dev, port, len);\nnet/dsa/tag_ksz.c-304-}\n--\nnet/dsa/tag_ksz.c=343=static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_ksz.c-353-\nnet/dsa/tag_ksz.c:354:\treturn ksz_common_rcv(skb, dev, tag[0] \u0026 KSZ8795_TAIL_TAG_EG_PORT_M,\nnet/dsa/tag_ksz.c-355-\t\t\t KSZ_EGRESS_TAG_LEN);\n--\nnet/dsa/tag_ksz.c=411=static struct sk_buff *ksz8463_rcv(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_ksz.c-444-common_rcv:\nnet/dsa/tag_ksz.c:445:\treturn ksz_common_rcv(skb, dev, port, len);\nnet/dsa/tag_ksz.c-446-}\n--\nnet/dsa/tag_ocelot_8021q.c=83=static struct sk_buff *ocelot_rcv(struct sk_buff *skb,\n--\nnet/dsa/tag_ocelot_8021q.c-87-\nnet/dsa/tag_ocelot_8021q.c:88:\tdsa_8021q_rcv(skb, \u0026src_port, \u0026switch_id, NULL, NULL);\nnet/dsa/tag_ocelot_8021q.c-89-\n--\nnet/dsa/tag_sja1105.c=475=static struct sk_buff *sja1105_rcv(struct sk_buff *skb,\n--\nnet/dsa/tag_sja1105.c-504-\tif (sja1105_skb_has_tag_8021q(skb)) {\nnet/dsa/tag_sja1105.c:505:\t\tdsa_8021q_rcv(skb, \u0026source_port, \u0026switch_id, \u0026vbid, \u0026vid);\nnet/dsa/tag_sja1105.c-506-\t} else if (source_port == -1 \u0026\u0026 switch_id == -1) {\n--\nnet/dsa/tag_sja1105.c-524-\nnet/dsa/tag_sja1105.c:525:\treturn sja1105_rcv_meta_state_machine(skb, \u0026meta, is_link_local,\nnet/dsa/tag_sja1105.c-526-\t\t\t\t\t is_meta);\n--\nnet/dsa/tag_sja1105.c=575=static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb,\n--\nnet/dsa/tag_sja1105.c-597-\tif (rx_header \u0026 SJA1110_RX_HEADER_IS_METADATA)\nnet/dsa/tag_sja1105.c:598:\t\treturn sja1110_rcv_meta(skb, rx_header);\nnet/dsa/tag_sja1105.c-599-\n--\nnet/dsa/tag_sja1105.c=644=static struct sk_buff *sja1110_rcv(struct sk_buff *skb,\n--\nnet/dsa/tag_sja1105.c-650-\tif (sja1110_skb_has_inband_control_extension(skb)) {\nnet/dsa/tag_sja1105.c:651:\t\tskb = sja1110_rcv_inband_control_extension(skb, \u0026source_port,\nnet/dsa/tag_sja1105.c-652-\t\t\t\t\t\t\t \u0026switch_id,\n--\nnet/dsa/tag_sja1105.c-659-\tif (likely(sja1105_skb_has_tag_8021q(skb)))\nnet/dsa/tag_sja1105.c:660:\t\tdsa_8021q_rcv(skb, \u0026source_port, \u0026switch_id, \u0026vbid, \u0026vid);\nnet/dsa/tag_sja1105.c-661-\n--\nnet/dsa/tag_vsc73xx_8021q.c=36=vsc73xx_rcv(struct sk_buff *skb, struct net_device *netdev)\n--\nnet/dsa/tag_vsc73xx_8021q.c-39-\nnet/dsa/tag_vsc73xx_8021q.c:40:\tdsa_8021q_rcv(skb, \u0026src_port, \u0026switch_id, \u0026vbid, \u0026vid);\nnet/dsa/tag_vsc73xx_8021q.c-41-\n"
} |
| 35/2 | 2026/10/20 15:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 54937 output: 21 thoughts: 594 Thoughts: **Analyzing the DSA Switch Tagging Protocol**
Okay, let's break this down. I'm looking at the `dsa_switch_rcv` function, specifically this line: `nskb = cpu_dp->rcv(skb, dev);`. I need to trace back where `cpu_dp->rcv` is defined. Right, it's coming from `cpu_dp->tag_ops->rcv`, and `cpu_dp->tag_ops` comes from `dst->tag_ops`. That, in turn, is set by the switch driver's `get_tag_protocol` function or via sysfs if the switch supports `change_tag_protocol`.
Now, I'm specifically thinking about the Motorcomm YT922x switch. Here's what I know:
1. It's a physical Motorcomm YT9224 switch chip, connected through an MDIO bus.
2. In my QEMU/amd64 environment, there's no actual YT9224, and no Motorcomm MDIO device described in the Device Tree.
3. The Motorcomm driver, `yt921x_mdio_probe`, isn't going to probe because it only kicks in if a matching MDIO device for `"motorcomm,yt9215"` or `"motorcomm,yt9224"` is present on the MDIO bus.
4. Can I *create* that MDIO device in QEMU? Probably not, since MDIO devices are usually registered via Device Tree (`of_mdiobus_register_device`), and x86_64 doesn't typically use DT for MDIO, and there are no mock MDIO devices for motorcomm.
5. Can the tagger `tag_yt922x` somehow be selected on *any* DSA switch? Let's see: The sysfs attribute `/sys/class/net/<conduit>/dsa/tagging` calls `dsa_tree_change_tag_proto`. This then calls `dsa_switch_change_tag_proto(ds, info)`. That, in turn, checks if the switch has a `change_tag_protocol` callback and calls it:
```c
if (!ds->ops->change_tag_protocol)
return -EOPNOTSUPP;
err = ds->ops->change_tag_protocol(ds, tag_ops->proto);
if (err)
return err;
```
The important bit: *Does any switch in the whole kernel implement a `change_tag_protocol` that would accept `DSA_TAG_PROTO_YT922X`?* I doubt it. Let's verify. I need to search the kernel source for every single implementation of `change_tag_protocol`. I'm going to start digging through the kernel code to verify my hypothesis.
|
| 36/2 | 2026/10/20 15:57 | tool | grepper |
0mArgs:{
"Expression": "change_tag_protocol.*="
}Results: {
"Output": "drivers/net/dsa/mv88e6xxx/chip.c=7256=static const struct dsa_switch_ops mv88e6xxx_switch_ops = {\ndrivers/net/dsa/mv88e6xxx/chip.c-7257-\t.get_tag_protocol\t= mv88e6xxx_get_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c:7258:\t.change_tag_protocol\t= mv88e6xxx_change_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c-7259-\t.setup\t\t\t= mv88e6xxx_setup,\n--\ndrivers/net/dsa/ocelot/felix.c=2306=static const struct dsa_switch_ops felix_switch_ops = {\ndrivers/net/dsa/ocelot/felix.c-2307-\t.get_tag_protocol\t\t= felix_get_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c:2308:\t.change_tag_protocol\t\t= felix_change_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c-2309-\t.connect_tag_protocol\t\t= felix_connect_tag_protocol,\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=3416=static const struct dsa_switch_ops rtl8365mb_switch_ops = {\ndrivers/net/dsa/realtek/rtl8365mb_main.c-3417-\t.get_tag_protocol = rtl8365mb_get_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c:3418:\t.change_tag_protocol = rtl8365mb_change_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c-3419-\t.setup = rtl8365mb_setup,\n"
} |
| 37/2 | 2026/10/20 15:57 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 56726 output: 148 thoughts: 1095 Thoughts: **WorthFuzzing Evaluation: Motorcomm YT922x Switch Driver** Okay, let's break this down. My analysis indicates that the code changes are entirely focused on the Motorcomm YT922x switch driver within the Linux kernel. I've confirmed that only three existing switch drivers (`mv88e6xxx`, `felix`, `rtl8365mb`) implement `change_tag_protocol`, and crucially, none of them support `DSA_TAG_PROTO_YT922X`. The Motorcomm YT922x switch (specifically the YT9224) is an embedded switch chip, communicating over an MDIO bus and probed via Device Tree. The critical issue is that standard QEMU amd64 fuzzing targets, which are my focus for this evaluation, neither possess the necessary hardware for this chip nor provide any emulation of it. The Device Tree configuration required for the `motorcomm,yt9224` isn't present in these environments. Thus, the `drivers/net/dsa/motorcomm/*` code path, including the `net/dsa/tag_yt922x.c` tag driver, is fundamentally unreachable. It cannot be probed or bound to any network device within a standard fuzzing environment. I've carefully reviewed Section 2 of the instructions, which defines when `WorthFuzzing=false` is appropriate. The modified code falls squarely into the "Structurally unreachable hardware" category, specifically, a vendor-specific embedded switch requiring physical hardware not emulated in the standard fuzzing environment. I've also checked all the modified files to confirm that this is the sole area of change. These are the `MAINTAINERS`, `drivers/net/dsa/motorcomm/*`, `net/dsa/tag_yt922x.c`, and the `include/net/dsa.h` header. The situation is clear: the changes are entirely bound to the YT922x hardware. Given these findings and the "REACHABILITY IS THE PRIMARY GATE" principle, I have to conclude that `WorthFuzzing` should be `false`. The `FocusSymbols` will be empty, because there's nothing to focus on, and the same goes for `EnableConfigs`. This driver will not be reachable with current available tooling. My reasoning is concise and based on the fundamental lack of hardware reachability in the target fuzzing environment. Time to call `set-results`. |
| 38/2 | 2026/10/20 15:58 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch series adds support for the Motorcomm YT9224 Ethernet switch chip and its associated DSA tagging protocol (DSA_TAG_PROTO_YT922X). The switch is a physical ASIC connected via an MDIO bus with Device Tree probing (motorcomm,yt9224), which is not present or emulated in standard QEMU amd64 virtualized fuzzing environments. Furthermore, the new tagging protocol tag_yt922x cannot be bound or exercised by any virtual or alternate switch. Therefore, the modified code is structurally unreachable.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch series adds support for the Motorcomm YT9224 Ethernet switch chip and its associated DSA tagging protocol (DSA_TAG_PROTO_YT922X). The switch is a physical ASIC connected via an MDIO bus with Device Tree probing (motorcomm,yt9224), which is not present or emulated in standard QEMU amd64 virtualized fuzzing environments. Furthermore, the new tagging protocol tag_yt922x cannot be bound or exercised by any virtual or alternate switch. Therefore, the modified code is structurally unreachable.",
"WorthFuzzing": false
} |
| 39/1 | 2026/10/20 15:58 | 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) |
|---|