AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/08 08:59 flow patch-triage
1m Args:
null

Results:
{
  "EnableConfigs": [
    "NET_DSA",
    "NET_DSA_TAG_YT922X",
    "NET_DSA_YT921X"
  ],
  "FocusSymbols": [
    "yt922x_tag_rcv",
    "yt922x_tag_xmit",
    "yt922x_dsa_setup",
    "yt922x_port_setup",
    "yt922x_pcs_config",
    "yt922x_pcs_get_state",
    "yt92xx_register_switch"
  ],
  "KMSANReasoning": "The patch introduces support for Motorcomm YT922x switches to the existing YT921x DSA driver and adds a new DSA tag driver (`tag_yt922x.c`).\n\nAnalysis of uninitialized memory risk:\n1. All private device structures are allocated using `devm_kzalloc()`, ensuring all fields are zero-initialized.\n2. In `yt922x_tag_xmit()`, the 8-byte tag inserted into outgoing packets is completely populated (`tag[0]`, `tag[1]`, `tag[2]`, `tag[3]` are all explicitly assigned), leaving no uninitialized padding or bytes.\n3. In `yt922x_tag_rcv()`, the packet length is validated using `pskb_may_pull()` before parsing header fields.\n4. Internal register read functions check return values before using output variables.\n5. No new user-space copies (`copy_to_user`, `put_user`, socket options, or netlink attributes) are introduced or modified.\n\nAny potential memory issues (e.g. out-of-bounds access or race conditions) are within the scope of KASAN/LOCKDEP. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series introduces a new DSA tagging driver (net/dsa/tag_yt922x.c) implementing packet receive (yt922x_tag_rcv) and transmit (yt922x_tag_xmit) tagging operations, and extends the Motorcomm switch driver (drivers/net/dsa/motorcomm/chip.c) to support the YT922x series. DSA tag parsing and frame generation execute in the network packet path and can be exercised in virtualized environments using DSA conduits, mock interfaces, or packet sockets.",
  "WorthFuzzing": true
}

1/1 2026/09/08 08:59 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 3a66b7892ba11c710bd496d44cf1b2bc9a8089c5\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Tue Sep 8 08:59:49 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig\nindex 79cdd79a1fd25..f690de4c7a7c5 100644\n--- a/drivers/net/dsa/motorcomm/Kconfig\n+++ b/drivers/net/dsa/motorcomm/Kconfig\n@@ -2,6 +2,7 @@\n config NET_DSA_YT921X\n \ttristate \"Motorcomm YT9215 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\ndiff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c\nindex d663af010f431..4a052b1886b51 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@@ -112,6 +112,7 @@ struct yt921x_info {\n #define YT921X_PORT_MASK_INT0_n(n)\tGENMASK((n) - 1, 0)\n #define YT921X_PORT_MASK_EXT0\t\tBIT(8)\n #define YT921X_PORT_MASK_EXT1\t\tBIT(9)\n+#define YT922X_PORT_MASK_INTm_n(m, n)\tGENMASK((n), (m))\n \n static const struct yt921x_info yt921x_infos[] = {\n \t{\n@@ -149,9 +150,17 @@ static const struct yt921x_info yt921x_infos[] = {\n \t\tYT921X_PORT_MASK_INT0_n(8),\n \t\tYT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,\n \t},\n+\t{\n+\t\t\"YT9224\", YT9224_MAJOR, 0, 0,\n+\t\tYT922X_PORT_MASK_INTm_n(4, 7) | YT921X_PORT_MASK_INTn(0) | YT921X_PORT_MASK_INTn(8),\n+\t\t0x0,\n+\t},\n \t{}\n };\n \n+/* Define top ext addr */\n+#define YT922X_COMMON_EXT_PHYADDR\t9\n+\n #define YT921X_VID_UNWARE\t4095\n \n /* The interval should be small enough to avoid overflow of 32bit MIBs.\n@@ -357,7 +366,7 @@ static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)\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@@ -375,7 +384,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@@ -390,6 +399,7 @@ yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)\n {\n \tstruct device *dev = to_device(priv);\n \tstruct mii_bus *mbus;\n+\tu32 max_ports;\n \tint res;\n \n \tmbus = devm_mdiobus_alloc(dev);\n@@ -402,7 +412,8 @@ 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 = (u32)~GENMASK(max_ports - 1, 0);\n \n \tres = devm_of_mdiobus_register(dev, mbus, mnp);\n \tif (res)\n@@ -4231,6 +4242,11 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds)\n #if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\n \tyt921x_leds_remove(priv);\n #endif\n+\tfor (size_t i = ARRAY_SIZE(priv-\u003eports); i-- \u003e 0; ) {\n+\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\n+\n+\t\tdisable_delayed_work_sync(\u0026pp-\u003emib_read);\n+\t}\n }\n \n static int yt921x_chip_detect(struct yt921x_priv *priv)\n@@ -4551,6 +4567,14 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)\n \tstruct device_node *child;\n \tint res;\n \n+\t/* mib polling init */\n+\tfor (size_t i = 0; i \u003c ARRAY_SIZE(priv-\u003eports); i++) {\n+\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\n+\n+\t\tpp-\u003eindex = i;\n+\t\tINIT_DELAYED_WORK(\u0026pp-\u003emib_read, yt921x_poll_mib);\n+\t}\n+\n \tmutex_lock(\u0026priv-\u003ereg_lock);\n \tres = yt921x_chip_reset(priv);\n \tmutex_unlock(\u0026priv-\u003ereg_lock);\n@@ -4679,99 +4703,984 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {\n \t.setup\t\t\t= yt921x_dsa_setup,\n };\n \n-static void yt921x_mdio_shutdown(struct mdio_device *mdiodev)\n+static int yt922x_port_down(struct yt921x_priv *priv, int port)\n {\n-\tstruct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);\n+\tu32 mask;\n+\tint res;\n \n-\tif (!priv)\n-\t\treturn;\n+\t/* mac force down */\n+\tmask = YT922X_PORT_LINK | YT922X_PORT_RX_MAC_EN |\n+\t\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-\tdsa_switch_shutdown(\u0026priv-\u003eds);\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 yt921x_mdio_remove(struct mdio_device *mdiodev)\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 yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);\n+\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n+\tstruct yt921x_priv *priv = to_yt921x_priv(dp-\u003eds);\n+\tint port = dp-\u003eindex;\n+\tint res;\n \n-\tif (!priv)\n-\t\treturn;\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_port_down(priv, port);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n \n-\tfor (size_t i = ARRAY_SIZE(priv-\u003eports); i-- \u003e 0; ) {\n-\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\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-\t\tdisable_delayed_work_sync(\u0026pp-\u003emib_read);\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+\tu32 mask;\n+\tu32 ctrl;\n+\tint res;\n+\n+\tswitch (speed) {\n+\tcase SPEED_10:\n+\t\tctrl = YT921X_PORT_SPEED_10;\n+\t\tbreak;\n+\tcase SPEED_100:\n+\t\tctrl = YT921X_PORT_SPEED_100;\n+\t\tbreak;\n+\tcase SPEED_1000:\n+\t\tctrl = YT921X_PORT_SPEED_1000;\n+\t\tbreak;\n+\tcase SPEED_2500:\n+\t\tctrl = YT921X_PORT_SPEED_2500;\n+\t\tbreak;\n+\tcase SPEED_5000:\n+\t\tctrl = YT921X_PORT_SPEED_5000;\n+\t\tbreak;\n+\tcase SPEED_10000:\n+\t\tctrl = YT921X_PORT_SPEED_10000;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n \t}\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\tYT922X_PORT_CFG_TX_EN | YT922X_PORT_LINK |\n+\t\tYT922X_PORT_CFG_RX_EN;\n+\tctrl \u0026= ~(YT922X_PORT_FC_AN | YT922X_PORT_LINK_AN);\n+\tres = yt921x_reg_write(priv, YT922X_PORTn_CTRL(port), ctrl);\n+\tif (res)\n+\t\treturn res;\n \n-\tdsa_unregister_switch(\u0026priv-\u003eds);\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-\tfor (unsigned int i = 0; i \u003c ARRAY_SIZE(priv-\u003eacl_blks); i++) {\n-\t\tstruct yt921x_acl_blk *aclblk = priv-\u003eacl_blks[i];\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-\t\tif (!aclblk)\n-\t\t\tcontinue;\n-\t\tfor (unsigned int j = 0; j \u003c ARRAY_SIZE(aclblk-\u003erules); j++) {\n-\t\t\tstruct yt921x_acl_rule *aclrule = aclblk-\u003erules[j];\n+\treturn 0;\n+}\n \n-\t\t\tif (!aclrule)\n-\t\t\t\tcontinue;\n-\t\t\tkvfree(aclrule);\n-\t\t}\n-\t\tkvfree(aclblk);\n-\t}\n-\tmutex_destroy(\u0026priv-\u003ereg_lock);\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 = 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 yt921x_mdio_probe(struct mdio_device *mdiodev)\n+static int\n+yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg, u16 val)\n {\n-\tstruct device *dev = \u0026mdiodev-\u003edev;\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-\t\treturn -ENOMEM;\n+\tif (port \u003e= priv-\u003eseries-\u003emax_ports)\n+\t\treturn -ENODEV;\n \n-\tmdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);\n-\tif (!mdio)\n-\t\treturn -ENOMEM;\n+\tres = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);\n+\tif (res)\n+\t\treturn res;\n \n-\tmdio-\u003ebus = mdiodev-\u003ebus;\n-\tmdio-\u003eaddr = mdiodev-\u003eaddr;\n-\tmdio-\u003eswitchid = 0;\n+\tres = yt921x_intif_write(priv, port, YT92XX_PAGE, val);\n+\tif (res)\n+\t\treturn res;\n \n-\tmutex_init(\u0026priv-\u003ereg_lock);\n+\treturn 0;\n+}\n \n-\tpriv-\u003ereg_ops = \u0026yt921x_reg_ops_mdio;\n-\tpriv-\u003ereg_ctx = mdio;\n+static int\n+yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\n+{\n+\tint res;\n \n-\tfor (size_t i = 0; i \u003c ARRAY_SIZE(priv-\u003eports); i++) {\n-\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\n+\tif (port \u003e= priv-\u003eseries-\u003emax_ports)\n+\t\treturn -ENODEV;\n \n-\t\tpp-\u003eindex = i;\n-\t\tINIT_DELAYED_WORK(\u0026pp-\u003emib_read, yt921x_poll_mib);\n-\t}\n+\tres = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);\n+\tif (res)\n+\t\treturn res;\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 = yt921x_intif_read(priv, port, YT92XX_PAGE, valp);\n+\tif (res)\n+\t\treturn res;\n \n-\tmdiodev_set_drvdata(mdiodev, priv);\n+\treturn 0;\n+}\n \n-\treturn dsa_register_switch(ds);\n+static int yt922x_sds_phyaddr_get(int port,\n+\t\t\t\t  enum yt922x_phy_reg_type reg_type,\n+\t\t\t\t  enum yt922x_phy_reg_space reg_space)\n+{\n+\tint res = port;\n+\n+\t/*\n+\t * sds phyaddr mapping depend on reg_type and reg_space\n+\t */\n+\tif (!yt922x_port_is_internal_sds(port))\n+\t\treturn -EOPNOTSUPP;\n+\tif (reg_type == YT922X_PHY_REG_TYPE_COMMON_EXT) {\n+\t\tres = YT922X_COMMON_EXT_PHYADDR;\n+\t\treturn res;\n+\t}\n+\n+\treturn res;\n }\n \n-static const struct of_device_id yt921x_of_match[] = {\n-\t{ .compatible = \"motorcomm,yt9215\" },\n-\t{}\n+/**\n+ * Initialize serdes configuration based on interface mode.\n+ */\n+static int yt922x_sds_init(struct yt921x_priv *priv, int port,\n+\t\t\t   phy_interface_t interface)\n+{\n+\tint addr;\n+\tu16 data;\n+\tint res;\n+\n+\taddr = yt922x_sds_phyaddr_get\n+\t\t(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,\n+\t\t YT922X_PHY_REG_SPACE_SGMII);\n+\tif (addr \u003c 0)\n+\t\treturn -EINVAL;\n+\t/* write protect */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4be, 0xd);\n+\tif (res)\n+\t\treturn res;\n+\t/* CDR */\n+\tif (interface == PHY_INTERFACE_MODE_100BASEX) {\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x406, 0x0);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x416, 0x3458);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t} else {\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x406, 0x800);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x416, 0x4558);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\t/* PLL */\n+\tif (interface == PHY_INTERFACE_MODE_USXGMII) {\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x43a, 0x1006);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x43f, 0x3029);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x42a, 0xf070);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t} else {\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x43d, 0x207d);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x43c, 0x207d);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x43f, 0x3032);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x43a, 0x6);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x42a, 0xf070);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\t/* VCO */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x439, 0xC0);\n+\tif (res)\n+\t\treturn res;\n+\t/* Vdac */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x492, 0x7f7f);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x491, 0x7f);\n+\tif (res)\n+\t\treturn res;\n+\t/* Eye */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x454, 0xf14);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x497, 0xa44);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4cd, 0x0);\n+\tif (res)\n+\t\treturn res;\n+\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4af, 0x45e3);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x48a, 0xfff);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x408, 0x7c00);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4d6, 0x7f);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x44f, 0xff08);\n+\tif (res)\n+\t\treturn res;\n+\t/* FFE */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x48e, 0x7d00);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0xd, 0x60f);\n+\tif (res)\n+\t\treturn res;\n+\t/* CTLE */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4b0, 0x804);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4b1, 0x7774);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x4af, 0x45e7);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x3, 0x5603);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmsleep(20);\n+\tres = yt921x_intif_ext_write(priv, addr, 0x492, 0x7fff);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x492, 0x7f7f);\n+\tif (res)\n+\t\treturn res;\n+\t/* CTLE */\n+\tres = yt921x_intif_ext_write(priv, addr, 0x2000, 0x40);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_intif_ext_write(priv, addr, 0x2000, 0x0);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif (interface == PHY_INTERFACE_MODE_SGMII) {\n+\t\tres = yt921x_intif_ext_write(priv, addr, 0x1042, 0x48c);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\t/* soft reset */\n+\taddr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII,\n+\t\t\t\t      YT922X_PHY_REG_SPACE_SGMII);\n+\tif (addr \u003c 0)\n+\t\treturn res;\n+\tres = yt921x_intif_read(priv, addr, 0x0, \u0026data);\n+\tif (res)\n+\t\treturn res;\n+\tdata \u0026= ~(1 \u003c\u003c 15);\n+\tres = yt921x_intif_write(priv, addr, 0x0, data);\n+\tif (res)\n+\t\treturn res;\n+\taddr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII,\n+\t\t\t\t      YT922X_PHY_REG_SPACE_USXGMII);\n+\tif (addr \u003c 0)\n+\t\treturn res;\n+\tres = yt921x_intif_read(priv, addr, 0x0, \u0026data);\n+\tif (res)\n+\t\treturn res;\n+\tdata |= 1 \u003c\u003c 15;\n+\tres = yt921x_intif_write(priv, addr, 0x0, data);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 0;\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+}\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 = dp-\u003eds-\u003epriv;\n+\tstruct phylink_pcs *pcs = NULL;\n+\tint port = dp-\u003eindex;\n+\n+\tswitch (interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\tcase PHY_INTERFACE_MODE_USXGMII:\n+\t\tswitch (port) {\n+\t\tcase 0:\n+\t\t\tpcs = \u0026priv-\u003epcs_port_0.pcs;\n+\t\t\tbreak;\n+\n+\t\tcase 8:\n+\t\t\tpcs = \u0026priv-\u003epcs_port_8.pcs;\n+\t\t\tbreak;\n+\t\t}\n+\t\tbreak;\n+\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn pcs;\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 struct yt922x_pcs *pcs_to_yt922x_pcs(struct phylink_pcs *pcs)\n+{\n+\treturn container_of(pcs, struct yt922x_pcs, pcs);\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_priv *priv = pcs_to_yt922x_pcs(pcs)-\u003epriv;\n+\tint port = pcs_to_yt922x_pcs(pcs)-\u003eport;\n+\tu32 reg;\n+\tint res;\n+\n+\tres = yt921x_reg_read(priv, YT922X_PORTn_STATUS(port), \u0026reg);\n+\tif (res \u003c 0) {\n+\t\tstate-\u003elink = false;\n+\t\treturn;\n+\t}\n+\n+\tstate-\u003elink = !!(reg \u0026 YT922X_PORT_LINK_STATE);\n+\tstate-\u003ean_complete = state-\u003elink;\n+\tstate-\u003eduplex = (reg \u0026 YT922X_PORT_LINK_DUPLEX) ? DUPLEX_FULL :\n+\t\t\t\t\t\t\t  DUPLEX_HALF;\n+\n+\tswitch (reg \u0026 YT922X_PORT_SPEED_M) {\n+\tcase YT922X_PORT_SPEED_10:\n+\t\tstate-\u003espeed = SPEED_10;\n+\t\tbreak;\n+\tcase YT922X_PORT_SPEED_100:\n+\t\tstate-\u003espeed = SPEED_100;\n+\t\tbreak;\n+\tcase YT922X_PORT_SPEED_1000:\n+\t\tstate-\u003espeed = SPEED_1000;\n+\t\tbreak;\n+\tcase YT922X_PORT_SPEED_10000:\n+\t\tstate-\u003espeed = SPEED_10000;\n+\t\tbreak;\n+\tcase YT922X_PORT_SPEED_2500:\n+\t\tstate-\u003espeed = SPEED_2500;\n+\t\tbreak;\n+\tcase YT922X_PORT_SPEED_5000:\n+\t\tstate-\u003espeed = SPEED_5000;\n+\t\tbreak;\n+\tdefault:\n+\t\tstate-\u003espeed = SPEED_UNKNOWN;\n+\t\tbreak;\n+\t}\n+}\n+\n+static void yt922x_pcs_an_restart(struct phylink_pcs *pcs)\n+{\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+\tstruct yt921x_priv *priv = pcs_to_yt922x_pcs(pcs)-\u003epriv;\n+\tint res, port;\n+\tu16 data;\n+\tu16 ctrl;\n+\tint addr;\n+\n+\tport = pcs_to_yt922x_pcs(pcs)-\u003eport;\n+\tif (port != 0 \u0026\u0026 port != 8)\n+\t\treturn -EINVAL;\n+\n+\t/* SERDES init and interface configuration */\n+\tres = yt922x_sds_init(priv, port, interface);\n+\n+\tswitch (interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\t\tctrl = YT92XX_SERDES_MODE_SGMII;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\t\tctrl = YT92XX_SERDES_MODE_100BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\t\tctrl = YT92XX_SERDES_MODE_1000BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\tctrl = YT92XX_SERDES_MODE_2500BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_USXGMII:\n+\t\tctrl = YT92XX_SERDES_MODE_USXGMII;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EINVAL;\n+\t}\n+\taddr = yt922x_sds_phyaddr_get\n+\t\t(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,\n+\t\t YT922X_PHY_REG_SPACE_SGMII);\n+\tif (addr \u003c 0)\n+\t\treturn -EINVAL;\n+\n+\tres = yt921x_intif_ext_read(priv, addr, YT922X_PORT_SDSn, \u0026data);\n+\tif (res)\n+\t\treturn res;\n+\tdata \u0026= ~YT922X_SERDES_MODE_M;\n+\tdata |= ctrl;\n+\tres = yt921x_intif_ext_write(priv, addr, YT922X_PORT_SDSn, data);\n+\n+\treturn res;\n+}\n+\n+static const struct phylink_pcs_ops yt922x_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+};\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 = 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\tif (port \u003e= 4 \u0026\u0026 port \u003c= 7) {\n+\t\t\t/* port 4 to port 7, internal utp */\n+\t\t\t__set_bit(PHY_INTERFACE_MODE_INTERNAL,\n+\t\t\t\t  config-\u003esupported_interfaces);\n+\t\t\tconfig-\u003emac_capabilities |= MAC_2500FD;\n+\t\t} else {\n+\t\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n+\t\t\t\t  config-\u003esupported_interfaces);\n+\t\t\t__set_bit(PHY_INTERFACE_MODE_100BASEX,\n+\t\t\t\t  config-\u003esupported_interfaces);\n+\t\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n+\t\t\t\t  config-\u003esupported_interfaces);\n+\t\t\t__set_bit(PHY_INTERFACE_MODE_2500BASEX,\n+\t\t\t\t  config-\u003esupported_interfaces);\n+\t\t\tconfig-\u003emac_capabilities |= MAC_2500FD;\n+\t\t\t__set_bit(PHY_INTERFACE_MODE_USXGMII,\n+\t\t\t\t  config-\u003esupported_interfaces);\n+\t\t\tconfig-\u003emac_capabilities |= MAC_2500FD;\n+\t\t\tconfig-\u003emac_capabilities |= MAC_5000FD;\n+\t\t\tconfig-\u003emac_capabilities |= MAC_10000FD;\n+\t\t}\n+\t} else {\n+\t\t/* external port will added later */\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 = 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_chip_detect(struct yt921x_priv *priv)\n+{\n+\tstruct device *dev = to_device(priv);\n+\tconst struct yt921x_info *info;\n+\tu32 chipid;\n+\tu32 major;\n+\tint res;\n+\n+\tres = yt921x_reg_read(priv, YT921X_CHIP_ID, \u0026chipid);\n+\tif (res)\n+\t\treturn res;\n+\tmajor = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);\n+\tfor (info = yt921x_infos; info-\u003ename; info++)\n+\t\tif (info-\u003emajor == major)\n+\t\t\tbreak;\n+\tif (!info-\u003ename) {\n+\t\tdev_err(dev, \"Unexpected chipid 0x%x\\n\", chipid);\n+\t\treturn -ENODEV;\n+\t}\n+\tpriv-\u003einfo = info;\n+\n+\treturn 0;\n+}\n+\n+static int yt922x_chip_reset(struct yt921x_priv *priv)\n+{\n+\tstruct device *dev = to_device(priv);\n+\tu16 eth_p_tag;\n+\tu32 val;\n+\tint res;\n+\n+\tres = yt922x_chip_detect(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* Reset */\n+\tres = yt921x_reg_write(priv, YT921X_RST, YT921X_RST_HW);\n+\tif (res)\n+\t\treturn res;\n+\n+\tfsleep(YT921X_RST_DELAY_US);\n+\n+\tval = 0;\n+\tres = yt921x_reg_wait(priv, YT921X_RST, ~0, \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\t/* TPID check */\n+\tres = yt921x_reg_read(priv, YT921X_CPU_TAG_TPID, \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\teth_p_tag = FIELD_GET(YT921X_CPU_TAG_TPID_TPID_M, val);\n+\tif (eth_p_tag != ETH_P_YT921X) {\n+\t\tdev_err(dev, \"Tag type 0x%x != 0x%x\\n\", eth_p_tag,\n+\t\t\tETH_P_YT921X);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\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+\tctrl = GENMASK(9, 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 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 void yt922x_setup_pcs(struct yt921x_priv *priv, struct yt922x_pcs *pcs,\n+\t\t\t     int port)\n+{\n+\tpcs-\u003epcs.ops = \u0026yt922x_pcs_ops;\n+\n+\tpcs-\u003epriv = priv;\n+\tpcs-\u003eport = port;\n+}\n+\n+static int yt922x_dsa_setup(struct dsa_switch *ds)\n+{\n+\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\n+\tstruct device *dev = 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 = yt922x_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+\t/* cpu port set */\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt922x_cpu_port_set(priv);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tif (res)\n+\t\treturn res;\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_setup_pcs(priv, \u0026priv-\u003epcs_port_0, 0);\n+\tyt922x_setup_pcs(priv, \u0026priv-\u003epcs_port_8, 8);\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.mode = 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.mode = 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+\tenum yt92xx_mode mode = YT92XX_MODE_MAX;\n+\tint i;\n+\n+\tif (major == YT9215_MAJOR || major == YT9218_MAJOR)\n+\t\tmode = YT92XX_MODE_YT921X;\n+\telse if (major == YT9224_MAJOR)\n+\t\tmode = YT92XX_MODE_YT922X;\n+\telse\n+\t\tmode = YT92XX_MODE_MAX;\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(yt92xx_series_table); ++i)\n+\t\tif (yt92xx_series_table[i].mode == mode)\n+\t\t\treturn \u0026yt92xx_series_table[i];\n+\n+\treturn NULL;\n+}\n+\n+static int yt92xx_register_switch(struct dsa_switch *ds)\n+{\n+\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\n+\tconst struct yt92xx_series *series;\n+\tu32 chipid;\n+\tu32 major;\n+\tint res;\n+\n+\tres = yt921x_reg_read(priv, YT921X_CHIP_ID, \u0026chipid);\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\treturn -ENODEV;\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+\n+\tif (!priv)\n+\t\treturn;\n+\n+\tdsa_switch_shutdown(\u0026priv-\u003eds);\n+}\n+\n+static void yt921x_mdio_remove(struct mdio_device *mdiodev)\n+{\n+\tstruct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);\n+\n+\tif (!priv)\n+\t\treturn;\n+\n+\tdsa_unregister_switch(\u0026priv-\u003eds);\n+\n+\tfor (unsigned int i = 0; i \u003c ARRAY_SIZE(priv-\u003eacl_blks); i++) {\n+\t\tstruct yt921x_acl_blk *aclblk = priv-\u003eacl_blks[i];\n+\n+\t\tif (!aclblk)\n+\t\t\tcontinue;\n+\t\tfor (unsigned int j = 0; j \u003c ARRAY_SIZE(aclblk-\u003erules); j++) {\n+\t\t\tstruct yt921x_acl_rule *aclrule = aclblk-\u003erules[j];\n+\n+\t\t\tif (!aclrule)\n+\t\t\t\tcontinue;\n+\t\t\tkvfree(aclrule);\n+\t\t}\n+\t\tkvfree(aclblk);\n+\t}\n+\tmutex_destroy(\u0026priv-\u003ereg_lock);\n+}\n+\n+static int yt921x_mdio_probe(struct mdio_device *mdiodev)\n+{\n+\tstruct device *dev = \u0026mdiodev-\u003edev;\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+\t\treturn -ENOMEM;\n+\n+\tmdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);\n+\tif (!mdio)\n+\t\treturn -ENOMEM;\n+\n+\tmdio-\u003ebus = mdiodev-\u003ebus;\n+\tmdio-\u003eaddr = mdiodev-\u003eaddr;\n+\tmdio-\u003eswitchid = 0;\n+\n+\tmutex_init(\u0026priv-\u003ereg_lock);\n+\n+\tpriv-\u003ereg_ops = \u0026yt921x_reg_ops_mdio;\n+\tpriv-\u003ereg_ctx = mdio;\n+\n+\tds = \u0026priv-\u003eds;\n+\tds-\u003edev = dev;\n+\tres = yt92xx_register_switch(ds);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmdiodev_set_drvdata(mdiodev, priv);\n+\n+\treturn dsa_register_switch(ds);\n+}\n+\n+static const struct of_device_id yt921x_of_match[] = {\n+\t{\n+\t\t.compatible = \"motorcomm,yt9215\",\n+\t},\n+\t{\n+\t\t.compatible = \"motorcomm,yt9224\",\n+\t},\n+\t{ /* sentinel */ }\n };\n MODULE_DEVICE_TABLE(of, yt921x_of_match);\n \n@@ -4788,5 +5697,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 83cd454955ddb..3b7ea3cbf5227 100644\n--- a/drivers/net/dsa/motorcomm/chip.h\n+++ b/drivers/net/dsa/motorcomm/chip.h\n@@ -111,6 +111,7 @@\n #define   YT921X_PORT_SPEED_1000\t\t\tYT921X_PORT_SPEED(2)\n #define   YT921X_PORT_SPEED_10000\t\t\tYT921X_PORT_SPEED(3)\n #define   YT921X_PORT_SPEED_2500\t\t\tYT921X_PORT_SPEED(4)\n+#define   YT921X_PORT_SPEED_5000\t\t\tYT921X_PORT_SPEED(5)\n #define YT921X_PON_STRAP_FUNC\t\t0x80320\n #define YT921X_PON_STRAP_VAL\t\t0x80324\n #define YT921X_PON_STRAP_CAP\t\t0x80328\n@@ -837,6 +838,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@@ -861,6 +863,99 @@ enum yt921x_fdb_entry_status {\n #define yt921x_port_is_internal(port) ((port) \u003c 8)\n #define yt921x_port_is_external(port) ((port) == 8 || (port) == 9)\n \n+/* yt922x register lists */\n+#define YT92XX_PAGE_SELECT\t0x1e\n+#define YT92XX_PAGE\t\t0x1f\n+#define YT922X_PORTn_STATUS(port)\t(0x80200 + 4 * (port))\n+#define  YT922X_PORT_LINK_STATE\t\t\tBIT(8)\n+#define  YT922X_PORT_LINK_DUPLEX\t\tBIT(7)\n+#define  YT922X_PORT_RX_FC_EN\t\t\tBIT(6)\n+#define  YT922X_PORT_TX_FC_EN\t\t\tBIT(5)\n+#define YT922X_PORT_SPEED_10\t\t0\n+#define YT922X_PORT_SPEED_100\t\t1\n+#define YT922X_PORT_SPEED_1000\t\t2\n+#define YT922X_PORT_SPEED_10000\t\t3\n+#define YT922X_PORT_SPEED_2500\t\t4\n+#define YT922X_PORT_SPEED_5000\t\t5\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\t0x400\n+#define  YT922X_SERDES_MODE_M\t\tGENMASK(6, 4)\n+#define   YT922X_SERDES_MODE(x)\t\t\tFIELD_PREP(YT922X_SERDES_MODE_M, (x))\n+#define YT92XX_SERDES_MODE_SGMII\tYT922X_SERDES_MODE(0)\n+#define YT92XX_SERDES_MODE_REVSGMII\tYT921X_SERDES_MODE(1)\n+#define YT92XX_SERDES_MODE_1000BASEX\tYT921X_SERDES_MODE(2)\n+#define YT92XX_SERDES_MODE_100BASEX\tYT921X_SERDES_MODE(3)\n+#define YT92XX_SERDES_MODE_2500BASEX\tYT921X_SERDES_MODE(4)\n+#define YT92XX_SERDES_MODE_USXGMII\tYT922X_SERDES_MODE(6)\n+#define YT922X_PORT_NUM\t\t9\n+\n+/* LAG */\n+#define YT922X_LAG_NUM\t\t4\n+/* ISO */\n+#define YT922X_PORTn_ISOLATION(port)\t(0x4 * (port) + 0x180d80)\n+/* FDB */\n+#define YT922X_PORTn_LEARN(port)\t(0x180300 + 4 * (port))\n+#define  YT922X_PORT_LEARN_DIS\t\t\tBIT(18)\n+/* GLOBAL CTRL */\n+#define  YT922X_FUNC_ACL               BIT(5)\n+#define  YT922X_FUNC_MIB               BIT(4)\n+/* CTRL PKT */\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\tGENMASK(2 * (port) + 1, 2 * (port))\n+#define  YT922X_ACT_UNK_ACTn(port, x)\t\t((x) \u003c\u003c (2 * (port)))\n+#define  YT922X_ACT_UNK_ACTn_FORWARD(port)\tYT922X_ACT_UNK_ACTn(port, 0)  /* flood */\n+#define  YT922X_ACT_UNK_ACTn_DROP(port)\t\tYT922X_ACT_UNK_ACTn(port, 1)  /* discard */\n+#define  YT922X_ACT_UNK_ACTn_TRAP(port)\t\tYT922X_ACT_UNK_ACTn(port, 3)  /* steer to CPU */\n+\n+/* CPU PORT */\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\t\tBIT(0)\n+#define  YT922X_CPU_TAG_TX_MODE\t\t\tBIT(1)\n+#define  YT922X_CPU_TAG_TX_CTAG_OP\t\tBIT(2)\n+#define  YT922X_CPU_TAG_TX_STAG_OP\t\tBIT(3)\n+\n+#define yt922x_port_is_internal_sds(port) ((port) == 0 || (port) == 8)\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+enum yt922x_phy_reg_space {\n+\tYT922X_PHY_REG_SPACE_SGMII,\n+\tYT922X_PHY_REG_SPACE_USXGMII,\n+\tYT922X_PHY_REG_SPACE_MAX\n+};\n+\n struct yt921x_mib {\n \tu64 rx_broadcast;\n \tu64 rx_pause;\n@@ -960,9 +1055,35 @@ struct yt921x_reg_ops {\n \tint (*write)(void *context, u32 reg, u32 val);\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+\tenum yt92xx_mode mode;\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 yt922x_pcs {\n+\tstruct phylink_pcs pcs;\n+\tstruct yt921x_priv *priv;\n+\tint port;\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@@ -987,6 +1108,8 @@ struct yt921x_priv {\n \n \tu8 acl_masks[YT921X_ACL_BLK_NUM];\n \tstruct yt921x_acl_blk *acl_blks[YT921X_ACL_BLK_NUM];\n+\tstruct yt922x_pcs pcs_port_0;\n+\tstruct yt922x_pcs pcs_port_8;\n };\n \n #endif\ndiff --git a/include/net/dsa.h b/include/net/dsa.h\nindex 7507d632e7c6d..0807a595aaad0 100644\n--- a/include/net/dsa.h\n+++ b/include/net/dsa.h\n@@ -61,6 +61,7 @@ struct tc_action;\n #define DSA_TAG_PROTO_NETC_VALUE\t\t33\n #define DSA_TAG_PROTO_KSZ8463_VALUE\t\t34\n #define DSA_TAG_PROTO_MT7628_VALUE\t\t35\n+#define DSA_TAG_PROTO_YT922X_VALUE\t\t36\n \n enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_NONE\t\t= DSA_TAG_PROTO_NONE_VALUE,\n@@ -99,6 +100,7 @@ enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_NETC\t\t= DSA_TAG_PROTO_NETC_VALUE,\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_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 23b4b74004ed5..0b9f8a632cf22 100644\n--- a/net/dsa/Kconfig\n+++ b/net/dsa/Kconfig\n@@ -227,4 +227,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 d15bcf5c68f02..0c53f4184bdbf 100644\n--- a/net/dsa/Makefile\n+++ b/net/dsa/Makefile\n@@ -44,6 +44,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..1ee9d17735988\n--- /dev/null\n+++ b/net/dsa/tag_yt922x.c\n@@ -0,0 +1,111 @@\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\t8\n+\n+/*\n+ * To define the from cpu tag format 8 bytes:\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\t(FIELD_PREP(YT922X_TAG_PRIO_M, (x)) | YT922X_TAG_PRIO_EN)\n+#define YT922X_TAG_RX_PORT_M\tGENMASK(5, 2)\n+#define YT922X_TAG_RX_PRIO_M\tGENMASK(15, 13)\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+\n"
}

