AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/19 23:04 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch modifies the Motorcomm YT921x (YT9215) ethernet switch DSA driver in drivers/net/dsa/motorcomm/. This driver controls a physical Ethernet switch ASIC connected via MDIO and configured via Device Tree (OF compatible \"motorcomm,yt9215\"). The hardware is not emulated in standard QEMU/GCE virtual machines on amd64, and cannot be instantiated through virtual interfaces or virtual buses. Therefore, the modified code is structurally unreachable for fuzzing.",
  "WorthFuzzing": false
}

1/1 2026/09/19 23:04 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit f604800e94cd31bc31226bda2c9fd576630992cf\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Sep 19 23:04:29 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile\nindex aeb12cb91f935..1d2c1b3064c41 100644\n--- a/drivers/net/dsa/motorcomm/Makefile\n+++ b/drivers/net/dsa/motorcomm/Makefile\n@@ -2,4 +2,6 @@\n obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o\n yt921x-objs := chip.o\n yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o\n+yt921x-objs += mdio_bus.o\n+yt921x-objs += pcs-921x.o\n yt921x-objs += smi.o\ndiff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c\nindex d663af010f431..530bea77ac70a 100644\n--- a/drivers/net/dsa/motorcomm/chip.c\n+++ b/drivers/net/dsa/motorcomm/chip.c\n@@ -27,6 +27,8 @@\n \n #include \"chip.h\"\n #include \"leds.h\"\n+#include \"mdio_bus.h\"\n+#include \"pcs.h\"\n #include \"smi.h\"\n \n struct yt921x_mib_desc {\n@@ -96,58 +98,48 @@ static const struct yt921x_mib_desc yt921x_mib_descs[] = {\n \tMIB_DESC(1, YT921X_MIB_DATA_TX_OAM, \"TxOAM\"),\n };\n \n-struct yt921x_info {\n-\tconst char *name;\n-\tu16 major;\n-\t/* Unknown, seems to be plain enumeration */\n-\tu8 mode;\n-\tu8 extmode;\n-\t/* Ports with integral GbE PHYs, not including MCU Port 10 */\n-\tu16 internal_mask;\n-\t/* TODO: see comments in yt921x_dsa_phylink_get_caps() */\n-\tu16 external_mask;\n-};\n-\n-#define YT921X_PORT_MASK_INTn(port)\tBIT(port)\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-\n static const struct yt921x_info yt921x_infos[] = {\n \t{\n \t\t\"YT9215SC\", YT9215_MAJOR, 1, 0,\n-\t\tYT921X_PORT_MASK_INT0_n(5),\n-\t\tYT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,\n+\t\tGENMASK(4, 0),\n+\t\tBIT(9),\n+\t\tBIT(8) | BIT(9),\n \t},\n \t{\n \t\t\"YT9215S\", YT9215_MAJOR, 2, 0,\n-\t\tYT921X_PORT_MASK_INT0_n(5),\n-\t\tYT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,\n+\t\tGENMASK(4, 0),\n+\t\tBIT(9),\n+\t\tBIT(8),\n \t},\n \t{\n \t\t\"YT9215RB\", YT9215_MAJOR, 3, 0,\n-\t\tYT921X_PORT_MASK_INT0_n(5),\n-\t\tYT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,\n+\t\tGENMASK(4, 0),\n+\t\tBIT(8) | BIT(9),\n+\t\t0,\n \t},\n \t{\n \t\t\"YT9214NB\", YT9215_MAJOR, 3, 2,\n-\t\tYT921X_PORT_MASK_INTn(1) | YT921X_PORT_MASK_INTn(3),\n-\t\tYT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,\n+\t\tBIT(1) | BIT(3),\n+\t\tBIT(9),\n+\t\tBIT(8),\n \t},\n \t{\n \t\t\"YT9213NB\", YT9215_MAJOR, 3, 3,\n-\t\tYT921X_PORT_MASK_INTn(1) | YT921X_PORT_MASK_INTn(3),\n-\t\tYT921X_PORT_MASK_EXT1,\n+\t\tBIT(1) | BIT(3),\n+\t\tBIT(9),\n+\t\tBIT(9),\n \t},\n \t{\n \t\t\"YT9218N\", YT9218_MAJOR, 0, 0,\n-\t\tYT921X_PORT_MASK_INT0_n(8),\n+\t\tGENMASK(7, 0),\n+\t\t0,\n \t\t0,\n \t},\n \t{\n \t\t\"YT9218MB\", YT9218_MAJOR, 1, 0,\n-\t\tYT921X_PORT_MASK_INT0_n(8),\n-\t\tYT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,\n+\t\tGENMASK(7, 0),\n+\t\tBIT(8) | BIT(9),\n+\t\tBIT(8) | BIT(9),\n \t},\n \t{}\n };\n@@ -276,274 +268,6 @@ static const struct yt921x_reg_ops yt921x_reg_ops_mdio = {\n \n /* TODO: SPI/I2C */\n \n-static int yt921x_intif_wait(struct yt921x_priv *priv)\n-{\n-\tu32 val = 0;\n-\n-\treturn yt921x_reg_wait(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START,\n-\t\t\t       \u0026val);\n-}\n-\n-static int\n-yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\n-{\n-\tstruct device *dev = to_device(priv);\n-\tu32 mask;\n-\tu32 ctrl;\n-\tu32 val;\n-\tint res;\n-\n-\tres = yt921x_intif_wait(priv);\n-\tif (res)\n-\t\treturn res;\n-\n-\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n-\t       YT921X_MBUS_CTRL_OP_M;\n-\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n-\t       YT921X_MBUS_CTRL_READ;\n-\tres = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);\n-\tif (res)\n-\t\treturn res;\n-\n-\tres = yt921x_intif_wait(priv);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_read(priv, YT921X_INT_MBUS_DIN, \u0026val);\n-\tif (res)\n-\t\treturn res;\n-\n-\tif ((u16)val != val)\n-\t\tdev_info(dev,\n-\t\t\t \"%s: port %d, reg 0x%x: Expected u16, got 0x%08x\\n\",\n-\t\t\t __func__, port, reg, val);\n-\t*valp = (u16)val;\n-\treturn 0;\n-}\n-\n-static int\n-yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val)\n-{\n-\tu32 mask;\n-\tu32 ctrl;\n-\tint res;\n-\n-\tres = yt921x_intif_wait(priv);\n-\tif (res)\n-\t\treturn res;\n-\n-\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n-\t       YT921X_MBUS_CTRL_OP_M;\n-\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n-\t       YT921X_MBUS_CTRL_WRITE;\n-\tres = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_DOUT, val);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);\n-\tif (res)\n-\t\treturn res;\n-\n-\treturn yt921x_intif_wait(priv);\n-}\n-\n-static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)\n-{\n-\tstruct yt921x_priv *priv = mbus-\u003epriv;\n-\tu16 val;\n-\tint res;\n-\n-\tif (port \u003e= YT921X_PORT_NUM)\n-\t\treturn U16_MAX;\n-\n-\tmutex_lock(\u0026priv-\u003ereg_lock);\n-\tres = yt921x_intif_read(priv, port, reg, \u0026val);\n-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n-\n-\tif (res)\n-\t\treturn res;\n-\treturn val;\n-}\n-\n-static int\n-yt921x_mbus_int_write(struct mii_bus *mbus, int port, int reg, u16 data)\n-{\n-\tstruct yt921x_priv *priv = mbus-\u003epriv;\n-\tint res;\n-\n-\tif (port \u003e= YT921X_PORT_NUM)\n-\t\treturn -ENODEV;\n-\n-\tmutex_lock(\u0026priv-\u003ereg_lock);\n-\tres = yt921x_intif_write(priv, port, reg, data);\n-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n-\n-\treturn res;\n-}\n-\n-static int\n-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-\tint res;\n-\n-\tmbus = devm_mdiobus_alloc(dev);\n-\tif (!mbus)\n-\t\treturn -ENOMEM;\n-\n-\tmbus-\u003ename = \"YT921x internal MDIO bus\";\n-\tsnprintf(mbus-\u003eid, MII_BUS_ID_SIZE, \"%s\", dev_name(dev));\n-\tmbus-\u003epriv = priv;\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-\n-\tres = devm_of_mdiobus_register(dev, mbus, mnp);\n-\tif (res)\n-\t\treturn res;\n-\n-\tpriv-\u003embus_int = mbus;\n-\n-\treturn 0;\n-}\n-\n-static int yt921x_extif_wait(struct yt921x_priv *priv)\n-{\n-\tu32 val = 0;\n-\n-\treturn yt921x_reg_wait(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START,\n-\t\t\t       \u0026val);\n-}\n-\n-static int\n-yt921x_extif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\n-{\n-\tstruct device *dev = to_device(priv);\n-\tu32 mask;\n-\tu32 ctrl;\n-\tu32 val;\n-\tint res;\n-\n-\tres = yt921x_extif_wait(priv);\n-\tif (res)\n-\t\treturn res;\n-\n-\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n-\t       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;\n-\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n-\t       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_READ;\n-\tres = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);\n-\tif (res)\n-\t\treturn res;\n-\n-\tres = yt921x_extif_wait(priv);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_read(priv, YT921X_EXT_MBUS_DIN, \u0026val);\n-\tif (res)\n-\t\treturn res;\n-\n-\tif ((u16)val != val)\n-\t\tdev_info(dev,\n-\t\t\t \"%s: port %d, reg 0x%x: Expected u16, got 0x%08x\\n\",\n-\t\t\t __func__, port, reg, val);\n-\t*valp = (u16)val;\n-\treturn 0;\n-}\n-\n-static int\n-yt921x_extif_write(struct yt921x_priv *priv, int port, int reg, u16 val)\n-{\n-\tu32 mask;\n-\tu32 ctrl;\n-\tint res;\n-\n-\tres = yt921x_extif_wait(priv);\n-\tif (res)\n-\t\treturn res;\n-\n-\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n-\t       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;\n-\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n-\t       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_WRITE;\n-\tres = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_DOUT, val);\n-\tif (res)\n-\t\treturn res;\n-\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);\n-\tif (res)\n-\t\treturn res;\n-\n-\treturn yt921x_extif_wait(priv);\n-}\n-\n-static int yt921x_mbus_ext_read(struct mii_bus *mbus, int port, int reg)\n-{\n-\tstruct yt921x_priv *priv = mbus-\u003epriv;\n-\tu16 val;\n-\tint res;\n-\n-\tmutex_lock(\u0026priv-\u003ereg_lock);\n-\tres = yt921x_extif_read(priv, port, reg, \u0026val);\n-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n-\n-\tif (res)\n-\t\treturn res;\n-\treturn val;\n-}\n-\n-static int\n-yt921x_mbus_ext_write(struct mii_bus *mbus, int port, int reg, u16 data)\n-{\n-\tstruct yt921x_priv *priv = mbus-\u003epriv;\n-\tint res;\n-\n-\tmutex_lock(\u0026priv-\u003ereg_lock);\n-\tres = yt921x_extif_write(priv, port, reg, data);\n-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n-\n-\treturn res;\n-}\n-\n-static int\n-yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)\n-{\n-\tstruct device *dev = to_device(priv);\n-\tstruct mii_bus *mbus;\n-\tint res;\n-\n-\tmbus = devm_mdiobus_alloc(dev);\n-\tif (!mbus)\n-\t\treturn -ENOMEM;\n-\n-\tmbus-\u003ename = \"YT921x external MDIO bus\";\n-\tsnprintf(mbus-\u003eid, MII_BUS_ID_SIZE, \"%s@ext\", dev_name(dev));\n-\tmbus-\u003epriv = priv;\n-\t/* TODO: c45? */\n-\tmbus-\u003eread = yt921x_mbus_ext_read;\n-\tmbus-\u003ewrite = yt921x_mbus_ext_write;\n-\tmbus-\u003eparent = dev;\n-\n-\tres = devm_of_mdiobus_register(dev, mbus, mnp);\n-\tif (res)\n-\t\treturn res;\n-\n-\tpriv-\u003embus_ext = mbus;\n-\n-\treturn 0;\n-}\n-\n /* Read and handle overflow of 32bit MIBs. MIB buffer must be zeroed before. */\n static int yt921x_read_mib(struct yt921x_priv *priv, int port)\n {\n@@ -608,9 +332,8 @@ static void yt921x_poll_mib(struct work_struct *work)\n {\n \tstruct yt921x_port *pp = container_of_const(work, struct yt921x_port,\n \t\t\t\t\t\t    mib_read.work);\n-\tstruct yt921x_priv *priv = (void *)(pp - pp-\u003eindex) -\n-\t\t\t\t   offsetof(struct yt921x_priv, ports);\n \tunsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \tint port = pp-\u003eindex;\n \tint res;\n \n@@ -3748,20 +3471,23 @@ yt921x_dsa_port_set_apptrust(struct dsa_switch *ds, int port, const u8 *sel,\n \n static int yt921x_port_down(struct yt921x_priv *priv, int port)\n {\n+\tconst struct yt921x_info *info = priv-\u003einfo;\n \tu32 mask;\n \tint res;\n \n-\tmask = YT921X_PORT_LINK | YT921X_PORT_RX_MAC_EN | YT921X_PORT_TX_MAC_EN;\n+\tmask = YT921X_PORT_CTRL_LINK_AN | YT921X_PORT_RX_MAC_EN |\n+\t       YT921X_PORT_TX_MAC_EN;\n \tres = yt921x_reg_clear_bits(priv, YT921X_PORTn_CTRL(port), mask);\n \tif (res)\n \t\treturn res;\n \n-\tif (yt921x_port_is_external(port)) {\n+\tif (BIT(port) \u0026 info-\u003eserdes_mask) {\n \t\tmask = YT921X_SERDES_LINK;\n \t\tres = yt921x_reg_clear_bits(priv, YT921X_SERDESn(port), mask);\n \t\tif (res)\n \t\t\treturn res;\n-\n+\t}\n+\tif (BIT(port) \u0026 info-\u003exmii_mask) {\n \t\tmask = YT921X_XMII_LINK;\n \t\tres = yt921x_reg_clear_bits(priv, YT921X_XMIIn(port), mask);\n \t\tif (res)\n@@ -3776,29 +3502,21 @@ yt921x_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+\tconst struct yt921x_info *info = priv-\u003einfo;\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tint ps = ethtool_speed_to_yt921x(speed);\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_10000:\n-\t\tctrl = YT921X_PORT_SPEED_10000;\n-\t\tbreak;\n-\tdefault:\n+\tif (ps == YT921X_SPEED_NUM)\n \t\treturn -EINVAL;\n-\t}\n+\n+\tmask = YT921X_PORT_SPEED_M | YT921X_PORT_TX_MAC_EN |\n+\t       YT921X_PORT_RX_MAC_EN | YT921X_PORT_TX_PAUSE |\n+\t       YT921X_PORT_RX_PAUSE | YT921X_PORT_DUPLEX_FULL |\n+\t       YT921X_PORT_CTRL_LINK_AN;\n+\tctrl = YT921X_PORT_SPEED(ps);\n \tif (duplex == DUPLEX_FULL)\n \t\tctrl |= YT921X_PORT_DUPLEX_FULL;\n \tif (tx_pause)\n@@ -3806,31 +3524,18 @@ yt921x_port_up(struct yt921x_priv *priv, int port, unsigned int mode,\n \tif (rx_pause)\n \t\tctrl |= YT921X_PORT_RX_PAUSE;\n \tctrl |= YT921X_PORT_RX_MAC_EN | YT921X_PORT_TX_MAC_EN;\n-\tres = yt921x_reg_write(priv, YT921X_PORTn_CTRL(port), ctrl);\n+\tif (pp-\u003eserdes \u0026\u0026 pp-\u003einband)\n+\t\tctrl |= YT921X_PORT_CTRL_LINK_AN;\n+\tres = yt921x_reg_update_bits(priv, YT921X_PORTn_CTRL(port), mask, ctrl);\n \tif (res)\n \t\treturn res;\n \n-\tif (yt921x_port_is_external(port)) {\n+\tif (!(BIT(port) \u0026 (info-\u003eserdes_mask | info-\u003exmii_mask)))\n+\t\treturn 0;\n+\n+\tif (pp-\u003eserdes) {\n \t\tmask = YT921X_SERDES_SPEED_M;\n-\t\tswitch (speed) {\n-\t\tcase SPEED_10:\n-\t\t\tctrl = YT921X_SERDES_SPEED_10;\n-\t\t\tbreak;\n-\t\tcase SPEED_100:\n-\t\t\tctrl = YT921X_SERDES_SPEED_100;\n-\t\t\tbreak;\n-\t\tcase SPEED_1000:\n-\t\t\tctrl = YT921X_SERDES_SPEED_1000;\n-\t\t\tbreak;\n-\t\tcase SPEED_2500:\n-\t\t\tctrl = YT921X_SERDES_SPEED_2500;\n-\t\t\tbreak;\n-\t\tcase SPEED_10000:\n-\t\t\tctrl = YT921X_SERDES_SPEED_10000;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn -EINVAL;\n-\t\t}\n+\t\tctrl = YT921X_SERDES_SPEED(ps);\n \t\tmask |= YT921X_SERDES_DUPLEX_FULL;\n \t\tif (duplex == DUPLEX_FULL)\n \t\t\tctrl |= YT921X_SERDES_DUPLEX_FULL;\n@@ -3841,36 +3546,19 @@ yt921x_port_up(struct yt921x_priv *priv, int port, unsigned int mode,\n \t\tif (rx_pause)\n \t\t\tctrl |= YT921X_SERDES_RX_PAUSE;\n \t\tmask |= YT921X_SERDES_LINK;\n-\t\tctrl |= YT921X_SERDES_LINK;\n+\t\tif (!pp-\u003einband)\n+\t\t\tctrl |= YT921X_SERDES_LINK;\n \t\tres = yt921x_reg_update_bits(priv, YT921X_SERDESn(port),\n \t\t\t\t\t     mask, ctrl);\n \t\tif (res)\n \t\t\treturn res;\n-\n+\t} else {\n \t\tmask = YT921X_XMII_LINK;\n \t\tres = yt921x_reg_set_bits(priv, YT921X_XMIIn(port), mask);\n \t\tif (res)\n \t\t\treturn res;\n \n-\t\tswitch (speed) {\n-\t\tcase SPEED_10:\n-\t\t\tctrl = YT921X_MDIO_POLLING_SPEED_10;\n-\t\t\tbreak;\n-\t\tcase SPEED_100:\n-\t\t\tctrl = YT921X_MDIO_POLLING_SPEED_100;\n-\t\t\tbreak;\n-\t\tcase SPEED_1000:\n-\t\t\tctrl = YT921X_MDIO_POLLING_SPEED_1000;\n-\t\t\tbreak;\n-\t\tcase SPEED_2500:\n-\t\t\tctrl = YT921X_MDIO_POLLING_SPEED_2500;\n-\t\t\tbreak;\n-\t\tcase SPEED_10000:\n-\t\t\tctrl = YT921X_MDIO_POLLING_SPEED_10000;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn -EINVAL;\n-\t\t}\n+\t\tctrl = YT921X_MDIO_POLLING_SPEED(ps);\n \t\tif (duplex == DUPLEX_FULL)\n \t\t\tctrl |= YT921X_MDIO_POLLING_DUPLEX_FULL;\n \t\tctrl |= YT921X_MDIO_POLLING_LINK;\n@@ -3886,17 +3574,15 @@ static int\n yt921x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,\n \t\t   phy_interface_t interface)\n {\n+\tconst struct yt921x_info *info = priv-\u003einfo;\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n \tstruct device *dev = to_device(priv);\n \tu32 mask;\n-\tu32 ctrl;\n \tint res;\n \n-\tif (!yt921x_port_is_external(port)) {\n-\t\tif (interface != PHY_INTERFACE_MODE_INTERNAL) {\n-\t\t\tdev_err(dev, \"Wrong mode %d on port %d\\n\",\n-\t\t\t\tinterface, port);\n-\t\t\treturn -EINVAL;\n-\t\t}\n+\tif (BIT(port) \u0026 info-\u003einternal_mask) {\n+\t\tif (interface != PHY_INTERFACE_MODE_INTERNAL)\n+\t\t\tgoto err;\n \t\treturn 0;\n \t}\n \n@@ -3906,6 +3592,9 @@ yt921x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,\n \tcase PHY_INTERFACE_MODE_100BASEX:\n \tcase PHY_INTERFACE_MODE_1000BASEX:\n \tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\tif (!(BIT(port) \u0026 info-\u003eserdes_mask))\n+\t\t\tgoto err;\n+\n \t\tmask = YT921X_SERDES_CTRL_PORTn(port);\n \t\tres = yt921x_reg_set_bits(priv, YT921X_SERDES_CTRL, mask);\n \t\tif (res)\n@@ -3916,35 +3605,44 @@ yt921x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,\n \t\tif (res)\n \t\t\treturn res;\n \n-\t\tmask = YT921X_SERDES_MODE_M;\n-\t\tswitch (interface) {\n-\t\tcase PHY_INTERFACE_MODE_SGMII:\n-\t\t\tctrl = YT921X_SERDES_MODE_SGMII;\n-\t\t\tbreak;\n-\t\tcase PHY_INTERFACE_MODE_100BASEX:\n-\t\t\tctrl = YT921X_SERDES_MODE_100BASEX;\n-\t\t\tbreak;\n-\t\tcase PHY_INTERFACE_MODE_1000BASEX:\n-\t\t\tctrl = YT921X_SERDES_MODE_1000BASEX;\n-\t\t\tbreak;\n-\t\tcase PHY_INTERFACE_MODE_2500BASEX:\n-\t\t\tctrl = YT921X_SERDES_MODE_2500BASEX;\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\treturn -EINVAL;\n-\t\t}\n-\t\tres = yt921x_reg_update_bits(priv, YT921X_SERDESn(port),\n-\t\t\t\t\t     mask, ctrl);\n-\t\tif (res)\n-\t\t\treturn res;\n-\n+\t\t/* The order is quite arbitrary - we can't return to a safe\n+\t\t * state on IO errors.\n+\t\t */\n+\t\tpp-\u003eserdes = true;\n \t\tbreak;\n \t/* add XMII support here */\n \tdefault:\n-\t\treturn -EINVAL;\n+\t\tgoto err;\n \t}\n \n \treturn 0;\n+\n+err:\n+\tdev_err(dev, \"Wrong mode %d on port %d\\n\", interface, port);\n+\treturn -EINVAL;\n+}\n+\n+static struct phylink_pcs *\n+yt921x_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 = to_yt921x_priv(dp-\u003eds);\n+\tconst struct yt921x_info *info = priv-\u003einfo;\n+\tint port = dp-\u003eindex;\n+\n+\tif (!(BIT(port) \u0026 info-\u003eserdes_mask))\n+\t\treturn NULL;\n+\n+\tswitch (interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\treturn \u0026priv-\u003eports[port].pcs;\n+\tdefault:\n+\t\treturn NULL;\n+\t}\n }\n \n static void\n@@ -4026,15 +3724,10 @@ yt921x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,\n \t\t */\n \t\t__set_bit(PHY_INTERFACE_MODE_INTERNAL,\n \t\t\t  config-\u003esupported_interfaces);\n-\t} else if (info-\u003eexternal_mask \u0026 BIT(port)) {\n-\t\t/* TODO: external ports may support SERDES only, XMII only, or\n-\t\t * SERDES + XMII depending on the chip. However, we can't get\n-\t\t * the accurate config table due to lack of document, thus\n-\t\t * we simply declare SERDES + XMII and rely on the correctness\n-\t\t * of devicetree for now.\n-\t\t */\n+\t\treturn;\n+\t}\n \n-\t\t/* SERDES */\n+\tif (BIT(port) \u0026 info-\u003eserdes_mask) {\n \t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n \t\t\t  config-\u003esupported_interfaces);\n \t\t/* REVSGMII (SGMII in PHY role) should go here, once\n@@ -4047,9 +3740,8 @@ yt921x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,\n \t\t__set_bit(PHY_INTERFACE_MODE_2500BASEX,\n \t\t\t  config-\u003esupported_interfaces);\n \t\tconfig-\u003emac_capabilities |= MAC_2500FD;\n-\n-\t\t/* XMII */\n-\n+\t}\n+\tif (BIT(port) \u0026 info-\u003exmii_mask) {\n \t\t/* Not tested. To add support for XMII:\n \t\t *   - Add proper interface modes below\n \t\t *   - Handle them in yt921x_port_config()\n@@ -4540,6 +4232,11 @@ static int yt921x_chip_setup(struct yt921x_priv *priv)\n \tif (res)\n \t\treturn res;\n \n+\tres = yt921x_reg_clear_bits(priv, YT921X_SERDES_CTRL,\n+\t\t\t\t    YT921X_SERDES_CTRL_TEST);\n+\tif (res)\n+\t\treturn res;\n+\n \treturn 0;\n }\n \n@@ -4549,6 +4246,8 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)\n \tstruct device *dev = to_device(priv);\n \tstruct device_node *np = dev-\u003eof_node;\n \tstruct device_node *child;\n+\tunsigned long mask;\n+\tint port;\n \tint res;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\n@@ -4582,6 +4281,23 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)\n \t\treturn -ENODEV;\n \t}\n \n+\tmask = priv-\u003einfo-\u003eserdes_mask;\n+\tfor_each_set_bit(port, \u0026mask, YT921X_PORT_NUM) {\n+\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\n+\t\tpp-\u003epcs.ops = \u0026yt921x_phylink_pcs_ops;\n+\t\tpp-\u003epcs.poll = true;\n+\n+\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n+\t\t\t  pp-\u003epcs.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_100BASEX,\n+\t\t\t  pp-\u003epcs.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n+\t\t\t  pp-\u003epcs.supported_interfaces);\n+\t\t__set_bit(PHY_INTERFACE_MODE_2500BASEX,\n+\t\t\t  pp-\u003epcs.supported_interfaces);\n+\t}\n+\n \tmutex_lock(\u0026priv-\u003ereg_lock);\n \tres = yt921x_chip_setup(priv);\n \tmutex_unlock(\u0026priv-\u003ereg_lock);\n@@ -4599,6 +4315,7 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)\n }\n \n static const struct phylink_mac_ops yt921x_phylink_mac_ops = {\n+\t.mac_select_pcs\t= yt921x_phylink_mac_select_pcs,\n \t.mac_link_down\t= yt921x_phylink_mac_link_down,\n \t.mac_link_up\t= yt921x_phylink_mac_link_up,\n \t.mac_config\t= yt921x_phylink_mac_config,\ndiff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h\nindex 83cd454955ddb..0cbb54834ffff 100644\n--- a/drivers/net/dsa/motorcomm/chip.h\n+++ b/drivers/net/dsa/motorcomm/chip.h\n@@ -42,7 +42,7 @@\n #define YT921X_PVID_SEL\t\t\t0x80014\n #define  YT921X_PVID_SEL_SVID_PORTn(port)\tBIT(port)\n #define YT921X_SERDES_CTRL\t\t0x80028\n-#define  YT921X_SERDES_CTRL_PORTn_TEST(port)\tBIT((port) - 3)\n+#define  YT921X_SERDES_CTRL_TEST\t\tBIT(6)\n #define  YT921X_SERDES_CTRL_PORTn(port)\t\tBIT((port) - 8)\n #define YT921X_IO_LEVEL\t\t\t0x80030\n #define  YT9215_IO_LEVEL_NORMAL_M\t\tGENMASK(5, 4)\n@@ -89,16 +89,12 @@\n #define  YT921X_SERDES_DUPLEX_FULL\t\tBIT(3)\n #define  YT921X_SERDES_SPEED_M\t\t\tGENMASK(2, 0)\n #define   YT921X_SERDES_SPEED(x)\t\t\tFIELD_PREP(YT921X_SERDES_SPEED_M, (x))\n-#define   YT921X_SERDES_SPEED_10\t\t\tYT921X_SERDES_SPEED(0)\n-#define   YT921X_SERDES_SPEED_100\t\t\tYT921X_SERDES_SPEED(1)\n-#define   YT921X_SERDES_SPEED_1000\t\t\tYT921X_SERDES_SPEED(2)\n-#define   YT921X_SERDES_SPEED_10000\t\t\tYT921X_SERDES_SPEED(3)\n-#define   YT921X_SERDES_SPEED_2500\t\t\tYT921X_SERDES_SPEED(4)\n-#define YT921X_PORTn_CTRL(port)\t\t(0x80100 + 4 * (port))\n+#define YT921X_PORTn_CTRL(port)\t\t(0x80100 + 4 * (port))  /* Bit 7-0 shared with PORT_STATUS */\n #define  YT921X_PORT_CTRL_PAUSE_AN\t\tBIT(10)\n+#define  YT921X_PORT_CTRL_LINK_AN\t\tBIT(9)\n+#define  YT921X_PORT_CTRL_HALF_PAUSE\t\tBIT(8)  /* Half-duplex back pressure mode */\n #define YT921X_PORTn_STATUS(port)\t(0x80200 + 4 * (port))\n-#define  YT921X_PORT_LINK\t\t\tBIT(9)  /* CTRL: auto negotiation */\n-#define  YT921X_PORT_HALF_PAUSE\t\t\tBIT(8)  /* Half-duplex back pressure mode */\n+#define  YT921X_PORT_LINK\t\t\tBIT(8)\n #define  YT921X_PORT_DUPLEX_FULL\t\tBIT(7)\n #define  YT921X_PORT_RX_PAUSE\t\t\tBIT(6)\n #define  YT921X_PORT_TX_PAUSE\t\t\tBIT(5)\n@@ -106,11 +102,6 @@\n #define  YT921X_PORT_TX_MAC_EN\t\t\tBIT(3)\n #define  YT921X_PORT_SPEED_M\t\t\tGENMASK(2, 0)\n #define   YT921X_PORT_SPEED(x)\t\t\t\tFIELD_PREP(YT921X_PORT_SPEED_M, (x))\n-#define   YT921X_PORT_SPEED_10\t\t\t\tYT921X_PORT_SPEED(0)\n-#define   YT921X_PORT_SPEED_100\t\t\t\tYT921X_PORT_SPEED(1)\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_PON_STRAP_FUNC\t\t0x80320\n #define YT921X_PON_STRAP_VAL\t\t0x80324\n #define YT921X_PON_STRAP_CAP\t\t0x80328\n@@ -121,11 +112,16 @@\n #define  YT921X_MDIO_POLLING_LINK\t\tBIT(3)\n #define  YT921X_MDIO_POLLING_SPEED_M\t\tGENMASK(2, 0)\n #define   YT921X_MDIO_POLLING_SPEED(x)\t\t\tFIELD_PREP(YT921X_MDIO_POLLING_SPEED_M, (x))\n-#define   YT921X_MDIO_POLLING_SPEED_10\t\t\tYT921X_MDIO_POLLING_SPEED(0)\n-#define   YT921X_MDIO_POLLING_SPEED_100\t\t\tYT921X_MDIO_POLLING_SPEED(1)\n-#define   YT921X_MDIO_POLLING_SPEED_1000\t\tYT921X_MDIO_POLLING_SPEED(2)\n-#define   YT921X_MDIO_POLLING_SPEED_10000\t\tYT921X_MDIO_POLLING_SPEED(3)\n-#define   YT921X_MDIO_POLLING_SPEED_2500\t\tYT921X_MDIO_POLLING_SPEED(4)\n+\n+enum yt921x_speed {\n+\tYT921X_SPEED_10,\n+\tYT921X_SPEED_100,\n+\tYT921X_SPEED_1000,\n+\tYT921X_SPEED_10000,\n+\tYT921X_SPEED_2500,\n+\tYT921X_SPEED_NUM\n+};\n+\n #define YT921X_SENSOR\t\t\t0x8036c\n #define  YT921X_SENSOR_TEMP\t\t\tBIT(18)\n #define YT921X_TEMP\t\t\t0x80374\n@@ -247,27 +243,6 @@\n #define   YT9218_SYS_CLK_167M\t\t\t\t0\n #define   YT921X_SYS_CLK_143M\t\t\t\t1\n \n-#define YT921X_EXT_MBUS_OP\t\t0x6a000\n-#define YT921X_INT_MBUS_OP\t\t0xf0000\n-#define  YT921X_MBUS_OP_START\t\t\tBIT(0)\n-#define YT921X_EXT_MBUS_CTRL\t\t0x6a004\n-#define YT921X_INT_MBUS_CTRL\t\t0xf0004\n-#define  YT921X_MBUS_CTRL_PORT_M\t\tGENMASK(25, 21)\n-#define   YT921X_MBUS_CTRL_PORT(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_PORT_M, (x))\n-#define  YT921X_MBUS_CTRL_REG_M\t\t\tGENMASK(20, 16)\n-#define   YT921X_MBUS_CTRL_REG(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_REG_M, (x))\n-#define  YT921X_MBUS_CTRL_TYPE_M\t\tGENMASK(11, 8)  /* wild guess */\n-#define   YT921X_MBUS_CTRL_TYPE(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_TYPE_M, (x))\n-#define   YT921X_MBUS_CTRL_TYPE_C22\t\t\tYT921X_MBUS_CTRL_TYPE(4)\n-#define  YT921X_MBUS_CTRL_OP_M\t\t\tGENMASK(3, 2)  /* wild guess */\n-#define   YT921X_MBUS_CTRL_OP(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_OP_M, (x))\n-#define   YT921X_MBUS_CTRL_WRITE\t\t\tYT921X_MBUS_CTRL_OP(1)\n-#define   YT921X_MBUS_CTRL_READ\t\t\t\tYT921X_MBUS_CTRL_OP(2)\n-#define YT921X_EXT_MBUS_DOUT\t\t0x6a008\n-#define YT921X_INT_MBUS_DOUT\t\t0xf0008\n-#define YT921X_EXT_MBUS_DIN\t\t0x6a00c\n-#define YT921X_INT_MBUS_DIN\t\t0xf000c\n-\n #define YT921X_PORTn_EGR(port)\t\t(0x100000 + 4 * (port))\n #define  YT921X_PORT_EGR_TPID_CTAG_M\t\tGENMASK(5, 4)\n #define   YT921X_PORT_EGR_TPID_CTAG(x)\t\t\tFIELD_PREP(YT921X_PORT_EGR_TPID_CTAG_M, (x))\n@@ -858,9 +833,6 @@ enum yt921x_fdb_entry_status {\n \n #define YT921X_NAME\t\"yt921x\"\n \n-#define yt921x_port_is_internal(port) ((port) \u003c 8)\n-#define yt921x_port_is_external(port) ((port) == 8 || (port) == 9)\n-\n struct yt921x_mib {\n \tu64 rx_broadcast;\n \tu64 rx_pause;\n@@ -936,8 +908,14 @@ struct yt921x_acl_blk {\n struct yt921x_port {\n \tunsigned char index;\n \n-\tbool hairpin;\n-\tbool isolated;\n+\t/* SerDes in use */\n+\tbool serdes:1;\n+\t/* Link from in-band status (PHYLINK_PCS_NEG_INBAND) */\n+\tbool inband:1;\n+\t/* BR_HAIRPIN_MODE */\n+\tbool hairpin:1;\n+\t/* BR_ISOLATED */\n+\tbool isolated:1;\n \n \tstruct delayed_work mib_read;\n \tstruct yt921x_mib mib;\n@@ -953,13 +931,30 @@ struct yt921x_port {\n \n \tstruct yt921x_led *leds[YT921X_LED_GROUP_NUM];\n #endif\n+\n+\tstruct phylink_pcs pcs;\n };\n \n+#define pcs_to_yt921x_port(_pcs) container_of((_pcs), struct yt921x_port, pcs)\n+\n struct yt921x_reg_ops {\n \tint (*read)(void *context, u32 reg, u32 *valp);\n \tint (*write)(void *context, u32 reg, u32 val);\n };\n \n+struct yt921x_info {\n+\tconst char *name;\n+\tu16 major;\n+\t/* Unknown, seems to be plain enumeration */\n+\tu8 mode;\n+\tu8 extmode;\n+\t/* Ports with integral GbE PHYs, not including MCU Port 10 */\n+\tu16 internal_mask;\n+\t/* Note: xmii_mask and serdes_mask may overlap */\n+\tu16 xmii_mask;\n+\tu16 serdes_mask;\n+};\n+\n struct yt921x_priv {\n \tstruct dsa_switch ds;\n \n@@ -989,4 +984,25 @@ struct yt921x_priv {\n \tstruct yt921x_acl_blk *acl_blks[YT921X_ACL_BLK_NUM];\n };\n \n+#define yt921x_port_to_priv(pp) \\\n+\tcontainer_of_const((pp), struct yt921x_priv, ports[(pp)-\u003eindex])\n+\n+static inline int ethtool_speed_to_yt921x(int speed)\n+{\n+\tswitch (speed) {\n+\tcase SPEED_10:\n+\t\treturn YT921X_SPEED_10;\n+\tcase SPEED_100:\n+\t\treturn YT921X_SPEED_100;\n+\tcase SPEED_1000:\n+\t\treturn YT921X_SPEED_1000;\n+\tcase SPEED_2500:\n+\t\treturn YT921X_SPEED_2500;\n+\tcase SPEED_10000:\n+\t\treturn YT921X_SPEED_10000;\n+\tdefault:\n+\t\treturn YT921X_SPEED_NUM;\n+\t}\n+}\n+\n #endif\ndiff --git a/drivers/net/dsa/motorcomm/leds.c b/drivers/net/dsa/motorcomm/leds.c\nindex 87a6b9cf60682..dd5b3684250db 100644\n--- a/drivers/net/dsa/motorcomm/leds.c\n+++ b/drivers/net/dsa/motorcomm/leds.c\n@@ -12,8 +12,6 @@\n #define to_yt921x_led(led_cdev) \\\n \tcontainer_of_const((led_cdev), struct yt921x_led, cdev)\n #define to_yt921x_port(led) ((led)-\u003eport)\n-#define to_yt921x_priv(pp) \\\n-\tcontainer_of_const((pp), struct yt921x_priv, ports[(pp)-\u003eindex])\n #define to_device(priv) ((priv)-\u003eds.dev)\n \n static u32 yt921x_led_regaddr(struct yt921x_priv *priv, int port, int group)\n@@ -321,7 +319,7 @@ yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,\n {\n \tstruct yt921x_led *led = to_yt921x_led(led_cdev);\n \tstruct yt921x_port *pp = to_yt921x_port(led);\n-\tstruct yt921x_priv *priv = to_yt921x_priv(pp);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \tint res;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\n@@ -337,7 +335,7 @@ yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,\n {\n \tstruct yt921x_led *led = to_yt921x_led(led_cdev);\n \tstruct yt921x_port *pp = to_yt921x_port(led);\n-\tstruct yt921x_priv *priv = to_yt921x_priv(pp);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \tint res;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\n@@ -353,7 +351,7 @@ yt921x_cled_hw_control_get_device(struct led_classdev *led_cdev)\n {\n \tstruct yt921x_led *led = to_yt921x_led(led_cdev);\n \tstruct yt921x_port *pp = to_yt921x_port(led);\n-\tstruct yt921x_priv *priv = to_yt921x_priv(pp);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \tstruct dsa_port *dp;\n \n \tdp = dsa_to_port(\u0026priv-\u003eds, pp-\u003eindex);\n@@ -374,7 +372,7 @@ yt921x_cled_hw_control_is_supported(struct led_classdev *led_cdev,\n {\n \tstruct yt921x_led *led = to_yt921x_led(led_cdev);\n \tstruct yt921x_port *pp = to_yt921x_port(led);\n-\tstruct yt921x_priv *priv = to_yt921x_priv(pp);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \n \tif (yt921x_led_trigger_is_supported(priv, pp-\u003eindex, led-\u003egroup, flags))\n \t\treturn 0;\n@@ -386,7 +384,7 @@ yt921x_cled_hw_control_get(struct led_classdev *led_cdev, unsigned long *flagsp)\n {\n \tstruct yt921x_led *led = to_yt921x_led(led_cdev);\n \tstruct yt921x_port *pp = to_yt921x_port(led);\n-\tstruct yt921x_priv *priv = to_yt921x_priv(pp);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \tint res;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\n@@ -401,7 +399,7 @@ yt921x_cled_hw_control_set(struct led_classdev *led_cdev, unsigned long flags)\n {\n \tstruct yt921x_led *led = to_yt921x_led(led_cdev);\n \tstruct yt921x_port *pp = to_yt921x_port(led);\n-\tstruct yt921x_priv *priv = to_yt921x_priv(pp);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n \tint res;\n \n \tmutex_lock(\u0026priv-\u003ereg_lock);\ndiff --git a/drivers/net/dsa/motorcomm/mdio_bus.c b/drivers/net/dsa/motorcomm/mdio_bus.c\nnew file mode 100644\nindex 0000000000000..1a3f3cc68275d\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/mdio_bus.c\n@@ -0,0 +1,301 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#include \u003clinux/of_mdio.h\u003e\n+\n+#include \"chip.h\"\n+#include \"mdio_bus.h\"\n+#include \"smi.h\"\n+\n+#define to_device(priv) ((priv)-\u003eds.dev)\n+\n+static int yt921x_intif_wait(struct yt921x_priv *priv)\n+{\n+\tu32 val = 0;\n+\n+\treturn yt921x_reg_wait(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START,\n+\t\t\t       \u0026val);\n+}\n+\n+int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\n+{\n+\tstruct device *dev = to_device(priv);\n+\tu32 mask;\n+\tu32 ctrl;\n+\tu32 val;\n+\tint res;\n+\n+\tres = yt921x_intif_wait(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n+\t       YT921X_MBUS_CTRL_OP_M;\n+\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n+\t       YT921X_MBUS_CTRL_READ;\n+\tres = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);\n+\tif (res)\n+\t\treturn res;\n+\n+\tres = yt921x_intif_wait(priv);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_read(priv, YT921X_INT_MBUS_DIN, \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif ((u16)val != val)\n+\t\tdev_info(dev,\n+\t\t\t \"%s: port %d, reg 0x%x: Expected u16, got 0x%08x\\n\",\n+\t\t\t __func__, port, reg, val);\n+\t*valp = (u16)val;\n+\treturn 0;\n+}\n+\n+int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val)\n+{\n+\tu32 mask;\n+\tu32 ctrl;\n+\tint res;\n+\n+\tres = yt921x_intif_wait(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n+\t       YT921X_MBUS_CTRL_OP_M;\n+\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n+\t       YT921X_MBUS_CTRL_WRITE;\n+\tres = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_DOUT, val);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn yt921x_intif_wait(priv);\n+}\n+\n+int\n+yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,\n+\t\t\t    u16 mask, u16 val)\n+{\n+\tint res;\n+\tu16 v;\n+\tu16 u;\n+\n+\tres = yt921x_intif_read(priv, port, reg, \u0026v);\n+\tif (res)\n+\t\treturn res;\n+\n+\tu = v;\n+\tu \u0026= ~mask;\n+\tu |= val;\n+\tif (u == v)\n+\t\treturn 0;\n+\n+\tres = yt921x_intif_write(priv, port, reg, u);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn 1;\n+}\n+\n+static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)\n+{\n+\tstruct yt921x_priv *priv = mbus-\u003epriv;\n+\tu16 val;\n+\tint res;\n+\n+\tif (port \u003e= YT921X_PORT_NUM)\n+\t\treturn U16_MAX;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_intif_read(priv, port, reg, \u0026val);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\treturn res;\n+\treturn val;\n+}\n+\n+static int\n+yt921x_mbus_int_write(struct mii_bus *mbus, int port, int reg, u16 data)\n+{\n+\tstruct yt921x_priv *priv = mbus-\u003epriv;\n+\tint res;\n+\n+\tif (port \u003e= YT921X_PORT_NUM)\n+\t\treturn -ENODEV;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_intif_write(priv, port, reg, data);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+int 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+\tint res;\n+\n+\tmbus = devm_mdiobus_alloc(dev);\n+\tif (!mbus)\n+\t\treturn -ENOMEM;\n+\n+\tmbus-\u003ename = \"YT921x internal MDIO bus\";\n+\tsnprintf(mbus-\u003eid, MII_BUS_ID_SIZE, \"%s\", dev_name(dev));\n+\tmbus-\u003epriv = priv;\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+\n+\tres = devm_of_mdiobus_register(dev, mbus, mnp);\n+\tif (res)\n+\t\treturn res;\n+\n+\tpriv-\u003embus_int = mbus;\n+\n+\treturn 0;\n+}\n+\n+static int yt921x_extif_wait(struct yt921x_priv *priv)\n+{\n+\tu32 val = 0;\n+\n+\treturn yt921x_reg_wait(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START,\n+\t\t\t       \u0026val);\n+}\n+\n+static int\n+yt921x_extif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\n+{\n+\tstruct device *dev = to_device(priv);\n+\tu32 mask;\n+\tu32 ctrl;\n+\tu32 val;\n+\tint res;\n+\n+\tres = yt921x_extif_wait(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n+\t       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;\n+\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n+\t       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_READ;\n+\tres = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);\n+\tif (res)\n+\t\treturn res;\n+\n+\tres = yt921x_extif_wait(priv);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_read(priv, YT921X_EXT_MBUS_DIN, \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif ((u16)val != val)\n+\t\tdev_info(dev,\n+\t\t\t \"%s: port %d, reg 0x%x: Expected u16, got 0x%08x\\n\",\n+\t\t\t __func__, port, reg, val);\n+\t*valp = (u16)val;\n+\treturn 0;\n+}\n+\n+static int\n+yt921x_extif_write(struct yt921x_priv *priv, int port, int reg, u16 val)\n+{\n+\tu32 mask;\n+\tu32 ctrl;\n+\tint res;\n+\n+\tres = yt921x_extif_wait(priv);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |\n+\t       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;\n+\tctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |\n+\t       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_WRITE;\n+\tres = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_DOUT, val);\n+\tif (res)\n+\t\treturn res;\n+\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);\n+\tif (res)\n+\t\treturn res;\n+\n+\treturn yt921x_extif_wait(priv);\n+}\n+\n+static int yt921x_mbus_ext_read(struct mii_bus *mbus, int port, int reg)\n+{\n+\tstruct yt921x_priv *priv = mbus-\u003epriv;\n+\tu16 val;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_extif_read(priv, port, reg, \u0026val);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\treturn res;\n+\treturn val;\n+}\n+\n+static int\n+yt921x_mbus_ext_write(struct mii_bus *mbus, int port, int reg, u16 data)\n+{\n+\tstruct yt921x_priv *priv = mbus-\u003epriv;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_extif_write(priv, port, reg, data);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)\n+{\n+\tstruct device *dev = to_device(priv);\n+\tstruct mii_bus *mbus;\n+\tint res;\n+\n+\tmbus = devm_mdiobus_alloc(dev);\n+\tif (!mbus)\n+\t\treturn -ENOMEM;\n+\n+\tmbus-\u003ename = \"YT921x external MDIO bus\";\n+\tsnprintf(mbus-\u003eid, MII_BUS_ID_SIZE, \"%s@ext\", dev_name(dev));\n+\tmbus-\u003epriv = priv;\n+\t/* TODO: c45? */\n+\tmbus-\u003eread = yt921x_mbus_ext_read;\n+\tmbus-\u003ewrite = yt921x_mbus_ext_write;\n+\tmbus-\u003eparent = dev;\n+\n+\tres = devm_of_mdiobus_register(dev, mbus, mnp);\n+\tif (res)\n+\t\treturn res;\n+\n+\tpriv-\u003embus_ext = mbus;\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/dsa/motorcomm/mdio_bus.h b/drivers/net/dsa/motorcomm/mdio_bus.h\nnew file mode 100644\nindex 0000000000000..e79b725d435bd\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/mdio_bus.h\n@@ -0,0 +1,54 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#ifndef _YT_MDIO_BUS_H\n+#define _YT_MDIO_BUS_H\n+\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/bits.h\u003e\n+#include \u003clinux/of.h\u003e\n+\n+#define YT921X_EXT_MBUS_OP\t\t0x6a000\n+#define YT921X_INT_MBUS_OP\t\t0xf0000\n+#define  YT921X_MBUS_OP_START\t\t\tBIT(0)\n+#define YT921X_EXT_MBUS_CTRL\t\t0x6a004\n+#define YT921X_INT_MBUS_CTRL\t\t0xf0004\n+#define  YT921X_MBUS_CTRL_PORT_M\t\tGENMASK(25, 21)\n+#define   YT921X_MBUS_CTRL_PORT(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_PORT_M, (x))\n+#define  YT921X_MBUS_CTRL_REG_M\t\t\tGENMASK(20, 16)\n+#define   YT921X_MBUS_CTRL_REG(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_REG_M, (x))\n+#define  YT921X_MBUS_CTRL_TYPE_M\t\tGENMASK(11, 8)  /* wild guess */\n+#define   YT921X_MBUS_CTRL_TYPE(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_TYPE_M, (x))\n+#define   YT921X_MBUS_CTRL_TYPE_C22\t\t\tYT921X_MBUS_CTRL_TYPE(4)\n+#define  YT921X_MBUS_CTRL_OP_M\t\t\tGENMASK(3, 2)  /* wild guess */\n+#define   YT921X_MBUS_CTRL_OP(x)\t\t\tFIELD_PREP(YT921X_MBUS_CTRL_OP_M, (x))\n+#define   YT921X_MBUS_CTRL_WRITE\t\t\tYT921X_MBUS_CTRL_OP(1)\n+#define   YT921X_MBUS_CTRL_READ\t\t\t\tYT921X_MBUS_CTRL_OP(2)\n+#define YT921X_EXT_MBUS_DOUT\t\t0x6a008\n+#define YT921X_INT_MBUS_DOUT\t\t0xf0008\n+#define YT921X_EXT_MBUS_DIN\t\t0x6a00c\n+#define YT921X_INT_MBUS_DIN\t\t0xf000c\n+\n+struct yt921x_priv;\n+\n+int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp);\n+int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val);\n+int yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,\n+\t\t\t\tu16 mask, u16 val);\n+\n+static inline int\n+yt921x_intif_modify(struct yt921x_priv *priv, int port, int reg, u16 mask,\n+\t\t    u16 val)\n+{\n+\tint res;\n+\n+\tres = yt921x_intif_modify_changed(priv, port, reg, mask, val);\n+\treturn res \u003e= 0 ? 0 : res;\n+}\n+\n+int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp);\n+int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp);\n+\n+#endif\ndiff --git a/drivers/net/dsa/motorcomm/pcs-921x.c b/drivers/net/dsa/motorcomm/pcs-921x.c\nnew file mode 100644\nindex 0000000000000..dcf7397cd2413\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/pcs-921x.c\n@@ -0,0 +1,235 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#include \"chip.h\"\n+#include \"mdio_bus.h\"\n+#include \"pcs.h\"\n+#include \"smi.h\"\n+\n+#define to_device(priv) ((priv)-\u003eds.dev)\n+\n+static int\n+yt921x_serdes_config(struct yt921x_priv *priv, int port, unsigned int neg_mode,\n+\t\t     phy_interface_t interface,\n+\t\t     const unsigned long *advertising, bool permit_pause_to_mac)\n+{\n+\tbool inband = neg_mode \u0026 PHYLINK_PCS_NEG_INBAND;\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tbool changed = false;\n+\tu16 bmcr;\n+\tu32 mask;\n+\tu32 ctrl;\n+\tu16 val;\n+\tint adv;\n+\tint res;\n+\n+\tswitch (interface) {\n+\tcase PHY_INTERFACE_MODE_SGMII:\n+\t\tctrl = YT921X_SERDES_MODE_SGMII;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_100BASEX:\n+\t\tctrl = YT921X_SERDES_MODE_100BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_1000BASEX:\n+\t\tctrl = YT921X_SERDES_MODE_1000BASEX;\n+\t\tbreak;\n+\tcase PHY_INTERFACE_MODE_2500BASEX:\n+\t\tctrl = YT921X_SERDES_MODE_2500BASEX;\n+\t\tbreak;\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tres = yt921x_reg_update_bits(priv, YT921X_SERDESn(port),\n+\t\t\t\t     YT921X_SERDES_MODE_M, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tmask = YT921X_PORT_CTRL_LINK_AN | YT921X_PORT_CTRL_PAUSE_AN;\n+\tctrl = 0;\n+\tif (inband)\n+\t\tctrl |= YT921X_PORT_CTRL_LINK_AN;\n+\tif (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED \u0026\u0026 permit_pause_to_mac)\n+\t\tctrl |= YT921X_PORT_CTRL_PAUSE_AN;\n+\tres = yt921x_reg_update_bits(priv, YT921X_PORTn_CTRL(port), mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif (inband) {\n+\t\tres = yt921x_reg_clear_bits(priv, YT921X_SERDESn(port),\n+\t\t\t\t\t    YT921X_SERDES_LINK);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\tadv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);\n+\tif (adv \u003e= 0) {\n+\t\tres = yt921x_intif_modify_changed(priv, port, MII_ADVERTISE,\n+\t\t\t\t\t\t  U16_MAX, adv);\n+\t\tif (res \u003c 0)\n+\t\t\treturn res;\n+\n+\t\tchanged = !!res;\n+\t}\n+\n+\tres = yt921x_intif_read(priv, port, MII_BMCR, \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\tbmcr = val;\n+\tif (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)\n+\t\tbmcr |= BMCR_ANENABLE;\n+\telse\n+\t\tbmcr \u0026= ~BMCR_ANENABLE;\n+\n+\t/* If the ANENABLE bit was changed, the PHY will restart negotiation,\n+\t * so we don't need to flag a change to trigger its own restart.\n+\t */\n+\tif (bmcr != val)\n+\t\tchanged = false;\n+\n+\tbmcr \u0026= ~BMCR_ISOLATE;\n+\tres = yt921x_intif_write(priv, port, MII_BMCR, bmcr);\n+\tif (res)\n+\t\treturn res;\n+\n+\tpp-\u003einband = inband;\n+\treturn changed;\n+}\n+\n+static unsigned int\n+yt921x_phylink_pcs_inband_caps(struct phylink_pcs *pcs,\n+\t\t\t       phy_interface_t interface)\n+{\n+\treturn LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;\n+}\n+\n+static void\n+yt921x_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,\n+\t\t\t     struct phylink_link_state *state)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tstruct device *dev = to_device(priv);\n+\tint port = pp-\u003eindex;\n+\tu16 bmsr;\n+\tu16 lpa;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\n+\tres = yt921x_intif_read(priv, port, MII_BMSR, \u0026bmsr);\n+\tif (res)\n+\t\tgoto out;\n+\n+\tres = yt921x_intif_read(priv, port, MII_LPA, \u0026lpa);\n+\n+out:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res) {\n+\t\tdev_err(dev, \"Failed to %s PCS port %d: %i\\n\", \"get state of\",\n+\t\t\tport, res);\n+\t\tstate-\u003elink = false;\n+\t\treturn;\n+\t}\n+\n+\tphylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);\n+}\n+\n+static void yt921x_phylink_pcs_an_restart(struct phylink_pcs *pcs)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tstruct device *dev = to_device(priv);\n+\tint port = pp-\u003eindex;\n+\tu16 val;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\n+\tres = yt921x_intif_read(priv, port, MII_BMCR, \u0026val);\n+\tif (res)\n+\t\tgoto end;\n+\n+\tval |= BMCR_ANRESTART;\n+\tres = yt921x_intif_write(priv, port, MII_BMCR, val);\n+\n+end:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dev, \"Failed to %s PCS port %d: %i\\n\", \"restart\",\n+\t\t\tport, res);\n+}\n+\n+static void yt921x_phylink_pcs_disable(struct phylink_pcs *pcs)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tstruct device *dev = to_device(priv);\n+\tint port = pp-\u003eindex;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_intif_modify(priv, port, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res)\n+\t\tdev_err(dev, \"Failed to %s PCS port %d: %i\\n\", \"power down\",\n+\t\t\tport, res);\n+}\n+\n+static int yt921x_phylink_pcs_enable(struct phylink_pcs *pcs)\n+{\n+\tstruct yt921x_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tint port = pp-\u003eindex;\n+\tu16 val;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\n+\tres = yt921x_intif_read(priv, port, MII_BMCR, \u0026val);\n+\tif (res)\n+\t\tgoto end;\n+\n+\tval \u0026= ~BMCR_PDOWN;\n+\tval |= BMCR_ANRESTART;\n+\tres = yt921x_intif_write(priv, port, MII_BMCR, val);\n+\n+end:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static int\n+yt921x_phylink_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_port *pp = pcs_to_yt921x_port(pcs);\n+\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\n+\tint port = pp-\u003eindex;\n+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_serdes_config(priv, port, neg_mode, interface,\n+\t\t\t\t   advertising, permit_pause_to_mac);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+const struct phylink_pcs_ops yt921x_phylink_pcs_ops = {\n+\t.pcs_inband_caps\t= yt921x_phylink_pcs_inband_caps,\n+\t.pcs_get_state\t\t= yt921x_phylink_pcs_get_state,\n+\t.pcs_an_restart\t\t= yt921x_phylink_pcs_an_restart,\n+\t.pcs_disable\t\t= yt921x_phylink_pcs_disable,\n+\t.pcs_enable\t\t= yt921x_phylink_pcs_enable,\n+\t.pcs_config\t\t= yt921x_phylink_pcs_config,\n+};\ndiff --git a/drivers/net/dsa/motorcomm/pcs.h b/drivers/net/dsa/motorcomm/pcs.h\nnew file mode 100644\nindex 0000000000000..42426558086af\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/pcs.h\n@@ -0,0 +1,13 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#ifndef _YT_PCS_H\n+#define _YT_PCS_H\n+\n+#include \u003clinux/phylink.h\u003e\n+\n+extern const struct phylink_pcs_ops yt921x_phylink_pcs_ops;\n+\n+#endif\n"
}