2/1 2026/09/08 08:59 agent patch-evaluator
1m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "NET_DSA",
    "NET_DSA_TAG_YT922X",
    "NET_DSA_YT921X"
  ],
  "FocusSymbols": [
    "yt922x_tag_rcv",
    "yt922x_tag_xmit",
    "yt922x_dsa_setup",
    "yt922x_port_setup",
    "yt922x_pcs_config",
    "yt922x_pcs_get_state",
    "yt92xx_register_switch"
  ],
  "Reasoning": "The patch series introduces a new DSA tagging driver (net/dsa/tag_yt922x.c) implementing packet receive (yt922x_tag_rcv) and transmit (yt922x_tag_xmit) tagging operations, and extends the Motorcomm switch driver (drivers/net/dsa/motorcomm/chip.c) to support the YT922x series. DSA tag parsing and frame generation execute in the network packet path and can be exercised in virtualized environments using DSA conduits, mock interfaces, or packet sockets.",
  "WorthFuzzing": true
}

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 3a66b7892ba11c710bd496d44cf1b2bc9a8089c5
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Sep 8 08:59:49 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
index 79cdd79a1fd25..f690de4c7a7c5 100644
--- a/drivers/net/dsa/motorcomm/Kconfig
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -2,6 +2,7 @@
 config NET_DSA_YT921X
 	tristate "Motorcomm YT9215 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
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index d663af010f431..4a052b1886b51 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.
@@ -112,6 +112,7 @@ struct yt921x_info {
 #define YT921X_PORT_MASK_INT0_n(n)	GENMASK((n) - 1, 0)
 #define YT921X_PORT_MASK_EXT0		BIT(8)
 #define YT921X_PORT_MASK_EXT1		BIT(9)
+#define YT922X_PORT_MASK_INTm_n(m, n)	GENMASK((n), (m))
 
 static const struct yt921x_info yt921x_infos[] = {
 	{
@@ -149,9 +150,17 @@ static const struct yt921x_info yt921x_infos[] = {
 		YT921X_PORT_MASK_INT0_n(8),
 		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
 	},
+	{
+		"YT9224", YT9224_MAJOR, 0, 0,
+		YT922X_PORT_MASK_INTm_n(4, 7) | YT921X_PORT_MASK_INTn(0) | YT921X_PORT_MASK_INTn(8),
+		0x0,
+	},
 	{}
 };
 
+/* Define top ext addr */
+#define YT922X_COMMON_EXT_PHYADDR	9
+
 #define YT921X_VID_UNWARE	4095
 
 /* The interval should be small enough to avoid overflow of 32bit MIBs.
@@ -357,7 +366,7 @@ static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)
 	u16 val;
 	int res;
 
-	if (port >= YT921X_PORT_NUM)
+	if (port >= priv->series->max_ports)
 		return U16_MAX;
 
 	mutex_lock(&priv->reg_lock);
@@ -375,7 +384,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);
@@ -390,6 +399,7 @@ yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)
 {
 	struct device *dev = to_device(priv);
 	struct mii_bus *mbus;
+	u32 max_ports;
 	int res;
 
 	mbus = devm_mdiobus_alloc(dev);
@@ -402,7 +412,8 @@ 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 = (u32)~GENMASK(max_ports - 1, 0);
 
 	res = devm_of_mdiobus_register(dev, mbus, mnp);
 	if (res)
@@ -4231,6 +4242,11 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds)
 #if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
 	yt921x_leds_remove(priv);
 #endif
+	for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
+		struct yt921x_port *pp = &priv->ports[i];
+
+		disable_delayed_work_sync(&pp->mib_read);
+	}
 }
 
 static int yt921x_chip_detect(struct yt921x_priv *priv)
@@ -4551,6 +4567,14 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 	struct device_node *child;
 	int res;
 
+	/* mib polling init */
+	for (size_t i = 0; i < ARRAY_SIZE(priv->ports); i++) {
+		struct yt921x_port *pp = &priv->ports[i];
+
+		pp->index = i;
+		INIT_DELAYED_WORK(&pp->mib_read, yt921x_poll_mib);
+	}
+
 	mutex_lock(&priv->reg_lock);
 	res = yt921x_chip_reset(priv);
 	mutex_unlock(&priv->reg_lock);
@@ -4679,99 +4703,984 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
 	.setup			= yt921x_dsa_setup,
 };
 
-static void yt921x_mdio_shutdown(struct mdio_device *mdiodev)
+static int yt922x_port_down(struct yt921x_priv *priv, int port)
 {
-	struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
+	u32 mask;
+	int res;
 
-	if (!priv)
-		return;
+	/* 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;
 
-	dsa_switch_shutdown(&priv->ds);
+	/* 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 yt921x_mdio_remove(struct mdio_device *mdiodev)
+static void
+yt922x_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
+			     phy_interface_t interface)
 {
-	struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+	struct yt921x_priv *priv = to_yt921x_priv(dp->ds);
+	int port = dp->index;
+	int res;
 
-	if (!priv)
-		return;
+	mutex_lock(&priv->reg_lock);
+	res = yt922x_port_down(priv, port);
+	mutex_unlock(&priv->reg_lock);
 
-	for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
-		struct yt921x_port *pp = &priv->ports[i];
+	if (res)
+		dev_err(dp->ds->dev, "Failed to %s port %d: %i\n", "bring down",
+			port, res);
+}
 
-		disable_delayed_work_sync(&pp->mib_read);
+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)
+{
+	u32 mask;
+	u32 ctrl;
+	int res;
+
+	switch (speed) {
+	case SPEED_10:
+		ctrl = YT921X_PORT_SPEED_10;
+		break;
+	case SPEED_100:
+		ctrl = YT921X_PORT_SPEED_100;
+		break;
+	case SPEED_1000:
+		ctrl = YT921X_PORT_SPEED_1000;
+		break;
+	case SPEED_2500:
+		ctrl = YT921X_PORT_SPEED_2500;
+		break;
+	case SPEED_5000:
+		ctrl = YT921X_PORT_SPEED_5000;
+		break;
+	case SPEED_10000:
+		ctrl = YT921X_PORT_SPEED_10000;
+		break;
+	default:
+		return -EINVAL;
 	}
+	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_LINK |
+		YT922X_PORT_CFG_RX_EN;
+	ctrl &= ~(YT922X_PORT_FC_AN | YT922X_PORT_LINK_AN);
+	res = yt921x_reg_write(priv, YT922X_PORTn_CTRL(port), ctrl);
+	if (res)
+		return res;
 
-	dsa_unregister_switch(&priv->ds);
+	/* force op */
+	mask = YT922X_PORT_FORCE_OP;
+	res = yt921x_reg_set_bits(priv, YT922X_PORTn_CTRL(port), mask);
+	if (res)
+		return res;
 
-	for (unsigned int i = 0; i < ARRAY_SIZE(priv->acl_blks); i++) {
-		struct yt921x_acl_blk *aclblk = priv->acl_blks[i];
+	/* 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;
 
-		if (!aclblk)
-			continue;
-		for (unsigned int j = 0; j < ARRAY_SIZE(aclblk->rules); j++) {
-			struct yt921x_acl_rule *aclrule = aclblk->rules[j];
+	return 0;
+}
 
-			if (!aclrule)
-				continue;
-			kvfree(aclrule);
-		}
-		kvfree(aclblk);
-	}
-	mutex_destroy(&priv->reg_lock);
+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 = 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 yt921x_mdio_probe(struct mdio_device *mdiodev)
+static int
+yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg, u16 val)
 {
-	struct device *dev = &mdiodev->dev;
-	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)
-		return -ENOMEM;
+	if (port >= priv->series->max_ports)
+		return -ENODEV;
 
-	mdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);
-	if (!mdio)
-		return -ENOMEM;
+	res = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);
+	if (res)
+		return res;
 
-	mdio->bus = mdiodev->bus;
-	mdio->addr = mdiodev->addr;
-	mdio->switchid = 0;
+	res = yt921x_intif_write(priv, port, YT92XX_PAGE, val);
+	if (res)
+		return res;
 
-	mutex_init(&priv->reg_lock);
+	return 0;
+}
 
-	priv->reg_ops = &yt921x_reg_ops_mdio;
-	priv->reg_ctx = mdio;
+static int
+yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
+{
+	int res;
 
-	for (size_t i = 0; i < ARRAY_SIZE(priv->ports); i++) {
-		struct yt921x_port *pp = &priv->ports[i];
+	if (port >= priv->series->max_ports)
+		return -ENODEV;
 
-		pp->index = i;
-		INIT_DELAYED_WORK(&pp->mib_read, yt921x_poll_mib);
-	}
+	res = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);
+	if (res)
+		return res;
 
-	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 = yt921x_intif_read(priv, port, YT92XX_PAGE, valp);
+	if (res)
+		return res;
 
-	mdiodev_set_drvdata(mdiodev, priv);
+	return 0;
+}
 
-	return dsa_register_switch(ds);
+static int yt922x_sds_phyaddr_get(int port,
+				  enum yt922x_phy_reg_type reg_type,
+				  enum yt922x_phy_reg_space reg_space)
+{
+	int res = port;
+
+	/*
+	 * sds phyaddr mapping depend on reg_type and reg_space
+	 */
+	if (!yt922x_port_is_internal_sds(port))
+		return -EOPNOTSUPP;
+	if (reg_type == YT922X_PHY_REG_TYPE_COMMON_EXT) {
+		res = YT922X_COMMON_EXT_PHYADDR;
+		return res;
+	}
+
+	return res;
 }
 
-static const struct of_device_id yt921x_of_match[] = {
-	{ .compatible = "motorcomm,yt9215" },
-	{}
+/**
+ * Initialize serdes configuration based on interface mode.
+ */
+static int yt922x_sds_init(struct yt921x_priv *priv, int port,
+			   phy_interface_t interface)
+{
+	int addr;
+	u16 data;
+	int res;
+
+	addr = yt922x_sds_phyaddr_get
+		(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,
+		 YT922X_PHY_REG_SPACE_SGMII);
+	if (addr < 0)
+		return -EINVAL;
+	/* write protect */
+	res = yt921x_intif_ext_write(priv, addr, 0x4be, 0xd);
+	if (res)
+		return res;
+	/* CDR */
+	if (interface == PHY_INTERFACE_MODE_100BASEX) {
+		res = yt921x_intif_ext_write(priv, addr, 0x406, 0x0);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x416, 0x3458);
+		if (res)
+			return res;
+	} else {
+		res = yt921x_intif_ext_write(priv, addr, 0x406, 0x800);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x416, 0x4558);
+		if (res)
+			return res;
+	}
+	/* PLL */
+	if (interface == PHY_INTERFACE_MODE_USXGMII) {
+		res = yt921x_intif_ext_write(priv, addr, 0x43a, 0x1006);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43f, 0x3029);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x42a, 0xf070);
+		if (res)
+			return res;
+	} else {
+		res = yt921x_intif_ext_write(priv, addr, 0x43d, 0x207d);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43c, 0x207d);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43f, 0x3032);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43a, 0x6);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x42a, 0xf070);
+		if (res)
+			return res;
+	}
+	/* VCO */
+	res = yt921x_intif_ext_write(priv, addr, 0x439, 0xC0);
+	if (res)
+		return res;
+	/* Vdac */
+	res = yt921x_intif_ext_write(priv, addr, 0x492, 0x7f7f);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x491, 0x7f);
+	if (res)
+		return res;
+	/* Eye */
+	res = yt921x_intif_ext_write(priv, addr, 0x454, 0xf14);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x497, 0xa44);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4cd, 0x0);
+	if (res)
+		return res;
+
+	res = yt921x_intif_ext_write(priv, addr, 0x4af, 0x45e3);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x48a, 0xfff);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x408, 0x7c00);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4d6, 0x7f);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x44f, 0xff08);
+	if (res)
+		return res;
+	/* FFE */
+	res = yt921x_intif_ext_write(priv, addr, 0x48e, 0x7d00);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0xd, 0x60f);
+	if (res)
+		return res;
+	/* CTLE */
+	res = yt921x_intif_ext_write(priv, addr, 0x4b0, 0x804);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4b1, 0x7774);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4af, 0x45e7);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x3, 0x5603);
+	if (res)
+		return res;
+
+	msleep(20);
+	res = yt921x_intif_ext_write(priv, addr, 0x492, 0x7fff);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x492, 0x7f7f);
+	if (res)
+		return res;
+	/* CTLE */
+	res = yt921x_intif_ext_write(priv, addr, 0x2000, 0x40);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x2000, 0x0);
+	if (res)
+		return res;
+
+	if (interface == PHY_INTERFACE_MODE_SGMII) {
+		res = yt921x_intif_ext_write(priv, addr, 0x1042, 0x48c);
+		if (res)
+			return res;
+	}
+	/* soft reset */
+	addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII,
+				      YT922X_PHY_REG_SPACE_SGMII);
+	if (addr < 0)
+		return res;
+	res = yt921x_intif_read(priv, addr, 0x0, &data);
+	if (res)
+		return res;
+	data &= ~(1 << 15);
+	res = yt921x_intif_write(priv, addr, 0x0, data);
+	if (res)
+		return res;
+	addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII,
+				      YT922X_PHY_REG_SPACE_USXGMII);
+	if (addr < 0)
+		return res;
+	res = yt921x_intif_read(priv, addr, 0x0, &data);
+	if (res)
+		return res;
+	data |= 1 << 15;
+	res = yt921x_intif_write(priv, addr, 0x0, data);
+	if (res)
+		return res;
+
+	return 0;
+}
+
+static void
+yt922x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
+			  const struct phylink_link_state *state)
+{
+}
+
+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 = dp->ds->priv;
+	struct phylink_pcs *pcs = NULL;
+	int port = dp->index;
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_100BASEX:
+	case PHY_INTERFACE_MODE_2500BASEX:
+	case PHY_INTERFACE_MODE_USXGMII:
+		switch (port) {
+		case 0:
+			pcs = &priv->pcs_port_0.pcs;
+			break;
+
+		case 8:
+			pcs = &priv->pcs_port_8.pcs;
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return pcs;
+}
+
+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 struct yt922x_pcs *pcs_to_yt922x_pcs(struct phylink_pcs *pcs)
+{
+	return container_of(pcs, struct yt922x_pcs, pcs);
+}
+
+static void yt922x_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
+				 struct phylink_link_state *state)
+{
+	struct yt921x_priv *priv = pcs_to_yt922x_pcs(pcs)->priv;
+	int port = pcs_to_yt922x_pcs(pcs)->port;
+	u32 reg;
+	int res;
+
+	res = yt921x_reg_read(priv, YT922X_PORTn_STATUS(port), &reg);
+	if (res < 0) {
+		state->link = false;
+		return;
+	}
+
+	state->link = !!(reg & YT922X_PORT_LINK_STATE);
+	state->an_complete = state->link;
+	state->duplex = (reg & YT922X_PORT_LINK_DUPLEX) ? DUPLEX_FULL :
+							  DUPLEX_HALF;
+
+	switch (reg & YT922X_PORT_SPEED_M) {
+	case YT922X_PORT_SPEED_10:
+		state->speed = SPEED_10;
+		break;
+	case YT922X_PORT_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case YT922X_PORT_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	case YT922X_PORT_SPEED_10000:
+		state->speed = SPEED_10000;
+		break;
+	case YT922X_PORT_SPEED_2500:
+		state->speed = SPEED_2500;
+		break;
+	case YT922X_PORT_SPEED_5000:
+		state->speed = SPEED_5000;
+		break;
+	default:
+		state->speed = SPEED_UNKNOWN;
+		break;
+	}
+}
+
+static void yt922x_pcs_an_restart(struct phylink_pcs *pcs)
+{
+}
+
+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)
+{
+	struct yt921x_priv *priv = pcs_to_yt922x_pcs(pcs)->priv;
+	int res, port;
+	u16 data;
+	u16 ctrl;
+	int addr;
+
+	port = pcs_to_yt922x_pcs(pcs)->port;
+	if (port != 0 && port != 8)
+		return -EINVAL;
+
+	/* SERDES init and interface configuration */
+	res = yt922x_sds_init(priv, port, interface);
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+		ctrl = YT92XX_SERDES_MODE_SGMII;
+		break;
+	case PHY_INTERFACE_MODE_100BASEX:
+		ctrl = YT92XX_SERDES_MODE_100BASEX;
+		break;
+	case PHY_INTERFACE_MODE_1000BASEX:
+		ctrl = YT92XX_SERDES_MODE_1000BASEX;
+		break;
+	case PHY_INTERFACE_MODE_2500BASEX:
+		ctrl = YT92XX_SERDES_MODE_2500BASEX;
+		break;
+	case PHY_INTERFACE_MODE_USXGMII:
+		ctrl = YT92XX_SERDES_MODE_USXGMII;
+		break;
+	default:
+		return -EINVAL;
+	}
+	addr = yt922x_sds_phyaddr_get
+		(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,
+		 YT922X_PHY_REG_SPACE_SGMII);
+	if (addr < 0)
+		return -EINVAL;
+
+	res = yt921x_intif_ext_read(priv, addr, YT922X_PORT_SDSn, &data);
+	if (res)
+		return res;
+	data &= ~YT922X_SERDES_MODE_M;
+	data |= ctrl;
+	res = yt921x_intif_ext_write(priv, addr, YT922X_PORT_SDSn, data);
+
+	return res;
+}
+
+static const struct phylink_pcs_ops yt922x_pcs_ops = {
+	.pcs_get_state = yt922x_pcs_get_state,
+	.pcs_config = yt922x_pcs_config,
+	.pcs_an_restart = yt922x_pcs_an_restart,
+};
+
+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 = 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)) {
+		if (port >= 4 && port <= 7) {
+			/* port 4 to port 7, internal utp */
+			__set_bit(PHY_INTERFACE_MODE_INTERNAL,
+				  config->supported_interfaces);
+			config->mac_capabilities |= MAC_2500FD;
+		} else {
+			__set_bit(PHY_INTERFACE_MODE_SGMII,
+				  config->supported_interfaces);
+			__set_bit(PHY_INTERFACE_MODE_100BASEX,
+				  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_2500FD;
+			config->mac_capabilities |= MAC_5000FD;
+			config->mac_capabilities |= MAC_10000FD;
+		}
+	} else {
+		/* external port will added later */
+	}
+}
+
+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 = 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_chip_detect(struct yt921x_priv *priv)
+{
+	struct device *dev = to_device(priv);
+	const struct yt921x_info *info;
+	u32 chipid;
+	u32 major;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
+	if (res)
+		return res;
+	major = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);
+	for (info = yt921x_infos; info->name; info++)
+		if (info->major == major)
+			break;
+	if (!info->name) {
+		dev_err(dev, "Unexpected chipid 0x%x\n", chipid);
+		return -ENODEV;
+	}
+	priv->info = info;
+
+	return 0;
+}
+
+static int yt922x_chip_reset(struct yt921x_priv *priv)
+{
+	struct device *dev = to_device(priv);
+	u16 eth_p_tag;
+	u32 val;
+	int res;
+
+	res = yt922x_chip_detect(priv);
+	if (res)
+		return res;
+
+	/* Reset */
+	res = yt921x_reg_write(priv, YT921X_RST, YT921X_RST_HW);
+	if (res)
+		return res;
+
+	fsleep(YT921X_RST_DELAY_US);
+
+	val = 0;
+	res = yt921x_reg_wait(priv, YT921X_RST, ~0, &val);
+	if (res)
+		return res;
+
+	/* TPID check */
+	res = yt921x_reg_read(priv, YT921X_CPU_TAG_TPID, &val);
+	if (res)
+		return res;
+	eth_p_tag = FIELD_GET(YT921X_CPU_TAG_TPID_TPID_M, val);
+	if (eth_p_tag != ETH_P_YT921X) {
+		dev_err(dev, "Tag type 0x%x != 0x%x\n", eth_p_tag,
+			ETH_P_YT921X);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int yt922x_chip_setup_dsa(struct yt921x_priv *priv)
+{
+	unsigned long cpu_ports_mask;
+	u32 ctrl;
+	int port;
+	int res;
+
+	ctrl = GENMASK(9, 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 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 void yt922x_setup_pcs(struct yt921x_priv *priv, struct yt922x_pcs *pcs,
+			     int port)
+{
+	pcs->pcs.ops = &yt922x_pcs_ops;
+
+	pcs->priv = priv;
+	pcs->port = port;
+}
+
+static int yt922x_dsa_setup(struct dsa_switch *ds)
+{
+	struct yt921x_priv *priv = to_yt921x_priv(ds);
+	struct device *dev = to_device(priv);
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt922x_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;
+	}
+
+	/* cpu port set */
+	mutex_lock(&priv->reg_lock);
+	res = yt922x_cpu_port_set(priv);
+	mutex_unlock(&priv->reg_lock);
+	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_setup_pcs(priv, &priv->pcs_port_0, 0);
+	yt922x_setup_pcs(priv, &priv->pcs_port_8, 8);
+
+	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] = {
+		.mode = 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] = {
+		.mode = 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)
+{
+	enum yt92xx_mode mode = YT92XX_MODE_MAX;
+	int i;
+
+	if (major == YT9215_MAJOR || major == YT9218_MAJOR)
+		mode = YT92XX_MODE_YT921X;
+	else if (major == YT9224_MAJOR)
+		mode = YT92XX_MODE_YT922X;
+	else
+		mode = YT92XX_MODE_MAX;
+
+	for (i = 0; i < ARRAY_SIZE(yt92xx_series_table); ++i)
+		if (yt92xx_series_table[i].mode == mode)
+			return &yt92xx_series_table[i];
+
+	return NULL;
+}
+
+static int yt92xx_register_switch(struct dsa_switch *ds)
+{
+	struct yt921x_priv *priv = to_yt921x_priv(ds);
+	const struct yt92xx_series *series;
+	u32 chipid;
+	u32 major;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
+	if (res)
+		return res;
+
+	major = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);
+	series = yt92xx_series_lookup(major);
+	if (!series)
+		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);
+
+	if (!priv)
+		return;
+
+	dsa_switch_shutdown(&priv->ds);
+}
+
+static void yt921x_mdio_remove(struct mdio_device *mdiodev)
+{
+	struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
+
+	if (!priv)
+		return;
+
+	dsa_unregister_switch(&priv->ds);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(priv->acl_blks); i++) {
+		struct yt921x_acl_blk *aclblk = priv->acl_blks[i];
+
+		if (!aclblk)
+			continue;
+		for (unsigned int j = 0; j < ARRAY_SIZE(aclblk->rules); j++) {
+			struct yt921x_acl_rule *aclrule = aclblk->rules[j];
+
+			if (!aclrule)
+				continue;
+			kvfree(aclrule);
+		}
+		kvfree(aclblk);
+	}
+	mutex_destroy(&priv->reg_lock);
+}
+
+static int yt921x_mdio_probe(struct mdio_device *mdiodev)
+{
+	struct device *dev = &mdiodev->dev;
+	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)
+		return -ENOMEM;
+
+	mdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);
+	if (!mdio)
+		return -ENOMEM;
+
+	mdio->bus = mdiodev->bus;
+	mdio->addr = mdiodev->addr;
+	mdio->switchid = 0;
+
+	mutex_init(&priv->reg_lock);
+
+	priv->reg_ops = &yt921x_reg_ops_mdio;
+	priv->reg_ctx = mdio;
+
+	ds = &priv->ds;
+	ds->dev = dev;
+	res = yt92xx_register_switch(ds);
+	if (res)
+		return res;
+
+	mdiodev_set_drvdata(mdiodev, priv);
+
+	return dsa_register_switch(ds);
+}
+
+static const struct of_device_id yt921x_of_match[] = {
+	{
+		.compatible = "motorcomm,yt9215",
+	},
+	{
+		.compatible = "motorcomm,yt9224",
+	},
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, yt921x_of_match);
 