2/1 2026/09/19 23:04 agent patch-evaluator
0m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT921x (YT9215) ethernet switch DSA driver in drivers/net/dsa/motorcomm/. This driver controls a physical Ethernet switch ASIC connected via MDIO and configured via Device Tree (OF compatible \"motorcomm,yt9215\"). The hardware is not emulated in standard QEMU/GCE virtual machines on amd64, and cannot be instantiated through virtual interfaces or virtual buses. Therefore, the modified code is structurally unreachable for fuzzing.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit f604800e94cd31bc31226bda2c9fd576630992cf
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Sep 19 23:04:29 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
index aeb12cb91f935..1d2c1b3064c41 100644
--- a/drivers/net/dsa/motorcomm/Makefile
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -2,4 +2,6 @@
 obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
 yt921x-objs := chip.o
 yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o
+yt921x-objs += mdio_bus.o
+yt921x-objs += pcs-921x.o
 yt921x-objs += smi.o
diff --git a/drivers/net/dsa/motorcomm/chip.c b/drivers/net/dsa/motorcomm/chip.c
index d663af010f431..530bea77ac70a 100644
--- a/drivers/net/dsa/motorcomm/chip.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -27,6 +27,8 @@
 
 #include "chip.h"
 #include "leds.h"
+#include "mdio_bus.h"
+#include "pcs.h"
 #include "smi.h"
 
 struct yt921x_mib_desc {
@@ -96,58 +98,48 @@ static const struct yt921x_mib_desc yt921x_mib_descs[] = {
 	MIB_DESC(1, YT921X_MIB_DATA_TX_OAM, "TxOAM"),
 };
 
-struct yt921x_info {
-	const char *name;
-	u16 major;
-	/* Unknown, seems to be plain enumeration */
-	u8 mode;
-	u8 extmode;
-	/* Ports with integral GbE PHYs, not including MCU Port 10 */
-	u16 internal_mask;
-	/* TODO: see comments in yt921x_dsa_phylink_get_caps() */
-	u16 external_mask;
-};
-
-#define YT921X_PORT_MASK_INTn(port)	BIT(port)
-#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)
-
 static const struct yt921x_info yt921x_infos[] = {
 	{
 		"YT9215SC", YT9215_MAJOR, 1, 0,
-		YT921X_PORT_MASK_INT0_n(5),
-		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
+		GENMASK(4, 0),
+		BIT(9),
+		BIT(8) | BIT(9),
 	},
 	{
 		"YT9215S", YT9215_MAJOR, 2, 0,
-		YT921X_PORT_MASK_INT0_n(5),
-		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
+		GENMASK(4, 0),
+		BIT(9),
+		BIT(8),
 	},
 	{
 		"YT9215RB", YT9215_MAJOR, 3, 0,
-		YT921X_PORT_MASK_INT0_n(5),
-		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
+		GENMASK(4, 0),
+		BIT(8) | BIT(9),
+		0,
 	},
 	{
 		"YT9214NB", YT9215_MAJOR, 3, 2,
-		YT921X_PORT_MASK_INTn(1) | YT921X_PORT_MASK_INTn(3),
-		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
+		BIT(1) | BIT(3),
+		BIT(9),
+		BIT(8),
 	},
 	{
 		"YT9213NB", YT9215_MAJOR, 3, 3,
-		YT921X_PORT_MASK_INTn(1) | YT921X_PORT_MASK_INTn(3),
-		YT921X_PORT_MASK_EXT1,
+		BIT(1) | BIT(3),
+		BIT(9),
+		BIT(9),
 	},
 	{
 		"YT9218N", YT9218_MAJOR, 0, 0,
-		YT921X_PORT_MASK_INT0_n(8),
+		GENMASK(7, 0),
+		0,
 		0,
 	},
 	{
 		"YT9218MB", YT9218_MAJOR, 1, 0,
-		YT921X_PORT_MASK_INT0_n(8),
-		YT921X_PORT_MASK_EXT0 | YT921X_PORT_MASK_EXT1,
+		GENMASK(7, 0),
+		BIT(8) | BIT(9),
+		BIT(8) | BIT(9),
 	},
 	{}
 };
@@ -276,274 +268,6 @@ static const struct yt921x_reg_ops yt921x_reg_ops_mdio = {
 
 /* TODO: SPI/I2C */
 
-static int yt921x_intif_wait(struct yt921x_priv *priv)
-{
-	u32 val = 0;
-
-	return yt921x_reg_wait(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START,
-			       &val);
-}
-
-static int
-yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
-{
-	struct device *dev = to_device(priv);
-	u32 mask;
-	u32 ctrl;
-	u32 val;
-	int res;
-
-	res = yt921x_intif_wait(priv);
-	if (res)
-		return res;
-
-	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
-	       YT921X_MBUS_CTRL_OP_M;
-	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
-	       YT921X_MBUS_CTRL_READ;
-	res = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);
-	if (res)
-		return res;
-	res = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);
-	if (res)
-		return res;
-
-	res = yt921x_intif_wait(priv);
-	if (res)
-		return res;
-	res = yt921x_reg_read(priv, YT921X_INT_MBUS_DIN, &val);
-	if (res)
-		return res;
-
-	if ((u16)val != val)
-		dev_info(dev,
-			 "%s: port %d, reg 0x%x: Expected u16, got 0x%08x\n",
-			 __func__, port, reg, val);
-	*valp = (u16)val;
-	return 0;
-}
-
-static int
-yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val)
-{
-	u32 mask;
-	u32 ctrl;
-	int res;
-
-	res = yt921x_intif_wait(priv);
-	if (res)
-		return res;
-
-	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
-	       YT921X_MBUS_CTRL_OP_M;
-	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
-	       YT921X_MBUS_CTRL_WRITE;
-	res = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);
-	if (res)
-		return res;
-	res = yt921x_reg_write(priv, YT921X_INT_MBUS_DOUT, val);
-	if (res)
-		return res;
-	res = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);
-	if (res)
-		return res;
-
-	return yt921x_intif_wait(priv);
-}
-
-static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)
-{
-	struct yt921x_priv *priv = mbus->priv;
-	u16 val;
-	int res;
-
-	if (port >= YT921X_PORT_NUM)
-		return U16_MAX;
-
-	mutex_lock(&priv->reg_lock);
-	res = yt921x_intif_read(priv, port, reg, &val);
-	mutex_unlock(&priv->reg_lock);
-
-	if (res)
-		return res;
-	return val;
-}
-
-static int
-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)
-		return -ENODEV;
-
-	mutex_lock(&priv->reg_lock);
-	res = yt921x_intif_write(priv, port, reg, data);
-	mutex_unlock(&priv->reg_lock);
-
-	return res;
-}
-
-static int
-yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)
-{
-	struct device *dev = to_device(priv);
-	struct mii_bus *mbus;
-	int res;
-
-	mbus = devm_mdiobus_alloc(dev);
-	if (!mbus)
-		return -ENOMEM;
-
-	mbus->name = "YT921x internal MDIO bus";
-	snprintf(mbus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
-	mbus->priv = priv;
-	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);
-
-	res = devm_of_mdiobus_register(dev, mbus, mnp);
-	if (res)
-		return res;
-
-	priv->mbus_int = mbus;
-
-	return 0;
-}
-
-static int yt921x_extif_wait(struct yt921x_priv *priv)
-{
-	u32 val = 0;
-
-	return yt921x_reg_wait(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START,
-			       &val);
-}
-
-static int
-yt921x_extif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
-{
-	struct device *dev = to_device(priv);
-	u32 mask;
-	u32 ctrl;
-	u32 val;
-	int res;
-
-	res = yt921x_extif_wait(priv);
-	if (res)
-		return res;
-
-	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
-	       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;
-	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
-	       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_READ;
-	res = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);
-	if (res)
-		return res;
-	res = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);
-	if (res)
-		return res;
-
-	res = yt921x_extif_wait(priv);
-	if (res)
-		return res;
-	res = yt921x_reg_read(priv, YT921X_EXT_MBUS_DIN, &val);
-	if (res)
-		return res;
-
-	if ((u16)val != val)
-		dev_info(dev,
-			 "%s: port %d, reg 0x%x: Expected u16, got 0x%08x\n",
-			 __func__, port, reg, val);
-	*valp = (u16)val;
-	return 0;
-}
-
-static int
-yt921x_extif_write(struct yt921x_priv *priv, int port, int reg, u16 val)
-{
-	u32 mask;
-	u32 ctrl;
-	int res;
-
-	res = yt921x_extif_wait(priv);
-	if (res)
-		return res;
-
-	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
-	       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;
-	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
-	       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_WRITE;
-	res = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);
-	if (res)
-		return res;
-	res = yt921x_reg_write(priv, YT921X_EXT_MBUS_DOUT, val);
-	if (res)
-		return res;
-	res = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);
-	if (res)
-		return res;
-
-	return yt921x_extif_wait(priv);
-}
-
-static int yt921x_mbus_ext_read(struct mii_bus *mbus, int port, int reg)
-{
-	struct yt921x_priv *priv = mbus->priv;
-	u16 val;
-	int res;
-
-	mutex_lock(&priv->reg_lock);
-	res = yt921x_extif_read(priv, port, reg, &val);
-	mutex_unlock(&priv->reg_lock);
-
-	if (res)
-		return res;
-	return val;
-}
-
-static int
-yt921x_mbus_ext_write(struct mii_bus *mbus, int port, int reg, u16 data)
-{
-	struct yt921x_priv *priv = mbus->priv;
-	int res;
-
-	mutex_lock(&priv->reg_lock);
-	res = yt921x_extif_write(priv, port, reg, data);
-	mutex_unlock(&priv->reg_lock);
-
-	return res;
-}
-
-static int
-yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)
-{
-	struct device *dev = to_device(priv);
-	struct mii_bus *mbus;
-	int res;
-
-	mbus = devm_mdiobus_alloc(dev);
-	if (!mbus)
-		return -ENOMEM;
-
-	mbus->name = "YT921x external MDIO bus";
-	snprintf(mbus->id, MII_BUS_ID_SIZE, "%s@ext", dev_name(dev));
-	mbus->priv = priv;
-	/* TODO: c45? */
-	mbus->read = yt921x_mbus_ext_read;
-	mbus->write = yt921x_mbus_ext_write;
-	mbus->parent = dev;
-
-	res = devm_of_mdiobus_register(dev, mbus, mnp);
-	if (res)
-		return res;
-
-	priv->mbus_ext = mbus;
-
-	return 0;
-}
-
 /* Read and handle overflow of 32bit MIBs. MIB buffer must be zeroed before. */
 static int yt921x_read_mib(struct yt921x_priv *priv, int port)
 {
@@ -608,9 +332,8 @@ static void yt921x_poll_mib(struct work_struct *work)
 {
 	struct yt921x_port *pp = container_of_const(work, struct yt921x_port,
 						    mib_read.work);
-	struct yt921x_priv *priv = (void *)(pp - pp->index) -
-				   offsetof(struct yt921x_priv, ports);
 	unsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 	int port = pp->index;
 	int res;
 
@@ -3748,20 +3471,23 @@ yt921x_dsa_port_set_apptrust(struct dsa_switch *ds, int port, const u8 *sel,
 
 static int yt921x_port_down(struct yt921x_priv *priv, int port)
 {
+	const struct yt921x_info *info = priv->info;
 	u32 mask;
 	int res;
 
-	mask = YT921X_PORT_LINK | YT921X_PORT_RX_MAC_EN | YT921X_PORT_TX_MAC_EN;
+	mask = YT921X_PORT_CTRL_LINK_AN | YT921X_PORT_RX_MAC_EN |
+	       YT921X_PORT_TX_MAC_EN;
 	res = yt921x_reg_clear_bits(priv, YT921X_PORTn_CTRL(port), mask);
 	if (res)
 		return res;
 
-	if (yt921x_port_is_external(port)) {
+	if (BIT(port) & info->serdes_mask) {
 		mask = YT921X_SERDES_LINK;
 		res = yt921x_reg_clear_bits(priv, YT921X_SERDESn(port), mask);
 		if (res)
 			return res;
-
+	}
+	if (BIT(port) & info->xmii_mask) {
 		mask = YT921X_XMII_LINK;
 		res = yt921x_reg_clear_bits(priv, YT921X_XMIIn(port), mask);
 		if (res)
@@ -3776,29 +3502,21 @@ yt921x_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)
 {
+	const struct yt921x_info *info = priv->info;
+	struct yt921x_port *pp = &priv->ports[port];
+	int ps = ethtool_speed_to_yt921x(speed);
 	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_10000:
-		ctrl = YT921X_PORT_SPEED_10000;
-		break;
-	default:
+	if (ps == YT921X_SPEED_NUM)
 		return -EINVAL;
-	}
+
+	mask = YT921X_PORT_SPEED_M | YT921X_PORT_TX_MAC_EN |
+	       YT921X_PORT_RX_MAC_EN | YT921X_PORT_TX_PAUSE |
+	       YT921X_PORT_RX_PAUSE | YT921X_PORT_DUPLEX_FULL |
+	       YT921X_PORT_CTRL_LINK_AN;
+	ctrl = YT921X_PORT_SPEED(ps);
 	if (duplex == DUPLEX_FULL)
 		ctrl |= YT921X_PORT_DUPLEX_FULL;
 	if (tx_pause)
@@ -3806,31 +3524,18 @@ yt921x_port_up(struct yt921x_priv *priv, int port, unsigned int mode,
 	if (rx_pause)
 		ctrl |= YT921X_PORT_RX_PAUSE;
 	ctrl |= YT921X_PORT_RX_MAC_EN | YT921X_PORT_TX_MAC_EN;
-	res = yt921x_reg_write(priv, YT921X_PORTn_CTRL(port), ctrl);
+	if (pp->serdes && pp->inband)
+		ctrl |= YT921X_PORT_CTRL_LINK_AN;
+	res = yt921x_reg_update_bits(priv, YT921X_PORTn_CTRL(port), mask, ctrl);
 	if (res)
 		return res;
 
-	if (yt921x_port_is_external(port)) {
+	if (!(BIT(port) & (info->serdes_mask | info->xmii_mask)))
+		return 0;
+
+	if (pp->serdes) {
 		mask = YT921X_SERDES_SPEED_M;
-		switch (speed) {
-		case SPEED_10:
-			ctrl = YT921X_SERDES_SPEED_10;
-			break;
-		case SPEED_100:
-			ctrl = YT921X_SERDES_SPEED_100;
-			break;
-		case SPEED_1000:
-			ctrl = YT921X_SERDES_SPEED_1000;
-			break;
-		case SPEED_2500:
-			ctrl = YT921X_SERDES_SPEED_2500;
-			break;
-		case SPEED_10000:
-			ctrl = YT921X_SERDES_SPEED_10000;
-			break;
-		default:
-			return -EINVAL;
-		}
+		ctrl = YT921X_SERDES_SPEED(ps);
 		mask |= YT921X_SERDES_DUPLEX_FULL;
 		if (duplex == DUPLEX_FULL)
 			ctrl |= YT921X_SERDES_DUPLEX_FULL;
@@ -3841,36 +3546,19 @@ yt921x_port_up(struct yt921x_priv *priv, int port, unsigned int mode,
 		if (rx_pause)
 			ctrl |= YT921X_SERDES_RX_PAUSE;
 		mask |= YT921X_SERDES_LINK;
-		ctrl |= YT921X_SERDES_LINK;
+		if (!pp->inband)
+			ctrl |= YT921X_SERDES_LINK;
 		res = yt921x_reg_update_bits(priv, YT921X_SERDESn(port),
 					     mask, ctrl);
 		if (res)
 			return res;
-
+	} else {
 		mask = YT921X_XMII_LINK;
 		res = yt921x_reg_set_bits(priv, YT921X_XMIIn(port), mask);
 		if (res)
 			return res;
 
-		switch (speed) {
-		case SPEED_10:
-			ctrl = YT921X_MDIO_POLLING_SPEED_10;
-			break;
-		case SPEED_100:
-			ctrl = YT921X_MDIO_POLLING_SPEED_100;
-			break;
-		case SPEED_1000:
-			ctrl = YT921X_MDIO_POLLING_SPEED_1000;
-			break;
-		case SPEED_2500:
-			ctrl = YT921X_MDIO_POLLING_SPEED_2500;
-			break;
-		case SPEED_10000:
-			ctrl = YT921X_MDIO_POLLING_SPEED_10000;
-			break;
-		default:
-			return -EINVAL;
-		}
+		ctrl = YT921X_MDIO_POLLING_SPEED(ps);
 		if (duplex == DUPLEX_FULL)
 			ctrl |= YT921X_MDIO_POLLING_DUPLEX_FULL;
 		ctrl |= YT921X_MDIO_POLLING_LINK;
@@ -3886,17 +3574,15 @@ static int
 yt921x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,
 		   phy_interface_t interface)
 {
+	const struct yt921x_info *info = priv->info;
+	struct yt921x_port *pp = &priv->ports[port];
 	struct device *dev = to_device(priv);
 	u32 mask;
-	u32 ctrl;
 	int res;
 
-	if (!yt921x_port_is_external(port)) {
-		if (interface != PHY_INTERFACE_MODE_INTERNAL) {
-			dev_err(dev, "Wrong mode %d on port %d\n",
-				interface, port);
-			return -EINVAL;
-		}
+	if (BIT(port) & info->internal_mask) {
+		if (interface != PHY_INTERFACE_MODE_INTERNAL)
+			goto err;
 		return 0;
 	}
 
@@ -3906,6 +3592,9 @@ yt921x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,
 	case PHY_INTERFACE_MODE_100BASEX:
 	case PHY_INTERFACE_MODE_1000BASEX:
 	case PHY_INTERFACE_MODE_2500BASEX:
+		if (!(BIT(port) & info->serdes_mask))
+			goto err;
+
 		mask = YT921X_SERDES_CTRL_PORTn(port);
 		res = yt921x_reg_set_bits(priv, YT921X_SERDES_CTRL, mask);
 		if (res)
@@ -3916,35 +3605,44 @@ yt921x_port_config(struct yt921x_priv *priv, int port, unsigned int mode,
 		if (res)
 			return res;
 
-		mask = YT921X_SERDES_MODE_M;
-		switch (interface) {
-		case PHY_INTERFACE_MODE_SGMII:
-			ctrl = YT921X_SERDES_MODE_SGMII;
-			break;
-		case PHY_INTERFACE_MODE_100BASEX:
-			ctrl = YT921X_SERDES_MODE_100BASEX;
-			break;
-		case PHY_INTERFACE_MODE_1000BASEX:
-			ctrl = YT921X_SERDES_MODE_1000BASEX;
-			break;
-		case PHY_INTERFACE_MODE_2500BASEX:
-			ctrl = YT921X_SERDES_MODE_2500BASEX;
-			break;
-		default:
-			return -EINVAL;
-		}
-		res = yt921x_reg_update_bits(priv, YT921X_SERDESn(port),
-					     mask, ctrl);
-		if (res)
-			return res;
-
+		/* The order is quite arbitrary - we can't return to a safe
+		 * state on IO errors.
+		 */
+		pp->serdes = true;
 		break;
 	/* add XMII support here */
 	default:
-		return -EINVAL;
+		goto err;
 	}
 
 	return 0;
+
+err:
+	dev_err(dev, "Wrong mode %d on port %d\n", interface, port);
+	return -EINVAL;
+}
+
+static struct phylink_pcs *
+yt921x_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 = to_yt921x_priv(dp->ds);
+	const struct yt921x_info *info = priv->info;
+	int port = dp->index;
+
+	if (!(BIT(port) & info->serdes_mask))
+		return NULL;
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+	case PHY_INTERFACE_MODE_100BASEX:
+	case PHY_INTERFACE_MODE_1000BASEX:
+	case PHY_INTERFACE_MODE_2500BASEX:
+		return &priv->ports[port].pcs;
+	default:
+		return NULL;
+	}
 }
 
 static void
@@ -4026,15 +3724,10 @@ yt921x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,
 		 */
 		__set_bit(PHY_INTERFACE_MODE_INTERNAL,
 			  config->supported_interfaces);
-	} else if (info->external_mask & BIT(port)) {
-		/* TODO: external ports may support SERDES only, XMII only, or
-		 * SERDES + XMII depending on the chip. However, we can't get
-		 * the accurate config table due to lack of document, thus
-		 * we simply declare SERDES + XMII and rely on the correctness
-		 * of devicetree for now.
-		 */
+		return;
+	}
 
-		/* SERDES */
+	if (BIT(port) & info->serdes_mask) {
 		__set_bit(PHY_INTERFACE_MODE_SGMII,
 			  config->supported_interfaces);
 		/* REVSGMII (SGMII in PHY role) should go here, once
@@ -4047,9 +3740,8 @@ yt921x_dsa_phylink_get_caps(struct dsa_switch *ds, int port,
 		__set_bit(PHY_INTERFACE_MODE_2500BASEX,
 			  config->supported_interfaces);
 		config->mac_capabilities |= MAC_2500FD;
-
-		/* XMII */
-
+	}
+	if (BIT(port) & info->xmii_mask) {
 		/* Not tested. To add support for XMII:
 		 *   - Add proper interface modes below
 		 *   - Handle them in yt921x_port_config()
@@ -4540,6 +4232,11 @@ static int yt921x_chip_setup(struct yt921x_priv *priv)
 	if (res)
 		return res;
 
+	res = yt921x_reg_clear_bits(priv, YT921X_SERDES_CTRL,
+				    YT921X_SERDES_CTRL_TEST);
+	if (res)
+		return res;
+
 	return 0;
 }
 
@@ -4549,6 +4246,8 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 	struct device *dev = to_device(priv);
 	struct device_node *np = dev->of_node;
 	struct device_node *child;
+	unsigned long mask;
+	int port;
 	int res;
 
 	mutex_lock(&priv->reg_lock);
@@ -4582,6 +4281,23 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 		return -ENODEV;
 	}
 
+	mask = priv->info->serdes_mask;
+	for_each_set_bit(port, &mask, YT921X_PORT_NUM) {
+		struct yt921x_port *pp = &priv->ports[port];
+
+		pp->pcs.ops = &yt921x_phylink_pcs_ops;
+		pp->pcs.poll = true;
+
+		__set_bit(PHY_INTERFACE_MODE_SGMII,
+			  pp->pcs.supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_100BASEX,
+			  pp->pcs.supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_1000BASEX,
+			  pp->pcs.supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_2500BASEX,
+			  pp->pcs.supported_interfaces);
+	}
+
 	mutex_lock(&priv->reg_lock);
 	res = yt921x_chip_setup(priv);
 	mutex_unlock(&priv->reg_lock);
@@ -4599,6 +4315,7 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 }
 
 static const struct phylink_mac_ops yt921x_phylink_mac_ops = {
+	.mac_select_pcs	= yt921x_phylink_mac_select_pcs,
 	.mac_link_down	= yt921x_phylink_mac_link_down,
 	.mac_link_up	= yt921x_phylink_mac_link_up,
 	.mac_config	= yt921x_phylink_mac_config,
diff --git a/drivers/net/dsa/motorcomm/chip.h b/drivers/net/dsa/motorcomm/chip.h
index 83cd454955ddb..0cbb54834ffff 100644
--- a/drivers/net/dsa/motorcomm/chip.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -42,7 +42,7 @@
 #define YT921X_PVID_SEL			0x80014
 #define  YT921X_PVID_SEL_SVID_PORTn(port)	BIT(port)
 #define YT921X_SERDES_CTRL		0x80028
-#define  YT921X_SERDES_CTRL_PORTn_TEST(port)	BIT((port) - 3)
+#define  YT921X_SERDES_CTRL_TEST		BIT(6)
 #define  YT921X_SERDES_CTRL_PORTn(port)		BIT((port) - 8)
 #define YT921X_IO_LEVEL			0x80030
 #define  YT9215_IO_LEVEL_NORMAL_M		GENMASK(5, 4)
@@ -89,16 +89,12 @@
 #define  YT921X_SERDES_DUPLEX_FULL		BIT(3)
 #define  YT921X_SERDES_SPEED_M			GENMASK(2, 0)
 #define   YT921X_SERDES_SPEED(x)			FIELD_PREP(YT921X_SERDES_SPEED_M, (x))
-#define   YT921X_SERDES_SPEED_10			YT921X_SERDES_SPEED(0)
-#define   YT921X_SERDES_SPEED_100			YT921X_SERDES_SPEED(1)
-#define   YT921X_SERDES_SPEED_1000			YT921X_SERDES_SPEED(2)
-#define   YT921X_SERDES_SPEED_10000			YT921X_SERDES_SPEED(3)
-#define   YT921X_SERDES_SPEED_2500			YT921X_SERDES_SPEED(4)
-#define YT921X_PORTn_CTRL(port)		(0x80100 + 4 * (port))
+#define YT921X_PORTn_CTRL(port)		(0x80100 + 4 * (port))  /* Bit 7-0 shared with PORT_STATUS */
 #define  YT921X_PORT_CTRL_PAUSE_AN		BIT(10)
+#define  YT921X_PORT_CTRL_LINK_AN		BIT(9)
+#define  YT921X_PORT_CTRL_HALF_PAUSE		BIT(8)  /* Half-duplex back pressure mode */
 #define YT921X_PORTn_STATUS(port)	(0x80200 + 4 * (port))
-#define  YT921X_PORT_LINK			BIT(9)  /* CTRL: auto negotiation */
-#define  YT921X_PORT_HALF_PAUSE			BIT(8)  /* Half-duplex back pressure mode */
+#define  YT921X_PORT_LINK			BIT(8)
 #define  YT921X_PORT_DUPLEX_FULL		BIT(7)
 #define  YT921X_PORT_RX_PAUSE			BIT(6)
 #define  YT921X_PORT_TX_PAUSE			BIT(5)
@@ -106,11 +102,6 @@
 #define  YT921X_PORT_TX_MAC_EN			BIT(3)
 #define  YT921X_PORT_SPEED_M			GENMASK(2, 0)
 #define   YT921X_PORT_SPEED(x)				FIELD_PREP(YT921X_PORT_SPEED_M, (x))
-#define   YT921X_PORT_SPEED_10				YT921X_PORT_SPEED(0)
-#define   YT921X_PORT_SPEED_100				YT921X_PORT_SPEED(1)
-#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_PON_STRAP_FUNC		0x80320
 #define YT921X_PON_STRAP_VAL		0x80324
 #define YT921X_PON_STRAP_CAP		0x80328
@@ -121,11 +112,16 @@
 #define  YT921X_MDIO_POLLING_LINK		BIT(3)
 #define  YT921X_MDIO_POLLING_SPEED_M		GENMASK(2, 0)
 #define   YT921X_MDIO_POLLING_SPEED(x)			FIELD_PREP(YT921X_MDIO_POLLING_SPEED_M, (x))
-#define   YT921X_MDIO_POLLING_SPEED_10			YT921X_MDIO_POLLING_SPEED(0)
-#define   YT921X_MDIO_POLLING_SPEED_100			YT921X_MDIO_POLLING_SPEED(1)
-#define   YT921X_MDIO_POLLING_SPEED_1000		YT921X_MDIO_POLLING_SPEED(2)
-#define   YT921X_MDIO_POLLING_SPEED_10000		YT921X_MDIO_POLLING_SPEED(3)
-#define   YT921X_MDIO_POLLING_SPEED_2500		YT921X_MDIO_POLLING_SPEED(4)
+
+enum yt921x_speed {
+	YT921X_SPEED_10,
+	YT921X_SPEED_100,
+	YT921X_SPEED_1000,
+	YT921X_SPEED_10000,
+	YT921X_SPEED_2500,
+	YT921X_SPEED_NUM
+};
+
 #define YT921X_SENSOR			0x8036c
 #define  YT921X_SENSOR_TEMP			BIT(18)
 #define YT921X_TEMP			0x80374
@@ -247,27 +243,6 @@
 #define   YT9218_SYS_CLK_167M				0
 #define   YT921X_SYS_CLK_143M				1
 
-#define YT921X_EXT_MBUS_OP		0x6a000
-#define YT921X_INT_MBUS_OP		0xf0000
-#define  YT921X_MBUS_OP_START			BIT(0)
-#define YT921X_EXT_MBUS_CTRL		0x6a004
-#define YT921X_INT_MBUS_CTRL		0xf0004
-#define  YT921X_MBUS_CTRL_PORT_M		GENMASK(25, 21)
-#define   YT921X_MBUS_CTRL_PORT(x)			FIELD_PREP(YT921X_MBUS_CTRL_PORT_M, (x))
-#define  YT921X_MBUS_CTRL_REG_M			GENMASK(20, 16)
-#define   YT921X_MBUS_CTRL_REG(x)			FIELD_PREP(YT921X_MBUS_CTRL_REG_M, (x))
-#define  YT921X_MBUS_CTRL_TYPE_M		GENMASK(11, 8)  /* wild guess */
-#define   YT921X_MBUS_CTRL_TYPE(x)			FIELD_PREP(YT921X_MBUS_CTRL_TYPE_M, (x))
-#define   YT921X_MBUS_CTRL_TYPE_C22			YT921X_MBUS_CTRL_TYPE(4)
-#define  YT921X_MBUS_CTRL_OP_M			GENMASK(3, 2)  /* wild guess */
-#define   YT921X_MBUS_CTRL_OP(x)			FIELD_PREP(YT921X_MBUS_CTRL_OP_M, (x))
-#define   YT921X_MBUS_CTRL_WRITE			YT921X_MBUS_CTRL_OP(1)
-#define   YT921X_MBUS_CTRL_READ				YT921X_MBUS_CTRL_OP(2)
-#define YT921X_EXT_MBUS_DOUT		0x6a008
-#define YT921X_INT_MBUS_DOUT		0xf0008
-#define YT921X_EXT_MBUS_DIN		0x6a00c
-#define YT921X_INT_MBUS_DIN		0xf000c
-
 #define YT921X_PORTn_EGR(port)		(0x100000 + 4 * (port))
 #define  YT921X_PORT_EGR_TPID_CTAG_M		GENMASK(5, 4)
 #define   YT921X_PORT_EGR_TPID_CTAG(x)			FIELD_PREP(YT921X_PORT_EGR_TPID_CTAG_M, (x))
@@ -858,9 +833,6 @@ enum yt921x_fdb_entry_status {
 
 #define YT921X_NAME	"yt921x"
 
-#define yt921x_port_is_internal(port) ((port) < 8)
-#define yt921x_port_is_external(port) ((port) == 8 || (port) == 9)
-
 struct yt921x_mib {
 	u64 rx_broadcast;
 	u64 rx_pause;
@@ -936,8 +908,14 @@ struct yt921x_acl_blk {
 struct yt921x_port {
 	unsigned char index;
 
-	bool hairpin;
-	bool isolated;
+	/* SerDes in use */
+	bool serdes:1;
+	/* Link from in-band status (PHYLINK_PCS_NEG_INBAND) */
+	bool inband:1;
+	/* BR_HAIRPIN_MODE */
+	bool hairpin:1;
+	/* BR_ISOLATED */
+	bool isolated:1;
 
 	struct delayed_work mib_read;
 	struct yt921x_mib mib;
@@ -953,13 +931,30 @@ struct yt921x_port {
 
 	struct yt921x_led *leds[YT921X_LED_GROUP_NUM];
 #endif
+
+	struct phylink_pcs pcs;
 };
 
+#define pcs_to_yt921x_port(_pcs) container_of((_pcs), struct yt921x_port, pcs)
+
 struct yt921x_reg_ops {
 	int (*read)(void *context, u32 reg, u32 *valp);
 	int (*write)(void *context, u32 reg, u32 val);
 };
 
+struct yt921x_info {
+	const char *name;
+	u16 major;
+	/* Unknown, seems to be plain enumeration */
+	u8 mode;
+	u8 extmode;
+	/* Ports with integral GbE PHYs, not including MCU Port 10 */
+	u16 internal_mask;
+	/* Note: xmii_mask and serdes_mask may overlap */
+	u16 xmii_mask;
+	u16 serdes_mask;
+};
+
 struct yt921x_priv {
 	struct dsa_switch ds;
 
@@ -989,4 +984,25 @@ struct yt921x_priv {
 	struct yt921x_acl_blk *acl_blks[YT921X_ACL_BLK_NUM];
 };
 
+#define yt921x_port_to_priv(pp) \
+	container_of_const((pp), struct yt921x_priv, ports[(pp)->index])
+
+static inline int ethtool_speed_to_yt921x(int speed)
+{
+	switch (speed) {
+	case SPEED_10:
+		return YT921X_SPEED_10;
+	case SPEED_100:
+		return YT921X_SPEED_100;
+	case SPEED_1000:
+		return YT921X_SPEED_1000;
+	case SPEED_2500:
+		return YT921X_SPEED_2500;
+	case SPEED_10000:
+		return YT921X_SPEED_10000;
+	default:
+		return YT921X_SPEED_NUM;
+	}
+}
+
 #endif
diff --git a/drivers/net/dsa/motorcomm/leds.c b/drivers/net/dsa/motorcomm/leds.c
index 87a6b9cf60682..dd5b3684250db 100644
--- a/drivers/net/dsa/motorcomm/leds.c
+++ b/drivers/net/dsa/motorcomm/leds.c
@@ -12,8 +12,6 @@
 #define to_yt921x_led(led_cdev) \
 	container_of_const((led_cdev), struct yt921x_led, cdev)
 #define to_yt921x_port(led) ((led)->port)
-#define to_yt921x_priv(pp) \
-	container_of_const((pp), struct yt921x_priv, ports[(pp)->index])
 #define to_device(priv) ((priv)->ds.dev)
 
 static u32 yt921x_led_regaddr(struct yt921x_priv *priv, int port, int group)
@@ -321,7 +319,7 @@ yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,
 {
 	struct yt921x_led *led = to_yt921x_led(led_cdev);
 	struct yt921x_port *pp = to_yt921x_port(led);
-	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 	int res;
 
 	mutex_lock(&priv->reg_lock);
@@ -337,7 +335,7 @@ yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
 {
 	struct yt921x_led *led = to_yt921x_led(led_cdev);
 	struct yt921x_port *pp = to_yt921x_port(led);
-	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 	int res;
 
 	mutex_lock(&priv->reg_lock);
@@ -353,7 +351,7 @@ yt921x_cled_hw_control_get_device(struct led_classdev *led_cdev)
 {
 	struct yt921x_led *led = to_yt921x_led(led_cdev);
 	struct yt921x_port *pp = to_yt921x_port(led);
-	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 	struct dsa_port *dp;
 
 	dp = dsa_to_port(&priv->ds, pp->index);
@@ -374,7 +372,7 @@ yt921x_cled_hw_control_is_supported(struct led_classdev *led_cdev,
 {
 	struct yt921x_led *led = to_yt921x_led(led_cdev);
 	struct yt921x_port *pp = to_yt921x_port(led);
-	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 
 	if (yt921x_led_trigger_is_supported(priv, pp->index, led->group, flags))
 		return 0;
@@ -386,7 +384,7 @@ yt921x_cled_hw_control_get(struct led_classdev *led_cdev, unsigned long *flagsp)
 {
 	struct yt921x_led *led = to_yt921x_led(led_cdev);
 	struct yt921x_port *pp = to_yt921x_port(led);
-	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 	int res;
 
 	mutex_lock(&priv->reg_lock);
@@ -401,7 +399,7 @@ yt921x_cled_hw_control_set(struct led_classdev *led_cdev, unsigned long flags)
 {
 	struct yt921x_led *led = to_yt921x_led(led_cdev);
 	struct yt921x_port *pp = to_yt921x_port(led);
-	struct yt921x_priv *priv = to_yt921x_priv(pp);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
 	int res;
 
 	mutex_lock(&priv->reg_lock);
diff --git a/drivers/net/dsa/motorcomm/mdio_bus.c b/drivers/net/dsa/motorcomm/mdio_bus.c
new file mode 100644
index 0000000000000..1a3f3cc68275d
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/mdio_bus.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/of_mdio.h>
+
+#include "chip.h"
+#include "mdio_bus.h"
+#include "smi.h"
+
+#define to_device(priv) ((priv)->ds.dev)
+
+static int yt921x_intif_wait(struct yt921x_priv *priv)
+{
+	u32 val = 0;
+
+	return yt921x_reg_wait(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START,
+			       &val);
+}
+
+int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
+{
+	struct device *dev = to_device(priv);
+	u32 mask;
+	u32 ctrl;
+	u32 val;
+	int res;
+
+	res = yt921x_intif_wait(priv);
+	if (res)
+		return res;
+
+	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
+	       YT921X_MBUS_CTRL_OP_M;
+	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
+	       YT921X_MBUS_CTRL_READ;
+	res = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);
+	if (res)
+		return res;
+	res = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);
+	if (res)
+		return res;
+
+	res = yt921x_intif_wait(priv);
+	if (res)
+		return res;
+	res = yt921x_reg_read(priv, YT921X_INT_MBUS_DIN, &val);
+	if (res)
+		return res;
+
+	if ((u16)val != val)
+		dev_info(dev,
+			 "%s: port %d, reg 0x%x: Expected u16, got 0x%08x\n",
+			 __func__, port, reg, val);
+	*valp = (u16)val;
+	return 0;
+}
+
+int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val)
+{
+	u32 mask;
+	u32 ctrl;
+	int res;
+
+	res = yt921x_intif_wait(priv);
+	if (res)
+		return res;
+
+	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
+	       YT921X_MBUS_CTRL_OP_M;
+	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
+	       YT921X_MBUS_CTRL_WRITE;
+	res = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);
+	if (res)
+		return res;
+	res = yt921x_reg_write(priv, YT921X_INT_MBUS_DOUT, val);
+	if (res)
+		return res;
+	res = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);
+	if (res)
+		return res;
+
+	return yt921x_intif_wait(priv);
+}
+
+int
+yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,
+			    u16 mask, u16 val)
+{
+	int res;
+	u16 v;
+	u16 u;
+
+	res = yt921x_intif_read(priv, port, reg, &v);
+	if (res)
+		return res;
+
+	u = v;
+	u &= ~mask;
+	u |= val;
+	if (u == v)
+		return 0;
+
+	res = yt921x_intif_write(priv, port, reg, u);
+	if (res)
+		return res;
+
+	return 1;
+}
+
+static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)
+{
+	struct yt921x_priv *priv = mbus->priv;
+	u16 val;
+	int res;
+
+	if (port >= YT921X_PORT_NUM)
+		return U16_MAX;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_intif_read(priv, port, reg, &val);
+	mutex_unlock(&priv->reg_lock);
+
+	if (res)
+		return res;
+	return val;
+}
+
+static int
+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)
+		return -ENODEV;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_intif_write(priv, port, reg, data);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)
+{
+	struct device *dev = to_device(priv);
+	struct mii_bus *mbus;
+	int res;
+
+	mbus = devm_mdiobus_alloc(dev);
+	if (!mbus)
+		return -ENOMEM;
+
+	mbus->name = "YT921x internal MDIO bus";
+	snprintf(mbus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
+	mbus->priv = priv;
+	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);
+
+	res = devm_of_mdiobus_register(dev, mbus, mnp);
+	if (res)
+		return res;
+
+	priv->mbus_int = mbus;
+
+	return 0;
+}
+
+static int yt921x_extif_wait(struct yt921x_priv *priv)
+{
+	u32 val = 0;
+
+	return yt921x_reg_wait(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START,
+			       &val);
+}
+
+static int
+yt921x_extif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)
+{
+	struct device *dev = to_device(priv);
+	u32 mask;
+	u32 ctrl;
+	u32 val;
+	int res;
+
+	res = yt921x_extif_wait(priv);
+	if (res)
+		return res;
+
+	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
+	       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;
+	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
+	       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_READ;
+	res = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);
+	if (res)
+		return res;
+	res = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);
+	if (res)
+		return res;
+
+	res = yt921x_extif_wait(priv);
+	if (res)
+		return res;
+	res = yt921x_reg_read(priv, YT921X_EXT_MBUS_DIN, &val);
+	if (res)
+		return res;
+
+	if ((u16)val != val)
+		dev_info(dev,
+			 "%s: port %d, reg 0x%x: Expected u16, got 0x%08x\n",
+			 __func__, port, reg, val);
+	*valp = (u16)val;
+	return 0;
+}
+
+static int
+yt921x_extif_write(struct yt921x_priv *priv, int port, int reg, u16 val)
+{
+	u32 mask;
+	u32 ctrl;
+	int res;
+
+	res = yt921x_extif_wait(priv);
+	if (res)
+		return res;
+
+	mask = YT921X_MBUS_CTRL_PORT_M | YT921X_MBUS_CTRL_REG_M |
+	       YT921X_MBUS_CTRL_TYPE_M | YT921X_MBUS_CTRL_OP_M;
+	ctrl = YT921X_MBUS_CTRL_PORT(port) | YT921X_MBUS_CTRL_REG(reg) |
+	       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_WRITE;
+	res = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);
+	if (res)
+		return res;
+	res = yt921x_reg_write(priv, YT921X_EXT_MBUS_DOUT, val);
+	if (res)
+		return res;
+	res = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);
+	if (res)
+		return res;
+
+	return yt921x_extif_wait(priv);
+}
+
+static int yt921x_mbus_ext_read(struct mii_bus *mbus, int port, int reg)
+{
+	struct yt921x_priv *priv = mbus->priv;
+	u16 val;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_extif_read(priv, port, reg, &val);
+	mutex_unlock(&priv->reg_lock);
+
+	if (res)
+		return res;
+	return val;
+}
+
+static int
+yt921x_mbus_ext_write(struct mii_bus *mbus, int port, int reg, u16 data)
+{
+	struct yt921x_priv *priv = mbus->priv;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_extif_write(priv, port, reg, data);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)
+{
+	struct device *dev = to_device(priv);
+	struct mii_bus *mbus;
+	int res;
+
+	mbus = devm_mdiobus_alloc(dev);
+	if (!mbus)
+		return -ENOMEM;
+
+	mbus->name = "YT921x external MDIO bus";
+	snprintf(mbus->id, MII_BUS_ID_SIZE, "%s@ext", dev_name(dev));
+	mbus->priv = priv;
+	/* TODO: c45? */
+	mbus->read = yt921x_mbus_ext_read;
+	mbus->write = yt921x_mbus_ext_write;
+	mbus->parent = dev;
+
+	res = devm_of_mdiobus_register(dev, mbus, mnp);
+	if (res)
+		return res;
+
+	priv->mbus_ext = mbus;
+
+	return 0;
+}
diff --git a/drivers/net/dsa/motorcomm/mdio_bus.h b/drivers/net/dsa/motorcomm/mdio_bus.h
new file mode 100644
index 0000000000000..e79b725d435bd
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/mdio_bus.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_MDIO_BUS_H
+#define _YT_MDIO_BUS_H
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/of.h>
+
+#define YT921X_EXT_MBUS_OP		0x6a000
+#define YT921X_INT_MBUS_OP		0xf0000
+#define  YT921X_MBUS_OP_START			BIT(0)
+#define YT921X_EXT_MBUS_CTRL		0x6a004
+#define YT921X_INT_MBUS_CTRL		0xf0004
+#define  YT921X_MBUS_CTRL_PORT_M		GENMASK(25, 21)
+#define   YT921X_MBUS_CTRL_PORT(x)			FIELD_PREP(YT921X_MBUS_CTRL_PORT_M, (x))
+#define  YT921X_MBUS_CTRL_REG_M			GENMASK(20, 16)
+#define   YT921X_MBUS_CTRL_REG(x)			FIELD_PREP(YT921X_MBUS_CTRL_REG_M, (x))
+#define  YT921X_MBUS_CTRL_TYPE_M		GENMASK(11, 8)  /* wild guess */
+#define   YT921X_MBUS_CTRL_TYPE(x)			FIELD_PREP(YT921X_MBUS_CTRL_TYPE_M, (x))
+#define   YT921X_MBUS_CTRL_TYPE_C22			YT921X_MBUS_CTRL_TYPE(4)
+#define  YT921X_MBUS_CTRL_OP_M			GENMASK(3, 2)  /* wild guess */
+#define   YT921X_MBUS_CTRL_OP(x)			FIELD_PREP(YT921X_MBUS_CTRL_OP_M, (x))
+#define   YT921X_MBUS_CTRL_WRITE			YT921X_MBUS_CTRL_OP(1)
+#define   YT921X_MBUS_CTRL_READ				YT921X_MBUS_CTRL_OP(2)
+#define YT921X_EXT_MBUS_DOUT		0x6a008
+#define YT921X_INT_MBUS_DOUT		0xf0008
+#define YT921X_EXT_MBUS_DIN		0x6a00c
+#define YT921X_INT_MBUS_DIN		0xf000c
+
+struct yt921x_priv;
+
+int yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp);
+int yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val);
+int yt921x_intif_modify_changed(struct yt921x_priv *priv, int port, int reg,
+				u16 mask, u16 val);
+
+static inline int
+yt921x_intif_modify(struct yt921x_priv *priv, int port, int reg, u16 mask,
+		    u16 val)
+{
+	int res;
+
+	res = yt921x_intif_modify_changed(priv, port, reg, mask, val);
+	return res >= 0 ? 0 : res;
+}
+
+int yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp);
+int yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp);
+
+#endif
diff --git a/drivers/net/dsa/motorcomm/pcs-921x.c b/drivers/net/dsa/motorcomm/pcs-921x.c
new file mode 100644
index 0000000000000..dcf7397cd2413
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/pcs-921x.c
@@ -0,0 +1,235 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include "chip.h"
+#include "mdio_bus.h"
+#include "pcs.h"
+#include "smi.h"
+
+#define to_device(priv) ((priv)->ds.dev)
+
+static int
+yt921x_serdes_config(struct yt921x_priv *priv, int port, unsigned int neg_mode,
+		     phy_interface_t interface,
+		     const unsigned long *advertising, bool permit_pause_to_mac)
+{
+	bool inband = neg_mode & PHYLINK_PCS_NEG_INBAND;
+	struct yt921x_port *pp = &priv->ports[port];
+	bool changed = false;
+	u16 bmcr;
+	u32 mask;
+	u32 ctrl;
+	u16 val;
+	int adv;
+	int res;
+
+	switch (interface) {
+	case PHY_INTERFACE_MODE_SGMII:
+		ctrl = YT921X_SERDES_MODE_SGMII;
+		break;
+	case PHY_INTERFACE_MODE_100BASEX:
+		ctrl = YT921X_SERDES_MODE_100BASEX;
+		break;
+	case PHY_INTERFACE_MODE_1000BASEX:
+		ctrl = YT921X_SERDES_MODE_1000BASEX;
+		break;
+	case PHY_INTERFACE_MODE_2500BASEX:
+		ctrl = YT921X_SERDES_MODE_2500BASEX;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	res = yt921x_reg_update_bits(priv, YT921X_SERDESn(port),
+				     YT921X_SERDES_MODE_M, ctrl);
+	if (res)
+		return res;
+
+	mask = YT921X_PORT_CTRL_LINK_AN | YT921X_PORT_CTRL_PAUSE_AN;
+	ctrl = 0;
+	if (inband)
+		ctrl |= YT921X_PORT_CTRL_LINK_AN;
+	if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED && permit_pause_to_mac)
+		ctrl |= YT921X_PORT_CTRL_PAUSE_AN;
+	res = yt921x_reg_update_bits(priv, YT921X_PORTn_CTRL(port), mask, ctrl);
+	if (res)
+		return res;
+
+	if (inband) {
+		res = yt921x_reg_clear_bits(priv, YT921X_SERDESn(port),
+					    YT921X_SERDES_LINK);
+		if (res)
+			return res;
+	}
+
+	adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);
+	if (adv >= 0) {
+		res = yt921x_intif_modify_changed(priv, port, MII_ADVERTISE,
+						  U16_MAX, adv);
+		if (res < 0)
+			return res;
+
+		changed = !!res;
+	}
+
+	res = yt921x_intif_read(priv, port, MII_BMCR, &val);
+	if (res)
+		return res;
+
+	bmcr = val;
+	if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
+		bmcr |= BMCR_ANENABLE;
+	else
+		bmcr &= ~BMCR_ANENABLE;
+
+	/* If the ANENABLE bit was changed, the PHY will restart negotiation,
+	 * so we don't need to flag a change to trigger its own restart.
+	 */
+	if (bmcr != val)
+		changed = false;
+
+	bmcr &= ~BMCR_ISOLATE;
+	res = yt921x_intif_write(priv, port, MII_BMCR, bmcr);
+	if (res)
+		return res;
+
+	pp->inband = inband;
+	return changed;
+}
+
+static unsigned int
+yt921x_phylink_pcs_inband_caps(struct phylink_pcs *pcs,
+			       phy_interface_t interface)
+{
+	return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
+}
+
+static void
+yt921x_phylink_pcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
+			     struct phylink_link_state *state)
+{
+	struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+	struct device *dev = to_device(priv);
+	int port = pp->index;
+	u16 bmsr;
+	u16 lpa;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+
+	res = yt921x_intif_read(priv, port, MII_BMSR, &bmsr);
+	if (res)
+		goto out;
+
+	res = yt921x_intif_read(priv, port, MII_LPA, &lpa);
+
+out:
+	mutex_unlock(&priv->reg_lock);
+
+	if (res) {
+		dev_err(dev, "Failed to %s PCS port %d: %i\n", "get state of",
+			port, res);
+		state->link = false;
+		return;
+	}
+
+	phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);
+}
+
+static void yt921x_phylink_pcs_an_restart(struct phylink_pcs *pcs)
+{
+	struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+	struct device *dev = to_device(priv);
+	int port = pp->index;
+	u16 val;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+
+	res = yt921x_intif_read(priv, port, MII_BMCR, &val);
+	if (res)
+		goto end;
+
+	val |= BMCR_ANRESTART;
+	res = yt921x_intif_write(priv, port, MII_BMCR, val);
+
+end:
+	mutex_unlock(&priv->reg_lock);
+
+	if (res)
+		dev_err(dev, "Failed to %s PCS port %d: %i\n", "restart",
+			port, res);
+}
+
+static void yt921x_phylink_pcs_disable(struct phylink_pcs *pcs)
+{
+	struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+	struct device *dev = to_device(priv);
+	int port = pp->index;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_intif_modify(priv, port, MII_BMCR, BMCR_PDOWN, BMCR_PDOWN);
+	mutex_unlock(&priv->reg_lock);
+
+	if (res)
+		dev_err(dev, "Failed to %s PCS port %d: %i\n", "power down",
+			port, res);
+}
+
+static int yt921x_phylink_pcs_enable(struct phylink_pcs *pcs)
+{
+	struct yt921x_port *pp = pcs_to_yt921x_port(pcs);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+	int port = pp->index;
+	u16 val;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+
+	res = yt921x_intif_read(priv, port, MII_BMCR, &val);
+	if (res)
+		goto end;
+
+	val &= ~BMCR_PDOWN;
+	val |= BMCR_ANRESTART;
+	res = yt921x_intif_write(priv, port, MII_BMCR, val);
+
+end:
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int
+yt921x_phylink_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_port *pp = pcs_to_yt921x_port(pcs);
+	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
+	int port = pp->index;
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_serdes_config(priv, port, neg_mode, interface,
+				   advertising, permit_pause_to_mac);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+const struct phylink_pcs_ops yt921x_phylink_pcs_ops = {
+	.pcs_inband_caps	= yt921x_phylink_pcs_inband_caps,
+	.pcs_get_state		= yt921x_phylink_pcs_get_state,
+	.pcs_an_restart		= yt921x_phylink_pcs_an_restart,
+	.pcs_disable		= yt921x_phylink_pcs_disable,
+	.pcs_enable		= yt921x_phylink_pcs_enable,
+	.pcs_config		= yt921x_phylink_pcs_config,
+};
diff --git a/drivers/net/dsa/motorcomm/pcs.h b/drivers/net/dsa/motorcomm/pcs.h
new file mode 100644
index 0000000000000..42426558086af
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/pcs.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_PCS_H
+#define _YT_PCS_H
+
+#include <linux/phylink.h>
+
+extern const struct phylink_pcs_ops yt921x_phylink_pcs_ops;
+
+#endif

3/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 24762
							output: 34
							thoughts: 205
						

Thoughts:
**Fuzzing Evaluation for a Motorcomm YT921x Ethernet Switch Driver Patch**

Okay, so I've got a patch series here, and the question is whether it's worth the time to run it through syzkaller. My first instinct is to dive into the changes themselves. Let's see... it's touching the `drivers/net/dsa/motorcomm/` directory. Specifically, I'm seeing modifications to the `Makefile`, `chip.c`, `chip.h`, `leds.c`, and, importantly, two new files: `mdio_bus.c`, `mdio_bus.h`, `pcs-921x.c` and `pcs.h`. That alone makes me perk up; new files are often a good indicator of potential fuzzing targets.

Now, let's establish context. This is the Motorcomm YT921x ethernet switch driver – DSA, distributed switch architecture. Right, so we're dealing with network hardware. But I need to figure out the fundamental bus type for this device. Is it MDIO, which is suggested by the new files? Or maybe SPI? I2C? Platform? How does the YT921x get probed and registered with the kernel? I need to search for how the device is hooked into the kernel to understand the attack surface. That's where I need to start digging to assess the potential impact and identify entry points for syzkaller.



4/2 2026/09/19 23:04 tool grepper
0m Args:
{
  "Expression": "yt921x",
  "PathPrefix": "drivers/net/dsa/motorcomm"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 2746 lines.\nUse more precise expression if possible.\n\ndrivers/net/dsa/motorcomm/Makefile-1-# SPDX-License-Identifier: GPL-2.0\ndrivers/net/dsa/motorcomm/Makefile:2:obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o\ndrivers/net/dsa/motorcomm/Makefile:3:yt921x-objs := chip.o\ndrivers/net/dsa/motorcomm/Makefile:4:yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o\ndrivers/net/dsa/motorcomm/Makefile:5:yt921x-objs += mdio_bus.o\ndrivers/net/dsa/motorcomm/Makefile:6:yt921x-objs += pcs-921x.o\ndrivers/net/dsa/motorcomm/Makefile:7:yt921x-objs += smi.o\n--\ndrivers/net/dsa/motorcomm/chip.c-33-\ndrivers/net/dsa/motorcomm/chip.c:34:struct yt921x_mib_desc {\ndrivers/net/dsa/motorcomm/chip.c-35-\tunsigned int size;\n--\ndrivers/net/dsa/motorcomm/chip.c-42-\ndrivers/net/dsa/motorcomm/chip.c:43:/* Must agree with yt921x_mib\ndrivers/net/dsa/motorcomm/chip.c-44- *\n--\ndrivers/net/dsa/motorcomm/chip.c-48- */\ndrivers/net/dsa/motorcomm/chip.c:49:static const struct yt921x_mib_desc yt921x_mib_descs[] = {\ndrivers/net/dsa/motorcomm/chip.c-50-\tMIB_DESC(1, YT921X_MIB_DATA_RX_BROADCAST, NULL),\n--\ndrivers/net/dsa/motorcomm/chip.c-100-\ndrivers/net/dsa/motorcomm/chip.c:101:static const struct yt921x_info yt921x_infos[] = {\ndrivers/net/dsa/motorcomm/chip.c-102-\t{\n--\ndrivers/net/dsa/motorcomm/chip.c-156-\ndrivers/net/dsa/motorcomm/chip.c:157:struct yt921x_reg_mdio {\ndrivers/net/dsa/motorcomm/chip.c-158-\tstruct mii_bus *bus;\n--\ndrivers/net/dsa/motorcomm/chip.c-173-\ndrivers/net/dsa/motorcomm/chip.c:174:#define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds)\ndrivers/net/dsa/motorcomm/chip.c-175-#define to_device(priv) ((priv)-\u003eds.dev)\n--\ndrivers/net/dsa/motorcomm/chip.c=182=static u32 ethaddr_lo2_to_u32(const unsigned char *addr)\n--\ndrivers/net/dsa/motorcomm/chip.c-186-\ndrivers/net/dsa/motorcomm/chip.c:187:static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)\ndrivers/net/dsa/motorcomm/chip.c-188-{\ndrivers/net/dsa/motorcomm/chip.c:189:\tstruct yt921x_reg_mdio *mdio = context;\ndrivers/net/dsa/motorcomm/chip.c-190-\tstruct mii_bus *bus = mdio-\u003ebus;\n--\ndrivers/net/dsa/motorcomm/chip.c-227-\ndrivers/net/dsa/motorcomm/chip.c:228:static int yt921x_reg_mdio_write(void *context, u32 reg, u32 val)\ndrivers/net/dsa/motorcomm/chip.c-229-{\ndrivers/net/dsa/motorcomm/chip.c:230:\tstruct yt921x_reg_mdio *mdio = context;\ndrivers/net/dsa/motorcomm/chip.c-231-\tstruct mii_bus *bus = mdio-\u003ebus;\n--\ndrivers/net/dsa/motorcomm/chip.c-263-\ndrivers/net/dsa/motorcomm/chip.c:264:static const struct yt921x_reg_ops yt921x_reg_ops_mdio = {\ndrivers/net/dsa/motorcomm/chip.c:265:\t.read = yt921x_reg_mdio_read,\ndrivers/net/dsa/motorcomm/chip.c:266:\t.write = yt921x_reg_mdio_write,\ndrivers/net/dsa/motorcomm/chip.c-267-};\n--\ndrivers/net/dsa/motorcomm/chip.c-271-/* Read and handle overflow of 32bit MIBs. MIB buffer must be zeroed before. */\ndrivers/net/dsa/motorcomm/chip.c:272:static int yt921x_read_mib(struct yt921x_priv *priv, int port)\ndrivers/net/dsa/motorcomm/chip.c-273-{\ndrivers/net/dsa/motorcomm/chip.c:274:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c-275-\tstruct device *dev = to_device(priv);\ndrivers/net/dsa/motorcomm/chip.c:276:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-277-\tint res = 0;\ndrivers/net/dsa/motorcomm/chip.c-278-\ndrivers/net/dsa/motorcomm/chip.c:279:\t/* Reading of yt921x_port::mib is not protected by a lock and it's vain\ndrivers/net/dsa/motorcomm/chip.c-280-\t * to keep its consistency, since we have to read registers one by one\n--\ndrivers/net/dsa/motorcomm/chip.c-286-\ndrivers/net/dsa/motorcomm/chip.c:287:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:288:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-289-\t\tu32 reg = YT921X_MIBn_DATA0(port) + desc-\u003eoffset;\n--\ndrivers/net/dsa/motorcomm/chip.c-293-\ndrivers/net/dsa/motorcomm/chip.c:294:\t\tres = yt921x_reg_read(priv, reg, \u0026val0);\ndrivers/net/dsa/motorcomm/chip.c-295-\t\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-306-\ndrivers/net/dsa/motorcomm/chip.c:307:\t\t\tres = yt921x_reg_read(priv, reg + 4, \u0026val1);\ndrivers/net/dsa/motorcomm/chip.c-308-\t\t\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-330-\ndrivers/net/dsa/motorcomm/chip.c:331:static void yt921x_poll_mib(struct work_struct *work)\ndrivers/net/dsa/motorcomm/chip.c-332-{\ndrivers/net/dsa/motorcomm/chip.c:333:\tstruct yt921x_port *pp = container_of_const(work, struct yt921x_port,\ndrivers/net/dsa/motorcomm/chip.c-334-\t\t\t\t\t\t    mib_read.work);\ndrivers/net/dsa/motorcomm/chip.c-335-\tunsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;\ndrivers/net/dsa/motorcomm/chip.c:336:\tstruct yt921x_priv *priv = yt921x_port_to_priv(pp);\ndrivers/net/dsa/motorcomm/chip.c-337-\tint port = pp-\u003eindex;\n--\ndrivers/net/dsa/motorcomm/chip.c-340-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:341:\tres = yt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-342-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=349=static void\ndrivers/net/dsa/motorcomm/chip.c:350:yt921x_dsa_get_strings(struct dsa_switch *ds, int port, u32 stringset,\ndrivers/net/dsa/motorcomm/chip.c-351-\t\t       uint8_t *data)\n--\ndrivers/net/dsa/motorcomm/chip.c-355-\ndrivers/net/dsa/motorcomm/chip.c:356:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:357:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-358-\n--\ndrivers/net/dsa/motorcomm/chip.c=364=static void\ndrivers/net/dsa/motorcomm/chip.c:365:yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)\ndrivers/net/dsa/motorcomm/chip.c-366-{\ndrivers/net/dsa/motorcomm/chip.c:367:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:368:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:369:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-370-\tsize_t j;\n--\ndrivers/net/dsa/motorcomm/chip.c-372-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:373:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-374-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c-376-\tj = 0;\ndrivers/net/dsa/motorcomm/chip.c:377:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:378:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-379-\n--\ndrivers/net/dsa/motorcomm/chip.c-387-\ndrivers/net/dsa/motorcomm/chip.c:388:static int yt921x_dsa_get_sset_count(struct dsa_switch *ds, int port, int sset)\ndrivers/net/dsa/motorcomm/chip.c-389-{\n--\ndrivers/net/dsa/motorcomm/chip.c-394-\ndrivers/net/dsa/motorcomm/chip.c:395:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:396:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-397-\n--\ndrivers/net/dsa/motorcomm/chip.c=405=static void\ndrivers/net/dsa/motorcomm/chip.c:406:yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-407-\t\t\t     struct ethtool_eth_mac_stats *mac_stats)\ndrivers/net/dsa/motorcomm/chip.c-408-{\ndrivers/net/dsa/motorcomm/chip.c:409:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:410:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:411:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-412-\ndrivers/net/dsa/motorcomm/chip.c-413-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:414:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-415-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=441=static void\ndrivers/net/dsa/motorcomm/chip.c:442:yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-443-\t\t\t      struct ethtool_eth_ctrl_stats *ctrl_stats)\ndrivers/net/dsa/motorcomm/chip.c-444-{\ndrivers/net/dsa/motorcomm/chip.c:445:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:446:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:447:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-448-\ndrivers/net/dsa/motorcomm/chip.c-449-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:450:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-451-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c-457-\ndrivers/net/dsa/motorcomm/chip.c:458:static const struct ethtool_rmon_hist_range yt921x_rmon_ranges[] = {\ndrivers/net/dsa/motorcomm/chip.c-459-\t{ 0, 64 },\n--\ndrivers/net/dsa/motorcomm/chip.c=469=static void\ndrivers/net/dsa/motorcomm/chip.c:470:yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-471-\t\t\t  struct ethtool_rmon_stats *rmon_stats,\n--\ndrivers/net/dsa/motorcomm/chip.c-473-{\ndrivers/net/dsa/motorcomm/chip.c:474:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:475:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:476:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-477-\ndrivers/net/dsa/motorcomm/chip.c-478-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:479:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-480-\tmutex_unlock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c-481-\ndrivers/net/dsa/motorcomm/chip.c:482:\t*ranges = yt921x_rmon_ranges;\ndrivers/net/dsa/motorcomm/chip.c-483-\n--\ndrivers/net/dsa/motorcomm/chip.c=506=static void\ndrivers/net/dsa/motorcomm/chip.c:507:yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-508-\t\t       struct rtnl_link_stats64 *stats)\ndrivers/net/dsa/motorcomm/chip.c-509-{\ndrivers/net/dsa/motorcomm/chip.c:510:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:511:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:512:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-513-\n--\ndrivers/net/dsa/motorcomm/chip.c=542=static void\ndrivers/net/dsa/motorcomm/chip.c:543:yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-544-\t\t\t   struct ethtool_pause_stats *pause_stats)\ndrivers/net/dsa/motorcomm/chip.c-545-{\ndrivers/net/dsa/motorcomm/chip.c:546:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:547:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:548:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-549-\ndrivers/net/dsa/motorcomm/chip.c-550-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:551:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-552-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=558=static int\ndrivers/net/dsa/motorcomm/chip.c:559:yt921x_set_eee(struct yt921x_priv *priv, int port, struct ethtool_keee *e)\ndrivers/net/dsa/motorcomm/chip.c-560-{\n--\ndrivers/net/dsa/motorcomm/chip.c-572-\tif (!!new_mask != !!priv-\u003eeee_ports_mask) {\ndrivers/net/dsa/motorcomm/chip.c:573:\t\tres = yt921x_reg_toggle_bits(priv, YT921X_PON_STRAP_FUNC,\ndrivers/net/dsa/motorcomm/chip.c-574-\t\t\t\t\t     YT921X_PON_STRAP_EEE, !!new_mask);\n--\ndrivers/net/dsa/motorcomm/chip.c-576-\t\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:577:\t\tres = yt921x_reg_toggle_bits(priv, YT921X_PON_STRAP_VAL,\ndrivers/net/dsa/motorcomm/chip.c-578-\t\t\t\t\t     YT921X_PON_STRAP_EEE, !!new_mask);\n--\ndrivers/net/dsa/motorcomm/chip.c-585-\t/* Enable / disable port EEE */\ndrivers/net/dsa/motorcomm/chip.c:586:\tres = yt921x_reg_toggle_bits(priv, YT921X_EEE_CTRL,\ndrivers/net/dsa/motorcomm/chip.c-587-\t\t\t\t     YT921X_EEE_CTRL_ENn(port), enable);\n--\ndrivers/net/dsa/motorcomm/chip.c-589-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:590:\tres = yt921x_reg_toggle_bits(priv, YT921X_EEEn_VAL(port),\ndrivers/net/dsa/motorcomm/chip.c-591-\t\t\t\t     YT921X_EEE_VAL_DATA, enable);\n--\ndrivers/net/dsa/motorcomm/chip.c=598=static int\ndrivers/net/dsa/motorcomm/chip.c:599:yt921x_dsa_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)\ndrivers/net/dsa/motorcomm/chip.c-600-{\ndrivers/net/dsa/motorcomm/chip.c:601:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-602-\tint res;\n--\ndrivers/net/dsa/motorcomm/chip.c-604-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:605:\tres = yt921x_set_eee(priv, port, e);\ndrivers/net/dsa/motorcomm/chip.c-606-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c-610-\ndrivers/net/dsa/motorcomm/chip.c:611:static int yt921x_mtu_fetch(struct yt921x_priv *priv, int port)\ndrivers/net/dsa/motorcomm/chip.c-612-{\n--\ndrivers/net/dsa/motorcomm/chip.c=618=static int\ndrivers/net/dsa/motorcomm/chip.c:619:yt921x_dsa_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\ndrivers/net/dsa/motorcomm/chip.c-620-{\n--\ndrivers/net/dsa/motorcomm/chip.c-624-\ndrivers/net/dsa/motorcomm/chip.c:625:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-626-\tstruct dsa_port *dp = dsa_to_port(ds, port);\n--\ndrivers/net/dsa/motorcomm/chip.c-634-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:635:\tres = yt921x_reg_update_bits(priv, YT921X_MACn_FRAME(port),\ndrivers/net/dsa/motorcomm/chip.c-636-\t\t\t\t     YT921X_MAC_FRAME_SIZE_M,\n--\ndrivers/net/dsa/motorcomm/chip.c-642-\ndrivers/net/dsa/motorcomm/chip.c:643:static int yt921x_dsa_port_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/motorcomm/chip.c-644-{\n--\ndrivers/net/dsa/motorcomm/chip.c=676=static u64 token2burst(u32 token, int unit, int C)\n--\ndrivers/net/dsa/motorcomm/chip.c-680-\ndrivers/net/dsa/motorcomm/chip.c:681:struct yt921x_marker {\ndrivers/net/dsa/motorcomm/chip.c-682-\tu32 cir;\n--\ndrivers/net/dsa/motorcomm/chip.c=692=static int\ndrivers/net/dsa/motorcomm/chip.c:693:yt921x_marker_tfm(struct yt921x_marker *marker, u64 rate, u64 burst,\ndrivers/net/dsa/motorcomm/chip.c-694-\t\t  unsigned int flags, unsigned int slot_ns, u32 cir_max,\ndrivers/net/dsa/motorcomm/chip.c:695:\t\t  u32 cbs_max, int unit_max, struct yt921x_priv *priv, int port,\ndrivers/net/dsa/motorcomm/chip.c-696-\t\t  struct netlink_ext_ack *extack)\n--\ndrivers/net/dsa/motorcomm/chip.c-700-\tstruct device *dev = to_device(priv);\ndrivers/net/dsa/motorcomm/chip.c:701:\tstruct yt921x_marker m;\ndrivers/net/dsa/motorcomm/chip.c-702-\tu64 burst_est;\n--\ndrivers/net/dsa/motorcomm/chip.c-722-\telse\ndrivers/net/dsa/motorcomm/chip.c:723:\t\tburst_sug += ETH_HLEN + yt921x_mtu_fetch(priv, port) +\ndrivers/net/dsa/motorcomm/chip.c-724-\t\t\t     ETH_FCS_LEN;\n--\ndrivers/net/dsa/motorcomm/chip.c=782=static int\ndrivers/net/dsa/motorcomm/chip.c:783:yt921x_marker_tfm_police(struct yt921x_marker *marker,\ndrivers/net/dsa/motorcomm/chip.c-784-\t\t\t const struct flow_action_police *police,\ndrivers/net/dsa/motorcomm/chip.c:785:\t\t\t unsigned int flags, struct yt921x_priv *priv, int port,\ndrivers/net/dsa/motorcomm/chip.c-786-\t\t\t struct netlink_ext_ack *extack)\n--\ndrivers/net/dsa/motorcomm/chip.c-796-\ndrivers/net/dsa/motorcomm/chip.c:797:\treturn yt921x_marker_tfm(marker, rate, burst, flags,\ndrivers/net/dsa/motorcomm/chip.c-798-\t\t\t\t priv-\u003emeter_slot_ns, YT921X_METER_CIR_MAX,\n--\ndrivers/net/dsa/motorcomm/chip.c=803=static int\ndrivers/net/dsa/motorcomm/chip.c:804:yt921x_marker_tfm_shape(struct yt921x_marker *marker, u64 rate, u64 burst,\ndrivers/net/dsa/motorcomm/chip.c:805:\t\t\tunsigned int flags, struct yt921x_priv *priv, int port,\ndrivers/net/dsa/motorcomm/chip.c-806-\t\t\tstruct netlink_ext_ack *extack)\ndrivers/net/dsa/motorcomm/chip.c-807-{\ndrivers/net/dsa/motorcomm/chip.c:808:\treturn yt921x_marker_tfm(marker, rate, burst, flags,\ndrivers/net/dsa/motorcomm/chip.c-809-\t\t\t\t priv-\u003eport_shape_slot_ns, YT921X_SHAPE_CIR_MAX,\n--\ndrivers/net/dsa/motorcomm/chip.c=814=static int\ndrivers/net/dsa/motorcomm/chip.c:815:yt921x_police_validate(const struct flow_action_police *police,\ndrivers/net/dsa/motorcomm/chip.c-816-\t\t       const struct flow_action *action,\n--\ndrivers/net/dsa/motorcomm/chip.c=850=static int\ndrivers/net/dsa/motorcomm/chip.c:851:yt921x_meter_config(struct yt921x_priv *priv, unsigned int id,\ndrivers/net/dsa/motorcomm/chip.c:852:\t\t    const struct yt921x_marker *marker)\ndrivers/net/dsa/motorcomm/chip.c-853-{\n--\ndrivers/net/dsa/motorcomm/chip.c-870-\ndrivers/net/dsa/motorcomm/chip.c:871:\treturn yt921x_reg96_write(priv, YT921X_METERn_CTRL(id), ctrls);\ndrivers/net/dsa/motorcomm/chip.c-872-}\ndrivers/net/dsa/motorcomm/chip.c-873-\ndrivers/net/dsa/motorcomm/chip.c:874:static void yt921x_dsa_port_policer_del(struct dsa_switch *ds, int port)\ndrivers/net/dsa/motorcomm/chip.c-875-{\ndrivers/net/dsa/motorcomm/chip.c:876:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-877-\tstruct device *dev = to_device(priv);\n--\ndrivers/net/dsa/motorcomm/chip.c-880-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:881:\tres = yt921x_reg_write(priv, YT921X_PORTn_METER(port), 0);\ndrivers/net/dsa/motorcomm/chip.c-882-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=889=static int\ndrivers/net/dsa/motorcomm/chip.c:890:yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-891-\t\t\t    const struct flow_action_police *police,\n--\ndrivers/net/dsa/motorcomm/chip.c-893-{\ndrivers/net/dsa/motorcomm/chip.c:894:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:895:\tstruct yt921x_marker marker;\ndrivers/net/dsa/motorcomm/chip.c-896-\tu32 ctrl;\n--\ndrivers/net/dsa/motorcomm/chip.c-898-\ndrivers/net/dsa/motorcomm/chip.c:899:\tres = yt921x_police_validate(police, NULL, NULL, extack);\ndrivers/net/dsa/motorcomm/chip.c-900-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-902-\ndrivers/net/dsa/motorcomm/chip.c:903:\tres = yt921x_marker_tfm_police(\u0026marker, police, 0, priv, port, extack);\ndrivers/net/dsa/motorcomm/chip.c-904-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-907-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:908:\tres = yt921x_meter_config(priv, port + YT921X_METER_NUM, \u0026marker);\ndrivers/net/dsa/motorcomm/chip.c-909-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-912-\tctrl = YT921X_PORT_METER_ID(port) | YT921X_PORT_METER_EN;\ndrivers/net/dsa/motorcomm/chip.c:913:\tres = yt921x_reg_write(priv, YT921X_PORTn_METER(port), ctrl);\ndrivers/net/dsa/motorcomm/chip.c-914-end:\n--\ndrivers/net/dsa/motorcomm/chip.c=920=static int\ndrivers/net/dsa/motorcomm/chip.c:921:yt921x_dsa_port_setup_tc_tbf_port(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-922-\t\t\t\t  const struct tc_tbf_qopt_offload *qopt)\ndrivers/net/dsa/motorcomm/chip.c-923-{\ndrivers/net/dsa/motorcomm/chip.c:924:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-925-\tstruct netlink_ext_ack *extack = qopt-\u003eextack;\n--\ndrivers/net/dsa/motorcomm/chip.c-943-\t\tconst struct tc_tbf_qopt_offload_replace_params *p;\ndrivers/net/dsa/motorcomm/chip.c:944:\t\tstruct yt921x_marker marker;\ndrivers/net/dsa/motorcomm/chip.c-945-\n--\ndrivers/net/dsa/motorcomm/chip.c-947-\ndrivers/net/dsa/motorcomm/chip.c:948:\t\tres = yt921x_marker_tfm_shape(\u0026marker, p-\u003erate.rate_bytes_ps,\ndrivers/net/dsa/motorcomm/chip.c-949-\t\t\t\t\t      p-\u003emax_size,\n--\ndrivers/net/dsa/motorcomm/chip.c-965-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:966:\tres = yt921x_reg64_write(priv, YT921X_PORTn_SHAPE_CTRL(port), ctrls);\ndrivers/net/dsa/motorcomm/chip.c-967-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=972=static int\ndrivers/net/dsa/motorcomm/chip.c:973:yt921x_dsa_port_setup_tc(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-974-\t\t\t enum tc_setup_type type, void *type_data)\n--\ndrivers/net/dsa/motorcomm/chip.c-979-\ndrivers/net/dsa/motorcomm/chip.c:980:\t\treturn yt921x_dsa_port_setup_tc_tbf_port(ds, port, qopt);\ndrivers/net/dsa/motorcomm/chip.c-981-\t}\n--\ndrivers/net/dsa/motorcomm/chip.c=992=static void\ndrivers/net/dsa/motorcomm/chip.c:993:yt921x_acl_entry_set(struct yt921x_acl_entry *entry, unsigned int offset,\ndrivers/net/dsa/motorcomm/chip.c-994-\t\t     u32 flags, bool set)\n--\ndrivers/net/dsa/motorcomm/chip.c=1001=static unsigned int\ndrivers/net/dsa/motorcomm/chip.c:1002:yt921x_acl_entries_set_is_fragment(struct yt921x_acl_entry *entries,\ndrivers/net/dsa/motorcomm/chip.c-1003-\t\t\t\t   unsigned int size, bool set)\n--\ndrivers/net/dsa/motorcomm/chip.c-1008-\t\tcase YT921X_ACL_TYPE_IPV4_SA:\ndrivers/net/dsa/motorcomm/chip.c:1009:\t\t\tyt921x_acl_entry_set(\u0026entries[i], 1,\ndrivers/net/dsa/motorcomm/chip.c-1010-\t\t\t\t\t     YT921X_ACL_BINb_IPV4_FRAG, set);\n--\ndrivers/net/dsa/motorcomm/chip.c-1013-\t\tcase YT921X_ACL_TYPE_IPV6_SA3:\ndrivers/net/dsa/motorcomm/chip.c:1014:\t\t\tyt921x_acl_entry_set(\u0026entries[i], 1,\ndrivers/net/dsa/motorcomm/chip.c-1015-\t\t\t\t\t     YT921X_ACL_BINb_IPV6_xA3_FRAG,\n--\ndrivers/net/dsa/motorcomm/chip.c-1018-\t\tcase YT921X_ACL_TYPE_MISC:\ndrivers/net/dsa/motorcomm/chip.c:1019:\t\t\tyt921x_acl_entry_set(\u0026entries[i], 1,\ndrivers/net/dsa/motorcomm/chip.c-1020-\t\t\t\t\t     YT921X_ACL_BINb_MISC_FRAG, set);\n--\ndrivers/net/dsa/motorcomm/chip.c-1022-\t\tcase YT921X_ACL_TYPE_L4:\ndrivers/net/dsa/motorcomm/chip.c:1023:\t\t\tyt921x_acl_entry_set(\u0026entries[i], 1,\ndrivers/net/dsa/motorcomm/chip.c-1024-\t\t\t\t\t     YT921X_ACL_BINb_L4_FRAG, set);\n--\ndrivers/net/dsa/motorcomm/chip.c-1032-\tentries[size].key[1] = YT921X_ACL_KEYb_TYPE(YT921X_ACL_TYPE_MISC);\ndrivers/net/dsa/motorcomm/chip.c:1033:\tyt921x_acl_entry_set(\u0026entries[size], 1, YT921X_ACL_BINb_MISC_FRAG, set);\ndrivers/net/dsa/motorcomm/chip.c-1034-\n--\ndrivers/net/dsa/motorcomm/chip.c=1038=static unsigned int\ndrivers/net/dsa/motorcomm/chip.c:1039:yt921x_acl_entries_set_first_frag(struct yt921x_acl_entry *entries,\ndrivers/net/dsa/motorcomm/chip.c-1040-\t\t\t\t  unsigned int size, bool set)\n--\ndrivers/net/dsa/motorcomm/chip.c-1045-\t\tcase YT921X_ACL_TYPE_IPV6_SA2:\ndrivers/net/dsa/motorcomm/chip.c:1046:\t\t\tyt921x_acl_entry_set(\u0026entries[i], 1,\ndrivers/net/dsa/motorcomm/chip.c-1047-\t\t\t\t\t     YT921X_ACL_BINb_IPV6_xA2_FIRST_FRAG,\n--\ndrivers/net/dsa/motorcomm/chip.c-1050-\t\tcase YT921X_ACL_TYPE_MISC:\ndrivers/net/dsa/motorcomm/chip.c:1051:\t\t\tyt921x_acl_entry_set(\u0026entries[i], 0,\ndrivers/net/dsa/motorcomm/chip.c-1052-\t\t\t\t\t     YT921X_ACL_BINa_MISC_FIRST_FRAG,\n--\ndrivers/net/dsa/motorcomm/chip.c-1061-\tentries[size].key[1] = YT921X_ACL_KEYb_TYPE(YT921X_ACL_TYPE_MISC);\ndrivers/net/dsa/motorcomm/chip.c:1062:\tyt921x_acl_entry_set(\u0026entries[size], 0,\ndrivers/net/dsa/motorcomm/chip.c-1063-\t\t\t     YT921X_ACL_BINa_MISC_FIRST_FRAG, set);\n--\ndrivers/net/dsa/motorcomm/chip.c=1068=static unsigned int\ndrivers/net/dsa/motorcomm/chip.c:1069:yt921x_acl_entries_set_l3_type(struct yt921x_acl_entry *entries,\ndrivers/net/dsa/motorcomm/chip.c:1070:\t\t\t       unsigned int size, enum yt921x_l3_type type)\ndrivers/net/dsa/motorcomm/chip.c-1071-{\n--\ndrivers/net/dsa/motorcomm/chip.c=1096=static unsigned int\ndrivers/net/dsa/motorcomm/chip.c:1097:yt921x_acl_entries_set_l4_type(struct yt921x_acl_entry *entries,\ndrivers/net/dsa/motorcomm/chip.c:1098:\t\t\t       unsigned int size, enum yt921x_l4_type type)\ndrivers/net/dsa/motorcomm/chip.c-1099-{\n--\ndrivers/net/dsa/motorcomm/chip.c-1138-\ndrivers/net/dsa/motorcomm/chip.c:1139:static struct yt921x_acl_entry *\ndrivers/net/dsa/motorcomm/chip.c:1140:yt921x_acl_entries_new(struct yt921x_acl_entry *entries, unsigned int *sizep,\ndrivers/net/dsa/motorcomm/chip.c-1141-\t\t       u32 type)\n--\ndrivers/net/dsa/motorcomm/chip.c-1154-\ndrivers/net/dsa/motorcomm/chip.c:1155:static struct yt921x_acl_entry *\ndrivers/net/dsa/motorcomm/chip.c:1156:yt921x_acl_entries_find(struct yt921x_acl_entry *entries, unsigned int *sizep,\ndrivers/net/dsa/motorcomm/chip.c-1157-\t\t\tu32 type)\n--\ndrivers/net/dsa/motorcomm/chip.c-1162-\t\t\treturn \u0026entries[i];\ndrivers/net/dsa/motorcomm/chip.c:1163:\treturn yt921x_acl_entries_new(entries, sizep, type);\ndrivers/net/dsa/motorcomm/chip.c-1164-}\n--\ndrivers/net/dsa/motorcomm/chip.c=1166=static void\ndrivers/net/dsa/motorcomm/chip.c:1167:yt921x_acl_rule_set_ports(struct yt921x_acl_rule *aclrule, u16 ord,\ndrivers/net/dsa/motorcomm/chip.c-1168-\t\t\t  u16 ports_mask)\ndrivers/net/dsa/motorcomm/chip.c-1169-{\ndrivers/net/dsa/motorcomm/chip.c:1170:\tstruct yt921x_acl_entry *entries = aclrule-\u003eentries;\ndrivers/net/dsa/motorcomm/chip.c-1171-\n--\ndrivers/net/dsa/motorcomm/chip.c-1177-\ndrivers/net/dsa/motorcomm/chip.c:1178:struct yt921x_acl_rule_ext {\ndrivers/net/dsa/motorcomm/chip.c:1179:\tstruct yt921x_acl_rule r;\ndrivers/net/dsa/motorcomm/chip.c-1180-\ndrivers/net/dsa/motorcomm/chip.c:1181:\tstruct yt921x_marker marker;\ndrivers/net/dsa/motorcomm/chip.c-1182-};\n--\ndrivers/net/dsa/motorcomm/chip.c=1184=static int\ndrivers/net/dsa/motorcomm/chip.c:1185:yt921x_acl_rule_ext_parse_flow_entries(struct yt921x_acl_rule_ext *ruleext,\ndrivers/net/dsa/motorcomm/chip.c-1186-\t\t\t\t       const struct flow_cls_offload *cls)\n--\ndrivers/net/dsa/motorcomm/chip.c-1188-\tconst struct flow_rule *rule = flow_cls_offload_flow_rule(cls);\ndrivers/net/dsa/motorcomm/chip.c:1189:\tstruct yt921x_acl_entry *entries = ruleext-\u003er.entries;\ndrivers/net/dsa/motorcomm/chip.c-1190-\tstruct netlink_ext_ack *extack = cls-\u003ecommon.extack;\ndrivers/net/dsa/motorcomm/chip.c-1191-\tconst struct flow_dissector *dissector;\ndrivers/net/dsa/motorcomm/chip.c:1192:\tstruct yt921x_acl_entry *entry;\ndrivers/net/dsa/motorcomm/chip.c-1193-\tunsigned int size = 0;\n--\ndrivers/net/dsa/motorcomm/chip.c-1221-\t\tif (match.mask-\u003edst) {\ndrivers/net/dsa/motorcomm/chip.c:1222:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1223-\t\t\t\t\t\t       YT921X_ACL_TYPE_IPV4_DA);\n--\ndrivers/net/dsa/motorcomm/chip.c-1231-\t\tif (match.mask-\u003esrc) {\ndrivers/net/dsa/motorcomm/chip.c:1232:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1233-\t\t\t\t\t\t       YT921X_ACL_TYPE_IPV4_SA);\n--\ndrivers/net/dsa/motorcomm/chip.c-1250-\ndrivers/net/dsa/motorcomm/chip.c:1251:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1252-\t\t\t\t\t\t       YT921X_ACL_TYPE_IPV6_DA0 + i);\n--\ndrivers/net/dsa/motorcomm/chip.c-1263-\ndrivers/net/dsa/motorcomm/chip.c:1264:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1265-\t\t\t\t\t\t       YT921X_ACL_TYPE_IPV6_SA0 + i);\n--\ndrivers/net/dsa/motorcomm/chip.c-1278-\ndrivers/net/dsa/motorcomm/chip.c:1279:\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1280-\t\t\t\t\t       YT921X_ACL_TYPE_L4);\n--\ndrivers/net/dsa/motorcomm/chip.c-1297-\ndrivers/net/dsa/motorcomm/chip.c:1298:\t\tentry = yt921x_acl_entries_find(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1299-\t\t\t\t\t\tYT921X_ACL_TYPE_L4);\n--\ndrivers/net/dsa/motorcomm/chip.c-1332-\t\tif (mask) {\ndrivers/net/dsa/motorcomm/chip.c:1333:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1334-\t\t\t\t\t\t       YT921X_ACL_TYPE_MAC_DA0);\n--\ndrivers/net/dsa/motorcomm/chip.c-1343-\t\tif (mask) {\ndrivers/net/dsa/motorcomm/chip.c:1344:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1345-\t\t\t\t\t\t       YT921X_ACL_TYPE_MAC_SA0);\n--\ndrivers/net/dsa/motorcomm/chip.c-1355-\t\tif (mask) {\ndrivers/net/dsa/motorcomm/chip.c:1356:\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1357-\t\t\t\t\t\t       YT921X_ACL_TYPE_MAC_DA1_SA1);\n--\ndrivers/net/dsa/motorcomm/chip.c-1373-\t\tif (match.mask-\u003en_proto) {\ndrivers/net/dsa/motorcomm/chip.c:1374:\t\t\tenum yt921x_l3_type l3type = YT921X_L3_TYPE_OTHER;\ndrivers/net/dsa/motorcomm/chip.c-1375-\n--\ndrivers/net/dsa/motorcomm/chip.c-1398-\t\t\tif (l3type != YT921X_L3_TYPE_OTHER) {\ndrivers/net/dsa/motorcomm/chip.c:1399:\t\t\t\tsize = yt921x_acl_entries_set_l3_type(entries,\ndrivers/net/dsa/motorcomm/chip.c-1400-\t\t\t\t\t\t\t\t      size,\n--\ndrivers/net/dsa/motorcomm/chip.c-1404-\t\t\t} else {\ndrivers/net/dsa/motorcomm/chip.c:1405:\t\t\t\tentry = yt921x_acl_entries_new(entries, \u0026size,\ndrivers/net/dsa/motorcomm/chip.c-1406-\t\t\t\t\t\t\t       YT921X_ACL_TYPE_ETHERTYPE);\n--\ndrivers/net/dsa/motorcomm/chip.c-1415-\t\tif (match.mask-\u003eip_proto) {\ndrivers/net/dsa/motorcomm/chip.c:1416:\t\t\tenum yt921x_l4_type l4type = YT921X_L4_TYPE_OTHER;\ndrivers/net/dsa/motorcomm/chip.c-1417-\n--\ndrivers/net/dsa/motorcomm/chip.c-1437-\t\t\tif (l4type != YT921X_L4_TYPE_OTHER) {\ndrivers/net/dsa/motorcomm/chip.c:1438:\t\t\t\tsize = yt921x_acl_entries_set_l4_type(entries,\ndrivers/net/dsa/motorcomm/chip.c-1439-\t\t\t\t\t\t\t\t      size,\n--\n\n"
}

5/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 38702
							output: 31
							thoughts: 54
						

Thoughts:
**Analyzing the Motorcomm DSA Driver**

Okay, let's dive in. I need to get a clear picture of how the Motorcomm DSA driver works, specifically the initialization and device probe sequence. My first instinct is to zero in on the core functionality, so I'll start by checking out the end of the `chip.c` file and probe functions within the `drivers/net/dsa/motorcomm/` directory. That seems like the most logical place to begin, to understand how the hardware is detected and initialized, and how the driver ties into the rest of the DSA framework.

To find the key elements rapidly, I'll use some targeted search terms. I'll search the `drivers/net/dsa/motorcomm/` files for keywords like `module_`, `_driver`, and, of course, `probe`. These are breadcrumbs to the module initialization and device driver registration, as well as the important probe function itself. I'm expecting this will quickly lead me to the crucial initialization routines where the driver interacts with the hardware. I can then trace through the surrounding code for a deeper understanding of the hardware specific aspects.



6/2 2026/09/19 23:04 tool grepper
0m Args:
{
  "Expression": "module_",
  "PathPrefix": "drivers/net/dsa/motorcomm"
}

Results:
{
  "Output": "drivers/net/dsa/motorcomm/chip.c=4495=static struct mdio_driver yt921x_mdio_driver = {\n--\ndrivers/net/dsa/motorcomm/chip.c-4504-\ndrivers/net/dsa/motorcomm/chip.c:4505:mdio_module_driver(yt921x_mdio_driver);\ndrivers/net/dsa/motorcomm/chip.c-4506-\n"
}

7/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 39157
							output: 42
							thoughts: 24
						

Thoughts:
Here's a summary of my thought process, as if I were analyzing that code snippet:

**Diving into yt921x_mdio_driver Registration**

Okay, I'm going to start by getting a handle on `yt921x_mdio_driver`'s registration and probing within `chip.c`. This suggests we're dealing with an MDIO (Management Data Input/Output) driver, and likely a specific implementation for the `yt921x` family, maybe in a chip-specific context. My initial instinct is to look for how this driver interacts with the broader MDIO subsystem. I want to see how it's *registered* – is it through the standard `mdio_driver_register()` function or something else? Understanding the registration method tells me a lot about the dependencies and initialization procedures. Then, I need to see the *probe* function. The probe is the workhorse, the first function executed after the kernel finds a device the driver is compatible with. That's where I'll get an understanding of the device instantiation and resource configuration. I expect to see the code handling things like device tree bindings, MDIO bus address setup, and any necessary clock enabling or pin configuration. I'm looking for the hardware initialization specifics, and how it links to the physical MDIO interface. Knowing how these two parts, registration and probe, are linked and function will give me a solid foundation for understanding the device driver's role.



8/2 2026/09/19 23:04 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/chip.c",
  "FirstLine": 4470,
  "LineCount": 60
}

Results:
{
  "Contents": "4470:\t\t}\n4471:\t\n4472:\t\tds = \u0026priv-\u003eds;\n4473:\t\tds-\u003edev = dev;\n4474:\t\tds-\u003eassisted_learning_on_cpu_port = true;\n4475:\t\tds-\u003edscp_prio_mapping_is_global = true;\n4476:\t\tds-\u003epriv = priv;\n4477:\t\tds-\u003eops = \u0026yt921x_dsa_switch_ops;\n4478:\t\tds-\u003eageing_time_min = 1 * 5000;\n4479:\t\tds-\u003eageing_time_max = U16_MAX * 5000;\n4480:\t\tds-\u003ephylink_mac_ops = \u0026yt921x_phylink_mac_ops;\n4481:\t\tds-\u003enum_lag_ids = YT921X_LAG_NUM;\n4482:\t\tds-\u003enum_ports = YT921X_PORT_NUM;\n4483:\t\n4484:\t\tmdiodev_set_drvdata(mdiodev, priv);\n4485:\t\n4486:\t\treturn dsa_register_switch(ds);\n4487:\t}\n4488:\t\n4489:\tstatic const struct of_device_id yt921x_of_match[] = {\n4490:\t\t{ .compatible = \"motorcomm,yt9215\" },\n4491:\t\t{}\n4492:\t};\n4493:\tMODULE_DEVICE_TABLE(of, yt921x_of_match);\n4494:\t\n4495:\tstatic struct mdio_driver yt921x_mdio_driver = {\n4496:\t\t.probe = yt921x_mdio_probe,\n4497:\t\t.remove = yt921x_mdio_remove,\n4498:\t\t.shutdown = yt921x_mdio_shutdown,\n4499:\t\t.mdiodrv.driver = {\n4500:\t\t\t.name = YT921X_NAME,\n4501:\t\t\t.of_match_table = yt921x_of_match,\n4502:\t\t},\n4503:\t};\n4504:\t\n4505:\tmdio_module_driver(yt921x_mdio_driver);\n4506:\t\n4507:\tMODULE_AUTHOR(\"David Yang \u003cmmyangfl@gmail.com\u003e\");\n4508:\tMODULE_DESCRIPTION(\"Driver for Motorcomm YT921x Switch\");\n4509:\tMODULE_LICENSE(\"GPL\");\n"
}