@@ -4788,5 +5697,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 83cd454955ddb..3b7ea3cbf5227 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -111,6 +111,7 @@
 #define   YT921X_PORT_SPEED_1000			YT921X_PORT_SPEED(2)
 #define   YT921X_PORT_SPEED_10000			YT921X_PORT_SPEED(3)
 #define   YT921X_PORT_SPEED_2500			YT921X_PORT_SPEED(4)
+#define   YT921X_PORT_SPEED_5000			YT921X_PORT_SPEED(5)
 #define YT921X_PON_STRAP_FUNC		0x80320
 #define YT921X_PON_STRAP_VAL		0x80324
 #define YT921X_PON_STRAP_CAP		0x80328
@@ -837,6 +838,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
@@ -861,6 +863,99 @@ enum yt921x_fdb_entry_status {
 #define yt921x_port_is_internal(port) ((port) < 8)
 #define yt921x_port_is_external(port) ((port) == 8 || (port) == 9)
 
+/* yt922x register lists */
+#define YT92XX_PAGE_SELECT	0x1e
+#define YT92XX_PAGE		0x1f
+#define YT922X_PORTn_STATUS(port)	(0x80200 + 4 * (port))
+#define  YT922X_PORT_LINK_STATE			BIT(8)
+#define  YT922X_PORT_LINK_DUPLEX		BIT(7)
+#define  YT922X_PORT_RX_FC_EN			BIT(6)
+#define  YT922X_PORT_TX_FC_EN			BIT(5)
+#define YT922X_PORT_SPEED_10		0
+#define YT922X_PORT_SPEED_100		1
+#define YT922X_PORT_SPEED_1000		2
+#define YT922X_PORT_SPEED_10000		3
+#define YT922X_PORT_SPEED_2500		4
+#define YT922X_PORT_SPEED_5000		5
+#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 YT92XX_SERDES_MODE_SGMII	YT922X_SERDES_MODE(0)
+#define YT92XX_SERDES_MODE_REVSGMII	YT921X_SERDES_MODE(1)
+#define YT92XX_SERDES_MODE_1000BASEX	YT921X_SERDES_MODE(2)
+#define YT92XX_SERDES_MODE_100BASEX	YT921X_SERDES_MODE(3)
+#define YT92XX_SERDES_MODE_2500BASEX	YT921X_SERDES_MODE(4)
+#define YT92XX_SERDES_MODE_USXGMII	YT922X_SERDES_MODE(6)
+#define YT922X_PORT_NUM		9
+
+/* LAG */
+#define YT922X_LAG_NUM		4
+/* ISO */
+#define YT922X_PORTn_ISOLATION(port)	(0x4 * (port) + 0x180d80)
+/* FDB */
+#define YT922X_PORTn_LEARN(port)	(0x180300 + 4 * (port))
+#define  YT922X_PORT_LEARN_DIS			BIT(18)
+/* GLOBAL CTRL */
+#define  YT922X_FUNC_ACL               BIT(5)
+#define  YT922X_FUNC_MIB               BIT(4)
+/* CTRL PKT */
+#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 */
+
+/* CPU PORT */
+#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 yt922x_port_is_internal_sds(port) ((port) == 0 || (port) == 8)
+
+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
+};
+
+enum yt922x_phy_reg_space {
+	YT922X_PHY_REG_SPACE_SGMII,
+	YT922X_PHY_REG_SPACE_USXGMII,
+	YT922X_PHY_REG_SPACE_MAX
+};
+
 struct yt921x_mib {
 	u64 rx_broadcast;
 	u64 rx_pause;
@@ -960,9 +1055,35 @@ struct yt921x_reg_ops {
 	int (*write)(void *context, u32 reg, u32 val);
 };
 
+enum yt92xx_mode {
+	YT92XX_MODE_YT921X,
+	YT92XX_MODE_YT922X,
+	YT92XX_MODE_MAX,
+};
+
+struct yt92xx_series {
+	enum yt92xx_mode mode;
+	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 yt922x_pcs {
+	struct phylink_pcs pcs;
+	struct yt921x_priv *priv;
+	int port;
+};
+
 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;
@@ -987,6 +1108,8 @@ struct yt921x_priv {
 
 	u8 acl_masks[YT921X_ACL_BLK_NUM];
 	struct yt921x_acl_blk *acl_blks[YT921X_ACL_BLK_NUM];
+	struct yt922x_pcs pcs_port_0;
+	struct yt922x_pcs pcs_port_8;
 };
 
 #endif
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 7507d632e7c6d..0807a595aaad0 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -61,6 +61,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_NETC_VALUE		33
 #define DSA_TAG_PROTO_KSZ8463_VALUE		34
 #define DSA_TAG_PROTO_MT7628_VALUE		35
+#define DSA_TAG_PROTO_YT922X_VALUE		36
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -99,6 +100,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NETC		= DSA_TAG_PROTO_NETC_VALUE,
 	DSA_TAG_PROTO_KSZ8463		= DSA_TAG_PROTO_KSZ8463_VALUE,
 	DSA_TAG_PROTO_MT7628		= DSA_TAG_PROTO_MT7628_VALUE,
+	DSA_TAG_PROTO_YT922X		= DSA_TAG_PROTO_YT922X_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 23b4b74004ed5..0b9f8a632cf22 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -227,4 +227,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 d15bcf5c68f02..0c53f4184bdbf 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -44,6 +44,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..1ee9d17735988
--- /dev/null
+++ b/net/dsa/tag_yt922x.c
@@ -0,0 +1,111 @@
+// 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:
+ */
+#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)
+#define YT922X_TAG_RX_PRIO_M	GENMASK(15, 13)
+
+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/09/08 08:59 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 22828
							output: 20
							thoughts: 358
						

Thoughts:
**My Initial Assessment of This Patch Series**

Okay, so I've got a patch series here that touches the Motorcomm DSA driver and some related DSA files. My immediate concern, as always, is reachability and potential fuzzing vulnerabilities. Before I dive deep into the code, I need to understand how these DSA components are used. Are the DSA tagging drivers and switch drivers actively reachable paths? Are they reachable from user space via a standard netlink interface, or are they only accessible through specific physical hardware configurations or some virtual/mock interface?

My initial thought is to check how DSA is currently fuzzed in the Linux syzkaller environments. What's the existing coverage? Do we have syzkaller tests that exercise these DSA taggers and switches? Are there existing test cases that could be expanded or adapted? This is crucial for understanding the potential risk surface.

I'll start by focusing on the DSA tag protocols themselves – the `net/dsa/tag_*.c` files. These are packet handlers, effectively, which immediately raises a flag for potential vulnerabilities. Can syzkaller construct packets that target these taggers? Do they require a specific DSA interface, or a physical hardware setup, or does the driver expose something like a `dsa_register_switch` function?

I need to understand the full attack surface. I'll need to check netlink, packet sockets, tun/tap, loopback interfaces and mock interfaces and dsa slave devices, looking for ways to reach these drivers. Are there any paths into the kernel that could trigger these functions? Is there a mock DSA driver to test with? The code itself will provide the answer, so I need to inspect how DSA works in the kernel and how that is used in syzkaller to see if these files and modules are reachable.

I'll run some targeted `grepper` searches to help identify usages of the DSA tag drivers, mock DSA implementations, and any related hooks or functions. This will help me build a clearer picture of the potential attack surface.



4/2 2026/09/08 08:59 tool grepper
0m Args:
{
  "Expression": "DSA_TAG_PROTO_"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 929 lines.\nUse more precise expression if possible.\n\nDocumentation/networking/dsa/configuration.rst=167=A minority of switches are not capable to use a taging protocol\nDocumentation/networking/dsa/configuration.rst:168:(DSA_TAG_PROTO_NONE). These switches can be configured by a VLAN based\nDocumentation/networking/dsa/configuration.rst-169-configuration.\n--\nDocumentation/networking/dsa/dsa.rst=72=DSA supports many vendor-specific tagging protocols, one software-defined\nDocumentation/networking/dsa/dsa.rst:73:tagging protocol, and a tag-less mode as well (``DSA_TAG_PROTO_NONE``).\nDocumentation/networking/dsa/dsa.rst-74-\n--\ndrivers/net/dsa/b53/b53_common.c=761=void b53_brcm_hdr_setup(struct dsa_switch *ds, int port)\n--\ndrivers/net/dsa/b53/b53_common.c-763-\tstruct b53_device *dev = ds-\u003epriv;\ndrivers/net/dsa/b53/b53_common.c:764:\tbool tag_en = !(dev-\u003etag_protocol == DSA_TAG_PROTO_NONE);\ndrivers/net/dsa/b53/b53_common.c-765-\tu8 hdr_ctl, val;\n--\ndrivers/net/dsa/b53/b53_common.c-800-\t/* B53_BRCM_HDR not present on devices with legacy tags */\ndrivers/net/dsa/b53/b53_common.c:801:\tif (dev-\u003etag_protocol == DSA_TAG_PROTO_BRCM_LEGACY ||\ndrivers/net/dsa/b53/b53_common.c:802:\t    dev-\u003etag_protocol == DSA_TAG_PROTO_BRCM_LEGACY_FCS)\ndrivers/net/dsa/b53/b53_common.c-803-\t\treturn;\n--\ndrivers/net/dsa/b53/b53_common.c=878=static bool b53_vlan_port_needs_forced_tagged(struct dsa_switch *ds, int port)\n--\ndrivers/net/dsa/b53/b53_common.c-881-\ndrivers/net/dsa/b53/b53_common.c:882:\treturn dev-\u003etag_protocol == DSA_TAG_PROTO_NONE \u0026\u0026 dsa_is_cpu_port(ds, port);\ndrivers/net/dsa/b53/b53_common.c-883-}\n--\ndrivers/net/dsa/b53/b53_common.c=901=int b53_configure_vlan(struct dsa_switch *ds)\n--\ndrivers/net/dsa/b53/b53_common.c-924-\t * entry. Do this only when the tagging protocol is not\ndrivers/net/dsa/b53/b53_common.c:925:\t * DSA_TAG_PROTO_NONE\ndrivers/net/dsa/b53/b53_common.c-926-\t */\n--\ndrivers/net/dsa/b53/b53_common.c=1276=static int b53_setup(struct dsa_switch *ds)\n--\ndrivers/net/dsa/b53/b53_common.c-1283-\ndrivers/net/dsa/b53/b53_common.c:1284:\t/* Request bridge PVID untagged when DSA_TAG_PROTO_NONE is set\ndrivers/net/dsa/b53/b53_common.c-1285-\t * which forces the CPU port to be tagged in all VLANs.\ndrivers/net/dsa/b53/b53_common.c-1286-\t */\ndrivers/net/dsa/b53/b53_common.c:1287:\tds-\u003euntag_bridge_pvid = dev-\u003etag_protocol == DSA_TAG_PROTO_NONE;\ndrivers/net/dsa/b53/b53_common.c-1288-\n--\ndrivers/net/dsa/b53/b53_common.c=2478=static bool b53_can_enable_brcm_tags(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/b53/b53_common.c-2489-\tswitch (tag_protocol) {\ndrivers/net/dsa/b53/b53_common.c:2490:\tcase DSA_TAG_PROTO_BRCM:\ndrivers/net/dsa/b53/b53_common.c:2491:\tcase DSA_TAG_PROTO_BRCM_PREPEND:\ndrivers/net/dsa/b53/b53_common.c-2492-\t\tdev_warn(ds-\u003edev,\n--\ndrivers/net/dsa/b53/b53_common.c=2504=enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/b53/b53_common.c-2509-\tif (!b53_can_enable_brcm_tags(ds, port, mprot)) {\ndrivers/net/dsa/b53/b53_common.c:2510:\t\tdev-\u003etag_protocol = DSA_TAG_PROTO_NONE;\ndrivers/net/dsa/b53/b53_common.c-2511-\t\tgoto out;\n--\ndrivers/net/dsa/b53/b53_common.c-2515-\tif (is5325(dev) || is5365(dev)) {\ndrivers/net/dsa/b53/b53_common.c:2516:\t\tdev-\u003etag_protocol = DSA_TAG_PROTO_BRCM_LEGACY_FCS;\ndrivers/net/dsa/b53/b53_common.c-2517-\t\tgoto out;\ndrivers/net/dsa/b53/b53_common.c-2518-\t} else if (is63xx(dev)) {\ndrivers/net/dsa/b53/b53_common.c:2519:\t\tdev-\u003etag_protocol = DSA_TAG_PROTO_BRCM_LEGACY;\ndrivers/net/dsa/b53/b53_common.c-2520-\t\tgoto out;\n--\ndrivers/net/dsa/b53/b53_common.c-2526-\tif (dev-\u003echip_id == BCM58XX_DEVICE_ID \u0026\u0026 port == B53_CPU_PORT) {\ndrivers/net/dsa/b53/b53_common.c:2527:\t\tdev-\u003etag_protocol = DSA_TAG_PROTO_BRCM_PREPEND;\ndrivers/net/dsa/b53/b53_common.c-2528-\t\tgoto out;\n--\ndrivers/net/dsa/b53/b53_common.c-2530-\ndrivers/net/dsa/b53/b53_common.c:2531:\tdev-\u003etag_protocol = DSA_TAG_PROTO_BRCM;\ndrivers/net/dsa/b53/b53_common.c-2532-out:\n--\ndrivers/net/dsa/dsa_loop.c=125=static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/dsa_loop.c-130-\ndrivers/net/dsa/dsa_loop.c:131:\treturn DSA_TAG_PROTO_NONE;\ndrivers/net/dsa/dsa_loop.c-132-}\n--\ndrivers/net/dsa/hirschmann/hellcreek.c=240=static enum dsa_tag_protocol hellcreek_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/hirschmann/hellcreek.c-243-{\ndrivers/net/dsa/hirschmann/hellcreek.c:244:\treturn DSA_TAG_PROTO_HELLCREEK;\ndrivers/net/dsa/hirschmann/hellcreek.c-245-}\n--\ndrivers/net/dsa/ks8995.c=531=dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/ks8995.c-535-\t/* This switch actually uses the 6 byte KS8995 protocol */\ndrivers/net/dsa/ks8995.c:536:\treturn DSA_TAG_PROTO_NONE;\ndrivers/net/dsa/ks8995.c-537-}\n--\ndrivers/net/dsa/lan9303-core.c=937=static enum dsa_tag_protocol lan9303_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/lan9303-core.c-940-{\ndrivers/net/dsa/lan9303-core.c:941:\treturn DSA_TAG_PROTO_LAN9303;\ndrivers/net/dsa/lan9303-core.c-942-}\n--\ndrivers/net/dsa/lantiq/lantiq_gswip.c=459=static const struct gswip_hw_info gswip_xrx200 = {\n--\ndrivers/net/dsa/lantiq/lantiq_gswip.c-478-\t.pce_microcode_size = ARRAY_SIZE(gswip_pce_microcode),\ndrivers/net/dsa/lantiq/lantiq_gswip.c:479:\t.tag_protocol = DSA_TAG_PROTO_GSWIP,\ndrivers/net/dsa/lantiq/lantiq_gswip.c-480-};\n--\ndrivers/net/dsa/lantiq/lantiq_gswip.c=482=static const struct gswip_hw_info gswip_xrx300 = {\n--\ndrivers/net/dsa/lantiq/lantiq_gswip.c-499-\t.pce_microcode_size = ARRAY_SIZE(gswip_pce_microcode),\ndrivers/net/dsa/lantiq/lantiq_gswip.c:500:\t.tag_protocol = DSA_TAG_PROTO_GSWIP,\ndrivers/net/dsa/lantiq/lantiq_gswip.c-501-};\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c=819=static const struct gswip_hw_info gsw12x_data = {\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-837-\t.pce_microcode_size\t= ARRAY_SIZE(gsw1xx_pce_microcode),\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c:838:\t.tag_protocol\t\t= DSA_TAG_PROTO_MXL_GSW1XX,\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-839-};\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c=841=static const struct gswip_hw_info gsw140_data = {\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-859-\t.pce_microcode_size\t= ARRAY_SIZE(gsw1xx_pce_microcode),\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c:860:\t.tag_protocol\t\t= DSA_TAG_PROTO_MXL_GSW1XX,\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-861-};\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c=863=static const struct gswip_hw_info gsw141_data = {\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-880-\t.pce_microcode_size\t= ARRAY_SIZE(gsw1xx_pce_microcode),\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c:881:\t.tag_protocol\t\t= DSA_TAG_PROTO_MXL_GSW1XX,\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-882-};\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c=884=static const struct gswip_hw_info gsw150_data = {\n--\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-905-\t.pce_microcode_size\t= ARRAY_SIZE(gsw1xx_pce_microcode),\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c:906:\t.tag_protocol\t\t= DSA_TAG_PROTO_MXL_GSW1XX,\ndrivers/net/dsa/lantiq/mxl-gsw1xx.c-907-};\n--\ndrivers/net/dsa/microchip/ksz8.c=2979=static enum dsa_tag_protocol ksz8463_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-2982-{\ndrivers/net/dsa/microchip/ksz8.c:2983:\treturn DSA_TAG_PROTO_KSZ8463;\ndrivers/net/dsa/microchip/ksz8.c-2984-}\n--\ndrivers/net/dsa/microchip/ksz8.c=2986=static int ksz8463_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-2990-\ndrivers/net/dsa/microchip/ksz8.c:2991:\tif (proto != DSA_TAG_PROTO_KSZ8463)\ndrivers/net/dsa/microchip/ksz8.c-2992-\t\treturn -EPROTONOSUPPORT;\n--\ndrivers/net/dsa/microchip/ksz8.c=3000=static enum dsa_tag_protocol ksz87xx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-3003-{\ndrivers/net/dsa/microchip/ksz8.c:3004:\treturn DSA_TAG_PROTO_KSZ8795;\ndrivers/net/dsa/microchip/ksz8.c-3005-}\n--\ndrivers/net/dsa/microchip/ksz8.c=3007=static int ksz87xx_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-3009-{\ndrivers/net/dsa/microchip/ksz8.c:3010:\tif (proto != DSA_TAG_PROTO_KSZ8795)\ndrivers/net/dsa/microchip/ksz8.c-3011-\t\treturn -EPROTONOSUPPORT;\n--\ndrivers/net/dsa/microchip/ksz8.c=3016=static enum dsa_tag_protocol ksz88xx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-3022-\tif (ksz_is_8895_family(dev)) /* KSZ8864, KSZ8895 */\ndrivers/net/dsa/microchip/ksz8.c:3023:\t\treturn DSA_TAG_PROTO_KSZ8795;\ndrivers/net/dsa/microchip/ksz8.c-3024-\ndrivers/net/dsa/microchip/ksz8.c:3025:\treturn DSA_TAG_PROTO_KSZ9893;\ndrivers/net/dsa/microchip/ksz8.c-3026-}\n--\ndrivers/net/dsa/microchip/ksz8.c=3028=static int ksz88xx_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-3033-\tif (ksz_is_8895_family(ds-\u003epriv)) { /* KSZ8864, KSZ8895 */\ndrivers/net/dsa/microchip/ksz8.c:3034:\t\tif (proto != DSA_TAG_PROTO_KSZ8795)\ndrivers/net/dsa/microchip/ksz8.c-3035-\t\t\treturn -EPROTONOSUPPORT;\n--\ndrivers/net/dsa/microchip/ksz8.c-3039-\ndrivers/net/dsa/microchip/ksz8.c:3040:\tif (proto != DSA_TAG_PROTO_KSZ9893)\ndrivers/net/dsa/microchip/ksz8.c-3041-\t\treturn -EPROTONOSUPPORT;\n--\ndrivers/net/dsa/microchip/ksz9477.c=1990=static enum dsa_tag_protocol ksz9477_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz9477.c-1998-\t    dev-\u003echip_id == KSZ9563_CHIP_ID)\ndrivers/net/dsa/microchip/ksz9477.c:1999:\t\treturn DSA_TAG_PROTO_KSZ9893;\ndrivers/net/dsa/microchip/ksz9477.c-2000-\ndrivers/net/dsa/microchip/ksz9477.c:2001:\treturn DSA_TAG_PROTO_KSZ9477;\ndrivers/net/dsa/microchip/ksz9477.c-2002-}\n--\ndrivers/net/dsa/microchip/ksz9477.c=2004=static int ksz9477_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz9477.c-2008-\ndrivers/net/dsa/microchip/ksz9477.c:2009:\tif (proto != DSA_TAG_PROTO_KSZ9893 \u0026\u0026 proto != DSA_TAG_PROTO_KSZ9477)\ndrivers/net/dsa/microchip/ksz9477.c-2010-\t\treturn -EPROTONOSUPPORT;\n--\ndrivers/net/dsa/microchip/lan937x_main.c=908=static enum dsa_tag_protocol lan937x_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/lan937x_main.c-911-{\ndrivers/net/dsa/microchip/lan937x_main.c:912:\treturn DSA_TAG_PROTO_LAN937X;\ndrivers/net/dsa/microchip/lan937x_main.c-913-}\n--\ndrivers/net/dsa/microchip/lan937x_main.c=915=static int lan937x_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/lan937x_main.c-919-\ndrivers/net/dsa/microchip/lan937x_main.c:920:\tif (proto != DSA_TAG_PROTO_LAN937X)\ndrivers/net/dsa/microchip/lan937x_main.c-921-\t\treturn -EPROTONOSUPPORT;\n--\ndrivers/net/dsa/motorcomm/chip.c=4116=yt921x_dsa_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/motorcomm/chip.c-4118-{\ndrivers/net/dsa/motorcomm/chip.c:4119:\treturn DSA_TAG_PROTO_YT921X;\ndrivers/net/dsa/motorcomm/chip.c-4120-}\n--\ndrivers/net/dsa/motorcomm/chip.c=5219=yt922x_dsa_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/motorcomm/chip.c-5221-{\ndrivers/net/dsa/motorcomm/chip.c:5222:\treturn DSA_TAG_PROTO_YT922X;\ndrivers/net/dsa/motorcomm/chip.c-5223-}\n--\ndrivers/net/dsa/mt7530.c=2115=mtk_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/mt7530.c-2117-{\ndrivers/net/dsa/mt7530.c:2118:\treturn DSA_TAG_PROTO_MTK;\ndrivers/net/dsa/mt7530.c-2119-}\n--\ndrivers/net/dsa/mt7628.c=457=mt7628_get_tag_proto(struct dsa_switch *ds, int port, enum dsa_tag_protocol mp)\ndrivers/net/dsa/mt7628.c-458-{\ndrivers/net/dsa/mt7628.c:459:\treturn DSA_TAG_PROTO_MT7628;\ndrivers/net/dsa/mt7628.c-460-}\n--\ndrivers/net/dsa/mv88e6060.c=45=static enum dsa_tag_protocol mv88e6060_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/mv88e6060.c-48-{\ndrivers/net/dsa/mv88e6060.c:49:\treturn DSA_TAG_PROTO_TRAILER;\ndrivers/net/dsa/mv88e6060.c-50-}\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=3262=static int mv88e6xxx_setup_port_mode(struct mv88e6xxx_chip *chip, int port)\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-3270-\t/* Setup CPU port mode depending on its supported tag format */\ndrivers/net/dsa/mv88e6xxx/chip.c:3271:\tif (chip-\u003etag_protocol == DSA_TAG_PROTO_DSA)\ndrivers/net/dsa/mv88e6xxx/chip.c-3272-\t\treturn mv88e6xxx_set_port_mode_dsa(chip, port);\ndrivers/net/dsa/mv88e6xxx/chip.c-3273-\ndrivers/net/dsa/mv88e6xxx/chip.c:3274:\tif (chip-\u003etag_protocol == DSA_TAG_PROTO_EDSA)\ndrivers/net/dsa/mv88e6xxx/chip.c-3275-\t\treturn mv88e6xxx_set_port_mode_edsa(chip, port);\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=6655=static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-6663-\tswitch (proto) {\ndrivers/net/dsa/mv88e6xxx/chip.c:6664:\tcase DSA_TAG_PROTO_EDSA:\ndrivers/net/dsa/mv88e6xxx/chip.c-6665-\t\tswitch (chip-\u003einfo-\u003eedsa_support) {\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-6674-\t\tbreak;\ndrivers/net/dsa/mv88e6xxx/chip.c:6675:\tcase DSA_TAG_PROTO_DSA:\ndrivers/net/dsa/mv88e6xxx/chip.c-6676-\t\tbreak;\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=7313=static int mv88e6xxx_probe(struct mdio_device *mdiodev)\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-7378-\tif (chip-\u003einfo-\u003eedsa_support == MV88E6XXX_EDSA_SUPPORTED)\ndrivers/net/dsa/mv88e6xxx/chip.c:7379:\t\tchip-\u003etag_protocol = DSA_TAG_PROTO_EDSA;\ndrivers/net/dsa/mv88e6xxx/chip.c-7380-\telse\ndrivers/net/dsa/mv88e6xxx/chip.c:7381:\t\tchip-\u003etag_protocol = DSA_TAG_PROTO_DSA;\ndrivers/net/dsa/mv88e6xxx/chip.c-7382-\n--\ndrivers/net/dsa/mxl862xx/mxl862xx.c=164=static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/mxl862xx/mxl862xx.c-167-{\ndrivers/net/dsa/mxl862xx/mxl862xx.c:168:\treturn DSA_TAG_PROTO_MXL862;\ndrivers/net/dsa/mxl862xx/mxl862xx.c-169-}\n--\ndrivers/net/dsa/netc/netc_main.c=62=netc_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/netc/netc_main.c-64-{\ndrivers/net/dsa/netc/netc_main.c:65:\treturn DSA_TAG_PROTO_NETC;\ndrivers/net/dsa/netc/netc_main.c-66-}\n--\ndrivers/net/dsa/ocelot/felix.c=754=static int felix_change_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/ocelot/felix.c-762-\tswitch (proto) {\ndrivers/net/dsa/ocelot/felix.c:763:\tcase DSA_TAG_PROTO_SEVILLE:\ndrivers/net/dsa/ocelot/felix.c:764:\tcase DSA_TAG_PROTO_OCELOT:\ndrivers/net/dsa/ocelot/felix.c-765-\t\tproto_ops = \u0026felix_tag_npi_proto_ops;\ndrivers/net/dsa/ocelot/felix.c-766-\t\tbreak;\ndrivers/net/dsa/ocelot/felix.c:767:\tcase DSA_TAG_PROTO_OCELOT_8021Q:\ndrivers/net/dsa/ocelot/felix.c-768-\t\tproto_ops = \u0026felix_tag_8021q_proto_ops;\n--\ndrivers/net/dsa/ocelot/felix.c=1096=static int felix_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,\n--\ndrivers/net/dsa/ocelot/felix.c-1108-\tfelix = ocelot_to_felix(ocelot);\ndrivers/net/dsa/ocelot/felix.c:1109:\tusing_tag_8021q = felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q;\ndrivers/net/dsa/ocelot/felix.c-1110-\tif (using_tag_8021q) {\n--\ndrivers/net/dsa/ocelot/felix.c=1230=static int felix_port_enable(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/ocelot/felix.c-1248-\ndrivers/net/dsa/ocelot/felix.c:1249:\tif (!dp-\u003ehsr_dev || felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q)\ndrivers/net/dsa/ocelot/felix.c-1250-\t\treturn 0;\n--\ndrivers/net/dsa/ocelot/felix.c=1255=static void felix_port_disable(struct dsa_switch *ds, int port)\n--\ndrivers/net/dsa/ocelot/felix.c-1263-\ndrivers/net/dsa/ocelot/felix.c:1264:\tif (!dp-\u003ehsr_dev || felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q)\ndrivers/net/dsa/ocelot/felix.c-1265-\t\treturn;\n--\ndrivers/net/dsa/ocelot/felix.c=1678=static int felix_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/ocelot/felix.c-1683-\tswitch (proto) {\ndrivers/net/dsa/ocelot/felix.c:1684:\tcase DSA_TAG_PROTO_OCELOT_8021Q:\ndrivers/net/dsa/ocelot/felix.c-1685-\t\ttagger_data = ocelot_8021q_tagger_data(ds);\n--\ndrivers/net/dsa/ocelot/felix.c-1687-\t\treturn 0;\ndrivers/net/dsa/ocelot/felix.c:1688:\tcase DSA_TAG_PROTO_OCELOT:\ndrivers/net/dsa/ocelot/felix.c:1689:\tcase DSA_TAG_PROTO_SEVILLE:\ndrivers/net/dsa/ocelot/felix.c-1690-\t\treturn 0;\n--\ndrivers/net/dsa/ocelot/felix.c=1807=static int felix_hwtstamp_set(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/ocelot/felix.c-1819-\ndrivers/net/dsa/ocelot/felix.c:1820:\tusing_tag_8021q = felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q;\ndrivers/net/dsa/ocelot/felix.c-1821-\n--\ndrivers/net/dsa/ocelot/felix.c=1825=static bool felix_check_xtr_pkt(struct ocelot *ocelot)\n--\ndrivers/net/dsa/ocelot/felix.c-1829-\ndrivers/net/dsa/ocelot/felix.c:1830:\tif (felix-\u003etag_proto != DSA_TAG_PROTO_OCELOT_8021Q)\ndrivers/net/dsa/ocelot/felix.c-1831-\t\treturn false;\n--\ndrivers/net/dsa/ocelot/felix.c=1970=static int felix_cls_flower_add(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/ocelot/felix.c-1981-\ndrivers/net/dsa/ocelot/felix.c:1982:\tusing_tag_8021q = felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q;\ndrivers/net/dsa/ocelot/felix.c-1983-\n--\ndrivers/net/dsa/ocelot/felix.c=2259=static int felix_port_hsr_join(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/ocelot/felix.c-2265-\ndrivers/net/dsa/ocelot/felix.c:2266:\tif (felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q) {\ndrivers/net/dsa/ocelot/felix.c-2267-\t\tint err;\n--\ndrivers/net/dsa/ocelot/felix.c=2284=static int felix_port_hsr_leave(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/ocelot/felix.c-2289-\ndrivers/net/dsa/ocelot/felix.c:2290:\tif (felix-\u003etag_proto == DSA_TAG_PROTO_OCELOT_8021Q)\ndrivers/net/dsa/ocelot/felix.c-2291-\t\treturn 0;\n--\ndrivers/net/dsa/ocelot/felix_vsc9959.c=2684=static int felix_pci_probe(struct pci_dev *pdev,\n--\ndrivers/net/dsa/ocelot/felix_vsc9959.c-2701-\terr = felix_register_switch(dev, switch_base, OCELOT_NUM_TC,\ndrivers/net/dsa/ocelot/felix_vsc9959.c:2702:\t\t\t\t    true, true, DSA_TAG_PROTO_OCELOT,\ndrivers/net/dsa/ocelot/felix_vsc9959.c-2703-\t\t\t\t    \u0026felix_info_vsc9959);\n--\ndrivers/net/dsa/ocelot/ocelot_ext.c=65=static int ocelot_ext_probe(struct platform_device *pdev)\n--\ndrivers/net/dsa/ocelot/ocelot_ext.c-67-\treturn felix_register_switch(\u0026pdev-\u003edev, 0, 1, false, false,\ndrivers/net/dsa/ocelot/ocelot_ext.c:68:\t\t\t\t     DSA_TAG_PROTO_OCELOT, \u0026vsc7512_info);\ndrivers/net/dsa/ocelot/ocelot_ext.c-69-}\n--\ndrivers/net/dsa/ocelot/seville_vsc9953.c=970=static int seville_probe(struct platform_device *pdev)\n--\ndrivers/net/dsa/ocelot/seville_vsc9953.c-981-\treturn felix_register_switch(dev, res-\u003estart, 1, false, false,\ndrivers/net/dsa/ocelot/seville_vsc9953.c:982:\t\t\t\t     DSA_TAG_PROTO_SEVILLE,\ndrivers/net/dsa/ocelot/seville_vsc9953.c-983-\t\t\t\t     \u0026seville_info_vsc9953);\n--\ndrivers/net/dsa/qca/ar9331.c=496=static enum dsa_tag_protocol ar9331_sw_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/qca/ar9331.c-499-{\ndrivers/net/dsa/qca/ar9331.c:500:\treturn DSA_TAG_PROTO_AR9331;\ndrivers/net/dsa/qca/ar9331.c-501-}\n--\ndrivers/net/dsa/qca/qca8k-8xxx.c=1756=qca8k_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/qca/qca8k-8xxx.c-1758-{\ndrivers/net/dsa/qca/qca8k-8xxx.c:1759:\treturn DSA_TAG_PROTO_QCA;\ndrivers/net/dsa/qca/qca8k-8xxx.c-1760-}\n--\ndrivers/net/dsa/qca/qca8k-8xxx.c=1782=static int qca8k_connect_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/qca/qca8k-8xxx.c-1787-\tswitch (proto) {\ndrivers/net/dsa/qca/qca8k-8xxx.c:1788:\tcase DSA_TAG_PROTO_QCA:\ndrivers/net/dsa/qca/qca8k-8xxx.c-1789-\t\ttagger_data = ds-\u003etagger_data;\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=1064=rtl8365mb_get_tag_protocol(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c-1074-\tif (cpu-\u003eposition == RTL8365MB_CPU_POS_BEFORE_CRC)\ndrivers/net/dsa/realtek/rtl8365mb_main.c:1075:\t\treturn DSA_TAG_PROTO_RTL8_4T;\ndrivers/net/dsa/realtek/rtl8365mb_main.c-1076-\ndrivers/net/dsa/realtek/rtl8365mb_main.c:1077:\treturn DSA_TAG_PROTO_RTL8_4;\ndrivers/net/dsa/realtek/rtl8365mb_main.c-1078-}\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=2920=static int rtl8365mb_change_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2930-\tswitch (proto) {\ndrivers/net/dsa/realtek/rtl8365mb_main.c:2931:\tcase DSA_TAG_PROTO_RTL8_4:\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2932-\t\tcpu-\u003eformat = RTL8365MB_CPU_FORMAT_8BYTES;\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2934-\t\tbreak;\ndrivers/net/dsa/realtek/rtl8365mb_main.c:2935:\tcase DSA_TAG_PROTO_RTL8_4T:\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2936-\t\tcpu-\u003eformat = RTL8365MB_CPU_FORMAT_8BYTES;\n--\ndrivers/net/dsa/realtek/rtl8366rb.c=1130=static enum dsa_tag_protocol rtl8366_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/realtek/rtl8366rb.c-1134-\t/* This switch uses the 4 byte protocol A Realtek DSA tag */\ndrivers/net/dsa/realtek/rtl8366rb.c:1135:\treturn DSA_TAG_PROTO_RTL4_A;\ndrivers/net/dsa/realtek/rtl8366rb.c-1136-}\n--\ndrivers/net/dsa/rzn1_a5psw.c=95=static enum dsa_tag_protocol a5psw_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/rzn1_a5psw.c-98-{\ndrivers/net/dsa/rzn1_a5psw.c:99:\treturn DSA_TAG_PROTO_RZN1_A5PSW;\ndrivers/net/dsa/rzn1_a5psw.c-100-}\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=573=const struct sja1105_info sja1105e_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-577-\t.dyn_ops\t\t= sja1105et_dyn_ops,\ndrivers/net/dsa/sja1105/sja1105_spi.c:578:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1105,\ndrivers/net/dsa/sja1105/sja1105_spi.c-579-\t.can_limit_mcast_flood\t= false,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=605=const struct sja1105_info sja1105t_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-609-\t.dyn_ops\t\t= sja1105et_dyn_ops,\ndrivers/net/dsa/sja1105/sja1105_spi.c:610:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1105,\ndrivers/net/dsa/sja1105/sja1105_spi.c-611-\t.can_limit_mcast_flood\t= false,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=637=const struct sja1105_info sja1105p_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-641-\t.dyn_ops\t\t= sja1105pqrs_dyn_ops,\ndrivers/net/dsa/sja1105/sja1105_spi.c:642:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1105,\ndrivers/net/dsa/sja1105/sja1105_spi.c-643-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=670=const struct sja1105_info sja1105q_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-674-\t.dyn_ops\t\t= sja1105pqrs_dyn_ops,\ndrivers/net/dsa/sja1105/sja1105_spi.c:675:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1105,\ndrivers/net/dsa/sja1105/sja1105_spi.c-676-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=703=const struct sja1105_info sja1105r_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-707-\t.dyn_ops\t\t= sja1105pqrs_dyn_ops,\ndrivers/net/dsa/sja1105/sja1105_spi.c:708:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1105,\ndrivers/net/dsa/sja1105/sja1105_spi.c-709-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=739=const struct sja1105_info sja1105s_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-744-\t.regs\t\t\t= \u0026sja1105pqrs_regs,\ndrivers/net/dsa/sja1105/sja1105_spi.c:745:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1105,\ndrivers/net/dsa/sja1105/sja1105_spi.c-746-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=775=const struct sja1105_info sja1110a_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-780-\t.regs\t\t\t= \u0026sja1110_regs,\ndrivers/net/dsa/sja1105/sja1105_spi.c:781:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1110,\ndrivers/net/dsa/sja1105/sja1105_spi.c-782-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=826=const struct sja1105_info sja1110b_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-831-\t.regs\t\t\t= \u0026sja1110_regs,\ndrivers/net/dsa/sja1105/sja1105_spi.c:832:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1110,\ndrivers/net/dsa/sja1105/sja1105_spi.c-833-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=877=const struct sja1105_info sja1110c_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-882-\t.regs\t\t\t= \u0026sja1110_regs,\ndrivers/net/dsa/sja1105/sja1105_spi.c:883:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1110,\ndrivers/net/dsa/sja1105/sja1105_spi.c-884-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c=928=const struct sja1105_info sja1110d_info = {\n--\ndrivers/net/dsa/sja1105/sja1105_spi.c-933-\t.regs\t\t\t= \u0026sja1110_regs,\ndrivers/net/dsa/sja1105/sja1105_spi.c:934:\t.tag_proto\t\t= DSA_TAG_PROTO_SJA1110,\ndrivers/net/dsa/sja1105/sja1105_spi.c-935-\t.can_limit_mcast_flood\t= true,\n--\ndrivers/net/dsa/vitesse-vsc73xx-core.c=686=static enum dsa_tag_protocol vsc73xx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/vitesse-vsc73xx-core.c-698-\t */\ndrivers/net/dsa/vitesse-vsc73xx-core.c:699:\treturn DSA_TAG_PROTO_VSC73XX_8021Q;\ndrivers/net/dsa/vitesse-vsc73xx-core.c-700-}\n--\ndrivers/net/dsa/xrs700x/xrs700x.c=226=static enum dsa_tag_protocol xrs700x_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/xrs700x/xrs700x.c-229-{\ndrivers/net/dsa/xrs700x/xrs700x.c:230:\treturn DSA_TAG_PROTO_XRS700X;\ndrivers/net/dsa/xrs700x/xrs700x.c-231-}\n--\ndrivers/net/ethernet/airoha/airoha_eth.c=2231=static u32 airoha_get_dsa_tag(struct sk_buff *skb, struct net_device *dev)\n--\ndrivers/net/ethernet/airoha/airoha_eth.c-2240-\ndrivers/net/ethernet/airoha/airoha_eth.c:2241:\tif (dev-\u003edsa_ptr-\u003etag_ops-\u003eproto != DSA_TAG_PROTO_MTK)\ndrivers/net/ethernet/airoha/airoha_eth.c-2242-\t\treturn 0;\n--\ndrivers/net/ethernet/mediatek/mtk_eth_soc.c=3540=static bool mtk_uses_dsa(struct net_device *dev)\n--\ndrivers/net/ethernet/mediatek/mtk_eth_soc.c-3543-\treturn netdev_uses_dsa(dev) \u0026\u0026\ndrivers/net/ethernet/mediatek/mtk_eth_soc.c:3544:\t       dev-\u003edsa_ptr-\u003etag_ops-\u003eproto == DSA_TAG_PROTO_MTK;\ndrivers/net/ethernet/mediatek/mtk_eth_soc.c-3545-#else\n--\ndrivers/net/ethernet/mediatek/mtk_ppe.c=738=void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)\n--\ndrivers/net/ethernet/mediatek/mtk_ppe.c-788-\t\tif (!netdev_uses_dsa(skb-\u003edev) ||\ndrivers/net/ethernet/mediatek/mtk_ppe.c:789:\t\t    skb-\u003edev-\u003edsa_ptr-\u003etag_ops-\u003eproto != DSA_TAG_PROTO_MTK)\ndrivers/net/ethernet/mediatek/mtk_ppe.c-790-\t\t\tgoto out;\n--\ndrivers/net/ethernet/mediatek/mtk_ppe_offload.c=179=mtk_flow_get_dsa_port(struct net_device **dev)\n--\ndrivers/net/ethernet/mediatek/mtk_ppe_offload.c-187-\ndrivers/net/ethernet/mediatek/mtk_ppe_offload.c:188:\tif (dp-\u003ecpu_dp-\u003etag_ops-\u003eproto != DSA_TAG_PROTO_MTK)\ndrivers/net/ethernet/mediatek/mtk_ppe_offload.c-189-\t\treturn -ENODEV;\n--\ninclude/linux/dsa/ocelot.h=180=ocelot_8021q_tagger_data(struct dsa_switch *ds)\ninclude/linux/dsa/ocelot.h-181-{\ninclude/linux/dsa/ocelot.h:182:\tBUG_ON(ds-\u003edst-\u003etag_ops-\u003eproto != DSA_TAG_PROTO_OCELOT_8021Q);\ninclude/linux/dsa/ocelot.h-183-\n--\n\n"
}

5/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 37117
							output: 18
							thoughts: 246
						

Thoughts:
**My Initial Thoughts on the YT9224 Switch Integration**

Okay, so I see that `tag_yt922x.c` has been added and `drivers/net/dsa/motorcomm/chip.c` is being updated to support the YT9224 switch chip. My first instinct is to dive into `drivers/net/dsa/motorcomm/chip.c` to understand exactly what that driver is doing. Ah, right, it's an MDIO driver. Specifically, `yt921x_mdio_driver`, which already supports the YT921x family and now, evidently, the YT922x switches, all connected via the MDIO bus. Good to know.

Now, circling back to `net/dsa/tag_yt922x.c`, this is a DSA tag driver. Specifically, it seems to implement `yt922x_tag_xmit` and `yt922x_tag_rcv`.

This raises a key question in my mind: Can this DSA functionality, particularly the DSA taggers and switches, be probed or instantiated in standard virtualization environments? We often rely on QEMU or Google Compute Engine for initial development and testing before moving to dedicated hardware. I'd need to know if we can do this initial work in a virtual environment.

I'd better start looking at how DSA switches and taggers are usually instantiated or tested. I should probably search the kernel source for examples of how DSA tag drivers are used, check for `dsa_loop` or anything else related to DSA testing in general.



6/2 2026/09/08 09:00 tool grepper
0m Args:
{
  "Expression": "dsa_loop"
}

Results:
{
  "Output": "Documentation/networking/dsa/dsa.rst=159=all attached switch ports must be down while doing this).\nDocumentation/networking/dsa/dsa.rst-160-\nDocumentation/networking/dsa/dsa.rst:161:It is desirable that all tagging protocols are testable with the ``dsa_loop``\nDocumentation/networking/dsa/dsa.rst-162-mockup driver, which can be attached to any network interface. The goal is that\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_KS8995) \t+= ks8995.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)\ndrivers/net/dsa/dsa_loop.c-398-{\ndrivers/net/dsa/dsa_loop.c-399-\tstruct dsa_switch *ds = dev_get_drvdata(\u0026mdiodev-\u003edev);\ndrivers/net/dsa/dsa_loop.c:400:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c-401-\n--\ndrivers/net/dsa/dsa_loop.c-410-\ndrivers/net/dsa/dsa_loop.c:411:static void dsa_loop_drv_shutdown(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-412-{\n--\ndrivers/net/dsa/dsa_loop.c-422-\ndrivers/net/dsa/dsa_loop.c:423:static struct mdio_driver dsa_loop_drv = {\ndrivers/net/dsa/dsa_loop.c-424-\t.mdiodrv.driver\t= {\n--\ndrivers/net/dsa/dsa_loop.c-426-\t},\ndrivers/net/dsa/dsa_loop.c:427:\t.probe\t= dsa_loop_drv_probe,\ndrivers/net/dsa/dsa_loop.c:428:\t.remove\t= dsa_loop_drv_remove,\ndrivers/net/dsa/dsa_loop.c:429:\t.shutdown = dsa_loop_drv_shutdown,\ndrivers/net/dsa/dsa_loop.c-430-};\ndrivers/net/dsa/dsa_loop.c-431-\ndrivers/net/dsa/dsa_loop.c:432:static int dsa_loop_bus_match(struct device *dev,\ndrivers/net/dsa/dsa_loop.c-433-\t\t\t      const struct device_driver *drv)\ndrivers/net/dsa/dsa_loop.c-434-{\ndrivers/net/dsa/dsa_loop.c:435:\treturn drv == \u0026dsa_loop_drv.mdiodrv.driver;\ndrivers/net/dsa/dsa_loop.c-436-}\ndrivers/net/dsa/dsa_loop.c-437-\ndrivers/net/dsa/dsa_loop.c:438:static void dsa_loop_phydevs_unregister(void)\ndrivers/net/dsa/dsa_loop.c-439-{\n--\ndrivers/net/dsa/dsa_loop.c-445-\ndrivers/net/dsa/dsa_loop.c:446:static int __init dsa_loop_create_switch_mdiodev(void)\ndrivers/net/dsa/dsa_loop.c-447-{\ndrivers/net/dsa/dsa_loop.c:448:\tstatic struct dsa_loop_pdata dsa_loop_pdata = {\ndrivers/net/dsa/dsa_loop.c-449-\t\t.cd = {\n--\ndrivers/net/dsa/dsa_loop.c-470-\ndrivers/net/dsa/dsa_loop.c:471:\tswitch_mdiodev-\u003ebus_match = dsa_loop_bus_match;\ndrivers/net/dsa/dsa_loop.c:472:\tswitch_mdiodev-\u003edev.platform_data = \u0026dsa_loop_pdata;\ndrivers/net/dsa/dsa_loop.c-473-\n--\ndrivers/net/dsa/dsa_loop.c-481-\ndrivers/net/dsa/dsa_loop.c:482:static int __init dsa_loop_init(void)\ndrivers/net/dsa/dsa_loop.c-483-{\n--\ndrivers/net/dsa/dsa_loop.c-486-\ndrivers/net/dsa/dsa_loop.c:487:\tret = dsa_loop_create_switch_mdiodev();\ndrivers/net/dsa/dsa_loop.c-488-\tif (ret)\n--\ndrivers/net/dsa/dsa_loop.c-493-\ndrivers/net/dsa/dsa_loop.c:494:\tret = mdio_driver_register(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c-495-\tif (ret) {\ndrivers/net/dsa/dsa_loop.c:496:\t\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c-497-\t\tmdio_device_remove(switch_mdiodev);\n--\ndrivers/net/dsa/dsa_loop.c-502-}\ndrivers/net/dsa/dsa_loop.c:503:module_init(dsa_loop_init);\ndrivers/net/dsa/dsa_loop.c-504-\ndrivers/net/dsa/dsa_loop.c:505:static void __exit dsa_loop_exit(void)\ndrivers/net/dsa/dsa_loop.c-506-{\ndrivers/net/dsa/dsa_loop.c:507:\tmdio_driver_unregister(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c:508:\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c-509-\tmdio_device_remove(switch_mdiodev);\n--\ndrivers/net/dsa/dsa_loop.c-511-}\ndrivers/net/dsa/dsa_loop.c:512:module_exit(dsa_loop_exit);\ndrivers/net/dsa/dsa_loop.c-513-\n"
}

7/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 44384
							output: 20
							thoughts: 62
						

Thoughts:
**Investigating DSA Tagging Protocols**

Okay, so I'm digging into this `dsa_loop.c` file and noticed it's using `DSA_TAG_PROTO_NONE`. That immediately sparks a question in my mind: are DSA tag protocols static, or can they be dynamically configured for network devices? I'm thinking specifically about whether this is something controllable via netlink, sysfs, or devlink. I'm going to jump into some searches now to see how these tagging protocols are actually set or altered within the system. Let's find out how flexible this configuration is.



8/2 2026/09/08 09:00 tool grepper
0m Args:
{
  "Expression": "dsa_tag_driver"
}

Results:
{
  "Output": "net/dsa/conduit.c=350=static ssize_t tagging_store(struct device *d, struct device_attribute *attr,\n--\nnet/dsa/conduit.c-368-\told_tag_ops = cpu_dp-\u003etag_ops;\nnet/dsa/conduit.c:369:\tnew_tag_ops = dsa_tag_driver_get_by_name(name);\nnet/dsa/conduit.c-370-\tkfree(name);\n--\nnet/dsa/conduit.c-386-\t\t */\nnet/dsa/conduit.c:387:\t\tdsa_tag_driver_put(new_tag_ops);\nnet/dsa/conduit.c-388-\t\treturn err;\n--\nnet/dsa/conduit.c-393-out:\nnet/dsa/conduit.c:394:\tdsa_tag_driver_put(old_tag_ops);\nnet/dsa/conduit.c-395-\treturn count;\n--\nnet/dsa/dsa.c=235=static void dsa_tree_free(struct dsa_switch_tree *dst)\n--\nnet/dsa/dsa.c-237-\tif (dst-\u003etag_ops)\nnet/dsa/dsa.c:238:\t\tdsa_tag_driver_put(dst-\u003etag_ops);\nnet/dsa/dsa.c-239-\tlist_del(\u0026dst-\u003elist);\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-1181-\nnet/dsa/dsa.c:1182:\t\ttag_ops = dsa_tag_driver_get_by_name(user_protocol);\nnet/dsa/dsa.c-1183-\t\tif (IS_ERR(tag_ops)) {\n--\nnet/dsa/dsa.c-1191-\tif (!tag_ops)\nnet/dsa/dsa.c:1192:\t\ttag_ops = dsa_tag_driver_get_by_id(default_proto);\nnet/dsa/dsa.c-1193-\n--\nnet/dsa/dsa.c-1206-\nnet/dsa/dsa.c:1207:\t\t\tdsa_tag_driver_put(tag_ops);\nnet/dsa/dsa.c-1208-\t\t\treturn -EINVAL;\n--\nnet/dsa/dsa.c-1213-\t\t */\nnet/dsa/dsa.c:1214:\t\tdsa_tag_driver_put(tag_ops);\nnet/dsa/dsa.c-1215-\t} else {\n--\nnet/dsa/tag.c-18-\nnet/dsa/tag.c:19:static LIST_HEAD(dsa_tag_drivers_list);\nnet/dsa/tag.c:20:static DEFINE_MUTEX(dsa_tag_drivers_lock);\nnet/dsa/tag.c-21-\n--\nnet/dsa/tag.c=128=struct packet_type dsa_pack_type __read_mostly = {\n--\nnet/dsa/tag.c-132-\nnet/dsa/tag.c:133:static void dsa_tag_driver_register(struct dsa_tag_driver *dsa_tag_driver,\nnet/dsa/tag.c-134-\t\t\t\t    struct module *owner)\nnet/dsa/tag.c-135-{\nnet/dsa/tag.c:136:\tdsa_tag_driver-\u003eowner = owner;\nnet/dsa/tag.c-137-\nnet/dsa/tag.c:138:\tmutex_lock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c:139:\tlist_add_tail(\u0026dsa_tag_driver-\u003elist, \u0026dsa_tag_drivers_list);\nnet/dsa/tag.c:140:\tmutex_unlock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c-141-}\nnet/dsa/tag.c-142-\nnet/dsa/tag.c:143:void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],\nnet/dsa/tag.c-144-\t\t\t      unsigned int count, struct module *owner)\n--\nnet/dsa/tag.c-148-\tfor (i = 0; i \u003c count; i++)\nnet/dsa/tag.c:149:\t\tdsa_tag_driver_register(dsa_tag_driver_array[i], owner);\nnet/dsa/tag.c-150-}\nnet/dsa/tag.c-151-\nnet/dsa/tag.c:152:static void dsa_tag_driver_unregister(struct dsa_tag_driver *dsa_tag_driver)\nnet/dsa/tag.c-153-{\nnet/dsa/tag.c:154:\tmutex_lock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c:155:\tlist_del(\u0026dsa_tag_driver-\u003elist);\nnet/dsa/tag.c:156:\tmutex_unlock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c-157-}\nnet/dsa/tag.c:158:EXPORT_SYMBOL_GPL(dsa_tag_drivers_register);\nnet/dsa/tag.c-159-\nnet/dsa/tag.c:160:void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],\nnet/dsa/tag.c-161-\t\t\t\tunsigned int count)\n--\nnet/dsa/tag.c-165-\tfor (i = 0; i \u003c count; i++)\nnet/dsa/tag.c:166:\t\tdsa_tag_driver_unregister(dsa_tag_driver_array[i]);\nnet/dsa/tag.c-167-}\nnet/dsa/tag.c:168:EXPORT_SYMBOL_GPL(dsa_tag_drivers_unregister);\nnet/dsa/tag.c-169-\nnet/dsa/tag.c=170=const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops)\n--\nnet/dsa/tag.c-175-/* Function takes a reference on the module owning the tagger,\nnet/dsa/tag.c:176: * so dsa_tag_driver_put must be called afterwards.\nnet/dsa/tag.c-177- */\nnet/dsa/tag.c:178:const struct dsa_device_ops *dsa_tag_driver_get_by_name(const char *name)\nnet/dsa/tag.c-179-{\nnet/dsa/tag.c-180-\tconst struct dsa_device_ops *ops = ERR_PTR(-ENOPROTOOPT);\nnet/dsa/tag.c:181:\tstruct dsa_tag_driver *dsa_tag_driver;\nnet/dsa/tag.c-182-\n--\nnet/dsa/tag.c-184-\nnet/dsa/tag.c:185:\tmutex_lock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c:186:\tlist_for_each_entry(dsa_tag_driver, \u0026dsa_tag_drivers_list, list) {\nnet/dsa/tag.c:187:\t\tconst struct dsa_device_ops *tmp = dsa_tag_driver-\u003eops;\nnet/dsa/tag.c-188-\n--\nnet/dsa/tag.c-191-\nnet/dsa/tag.c:192:\t\tif (!try_module_get(dsa_tag_driver-\u003eowner))\nnet/dsa/tag.c-193-\t\t\tbreak;\n--\nnet/dsa/tag.c-197-\t}\nnet/dsa/tag.c:198:\tmutex_unlock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c-199-\n--\nnet/dsa/tag.c-202-\nnet/dsa/tag.c:203:const struct dsa_device_ops *dsa_tag_driver_get_by_id(int tag_protocol)\nnet/dsa/tag.c-204-{\nnet/dsa/tag.c:205:\tstruct dsa_tag_driver *dsa_tag_driver;\nnet/dsa/tag.c-206-\tconst struct dsa_device_ops *ops;\n--\nnet/dsa/tag.c-210-\nnet/dsa/tag.c:211:\tmutex_lock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c:212:\tlist_for_each_entry(dsa_tag_driver, \u0026dsa_tag_drivers_list, list) {\nnet/dsa/tag.c:213:\t\tops = dsa_tag_driver-\u003eops;\nnet/dsa/tag.c-214-\t\tif (ops-\u003eproto == tag_protocol) {\n--\nnet/dsa/tag.c-220-\tif (found) {\nnet/dsa/tag.c:221:\t\tif (!try_module_get(dsa_tag_driver-\u003eowner))\nnet/dsa/tag.c-222-\t\t\tops = ERR_PTR(-ENOPROTOOPT);\n--\nnet/dsa/tag.c-226-\nnet/dsa/tag.c:227:\tmutex_unlock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c-228-\n--\nnet/dsa/tag.c-231-\nnet/dsa/tag.c:232:void dsa_tag_driver_put(const struct dsa_device_ops *ops)\nnet/dsa/tag.c-233-{\nnet/dsa/tag.c:234:\tstruct dsa_tag_driver *dsa_tag_driver;\nnet/dsa/tag.c-235-\nnet/dsa/tag.c:236:\tmutex_lock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c:237:\tlist_for_each_entry(dsa_tag_driver, \u0026dsa_tag_drivers_list, list) {\nnet/dsa/tag.c:238:\t\tif (dsa_tag_driver-\u003eops == ops) {\nnet/dsa/tag.c:239:\t\t\tmodule_put(dsa_tag_driver-\u003eowner);\nnet/dsa/tag.c-240-\t\t\tbreak;\n--\nnet/dsa/tag.c-242-\t}\nnet/dsa/tag.c:243:\tmutex_unlock(\u0026dsa_tag_drivers_lock);\nnet/dsa/tag.c-244-}\n--\nnet/dsa/tag.h-13-\nnet/dsa/tag.h:14:struct dsa_tag_driver {\nnet/dsa/tag.h-15-\tconst struct dsa_device_ops *ops;\n--\nnet/dsa/tag.h=20=extern struct packet_type dsa_pack_type;\nnet/dsa/tag.h-21-\nnet/dsa/tag.h:22:const struct dsa_device_ops *dsa_tag_driver_get_by_id(int tag_protocol);\nnet/dsa/tag.h:23:const struct dsa_device_ops *dsa_tag_driver_get_by_name(const char *name);\nnet/dsa/tag.h:24:void dsa_tag_driver_put(const struct dsa_device_ops *ops);\nnet/dsa/tag.h-25-const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops);\n--\nnet/dsa/tag.h=322=static inline unsigned long dsa_xmit_port_mask(const struct sk_buff *skb,\n--\nnet/dsa/tag.h-348-\nnet/dsa/tag.h:349:void dsa_tag_drivers_register(struct dsa_tag_driver *dsa_tag_driver_array[],\nnet/dsa/tag.h-350-\t\t\t      unsigned int count,\nnet/dsa/tag.h-351-\t\t\t      struct module *owner);\nnet/dsa/tag.h:352:void dsa_tag_drivers_unregister(struct dsa_tag_driver *dsa_tag_driver_array[],\nnet/dsa/tag.h-353-\t\t\t\tunsigned int count);\nnet/dsa/tag.h-354-\nnet/dsa/tag.h:355:#define dsa_tag_driver_module_drivers(__dsa_tag_drivers_array, __count)\t\\\nnet/dsa/tag.h:356:static int __init dsa_tag_driver_module_init(void)\t\t\t\\\nnet/dsa/tag.h-357-{\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:358:\tdsa_tag_drivers_register(__dsa_tag_drivers_array, __count,\t\\\nnet/dsa/tag.h-359-\t\t\t\t THIS_MODULE);\t\t\t\t\\\n--\nnet/dsa/tag.h-361-}\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:362:module_init(dsa_tag_driver_module_init);\t\t\t\t\\\nnet/dsa/tag.h-363-\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:364:static void __exit dsa_tag_driver_module_exit(void)\t\t\t\\\nnet/dsa/tag.h-365-{\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:366:\tdsa_tag_drivers_unregister(__dsa_tag_drivers_array, __count);\t\\\nnet/dsa/tag.h-367-}\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:368:module_exit(dsa_tag_driver_module_exit)\nnet/dsa/tag.h-369-\nnet/dsa/tag.h-370-/**\nnet/dsa/tag.h:371: * module_dsa_tag_drivers() - Helper macro for registering DSA tag\nnet/dsa/tag.h-372- * drivers\n--\nnet/dsa/tag.h-378- */\nnet/dsa/tag.h:379:#define module_dsa_tag_drivers(__ops_array)\t\t\t\t\\\nnet/dsa/tag.h:380:dsa_tag_driver_module_drivers(__ops_array, ARRAY_SIZE(__ops_array))\nnet/dsa/tag.h-381-\nnet/dsa/tag.h:382:#define DSA_TAG_DRIVER_NAME(__ops) dsa_tag_driver ## _ ## __ops\nnet/dsa/tag.h-383-\n--\nnet/dsa/tag.h-387-#define DSA_TAG_DRIVER(__ops)\t\t\t\t\t\t\\\nnet/dsa/tag.h:388:static struct dsa_tag_driver DSA_TAG_DRIVER_NAME(__ops) = {\t\t\\\nnet/dsa/tag.h-389-\t.ops = \u0026__ops,\t\t\t\t\t\t\t\\\n--\nnet/dsa/tag.h-392-/**\nnet/dsa/tag.h:393: * module_dsa_tag_driver() - Helper macro for registering a single DSA tag\nnet/dsa/tag.h-394- * driver\n--\nnet/dsa/tag.h-400- */\nnet/dsa/tag.h:401:#define module_dsa_tag_driver(__ops)\t\t\t\t\t\\\nnet/dsa/tag.h-402-DSA_TAG_DRIVER(__ops);\t\t\t\t\t\t\t\\\nnet/dsa/tag.h-403-\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:404:static struct dsa_tag_driver *dsa_tag_driver_array[] =\t{\t\t\\\nnet/dsa/tag.h-405-\t\u0026DSA_TAG_DRIVER_NAME(__ops)\t\t\t\t\t\\\nnet/dsa/tag.h-406-};\t\t\t\t\t\t\t\t\t\\\nnet/dsa/tag.h:407:module_dsa_tag_drivers(dsa_tag_driver_array)\nnet/dsa/tag.h-408-\n--\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=406=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND, BRCM_PREPEND_NAME);\n--\nnet/dsa/tag_brcm.c-408-\nnet/dsa/tag_brcm.c:409:static struct dsa_tag_driver *dsa_tag_driver_array[] =\t{\nnet/dsa/tag_brcm.c-410-#if IS_ENABLED(CONFIG_NET_DSA_TAG_BRCM)\n--\nnet/dsa/tag_brcm.c-423-\nnet/dsa/tag_brcm.c:424:module_dsa_tag_drivers(dsa_tag_driver_array);\nnet/dsa/tag_brcm.c-425-\n--\nnet/dsa/tag_dsa.c=404=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_EDSA, EDSA_NAME);\n--\nnet/dsa/tag_dsa.c-406-\nnet/dsa/tag_dsa.c:407:static struct dsa_tag_driver *dsa_tag_drivers[] = {\nnet/dsa/tag_dsa.c-408-#if IS_ENABLED(CONFIG_NET_DSA_TAG_DSA)\n--\nnet/dsa/tag_dsa.c-415-\nnet/dsa/tag_dsa.c:416:module_dsa_tag_drivers(dsa_tag_drivers);\nnet/dsa/tag_dsa.c-417-\n--\nnet/dsa/tag_gswip.c=114=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP, GSWIP_NAME);\nnet/dsa/tag_gswip.c-115-\nnet/dsa/tag_gswip.c:116:module_dsa_tag_driver(gswip_netdev_ops);\n--\nnet/dsa/tag_hellcreek.c=76=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_HELLCREEK, HELLCREEK_NAME);\nnet/dsa/tag_hellcreek.c-77-\nnet/dsa/tag_hellcreek.c:78:module_dsa_tag_driver(hellcreek_netdev_ops);\n--\nnet/dsa/tag_ksz.c=533=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X, LAN937X_NAME);\nnet/dsa/tag_ksz.c-534-\nnet/dsa/tag_ksz.c:535:static struct dsa_tag_driver *dsa_tag_driver_array[] = {\nnet/dsa/tag_ksz.c-536-\t\u0026DSA_TAG_DRIVER_NAME(ksz8463_netdev_ops),\n--\nnet/dsa/tag_ksz.c-542-\nnet/dsa/tag_ksz.c:543:module_dsa_tag_drivers(dsa_tag_driver_array);\nnet/dsa/tag_ksz.c-544-\n--\nnet/dsa/tag_lan9303.c=126=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9303, LAN9303_NAME);\nnet/dsa/tag_lan9303.c-127-\nnet/dsa/tag_lan9303.c:128:module_dsa_tag_driver(lan9303_netdev_ops);\n--\nnet/dsa/tag_mt7628.c=81=static const struct dsa_device_ops mt7628_tag_ops = {\n--\nnet/dsa/tag_mt7628.c-88-\nnet/dsa/tag_mt7628.c:89:module_dsa_tag_driver(mt7628_tag_ops);\nnet/dsa/tag_mt7628.c-90-\n--\nnet/dsa/tag_mtk.c=112=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MTK, MTK_NAME);\nnet/dsa/tag_mtk.c-113-\nnet/dsa/tag_mtk.c:114:module_dsa_tag_driver(mtk_netdev_ops);\n--\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-\nnet/dsa/tag_mxl-gsw1xx.c:120:module_dsa_tag_driver(gsw1xx_netdev_ops);\n--\nnet/dsa/tag_mxl862xx.c=114=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_mxl862xx.c-115-\nnet/dsa/tag_mxl862xx.c:116:module_dsa_tag_driver(mxl862_netdev_ops);\n--\nnet/dsa/tag_netc.c=215=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NETC, NETC_NAME);\nnet/dsa/tag_netc.c:216:module_dsa_tag_driver(netc_netdev_ops);\n--\nnet/dsa/tag_none.c=22=static const struct dsa_device_ops none_ops = {\n--\nnet/dsa/tag_none.c-27-\nnet/dsa/tag_none.c:28:module_dsa_tag_driver(none_ops);\nnet/dsa/tag_none.c-29-MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NONE, NONE_NAME);\n--\nnet/dsa/tag_ocelot.c=178=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SEVILLE, SEVILLE_NAME);\nnet/dsa/tag_ocelot.c-179-\nnet/dsa/tag_ocelot.c:180:static struct dsa_tag_driver *ocelot_tag_driver_array[] = {\nnet/dsa/tag_ocelot.c-181-\t\u0026DSA_TAG_DRIVER_NAME(ocelot_netdev_ops),\n--\nnet/dsa/tag_ocelot.c-184-\nnet/dsa/tag_ocelot.c:185:module_dsa_tag_drivers(ocelot_tag_driver_array);\nnet/dsa/tag_ocelot.c-186-\n--\nnet/dsa/tag_ocelot_8021q.c=144=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT_8021Q, OCELOT_8021Q_NAME);\nnet/dsa/tag_ocelot_8021q.c-145-\nnet/dsa/tag_ocelot_8021q.c:146:module_dsa_tag_driver(ocelot_8021q_netdev_ops);\n--\nnet/dsa/tag_qca.c=131=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_QCA, QCA_NAME);\nnet/dsa/tag_qca.c-132-\nnet/dsa/tag_qca.c:133:module_dsa_tag_driver(qca_netdev_ops);\n--\nnet/dsa/tag_rtl4_a.c=119=static const struct dsa_device_ops rtl4a_netdev_ops = {\n--\nnet/dsa/tag_rtl4_a.c-125-};\nnet/dsa/tag_rtl4_a.c:126:module_dsa_tag_driver(rtl4a_netdev_ops);\nnet/dsa/tag_rtl4_a.c-127-\n--\nnet/dsa/tag_rtl8_4.c=269=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4T, RTL8_4T_NAME);\nnet/dsa/tag_rtl8_4.c-270-\nnet/dsa/tag_rtl8_4.c:271:static struct dsa_tag_driver *dsa_tag_drivers[] = {\nnet/dsa/tag_rtl8_4.c-272-\t\u0026DSA_TAG_DRIVER_NAME(rtl8_4_netdev_ops),\n--\nnet/dsa/tag_rtl8_4.c-274-};\nnet/dsa/tag_rtl8_4.c:275:module_dsa_tag_drivers(dsa_tag_drivers);\nnet/dsa/tag_rtl8_4.c-276-\n--\nnet/dsa/tag_rzn1_a5psw.c=118=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_A5PSW, A5PSW_NAME);\nnet/dsa/tag_rzn1_a5psw.c:119:module_dsa_tag_driver(a5psw_netdev_ops);\n--\nnet/dsa/tag_sja1105.c=764=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SJA1110, SJA1110_NAME);\nnet/dsa/tag_sja1105.c-765-\nnet/dsa/tag_sja1105.c:766:static struct dsa_tag_driver *sja1105_tag_driver_array[] = {\nnet/dsa/tag_sja1105.c-767-\t\u0026DSA_TAG_DRIVER_NAME(sja1105_netdev_ops),\n--\nnet/dsa/tag_sja1105.c-770-\nnet/dsa/tag_sja1105.c:771:module_dsa_tag_drivers(sja1105_tag_driver_array);\nnet/dsa/tag_sja1105.c-772-\n--\nnet/dsa/tag_trailer.c=71=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_TRAILER, TRAILER_NAME);\nnet/dsa/tag_trailer.c-72-\nnet/dsa/tag_trailer.c:73:module_dsa_tag_driver(trailer_netdev_ops);\n--\nnet/dsa/tag_vsc73xx_8021q.c=67=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_VSC73XX_8021Q, VSC73XX_8021Q_NAME);\nnet/dsa/tag_vsc73xx_8021q.c-68-\nnet/dsa/tag_vsc73xx_8021q.c:69:module_dsa_tag_driver(vsc73xx_8021q_netdev_ops);\n--\nnet/dsa/tag_xrs700x.c=65=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_XRS700X, XRS700X_NAME);\nnet/dsa/tag_xrs700x.c-66-\nnet/dsa/tag_xrs700x.c:67:module_dsa_tag_driver(xrs700x_netdev_ops);\n--\nnet/dsa/tag_yt921x.c=171=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT921X, YT921X_TAG_NAME);\nnet/dsa/tag_yt921x.c-172-\nnet/dsa/tag_yt921x.c:173:module_dsa_tag_driver(yt921x_netdev_ops);\n--\nnet/dsa/tag_yt922x.c=108=MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT922X, YT922X_TAG_NAME);\nnet/dsa/tag_yt922x.c-109-\nnet/dsa/tag_yt922x.c:110:module_dsa_tag_driver(yt922x_netdev_ops);\nnet/dsa/tag_yt922x.c-111-\n"
}

9/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 52222
							output: 39
							thoughts: 85
						

Thoughts:
Okay, let's break this down. Where *exactly* is DSA being configured and instantiated within the Linux kernel? I need to get the definitive answer here. My initial thought is to dive into the documentation, specifically looking at `Documentation/networking/dsa/dsa.rst`. I should also examine the source code, maybe checking out `dsa_loop.c` to see if that gives me any more insight or possibly the sysfs interface and its `tagging_store` attribute or even looking at mock devices as a potential example. But before I start blindly searching, let me zero in on the documentation. It's likely that a key portion is dedicated to explaining this, so I'll go directly to lines 150-180 of `Documentation/networking/dsa/dsa.rst`. That's probably where the meat of the discussion will be.



10/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "Documentation/networking/dsa/dsa.rst",
  "FirstLine": 145,
  "LineCount": 50
}

Results:
{
  "Contents": " 145:\ttagging protocols are not compatible with one another. In this case, there are\n 146:\tno DSA links in this fabric, and each switch constitutes a disjoint DSA switch\n 147:\ttree. The DSA links are viewed as simply a pair of a DSA conduit (the out-facing\n 148:\tport of the upstream DSA switch) and a CPU port (the in-facing port of the\n 149:\tdownstream DSA switch).\n 150:\t\n 151:\tThe tagging protocol of the attached DSA switch tree can be viewed through the\n 152:\t``dsa/tagging`` sysfs attribute of the DSA conduit::\n 153:\t\n 154:\t    cat /sys/class/net/eth0/dsa/tagging\n 155:\t\n 156:\tIf the hardware and driver are capable, the tagging protocol of the DSA switch\n 157:\ttree can be changed at runtime. This is done by writing the new tagging\n 158:\tprotocol name to the same sysfs device attribute as above (the DSA conduit and\n 159:\tall attached switch ports must be down while doing this).\n 160:\t\n 161:\tIt is desirable that all tagging protocols are testable with the ``dsa_loop``\n 162:\tmockup driver, which can be attached to any network interface. The goal is that\n 163:\tany network interface should be capable of transmitting the same packet in the\n 164:\tsame way, and the tagger should decode the same received packet in the same way\n 165:\tregardless of the driver used for the switch control path, and the driver used\n 166:\tfor the DSA conduit.\n 167:\t\n 168:\tThe transmission of a packet goes through the tagger's ``xmit`` function.\n 169:\tThe passed ``struct sk_buff *skb`` has ``skb-\u003edata`` pointing at\n 170:\t``skb_mac_header(skb)``, i.e. at the destination MAC address, and the passed\n 171:\t``struct net_device *dev`` represents the virtual DSA user network interface\n 172:\twhose hardware counterpart the packet must be steered to (i.e. ``swp0``).\n 173:\tThe job of this method is to prepare the skb in a way that the switch will\n 174:\tunderstand what egress port the packet is for (and not deliver it towards other\n 175:\tports). Typically this is fulfilled by pushing a frame header. Checking for\n 176:\tinsufficient size in the skb headroom or tailroom is unnecessary provided that\n 177:\tthe ``needed_headroom`` and ``needed_tailroom`` properties were filled out\n 178:\tproperly, because DSA ensures there is enough space before calling this method.\n 179:\t\n 180:\tThe reception of a packet goes through the tagger's ``rcv`` function. The\n 181:\tpassed ``struct sk_buff *skb`` has ``skb-\u003edata`` pointing at\n 182:\t``skb_mac_header(skb) + ETH_ALEN`` octets, i.e. to where the first octet after\n 183:\tthe EtherType would have been, were this frame not tagged. The role of this\n 184:\tmethod is to consume the frame header, adjust ``skb-\u003edata`` to really point at\n 185:\tthe first octet after the EtherType, and to change ``skb-\u003edev`` to point to the\n 186:\tvirtual DSA user network interface corresponding to the physical front-facing\n 187:\tswitch port that the packet was received on.\n 188:\t\n 189:\tSince tagging protocols in category 1 and 2 break software (and most often also\n 190:\thardware) packet dissection on the DSA conduit, features such as RPS (Receive\n 191:\tPacket Steering) on the DSA conduit would be broken. The DSA framework deals\n 192:\twith this by hooking into the flow dissector and shifting the offset at which\n 193:\tthe IP header is to be found in the tagged frame as seen by the DSA conduit.\n 194:\tThis behavior is automatic based on the ``overhead`` value of the tagging\n"
}

11/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 53594
							output: 19
							thoughts: 87
						

Thoughts:
Here's my thinking process:

**Diving into the DSA Loop Driver**

Okay, so I'm looking at this `dsa_loop` thing and it's flagged as a mockup driver. My immediate questions are: how is this loopback driver integrated with the DSA (Distributed Switch Architecture) framework, and how is it *actually* configured? I need to understand the connection.

The obvious next step is to examine the source code. I'm going to head straight for `drivers/net/dsa/dsa_loop.c` and `drivers/net/dsa/dsa_loop_bdinfo.c`, or anything else that seems relevant in the `drivers/net/dsa/` directory. A quick `grep` for `dsa_loop` should get me up to speed. I'm hoping to find the configuration mechanisms and understand the relationship with the overall DSA architecture. I need to get a clear picture of its role within the larger system.



12/2 2026/09/08 09:00 tool grepper
0m Args:
{
  "Expression": "dsa_loop_"
}

Results:
{
  "Output": "drivers/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)\ndrivers/net/dsa/dsa_loop.c-398-{\ndrivers/net/dsa/dsa_loop.c-399-\tstruct dsa_switch *ds = dev_get_drvdata(\u0026mdiodev-\u003edev);\ndrivers/net/dsa/dsa_loop.c:400:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c-401-\n--\ndrivers/net/dsa/dsa_loop.c-410-\ndrivers/net/dsa/dsa_loop.c:411:static void dsa_loop_drv_shutdown(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-412-{\n--\ndrivers/net/dsa/dsa_loop.c-422-\ndrivers/net/dsa/dsa_loop.c:423:static struct mdio_driver dsa_loop_drv = {\ndrivers/net/dsa/dsa_loop.c-424-\t.mdiodrv.driver\t= {\n--\ndrivers/net/dsa/dsa_loop.c-426-\t},\ndrivers/net/dsa/dsa_loop.c:427:\t.probe\t= dsa_loop_drv_probe,\ndrivers/net/dsa/dsa_loop.c:428:\t.remove\t= dsa_loop_drv_remove,\ndrivers/net/dsa/dsa_loop.c:429:\t.shutdown = dsa_loop_drv_shutdown,\ndrivers/net/dsa/dsa_loop.c-430-};\ndrivers/net/dsa/dsa_loop.c-431-\ndrivers/net/dsa/dsa_loop.c:432:static int dsa_loop_bus_match(struct device *dev,\ndrivers/net/dsa/dsa_loop.c-433-\t\t\t      const struct device_driver *drv)\ndrivers/net/dsa/dsa_loop.c-434-{\ndrivers/net/dsa/dsa_loop.c:435:\treturn drv == \u0026dsa_loop_drv.mdiodrv.driver;\ndrivers/net/dsa/dsa_loop.c-436-}\ndrivers/net/dsa/dsa_loop.c-437-\ndrivers/net/dsa/dsa_loop.c:438:static void dsa_loop_phydevs_unregister(void)\ndrivers/net/dsa/dsa_loop.c-439-{\n--\ndrivers/net/dsa/dsa_loop.c-445-\ndrivers/net/dsa/dsa_loop.c:446:static int __init dsa_loop_create_switch_mdiodev(void)\ndrivers/net/dsa/dsa_loop.c-447-{\ndrivers/net/dsa/dsa_loop.c:448:\tstatic struct dsa_loop_pdata dsa_loop_pdata = {\ndrivers/net/dsa/dsa_loop.c-449-\t\t.cd = {\n--\ndrivers/net/dsa/dsa_loop.c-470-\ndrivers/net/dsa/dsa_loop.c:471:\tswitch_mdiodev-\u003ebus_match = dsa_loop_bus_match;\ndrivers/net/dsa/dsa_loop.c:472:\tswitch_mdiodev-\u003edev.platform_data = \u0026dsa_loop_pdata;\ndrivers/net/dsa/dsa_loop.c-473-\n--\ndrivers/net/dsa/dsa_loop.c-481-\ndrivers/net/dsa/dsa_loop.c:482:static int __init dsa_loop_init(void)\ndrivers/net/dsa/dsa_loop.c-483-{\n--\ndrivers/net/dsa/dsa_loop.c-486-\ndrivers/net/dsa/dsa_loop.c:487:\tret = dsa_loop_create_switch_mdiodev();\ndrivers/net/dsa/dsa_loop.c-488-\tif (ret)\n--\ndrivers/net/dsa/dsa_loop.c-493-\ndrivers/net/dsa/dsa_loop.c:494:\tret = mdio_driver_register(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c-495-\tif (ret) {\ndrivers/net/dsa/dsa_loop.c:496:\t\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c-497-\t\tmdio_device_remove(switch_mdiodev);\n--\ndrivers/net/dsa/dsa_loop.c-502-}\ndrivers/net/dsa/dsa_loop.c:503:module_init(dsa_loop_init);\ndrivers/net/dsa/dsa_loop.c-504-\ndrivers/net/dsa/dsa_loop.c:505:static void __exit dsa_loop_exit(void)\ndrivers/net/dsa/dsa_loop.c-506-{\ndrivers/net/dsa/dsa_loop.c:507:\tmdio_driver_unregister(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c:508:\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c-509-\tmdio_device_remove(switch_mdiodev);\n--\ndrivers/net/dsa/dsa_loop.c-511-}\ndrivers/net/dsa/dsa_loop.c:512:module_exit(dsa_loop_exit);\ndrivers/net/dsa/dsa_loop.c-513-\n"
}

13/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 60344
							output: 37
							thoughts: 128
						

Thoughts:
**Investigating DSA Conduit Tagging**

Okay, so I'm looking at this `dsa_loop` setup, which is using a `fixed_mdio` bus to connect to a mock conduit netdev, similar to how it works with `fixed-0`. Interesting. I see that under `/sys/class/net/<conduit>/dsa/tagging` I can write a tag protocol name, such as `yt922x`, to switch the conduit's tagging protocol. Hmm... a `yt922x` tag protocol on a DSA conduit? That doesn't immediately strike me as obvious. I should probably verify whether this is even supported. Let me dive into the `tagging_store` function in `net/dsa/conduit.c` to confirm. That's where I need to be to understand the protocol selection logic.



14/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "net/dsa/conduit.c",
  "FirstLine": 345,
  "LineCount": 60
}

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 390:\t\n 391:\t\t/* On success we no longer need the module for the old tagging protocol\n 392:\t\t */\n 393:\tout:\n 394:\t\tdsa_tag_driver_put(old_tag_ops);\n 395:\t\treturn count;\n 396:\t}\n 397:\tstatic DEVICE_ATTR_RW(tagging);\n 398:\t\n 399:\tstatic struct attribute *dsa_user_attrs[] = {\n 400:\t\t\u0026dev_attr_tagging.attr,\n 401:\t\tNULL\n 402:\t};\n 403:\t\n 404:\tstatic const struct attribute_group dsa_group = {\n"
}

15/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 61590
							output: 24
							thoughts: 77
						

Thoughts:
Here's my summary, as I see it:

**Analyzing the `dsa_tree_change_tag_proto` Function**

Okay, so I'm digging into how the DSA tagging protocol is changed, and my focus is on this `dsa_tree_change_tag_proto` function. I see that when I execute a command like `echo "yt922x" > /sys/class/net/<conduit>/dsa/tagging`, that's the trigger. This function is the crucial piece that gets called when I want to manipulate the tagging protocol on a network interface. Now I want to get a much better handle on precisely what the code actually *does*. Time to dive into the implementation of `dsa_tree_change_tag_proto` and see what's happening under the hood. I need to understand its logic flow and identify any potential pitfalls.



16/2 2026/09/08 09:00 tool grepper
0m Args:
{
  "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"
}

17/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 62362
							output: 41
							thoughts: 146
						

Thoughts:
**Analyzing the DSA and YT922x Tagging Behavior**

Okay, so I'm digging into this DSA code, and it looks like a key behavior change happens when `dsa_loop` is active or a DSA switch is connected. In these scenarios, `dsa_tree_change_tag_proto` kicks in and modifies the tagging mechanism. This has immediately piqued my interest. It implies that traffic flowing through the DSA user port or conduit will then utilize the `yt922x_tag_xmit` and `yt922x_tag_rcv` functions.

I need to confirm this. I'll move swiftly to `net/dsa/tag_yt922x.c` and take a look at the definitions of `yt922x_tag_rcv` and `yt922x_tag_xmit`. Let's step through `tag_yt922x.c` line by line. I need to fully understand how these functions handle the frame tagging and untagging processes.



18/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "net/dsa/tag_yt922x.c",
  "FirstLine": 1,
  "LineCount": 115
}

Results:
{
  "Contents": "   1:\t// SPDX-License-Identifier: GPL-2.0-or-later\n   2:\t/*\n   3:\t * Motorcomm YT922x Switch Extended CPU Port Tagging\n   4:\t *\n   5:\t * Copyright (c) 2026 Kyle switch \u003ckyle.switch@motor-comm.com\u003e\n   6:\t *\n   7:\t */\n   8:\t\n   9:\t#include \u003clinux/etherdevice.h\u003e\n  10:\t\n  11:\t#include \"tag.h\"\n  12:\t\n  13:\t#define YT922X_TAG_LEN\t8\n  14:\t\n  15:\t/*\n  16:\t * To define the from cpu tag format 8 bytes:\n  17:\t */\n  18:\t#define YT922X_TAG_NAME\t\t\"yt922x\"\n  19:\t#define YT922X_TAG_PORTMASK_0\tBIT(15)\n  20:\t#define YT922X_TAG_PORTMASK_M\tGENMASK(8, 0)\n  21:\t#define  YT922X_TAG_PORTS(x)\t\tFIELD_PREP(YT922X_TAG_PORTMASK_M, (x))\n  22:\t#define YT922X_TAG_FORCE_DST\tBIT(9)\n  23:\t#define YT922X_TAG_PRIO_M\tGENMASK(12, 10)\n  24:\t#define YT922X_TAG_PRIO_EN\tBIT(13)\n  25:\t#define  YT922X_TAG_PRIO(x)\t\t(FIELD_PREP(YT922X_TAG_PRIO_M, (x)) | YT922X_TAG_PRIO_EN)\n  26:\t#define YT922X_TAG_RX_PORT_M\tGENMASK(5, 2)\n  27:\t#define YT922X_TAG_RX_PRIO_M\tGENMASK(15, 13)\n  28:\t\n  29:\tstatic struct sk_buff *\n  30:\tyt922x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)\n  31:\t{\n  32:\t\tunsigned long ports;\n  33:\t\t__be16 *tag;\n  34:\t\tu16 ctrl;\n  35:\t\n  36:\t\tskb_push(skb, YT922X_TAG_LEN);\n  37:\t\tdsa_alloc_etype_header(skb, YT922X_TAG_LEN);\n  38:\t\ttag = dsa_etype_header_pos_tx(skb);\n  39:\t\n  40:\t\ttag[0] = htons(ETH_P_YT921X);\n  41:\t\tports = dsa_xmit_port_mask(skb, netdev);\n  42:\t\t/*To fill in the case where the port index is not 0 */\n  43:\t\tctrl = YT922X_TAG_PRIO(skb-\u003epriority) | YT922X_TAG_FORCE_DST |\n  44:\t\t       YT922X_TAG_PORTS(ports \u003e\u003e 1);\n  45:\t\ttag[1] = htons(ctrl);\n  46:\t\tif (ports \u0026 BIT(0)) {\n  47:\t\t\t/* To fill in the case where the port index is 0 */\n  48:\t\t\tctrl = YT922X_TAG_PORTMASK_0;\n  49:\t\t\ttag[2] = htons(ctrl);\n  50:\t\t} else {\n  51:\t\t\ttag[2] = 0;\n  52:\t\t}\n  53:\t\ttag[3] = 0;\n  54:\t\n  55:\t\treturn skb;\n  56:\t}\n  57:\t\n  58:\tstatic struct sk_buff *\n  59:\tyt922x_tag_rcv(struct sk_buff *skb, struct net_device *netdev)\n  60:\t{\n  61:\t\tunsigned int port;\n  62:\t\t__be16 *tag;\n  63:\t\tu16 rx;\n  64:\t\n  65:\t\tif (unlikely(!pskb_may_pull(skb, YT922X_TAG_LEN))) {\n  66:\t\t\tkfree_skb(skb);\n  67:\t\t\treturn NULL;\n  68:\t\t}\n  69:\t\n  70:\t\ttag = dsa_etype_header_pos_rx(skb);\n  71:\t\n  72:\t\tif (unlikely(tag[0] != htons(ETH_P_YT921X))) {\n  73:\t\t\tdev_warn_ratelimited(\u0026netdev-\u003edev,\n  74:\t\t\t\t\t     \"Unexpected EtherType 0x%04x\\n\",\n  75:\t\t\t\t\t     ntohs(tag[0]));\n  76:\t\t\tkfree_skb(skb);\n  77:\t\t\treturn NULL;\n  78:\t\t}\n  79:\t\n  80:\t\t/* Locate which port this is coming from */\n  81:\t\trx = ntohs(tag[2]);\n  82:\t\tport = FIELD_GET(YT922X_TAG_RX_PORT_M, rx);\n  83:\t\tskb-\u003edev = dsa_conduit_find_user(netdev, 0, port);\n  84:\t\tif (unlikely(!skb-\u003edev)) {\n  85:\t\t\tdev_warn_ratelimited(\u0026netdev-\u003edev,\n  86:\t\t\t\t\t     \"Couldn't decode source port %u\\n\", port);\n  87:\t\t\tkfree_skb(skb);\n  88:\t\t\treturn NULL;\n  89:\t\t}\n  90:\t\n  91:\t\t/* Remove tag and update checksum */\n  92:\t\tskb_pull_rcsum(skb, YT922X_TAG_LEN);\n  93:\t\tdsa_strip_etype_header(skb, YT922X_TAG_LEN);\n  94:\t\n  95:\t\treturn skb;\n  96:\t}\n  97:\t\n  98:\tstatic const struct dsa_device_ops yt922x_netdev_ops = {\n  99:\t\t.name = YT922X_TAG_NAME,\n 100:\t\t.proto = DSA_TAG_PROTO_YT922X,\n"
}

19/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 64431
							output: 35
							thoughts: 597
						

Thoughts:
**Analyzing Motorcomm Switch Driver Changes**

Okay, first things first, I need to dig into `drivers/net/dsa/motorcomm/chip.c` and `chip.h`. I'm curious about the recent modifications. Let's see... ah, right, the delayed work initialization for `mib_read` was moved around between `yt921x_dsa_setup` and `yt921x_dsa_teardown`. It's now started in setup and stopped during teardown.

But, a nagging thought: is this code hardware-specific? `yt921x_mdio_driver` is an MDIO device driver, specifically for the `motorcomm,yt9215` and `motorcomm,yt9224` switch chips. MDIO devices typically probe via the Device Tree or an MDIO bus scan. Can this `motorcomm` switch driver even be tested in a QEMU or other standard virtual environment? Normally, it would need the Device Tree or a real MDIO bus. Unless we're using mock MDIO, or a platform device, or some sysfs bind...

Wait a second. I'm remembering something. The `tag_yt922x.c` file is part of the core DSA tagging drivers, it's located under `net/dsa/tag_yt922x.c`. It's compiled into `net/dsa/tag_yt922x.ko` or built directly into vmlinux if `CONFIG_NET_DSA_TAG_YT922X` is enabled! And, that config option is independently selectable in `net/dsa/Kconfig`, or, it can be selected by `CONFIG_NET_DSA_YT921X`.

Let me quickly verify that `net/dsa/Kconfig`... Okay, yes, it's there:
```
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.
```
So, what about packet reception and transmission with these DSA taggers? How does this all work? DSA conduits register a `dsa_pack_type` packet handler, `ETH_P_XDSA` or whatever EtherType they use. Or, for EtherType-based tagging, the packet socket/conduit rx calls `tag_ops->rcv`. Alright, time to refresh my memory on the core DSA tagging logic. I'll need to check how `dsa_pack_type` or `dsa_switch_rcv` works in `net/dsa/tag.c`.



20/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "net/dsa/tag.c",
  "FirstLine": 1,
  "LineCount": 100
}

Results:
{
  "Contents": "   1:\t// SPDX-License-Identifier: GPL-2.0-or-later\n   2:\t/*\n   3:\t * DSA tagging protocol handling\n   4:\t *\n   5:\t * Copyright (c) 2008-2009 Marvell Semiconductor\n   6:\t * Copyright (c) 2013 Florian Fainelli \u003cflorian@openwrt.org\u003e\n   7:\t * Copyright (c) 2016 Andrew Lunn \u003candrew@lunn.ch\u003e\n   8:\t */\n   9:\t\n  10:\t#include \u003clinux/netdevice.h\u003e\n  11:\t#include \u003clinux/ptp_classify.h\u003e\n  12:\t#include \u003clinux/skbuff.h\u003e\n  13:\t#include \u003cnet/dsa.h\u003e\n  14:\t#include \u003cnet/dst_metadata.h\u003e\n  15:\t\n  16:\t#include \"tag.h\"\n  17:\t#include \"user.h\"\n  18:\t\n  19:\tstatic LIST_HEAD(dsa_tag_drivers_list);\n  20:\tstatic DEFINE_MUTEX(dsa_tag_drivers_lock);\n  21:\t\n  22:\t/* Determine if we should defer delivery of skb until we have a rx timestamp.\n  23:\t *\n  24:\t * Called from dsa_switch_rcv. For now, this will only work if tagging is\n  25:\t * enabled on the switch. Normally the MAC driver would retrieve the hardware\n  26:\t * timestamp when it reads the packet out of the hardware. However in a DSA\n  27:\t * switch, the DSA driver owning the interface to which the packet is\n  28:\t * delivered is never notified unless we do so here.\n  29:\t */\n  30:\tstatic bool dsa_skb_defer_rx_timestamp(struct dsa_user_priv *p,\n  31:\t\t\t\t\t       struct sk_buff *skb)\n  32:\t{\n  33:\t\tstruct dsa_switch *ds = p-\u003edp-\u003eds;\n  34:\t\tunsigned int type;\n  35:\t\n  36:\t\tif (!ds-\u003eops-\u003eport_rxtstamp)\n  37:\t\t\treturn false;\n  38:\t\n  39:\t\tif (skb_headroom(skb) \u003c ETH_HLEN)\n  40:\t\t\treturn false;\n  41:\t\n  42:\t\t__skb_push(skb, ETH_HLEN);\n  43:\t\n  44:\t\ttype = ptp_classify_raw(skb);\n  45:\t\n  46:\t\t__skb_pull(skb, ETH_HLEN);\n  47:\t\n  48:\t\tif (type == PTP_CLASS_NONE)\n  49:\t\t\treturn false;\n  50:\t\n  51:\t\treturn ds-\u003eops-\u003eport_rxtstamp(ds, p-\u003edp-\u003eindex, skb, type);\n  52:\t}\n  53:\t\n  54:\tstatic int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,\n  55:\t\t\t\t  struct packet_type *pt, struct net_device *unused)\n  56:\t{\n  57:\t\tstruct metadata_dst *md_dst = skb_metadata_dst(skb);\n  58:\t\tstruct dsa_port *cpu_dp = dev-\u003edsa_ptr;\n  59:\t\tstruct sk_buff *nskb = NULL;\n  60:\t\tstruct dsa_user_priv *p;\n  61:\t\n  62:\t\tif (unlikely(!cpu_dp)) {\n  63:\t\t\tkfree_skb(skb);\n  64:\t\t\treturn 0;\n  65:\t\t}\n  66:\t\n  67:\t\tskb = skb_unshare(skb, GFP_ATOMIC);\n  68:\t\tif (!skb)\n  69:\t\t\treturn 0;\n  70:\t\n  71:\t\tif (md_dst \u0026\u0026 md_dst-\u003etype == METADATA_HW_PORT_MUX) {\n  72:\t\t\tunsigned int port = md_dst-\u003eu.port_info.port_id;\n  73:\t\n  74:\t\t\tskb_dst_drop(skb);\n  75:\t\t\tif (!skb_has_extensions(skb))\n  76:\t\t\t\tskb-\u003eslow_gro = 0;\n  77:\t\n  78:\t\t\tskb-\u003edev = dsa_conduit_find_user(dev, 0, port);\n  79:\t\t\tif (likely(skb-\u003edev)) {\n  80:\t\t\t\tdsa_default_offload_fwd_mark(skb);\n  81:\t\t\t\tnskb = skb;\n  82:\t\t\t} else {\n  83:\t\t\t\t/* Just drop the skb if we can't find the user */\n  84:\t\t\t\tkfree_skb(skb);\n  85:\t\t\t}\n  86:\t\t} else {\n  87:\t\t\tnskb = cpu_dp-\u003ercv(skb, dev);\n  88:\t\t}\n  89:\t\n  90:\t\tif (!nskb)\n  91:\t\t\treturn 0;\n  92:\t\n  93:\t\tskb = nskb;\n  94:\t\tskb_push(skb, ETH_HLEN);\n  95:\t\tskb-\u003epkt_type = PACKET_HOST;\n  96:\t\tskb-\u003eprotocol = eth_type_trans(skb, skb-\u003edev);\n  97:\t\n  98:\t\tif (unlikely(!dsa_user_dev_check(skb-\u003edev))) {\n  99:\t\t\t/* Packet is to be injected directly on an upper\n 100:\t\t\t * device, e.g. a team/bond, so skip all DSA-port\n"
}

21/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 67147
							output: 35
							thoughts: 983
						

Thoughts:
**Analyzing the DSA and YT922X Tagging Implementation for Fuzzing Potential**

Okay, let's break this down. My initial observation is focused on `dsa_switch_rcv`, specifically how `cpu_dp->rcv(skb, dev)` calls `yt922x_tag_rcv`. Similarly, on the transmit side, `dsa_user_xmit` calls `cpu_dp->tag_ops->xmit`, which resolves to `yt922x_tag_xmit`. The cool part is DSA can leverage `dsa_loop` or any virtual conduit in test/fuzz environments. This is important.

So, the key functions, `yt922x_tag_xmit` and `yt922x_tag_rcv`, are in `net/dsa/tag_yt922x.c`, taking an `sk_buff` and `net_device` as arguments. That's our data entry point.

Now, glancing at `drivers/net/dsa/motorcomm/chip.c` reveals a raft of functions added or changed related to the YT921x and YT922x series, covering everything from interrupt handling, setup, teardown, link state management, MDIO operations, and various PHY and MAC configurations. These are foundational.

The question then becomes: Is `NET_DSA_TAG_YT922X` accessible within a fuzzing context like Syzkaller? Absolutely. DSA tagging protocols directly handle network packets – frame tagging and untagging – critical for switch architectures. With `dsa_loop` or mock interfaces, we're basically looking at direct ingress and egress points for packets hitting `yt922x_tag_rcv` and `yt922x_tag_xmit`.

This is gold. We've got raw `skb` packets flowing from network or user input into these functions. This opens the floodgates for fuzzing. We are talking about manipulating the `skb` itself, packet header parsing, length checks, memory bounds violations – all classic fuzzing targets.

Finally, I will need to check Kconfig dependencies for `NET_DSA_TAG_YT922X` and `NET_DSA_YT921X` in `net/dsa/Kconfig`, to know if they will be included in the test image.



22/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "net/dsa/Kconfig",
  "FirstLine": 220,
  "LineCount": 25
}

Results:
{
  "Contents": " 220:\t\thelp\n 221:\t\t  Say Y or M if you want to enable support for tagging frames for\n 222:\t\t  Arrow SpeedChips XRS700x switches that use a single byte tag trailer.\n 223:\t\n 224:\tconfig NET_DSA_TAG_YT921X\n 225:\t\ttristate \"Tag driver for Motorcomm YT921x switches\"\n 226:\t\thelp\n 227:\t\t  Say Y or M if you want to enable support for tagging frames for\n 228:\t\t  Motorcomm YT921x switches.\n 229:\t\n 230:\tconfig NET_DSA_TAG_YT922X\n 231:\t\ttristate \"Tag driver for Motorcomm YT922x switches\"\n 232:\t\thelp\n 233:\t\t  Say Y or M if you want to enable support for tagging frames for\n 234:\t\t  Motorcomm YT922x switches.\n 235:\t\n 236:\tendif\n"
}

23/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 68959
							output: 33
							thoughts: 28
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Investigating the Kconfig Hierarchy for DSA Configuration**

Okay, first things first, I need to get a handle on the overall structure of this DSA configuration option. The best place to start is always the `net/dsa/Kconfig` file itself. Let's immediately jump to the top of the file. My goal is to quickly pinpoint the specific menu or, more likely, the surrounding `if` blocks that govern the inclusion of the option I'm interested in. I need to understand its dependencies and any potential conditional compilation aspects *before* diving into the specifics of the option itself. This top-down approach is critical for quickly grasping its placement within the broader networking configuration framework. Knowing where it sits will greatly inform my understanding of potential interactions with other kernel features and how it's exposed during the build process.



24/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "net/dsa/Kconfig",
  "FirstLine": 1,
  "LineCount": 40
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\t\n   3:\tmenuconfig NET_DSA\n   4:\t\ttristate \"Distributed Switch Architecture\"\n   5:\t\tdepends on BRIDGE || BRIDGE=n\n   6:\t\tdepends on HSR || HSR=n\n   7:\t\tdepends on INET \u0026\u0026 NETDEVICES\n   8:\t\tselect GRO_CELLS\n   9:\t\tselect NET_SWITCHDEV\n  10:\t\tselect PHYLINK\n  11:\t\tselect NET_DEVLINK\n  12:\t\timply NET_SELFTESTS\n  13:\t\thelp\n  14:\t\t  Say Y if you want to enable support for the hardware switches supported\n  15:\t\t  by the Distributed Switch Architecture.\n  16:\t\n  17:\tif NET_DSA\n  18:\t\n  19:\t# Drivers must select the appropriate tagging format(s)\n  20:\t\n  21:\tconfig NET_DSA_TAG_NONE\n  22:\t\ttristate \"No-op tag driver\"\n  23:\t\thelp\n  24:\t\t  Say Y or M if you want to enable support for switches which don't tag\n  25:\t\t  frames over the CPU port.\n  26:\t\n  27:\tconfig NET_DSA_TAG_AR9331\n  28:\t\ttristate \"Tag driver for Atheros AR9331 SoC with built-in switch\"\n  29:\t\thelp\n  30:\t\t  Say Y or M if you want to enable support for tagging frames for\n  31:\t\t  the Atheros AR9331 SoC with built-in switch.\n  32:\t\n  33:\tconfig NET_DSA_TAG_BRCM_COMMON\n  34:\t\ttristate\n  35:\t\tdefault n\n  36:\t\n  37:\tconfig NET_DSA_TAG_BRCM\n  38:\t\ttristate \"Tag driver for Broadcom switches using in-frame headers\"\n  39:\t\tselect NET_DSA_TAG_BRCM_COMMON\n  40:\t\thelp\n"
}

25/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 69728
							output: 38
							thoughts: 21
						

Thoughts:
Here's my thought process, as requested:

**Checking DSA Driver Configuration**

Okay, I'm taking a look at network driver configurations. I need to make sure I haven't missed anything specific to MotorComm's DSA (Distributed Switch Architecture) implementation. Given my experience, I know that changes or specific options can often be located in unexpected places within the kernel build system. Therefore, I should check the Kconfig file for that driver, specifically the one located at `drivers/net/dsa/motorcomm/Kconfig`. It’s a standard practice in Kconfig-driven kernel builds to check the appropriate file for all possible changes to see whether the new functionality is already present or could be easily enabled through a simple config option, rather than attempting to add something entirely new. This could save a significant amount of time and is always a good starting point. This is an efficient way to make sure that I don't overlook a critical detail.



26/2 2026/09/08 09:00 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/Kconfig",
  "FirstLine": 1,
  "LineCount": 30
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\tconfig NET_DSA_YT921X\n   3:\t\ttristate \"Motorcomm YT9215 ethernet switch chip support\"\n   4:\t\tselect NET_DSA_TAG_YT921X\n   5:\t\tselect NET_DSA_TAG_YT922X\n   6:\t\tselect NET_IEEE8021Q_HELPERS if DCB\n   7:\t\thelp\n   8:\t\t  This enables support for the Motorcomm YT9215 ethernet switch\n   9:\t\t  chip.\n  10:\t\n  11:\tconfig NET_DSA_YT921X_LEDS\n  12:\t\tbool \"LED support for Motorcomm YT9215\"\n  13:\t\tdefault y\n  14:\t\tdepends on NET_DSA_YT921X\n  15:\t\tdepends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X\n  16:\t\thelp\n  17:\t\t  This enables support for controlling the LEDs attached to the\n  18:\t\t  Motorcomm YT9215 switch chips.\n"
}

27/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 70280
							output: 22
							thoughts: 15
						

Thoughts:
Here's my take on the thought process, as if I were the one thinking it:

**Examining the DSA Kconfig File**

Okay, so I need to understand the configuration options for DSA (Distributed Switch Architecture) within the networking subsystem. My initial thought is, where would that reside within the kernel source tree? I immediately think, based on prior experience, that the likely place to find the configuration options would be within the `drivers/net/dsa/` directory. And within that directory, the standard place for Kconfig files, which define the configuration variables for the build system, is going to be `Kconfig`. Therefore, I'll start by checking `drivers/net/dsa/Kconfig`. That should give me a good overview of what’s available and how the various DSA features are controlled during the kernel build process. Time to dive in!



28/2 2026/09/08 09:00 tool grepper
0m Args:
{
  "Expression": "source.*drivers/net/dsa"
}

Results:
{
  "Output": "drivers/net/Kconfig=504=source \"drivers/atm/Kconfig\"\ndrivers/net/Kconfig-505-\ndrivers/net/Kconfig:506:source \"drivers/net/dsa/Kconfig\"\ndrivers/net/Kconfig-507-\n--\ndrivers/net/dsa/Kconfig=2=menu \"Distributed Switch Architecture drivers\"\n--\ndrivers/net/dsa/Kconfig-4-\ndrivers/net/dsa/Kconfig:5:source \"drivers/net/dsa/b53/Kconfig\"\ndrivers/net/dsa/Kconfig-6-\n--\ndrivers/net/dsa/Kconfig=19=config NET_DSA_LOOP\n--\ndrivers/net/dsa/Kconfig-26-\ndrivers/net/dsa/Kconfig:27:source \"drivers/net/dsa/hirschmann/Kconfig\"\ndrivers/net/dsa/Kconfig-28-\ndrivers/net/dsa/Kconfig:29:source \"drivers/net/dsa/lantiq/Kconfig\"\ndrivers/net/dsa/Kconfig-30-\n--\ndrivers/net/dsa/Kconfig=76=config NET_DSA_MV88E6060\n--\ndrivers/net/dsa/Kconfig-82-\ndrivers/net/dsa/Kconfig:83:source \"drivers/net/dsa/microchip/Kconfig\"\ndrivers/net/dsa/Kconfig-84-\ndrivers/net/dsa/Kconfig:85:source \"drivers/net/dsa/motorcomm/Kconfig\"\ndrivers/net/dsa/Kconfig-86-\ndrivers/net/dsa/Kconfig:87:source \"drivers/net/dsa/mv88e6xxx/Kconfig\"\ndrivers/net/dsa/Kconfig-88-\ndrivers/net/dsa/Kconfig:89:source \"drivers/net/dsa/mxl862xx/Kconfig\"\ndrivers/net/dsa/Kconfig-90-\ndrivers/net/dsa/Kconfig:91:source \"drivers/net/dsa/netc/Kconfig\"\ndrivers/net/dsa/Kconfig-92-\ndrivers/net/dsa/Kconfig:93:source \"drivers/net/dsa/ocelot/Kconfig\"\ndrivers/net/dsa/Kconfig-94-\ndrivers/net/dsa/Kconfig:95:source \"drivers/net/dsa/qca/Kconfig\"\ndrivers/net/dsa/Kconfig-96-\ndrivers/net/dsa/Kconfig:97:source \"drivers/net/dsa/sja1105/Kconfig\"\ndrivers/net/dsa/Kconfig-98-\ndrivers/net/dsa/Kconfig:99:source \"drivers/net/dsa/xrs700x/Kconfig\"\ndrivers/net/dsa/Kconfig-100-\ndrivers/net/dsa/Kconfig:101:source \"drivers/net/dsa/realtek/Kconfig\"\ndrivers/net/dsa/Kconfig-102-\n"
}

29/2 2026/09/08 09:00 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 71280
							output: 269
							thoughts: 572
						

Thoughts:
**My Assessment of the YT922x DSA Driver Patch**

Okay, let's break this down. First, I need to make sure the essential `CONFIG` options are defined: `NET_DSA` for the Distributed Switch Architecture core, `NET_DSA_TAG_YT922X` for the YT922x DSA tagging protocol driver, and `NET_DSA_YT921X` for the Motorcomm switch chip driver, which implicitly selects the tagging protocol. That seems straightforward enough.

Now, let me focus on the key new and modified functions. I need to understand what's been implemented. The core seems to be around `yt922x_tag_rcv` and `yt922x_tag_xmit`, which are clearly the packet parsing and frame tagging functions. Then we have the setup functions `yt922x_dsa_setup`, `yt922x_port_setup`, `yt922x_pcs_config`, and `yt922x_pcs_get_state`. And finally, there are `yt922x_phylink_mac_link_up` and `yt922x_phylink_mac_link_down`, and `yt92xx_register_switch`. This gives me a good overview of the patch's scope.

Alright, time to evaluate this patch according to the fuzzing criteria. The "WorthFuzzing" flag is set to true, which makes sense. This patch introduces a new DSA tagging protocol (`DSA_TAG_PROTO_YT922X`) via `net/dsa/tag_yt922x.c`, which includes implementations for frame handling. The driver support for YT922x switch chips in `drivers/net/dsa/motorcomm/chip.c` also seems like a crucial part. It's also good to see that the code is reachable in software/virtual network environments. This means it is easily testable. The "EnableConfigs" are as expected; the necessary `CONFIG` options are clearly listed. And the "FocusSymbols" are the same as what I identified earlier: the tagging, and configuration functions.

I need to make sure I'm following my internal guidelines: Reachability is confirmed, and none of the key functions seem to be excessively general. The `CONFIG` options are specified exactly as they are without the prefix.

Okay, everything looks good. I've done my due diligence. Now, I need to call the `set-results` function to complete the evaluation.



30/2 2026/09/08 09:00 tool set-results
0m Args:
{
  "EnableConfigs": [
    "NET_DSA",
    "NET_DSA_TAG_YT922X",
    "NET_DSA_YT921X"
  ],
  "FocusSymbols": [
    "yt922x_tag_rcv",
    "yt922x_tag_xmit",
    "yt922x_dsa_setup",
    "yt922x_port_setup",
    "yt922x_pcs_config",
    "yt922x_pcs_get_state",
    "yt92xx_register_switch"
  ],
  "Reasoning": "The patch series introduces a new DSA tagging driver (net/dsa/tag_yt922x.c) implementing packet receive (yt922x_tag_rcv) and transmit (yt922x_tag_xmit) tagging operations, and extends the Motorcomm switch driver (drivers/net/dsa/motorcomm/chip.c) to support the YT922x series. DSA tag parsing and frame generation execute in the network packet path and can be exercised in virtualized environments using DSA conduits, mock interfaces, or packet sockets.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "NET_DSA",
    "NET_DSA_TAG_YT922X",
    "NET_DSA_YT921X"
  ],
  "FocusSymbols": [
    "yt922x_tag_rcv",
    "yt922x_tag_xmit",
    "yt922x_dsa_setup",
    "yt922x_port_setup",
    "yt922x_pcs_config",
    "yt922x_pcs_get_state",
    "yt92xx_register_switch"
  ],
  "Reasoning": "The patch series introduces a new DSA tagging driver (net/dsa/tag_yt922x.c) implementing packet receive (yt922x_tag_rcv) and transmit (yt922x_tag_xmit) tagging operations, and extends the Motorcomm switch driver (drivers/net/dsa/motorcomm/chip.c) to support the YT922x series. DSA tag parsing and frame generation execute in the network packet path and can be exercised in virtualized environments using DSA conduits, mock interfaces, or packet sockets.",
  "WorthFuzzing": true
}

31/1 2026/09/08 09:00 action If
0m Args:
{
  "WorthFuzzing": true
}

Results:
null

32/2 2026/09/08 09:00 agent kmsan-evaluator
0m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch introduces support for Motorcomm YT922x switches to the existing YT921x DSA driver and adds a new DSA tag driver (`tag_yt922x.c`).\n\nAnalysis of uninitialized memory risk:\n1. All private device structures are allocated using `devm_kzalloc()`, ensuring all fields are zero-initialized.\n2. In `yt922x_tag_xmit()`, the 8-byte tag inserted into outgoing packets is completely populated (`tag[0]`, `tag[1]`, `tag[2]`, `tag[3]` are all explicitly assigned), leaving no uninitialized padding or bytes.\n3. In `yt922x_tag_rcv()`, the packet length is validated using `pskb_may_pull()` before parsing header fields.\n4. Internal register read functions check return values before using output variables.\n5. No new user-space copies (`copy_to_user`, `put_user`, socket options, or netlink attributes) are introduced or modified.\n\nAny potential memory issues (e.g. out-of-bounds access or race conditions) are within the scope of KASAN/LOCKDEP. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
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 3a66b7892ba11c710bd496d44cf1b2bc9a8089c5
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Sep 8 08:59:49 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
index 79cdd79a1fd25..f690de4c7a7c5 100644
--- a/drivers/net/dsa/motorcomm/Kconfig
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -2,6 +2,7 @@
 config NET_DSA_YT921X
 	tristate "Motorcomm YT9215 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
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index d663af010f431..4a052b1886b51 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.
@@ -112,6 +112,7 @@ struct yt921x_info {
 #define YT921X_PORT_MASK_INT0_n(n)	GENMASK((n) - 1, 0)
 #define YT921X_PORT_MASK_EXT0		BIT(8)
 #define YT921X_PORT_MASK_EXT1		BIT(9)
+#define YT922X_PORT_MASK_INTm_n(m, n)	GENMASK((n), (m))
 
 static const struct yt921x_info yt921x_infos[] = {
 	{
@@ -149,9 +150,17 @@ static const struct yt921x_info yt921x_infos[] = {
 		YT921X_PORT_MASK_INT0_n(8),
 		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
 	},
+	{
+		"YT9224", YT9224_MAJOR, 0, 0,
+		YT922X_PORT_MASK_INTm_n(4, 7) | YT921X_PORT_MASK_INTn(0) | YT921X_PORT_MASK_INTn(8),
+		0x0,
+	},
 	{}
 };
 
+/* Define top ext addr */
+#define YT922X_COMMON_EXT_PHYADDR	9
+
 #define YT921X_VID_UNWARE	4095
 
 /* The interval should be small enough to avoid overflow of 32bit MIBs.
@@ -357,7 +366,7 @@ static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)
 	u16 val;
 	int res;
 
-	if (port >= YT921X_PORT_NUM)
+	if (port >= priv->series->max_ports)
 		return U16_MAX;
 
 	mutex_lock(&priv->reg_lock);
@@ -375,7 +384,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);
@@ -390,6 +399,7 @@ yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)
 {
 	struct device *dev = to_device(priv);
 	struct mii_bus *mbus;
+	u32 max_ports;
 	int res;
 
 	mbus = devm_mdiobus_alloc(dev);
@@ -402,7 +412,8 @@ 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 = (u32)~GENMASK(max_ports - 1, 0);
 
 	res = devm_of_mdiobus_register(dev, mbus, mnp);
 	if (res)
@@ -4231,6 +4242,11 @@ static void yt921x_dsa_teardown(struct dsa_switch *ds)
 #if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
 	yt921x_leds_remove(priv);
 #endif
+	for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
+		struct yt921x_port *pp = &priv->ports[i];
+
+		disable_delayed_work_sync(&pp->mib_read);
+	}
 }
 
 static int yt921x_chip_detect(struct yt921x_priv *priv)
@@ -4551,6 +4567,14 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 	struct device_node *child;
 	int res;
 
+	/* mib polling init */
+	for (size_t i = 0; i < ARRAY_SIZE(priv->ports); i++) {
+		struct yt921x_port *pp = &priv->ports[i];
+
+		pp->index = i;
+		INIT_DELAYED_WORK(&pp->mib_read, yt921x_poll_mib);
+	}
+
 	mutex_lock(&priv->reg_lock);
 	res = yt921x_chip_reset(priv);
 	mutex_unlock(&priv->reg_lock);
@@ -4679,99 +4703,984 @@ static const struct dsa_switch_ops yt921x_dsa_switch_ops = {
 	.setup			= yt921x_dsa_setup,
 };
 
-static void yt921x_mdio_shutdown(struct mdio_device *mdiodev)
+static int yt922x_port_down(struct yt921x_priv *priv, int port)
 {
-	struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
+	u32 mask;
+	int res;
 
-	if (!priv)
-		return;
+	/* 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;
 
-	dsa_switch_shutdown(&priv->ds);
+	/* 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 yt921x_mdio_remove(struct mdio_device *mdiodev)
+static void
+yt922x_phylink_mac_link_down(struct phylink_config *config, unsigned int mode,
+			     phy_interface_t interface)
 {
-	struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+	struct yt921x_priv *priv = to_yt921x_priv(dp->ds);
+	int port = dp->index;
+	int res;
 
-	if (!priv)
-		return;
+	mutex_lock(&priv->reg_lock);
+	res = yt922x_port_down(priv, port);
+	mutex_unlock(&priv->reg_lock);
 
-	for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
-		struct yt921x_port *pp = &priv->ports[i];
+	if (res)
+		dev_err(dp->ds->dev, "Failed to %s port %d: %i\n", "bring down",
+			port, res);
+}
 
-		disable_delayed_work_sync(&pp->mib_read);
+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)
+{
+	u32 mask;
+	u32 ctrl;
+	int res;
+
+	switch (speed) {
+	case SPEED_10:
+		ctrl = YT921X_PORT_SPEED_10;
+		break;
+	case SPEED_100:
+		ctrl = YT921X_PORT_SPEED_100;
+		break;
+	case SPEED_1000:
+		ctrl = YT921X_PORT_SPEED_1000;
+		break;
+	case SPEED_2500:
+		ctrl = YT921X_PORT_SPEED_2500;
+		break;
+	case SPEED_5000:
+		ctrl = YT921X_PORT_SPEED_5000;
+		break;
+	case SPEED_10000:
+		ctrl = YT921X_PORT_SPEED_10000;
+		break;
+	default:
+		return -EINVAL;
 	}
+	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_LINK |
+		YT922X_PORT_CFG_RX_EN;
+	ctrl &= ~(YT922X_PORT_FC_AN | YT922X_PORT_LINK_AN);
+	res = yt921x_reg_write(priv, YT922X_PORTn_CTRL(port), ctrl);
+	if (res)
+		return res;
 
-	dsa_unregister_switch(&priv->ds);
+	/* force op */
+	mask = YT922X_PORT_FORCE_OP;
+	res = yt921x_reg_set_bits(priv, YT922X_PORTn_CTRL(port), mask);
+	if (res)
+		return res;
 
-	for (unsigned int i = 0; i < ARRAY_SIZE(priv->acl_blks); i++) {
-		struct yt921x_acl_blk *aclblk = priv->acl_blks[i];
+	/* 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;
 
-		if (!aclblk)
-			continue;
-		for (unsigned int j = 0; j < ARRAY_SIZE(aclblk->rules); j++) {
-			struct yt921x_acl_rule *aclrule = aclblk->rules[j];
+	return 0;
+}
 
-			if (!aclrule)
-				continue;
-			kvfree(aclrule);
-		}
-		kvfree(aclblk);
-	}
-	mutex_destroy(&priv->reg_lock);
+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 = 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 yt921x_mdio_probe(struct mdio_device *mdiodev)
+static int
+yt921x_intif_ext_write(struct yt921x_priv *priv, int port, int reg, u16 val)
 {
-	struct device *dev = &mdiodev->dev;
-	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)
-		return -ENOMEM;
+	if (port >= priv->series->max_ports)
+		return -ENODEV;
 
-	mdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);
-	if (!mdio)
-		return -ENOMEM;
+	res = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);
+	if (res)
+		return res;
 
-	mdio->bus = mdiodev->bus;
-	mdio->addr = mdiodev->addr;
-	mdio->switchid = 0;
+	res = yt921x_intif_write(priv, port, YT92XX_PAGE, val);
+	if (res)
+		return res;
 
-	mutex_init(&priv->reg_lock);
+	return 0;
+}
 
-	priv->reg_ops = &yt921x_reg_ops_mdio;
-	priv->reg_ctx = mdio;
+static int
+yt921x_intif_ext_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
+{
+	int res;
 
-	for (size_t i = 0; i < ARRAY_SIZE(priv->ports); i++) {
-		struct yt921x_port *pp = &priv->ports[i];
+	if (port >= priv->series->max_ports)
+		return -ENODEV;
 
-		pp->index = i;
-		INIT_DELAYED_WORK(&pp->mib_read, yt921x_poll_mib);
-	}
+	res = yt921x_intif_write(priv, port, YT92XX_PAGE_SELECT, reg);
+	if (res)
+		return res;
 
-	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 = yt921x_intif_read(priv, port, YT92XX_PAGE, valp);
+	if (res)
+		return res;
 
-	mdiodev_set_drvdata(mdiodev, priv);
+	return 0;
+}
 
-	return dsa_register_switch(ds);
+static int yt922x_sds_phyaddr_get(int port,
+				  enum yt922x_phy_reg_type reg_type,
+				  enum yt922x_phy_reg_space reg_space)
+{
+	int res = port;
+
+	/*
+	 * sds phyaddr mapping depend on reg_type and reg_space
+	 */
+	if (!yt922x_port_is_internal_sds(port))
+		return -EOPNOTSUPP;
+	if (reg_type == YT922X_PHY_REG_TYPE_COMMON_EXT) {
+		res = YT922X_COMMON_EXT_PHYADDR;
+		return res;
+	}
+
+	return res;
 }
 
-static const struct of_device_id yt921x_of_match[] = {
-	{ .compatible = "motorcomm,yt9215" },
-	{}
+/**
+ * Initialize serdes configuration based on interface mode.
+ */
+static int yt922x_sds_init(struct yt921x_priv *priv, int port,
+			   phy_interface_t interface)
+{
+	int addr;
+	u16 data;
+	int res;
+
+	addr = yt922x_sds_phyaddr_get
+		(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,
+		 YT922X_PHY_REG_SPACE_SGMII);
+	if (addr < 0)
+		return -EINVAL;
+	/* write protect */
+	res = yt921x_intif_ext_write(priv, addr, 0x4be, 0xd);
+	if (res)
+		return res;
+	/* CDR */
+	if (interface == PHY_INTERFACE_MODE_100BASEX) {
+		res = yt921x_intif_ext_write(priv, addr, 0x406, 0x0);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x416, 0x3458);
+		if (res)
+			return res;
+	} else {
+		res = yt921x_intif_ext_write(priv, addr, 0x406, 0x800);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x416, 0x4558);
+		if (res)
+			return res;
+	}
+	/* PLL */
+	if (interface == PHY_INTERFACE_MODE_USXGMII) {
+		res = yt921x_intif_ext_write(priv, addr, 0x43a, 0x1006);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43f, 0x3029);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x42a, 0xf070);
+		if (res)
+			return res;
+	} else {
+		res = yt921x_intif_ext_write(priv, addr, 0x43d, 0x207d);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43c, 0x207d);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43f, 0x3032);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x43a, 0x6);
+		if (res)
+			return res;
+		res = yt921x_intif_ext_write(priv, addr, 0x42a, 0xf070);
+		if (res)
+			return res;
+	}
+	/* VCO */
+	res = yt921x_intif_ext_write(priv, addr, 0x439, 0xC0);
+	if (res)
+		return res;
+	/* Vdac */
+	res = yt921x_intif_ext_write(priv, addr, 0x492, 0x7f7f);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x491, 0x7f);
+	if (res)
+		return res;
+	/* Eye */
+	res = yt921x_intif_ext_write(priv, addr, 0x454, 0xf14);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x497, 0xa44);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4cd, 0x0);
+	if (res)
+		return res;
+
+	res = yt921x_intif_ext_write(priv, addr, 0x4af, 0x45e3);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x48a, 0xfff);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x408, 0x7c00);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4d6, 0x7f);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x44f, 0xff08);
+	if (res)
+		return res;
+	/* FFE */
+	res = yt921x_intif_ext_write(priv, addr, 0x48e, 0x7d00);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0xd, 0x60f);
+	if (res)
+		return res;
+	/* CTLE */
+	res = yt921x_intif_ext_write(priv, addr, 0x4b0, 0x804);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4b1, 0x7774);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x4af, 0x45e7);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x3, 0x5603);
+	if (res)
+		return res;
+
+	msleep(20);
+	res = yt921x_intif_ext_write(priv, addr, 0x492, 0x7fff);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x492, 0x7f7f);
+	if (res)
+		return res;
+	/* CTLE */
+	res = yt921x_intif_ext_write(priv, addr, 0x2000, 0x40);
+	if (res)
+		return res;
+	res = yt921x_intif_ext_write(priv, addr, 0x2000, 0x0);
+	if (res)
+		return res;
+
+	if (interface == PHY_INTERFACE_MODE_SGMII) {
+		res = yt921x_intif_ext_write(priv, addr, 0x1042, 0x48c);
+		if (res)
+			return res;
+	}
+	/* soft reset */
+	addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII,
+				      YT922X_PHY_REG_SPACE_SGMII);
+	if (addr < 0)
+		return res;
+	res = yt921x_intif_read(priv, addr, 0x0, &data);
+	if (res)
+		return res;
+	data &= ~(1 << 15);
+	res = yt921x_intif_write(priv, addr, 0x0, data);
+	if (res)
+		return res;
+	addr = yt922x_sds_phyaddr_get(port, YT922X_PHY_REG_TYPE_MII,
+				      YT922X_PHY_REG_SPACE_USXGMII);
+	if (addr < 0)
+		return res;
+	res = yt921x_intif_read(priv, addr, 0x0, &data);
+	if (res)
+		return res;
+	data |= 1 << 15;
+	res = yt921x_intif_write(priv, addr, 0x0, data);
+	if (res)
+		return res;
+
+	return 0;
+}
+
+static void
+yt922x_phylink_mac_config(struct phylink_config *config, unsigned int mode,
+			  const struct phylink_link_state *state)
+{
+}
+
+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 = dp->ds->priv;
+	struct phylink_pcs *pcs = NULL;
+	int port = dp->index;
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_100BASEX:
+	case PHY_INTERFACE_MODE_2500BASEX:
+	case PHY_INTERFACE_MODE_USXGMII:
+		switch (port) {
+		case 0:
+			pcs = &priv->pcs_port_0.pcs;
+			break;
+
+		case 8:
+			pcs = &priv->pcs_port_8.pcs;
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return pcs;
+}
+
+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 struct yt922x_pcs *pcs_to_yt922x_pcs(struct phylink_pcs *pcs)
+{
+	return container_of(pcs, struct yt922x_pcs, pcs);
+}
+
+static void yt922x_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
+				 struct phylink_link_state *state)
+{
+	struct yt921x_priv *priv = pcs_to_yt922x_pcs(pcs)->priv;
+	int port = pcs_to_yt922x_pcs(pcs)->port;
+	u32 reg;
+	int res;
+
+	res = yt921x_reg_read(priv, YT922X_PORTn_STATUS(port), &reg);
+	if (res < 0) {
+		state->link = false;
+		return;
+	}
+
+	state->link = !!(reg & YT922X_PORT_LINK_STATE);
+	state->an_complete = state->link;
+	state->duplex = (reg & YT922X_PORT_LINK_DUPLEX) ? DUPLEX_FULL :
+							  DUPLEX_HALF;
+
+	switch (reg & YT922X_PORT_SPEED_M) {
+	case YT922X_PORT_SPEED_10:
+		state->speed = SPEED_10;
+		break;
+	case YT922X_PORT_SPEED_100:
+		state->speed = SPEED_100;
+		break;
+	case YT922X_PORT_SPEED_1000:
+		state->speed = SPEED_1000;
+		break;
+	case YT922X_PORT_SPEED_10000:
+		state->speed = SPEED_10000;
+		break;
+	case YT922X_PORT_SPEED_2500:
+		state->speed = SPEED_2500;
+		break;
+	case YT922X_PORT_SPEED_5000:
+		state->speed = SPEED_5000;
+		break;
+	default:
+		state->speed = SPEED_UNKNOWN;
+		break;
+	}
+}
+
+static void yt922x_pcs_an_restart(struct phylink_pcs *pcs)
+{
+}
+
+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)
+{
+	struct yt921x_priv *priv = pcs_to_yt922x_pcs(pcs)->priv;
+	int res, port;
+	u16 data;
+	u16 ctrl;
+	int addr;
+
+	port = pcs_to_yt922x_pcs(pcs)->port;
+	if (port != 0 && port != 8)
+		return -EINVAL;
+
+	/* SERDES init and interface configuration */
+	res = yt922x_sds_init(priv, port, interface);
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+		ctrl = YT92XX_SERDES_MODE_SGMII;
+		break;
+	case PHY_INTERFACE_MODE_100BASEX:
+		ctrl = YT92XX_SERDES_MODE_100BASEX;
+		break;
+	case PHY_INTERFACE_MODE_1000BASEX:
+		ctrl = YT92XX_SERDES_MODE_1000BASEX;
+		break;
+	case PHY_INTERFACE_MODE_2500BASEX:
+		ctrl = YT92XX_SERDES_MODE_2500BASEX;
+		break;
+	case PHY_INTERFACE_MODE_USXGMII:
+		ctrl = YT92XX_SERDES_MODE_USXGMII;
+		break;
+	default:
+		return -EINVAL;
+	}
+	addr = yt922x_sds_phyaddr_get
+		(port, YT922X_PHY_REG_TYPE_SDS_COMMON_EXT,
+		 YT922X_PHY_REG_SPACE_SGMII);
+	if (addr < 0)
+		return -EINVAL;
+
+	res = yt921x_intif_ext_read(priv, addr, YT922X_PORT_SDSn, &data);
+	if (res)
+		return res;
+	data &= ~YT922X_SERDES_MODE_M;
+	data |= ctrl;
+	res = yt921x_intif_ext_write(priv, addr, YT922X_PORT_SDSn, data);
+
+	return res;
+}
+
+static const struct phylink_pcs_ops yt922x_pcs_ops = {
+	.pcs_get_state = yt922x_pcs_get_state,
+	.pcs_config = yt922x_pcs_config,
+	.pcs_an_restart = yt922x_pcs_an_restart,
+};
+
+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 = 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)) {
+		if (port >= 4 && port <= 7) {
+			/* port 4 to port 7, internal utp */
+			__set_bit(PHY_INTERFACE_MODE_INTERNAL,
+				  config->supported_interfaces);
+			config->mac_capabilities |= MAC_2500FD;
+		} else {
+			__set_bit(PHY_INTERFACE_MODE_SGMII,
+				  config->supported_interfaces);
+			__set_bit(PHY_INTERFACE_MODE_100BASEX,
+				  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_2500FD;
+			config->mac_capabilities |= MAC_5000FD;
+			config->mac_capabilities |= MAC_10000FD;
+		}
+	} else {
+		/* external port will added later */
+	}
+}
+
+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 = 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_chip_detect(struct yt921x_priv *priv)
+{
+	struct device *dev = to_device(priv);
+	const struct yt921x_info *info;
+	u32 chipid;
+	u32 major;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
+	if (res)
+		return res;
+	major = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);
+	for (info = yt921x_infos; info->name; info++)
+		if (info->major == major)
+			break;
+	if (!info->name) {
+		dev_err(dev, "Unexpected chipid 0x%x\n", chipid);
+		return -ENODEV;
+	}
+	priv->info = info;
+
+	return 0;
+}
+
+static int yt922x_chip_reset(struct yt921x_priv *priv)
+{
+	struct device *dev = to_device(priv);
+	u16 eth_p_tag;
+	u32 val;
+	int res;
+
+	res = yt922x_chip_detect(priv);
+	if (res)
+		return res;
+
+	/* Reset */
+	res = yt921x_reg_write(priv, YT921X_RST, YT921X_RST_HW);
+	if (res)
+		return res;
+
+	fsleep(YT921X_RST_DELAY_US);
+
+	val = 0;
+	res = yt921x_reg_wait(priv, YT921X_RST, ~0, &val);
+	if (res)
+		return res;
+
+	/* TPID check */
+	res = yt921x_reg_read(priv, YT921X_CPU_TAG_TPID, &val);
+	if (res)
+		return res;
+	eth_p_tag = FIELD_GET(YT921X_CPU_TAG_TPID_TPID_M, val);
+	if (eth_p_tag != ETH_P_YT921X) {
+		dev_err(dev, "Tag type 0x%x != 0x%x\n", eth_p_tag,
+			ETH_P_YT921X);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int yt922x_chip_setup_dsa(struct yt921x_priv *priv)
+{
+	unsigned long cpu_ports_mask;
+	u32 ctrl;
+	int port;
+	int res;
+
+	ctrl = GENMASK(9, 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 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 void yt922x_setup_pcs(struct yt921x_priv *priv, struct yt922x_pcs *pcs,
+			     int port)
+{
+	pcs->pcs.ops = &yt922x_pcs_ops;
+
+	pcs->priv = priv;
+	pcs->port = port;
+}
+
+static int yt922x_dsa_setup(struct dsa_switch *ds)
+{
+	struct yt921x_priv *priv = to_yt921x_priv(ds);
+	struct device *dev = to_device(priv);
+	struct device_node *np = dev->of_node;
+	struct device_node *child;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt922x_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;
+	}
+
+	/* cpu port set */
+	mutex_lock(&priv->reg_lock);
+	res = yt922x_cpu_port_set(priv);
+	mutex_unlock(&priv->reg_lock);
+	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_setup_pcs(priv, &priv->pcs_port_0, 0);
+	yt922x_setup_pcs(priv, &priv->pcs_port_8, 8);
+
+	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] = {
+		.mode = 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] = {
+		.mode = 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)
+{
+	enum yt92xx_mode mode = YT92XX_MODE_MAX;
+	int i;
+
+	if (major == YT9215_MAJOR || major == YT9218_MAJOR)
+		mode = YT92XX_MODE_YT921X;
+	else if (major == YT9224_MAJOR)
+		mode = YT92XX_MODE_YT922X;
+	else
+		mode = YT92XX_MODE_MAX;
+
+	for (i = 0; i < ARRAY_SIZE(yt92xx_series_table); ++i)
+		if (yt92xx_series_table[i].mode == mode)
+			return &yt92xx_series_table[i];
+
+	return NULL;
+}
+
+static int yt92xx_register_switch(struct dsa_switch *ds)
+{
+	struct yt921x_priv *priv = to_yt921x_priv(ds);
+	const struct yt92xx_series *series;
+	u32 chipid;
+	u32 major;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_CHIP_ID, &chipid);
+	if (res)
+		return res;
+
+	major = FIELD_GET(YT921X_CHIP_ID_MAJOR, chipid);
+	series = yt92xx_series_lookup(major);
+	if (!series)
+		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);
+
+	if (!priv)
+		return;
+
+	dsa_switch_shutdown(&priv->ds);
+}
+
+static void yt921x_mdio_remove(struct mdio_device *mdiodev)
+{
+	struct yt921x_priv *priv = mdiodev_get_drvdata(mdiodev);
+
+	if (!priv)
+		return;
+
+	dsa_unregister_switch(&priv->ds);
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(priv->acl_blks); i++) {
+		struct yt921x_acl_blk *aclblk = priv->acl_blks[i];
+
+		if (!aclblk)
+			continue;
+		for (unsigned int j = 0; j < ARRAY_SIZE(aclblk->rules); j++) {
+			struct yt921x_acl_rule *aclrule = aclblk->rules[j];
+
+			if (!aclrule)
+				continue;
+			kvfree(aclrule);
+		}
+		kvfree(aclblk);
+	}
+	mutex_destroy(&priv->reg_lock);
+}
+
+static int yt921x_mdio_probe(struct mdio_device *mdiodev)
+{
+	struct device *dev = &mdiodev->dev;
+	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)
+		return -ENOMEM;
+
+	mdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);
+	if (!mdio)
+		return -ENOMEM;
+
+	mdio->bus = mdiodev->bus;
+	mdio->addr = mdiodev->addr;
+	mdio->switchid = 0;
+
+	mutex_init(&priv->reg_lock);
+
+	priv->reg_ops = &yt921x_reg_ops_mdio;
+	priv->reg_ctx = mdio;
+
+	ds = &priv->ds;
+	ds->dev = dev;
+	res = yt92xx_register_switch(ds);
+	if (res)
+		return res;
+
+	mdiodev_set_drvdata(mdiodev, priv);
+
+	return dsa_register_switch(ds);
+}
+
+static const struct of_device_id yt921x_of_match[] = {
+	{
+		.compatible = "motorcomm,yt9215",
+	},
+	{
+		.compatible = "motorcomm,yt9224",
+	},
+	{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, yt921x_of_match);
 
@@ -4788,5 +5697,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 83cd454955ddb..3b7ea3cbf5227 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -111,6 +111,7 @@
 #define   YT921X_PORT_SPEED_1000			YT921X_PORT_SPEED(2)
 #define   YT921X_PORT_SPEED_10000			YT921X_PORT_SPEED(3)
 #define   YT921X_PORT_SPEED_2500			YT921X_PORT_SPEED(4)
+#define   YT921X_PORT_SPEED_5000			YT921X_PORT_SPEED(5)
 #define YT921X_PON_STRAP_FUNC		0x80320
 #define YT921X_PON_STRAP_VAL		0x80324
 #define YT921X_PON_STRAP_CAP		0x80328
@@ -837,6 +838,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
@@ -861,6 +863,99 @@ enum yt921x_fdb_entry_status {
 #define yt921x_port_is_internal(port) ((port) < 8)
 #define yt921x_port_is_external(port) ((port) == 8 || (port) == 9)
 
+/* yt922x register lists */
+#define YT92XX_PAGE_SELECT	0x1e
+#define YT92XX_PAGE		0x1f
+#define YT922X_PORTn_STATUS(port)	(0x80200 + 4 * (port))
+#define  YT922X_PORT_LINK_STATE			BIT(8)
+#define  YT922X_PORT_LINK_DUPLEX		BIT(7)
+#define  YT922X_PORT_RX_FC_EN			BIT(6)
+#define  YT922X_PORT_TX_FC_EN			BIT(5)
+#define YT922X_PORT_SPEED_10		0
+#define YT922X_PORT_SPEED_100		1
+#define YT922X_PORT_SPEED_1000		2
+#define YT922X_PORT_SPEED_10000		3
+#define YT922X_PORT_SPEED_2500		4
+#define YT922X_PORT_SPEED_5000		5
+#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 YT92XX_SERDES_MODE_SGMII	YT922X_SERDES_MODE(0)
+#define YT92XX_SERDES_MODE_REVSGMII	YT921X_SERDES_MODE(1)
+#define YT92XX_SERDES_MODE_1000BASEX	YT921X_SERDES_MODE(2)
+#define YT92XX_SERDES_MODE_100BASEX	YT921X_SERDES_MODE(3)
+#define YT92XX_SERDES_MODE_2500BASEX	YT921X_SERDES_MODE(4)
+#define YT92XX_SERDES_MODE_USXGMII	YT922X_SERDES_MODE(6)
+#define YT922X_PORT_NUM		9
+
+/* LAG */
+#define YT922X_LAG_NUM		4
+/* ISO */
+#define YT922X_PORTn_ISOLATION(port)	(0x4 * (port) + 0x180d80)
+/* FDB */
+#define YT922X_PORTn_LEARN(port)	(0x180300 + 4 * (port))
+#define  YT922X_PORT_LEARN_DIS			BIT(18)
+/* GLOBAL CTRL */
+#define  YT922X_FUNC_ACL               BIT(5)
+#define  YT922X_FUNC_MIB               BIT(4)
+/* CTRL PKT */
+#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 */
+
+/* CPU PORT */
+#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 yt922x_port_is_internal_sds(port) ((port) == 0 || (port) == 8)
+
+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
+};
+
+enum yt922x_phy_reg_space {
+	YT922X_PHY_REG_SPACE_SGMII,
+	YT922X_PHY_REG_SPACE_USXGMII,
+	YT922X_PHY_REG_SPACE_MAX
+};
+
 struct yt921x_mib {
 	u64 rx_broadcast;
 	u64 rx_pause;
@@ -960,9 +1055,35 @@ struct yt921x_reg_ops {
 	int (*write)(void *context, u32 reg, u32 val);
 };
 
+enum yt92xx_mode {
+	YT92XX_MODE_YT921X,
+	YT92XX_MODE_YT922X,
+	YT92XX_MODE_MAX,
+};
+
+struct yt92xx_series {
+	enum yt92xx_mode mode;
+	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 yt922x_pcs {
+	struct phylink_pcs pcs;
+	struct yt921x_priv *priv;
+	int port;
+};
+
 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;
@@ -987,6 +1108,8 @@ struct yt921x_priv {
 
 	u8 acl_masks[YT921X_ACL_BLK_NUM];
 	struct yt921x_acl_blk *acl_blks[YT921X_ACL_BLK_NUM];
+	struct yt922x_pcs pcs_port_0;
+	struct yt922x_pcs pcs_port_8;
 };
 
 #endif
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 7507d632e7c6d..0807a595aaad0 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -61,6 +61,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_NETC_VALUE		33
 #define DSA_TAG_PROTO_KSZ8463_VALUE		34
 #define DSA_TAG_PROTO_MT7628_VALUE		35
+#define DSA_TAG_PROTO_YT922X_VALUE		36
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -99,6 +100,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NETC		= DSA_TAG_PROTO_NETC_VALUE,
 	DSA_TAG_PROTO_KSZ8463		= DSA_TAG_PROTO_KSZ8463_VALUE,
 	DSA_TAG_PROTO_MT7628		= DSA_TAG_PROTO_MT7628_VALUE,
+	DSA_TAG_PROTO_YT922X		= DSA_TAG_PROTO_YT922X_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 23b4b74004ed5..0b9f8a632cf22 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -227,4 +227,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 d15bcf5c68f02..0c53f4184bdbf 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -44,6 +44,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..1ee9d17735988
--- /dev/null
+++ b/net/dsa/tag_yt922x.c
@@ -0,0 +1,111 @@
+// 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:
+ */
+#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)
+#define YT922X_TAG_RX_PRIO_M	GENMASK(15, 13)
+
+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);
+

33/3 2026/09/08 09:00 llm kmsan-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 22040
							output: 34
							thoughts: 1730
						

Thoughts:
**Patch Analysis: Motorcomm YT922x Switch Support**

Alright, let's dive into this patch. My initial assessment is that it's adding support for Motorcomm YT922x series switches to the existing `yt921x` DSA driver.  Specifically, it's introducing a new `tag_yt922x.c` file and extending the existing driver.

First, I see the typical Kconfig and Makefile additions: `NET_DSA_TAG_YT922X`, making sure the build system knows about this new component. Then, looking at `chip.c`, the core of the driver, I see the expected extensions for the YT922x series. This includes refactoring port and series operations, adding PHY link MAC/PCS operations specific to YT922x, and handling port setup, chip setup, register access, resets, etc. The inclusion of `yt921x_intif_ext_read` and `yt921x_intif_ext_write` functions suggests they're reusing some of the existing internal interface functionality which is smart and saves a lot of time. The addition of a `yt92xx_register_switch` function is also as expected, for registering the new switch.

A quick skim of `include/net/dsa.h` shows the addition of `DSA_TAG_PROTO_YT922X_VALUE` and related enums, which is fundamental for the DSA tagging protocol.

Now, let's focus on the `tag_yt922x.c` file. This is the heart of the tag implementation. The `yt922x_tag_xmit` function looks straightforward; it pushes the 8-byte tag onto the SKB and sets all elements.  The code seems clean, explicitly assigning values to all 8 bytes. That's good, no chance of uninitialized memory making it onto the wire. Similarly, `yt922x_tag_rcv` handles the receive side, checking packet validity and stripping the header. The code is well-structured.

Now, the important part.  I'll start checking for potential vulnerabilities, particularly uninitialized memory reads or information leaks. I want to be certain there's no data being unintentionally exposed. Let's start with `yt921x_intif_ext_read` and its callers. The code is clear; `data` is only read into if the read operation is successful, making it safe. No concerns there. Similar to `yt922x_pcs_get_state`, the `state` struct, which is populated, is passed by phylink core so that's the expected standard.

Checking `tag_yt922x.c` again, I see the tx function is doing the right thing. All tag elements are properly written. No issues. I can also verify that data is read before write, which is good practice.

Checking memory allocations in `yt921x_mdio_probe`, the `priv` and `mdio` structs are allocated with `devm_kzalloc`, which means zeroed memory. Good.

I've also verified that there are no `copy_to_user`, netlink messages, ioctls, or socket options touched here, and no obvious uninitialized variables or struct fields, or any uninitialized padding. No information leaks are apparent.

As a final measure, I'll quickly check the existing `tag_yt921x.c` to see how it operates to compare the context. Overall, this patch looks very solid. It seems to have been carefully implemented, and I don't see any obvious vulnerabilities.



34/3 2026/09/08 09:01 tool grepper
0m Args:
{
  "Expression": "dsa_etype_header_pos_tx",
  "PathPrefix": "net/dsa"
}

Results:
{
  "Output": "net/dsa/tag.h=308=static inline void *dsa_etype_header_pos_rx(struct sk_buff *skb)\n--\nnet/dsa/tag.h-316- */\nnet/dsa/tag.h:317:static inline void *dsa_etype_header_pos_tx(struct sk_buff *skb)\nnet/dsa/tag.h-318-{\n--\nnet/dsa/tag_dsa.c=129=static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,\n--\nnet/dsa/tag_dsa.c-171-\t\t/* Construct tagged DSA tag from 802.1Q tag. */\nnet/dsa/tag_dsa.c:172:\t\tdsa_header = dsa_etype_header_pos_tx(skb) + extra;\nnet/dsa/tag_dsa.c-173-\t\tdsa_header[0] = (cmd \u003c\u003c 6) | 0x20 | tag_dev;\n--\nnet/dsa/tag_dsa.c-189-\t\t/* Construct DSA header from untagged frame. */\nnet/dsa/tag_dsa.c:190:\t\tdsa_header = dsa_etype_header_pos_tx(skb) + extra;\nnet/dsa/tag_dsa.c-191-\n--\nnet/dsa/tag_dsa.c=367=static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_dsa.c-374-\nnet/dsa/tag_dsa.c:375:\tedsa_header = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_dsa.c-376-\tedsa_header[0] = (ETH_P_EDSA \u003e\u003e 8) \u0026 0xff;\n--\nnet/dsa/tag_lan9303.c=57=static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_lan9303.c-68-\nnet/dsa/tag_lan9303.c:69:\tlan9303_tag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_lan9303.c-70-\n--\nnet/dsa/tag_mt7628.c=33=static struct sk_buff *mt7628_tag_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_mt7628.c-45-\nnet/dsa/tag_mt7628.c:46:\ttag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_mt7628.c-47-\n--\nnet/dsa/tag_mtk.c=23=static struct sk_buff *mtk_tag_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_mtk.c-50-\nnet/dsa/tag_mtk.c:51:\tmtk_tag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_mtk.c-52-\n--\nnet/dsa/tag_mxl-gsw1xx.c=43=static struct sk_buff *gsw1xx_tag_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_mxl-gsw1xx.c-55-\t/* special tag ingress */\nnet/dsa/tag_mxl-gsw1xx.c:56:\tgsw1xx_tag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_mxl-gsw1xx.c-57-\tgsw1xx_tag[0] = htons(ETH_P_MXLGSW);\n--\nnet/dsa/tag_mxl862xx.c=27=static struct sk_buff *mxl862_tag_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_mxl862xx.c-49-\t/* special tag ingress (from the perspective of the switch) */\nnet/dsa/tag_mxl862xx.c:50:\tmxl862_tag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_mxl862xx.c-51-\tmxl862_tag[0] = htons(ETH_P_MXLGSW);\n--\nnet/dsa/tag_netc.c=62=static void *netc_fill_common_tp_tag(struct sk_buff *skb,\n--\nnet/dsa/tag_netc.c-76-\nnet/dsa/tag_netc.c:77:\ttag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_netc.c-78-\tmemset(tag + NETC_TAG_CMN_LEN, 0, tag_len - NETC_TAG_CMN_LEN);\n--\nnet/dsa/tag_qca.c=15=static struct sk_buff *qca_tag_xmit(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_qca.c-22-\tdsa_alloc_etype_header(skb, QCA_HDR_LEN);\nnet/dsa/tag_qca.c:23:\tphdr = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_qca.c-24-\n--\nnet/dsa/tag_rtl4_a.c=35=static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_rtl4_a.c-51-\tdsa_alloc_etype_header(skb, RTL4_A_HDR_LEN);\nnet/dsa/tag_rtl4_a.c:52:\ttag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_rtl4_a.c-53-\n--\nnet/dsa/tag_rtl8_4.c=128=static struct sk_buff *rtl8_4_tag_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_rtl8_4.c-134-\nnet/dsa/tag_rtl8_4.c:135:\trtl8_4_write_tag(skb, dev, dsa_etype_header_pos_tx(skb));\nnet/dsa/tag_rtl8_4.c-136-\n--\nnet/dsa/tag_rzn1_a5psw.c=40=static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *dev)\n--\nnet/dsa/tag_rzn1_a5psw.c-59-\nnet/dsa/tag_rzn1_a5psw.c:60:\tptag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_rzn1_a5psw.c-61-\n--\nnet/dsa/tag_sja1105.c=294=static struct sk_buff *sja1110_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_sja1105.c-326-\nnet/dsa/tag_sja1105.c:327:\ttx_header = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_sja1105.c-328-\ttx_trailer = skb_put(skb, SJA1110_TX_TRAILER_LEN);\n--\nnet/dsa/tag_yt921x.c=60=yt921x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)\n--\nnet/dsa/tag_yt921x.c-67-\nnet/dsa/tag_yt921x.c:68:\ttag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_yt921x.c-69-\n--\nnet/dsa/tag_yt922x.c=30=yt922x_tag_xmit(struct sk_buff *skb, struct net_device *netdev)\n--\nnet/dsa/tag_yt922x.c-37-\tdsa_alloc_etype_header(skb, YT922X_TAG_LEN);\nnet/dsa/tag_yt922x.c:38:\ttag = dsa_etype_header_pos_tx(skb);\nnet/dsa/tag_yt922x.c-39-\n"
}

35/3 2026/09/08 09:01 llm kmsan-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 26920
							output: 297
							thoughts: 215
						

Thoughts:
**Assessment of the YT922x Switch Driver Patch**

Okay, let's see, I need to make a judgment here. Everything seems remarkably clean, which is a good starting point. I see the patch is adding support for a new hardware model, the Motorcomm YT922x, by sensibly extending the existing DSA driver. They're adding a tag handler for the YT922x frames. That's a reasonable architectural choice, nothing immediately alarming there.

I'm noting the use of `devm_kzalloc` for device structure allocation, which is standard and ensures proper memory management. Delayed work initialization via `INIT_DELAYED_WORK` is also as expected in this context. Excellent, I'm seeing that register access values are being properly assigned or validated for errors before being read. That's a critical detail for hardware drivers, and the fact that the transmit tag buffer is being fully written before transmission is very important.

Crucially, there are no user-space copy paths added or modified. No `copy_to_user`, `put_user`, netlink, or ioctls, that's definitely a point in its favor. And the lack of conditional branching on uninitialized memory is also a positive sign, preventing a common class of errors. The KASAN, LOCKDEP, and UB-sanitizers should be sufficient to catch any memory safety issues. Given all this, it does indeed seem like there's no need for KMSAN to be enabled in this specific case. So, NeedsKMSAN is definitely `false`.

Now, let's get ready to call that tool to set the results.



36/3 2026/09/08 09:01 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch introduces support for Motorcomm YT922x switches to the existing YT921x DSA driver and adds a new DSA tag driver (`tag_yt922x.c`).\n\nAnalysis of uninitialized memory risk:\n1. All private device structures are allocated using `devm_kzalloc()`, ensuring all fields are zero-initialized.\n2. In `yt922x_tag_xmit()`, the 8-byte tag inserted into outgoing packets is completely populated (`tag[0]`, `tag[1]`, `tag[2]`, `tag[3]` are all explicitly assigned), leaving no uninitialized padding or bytes.\n3. In `yt922x_tag_rcv()`, the packet length is validated using `pskb_may_pull()` before parsing header fields.\n4. Internal register read functions check return values before using output variables.\n5. No new user-space copies (`copy_to_user`, `put_user`, socket options, or netlink attributes) are introduced or modified.\n\nAny potential memory issues (e.g. out-of-bounds access or race conditions) are within the scope of KASAN/LOCKDEP. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch introduces support for Motorcomm YT922x switches to the existing YT921x DSA driver and adds a new DSA tag driver (`tag_yt922x.c`).\n\nAnalysis of uninitialized memory risk:\n1. All private device structures are allocated using `devm_kzalloc()`, ensuring all fields are zero-initialized.\n2. In `yt922x_tag_xmit()`, the 8-byte tag inserted into outgoing packets is completely populated (`tag[0]`, `tag[1]`, `tag[2]`, `tag[3]` are all explicitly assigned), leaving no uninitialized padding or bytes.\n3. In `yt922x_tag_rcv()`, the packet length is validated using `pskb_may_pull()` before parsing header fields.\n4. Internal register read functions check return values before using output variables.\n5. No new user-space copies (`copy_to_user`, `put_user`, socket options, or netlink attributes) are introduced or modified.\n\nAny potential memory issues (e.g. out-of-bounds access or race conditions) are within the scope of KASAN/LOCKDEP. Therefore, a dedicated KMSAN fuzzing session is not warranted.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)