9/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 40226
							output: 30
							thoughts: 487
						

Thoughts:
**My Initial Thoughts on MDIO and DSA Driver Probing for Fuzzing**

Okay, so I'm looking at this MDIO driver registration: `static const struct of_device_id yt921x_of_match[] = { { .compatible = "motorcomm,yt9215" }, {} };`, and the `static struct mdio_driver yt921x_mdio_driver = { ... };` followed by `mdio_module_driver(yt921x_mdio_driver);`. The question is, how *exactly* does this get probed? Can I get an MDIO driver to probe without physical hardware or a Device Tree in QEMU? Can I do this with virtual buses?

Hmm, let's go back to basics. Remember, reachability is key for fuzzing: "REACHABILITY IS THE PRIMARY GATE". I can only fuzz code that actually executes in a standard virtualized environment like QEMU. If the code is structurally unreachable, it's a no-go, even if it adds assertions.

Now, Section 2 highlights examples of this. Stuff that requires real hardware, like vendor-specific PCIe switches, or those drivers that only trigger on physical hot-unplug, or code specific to other architectures are explicitly mentioned as problematic for fuzzing.

My primary question now: can syzkaller actually instantiate MDIO devices or DSA switches? Does it have an MDIO emulator, or any way to instantiate or emulate DSA switch drivers? I need to know if syzkaller has syzlang descriptions or if Linux has any virtual MDIO or DSA mechanisms.

Wait a second, DSA switches. Can DSA switches be created in userspace? I need to check the `drivers/net/dsa/` directory. Maybe I can find a way to create or bind DSA switches dynamically. I should be looking for ways to do this through netlink, configfs, sysfs, or something similar. Let me `grep` for `dsa_register_switch`, or see how DSA switches are bound. This is the crux of whether I can effectively fuzz these drivers.



10/2 2026/09/19 23:04 tool grepper
0m Args:
{
  "Expression": "dsa_register_switch",
  "PathPrefix": "net/dsa"
}

Results:
{
  "Output": "net/dsa/dsa.c=1534=static int dsa_switch_probe(struct dsa_switch *ds)\n--\nnet/dsa/dsa.c-1575-\nnet/dsa/dsa.c:1576:int dsa_register_switch(struct dsa_switch *ds)\nnet/dsa/dsa.c-1577-{\n--\nnet/dsa/dsa.c-1586-}\nnet/dsa/dsa.c:1587:EXPORT_SYMBOL_GPL(dsa_register_switch);\nnet/dsa/dsa.c-1588-\n"
}

11/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41368
							output: 42
							thoughts: 19
						

Thoughts:
Okay, let's dive into this `yt921x_mdio_probe` function and see what it's all about. I need to understand this probe function to get a handle on this entire driver's initialization process. I'll need to follow the code flow, identify the key data structures it's interacting with, and figure out its purpose within the broader driver context. Is it responsible for detecting the PHY? Is it setting up the MDIO bus communication? Is it registering interrupts? And what about resource allocation; what resources is it requesting or reserving? What are the key configuration parameters it’s using and where are they sourced? I’m expecting to see calls to common MDIO functions, probably some device tree parsing if it's modern, and hopefully some error handling that will give me insights into potential failure scenarios. I need to understand what happens if things go wrong. Time to get started.



12/2 2026/09/19 23:04 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/chip.c",
  "FirstLine": 4420,
  "LineCount": 55
}

Results:
{
  "Contents": "4420:\t\t}\n4421:\t\n4422:\t\tdsa_unregister_switch(\u0026priv-\u003eds);\n4423:\t\n4424:\t\tfor (unsigned int i = 0; i \u003c ARRAY_SIZE(priv-\u003eacl_blks); i++) {\n4425:\t\t\tstruct yt921x_acl_blk *aclblk = priv-\u003eacl_blks[i];\n4426:\t\n4427:\t\t\tif (!aclblk)\n4428:\t\t\t\tcontinue;\n4429:\t\t\tfor (unsigned int j = 0; j \u003c ARRAY_SIZE(aclblk-\u003erules); j++) {\n4430:\t\t\t\tstruct yt921x_acl_rule *aclrule = aclblk-\u003erules[j];\n4431:\t\n4432:\t\t\t\tif (!aclrule)\n4433:\t\t\t\t\tcontinue;\n4434:\t\t\t\tkvfree(aclrule);\n4435:\t\t\t}\n4436:\t\t\tkvfree(aclblk);\n4437:\t\t}\n4438:\t\tmutex_destroy(\u0026priv-\u003ereg_lock);\n4439:\t}\n4440:\t\n4441:\tstatic int yt921x_mdio_probe(struct mdio_device *mdiodev)\n4442:\t{\n4443:\t\tstruct device *dev = \u0026mdiodev-\u003edev;\n4444:\t\tstruct yt921x_reg_mdio *mdio;\n4445:\t\tstruct yt921x_priv *priv;\n4446:\t\tstruct dsa_switch *ds;\n4447:\t\n4448:\t\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n4449:\t\tif (!priv)\n4450:\t\t\treturn -ENOMEM;\n4451:\t\n4452:\t\tmdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);\n4453:\t\tif (!mdio)\n4454:\t\t\treturn -ENOMEM;\n4455:\t\n4456:\t\tmdio-\u003ebus = mdiodev-\u003ebus;\n4457:\t\tmdio-\u003eaddr = mdiodev-\u003eaddr;\n4458:\t\tmdio-\u003eswitchid = 0;\n4459:\t\n4460:\t\tmutex_init(\u0026priv-\u003ereg_lock);\n4461:\t\n4462:\t\tpriv-\u003ereg_ops = \u0026yt921x_reg_ops_mdio;\n4463:\t\tpriv-\u003ereg_ctx = mdio;\n4464:\t\n4465:\t\tfor (size_t i = 0; i \u003c ARRAY_SIZE(priv-\u003eports); i++) {\n4466:\t\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\n4467:\t\n4468:\t\t\tpp-\u003eindex = i;\n4469:\t\t\tINIT_DELAYED_WORK(\u0026pp-\u003emib_read, yt921x_poll_mib);\n4470:\t\t}\n4471:\t\n4472:\t\tds = \u0026priv-\u003eds;\n4473:\t\tds-\u003edev = dev;\n4474:\t\tds-\u003eassisted_learning_on_cpu_port = true;\n"
}

13/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 42464
							output: 36
							thoughts: 151
						

Thoughts:
**My Initial Thoughts on the `yt921x_mdio_probe` Function**

Okay, so `yt921x_mdio_probe` is triggered when a device matches the "motorcomm,yt9215" ID. Makes sense. But my immediate question is, how exactly does this MDIO device even *come into existence* in the first place? I know it's related to the MDIO bus, but I need to trace the creation.

My understanding is that MDIO devices are typically registered by MDIO bus drivers when they parse the device tree, or potentially from ACPI or platform code. But, is there any possibility of MDIO device creation happening outside of that framework, maybe some way to create them virtually from userspace? I'll probably need to rule that out.

I need to dive deeper into how MDIO devices are handled. Time to check the standard locations, starting with `drivers/net/mdio/`. I should probably also check any relevant syzkaller descriptions, in case they shed any light on device creation methods.

Wait a second. Can an MDIO *bus* itself be created from userspace? If that's possible, then devices *could* be attached dynamically. Okay, time to go straight to the code. I'll grep for `mdio_device_create` and `mdiobus_register_device`. Those should point me to any relevant creation pathways.



14/2 2026/09/19 23:04 tool grepper
0m Args:
{
  "Expression": "mdio_device_register|mdio_device_create",
  "PathPrefix": "drivers/net"
}

Results:
{
  "Output": "drivers/net/dsa/dsa_loop.c=446=static int __init dsa_loop_create_switch_mdiodev(void)\n--\ndrivers/net/dsa/dsa_loop.c-466-\ndrivers/net/dsa/dsa_loop.c:467:\tswitch_mdiodev = mdio_device_create(bus, 31);\ndrivers/net/dsa/dsa_loop.c-468-\tif (IS_ERR(switch_mdiodev))\n--\ndrivers/net/dsa/dsa_loop.c-473-\ndrivers/net/dsa/dsa_loop.c:474:\tret = mdio_device_register(switch_mdiodev);\ndrivers/net/dsa/dsa_loop.c-475-\tif (ret)\n--\ndrivers/net/mdio/of_mdio.c=52=static int of_mdiobus_register_device(struct mii_bus *mdio,\n--\ndrivers/net/mdio/of_mdio.c-58-\ndrivers/net/mdio/of_mdio.c:59:\tmdiodev = mdio_device_create(mdio, addr);\ndrivers/net/mdio/of_mdio.c-60-\tif (IS_ERR(mdiodev))\n--\ndrivers/net/mdio/of_mdio.c-68-\t/* All data is now stored in the mdiodev struct; register it. */\ndrivers/net/mdio/of_mdio.c:69:\trc = mdio_device_register(mdiodev);\ndrivers/net/mdio/of_mdio.c-70-\tif (rc) {\n--\ndrivers/net/pcs/pcs-lynx.c=310=struct phylink_pcs *lynx_pcs_create_mdiodev(struct mii_bus *bus, int addr)\n--\ndrivers/net/pcs/pcs-lynx.c-314-\ndrivers/net/pcs/pcs-lynx.c:315:\tmdio = mdio_device_create(bus, addr);\ndrivers/net/pcs/pcs-lynx.c-316-\tif (IS_ERR(mdio))\n--\ndrivers/net/pcs/pcs-xpcs-plat.c=337=static int xpcs_plat_init_dev(struct dw_xpcs_plat *pxpcs)\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-343-\t/* There is a single memory-mapped DW XPCS device */\ndrivers/net/pcs/pcs-xpcs-plat.c:344:\tmdiodev = mdio_device_create(pxpcs-\u003ebus, 0);\ndrivers/net/pcs/pcs-xpcs-plat.c-345-\tif (IS_ERR(mdiodev))\n--\ndrivers/net/pcs/pcs-xpcs-plat.c-356-\ndrivers/net/pcs/pcs-xpcs-plat.c:357:\tret = mdio_device_register(mdiodev);\ndrivers/net/pcs/pcs-xpcs-plat.c-358-\tif (ret) {\n--\ndrivers/net/pcs/pcs-xpcs.c=1621=struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr)\n--\ndrivers/net/pcs/pcs-xpcs.c-1625-\ndrivers/net/pcs/pcs-xpcs.c:1626:\tmdiodev = mdio_device_create(bus, addr);\ndrivers/net/pcs/pcs-xpcs.c-1627-\tif (IS_ERR(mdiodev))\n--\ndrivers/net/phy/air_en8811h.c=1131=static int an8811hb_probe(struct phy_device *phydev)\n--\ndrivers/net/phy/air_en8811h.c-1150-\t */\ndrivers/net/phy/air_en8811h.c:1151:\tmdiodev = mdio_device_create(phydev-\u003emdio.bus,\ndrivers/net/phy/air_en8811h.c-1152-\t\t\t\t     phydev-\u003emdio.addr + EN8811H_PBUS_ADDR_OFFS);\n--\ndrivers/net/phy/air_en8811h.c-1155-\ndrivers/net/phy/air_en8811h.c:1156:\tret = mdio_device_register(mdiodev);\ndrivers/net/phy/air_en8811h.c-1157-\tif (ret)\n--\ndrivers/net/phy/mdio_device.c-26-/**\ndrivers/net/phy/mdio_device.c:27: * mdio_device_register_reset - Read and initialize the reset properties of\ndrivers/net/phy/mdio_device.c-28- *\t\t\t\tan mdio device\n--\ndrivers/net/phy/mdio_device.c-32- */\ndrivers/net/phy/mdio_device.c:33:static int mdio_device_register_reset(struct mdio_device *mdiodev)\ndrivers/net/phy/mdio_device.c-34-{\n--\ndrivers/net/phy/mdio_device.c=113=static void mdio_device_release(struct device *dev)\n--\ndrivers/net/phy/mdio_device.c-118-\ndrivers/net/phy/mdio_device.c:119:struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr)\ndrivers/net/phy/mdio_device.c-120-{\n--\ndrivers/net/phy/mdio_device.c-142-}\ndrivers/net/phy/mdio_device.c:143:EXPORT_SYMBOL(mdio_device_create);\ndrivers/net/phy/mdio_device.c-144-\ndrivers/net/phy/mdio_device.c-145-/**\ndrivers/net/phy/mdio_device.c:146: * mdio_device_register - Register the mdio device on the MDIO bus\ndrivers/net/phy/mdio_device.c-147- * @mdiodev: mdio_device structure to be added to the MDIO bus\n--\ndrivers/net/phy/mdio_device.c-150- */\ndrivers/net/phy/mdio_device.c:151:int mdio_device_register(struct mdio_device *mdiodev)\ndrivers/net/phy/mdio_device.c-152-{\n--\ndrivers/net/phy/mdio_device.c-172-}\ndrivers/net/phy/mdio_device.c:173:EXPORT_SYMBOL(mdio_device_register);\ndrivers/net/phy/mdio_device.c-174-\n--\ndrivers/net/phy/mdio_device.c-180- * This doesn't free the mdio_device itself, it merely reverses the effects\ndrivers/net/phy/mdio_device.c:181: * of mdio_device_register(). Use mdio_device_free() to free the device\ndrivers/net/phy/mdio_device.c-182- * after calling this function.\n--\ndrivers/net/phy/mdio_device.c=191=int mdiobus_register_device(struct mdio_device *mdiodev)\n--\ndrivers/net/phy/mdio_device.c-198-\tif (mdiodev-\u003eflags \u0026 MDIO_DEVICE_FLAG_PHY) {\ndrivers/net/phy/mdio_device.c:199:\t\terr = mdio_device_register_reset(mdiodev);\ndrivers/net/phy/mdio_device.c-200-\t\tif (err)\n"
}

15/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 44948
							output: 35
							thoughts: 755
						

Thoughts:
**My Analysis of Fuzzing Reachability**

Okay, so I'm looking at this `of_mdiobus_register_device` function and it's making me think about how devices are created based on DeviceTree.  Can this be done dynamically at runtime on an AMD64 system within QEMU? I'm pretty sure that the AMD64 kernels I'm familiar with in environments like syzkaller boot using ACPI/EFI, not DeviceTree. Even on ARM/ARM64, where DeviceTree *is* used, QEMU provides that information during boot, right?

The question then is, can DeviceTree overlays even be loaded? Could they be loaded using something like configfs? Let me see if `CONFIG_OF_CONFIGFS` or some form of overlay is actually being utilized, or if syzkaller is even doing this.

Alright, let's refocus. What does section 2 of these instructions tell me? Time for a careful re-read.

The core of the matter is reachability: fuzzing is only worthwhile if the modified code actually executes in these standard virtualized environments. If the code is structurally unreachable, it's a no-go, regardless of what the code *does*.

Now, based on the *negative criteria* in section 2, I need to check to make sure my code doesn't fall into the category of:

*   Non-kernel and non-executable changes
*   Structurally unreachable hardware: This doesn't seem to apply because it talks about ASIC/PCIe cards not emulated in standard QEMU.
*   Unreachable execution paths: like driver teardown callbacks (remove, shutdown, pci_unregister_driver) or code exclusive to other architectures.

Now looking at the *positive criteria* in section 3, I know my code should be worth fuzzing if it touches reachable, executable code:

*   Core Subsystems
*   Refactorings and Code Cleanups
*   Runtime Assertions and Defensive Checks
*   Reachable Drivers and Protocols.

So let's take a look at the target architecture specified by the user: AMD64.

Lastly, let's see what the Kconfig says about NET\_DSA\_YT921X.



16/2 2026/09/19 23:04 tool grepper
0m Args:
{
  "Expression": "NET_DSA_YT921X",
  "PathPrefix": "drivers/net/dsa"
}

Results:
{
  "Output": "drivers/net/dsa/motorcomm/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/net/dsa/motorcomm/Kconfig:2:config NET_DSA_YT921X\ndrivers/net/dsa/motorcomm/Kconfig-3-\ttristate \"Motorcomm YT9215 ethernet switch chip support\"\n--\ndrivers/net/dsa/motorcomm/Kconfig-9-\ndrivers/net/dsa/motorcomm/Kconfig:10:config NET_DSA_YT921X_LEDS\ndrivers/net/dsa/motorcomm/Kconfig-11-\tbool \"LED support for Motorcomm YT9215\"\ndrivers/net/dsa/motorcomm/Kconfig-12-\tdefault y\ndrivers/net/dsa/motorcomm/Kconfig:13:\tdepends on NET_DSA_YT921X\ndrivers/net/dsa/motorcomm/Kconfig:14:\tdepends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X\ndrivers/net/dsa/motorcomm/Kconfig-15-\thelp\n--\ndrivers/net/dsa/motorcomm/Makefile-1-# SPDX-License-Identifier: GPL-2.0\ndrivers/net/dsa/motorcomm/Makefile:2:obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o\ndrivers/net/dsa/motorcomm/Makefile-3-yt921x-objs := chip.o\ndrivers/net/dsa/motorcomm/Makefile:4:yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o\ndrivers/net/dsa/motorcomm/Makefile-5-yt921x-objs += mdio_bus.o\n--\ndrivers/net/dsa/motorcomm/chip.c=3919=static void yt921x_dsa_teardown(struct dsa_switch *ds)\n--\ndrivers/net/dsa/motorcomm/chip.c-3922-\ndrivers/net/dsa/motorcomm/chip.c:3923:#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\ndrivers/net/dsa/motorcomm/chip.c-3924-\tyt921x_leds_remove(priv);\n--\ndrivers/net/dsa/motorcomm/chip.c=4243=static int yt921x_dsa_setup(struct dsa_switch *ds)\n--\ndrivers/net/dsa/motorcomm/chip.c-4307-\ndrivers/net/dsa/motorcomm/chip.c:4308:#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\ndrivers/net/dsa/motorcomm/chip.c-4309-\tres = yt921x_leds_setup(priv);\n--\ndrivers/net/dsa/motorcomm/chip.h=908=struct yt921x_port {\n--\ndrivers/net/dsa/motorcomm/chip.h-924-\ndrivers/net/dsa/motorcomm/chip.h:925:#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\ndrivers/net/dsa/motorcomm/chip.h-926-\tunsigned char led_duty;\n--\ndrivers/net/dsa/motorcomm/leds.h=96=struct yt921x_led {\n--\ndrivers/net/dsa/motorcomm/leds.h-101-\ndrivers/net/dsa/motorcomm/leds.h:102:#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\ndrivers/net/dsa/motorcomm/leds.h-103-\n"
}

17/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 47180
							output: 38
							thoughts: 18
						

Thoughts:
Here's my take on those thoughts, tailored for an expert like yourself:

**Diving into the Motorcomm DSA Kconfig**

Okay, let's pull up that `drivers/net/dsa/motorcomm/Kconfig` file. Right, so I'm thinking, this is where the *meat* of the configuration for Motorcomm's DSA switch support lives. I'm expecting to see the core options for enabling and disabling the driver itself – the fundamental `CONFIG_MOTORCOMM_DSA` flag, likely. From there, I'll be looking for any device-specific options, any dependencies on other kernel components (like MDIO or PHY drivers), and probably some configurable parameters. I'll want to see how granular the configuration is. Does it cover just the basic driver, or does it allow for fine-grained control over specific features or hardware revisions? Are there any module-specific build options? Are there different features for different Motorcomm silicon versions? What about any specific vendor customizations? Are they modularized in a way that allows us to disable the features we don't need, to minimize the kernel footprint? What about different hardware revisions? This is where I can tell how much thought went into making this a flexible and maintainable driver. Let's get to it.



18/2 2026/09/19 23:04 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/Kconfig",
  "FirstLine": 1,
  "LineCount": 25
}

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_IEEE8021Q_HELPERS if DCB\n   6:\t\thelp\n   7:\t\t  This enables support for the Motorcomm YT9215 ethernet switch\n   8:\t\t  chip.\n   9:\t\n  10:\tconfig NET_DSA_YT921X_LEDS\n  11:\t\tbool \"LED support for Motorcomm YT9215\"\n  12:\t\tdefault y\n  13:\t\tdepends on NET_DSA_YT921X\n  14:\t\tdepends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X\n  15:\t\thelp\n  16:\t\t  This enables support for controlling the LEDs attached to the\n  17:\t\t  Motorcomm YT9215 switch chips.\n"
}

19/2 2026/09/19 23:04 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 47783
							output: 28
							thoughts: 23
						

Thoughts:
Here's my take on the thought process:

**Diving into the Kconfig**

Okay, so I need to understand the configuration options for this networking subsystem. Let's start with the parent directory's `Kconfig` file. I'll take a look at `drivers/net/dsa/Kconfig`. This should give me a high-level view of the configurable features and dependencies within the Distributed Switch Architecture (DSA) driver framework. Hopefully, this Kconfig will provide a good jumping-off point to see how the various components are put together.



20/2 2026/09/19 23:04 tool grepper
0m Args:
{
  "Expression": "motorcomm",
  "PathPrefix": "drivers/net/dsa"
}

Results:
{
  "Output": "drivers/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-\n--\ndrivers/net/dsa/Makefile=20=obj-y\t\t\t\t+= microchip/\ndrivers/net/dsa/Makefile:21:obj-y\t\t\t\t+= motorcomm/\ndrivers/net/dsa/Makefile-22-obj-y\t\t\t\t+= mv88e6xxx/\n--\ndrivers/net/dsa/motorcomm/chip.c=4489=static const struct of_device_id yt921x_of_match[] = {\ndrivers/net/dsa/motorcomm/chip.c:4490:\t{ .compatible = \"motorcomm,yt9215\" },\ndrivers/net/dsa/motorcomm/chip.c-4491-\t{}\n"
}

21/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 48220
							output: 41
							thoughts: 128
						

Thoughts:
**YT921x Device and Bus Investigation**

Okay, let's dive into this yt921x situation. First, I need to understand the hardware. I'll start by checking the devices and the buses it's using. Looking at `chip.c`, I see a defined OF match table, specifically with `"motorcomm,yt9215"`. Alright, that confirms the compatible ID. And I also spot a `yt921x_mdio_driver` declared and registered with `mdio_module_driver`. So, it's definitely tied to MDIO. That makes sense, likely for management interface interaction.

But wait, I need a holistic view. I don't want to jump to conclusions based on just one driver. Let me dig a bit deeper. Time to check `smi.c` to see if there are other drivers involved in this architecture. This is important to determine what kind of interaction or other interfaces this chip may be utilizing.



22/2 2026/09/19 23:05 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/smi.c",
  "FirstLine": 1,
  "LineCount": 100
}

Results:
{
  "Contents": "   1:\t// SPDX-License-Identifier: GPL-2.0-or-later\n   2:\t/*\n   3:\t * Copyright (c) 2026 David Yang\n   4:\t */\n   5:\t\n   6:\t#include \u003clinux/iopoll.h\u003e\n   7:\t\n   8:\t#include \"chip.h\"\n   9:\t#include \"smi.h\"\n  10:\t\n  11:\t#define YT921X_POLL_SLEEP_US\t10000\n  12:\t#define YT921X_POLL_TIMEOUT_US\t100000\n  13:\t\n  14:\tint yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)\n  15:\t{\n  16:\t\tlockdep_assert_held_once(\u0026priv-\u003ereg_lock);\n  17:\t\n  18:\t\treturn priv-\u003ereg_ops-\u003eread(priv-\u003ereg_ctx, reg, valp);\n  19:\t}\n  20:\t\n  21:\tint yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)\n  22:\t{\n  23:\t\tlockdep_assert_held_once(\u0026priv-\u003ereg_lock);\n  24:\t\n  25:\t\treturn priv-\u003ereg_ops-\u003ewrite(priv-\u003ereg_ctx, reg, val);\n  26:\t}\n  27:\t\n  28:\tint yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)\n  29:\t{\n  30:\t\tu32 val;\n  31:\t\tint res;\n  32:\t\tint ret;\n  33:\t\n  34:\t\tret = read_poll_timeout(yt921x_reg_read, res,\n  35:\t\t\t\t\tres || (val \u0026 mask) == *valp,\n  36:\t\t\t\t\tYT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,\n  37:\t\t\t\t\tfalse, priv, reg, \u0026val);\n  38:\t\tif (ret)\n  39:\t\t\treturn ret;\n  40:\t\tif (res)\n  41:\t\t\treturn res;\n  42:\t\n  43:\t\t*valp = val;\n  44:\t\treturn 0;\n  45:\t}\n  46:\t\n  47:\tint yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)\n  48:\t{\n  49:\t\tint res;\n  50:\t\tu32 v;\n  51:\t\tu32 u;\n  52:\t\n  53:\t\tres = yt921x_reg_read(priv, reg, \u0026v);\n  54:\t\tif (res)\n  55:\t\t\treturn res;\n  56:\t\n  57:\t\tu = v;\n  58:\t\tu \u0026= ~mask;\n  59:\t\tu |= val;\n  60:\t\tif (u == v)\n  61:\t\t\treturn 0;\n  62:\t\n  63:\t\treturn yt921x_reg_write(priv, reg, u);\n  64:\t}\n  65:\t\n  66:\tstatic int\n  67:\tyt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,\n  68:\t\t\t unsigned int num_regs)\n  69:\t{\n  70:\t\tint res;\n  71:\t\n  72:\t\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n  73:\t\t\tres = yt921x_reg_read(priv, reg + 4 * i, \u0026vals[i]);\n  74:\t\t\tif (res)\n  75:\t\t\t\treturn res;\n  76:\t\t}\n  77:\t\n  78:\t\treturn 0;\n  79:\t}\n  80:\t\n  81:\tstatic int\n  82:\tyt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,\n  83:\t\t\t  unsigned int num_regs)\n  84:\t{\n  85:\t\tint res;\n  86:\t\n  87:\t\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n  88:\t\t\tres = yt921x_reg_write(priv, reg + 4 * i, vals[i]);\n  89:\t\t\tif (res)\n  90:\t\t\t\treturn res;\n  91:\t\t}\n  92:\t\n  93:\t\treturn 0;\n  94:\t}\n  95:\t\n  96:\tstatic int\n  97:\tyt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n  98:\t\t\t\tconst u32 *vals, unsigned int num_regs)\n  99:\t{\n 100:\t\tbool changed = false;\n"
}

23/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 49963
							output: 31
							thoughts: 612
						

Thoughts:
**My Analysis of the Motorcomm YT9215 Driver in a QEMU Environment**

Okay, let's break this down. First, I wanted to confirm if there were any other driver registrations within the `drivers/net/dsa/motorcomm/` directory besides the one in `chip.c`, specifically `mdio_module_driver(yt921x_mdio_driver);`. Looking at the `Makefile`, it seems `chip.c` is the only one. Excellent. It seems this driver, `yt921x_mdio_driver`, is the only one that registers with the system. That `yt921x_of_match` with the `motorcomm,yt9215` compatible string is the matching criteria.

Now, the crucial question: can this ever *actually* probe in a standard QEMU amd64 environment? Let's dissect this.

1.  **Target Architecture:** It's amd64. Straightforward.
2.  **Hardware Context:** We're dealing with a Motorcomm YT9215 ethernet switch chip – an external physical ASIC connected via MDIO/SMI bus.
3.  **QEMU Emulation:** This is where the red flag goes up. Does QEMU emulate this chip? Absolutely not. QEMU's standard network interfaces on amd64 are e1000/e1000e, virtio-net, rtl8139, ne2k\_pci, pcnet, vmxnet3, and igb. None of those are a Motorcomm YT921x switch. They are all emulated NICs.
4.  **Driver Probing Mechanism:** The driver uses an MDIO bus with `of_device_id` matching on `motorcomm,yt9215` via `yt921x_of_match`. MDIO bus devices are matched and probed when an MDIO bus is registered AND a device is on it. The key here is MDIO buses on amd64 are usually part of physical Ethernet controllers or not present. This driver does not register a standard ethernet PHY.

MDIO device probing is usually done via scanning standard PHY IDs for ethernet PHYs. However, this is an `mdio_driver`, not a `phy_driver`. It requires the underlying MDIO bus to be present and populated with devices. The MDIO bus is registered via the `mdio_bus_type`. This is where the match and probe logic resides.

So, in a standard QEMU amd64 environment, this driver has *zero* chance of probing. There's no emulated YT9215 switch and no MDIO bus containing that switch to be detected and the driver to be matched. It's a fundamental mismatch between the driver's hardware expectations and the emulated environment. This driver *must* run on physical hardware with a real YT9215 switch connected to a working MDIO bus.



24/2 2026/09/19 23:05 tool grepper
0m Args:
{
  "Expression": "mdio_bus_match",
  "PathPrefix": "drivers/net/phy"
}

Results:
{
  "Output": "drivers/net/phy/mdio_bus_provider.c=238=const struct class mdio_bus_class = {\n--\ndrivers/net/phy/mdio_bus_provider.c-244-/**\ndrivers/net/phy/mdio_bus_provider.c:245: * mdio_bus_match - determine if given MDIO driver supports the given\ndrivers/net/phy/mdio_bus_provider.c-246- *\t\t    MDIO device\n--\ndrivers/net/phy/mdio_bus_provider.c-254- */\ndrivers/net/phy/mdio_bus_provider.c:255:static int mdio_bus_match(struct device *dev, const struct device_driver *drv)\ndrivers/net/phy/mdio_bus_provider.c-256-{\n--\ndrivers/net/phy/mdio_bus_provider.c=300=const struct bus_type mdio_bus_type = {\n--\ndrivers/net/phy/mdio_bus_provider.c-302-\t.dev_groups\t= mdio_bus_device_statistics_groups,\ndrivers/net/phy/mdio_bus_provider.c:303:\t.match\t\t= mdio_bus_match,\ndrivers/net/phy/mdio_bus_provider.c-304-\t.uevent\t\t= mdio_uevent,\n"
}

25/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 51601
							output: 42
							thoughts: 12
						

Thoughts:
Okay, here's my attempt at summarizing the thought process, as if it were my own, assuming I'm an expert in the field:

**Analyzing the `mdio_bus_match` Function**

Alright, let's dive into the `mdio_bus_match` function. I'm going to quickly get a sense of its purpose. Based on the name, it's obviously involved in matching something to a MDIO bus, likely a device. My initial assumption is that it's a vital piece within a driver or the MDIO core itself, responsible for identifying and associating a specific device with a particular MDIO bus instance during probing or device enumeration.

I'll be looking for clues about the matching criteria. Is it based on device IDs, vendor information, compatible strings, or perhaps some form of resource assignment? I'd expect it to leverage some form of a `struct device_id` or similar data structure to perform the comparison. I'll need to figure out how it handles potential conflicts or ambiguities. Does it have any provisions for handling multiple potential matches?

I'm particularly interested in how efficient this matching process is. Is it a linear search, or does it employ some kind of lookup table or optimized algorithm? Performance here is crucial, especially in systems with many devices. I'll also be considering whether the function can handle the scenario of a device that is configured to be on the MDIO bus, but is not physically present, and how that is handled.

I need to understand its return value. A simple boolean (match/no match) is likely, but it could be more nuanced. Perhaps it indicates the degree of the match or provides some other information. I'll need to carefully examine what happens when the function returns "match" to understand the subsequent steps in the system. Does it immediately proceed to binding the driver, or are there additional checks or setup steps that need to occur?

Finally, I'll be looking for any error handling or edge case management. How does it handle invalid input parameters or unexpected conditions? Is there any logging, and what is its verbosity? My goal is to understand how robust and reliable this matching mechanism is within the overall MDIO system. Let's see what we've got!



26/2 2026/09/19 23:05 tool read-file
0m Args:
{
  "File": "drivers/net/phy/mdio_bus_provider.c",
  "FirstLine": 250,
  "LineCount": 45
}

Results:
{
  "Contents": " 250:\t * Return: 1 if the driver supports the device, 0 otherwise\n 251:\t *\n 252:\t * Description: This may require calling the devices own match function,\n 253:\t *   since different classes of MDIO devices have different match criteria.\n 254:\t */\n 255:\tstatic int mdio_bus_match(struct device *dev, const struct device_driver *drv)\n 256:\t{\n 257:\t\tconst struct mdio_driver *mdiodrv = to_mdio_driver(drv);\n 258:\t\tstruct mdio_device *mdio = to_mdio_device(dev);\n 259:\t\n 260:\t\t/* Both the driver and device must type-match */\n 261:\t\tif (!(mdiodrv-\u003emdiodrv.flags \u0026 MDIO_DEVICE_IS_PHY) !=\n 262:\t\t    !(mdio-\u003eflags \u0026 MDIO_DEVICE_FLAG_PHY))\n 263:\t\t\treturn 0;\n 264:\t\n 265:\t\tif (of_driver_match_device(dev, drv))\n 266:\t\t\treturn 1;\n 267:\t\n 268:\t\tif (mdio-\u003ebus_match)\n 269:\t\t\treturn mdio-\u003ebus_match(dev, drv);\n 270:\t\n 271:\t\treturn 0;\n 272:\t}\n 273:\t\n 274:\tstatic int mdio_uevent(const struct device *dev, struct kobj_uevent_env *env)\n 275:\t{\n 276:\t\tint rc;\n 277:\t\n 278:\t\t/* Some devices have extra OF data and an OF-style MODALIAS */\n 279:\t\trc = of_device_uevent_modalias(dev, env);\n 280:\t\tif (rc != -ENODEV)\n 281:\t\t\treturn rc;\n 282:\t\n 283:\t\treturn 0;\n 284:\t}\n 285:\t\n 286:\tstatic const struct attribute *const mdio_bus_device_statistics_attrs[] = {\n 287:\t\t\u0026dev_attr_mdio_bus_device_transfers.attr.attr,\n 288:\t\t\u0026dev_attr_mdio_bus_device_errors.attr.attr,\n 289:\t\t\u0026dev_attr_mdio_bus_device_writes.attr.attr,\n 290:\t\t\u0026dev_attr_mdio_bus_device_reads.attr.attr,\n 291:\t\tNULL,\n 292:\t};\n 293:\t\n 294:\tstatic const struct attribute_group mdio_bus_device_statistics_group = {\n"
}

27/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 52848
							output: 30
							thoughts: 357
						

Thoughts:
**My Analysis of the `mdio_bus_match` Function**

Okay, so I'm looking at this `mdio_bus_match` function, and it seems pretty straightforward at first glance. It's checking if a given MDIO driver (`mdiodrv`) and MDIO device (`mdio`) are compatible based on whether they're PHYs or not. The crucial line is: `if (!(mdiodrv->mdiodrv.flags & MDIO_DEVICE_IS_PHY) != !(mdio->flags & MDIO_DEVICE_FLAG_PHY)) return 0;`. This means if one is a PHY and the other isn't, they're not a match. Seems logical.

Specifically, I'm focusing on how `yt921x_mdio_driver` will match. From what I can tell, it *doesn't* set the `MDIO_DEVICE_IS_PHY` flag because it's *not* a PHY. So, the match hinges on `mdio->flags` *not* having the `MDIO_DEVICE_FLAG_PHY` flag set. That makes sense. The matching is then handled by `of_driver_match_device(dev, drv)`. That function needs an Open Firmware (OF) / Device Tree (DT) node associated with the device (`dev`).

Now, the important question is: who creates these non-PHY `mdio_device` structures *with* an OF node? Based on my knowledge, the answer is only `of_mdiobus_register_device` in `drivers/net/mdio/of_mdio.c`, and that happens during device tree scanning.

Here's where things get interesting and where I start to suspect a problem. I'm working with an x86_64 architecture on QEMU, probably standard configuration. Does this even *have* a Device Tree? No! Standard QEMU amd64 machines are usually ACPI/BIOS based. CONFIG_OF is typically not even enabled, and no DTB is loaded! Even if it *were* enabled, QEMU doesn't load a Device Tree containing a "motorcomm,yt9215" node, nor does QEMU emulate the Motorcomm YT921x hardware. This suggests that the default configuration wouldn't ever allow the match.

But, before I dismiss it completely, I'd better be sure there aren't *other* ways a match might occur. Could a virtual switch driver be involved? It's worth a quick check. I should verify that. I'll look into `drivers/net/dsa/dsa_loop.c` just in case.



28/2 2026/09/19 23:05 tool grepper
0m Args:
{
  "Expression": "dsa_loop",
  "PathPrefix": "drivers/net/dsa"
}

Results:
{
  "Output": "drivers/net/dsa/Makefile=3=bcm-sf2-objs\t\t\t:= bcm_sf2.o bcm_sf2_cfp.o\ndrivers/net/dsa/Makefile:4:obj-$(CONFIG_NET_DSA_LOOP)\t+= dsa_loop.o\ndrivers/net/dsa/Makefile-5-obj-$(CONFIG_NET_DSA_MT7530)\t+= mt7530.o\n--\ndrivers/net/dsa/dsa_loop.c-24-\ndrivers/net/dsa/dsa_loop.c:25:struct dsa_loop_vlan {\ndrivers/net/dsa/dsa_loop.c-26-\tu16 members;\n--\ndrivers/net/dsa/dsa_loop.c-29-\ndrivers/net/dsa/dsa_loop.c:30:struct dsa_loop_mib_entry {\ndrivers/net/dsa/dsa_loop.c-31-\tchar name[ETH_GSTRING_LEN];\n--\ndrivers/net/dsa/dsa_loop.c-34-\ndrivers/net/dsa/dsa_loop.c:35:enum dsa_loop_mib_counters {\ndrivers/net/dsa/dsa_loop.c-36-\tDSA_LOOP_PHY_READ_OK,\n--\ndrivers/net/dsa/dsa_loop.c-42-\ndrivers/net/dsa/dsa_loop.c:43:struct dsa_loop_port {\ndrivers/net/dsa/dsa_loop.c:44:\tstruct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX];\ndrivers/net/dsa/dsa_loop.c-45-\tu16 pvid;\n--\ndrivers/net/dsa/dsa_loop.c-48-\ndrivers/net/dsa/dsa_loop.c:49:struct dsa_loop_priv {\ndrivers/net/dsa/dsa_loop.c-50-\tstruct mii_bus\t*bus;\ndrivers/net/dsa/dsa_loop.c-51-\tunsigned int\tport_base;\ndrivers/net/dsa/dsa_loop.c:52:\tstruct dsa_loop_vlan vlans[VLAN_N_VID];\ndrivers/net/dsa/dsa_loop.c-53-\tstruct net_device *netdev;\ndrivers/net/dsa/dsa_loop.c:54:\tstruct dsa_loop_port ports[DSA_MAX_PORTS];\ndrivers/net/dsa/dsa_loop.c-55-};\ndrivers/net/dsa/dsa_loop.c-56-\ndrivers/net/dsa/dsa_loop.c:57:struct dsa_loop_pdata {\ndrivers/net/dsa/dsa_loop.c-58-\t/* Must be first, such that dsa_register_switch() can access this\n--\ndrivers/net/dsa/dsa_loop.c-66-\ndrivers/net/dsa/dsa_loop.c:67:static struct dsa_loop_mib_entry dsa_loop_mibs[] = {\ndrivers/net/dsa/dsa_loop.c-68-\t[DSA_LOOP_PHY_READ_OK]\t= { \"phy_read_ok\", },\n--\ndrivers/net/dsa/dsa_loop.c=75=static struct mdio_device *switch_mdiodev;\ndrivers/net/dsa/dsa_loop.c-76-\ndrivers/net/dsa/dsa_loop.c:77:enum dsa_loop_devlink_resource_id {\ndrivers/net/dsa/dsa_loop.c-78-\tDSA_LOOP_DEVLINK_PARAM_ID_NONE,  /* DEVLINK_RESOURCE_ID_PARENT_TOP */\n--\ndrivers/net/dsa/dsa_loop.c-81-\ndrivers/net/dsa/dsa_loop.c:82:static u64 dsa_loop_devlink_vtu_get(void *priv)\ndrivers/net/dsa/dsa_loop.c-83-{\ndrivers/net/dsa/dsa_loop.c:84:\tstruct dsa_loop_priv *ps = priv;\ndrivers/net/dsa/dsa_loop.c-85-\tunsigned int i, count = 0;\ndrivers/net/dsa/dsa_loop.c:86:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-87-\n--\ndrivers/net/dsa/dsa_loop.c-96-\ndrivers/net/dsa/dsa_loop.c:97:static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-98-{\ndrivers/net/dsa/dsa_loop.c-99-\tstruct devlink_resource_size_params size_params;\ndrivers/net/dsa/dsa_loop.c:100:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-101-\tint err;\n--\ndrivers/net/dsa/dsa_loop.c-115-\t\t\t\t\t      DSA_LOOP_DEVLINK_PARAM_ID_VTU,\ndrivers/net/dsa/dsa_loop.c:116:\t\t\t\t\t      dsa_loop_devlink_vtu_get, ps);\ndrivers/net/dsa/dsa_loop.c-117-\n--\ndrivers/net/dsa/dsa_loop.c-124-\ndrivers/net/dsa/dsa_loop.c:125:static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/dsa_loop.c-126-\t\t\t\t\t\t   int port,\n--\ndrivers/net/dsa/dsa_loop.c-133-\ndrivers/net/dsa/dsa_loop.c:134:static int dsa_loop_setup(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-135-{\ndrivers/net/dsa/dsa_loop.c:136:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-137-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-139-\tfor (i = 0; i \u003c ds-\u003enum_ports; i++)\ndrivers/net/dsa/dsa_loop.c:140:\t\tmemcpy(ps-\u003eports[i].mib, dsa_loop_mibs,\ndrivers/net/dsa/dsa_loop.c:141:\t\t       sizeof(dsa_loop_mibs));\ndrivers/net/dsa/dsa_loop.c-142-\n--\ndrivers/net/dsa/dsa_loop.c-144-\ndrivers/net/dsa/dsa_loop.c:145:\treturn dsa_loop_setup_devlink_resources(ds);\ndrivers/net/dsa/dsa_loop.c-146-}\ndrivers/net/dsa/dsa_loop.c-147-\ndrivers/net/dsa/dsa_loop.c:148:static void dsa_loop_teardown(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-149-{\n--\ndrivers/net/dsa/dsa_loop.c-152-\ndrivers/net/dsa/dsa_loop.c:153:static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)\ndrivers/net/dsa/dsa_loop.c-154-{\n--\ndrivers/net/dsa/dsa_loop.c-160-\ndrivers/net/dsa/dsa_loop.c:161:static void dsa_loop_get_strings(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-162-\t\t\t\t u32 stringset, uint8_t *data)\ndrivers/net/dsa/dsa_loop.c-163-{\ndrivers/net/dsa/dsa_loop.c:164:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-165-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-173-\ndrivers/net/dsa/dsa_loop.c:174:static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-175-\t\t\t\t       uint64_t *data)\ndrivers/net/dsa/dsa_loop.c-176-{\ndrivers/net/dsa/dsa_loop.c:177:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-178-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-183-\ndrivers/net/dsa/dsa_loop.c:184:static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum)\ndrivers/net/dsa/dsa_loop.c-185-{\ndrivers/net/dsa/dsa_loop.c:186:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-187-\tstruct mii_bus *bus = ps-\u003ebus;\n--\ndrivers/net/dsa/dsa_loop.c-198-\ndrivers/net/dsa/dsa_loop.c:199:static int dsa_loop_phy_write(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-200-\t\t\t      int regnum, u16 value)\ndrivers/net/dsa/dsa_loop.c-201-{\ndrivers/net/dsa/dsa_loop.c:202:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-203-\tstruct mii_bus *bus = ps-\u003ebus;\n--\ndrivers/net/dsa/dsa_loop.c-214-\ndrivers/net/dsa/dsa_loop.c:215:static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-216-\t\t\t\t     struct dsa_bridge bridge,\n--\ndrivers/net/dsa/dsa_loop.c-225-\ndrivers/net/dsa/dsa_loop.c:226:static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-227-\t\t\t\t       struct dsa_bridge bridge)\n--\ndrivers/net/dsa/dsa_loop.c-232-\ndrivers/net/dsa/dsa_loop.c:233:static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-234-\t\t\t\t\tu8 state)\n--\ndrivers/net/dsa/dsa_loop.c-239-\ndrivers/net/dsa/dsa_loop.c:240:static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-241-\t\t\t\t\tbool vlan_filtering,\n--\ndrivers/net/dsa/dsa_loop.c-249-\ndrivers/net/dsa/dsa_loop.c:250:static int dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-251-\t\t\t\t  const struct switchdev_obj_port_vlan *vlan,\n--\ndrivers/net/dsa/dsa_loop.c-255-\tbool pvid = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_PVID;\ndrivers/net/dsa/dsa_loop.c:256:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-257-\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:258:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-259-\n--\ndrivers/net/dsa/dsa_loop.c-282-\ndrivers/net/dsa/dsa_loop.c:283:static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-284-\t\t\t\t  const struct switchdev_obj_port_vlan *vlan)\n--\ndrivers/net/dsa/dsa_loop.c-286-\tbool untagged = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_UNTAGGED;\ndrivers/net/dsa/dsa_loop.c:287:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-288-\tu16 pvid = ps-\u003eports[port].pvid;\ndrivers/net/dsa/dsa_loop.c-289-\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:290:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-291-\n--\ndrivers/net/dsa/dsa_loop.c-310-\ndrivers/net/dsa/dsa_loop.c:311:static int dsa_loop_port_change_mtu(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-312-\t\t\t\t    int new_mtu)\ndrivers/net/dsa/dsa_loop.c-313-{\ndrivers/net/dsa/dsa_loop.c:314:\tstruct dsa_loop_priv *priv = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-315-\n--\ndrivers/net/dsa/dsa_loop.c-320-\ndrivers/net/dsa/dsa_loop.c:321:static int dsa_loop_port_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/dsa_loop.c-322-{\n--\ndrivers/net/dsa/dsa_loop.c-325-\ndrivers/net/dsa/dsa_loop.c:326:static void dsa_loop_phylink_get_caps(struct dsa_switch *dsa, int port,\ndrivers/net/dsa/dsa_loop.c-327-\t\t\t\t      struct phylink_config *config)\n--\ndrivers/net/dsa/dsa_loop.c-333-\ndrivers/net/dsa/dsa_loop.c:334:static const struct dsa_switch_ops dsa_loop_driver = {\ndrivers/net/dsa/dsa_loop.c:335:\t.get_tag_protocol\t= dsa_loop_get_protocol,\ndrivers/net/dsa/dsa_loop.c:336:\t.setup\t\t\t= dsa_loop_setup,\ndrivers/net/dsa/dsa_loop.c:337:\t.teardown\t\t= dsa_loop_teardown,\ndrivers/net/dsa/dsa_loop.c:338:\t.get_strings\t\t= dsa_loop_get_strings,\ndrivers/net/dsa/dsa_loop.c:339:\t.get_ethtool_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:340:\t.get_sset_count\t\t= dsa_loop_get_sset_count,\ndrivers/net/dsa/dsa_loop.c:341:\t.get_ethtool_phy_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:342:\t.phy_read\t\t= dsa_loop_phy_read,\ndrivers/net/dsa/dsa_loop.c:343:\t.phy_write\t\t= dsa_loop_phy_write,\ndrivers/net/dsa/dsa_loop.c:344:\t.port_bridge_join\t= dsa_loop_port_bridge_join,\ndrivers/net/dsa/dsa_loop.c:345:\t.port_bridge_leave\t= dsa_loop_port_bridge_leave,\ndrivers/net/dsa/dsa_loop.c:346:\t.port_stp_state_set\t= dsa_loop_port_stp_state_set,\ndrivers/net/dsa/dsa_loop.c:347:\t.port_vlan_filtering\t= dsa_loop_port_vlan_filtering,\ndrivers/net/dsa/dsa_loop.c:348:\t.port_vlan_add\t\t= dsa_loop_port_vlan_add,\ndrivers/net/dsa/dsa_loop.c:349:\t.port_vlan_del\t\t= dsa_loop_port_vlan_del,\ndrivers/net/dsa/dsa_loop.c:350:\t.port_change_mtu\t= dsa_loop_port_change_mtu,\ndrivers/net/dsa/dsa_loop.c:351:\t.port_max_mtu\t\t= dsa_loop_port_max_mtu,\ndrivers/net/dsa/dsa_loop.c:352:\t.phylink_get_caps\t= dsa_loop_phylink_get_caps,\ndrivers/net/dsa/dsa_loop.c-353-};\ndrivers/net/dsa/dsa_loop.c-354-\ndrivers/net/dsa/dsa_loop.c:355:static int dsa_loop_drv_probe(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-356-{\ndrivers/net/dsa/dsa_loop.c:357:\tstruct dsa_loop_pdata *pdata = mdiodev-\u003edev.platform_data;\ndrivers/net/dsa/dsa_loop.c:358:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c-359-\tstruct dsa_switch *ds;\n--\ndrivers/net/dsa/dsa_loop.c-382-\tds-\u003edev = \u0026mdiodev-\u003edev;\ndrivers/net/dsa/dsa_loop.c:383:\tds-\u003eops = \u0026dsa_loop_driver;\ndrivers/net/dsa/dsa_loop.c-384-\tds-\u003epriv = ps;\n--\ndrivers/net/dsa/dsa_loop.c-396-\ndrivers/net/dsa/dsa_loop.c:397:static void dsa_loop_drv_remove(struct mdio_device *mdiodev)\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"
}

29/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 60356
							output: 42
							thoughts: 295
						

Thoughts:
**Analyzing DSA Driver Dependencies: dsa_loop vs. yt921x**

Okay, let's break this down. I'm looking at `dsa_loop.c` and immediately see it's a mock DSA driver, a loopback. It fabricates its own MDIO bus and registers a fixed `switch_mdiodev`. The key here is `.bus_match = dsa_loop_bus_match`, which is specifically designed to only match the `dsa_loop_drv.mdiodrv.driver`. That's important.

Now, I'm pivoting to `drivers/net/dsa/motorcomm/chip.c`, specifically the `yt921x` driver. This is a *real* hardware driver for the Motorcomm YT9215 ethernet switch chip. It's designed to match the OF compatible string `"motorcomm,yt9215"`.

The question that jumps out at me is, can `motorcomm,yt9215` *ever* probe successfully without actual hardware in the system and a Device Tree describing it? The answer is a definitive no. It has specific hardware dependencies:

1.  We need an MDIO bus described in the Device Tree.
2.  Within the MDIO bus description, we need a child node with `compatible = "motorcomm,yt9215"`.
3.  Critically, the *actual* Motorcomm YT9215 hardware *must* be connected to that MDIO bus and capable of responding to SMI/MDIO transactions. It needs to be present and responding!

Hold on, I need to double-check something in `chip.c`. Let's scrutinize the probe function. Let's see if `yt921x_mdio_probe` itself does hardware I/O directly. I'll check `yt921x_mdio_probe`.



30/2 2026/09/19 23:05 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/chip.c",
  "FirstLine": 4440,
  "LineCount": 55
}

Results:
{
  "Contents": "4440:\t\n4441:\tstatic int yt921x_mdio_probe(struct mdio_device *mdiodev)\n4442:\t{\n4443:\t\tstruct device *dev = \u0026mdiodev-\u003edev;\n4444:\t\tstruct yt921x_reg_mdio *mdio;\n4445:\t\tstruct yt921x_priv *priv;\n4446:\t\tstruct dsa_switch *ds;\n4447:\t\n4448:\t\tpriv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);\n4449:\t\tif (!priv)\n4450:\t\t\treturn -ENOMEM;\n4451:\t\n4452:\t\tmdio = devm_kzalloc(dev, sizeof(*mdio), GFP_KERNEL);\n4453:\t\tif (!mdio)\n4454:\t\t\treturn -ENOMEM;\n4455:\t\n4456:\t\tmdio-\u003ebus = mdiodev-\u003ebus;\n4457:\t\tmdio-\u003eaddr = mdiodev-\u003eaddr;\n4458:\t\tmdio-\u003eswitchid = 0;\n4459:\t\n4460:\t\tmutex_init(\u0026priv-\u003ereg_lock);\n4461:\t\n4462:\t\tpriv-\u003ereg_ops = \u0026yt921x_reg_ops_mdio;\n4463:\t\tpriv-\u003ereg_ctx = mdio;\n4464:\t\n4465:\t\tfor (size_t i = 0; i \u003c ARRAY_SIZE(priv-\u003eports); i++) {\n4466:\t\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\n4467:\t\n4468:\t\t\tpp-\u003eindex = i;\n4469:\t\t\tINIT_DELAYED_WORK(\u0026pp-\u003emib_read, yt921x_poll_mib);\n4470:\t\t}\n4471:\t\n4472:\t\tds = \u0026priv-\u003eds;\n4473:\t\tds-\u003edev = dev;\n4474:\t\tds-\u003eassisted_learning_on_cpu_port = true;\n4475:\t\tds-\u003edscp_prio_mapping_is_global = true;\n4476:\t\tds-\u003epriv = priv;\n4477:\t\tds-\u003eops = \u0026yt921x_dsa_switch_ops;\n4478:\t\tds-\u003eageing_time_min = 1 * 5000;\n4479:\t\tds-\u003eageing_time_max = U16_MAX * 5000;\n4480:\t\tds-\u003ephylink_mac_ops = \u0026yt921x_phylink_mac_ops;\n4481:\t\tds-\u003enum_lag_ids = YT921X_LAG_NUM;\n4482:\t\tds-\u003enum_ports = YT921X_PORT_NUM;\n4483:\t\n4484:\t\tmdiodev_set_drvdata(mdiodev, priv);\n4485:\t\n4486:\t\treturn dsa_register_switch(ds);\n4487:\t}\n4488:\t\n4489:\tstatic const struct of_device_id yt921x_of_match[] = {\n4490:\t\t{ .compatible = \"motorcomm,yt9215\" },\n4491:\t\t{}\n4492:\t};\n4493:\tMODULE_DEVICE_TABLE(of, yt921x_of_match);\n4494:\t\n"
}

31/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 62018
							output: 42
							thoughts: 14
						

Thoughts:
Okay, here's my interpretation of those thoughts, summarized from a first-person expert perspective:

**Deep Dive into `yt921x_dsa_setup`**

Alright, let's break this down. When I see `yt921x_dsa_setup`, my mind immediately goes into analysis mode. This is likely a critical setup function related to a specific hardware component, probably a Digital Signal Analyzer (DSA) within the `yt921x` family. The "setup" part suggests this is where the initial configuration happens – parameters, calibration, initialization – all the critical groundwork for proper operation.

My initial questions are: What's the target hardware? What's the overall system architecture? Is this a standalone module or part of a larger system? What's the role of this DSA within that system? What are the likely inputs and outputs? I would be especially keen to examine the interaction between registers, memory, and any associated firmware. I'd be looking for potential race conditions, lock mechanisms, and any hard-coded values that might become bottlenecks. Security vulnerabilities and potential points for compromise would be something I'd keep an eye on. I need to understand this to have any insight on its performance.

The first step for me would be to look through the source code and any documentation, paying particular attention to error handling. Is there robust error checking to handle unexpected hardware responses or invalid input parameters? Are there clearly defined states or flags that indicate successful setup versus failure? I expect this function contains a whole ecosystem of important considerations. It’s here, in these sorts of low-level setups, that performance and reliability are built or broken.



32/2 2026/09/19 23:05 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/motorcomm/chip.c",
  "FirstLine": 4240,
  "LineCount": 70
}

Results:
{
  "Contents": "4240:\t\treturn 0;\n4241:\t}\n4242:\t\n4243:\tstatic int yt921x_dsa_setup(struct dsa_switch *ds)\n4244:\t{\n4245:\t\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\n4246:\t\tstruct device *dev = to_device(priv);\n4247:\t\tstruct device_node *np = dev-\u003eof_node;\n4248:\t\tstruct device_node *child;\n4249:\t\tunsigned long mask;\n4250:\t\tint port;\n4251:\t\tint res;\n4252:\t\n4253:\t\tmutex_lock(\u0026priv-\u003ereg_lock);\n4254:\t\tres = yt921x_chip_reset(priv);\n4255:\t\tmutex_unlock(\u0026priv-\u003ereg_lock);\n4256:\t\n4257:\t\tif (res)\n4258:\t\t\treturn res;\n4259:\t\n4260:\t\t/* Register the internal mdio bus. Nodes for internal ports should have\n4261:\t\t * proper phy-handle pointing to their PHYs. Not enabling the internal\n4262:\t\t * bus is possible, though pretty wired, if internal ports are not used.\n4263:\t\t */\n4264:\t\tchild = of_get_child_by_name(np, \"mdio\");\n4265:\t\tif (child) {\n4266:\t\t\tres = yt921x_mbus_int_init(priv, child);\n4267:\t\t\tof_node_put(child);\n4268:\t\t\tif (res)\n4269:\t\t\t\treturn res;\n4270:\t\t}\n4271:\t\n4272:\t\t/* External mdio bus is optional */\n4273:\t\tchild = of_get_child_by_name(np, \"mdio-external\");\n4274:\t\tif (child) {\n4275:\t\t\tres = yt921x_mbus_ext_init(priv, child);\n4276:\t\t\tof_node_put(child);\n4277:\t\t\tif (res)\n4278:\t\t\t\treturn res;\n4279:\t\n4280:\t\t\tdev_err(dev, \"Untested external mdio bus\\n\");\n4281:\t\t\treturn -ENODEV;\n4282:\t\t}\n4283:\t\n4284:\t\tmask = priv-\u003einfo-\u003eserdes_mask;\n4285:\t\tfor_each_set_bit(port, \u0026mask, YT921X_PORT_NUM) {\n4286:\t\t\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n4287:\t\n4288:\t\t\tpp-\u003epcs.ops = \u0026yt921x_phylink_pcs_ops;\n4289:\t\t\tpp-\u003epcs.poll = true;\n4290:\t\n4291:\t\t\t__set_bit(PHY_INTERFACE_MODE_SGMII,\n4292:\t\t\t\t  pp-\u003epcs.supported_interfaces);\n4293:\t\t\t__set_bit(PHY_INTERFACE_MODE_100BASEX,\n4294:\t\t\t\t  pp-\u003epcs.supported_interfaces);\n4295:\t\t\t__set_bit(PHY_INTERFACE_MODE_1000BASEX,\n4296:\t\t\t\t  pp-\u003epcs.supported_interfaces);\n4297:\t\t\t__set_bit(PHY_INTERFACE_MODE_2500BASEX,\n4298:\t\t\t\t  pp-\u003epcs.supported_interfaces);\n4299:\t\t}\n4300:\t\n4301:\t\tmutex_lock(\u0026priv-\u003ereg_lock);\n4302:\t\tres = yt921x_chip_setup(priv);\n4303:\t\tmutex_unlock(\u0026priv-\u003ereg_lock);\n4304:\t\n4305:\t\tif (res)\n4306:\t\t\treturn res;\n4307:\t\n4308:\t#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\n4309:\t\tres = yt921x_leds_setup(priv);\n"
}

33/2 2026/09/19 23:05 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 63515
							output: 138
							thoughts: 805
						

Thoughts:
**Triage: WorthFuzzing = False**

Okay, let's break this down. The code in question, specifically the `yt921x_dsa_setup` function, relies on interacting directly with the Motorcomm YT921x chip via MDIO/SMI registers. This communication is tightly coupled with Device Tree configurations and, ultimately, the physical hardware. I can see this just from the initial function call and the use of `of_get_child_by_name`.

The instructions are explicit: if the code is structurally unreachable, we shouldn't waste fuzzing resources on it. Section 2 is very clear on this point, highlighting vendor-specific hardware requiring physical ASICs or PCIe cards, which aren't emulated in standard QEMU. That's a huge red flag.

In this case, the driver, residing in `drivers/net/dsa/motorcomm/`, is the culprit. It's a DSA driver for Motorcomm's YT9215 / YT921x Ethernet switch ASICs. The code attempts to establish communication, but it needs this specific physical hardware, and it uses Device Tree. We need to confirm this.

I've examined the changes. All of the modified files are neatly contained within the `drivers/net/dsa/motorcomm/` directory. No cross-driver dependencies. This confirms my suspicion. The driver itself registers an `mdio_driver` compatible with the `"motorcomm,yt9215"` Device Tree string.

Therefore, this hardware, and by extension the driver's critical functions, are *structurally unreachable* in the standard virtualized environments we're using for fuzzing (QEMU/GCE), especially on `amd64`. No Device Tree, no Motorcomm hardware, no communication. QEMU and GCE don't emulate this kind of specialized hardware. It's a dead end.

My conclusion is rock solid: This code is inaccessible to standard fuzzing. The `WorthFuzzing` flag must be set to `false`. The reasoning is straightforward: Structurally unreachable hardware/driver; requires physical Motorcomm YT9215 switch ASIC via MDIO/Device Tree not emulated in QEMU/GCE on amd64. The `FocusSymbols` and `EnableConfigs` are correctly empty. The output format is correct. We're good to go.



34/2 2026/09/19 23:05 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT921x (YT9215) ethernet switch DSA driver in drivers/net/dsa/motorcomm/. This driver controls a physical Ethernet switch ASIC connected via MDIO and configured via Device Tree (OF compatible \"motorcomm,yt9215\"). The hardware is not emulated in standard QEMU/GCE virtual machines on amd64, and cannot be instantiated through virtual interfaces or virtual buses. Therefore, the modified code is structurally unreachable for fuzzing.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT921x (YT9215) ethernet switch DSA driver in drivers/net/dsa/motorcomm/. This driver controls a physical Ethernet switch ASIC connected via MDIO and configured via Device Tree (OF compatible \"motorcomm,yt9215\"). The hardware is not emulated in standard QEMU/GCE virtual machines on amd64, and cannot be instantiated through virtual interfaces or virtual buses. Therefore, the modified code is structurally unreachable for fuzzing.",
  "WorthFuzzing": false
}

35/1 2026/09/19 23:05 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

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)