AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/25 02:31 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT9215 DSA switch driver, which is a hardware-specific MDIO device. Since there is no QEMU emulation for this hardware and MDIO devices cannot be arbitrarily instantiated from userspace (unlike I2C), the driver cannot be probed and its code paths are impossible to reach in virtualized environments.",
  "WorthFuzzing": false
}

1/1 2026/07/25 02:31 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit e9d3cec8564c1e8b0790f1c8859b1e6069d67628\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Jul 25 02:31:54 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex b72d2bd07f0882..fbaa590a3a22d3 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -18239,7 +18239,7 @@ M:\tDavid Yang \u003cmmyangfl@gmail.com\u003e\n L:\tnetdev@vger.kernel.org\n S:\tMaintained\n F:\tDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml\n-F:\tdrivers/net/dsa/yt921x.*\n+F:\tdrivers/net/dsa/motorcomm/\n F:\tnet/dsa/tag_yt921x.c\n \n MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD\ndiff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig\nindex 4ab567c5bbafc6..98e9bbe47de7b1 100644\n--- a/drivers/net/dsa/Kconfig\n+++ b/drivers/net/dsa/Kconfig\n@@ -72,6 +72,8 @@ config NET_DSA_MV88E6060\n \n source \"drivers/net/dsa/microchip/Kconfig\"\n \n+source \"drivers/net/dsa/motorcomm/Kconfig\"\n+\n source \"drivers/net/dsa/mv88e6xxx/Kconfig\"\n \n source \"drivers/net/dsa/mxl862xx/Kconfig\"\n@@ -158,12 +160,4 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM\n \t  This enables support for the Vitesse VSC7385, VSC7388, VSC7395\n \t  and VSC7398 SparX integrated ethernet switches, connected over\n \t  a CPU-attached address bus and work in memory-mapped I/O mode.\n-\n-config NET_DSA_YT921X\n-\ttristate \"Motorcomm YT9215 ethernet switch chip support\"\n-\tselect NET_DSA_TAG_YT921X\n-\tselect NET_IEEE8021Q_HELPERS if DCB\n-\thelp\n-\t  This enables support for the Motorcomm YT9215 ethernet switch\n-\t  chip.\n endmenu\ndiff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile\nindex d2975badffc093..138225baa4d564 100644\n--- a/drivers/net/dsa/Makefile\n+++ b/drivers/net/dsa/Makefile\n@@ -14,11 +14,11 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o\n obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o\n obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o\n obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o\n-obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o\n obj-y\t\t\t\t+= b53/\n obj-y\t\t\t\t+= hirschmann/\n obj-y\t\t\t\t+= lantiq/\n obj-y\t\t\t\t+= microchip/\n+obj-y\t\t\t\t+= motorcomm/\n obj-y\t\t\t\t+= mv88e6xxx/\n obj-y\t\t\t\t+= mxl862xx/\n obj-y\t\t\t\t+= netc/\ndiff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig\nnew file mode 100644\nindex 00000000000000..3438e0b143611a\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/Kconfig\n@@ -0,0 +1,17 @@\n+# SPDX-License-Identifier: ISC\n+config NET_DSA_YT921X\n+\ttristate \"Motorcomm YT9215 ethernet switch chip support\"\n+\tselect NET_DSA_TAG_YT921X\n+\tselect NET_IEEE8021Q_HELPERS if DCB\n+\thelp\n+\t  This enables support for the Motorcomm YT9215 ethernet switch\n+\t  chip.\n+\n+config NET_DSA_YT921X_LEDS\n+\tbool \"LED support for Motorcomm YT9215\"\n+\tdefault y\n+\tdepends on NET_DSA_YT921X\n+\tdepends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X\n+\thelp\n+\t  This enables support for controlling the LEDs attached to the\n+\t  Motorcomm YT9215 switch chips.\ndiff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile\nnew file mode 100644\nindex 00000000000000..5a63db0029ffe2\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/Makefile\n@@ -0,0 +1,5 @@\n+# SPDX-License-Identifier: ISC\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 += smi.o\ndiff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/motorcomm/chip.c\nsimilarity index 96%\nrename from drivers/net/dsa/yt921x.c\nrename to drivers/net/dsa/motorcomm/chip.c\nindex 159b16606f6ca4..553efacd4f5ee3 100644\n--- a/drivers/net/dsa/yt921x.c\n+++ b/drivers/net/dsa/motorcomm/chip.c\n@@ -13,7 +13,6 @@\n #include \u003clinux/if_bridge.h\u003e\n #include \u003clinux/if_hsr.h\u003e\n #include \u003clinux/if_vlan.h\u003e\n-#include \u003clinux/iopoll.h\u003e\n #include \u003clinux/mdio.h\u003e\n #include \u003clinux/module.h\u003e\n #include \u003clinux/of.h\u003e\n@@ -26,7 +25,9 @@\n #include \u003cnet/ieee8021q.h\u003e\n #include \u003cnet/pkt_cls.h\u003e\n \n-#include \"yt921x.h\"\n+#include \"chip.h\"\n+#include \"leds.h\"\n+#include \"smi.h\"\n \n struct yt921x_mib_desc {\n \tunsigned int size;\n@@ -151,13 +152,8 @@ static const struct yt921x_info yt921x_infos[] = {\n \t{}\n };\n \n-#define YT921X_NAME\t\"yt921x\"\n-\n #define YT921X_VID_UNWARE\t4095\n \n-#define YT921X_POLL_SLEEP_US\t10000\n-#define YT921X_POLL_TIMEOUT_US\t100000\n-\n /* The interval should be small enough to avoid overflow of 32bit MIBs.\n  *\n  * Until we can read MIBs from stats64 call directly (i.e. sleep\n@@ -196,208 +192,6 @@ static u32 ethaddr_lo2_to_u32(const unsigned char *addr)\n \treturn (addr[4] \u003c\u003c 8) | addr[5];\n }\n \n-static int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)\n-{\n-\tWARN_ON(!mutex_is_locked(\u0026priv-\u003ereg_lock));\n-\n-\treturn priv-\u003ereg_ops-\u003eread(priv-\u003ereg_ctx, reg, valp);\n-}\n-\n-static int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)\n-{\n-\tWARN_ON(!mutex_is_locked(\u0026priv-\u003ereg_lock));\n-\n-\treturn priv-\u003ereg_ops-\u003ewrite(priv-\u003ereg_ctx, reg, val);\n-}\n-\n-static int\n-yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)\n-{\n-\tu32 val;\n-\tint res;\n-\tint ret;\n-\n-\tret = read_poll_timeout(yt921x_reg_read, res,\n-\t\t\t\tres || (val \u0026 mask) == *valp,\n-\t\t\t\tYT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,\n-\t\t\t\tfalse, priv, reg, \u0026val);\n-\tif (ret)\n-\t\treturn ret;\n-\tif (res)\n-\t\treturn res;\n-\n-\t*valp = val;\n-\treturn 0;\n-}\n-\n-static int\n-yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)\n-{\n-\tint res;\n-\tu32 v;\n-\tu32 u;\n-\n-\tres = yt921x_reg_read(priv, 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-\treturn yt921x_reg_write(priv, reg, u);\n-}\n-\n-static int yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)\n-{\n-\treturn yt921x_reg_update_bits(priv, reg, 0, mask);\n-}\n-\n-static int yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)\n-{\n-\treturn yt921x_reg_update_bits(priv, reg, mask, 0);\n-}\n-\n-static int\n-yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)\n-{\n-\treturn yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);\n-}\n-\n-/* Some multi-word registers, like VLANn_CTRL, should be treated as a single\n- * long register. More specifically, writes to parts of its words won't become\n- * visible, until the last word is written.\n- *\n- * Here we require full read and write operations over these registers to\n- * eliminate potential issues, although partial reads/writes are also possible.\n- */\n-\n-static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)\n-{\n-\t*lo \u0026= ~lower_32_bits(mask);\n-\t*hi \u0026= ~upper_32_bits(mask);\n-\t*lo |= lower_32_bits(val);\n-\t*hi |= upper_32_bits(val);\n-}\n-\n-static int\n-yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,\n-\t\t unsigned int num_regs)\n-{\n-\tint res;\n-\n-\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n-\t\tres = yt921x_reg_read(priv, reg + 4 * i, \u0026vals[i]);\n-\t\tif (res)\n-\t\t\treturn res;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int\n-yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,\n-\t\t  unsigned int num_regs)\n-{\n-\tint res;\n-\n-\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n-\t\tres = yt921x_reg_write(priv, reg + 4 * i, vals[i]);\n-\t\tif (res)\n-\t\t\treturn res;\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static int\n-yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n-\t\t\tconst u32 *vals, unsigned int num_regs)\n-{\n-\tbool changed = false;\n-\tu32 vs[4];\n-\tint res;\n-\n-\tBUILD_BUG_ON(num_regs \u003e ARRAY_SIZE(vs));\n-\n-\tres = yt921x_regs_read(priv, reg, vs, num_regs);\n-\tif (res)\n-\t\treturn res;\n-\n-\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n-\t\tu32 u = vs[i];\n-\n-\t\tu \u0026= ~masks[i];\n-\t\tu |= vals[i];\n-\t\tif (u != vs[i])\n-\t\t\tchanged = true;\n-\n-\t\tvs[i] = u;\n-\t}\n-\n-\tif (!changed)\n-\t\treturn 0;\n-\n-\treturn yt921x_regs_write(priv, reg, vs, num_regs);\n-}\n-\n-static int\n-yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n-\t\t       unsigned int num_regs)\n-{\n-\tbool changed = false;\n-\tu32 vs[4];\n-\tint res;\n-\n-\tBUILD_BUG_ON(num_regs \u003e ARRAY_SIZE(vs));\n-\n-\tres = yt921x_regs_read(priv, reg, vs, num_regs);\n-\tif (res)\n-\t\treturn res;\n-\n-\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n-\t\tu32 u = vs[i];\n-\n-\t\tu \u0026= ~masks[i];\n-\t\tif (u != vs[i])\n-\t\t\tchanged = true;\n-\n-\t\tvs[i] = u;\n-\t}\n-\n-\tif (!changed)\n-\t\treturn 0;\n-\n-\treturn yt921x_regs_write(priv, reg, vs, num_regs);\n-}\n-\n-static int\n-yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)\n-{\n-\treturn yt921x_regs_write(priv, reg, vals, 2);\n-}\n-\n-static int\n-yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n-\t\t\t const u32 *vals)\n-{\n-\treturn yt921x_regs_update_bits(priv, reg, masks, vals, 2);\n-}\n-\n-static int\n-yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)\n-{\n-\treturn yt921x_regs_clear_bits(priv, reg, masks, 2);\n-}\n-\n-static int\n-yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)\n-{\n-\treturn yt921x_regs_write(priv, reg, vals, 3);\n-}\n-\n static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)\n {\n \tstruct yt921x_reg_mdio *mdio = context;\n@@ -4786,6 +4580,12 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)\n \tif (res)\n \t\treturn res;\n \n+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\n+\tres = yt921x_leds_setup(priv);\n+\tif (res)\n+\t\tdev_warn(dev, \"Failed to setup LEDs: %d\\n\", res);\n+#endif\n+\n \treturn 0;\n }\n \n@@ -4886,6 +4686,10 @@ static void yt921x_mdio_remove(struct mdio_device *mdiodev)\n \tif (!priv)\n \t\treturn;\n \n+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\n+\tyt921x_leds_remove(priv);\n+#endif\n+\n \tfor (size_t i = ARRAY_SIZE(priv-\u003eports); i-- \u003e 0; ) {\n \t\tstruct yt921x_port *pp = \u0026priv-\u003eports[i];\n \ndiff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/motorcomm/chip.h\nsimilarity index 99%\nrename from drivers/net/dsa/yt921x.h\nrename to drivers/net/dsa/motorcomm/chip.h\nindex 55504652666952..de41430579313c 100644\n--- a/drivers/net/dsa/yt921x.h\n+++ b/drivers/net/dsa/motorcomm/chip.h\n@@ -850,9 +850,13 @@ enum yt921x_fdb_entry_status {\n #define YT921X_ACL_NUM\t\t(YT921X_ACL_BLK_NUM * YT921X_ACL_ENT_PER_BLK)\n #define YT921X_UDF_NUM\t\t8\n \n+#define YT921X_LED_GROUP_NUM\t3\n+\n /* 8 internal + 2 external + 1 mcu */\n #define YT921X_PORT_NUM\t\t\t11\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) (8 \u003c= (port) \u0026\u0026 (port) \u003c 9)\n \n@@ -938,6 +942,13 @@ struct yt921x_port {\n \tstruct yt921x_mib mib;\n \tu64 rx_frames;\n \tu64 tx_frames;\n+\n+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\n+\tunsigned char led_duty;\n+\tunsigned short led_cycle;\n+\n+\tstruct yt921x_led *leds[YT921X_LED_GROUP_NUM];\n+#endif\n };\n \n struct yt921x_reg_ops {\ndiff --git a/drivers/net/dsa/motorcomm/leds.c b/drivers/net/dsa/motorcomm/leds.c\nnew file mode 100644\nindex 00000000000000..85c9bb139ead89\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/leds.c\n@@ -0,0 +1,647 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#include \u003clinux/uleds.h\u003e\n+\n+#include \"chip.h\"\n+#include \"leds.h\"\n+#include \"smi.h\"\n+\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+{\n+\tswitch (group) {\n+\tcase 0:\n+\tdefault:\n+\t\treturn YT921X_LED0_PORTn(port);\n+\tcase 1:\n+\t\treturn YT921X_LED1_PORTn(port);\n+\tcase 2:\n+\t\treturn YT921X_LED2_PORTn(port);\n+\t}\n+}\n+\n+static int\n+yt921x_led_force_get(struct yt921x_priv *priv, int port, int group, bool *onp)\n+{\n+\tu32 val;\n+\tint res;\n+\n+\tres = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\t*onp = (val \u0026 YT921X_LED2_PORT_FORCEn_M(group)) ==\n+\t       YT921X_LED2_PORT_FORCEn_ON(group);\n+\treturn 0;\n+}\n+\n+static int\n+yt921x_led_force_set(struct yt921x_priv *priv, int port, int group, bool on)\n+{\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tstruct yt921x_led *led = pp-\u003eleds[group];\n+\tu32 ctrl;\n+\tu32 mask;\n+\n+\tled-\u003euse_cycle = false;\n+\tled-\u003euse_duty = false;\n+\n+\tmask = YT921X_LED2_PORT_FORCEn_M(group);\n+\tctrl = on ? YT921X_LED2_PORT_FORCEn_ON(group) :\n+\t       YT921X_LED2_PORT_FORCEn_OFF(group);\n+\treturn yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port), mask,\n+\t\t\t\t      ctrl);\n+}\n+\n+static int\n+yt921x_led_blink_select(const struct yt921x_priv *priv, unsigned long on,\n+\t\t\tunsigned long off, unsigned short *cyclep,\n+\t\t\tunsigned char *dutyp)\n+{\n+\tstatic const unsigned char dutys[] = {\n+\t\tYT921X_LED_DUTY(1, 6),\n+\t\tYT921X_LED_DUTY(1, 4),\n+\t\tYT921X_LED_DUTY(1, 3),\n+\t\tYT921X_LED_DUTY(1, 2),\n+\t};\n+\tunsigned int cycle_upper;\n+\tunsigned int cycle_req;\n+\tunsigned int duty_req;\n+\tunsigned int cycle;\n+\tunsigned int duty;\n+\n+\tcycle = YT921X_LED_BLINK_MAX;\n+\tcycle_upper = cycle * 11585 / 8192 + 1;  /* M_SQRT2 * cycle */\n+\tif (check_add_overflow(on, off, \u0026cycle_req) || cycle_req \u003e= cycle_upper)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tfor (; cycle \u003e YT921X_LED_BLINK_MIN; cycle_upper \u003e\u003e= 1, cycle \u003e\u003e= 1)\n+\t\tif (cycle_req \u003e= cycle_upper \u003e\u003e 1)\n+\t\t\tbreak;\n+\t*cyclep = cycle;\n+\n+\tduty_req = DIV_ROUND_CLOSEST(YT921X_LED_DUTY_DENOM *\n+\t\t\t\t     (on \u003e off ? off : on), cycle_req);\n+\tfor (unsigned int i = ARRAY_SIZE(dutys) - 1;; i--)\n+\t\tif (i == 0 || duty_req \u003e= (dutys[i - 1] + dutys[i]) / 2) {\n+\t\t\tduty = dutys[i];\n+\t\t\tbreak;\n+\t\t}\n+\tif (on \u003e off)\n+\t\tduty = YT921X_LED_DUTY_DENOM - duty;\n+\t*dutyp = duty;\n+\n+\treturn 0;\n+}\n+\n+static int\n+yt921x_led_blink_set(struct yt921x_priv *priv, int port, int group,\n+\t\t     unsigned long *onp, unsigned long *offp)\n+{\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tstruct yt921x_led *led = pp-\u003eleds[group];\n+\tunsigned short cycle;\n+\tunsigned char duty;\n+\tbool use_cycle;\n+\tu32 ctrl;\n+\tu32 mask;\n+\tu32 val;\n+\tint res;\n+\n+\tif (!*onp \u0026\u0026 !*offp) {\n+\t\tcycle = YT921X_LED_BLINK_DEF;\n+\t\tduty = YT921X_LED_DUTY(1, 2);\n+\t\tfor (unsigned int i = 0; i \u003c YT921X_LED_GROUP_NUM; i++)\n+\t\t\tif (i != group \u0026\u0026 pp-\u003eleds[i] \u0026\u0026\n+\t\t\t    pp-\u003eleds[i]-\u003euse_duty) {\n+\t\t\t\tduty = pp-\u003eled_duty;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\tuse_cycle = false;\n+\t} else {\n+\t\tbool change_cycle;\n+\t\tbool change_duty;\n+\n+\t\tres = yt921x_led_blink_select(priv, *onp, *offp, \u0026cycle, \u0026duty);\n+\t\tif (res)\n+\t\t\treturn res;\n+\n+\t\tuse_cycle = cycle \u003c YT921X_LED_BLINK_DEF;\n+\t\tchange_cycle = use_cycle \u0026\u0026 cycle != pp-\u003eled_cycle;\n+\t\tchange_duty = duty != pp-\u003eled_duty;\n+\t\tif (change_cycle || change_duty)\n+\t\t\tfor (unsigned int i = 0; i \u003c YT921X_LED_GROUP_NUM;\n+\t\t\t     i++) {\n+\t\t\t\tif (i == group || !pp-\u003eleds[i])\n+\t\t\t\t\tcontinue;\n+\t\t\t\tif ((change_cycle \u0026\u0026 pp-\u003eleds[i]-\u003euse_cycle) ||\n+\t\t\t\t    (change_duty \u0026\u0026 pp-\u003eleds[i]-\u003euse_duty))\n+\t\t\t\t\treturn -EOPNOTSUPP;\n+\t\t\t}\n+\t}\n+\n+\t/* The chip seems to jam a while if changing duty directly */\n+\tres = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\tctrl = val \u0026 ~YT921X_LED2_PORT_FORCEn_M(group);\n+\tctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);\n+\tif (val != ctrl) {\n+\t\tres = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\tmask = YT921X_LED1_PORT_BLINK_DUTY_M | YT921X_LED1_PORT_BLINK_DUTY_COMP;\n+\tswitch (duty \u003e= YT921X_LED_DUTY(1, 2) ? duty :\n+\t\tYT921X_LED_DUTY_DENOM - duty) {\n+\tdefault:\n+\t\tduty = YT921X_LED_DUTY(1, 2);\n+\t\tfallthrough;\n+\tcase YT921X_LED_DUTY(1, 2):\n+\t\tctrl = YT921X_LED1_PORT_BLINK_DUTY_1_2;\n+\t\tbreak;\n+\tcase YT921X_LED_DUTY(2, 3):\n+\t\tctrl = YT921X_LED1_PORT_BLINK_DUTY_2_3;\n+\t\tbreak;\n+\tcase YT921X_LED_DUTY(3, 4):\n+\t\tctrl = YT921X_LED1_PORT_BLINK_DUTY_3_4;\n+\t\tbreak;\n+\tcase YT921X_LED_DUTY(5, 6):\n+\t\tctrl = YT921X_LED1_PORT_BLINK_DUTY_5_6;\n+\t\tbreak;\n+\t}\n+\tif (duty \u003c YT921X_LED_DUTY(1, 2))\n+\t\tctrl |= YT921X_LED1_PORT_BLINK_DUTY_COMP;\n+\tif (use_cycle) {\n+\t\tmask |= YT921X_LED1_PORT_OTHER_BLINK_M;\n+\t\tctrl |= YT921X_LED1_PORT_OTHER_BLINK(9 - __fls(cycle));\n+\t}\n+\tres = yt921x_reg_update_bits(priv, YT921X_LED1_PORTn(port), mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tctrl = val \u0026 ~(YT921X_LED2_PORT_FORCEn_M(group) |\n+\t\t       YT921X_LED2_PORT_FORCE_BLINKn_M(group));\n+\tctrl |= YT921X_LED2_PORT_FORCEn_BLINK(group);\n+\tif (use_cycle)\n+\t\tctrl |= YT921X_LED2_PORT_FORCE_BLINKn_OTHER(group);\n+\telse\n+\t\tctrl |= YT921X_LED2_PORT_FORCE_BLINKn(group, __fls(cycle) - 9);\n+\tres = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tled-\u003euse_cycle = use_cycle;\n+\tif (use_cycle)\n+\t\tpp-\u003eled_cycle = cycle;\n+\tled-\u003euse_duty = true;\n+\tpp-\u003eled_duty = duty;\n+\n+\t*onp = DIV_ROUND_CLOSEST(duty * cycle, YT921X_LED_DUTY_DENOM);\n+\t*offp = cycle - *onp;\n+\treturn 0;\n+}\n+\n+struct yt921x_led_trigger_map {\n+\tunsigned long flags;\n+\tu32 mask;\n+};\n+\n+static const struct yt921x_led_trigger_map yt921x_led_trigger_maps[] = {\n+\t{BIT(TRIGGER_NETDEV_LINK),\n+\t YT921X_LEDx_PORT_ACT_DUPLEX_HALF | YT921X_LEDx_PORT_ACT_DUPLEX_FULL},\n+\t{BIT(TRIGGER_NETDEV_LINK_10), YT921X_LEDx_PORT_ACT_10M},\n+\t{BIT(TRIGGER_NETDEV_LINK_100), YT921X_LEDx_PORT_ACT_100M},\n+\t{BIT(TRIGGER_NETDEV_LINK_1000), YT921X_LEDx_PORT_ACT_1000M},\n+\t{BIT(TRIGGER_NETDEV_HALF_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_HALF},\n+\t{BIT(TRIGGER_NETDEV_FULL_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_FULL},\n+\t{BIT(TRIGGER_NETDEV_TX), YT921X_LEDx_PORT_ACT_TX_BLINK},\n+\t{BIT(TRIGGER_NETDEV_RX), YT921X_LEDx_PORT_ACT_RX_BLINK},\n+\t{BIT(TRIGGER_NETDEV_TX_ERR) | BIT(TRIGGER_NETDEV_RX_ERR),\n+\t YT921X_LEDx_PORT_ACT_COLLISION_BLINK},\n+};\n+\n+static bool\n+yt921x_led_trigger_is_supported(const struct yt921x_priv *priv, int port,\n+\t\t\t\tint group, unsigned long flags)\n+{\n+\tif (!flags)\n+\t\treturn true;\n+\n+\tfor (unsigned int i = 0; i \u003c ARRAY_SIZE(yt921x_led_trigger_maps); i++) {\n+\t\tconst struct yt921x_led_trigger_map *map = \u0026yt921x_led_trigger_maps[i];\n+\n+\t\tif ((flags \u0026 map-\u003eflags) == map-\u003eflags) {\n+\t\t\tflags \u0026= ~map-\u003eflags;\n+\t\t\tif (!flags)\n+\t\t\t\treturn true;\n+\t\t}\n+\t}\n+\n+\treturn false;\n+}\n+\n+static int\n+yt921x_led_trigger_get(struct yt921x_priv *priv, int port, int group,\n+\t\t       unsigned long *flagsp)\n+{\n+\tu32 addr;\n+\tu32 val;\n+\tint res;\n+\n+\tres = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), \u0026val);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif ((val \u0026 YT921X_LED2_PORT_FORCEn_M(group)) !=\n+\t    YT921X_LED2_PORT_FORCEn_DONTCARE(group)) {\n+\t\t*flagsp = 0;\n+\t\treturn 0;\n+\t}\n+\n+\tif (group != 2) {\n+\t\taddr = yt921x_led_regaddr(priv, port, group);\n+\t\tres = yt921x_reg_read(priv, addr, \u0026val);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\t*flagsp = 0;\n+\tfor (unsigned int i = 0; i \u003c ARRAY_SIZE(yt921x_led_trigger_maps); i++) {\n+\t\tconst struct yt921x_led_trigger_map *map = \u0026yt921x_led_trigger_maps[i];\n+\n+\t\tif ((val \u0026 map-\u003emask) == map-\u003emask)\n+\t\t\t*flagsp |= map-\u003eflags;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+yt921x_led_trigger_set(struct yt921x_priv *priv, int port, int group,\n+\t\t       unsigned long flags)\n+{\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tstruct yt921x_led *led = pp-\u003eleds[group];\n+\tu32 addr;\n+\tu32 ctrl;\n+\tu32 mask;\n+\tint res;\n+\n+\tctrl = 0;\n+\tfor (unsigned int i = 0; i \u003c ARRAY_SIZE(yt921x_led_trigger_maps); i++) {\n+\t\tconst struct yt921x_led_trigger_map *map = \u0026yt921x_led_trigger_maps[i];\n+\n+\t\tif ((flags \u0026 map-\u003eflags) == map-\u003eflags) {\n+\t\t\tflags \u0026= ~map-\u003eflags;\n+\t\t\tctrl |= map-\u003emask;\n+\t\t\tif (!flags)\n+\t\t\t\tbreak;\n+\t\t}\n+\t}\n+\tif (flags)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tled-\u003euse_cycle = false;\n+\tled-\u003euse_duty = false;\n+\n+\tmask = !group ? YT921X_LED0_PORT_ACT_M : YT921X_LEDx_PORT_ACT_M;\n+\tif (group == 2) {\n+\t\tmask |= YT921X_LED2_PORT_FORCEn_M(group);\n+\t\tctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);\n+\t}\n+\taddr = yt921x_led_regaddr(priv, port, group);\n+\tres = yt921x_reg_update_bits(priv, addr, mask, ctrl);\n+\tif (res)\n+\t\treturn res;\n+\n+\tif (group != 2) {\n+\t\tmask = YT921X_LED2_PORT_FORCEn_M(group);\n+\t\tctrl = YT921X_LED2_PORT_FORCEn_DONTCARE(group);\n+\t\tres = yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port),\n+\t\t\t\t\t     mask, ctrl);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,\n+\t\t\t\t    enum led_brightness brightness)\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+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_led_force_set(priv, pp-\u003eindex, led-\u003egroup, brightness);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static int\n+yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,\n+\t\t      unsigned long *delay_off)\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+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_led_blink_set(priv, pp-\u003eindex, led-\u003egroup, delay_on,\n+\t\t\t\t   delay_off);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static struct device * __maybe_unused\n+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 dsa_port *dp;\n+\n+\tdp = dsa_to_port(\u0026priv-\u003eds, pp-\u003eindex);\n+\tif (!dp || !dp-\u003euser)\n+\t\treturn NULL;\n+\treturn \u0026dp-\u003euser-\u003edev;\n+}\n+\n+static int __maybe_unused\n+yt921x_cled_hw_control_is_supported(struct led_classdev *led_cdev,\n+\t\t\t\t    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+\n+\tif (yt921x_led_trigger_is_supported(priv, pp-\u003eindex, led-\u003egroup, flags))\n+\t\treturn 0;\n+\treturn -EOPNOTSUPP;\n+}\n+\n+static int __maybe_unused\n+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+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_led_trigger_get(priv, pp-\u003eindex, led-\u003egroup, flagsp);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static int __maybe_unused\n+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+\tint res;\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tres = yt921x_led_trigger_set(priv, pp-\u003eindex, led-\u003egroup, flags);\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\treturn res;\n+}\n+\n+static int\n+yt921x_led_setup(struct yt921x_priv *priv, int port,\n+\t\t struct fwnode_handle *fwnode, u32 *inv_maskp, u32 *inv_ctrlp)\n+{\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tstruct device *dev = to_device(priv);\n+\tstruct led_init_data init_data;\n+\tstruct led_classdev *led_cdev;\n+\tchar name[LED_MAX_NAME_SIZE];\n+\tenum led_default_state state;\n+\tstruct yt921x_led *led;\n+\tbool force_high;\n+\tbool force_low;\n+\tint polarity;\n+\tu32 group;\n+\tbool on;\n+\tint res;\n+\n+\tres = fwnode_property_read_u32(fwnode, \"reg\", \u0026group);\n+\tif (res)\n+\t\treturn res;\n+\tif (group \u003e= YT921X_LED_GROUP_NUM) {\n+\t\tdev_err(dev, \"Invalid LED reg %u for port %d\\n\", group, port);\n+\t\treturn -EINVAL;\n+\t}\n+\tif (pp-\u003eleds[group])\n+\t\treturn -EEXIST;\n+\n+\tforce_high = fwnode_property_read_bool(fwnode, \"active-high\");\n+\tforce_low = fwnode_property_read_bool(fwnode, \"active-low\");\n+\tif (force_high \u0026\u0026 force_low) {\n+\t\tdev_err(dev, \"Duplicate polarities for LED %02d:%02u\\n\",\n+\t\t\tport, group);\n+\t\treturn -EINVAL;\n+\t}\n+\tpolarity = force_high ? 1 : force_low ? -1 : 0;\n+\n+\tled = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);\n+\tif (!led)\n+\t\treturn -ENOMEM;\n+\tled-\u003eport = pp;\n+\tled-\u003egroup = group;\n+\n+\tstate = led_init_default_state_get(fwnode);\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tpp-\u003eleds[group] = led;\n+\tswitch (state) {\n+\tcase LEDS_DEFSTATE_OFF:\n+\tcase LEDS_DEFSTATE_ON:\n+\tdefault:\n+\t\ton = state == LEDS_DEFSTATE_ON;\n+\t\tres = yt921x_led_force_set(priv, port, group, on);\n+\t\tbreak;\n+\tcase LEDS_DEFSTATE_KEEP:\n+\t\tres = yt921x_led_force_get(priv, port, group, \u0026on);\n+\t\tbreak;\n+\t}\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\tif (res)\n+\t\tgoto err;\n+\n+\tled_cdev = \u0026led-\u003ecdev;\n+\tled_cdev-\u003ebrightness = on;\n+\tled_cdev-\u003emax_brightness = 1;\n+\tled_cdev-\u003eflags = LED_RETAIN_AT_SHUTDOWN;\n+\tled_cdev-\u003ebrightness_set_blocking = yt921x_cled_brightness_set_blocking;\n+\tled_cdev-\u003eblink_set = yt921x_cled_blink_set;\n+#ifdef CONFIG_LEDS_TRIGGERS\n+\tled_cdev-\u003ehw_control_trigger = \"netdev\";\n+\tled_cdev-\u003ehw_control_get_device = yt921x_cled_hw_control_get_device;\n+\tled_cdev-\u003ehw_control_is_supported = yt921x_cled_hw_control_is_supported;\n+\tled_cdev-\u003ehw_control_get = yt921x_cled_hw_control_get;\n+\tled_cdev-\u003ehw_control_set = yt921x_cled_hw_control_set;\n+#endif\n+\n+\tsnprintf(name, sizeof(name), YT921X_NAME \"-%u:%02d:%02u\",\n+\t\t priv-\u003eds.index, port, group);\n+\tinit_data = (typeof(init_data)){\n+\t\t.fwnode = fwnode,\n+\t\t.devicename = name,\n+\t\t.devname_mandatory = true,\n+\t};\n+\tres = devm_led_classdev_register_ext(dev, led_cdev, \u0026init_data);\n+\tif (res)\n+\t\tgoto err;\n+\n+\tif (polarity) {\n+\t\tu32 bit = YT921X_LED_PAR_INV_INVnm(group, port);\n+\n+\t\t*inv_maskp |= bit;\n+\t\tif (polarity \u003e 0)\n+\t\t\t*inv_ctrlp |= bit;\n+\t}\n+\treturn 0;\n+\n+err:\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\tpp-\u003eleds[group] = NULL;\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tdevm_kfree(dev, led);\n+\treturn res;\n+}\n+\n+static void yt921x_leds_remove_port(struct yt921x_priv *priv, int port)\n+{\n+\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\n+\tstruct device *dev = to_device(priv);\n+\n+\tfor (int group = 0; group \u003c YT921X_LED_GROUP_NUM; group++) {\n+\t\tstruct yt921x_led *led = pp-\u003eleds[group];\n+\n+\t\tif (led)\n+\t\t\tdevm_led_classdev_unregister(dev, \u0026led-\u003ecdev);\n+\t}\n+\n+\tfor (int group = 0; group \u003c YT921X_LED_GROUP_NUM; group++) {\n+\t\tstruct yt921x_led *led = pp-\u003eleds[group];\n+\n+\t\tif (led) {\n+\t\t\tpp-\u003eleds[group] = NULL;\n+\t\t\tdevm_kfree(dev, led);\n+\t\t}\n+\t}\n+}\n+\n+static int\n+yt921x_leds_setup_port(struct yt921x_priv *priv, int port, u32 *inv_maskp,\n+\t\t       u32 *inv_ctrlp)\n+{\n+\tstruct dsa_switch *ds = \u0026priv-\u003eds;\n+\tstruct device_node *leds_np;\n+\tstruct dsa_port *dp;\n+\tint res;\n+\n+\tdp = dsa_to_port(ds, port);\n+\tleds_np = of_get_child_by_name(dp-\u003edn, \"leds\");\n+\tif (!leds_np)\n+\t\treturn 0;\n+\n+\tfor_each_child_of_node_scoped(leds_np, led_np) {\n+\t\tres = yt921x_led_setup(priv, port, of_fwnode_handle(led_np),\n+\t\t\t\t       inv_maskp, inv_ctrlp);\n+\t\tif (res) {\n+\t\t\tof_node_put(leds_np);\n+\t\t\tgoto err;\n+\t\t}\n+\t}\n+\n+\tof_node_put(leds_np);\n+\treturn 0;\n+\n+err:\n+\tyt921x_leds_remove_port(priv, port);\n+\treturn res;\n+}\n+\n+void yt921x_leds_remove(struct yt921x_priv *priv)\n+{\n+\tfor (int port = 0; port \u003c YT921X_PORT_NUM; port++)\n+\t\tyt921x_leds_remove_port(priv, port);\n+}\n+\n+int yt921x_leds_setup(struct yt921x_priv *priv)\n+{\n+\tstruct device *dev = to_device(priv);\n+\tstruct dsa_switch *ds = \u0026priv-\u003eds;\n+\tstruct dsa_port *dp;\n+\tu32 inv_ctrl = 0;\n+\tu32 inv_mask = 0;\n+\tu32 ctrl;\n+\tu32 mask;\n+\tint res;\n+\n+\tdsa_switch_for_each_port(dp, ds) {\n+\t\tint port = dp-\u003eindex;\n+\n+\t\tif (!dp-\u003edn)\n+\t\t\tcontinue;\n+\n+\t\tres = yt921x_leds_setup_port(priv, port, \u0026inv_mask, \u0026inv_ctrl);\n+\t\tif (res)\n+\t\t\tdev_warn(dev, \"Failed to setup LEDs for port %d: %d\\n\",\n+\t\t\t\t port, res);\n+\t}\n+\n+\tmutex_lock(\u0026priv-\u003ereg_lock);\n+\n+\t/* Inversion is internal - force on will give low logic.\n+\t * In the rest of the file, treat LEDs as if active-low.\n+\t */\n+\tif (inv_mask) {\n+\t\tres = yt921x_reg_update_bits(priv, YT921X_LED_PAR_INV, inv_mask,\n+\t\t\t\t\t     inv_ctrl);\n+\t\tif (res)\n+\t\t\tgoto end;\n+\t}\n+\n+\tmask = YT921X_LED_CTRL_MODE_M | YT921X_LED_CTRL_PORT_NUM_M |\n+\t       YT921X_LED_CTRL_EN;\n+\tctrl = YT921X_LED_CTRL_MODE_PARALLEL |\n+\t       YT921X_LED_CTRL_PORT_NUM(YT921X_PORT_NUM - 1) |\n+\t       YT921X_LED_CTRL_EN;\n+\tres = yt921x_reg_update_bits(priv, YT921X_LED_CTRL, mask, ctrl);\n+\n+end:\n+\tmutex_unlock(\u0026priv-\u003ereg_lock);\n+\n+\tif (res) {\n+\t\tyt921x_leds_remove(priv);\n+\t\treturn res;\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/dsa/motorcomm/leds.h b/drivers/net/dsa/motorcomm/leds.h\nnew file mode 100644\nindex 00000000000000..67373a190c8f4b\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/leds.h\n@@ -0,0 +1,121 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#ifndef _YT_LEDS_H\n+#define _YT_LEDS_H\n+\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/bits.h\u003e\n+#include \u003clinux/kconfig.h\u003e\n+#include \u003clinux/leds.h\u003e\n+\n+#define YT921X_LED_CTRL\t\t\t0xd0000\n+#define  YT921X_LED_CTRL_EN\t\t\tBIT(21)\n+#define  YT921X_LED_CTRL_LOOPDETECT_BLINK_M\tGENMASK(20, 19)\t/* cycle = 512 * x ms */\n+#define   YT921X_LED_CTRL_LOOPDETECT_BLINK(x)\t\tFIELD_PREP(YT921X_LED_CTRL_LOOPDETECT_BLINK_M, (x))\n+#define  YT921X_LED_CTRL_PORT_NUM_M\t\tGENMASK(16, 13)\n+#define   YT921X_LED_CTRL_PORT_NUM(x)\t\t\tFIELD_PREP(YT921X_LED_CTRL_PORT_NUM_M, (x))\n+#define  YT921X_LED_CTRL_MODE_M\t\t\tGENMASK(1, 0)\n+#define   YT921X_LED_CTRL_MODE(x)\t\t\tFIELD_PREP(YT921X_LED_CTRL_MODE_M, (x))\n+#define   YT921X_LED_CTRL_MODE_PARALLEL\t\t\tYT921X_LED_CTRL_MODE(0)\n+#define   YT921X_LED_CTRL_MODE_SERIAL\t\t\tYT921X_LED_CTRL_MODE(2)\n+#define YT921X_LED0_PORTn(port)\t\t(0xd0004 + 4 * (port))\n+#define  YT921X_LED0_PORT_ACT_M\t\t\tGENMASK(17, 0)\n+#define  YT921X_LED0_PORT_ACT_LINK_TRY_DIS\tBIT(17)\n+#define  YT921X_LED0_PORT_ACT_COLLISION_BLINK_INDI\tBIT(16)\n+#define YT921X_LED1_PORTn(port)\t\t(0xd0040 + 4 * (port))\n+#define  YT921X_LED1_PORT_OTHER_BLINK_M\t\tGENMASK(31, 30)\t/* cycle = 512 \u003e\u003e x ms */\n+#define   YT921X_LED1_PORT_OTHER_BLINK(x)\t\tFIELD_PREP(YT921X_LED1_PORT_OTHER_BLINK_M, (x))\n+#define  YT921X_LED1_PORT_EEE_BLINK_M\t\tGENMASK(29, 28)\t/* cycle = 512 \u003e\u003e x ms */\n+#define   YT921X_LED1_PORT_EEE_BLINK(x)\t\t\tFIELD_PREP(YT921X_LED1_PORT_EEE_BLINK_M, (x))\n+#define  YT921X_LED1_PORT_BLINK_DUTY_COMP\tBIT(27)\n+#define  YT921X_LED1_PORT_BLINK_DUTY_M\t\tGENMASK(26, 25)\n+#define   YT921X_LED1_PORT_BLINK_DUTY(x)\t\tFIELD_PREP(YT921X_LED1_PORT_BLINK_DUTY_M, (x))\n+#define   YT921X_LED1_PORT_BLINK_DUTY_1_2\t\tYT921X_LED1_PORT_BLINK_DUTY(0)\n+#define   YT921X_LED1_PORT_BLINK_DUTY_2_3\t\tYT921X_LED1_PORT_BLINK_DUTY(1)\n+#define   YT921X_LED1_PORT_BLINK_DUTY_3_4\t\tYT921X_LED1_PORT_BLINK_DUTY(2)\n+#define   YT921X_LED1_PORT_BLINK_DUTY_5_6\t\tYT921X_LED1_PORT_BLINK_DUTY(3)\n+#define YT921X_LED2_PORTn(port)\t\t(0xd0080 + 4 * (port))\n+#define  YT921X_LED2_PORT_FORCEn_M(grp)\t\tGENMASK(4 * (grp) + 19, 4 * (grp) + 18)\n+#define   YT921X_LED2_PORT_FORCEn(grp, x)\t\t((x) \u003c\u003c (4 * (grp) + 18))\n+#define   YT921X_LED2_PORT_FORCEn_DONTCARE(grp)\t\tYT921X_LED2_PORT_FORCEn(grp, 0)\n+#define   YT921X_LED2_PORT_FORCEn_BLINK(grp)\t\tYT921X_LED2_PORT_FORCEn(grp, 1)\n+#define   YT921X_LED2_PORT_FORCEn_ON(grp)\t\tYT921X_LED2_PORT_FORCEn(grp, 2)\n+#define   YT921X_LED2_PORT_FORCEn_OFF(grp)\t\tYT921X_LED2_PORT_FORCEn(grp, 3)\n+#define  YT921X_LED2_PORT_FORCE_BLINKn_M(grp)\tGENMASK(4 * (grp) + 17, 4 * (grp) + 16)\t/* cycle = 512 \u003c\u003c x ms */\n+#define   YT921X_LED2_PORT_FORCE_BLINKn(grp, x)\t\t((x) \u003c\u003c (4 * (grp) + 16))\n+#define   YT921X_LED2_PORT_FORCE_BLINKn_OTHER(grp)\tYT921X_LED2_PORT_FORCE_BLINKn(grp, 3)\n+#define  YT921X_LEDx_PORT_ACT_M\t\t\tGENMASK(15, 0)\n+#define  YT921X_LEDx_PORT_ACT_EEE_BLINK\t\tBIT(15)\n+#define  YT921X_LEDx_PORT_ACT_LOOPDETECT_BLINK\tBIT(14)\n+#define  YT921X_LEDx_PORT_ACT_ACTIVE_BLINK\tBIT(13)\n+#define  YT921X_LEDx_PORT_ACT_DUPLEX_FULL\tBIT(12)\n+#define  YT921X_LEDx_PORT_ACT_DUPLEX_HALF\tBIT(11)\n+#define  YT921X_LEDx_PORT_ACT_TX_BLINK\t\tBIT(10)\n+#define  YT921X_LEDx_PORT_ACT_RX_BLINK\t\tBIT(9)\n+#define  YT921X_LEDx_PORT_ACT_TX\t\tBIT(8)\n+#define  YT921X_LEDx_PORT_ACT_RX\t\tBIT(7)\n+#define  YT921X_LEDx_PORT_ACT_1000M\t\tBIT(6)\n+#define  YT921X_LEDx_PORT_ACT_100M\t\tBIT(5)\n+#define  YT921X_LEDx_PORT_ACT_10M\t\tBIT(4)\n+#define  YT921X_LEDx_PORT_ACT_COLLISION_BLINK\tBIT(3)\n+#define  YT921X_LEDx_PORT_ACT_1000M_BLINK\tBIT(2)\n+#define  YT921X_LEDx_PORT_ACT_100M_BLINK\tBIT(1)\n+#define  YT921X_LEDx_PORT_ACT_10M_BLINK\t\tBIT(0)\n+#define YT921X_LED_SER_CTRL\t\t0xd0100\n+#define  YT921X_LED_SER_CTRL_UNK\t\tGENMASK(25, 24)\t/* delay? */\n+#define  YT921X_LED_SER_CTRL_ACTIVE_LOW\t\tBIT(4)\n+#define  YT921X_LED_SER_CTRL_GRP_NUM_M\t\tGENMASK(1, 0)\t/* #grp - 1 */\n+#define   YT921X_LED_SER_CTRL_GRP_NUM(x)\t\tFIELD_PREP(YT921X_LED_SER_CTRL_GRP_NUM_M, (x))\n+#define YT921X_LED_SER_MAPnm(grp, port)\t(0xd0104 + 8 * (2 - (grp)) + 4 * ((port) / 5))\n+#define  YT921X_LED_SER_MAP_DSTn_PORT_M(port)\tGENMASK(6 * ((port) % 5) + 5, 6 * ((port) % 5) + 2)\n+#define   YT921X_LED_SER_MAP_DSTn_PORT(port, x)\t\t((x) \u003c\u003c (6 * ((port) % 5) + 2))\n+#define  YT921X_LED_SER_MAP_DSTn_LED_M(port)\tGENMASK(6 * ((port) % 5) + 1, 6 * ((port) % 5))\n+#define   YT921X_LED_SER_MAP_DSTn_LED(port, x)\t\t((x) \u003c\u003c (6 * ((port) % 5)))\n+#define YT921X_LED_PAR_PORTS\t\t0xd01c4\n+#define YT921X_LED_PAR_INV\t\t0xd01c8\n+#define  YT921X_LED_PAR_INV_INVnm(grp, port)\tBIT(10 * (grp) + (port))\n+#define YT921X_LED_PAR_MAPn(port)\t(0xd01d0 + 4 * (port))\n+#define  YT921X_LED_PAR_MAP_DSTn_PORT_M(grp)\tGENMASK(6 * (grp) + 5, 6 * (grp) + 2)\n+#define   YT921X_LED_PAR_MAP_DSTn_PORT(grp, x)\t\t((x) \u003c\u003c (6 * (grp) + 2))\n+#define  YT921X_LED_PAR_MAP_DSTn_LED_M(grp)\tGENMASK(6 * (grp) + 1, 6 * (grp))\n+#define   YT921X_LED_PAR_MAP_DSTn_LED(grp, x)\t\t((x) \u003c\u003c (6 * (grp)))\n+\n+#define YT921X_LED_BLINK_MIN\t64\n+#define YT921X_LED_BLINK_DEF\t512\n+#define YT921X_LED_BLINK_MAX\t2048\n+\n+/* 2 * lcm(2, 3, 4, 6) */\n+#define YT921X_LED_DUTY_DENOM\t\t24\n+#define YT921X_LED_DUTY(nom, denom)\t(YT921X_LED_DUTY_DENOM * (nom) / (denom))\n+\n+struct yt921x_priv;\n+\n+struct yt921x_led {\n+\tstruct led_classdev cdev;\n+\tstruct yt921x_port *port;\n+\tunsigned char group;\n+\n+\tbool use_cycle:1;\n+\tbool use_duty:1;\n+};\n+\n+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)\n+\n+void yt921x_leds_remove(struct yt921x_priv *priv);\n+int yt921x_leds_setup(struct yt921x_priv *priv);\n+\n+#else\n+\n+static inline void yt921x_leds_remove(struct yt921x_priv *priv) {}\n+\n+static inline int yt921x_leds_setup(struct yt921x_priv *priv)\n+{\n+\treturn 0;\n+}\n+\n+#endif\n+\n+#endif\ndiff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c\nnew file mode 100644\nindex 00000000000000..9054896e4cd12b\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/smi.c\n@@ -0,0 +1,157 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#include \u003clinux/iopoll.h\u003e\n+\n+#include \"chip.h\"\n+#include \"smi.h\"\n+\n+#define YT921X_POLL_SLEEP_US\t10000\n+#define YT921X_POLL_TIMEOUT_US\t100000\n+\n+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)\n+{\n+\tlockdep_assert_held_once(\u0026priv-\u003ereg_lock);\n+\n+\treturn priv-\u003ereg_ops-\u003eread(priv-\u003ereg_ctx, reg, valp);\n+}\n+\n+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)\n+{\n+\tlockdep_assert_held_once(\u0026priv-\u003ereg_lock);\n+\n+\treturn priv-\u003ereg_ops-\u003ewrite(priv-\u003ereg_ctx, reg, val);\n+}\n+\n+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)\n+{\n+\tu32 val;\n+\tint res;\n+\tint ret;\n+\n+\tret = read_poll_timeout(yt921x_reg_read, res,\n+\t\t\t\tres || (val \u0026 mask) == *valp,\n+\t\t\t\tYT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,\n+\t\t\t\tfalse, priv, reg, \u0026val);\n+\tif (ret)\n+\t\treturn ret;\n+\tif (res)\n+\t\treturn res;\n+\n+\t*valp = val;\n+\treturn 0;\n+}\n+\n+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)\n+{\n+\tint res;\n+\tu32 v;\n+\tu32 u;\n+\n+\tres = yt921x_reg_read(priv, 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+\treturn yt921x_reg_write(priv, reg, u);\n+}\n+\n+int\n+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,\n+\t\t unsigned int num_regs)\n+{\n+\tint res;\n+\n+\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n+\t\tres = yt921x_reg_read(priv, reg + 4 * i, \u0026vals[i]);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,\n+\t\t  unsigned int num_regs)\n+{\n+\tint res;\n+\n+\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n+\t\tres = yt921x_reg_write(priv, reg + 4 * i, vals[i]);\n+\t\tif (res)\n+\t\t\treturn res;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+int\n+yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n+\t\t\tconst u32 *vals, unsigned int num_regs)\n+{\n+\tbool changed = false;\n+\tu32 vs[4];\n+\tint res;\n+\n+\tif (WARN_ON_ONCE(num_regs \u003e ARRAY_SIZE(vs)))\n+\t\treturn -EINVAL;\n+\n+\tres = yt921x_regs_read(priv, reg, vs, num_regs);\n+\tif (res)\n+\t\treturn res;\n+\n+\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n+\t\tu32 u = vs[i];\n+\n+\t\tu \u0026= ~masks[i];\n+\t\tu |= vals[i];\n+\t\tif (u != vs[i])\n+\t\t\tchanged = true;\n+\n+\t\tvs[i] = u;\n+\t}\n+\n+\tif (!changed)\n+\t\treturn 0;\n+\n+\treturn yt921x_regs_write(priv, reg, vs, num_regs);\n+}\n+\n+int\n+yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n+\t\t       unsigned int num_regs)\n+{\n+\tbool changed = false;\n+\tu32 vs[4];\n+\tint res;\n+\n+\tif (WARN_ON_ONCE(num_regs \u003e ARRAY_SIZE(vs)))\n+\t\treturn -EINVAL;\n+\n+\tres = yt921x_regs_read(priv, reg, vs, num_regs);\n+\tif (res)\n+\t\treturn res;\n+\n+\tfor (unsigned int i = 0; i \u003c num_regs; i++) {\n+\t\tu32 u = vs[i];\n+\n+\t\tu \u0026= ~masks[i];\n+\t\tif (u != vs[i])\n+\t\t\tchanged = true;\n+\n+\t\tvs[i] = u;\n+\t}\n+\n+\tif (!changed)\n+\t\treturn 0;\n+\n+\treturn yt921x_regs_write(priv, reg, vs, num_regs);\n+}\ndiff --git a/drivers/net/dsa/motorcomm/smi.h b/drivers/net/dsa/motorcomm/smi.h\nnew file mode 100644\nindex 00000000000000..2e956065eb90ee\n--- /dev/null\n+++ b/drivers/net/dsa/motorcomm/smi.h\n@@ -0,0 +1,88 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ * Copyright (c) 2026 David Yang\n+ */\n+\n+#ifndef _YT_SMI_H\n+#define _YT_SMI_H\n+\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/wordpart.h\u003e\n+\n+struct yt921x_priv;\n+\n+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp);\n+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val);\n+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp);\n+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask,\n+\t\t\t   u32 val);\n+\n+static inline int\n+yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)\n+{\n+\treturn yt921x_reg_update_bits(priv, reg, 0, mask);\n+}\n+\n+static inline int\n+yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)\n+{\n+\treturn yt921x_reg_update_bits(priv, reg, mask, 0);\n+}\n+\n+static inline int\n+yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)\n+{\n+\treturn yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);\n+}\n+\n+/* Some multi-word registers, like VLANn_CTRL, should be treated as a single\n+ * long register. More specifically, writes to parts of its words won't become\n+ * visible, until the last word is written.\n+ *\n+ * Here we require full read and write operations over these registers to\n+ * eliminate potential issues, although partial reads/writes are also possible.\n+ */\n+\n+static inline void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)\n+{\n+\t*lo \u0026= ~lower_32_bits(mask);\n+\t*hi \u0026= ~upper_32_bits(mask);\n+\t*lo |= lower_32_bits(val);\n+\t*hi |= upper_32_bits(val);\n+}\n+\n+int yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,\n+\t\t     unsigned int num_regs);\n+int yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,\n+\t\t      unsigned int num_regs);\n+int yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n+\t\t\t    const u32 *vals, unsigned int num_regs);\n+int yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n+\t\t\t   unsigned int num_regs);\n+\n+static inline int\n+yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)\n+{\n+\treturn yt921x_regs_write(priv, reg, vals, 2);\n+}\n+\n+static inline int\n+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,\n+\t\t\t const u32 *vals)\n+{\n+\treturn yt921x_regs_update_bits(priv, reg, masks, vals, 2);\n+}\n+\n+static inline int\n+yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)\n+{\n+\treturn yt921x_regs_clear_bits(priv, reg, masks, 2);\n+}\n+\n+static inline int\n+yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)\n+{\n+\treturn yt921x_regs_write(priv, reg, vals, 3);\n+}\n+\n+#endif\n"
}

2/1 2026/07/25 02:31 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT9215 DSA switch driver, which is a hardware-specific MDIO device. Since there is no QEMU emulation for this hardware and MDIO devices cannot be arbitrarily instantiated from userspace (unlike I2C), the driver cannot be probed and its code paths are impossible to reach in virtualized environments.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a '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:
For your convenience, here is the diff of the changes:
commit e9d3cec8564c1e8b0790f1c8859b1e6069d67628
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Jul 25 02:31:54 2026 +0000

    syz-cluster: applied patch under review

diff --git a/MAINTAINERS b/MAINTAINERS
index b72d2bd07f0882..fbaa590a3a22d3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18239,7 +18239,7 @@ M:	David Yang <mmyangfl@gmail.com>
 L:	netdev@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml
-F:	drivers/net/dsa/yt921x.*
+F:	drivers/net/dsa/motorcomm/
 F:	net/dsa/tag_yt921x.c
 
 MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 4ab567c5bbafc6..98e9bbe47de7b1 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -72,6 +72,8 @@ config NET_DSA_MV88E6060
 
 source "drivers/net/dsa/microchip/Kconfig"
 
+source "drivers/net/dsa/motorcomm/Kconfig"
+
 source "drivers/net/dsa/mv88e6xxx/Kconfig"
 
 source "drivers/net/dsa/mxl862xx/Kconfig"
@@ -158,12 +160,4 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM
 	  This enables support for the Vitesse VSC7385, VSC7388, VSC7395
 	  and VSC7398 SparX integrated ethernet switches, connected over
 	  a CPU-attached address bus and work in memory-mapped I/O mode.
-
-config NET_DSA_YT921X
-	tristate "Motorcomm YT9215 ethernet switch chip support"
-	select NET_DSA_TAG_YT921X
-	select NET_IEEE8021Q_HELPERS if DCB
-	help
-	  This enables support for the Motorcomm YT9215 ethernet switch
-	  chip.
 endmenu
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index d2975badffc093..138225baa4d564 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -14,11 +14,11 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o
 obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o
-obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
 obj-y				+= b53/
 obj-y				+= hirschmann/
 obj-y				+= lantiq/
 obj-y				+= microchip/
+obj-y				+= motorcomm/
 obj-y				+= mv88e6xxx/
 obj-y				+= mxl862xx/
 obj-y				+= netc/
diff --git a/drivers/net/dsa/motorcomm/Kconfig b/drivers/net/dsa/motorcomm/Kconfig
new file mode 100644
index 00000000000000..3438e0b143611a
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/Kconfig
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: ISC
+config NET_DSA_YT921X
+	tristate "Motorcomm YT9215 ethernet switch chip support"
+	select NET_DSA_TAG_YT921X
+	select NET_IEEE8021Q_HELPERS if DCB
+	help
+	  This enables support for the Motorcomm YT9215 ethernet switch
+	  chip.
+
+config NET_DSA_YT921X_LEDS
+	bool "LED support for Motorcomm YT9215"
+	default y
+	depends on NET_DSA_YT921X
+	depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_YT921X
+	help
+	  This enables support for controlling the LEDs attached to the
+	  Motorcomm YT9215 switch chips.
diff --git a/drivers/net/dsa/motorcomm/Makefile b/drivers/net/dsa/motorcomm/Makefile
new file mode 100644
index 00000000000000..5a63db0029ffe2
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: ISC
+obj-$(CONFIG_NET_DSA_YT921X) += yt921x.o
+yt921x-objs := chip.o
+yt921x-$(CONFIG_NET_DSA_YT921X_LEDS) += leds.o
+yt921x-objs += smi.o
diff --git a/drivers/net/dsa/yt921x.c b/drivers/net/dsa/motorcomm/chip.c
similarity index 96%
rename from drivers/net/dsa/yt921x.c
rename to drivers/net/dsa/motorcomm/chip.c
index 159b16606f6ca4..553efacd4f5ee3 100644
--- a/drivers/net/dsa/yt921x.c
+++ b/drivers/net/dsa/motorcomm/chip.c
@@ -13,7 +13,6 @@
 #include <linux/if_bridge.h>
 #include <linux/if_hsr.h>
 #include <linux/if_vlan.h>
-#include <linux/iopoll.h>
 #include <linux/mdio.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -26,7 +25,9 @@
 #include <net/ieee8021q.h>
 #include <net/pkt_cls.h>
 
-#include "yt921x.h"
+#include "chip.h"
+#include "leds.h"
+#include "smi.h"
 
 struct yt921x_mib_desc {
 	unsigned int size;
@@ -151,13 +152,8 @@ static const struct yt921x_info yt921x_infos[] = {
 	{}
 };
 
-#define YT921X_NAME	"yt921x"
-
 #define YT921X_VID_UNWARE	4095
 
-#define YT921X_POLL_SLEEP_US	10000
-#define YT921X_POLL_TIMEOUT_US	100000
-
 /* The interval should be small enough to avoid overflow of 32bit MIBs.
  *
  * Until we can read MIBs from stats64 call directly (i.e. sleep
@@ -196,208 +192,6 @@ static u32 ethaddr_lo2_to_u32(const unsigned char *addr)
 	return (addr[4] << 8) | addr[5];
 }
 
-static int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
-{
-	WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
-	return priv->reg_ops->read(priv->reg_ctx, reg, valp);
-}
-
-static int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
-{
-	WARN_ON(!mutex_is_locked(&priv->reg_lock));
-
-	return priv->reg_ops->write(priv->reg_ctx, reg, val);
-}
-
-static int
-yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
-{
-	u32 val;
-	int res;
-	int ret;
-
-	ret = read_poll_timeout(yt921x_reg_read, res,
-				res || (val & mask) == *valp,
-				YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
-				false, priv, reg, &val);
-	if (ret)
-		return ret;
-	if (res)
-		return res;
-
-	*valp = val;
-	return 0;
-}
-
-static int
-yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
-{
-	int res;
-	u32 v;
-	u32 u;
-
-	res = yt921x_reg_read(priv, reg, &v);
-	if (res)
-		return res;
-
-	u = v;
-	u &= ~mask;
-	u |= val;
-	if (u == v)
-		return 0;
-
-	return yt921x_reg_write(priv, reg, u);
-}
-
-static int yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
-	return yt921x_reg_update_bits(priv, reg, 0, mask);
-}
-
-static int yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
-{
-	return yt921x_reg_update_bits(priv, reg, mask, 0);
-}
-
-static int
-yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
-{
-	return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
-}
-
-/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
- * long register. More specifically, writes to parts of its words won't become
- * visible, until the last word is written.
- *
- * Here we require full read and write operations over these registers to
- * eliminate potential issues, although partial reads/writes are also possible.
- */
-
-static void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
-{
-	*lo &= ~lower_32_bits(mask);
-	*hi &= ~upper_32_bits(mask);
-	*lo |= lower_32_bits(val);
-	*hi |= upper_32_bits(val);
-}
-
-static int
-yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
-		 unsigned int num_regs)
-{
-	int res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
-		if (res)
-			return res;
-	}
-
-	return 0;
-}
-
-static int
-yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
-		  unsigned int num_regs)
-{
-	int res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
-		if (res)
-			return res;
-	}
-
-	return 0;
-}
-
-static int
-yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
-			const u32 *vals, unsigned int num_regs)
-{
-	bool changed = false;
-	u32 vs[4];
-	int res;
-
-	BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
-	res = yt921x_regs_read(priv, reg, vs, num_regs);
-	if (res)
-		return res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		u32 u = vs[i];
-
-		u &= ~masks[i];
-		u |= vals[i];
-		if (u != vs[i])
-			changed = true;
-
-		vs[i] = u;
-	}
-
-	if (!changed)
-		return 0;
-
-	return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
-		       unsigned int num_regs)
-{
-	bool changed = false;
-	u32 vs[4];
-	int res;
-
-	BUILD_BUG_ON(num_regs > ARRAY_SIZE(vs));
-
-	res = yt921x_regs_read(priv, reg, vs, num_regs);
-	if (res)
-		return res;
-
-	for (unsigned int i = 0; i < num_regs; i++) {
-		u32 u = vs[i];
-
-		u &= ~masks[i];
-		if (u != vs[i])
-			changed = true;
-
-		vs[i] = u;
-	}
-
-	if (!changed)
-		return 0;
-
-	return yt921x_regs_write(priv, reg, vs, num_regs);
-}
-
-static int
-yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
-	return yt921x_regs_write(priv, reg, vals, 2);
-}
-
-static int
-yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
-			 const u32 *vals)
-{
-	return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
-}
-
-static int
-yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
-{
-	return yt921x_regs_clear_bits(priv, reg, masks, 2);
-}
-
-static int
-yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
-{
-	return yt921x_regs_write(priv, reg, vals, 3);
-}
-
 static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)
 {
 	struct yt921x_reg_mdio *mdio = context;
@@ -4786,6 +4580,12 @@ static int yt921x_dsa_setup(struct dsa_switch *ds)
 	if (res)
 		return res;
 
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+	res = yt921x_leds_setup(priv);
+	if (res)
+		dev_warn(dev, "Failed to setup LEDs: %d\n", res);
+#endif
+
 	return 0;
 }
 
@@ -4886,6 +4686,10 @@ static void yt921x_mdio_remove(struct mdio_device *mdiodev)
 	if (!priv)
 		return;
 
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+	yt921x_leds_remove(priv);
+#endif
+
 	for (size_t i = ARRAY_SIZE(priv->ports); i-- > 0; ) {
 		struct yt921x_port *pp = &priv->ports[i];
 
diff --git a/drivers/net/dsa/yt921x.h b/drivers/net/dsa/motorcomm/chip.h
similarity index 99%
rename from drivers/net/dsa/yt921x.h
rename to drivers/net/dsa/motorcomm/chip.h
index 55504652666952..de41430579313c 100644
--- a/drivers/net/dsa/yt921x.h
+++ b/drivers/net/dsa/motorcomm/chip.h
@@ -850,9 +850,13 @@ enum yt921x_fdb_entry_status {
 #define YT921X_ACL_NUM		(YT921X_ACL_BLK_NUM * YT921X_ACL_ENT_PER_BLK)
 #define YT921X_UDF_NUM		8
 
+#define YT921X_LED_GROUP_NUM	3
+
 /* 8 internal + 2 external + 1 mcu */
 #define YT921X_PORT_NUM			11
 
+#define YT921X_NAME	"yt921x"
+
 #define yt921x_port_is_internal(port) ((port) < 8)
 #define yt921x_port_is_external(port) (8 <= (port) && (port) < 9)
 
@@ -938,6 +942,13 @@ struct yt921x_port {
 	struct yt921x_mib mib;
 	u64 rx_frames;
 	u64 tx_frames;
+
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+	unsigned char led_duty;
+	unsigned short led_cycle;
+
+	struct yt921x_led *leds[YT921X_LED_GROUP_NUM];
+#endif
 };
 
 struct yt921x_reg_ops {
diff --git a/drivers/net/dsa/motorcomm/leds.c b/drivers/net/dsa/motorcomm/leds.c
new file mode 100644
index 00000000000000..85c9bb139ead89
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/leds.c
@@ -0,0 +1,647 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/uleds.h>
+
+#include "chip.h"
+#include "leds.h"
+#include "smi.h"
+
+#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)
+{
+	switch (group) {
+	case 0:
+	default:
+		return YT921X_LED0_PORTn(port);
+	case 1:
+		return YT921X_LED1_PORTn(port);
+	case 2:
+		return YT921X_LED2_PORTn(port);
+	}
+}
+
+static int
+yt921x_led_force_get(struct yt921x_priv *priv, int port, int group, bool *onp)
+{
+	u32 val;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+	if (res)
+		return res;
+
+	*onp = (val & YT921X_LED2_PORT_FORCEn_M(group)) ==
+	       YT921X_LED2_PORT_FORCEn_ON(group);
+	return 0;
+}
+
+static int
+yt921x_led_force_set(struct yt921x_priv *priv, int port, int group, bool on)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct yt921x_led *led = pp->leds[group];
+	u32 ctrl;
+	u32 mask;
+
+	led->use_cycle = false;
+	led->use_duty = false;
+
+	mask = YT921X_LED2_PORT_FORCEn_M(group);
+	ctrl = on ? YT921X_LED2_PORT_FORCEn_ON(group) :
+	       YT921X_LED2_PORT_FORCEn_OFF(group);
+	return yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port), mask,
+				      ctrl);
+}
+
+static int
+yt921x_led_blink_select(const struct yt921x_priv *priv, unsigned long on,
+			unsigned long off, unsigned short *cyclep,
+			unsigned char *dutyp)
+{
+	static const unsigned char dutys[] = {
+		YT921X_LED_DUTY(1, 6),
+		YT921X_LED_DUTY(1, 4),
+		YT921X_LED_DUTY(1, 3),
+		YT921X_LED_DUTY(1, 2),
+	};
+	unsigned int cycle_upper;
+	unsigned int cycle_req;
+	unsigned int duty_req;
+	unsigned int cycle;
+	unsigned int duty;
+
+	cycle = YT921X_LED_BLINK_MAX;
+	cycle_upper = cycle * 11585 / 8192 + 1;  /* M_SQRT2 * cycle */
+	if (check_add_overflow(on, off, &cycle_req) || cycle_req >= cycle_upper)
+		return -EOPNOTSUPP;
+
+	for (; cycle > YT921X_LED_BLINK_MIN; cycle_upper >>= 1, cycle >>= 1)
+		if (cycle_req >= cycle_upper >> 1)
+			break;
+	*cyclep = cycle;
+
+	duty_req = DIV_ROUND_CLOSEST(YT921X_LED_DUTY_DENOM *
+				     (on > off ? off : on), cycle_req);
+	for (unsigned int i = ARRAY_SIZE(dutys) - 1;; i--)
+		if (i == 0 || duty_req >= (dutys[i - 1] + dutys[i]) / 2) {
+			duty = dutys[i];
+			break;
+		}
+	if (on > off)
+		duty = YT921X_LED_DUTY_DENOM - duty;
+	*dutyp = duty;
+
+	return 0;
+}
+
+static int
+yt921x_led_blink_set(struct yt921x_priv *priv, int port, int group,
+		     unsigned long *onp, unsigned long *offp)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct yt921x_led *led = pp->leds[group];
+	unsigned short cycle;
+	unsigned char duty;
+	bool use_cycle;
+	u32 ctrl;
+	u32 mask;
+	u32 val;
+	int res;
+
+	if (!*onp && !*offp) {
+		cycle = YT921X_LED_BLINK_DEF;
+		duty = YT921X_LED_DUTY(1, 2);
+		for (unsigned int i = 0; i < YT921X_LED_GROUP_NUM; i++)
+			if (i != group && pp->leds[i] &&
+			    pp->leds[i]->use_duty) {
+				duty = pp->led_duty;
+				break;
+			}
+
+		use_cycle = false;
+	} else {
+		bool change_cycle;
+		bool change_duty;
+
+		res = yt921x_led_blink_select(priv, *onp, *offp, &cycle, &duty);
+		if (res)
+			return res;
+
+		use_cycle = cycle < YT921X_LED_BLINK_DEF;
+		change_cycle = use_cycle && cycle != pp->led_cycle;
+		change_duty = duty != pp->led_duty;
+		if (change_cycle || change_duty)
+			for (unsigned int i = 0; i < YT921X_LED_GROUP_NUM;
+			     i++) {
+				if (i == group || !pp->leds[i])
+					continue;
+				if ((change_cycle && pp->leds[i]->use_cycle) ||
+				    (change_duty && pp->leds[i]->use_duty))
+					return -EOPNOTSUPP;
+			}
+	}
+
+	/* The chip seems to jam a while if changing duty directly */
+	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+	if (res)
+		return res;
+
+	ctrl = val & ~YT921X_LED2_PORT_FORCEn_M(group);
+	ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+	if (val != ctrl) {
+		res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
+		if (res)
+			return res;
+	}
+
+	mask = YT921X_LED1_PORT_BLINK_DUTY_M | YT921X_LED1_PORT_BLINK_DUTY_COMP;
+	switch (duty >= YT921X_LED_DUTY(1, 2) ? duty :
+		YT921X_LED_DUTY_DENOM - duty) {
+	default:
+		duty = YT921X_LED_DUTY(1, 2);
+		fallthrough;
+	case YT921X_LED_DUTY(1, 2):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_1_2;
+		break;
+	case YT921X_LED_DUTY(2, 3):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_2_3;
+		break;
+	case YT921X_LED_DUTY(3, 4):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_3_4;
+		break;
+	case YT921X_LED_DUTY(5, 6):
+		ctrl = YT921X_LED1_PORT_BLINK_DUTY_5_6;
+		break;
+	}
+	if (duty < YT921X_LED_DUTY(1, 2))
+		ctrl |= YT921X_LED1_PORT_BLINK_DUTY_COMP;
+	if (use_cycle) {
+		mask |= YT921X_LED1_PORT_OTHER_BLINK_M;
+		ctrl |= YT921X_LED1_PORT_OTHER_BLINK(9 - __fls(cycle));
+	}
+	res = yt921x_reg_update_bits(priv, YT921X_LED1_PORTn(port), mask, ctrl);
+	if (res)
+		return res;
+
+	ctrl = val & ~(YT921X_LED2_PORT_FORCEn_M(group) |
+		       YT921X_LED2_PORT_FORCE_BLINKn_M(group));
+	ctrl |= YT921X_LED2_PORT_FORCEn_BLINK(group);
+	if (use_cycle)
+		ctrl |= YT921X_LED2_PORT_FORCE_BLINKn_OTHER(group);
+	else
+		ctrl |= YT921X_LED2_PORT_FORCE_BLINKn(group, __fls(cycle) - 9);
+	res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
+	if (res)
+		return res;
+
+	led->use_cycle = use_cycle;
+	if (use_cycle)
+		pp->led_cycle = cycle;
+	led->use_duty = true;
+	pp->led_duty = duty;
+
+	*onp = DIV_ROUND_CLOSEST(duty * cycle, YT921X_LED_DUTY_DENOM);
+	*offp = cycle - *onp;
+	return 0;
+}
+
+struct yt921x_led_trigger_map {
+	unsigned long flags;
+	u32 mask;
+};
+
+static const struct yt921x_led_trigger_map yt921x_led_trigger_maps[] = {
+	{BIT(TRIGGER_NETDEV_LINK),
+	 YT921X_LEDx_PORT_ACT_DUPLEX_HALF | YT921X_LEDx_PORT_ACT_DUPLEX_FULL},
+	{BIT(TRIGGER_NETDEV_LINK_10), YT921X_LEDx_PORT_ACT_10M},
+	{BIT(TRIGGER_NETDEV_LINK_100), YT921X_LEDx_PORT_ACT_100M},
+	{BIT(TRIGGER_NETDEV_LINK_1000), YT921X_LEDx_PORT_ACT_1000M},
+	{BIT(TRIGGER_NETDEV_HALF_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_HALF},
+	{BIT(TRIGGER_NETDEV_FULL_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_FULL},
+	{BIT(TRIGGER_NETDEV_TX), YT921X_LEDx_PORT_ACT_TX_BLINK},
+	{BIT(TRIGGER_NETDEV_RX), YT921X_LEDx_PORT_ACT_RX_BLINK},
+	{BIT(TRIGGER_NETDEV_TX_ERR) | BIT(TRIGGER_NETDEV_RX_ERR),
+	 YT921X_LEDx_PORT_ACT_COLLISION_BLINK},
+};
+
+static bool
+yt921x_led_trigger_is_supported(const struct yt921x_priv *priv, int port,
+				int group, unsigned long flags)
+{
+	if (!flags)
+		return true;
+
+	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
+		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
+
+		if ((flags & map->flags) == map->flags) {
+			flags &= ~map->flags;
+			if (!flags)
+				return true;
+		}
+	}
+
+	return false;
+}
+
+static int
+yt921x_led_trigger_get(struct yt921x_priv *priv, int port, int group,
+		       unsigned long *flagsp)
+{
+	u32 addr;
+	u32 val;
+	int res;
+
+	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
+	if (res)
+		return res;
+
+	if ((val & YT921X_LED2_PORT_FORCEn_M(group)) !=
+	    YT921X_LED2_PORT_FORCEn_DONTCARE(group)) {
+		*flagsp = 0;
+		return 0;
+	}
+
+	if (group != 2) {
+		addr = yt921x_led_regaddr(priv, port, group);
+		res = yt921x_reg_read(priv, addr, &val);
+		if (res)
+			return res;
+	}
+
+	*flagsp = 0;
+	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
+		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
+
+		if ((val & map->mask) == map->mask)
+			*flagsp |= map->flags;
+	}
+
+	return 0;
+}
+
+static int
+yt921x_led_trigger_set(struct yt921x_priv *priv, int port, int group,
+		       unsigned long flags)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct yt921x_led *led = pp->leds[group];
+	u32 addr;
+	u32 ctrl;
+	u32 mask;
+	int res;
+
+	ctrl = 0;
+	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
+		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
+
+		if ((flags & map->flags) == map->flags) {
+			flags &= ~map->flags;
+			ctrl |= map->mask;
+			if (!flags)
+				break;
+		}
+	}
+	if (flags)
+		return -EOPNOTSUPP;
+
+	led->use_cycle = false;
+	led->use_duty = false;
+
+	mask = !group ? YT921X_LED0_PORT_ACT_M : YT921X_LEDx_PORT_ACT_M;
+	if (group == 2) {
+		mask |= YT921X_LED2_PORT_FORCEn_M(group);
+		ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+	}
+	addr = yt921x_led_regaddr(priv, port, group);
+	res = yt921x_reg_update_bits(priv, addr, mask, ctrl);
+	if (res)
+		return res;
+
+	if (group != 2) {
+		mask = YT921X_LED2_PORT_FORCEn_M(group);
+		ctrl = YT921X_LED2_PORT_FORCEn_DONTCARE(group);
+		res = yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port),
+					     mask, ctrl);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+static int
+yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,
+				    enum led_brightness brightness)
+{
+	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);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_force_set(priv, pp->index, led->group, brightness);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int
+yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
+		      unsigned long *delay_off)
+{
+	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);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_blink_set(priv, pp->index, led->group, delay_on,
+				   delay_off);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static struct device * __maybe_unused
+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 dsa_port *dp;
+
+	dp = dsa_to_port(&priv->ds, pp->index);
+	if (!dp || !dp->user)
+		return NULL;
+	return &dp->user->dev;
+}
+
+static int __maybe_unused
+yt921x_cled_hw_control_is_supported(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);
+
+	if (yt921x_led_trigger_is_supported(priv, pp->index, led->group, flags))
+		return 0;
+	return -EOPNOTSUPP;
+}
+
+static int __maybe_unused
+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);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_trigger_get(priv, pp->index, led->group, flagsp);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int __maybe_unused
+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);
+	int res;
+
+	mutex_lock(&priv->reg_lock);
+	res = yt921x_led_trigger_set(priv, pp->index, led->group, flags);
+	mutex_unlock(&priv->reg_lock);
+
+	return res;
+}
+
+static int
+yt921x_led_setup(struct yt921x_priv *priv, int port,
+		 struct fwnode_handle *fwnode, u32 *inv_maskp, u32 *inv_ctrlp)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct device *dev = to_device(priv);
+	struct led_init_data init_data;
+	struct led_classdev *led_cdev;
+	char name[LED_MAX_NAME_SIZE];
+	enum led_default_state state;
+	struct yt921x_led *led;
+	bool force_high;
+	bool force_low;
+	int polarity;
+	u32 group;
+	bool on;
+	int res;
+
+	res = fwnode_property_read_u32(fwnode, "reg", &group);
+	if (res)
+		return res;
+	if (group >= YT921X_LED_GROUP_NUM) {
+		dev_err(dev, "Invalid LED reg %u for port %d\n", group, port);
+		return -EINVAL;
+	}
+	if (pp->leds[group])
+		return -EEXIST;
+
+	force_high = fwnode_property_read_bool(fwnode, "active-high");
+	force_low = fwnode_property_read_bool(fwnode, "active-low");
+	if (force_high && force_low) {
+		dev_err(dev, "Duplicate polarities for LED %02d:%02u\n",
+			port, group);
+		return -EINVAL;
+	}
+	polarity = force_high ? 1 : force_low ? -1 : 0;
+
+	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
+	if (!led)
+		return -ENOMEM;
+	led->port = pp;
+	led->group = group;
+
+	state = led_init_default_state_get(fwnode);
+
+	mutex_lock(&priv->reg_lock);
+	pp->leds[group] = led;
+	switch (state) {
+	case LEDS_DEFSTATE_OFF:
+	case LEDS_DEFSTATE_ON:
+	default:
+		on = state == LEDS_DEFSTATE_ON;
+		res = yt921x_led_force_set(priv, port, group, on);
+		break;
+	case LEDS_DEFSTATE_KEEP:
+		res = yt921x_led_force_get(priv, port, group, &on);
+		break;
+	}
+	mutex_unlock(&priv->reg_lock);
+	if (res)
+		goto err;
+
+	led_cdev = &led->cdev;
+	led_cdev->brightness = on;
+	led_cdev->max_brightness = 1;
+	led_cdev->flags = LED_RETAIN_AT_SHUTDOWN;
+	led_cdev->brightness_set_blocking = yt921x_cled_brightness_set_blocking;
+	led_cdev->blink_set = yt921x_cled_blink_set;
+#ifdef CONFIG_LEDS_TRIGGERS
+	led_cdev->hw_control_trigger = "netdev";
+	led_cdev->hw_control_get_device = yt921x_cled_hw_control_get_device;
+	led_cdev->hw_control_is_supported = yt921x_cled_hw_control_is_supported;
+	led_cdev->hw_control_get = yt921x_cled_hw_control_get;
+	led_cdev->hw_control_set = yt921x_cled_hw_control_set;
+#endif
+
+	snprintf(name, sizeof(name), YT921X_NAME "-%u:%02d:%02u",
+		 priv->ds.index, port, group);
+	init_data = (typeof(init_data)){
+		.fwnode = fwnode,
+		.devicename = name,
+		.devname_mandatory = true,
+	};
+	res = devm_led_classdev_register_ext(dev, led_cdev, &init_data);
+	if (res)
+		goto err;
+
+	if (polarity) {
+		u32 bit = YT921X_LED_PAR_INV_INVnm(group, port);
+
+		*inv_maskp |= bit;
+		if (polarity > 0)
+			*inv_ctrlp |= bit;
+	}
+	return 0;
+
+err:
+	mutex_lock(&priv->reg_lock);
+	pp->leds[group] = NULL;
+	mutex_unlock(&priv->reg_lock);
+
+	devm_kfree(dev, led);
+	return res;
+}
+
+static void yt921x_leds_remove_port(struct yt921x_priv *priv, int port)
+{
+	struct yt921x_port *pp = &priv->ports[port];
+	struct device *dev = to_device(priv);
+
+	for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
+		struct yt921x_led *led = pp->leds[group];
+
+		if (led)
+			devm_led_classdev_unregister(dev, &led->cdev);
+	}
+
+	for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
+		struct yt921x_led *led = pp->leds[group];
+
+		if (led) {
+			pp->leds[group] = NULL;
+			devm_kfree(dev, led);
+		}
+	}
+}
+
+static int
+yt921x_leds_setup_port(struct yt921x_priv *priv, int port, u32 *inv_maskp,
+		       u32 *inv_ctrlp)
+{
+	struct dsa_switch *ds = &priv->ds;
+	struct device_node *leds_np;
+	struct dsa_port *dp;
+	int res;
+
+	dp = dsa_to_port(ds, port);
+	leds_np = of_get_child_by_name(dp->dn, "leds");
+	if (!leds_np)
+		return 0;
+
+	for_each_child_of_node_scoped(leds_np, led_np) {
+		res = yt921x_led_setup(priv, port, of_fwnode_handle(led_np),
+				       inv_maskp, inv_ctrlp);
+		if (res) {
+			of_node_put(leds_np);
+			goto err;
+		}
+	}
+
+	of_node_put(leds_np);
+	return 0;
+
+err:
+	yt921x_leds_remove_port(priv, port);
+	return res;
+}
+
+void yt921x_leds_remove(struct yt921x_priv *priv)
+{
+	for (int port = 0; port < YT921X_PORT_NUM; port++)
+		yt921x_leds_remove_port(priv, port);
+}
+
+int yt921x_leds_setup(struct yt921x_priv *priv)
+{
+	struct device *dev = to_device(priv);
+	struct dsa_switch *ds = &priv->ds;
+	struct dsa_port *dp;
+	u32 inv_ctrl = 0;
+	u32 inv_mask = 0;
+	u32 ctrl;
+	u32 mask;
+	int res;
+
+	dsa_switch_for_each_port(dp, ds) {
+		int port = dp->index;
+
+		if (!dp->dn)
+			continue;
+
+		res = yt921x_leds_setup_port(priv, port, &inv_mask, &inv_ctrl);
+		if (res)
+			dev_warn(dev, "Failed to setup LEDs for port %d: %d\n",
+				 port, res);
+	}
+
+	mutex_lock(&priv->reg_lock);
+
+	/* Inversion is internal - force on will give low logic.
+	 * In the rest of the file, treat LEDs as if active-low.
+	 */
+	if (inv_mask) {
+		res = yt921x_reg_update_bits(priv, YT921X_LED_PAR_INV, inv_mask,
+					     inv_ctrl);
+		if (res)
+			goto end;
+	}
+
+	mask = YT921X_LED_CTRL_MODE_M | YT921X_LED_CTRL_PORT_NUM_M |
+	       YT921X_LED_CTRL_EN;
+	ctrl = YT921X_LED_CTRL_MODE_PARALLEL |
+	       YT921X_LED_CTRL_PORT_NUM(YT921X_PORT_NUM - 1) |
+	       YT921X_LED_CTRL_EN;
+	res = yt921x_reg_update_bits(priv, YT921X_LED_CTRL, mask, ctrl);
+
+end:
+	mutex_unlock(&priv->reg_lock);
+
+	if (res) {
+		yt921x_leds_remove(priv);
+		return res;
+	}
+
+	return 0;
+}
diff --git a/drivers/net/dsa/motorcomm/leds.h b/drivers/net/dsa/motorcomm/leds.h
new file mode 100644
index 00000000000000..67373a190c8f4b
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/leds.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_LEDS_H
+#define _YT_LEDS_H
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/kconfig.h>
+#include <linux/leds.h>
+
+#define YT921X_LED_CTRL			0xd0000
+#define  YT921X_LED_CTRL_EN			BIT(21)
+#define  YT921X_LED_CTRL_LOOPDETECT_BLINK_M	GENMASK(20, 19)	/* cycle = 512 * x ms */
+#define   YT921X_LED_CTRL_LOOPDETECT_BLINK(x)		FIELD_PREP(YT921X_LED_CTRL_LOOPDETECT_BLINK_M, (x))
+#define  YT921X_LED_CTRL_PORT_NUM_M		GENMASK(16, 13)
+#define   YT921X_LED_CTRL_PORT_NUM(x)			FIELD_PREP(YT921X_LED_CTRL_PORT_NUM_M, (x))
+#define  YT921X_LED_CTRL_MODE_M			GENMASK(1, 0)
+#define   YT921X_LED_CTRL_MODE(x)			FIELD_PREP(YT921X_LED_CTRL_MODE_M, (x))
+#define   YT921X_LED_CTRL_MODE_PARALLEL			YT921X_LED_CTRL_MODE(0)
+#define   YT921X_LED_CTRL_MODE_SERIAL			YT921X_LED_CTRL_MODE(2)
+#define YT921X_LED0_PORTn(port)		(0xd0004 + 4 * (port))
+#define  YT921X_LED0_PORT_ACT_M			GENMASK(17, 0)
+#define  YT921X_LED0_PORT_ACT_LINK_TRY_DIS	BIT(17)
+#define  YT921X_LED0_PORT_ACT_COLLISION_BLINK_INDI	BIT(16)
+#define YT921X_LED1_PORTn(port)		(0xd0040 + 4 * (port))
+#define  YT921X_LED1_PORT_OTHER_BLINK_M		GENMASK(31, 30)	/* cycle = 512 >> x ms */
+#define   YT921X_LED1_PORT_OTHER_BLINK(x)		FIELD_PREP(YT921X_LED1_PORT_OTHER_BLINK_M, (x))
+#define  YT921X_LED1_PORT_EEE_BLINK_M		GENMASK(29, 28)	/* cycle = 512 >> x ms */
+#define   YT921X_LED1_PORT_EEE_BLINK(x)			FIELD_PREP(YT921X_LED1_PORT_EEE_BLINK_M, (x))
+#define  YT921X_LED1_PORT_BLINK_DUTY_COMP	BIT(27)
+#define  YT921X_LED1_PORT_BLINK_DUTY_M		GENMASK(26, 25)
+#define   YT921X_LED1_PORT_BLINK_DUTY(x)		FIELD_PREP(YT921X_LED1_PORT_BLINK_DUTY_M, (x))
+#define   YT921X_LED1_PORT_BLINK_DUTY_1_2		YT921X_LED1_PORT_BLINK_DUTY(0)
+#define   YT921X_LED1_PORT_BLINK_DUTY_2_3		YT921X_LED1_PORT_BLINK_DUTY(1)
+#define   YT921X_LED1_PORT_BLINK_DUTY_3_4		YT921X_LED1_PORT_BLINK_DUTY(2)
+#define   YT921X_LED1_PORT_BLINK_DUTY_5_6		YT921X_LED1_PORT_BLINK_DUTY(3)
+#define YT921X_LED2_PORTn(port)		(0xd0080 + 4 * (port))
+#define  YT921X_LED2_PORT_FORCEn_M(grp)		GENMASK(4 * (grp) + 19, 4 * (grp) + 18)
+#define   YT921X_LED2_PORT_FORCEn(grp, x)		((x) << (4 * (grp) + 18))
+#define   YT921X_LED2_PORT_FORCEn_DONTCARE(grp)		YT921X_LED2_PORT_FORCEn(grp, 0)
+#define   YT921X_LED2_PORT_FORCEn_BLINK(grp)		YT921X_LED2_PORT_FORCEn(grp, 1)
+#define   YT921X_LED2_PORT_FORCEn_ON(grp)		YT921X_LED2_PORT_FORCEn(grp, 2)
+#define   YT921X_LED2_PORT_FORCEn_OFF(grp)		YT921X_LED2_PORT_FORCEn(grp, 3)
+#define  YT921X_LED2_PORT_FORCE_BLINKn_M(grp)	GENMASK(4 * (grp) + 17, 4 * (grp) + 16)	/* cycle = 512 << x ms */
+#define   YT921X_LED2_PORT_FORCE_BLINKn(grp, x)		((x) << (4 * (grp) + 16))
+#define   YT921X_LED2_PORT_FORCE_BLINKn_OTHER(grp)	YT921X_LED2_PORT_FORCE_BLINKn(grp, 3)
+#define  YT921X_LEDx_PORT_ACT_M			GENMASK(15, 0)
+#define  YT921X_LEDx_PORT_ACT_EEE_BLINK		BIT(15)
+#define  YT921X_LEDx_PORT_ACT_LOOPDETECT_BLINK	BIT(14)
+#define  YT921X_LEDx_PORT_ACT_ACTIVE_BLINK	BIT(13)
+#define  YT921X_LEDx_PORT_ACT_DUPLEX_FULL	BIT(12)
+#define  YT921X_LEDx_PORT_ACT_DUPLEX_HALF	BIT(11)
+#define  YT921X_LEDx_PORT_ACT_TX_BLINK		BIT(10)
+#define  YT921X_LEDx_PORT_ACT_RX_BLINK		BIT(9)
+#define  YT921X_LEDx_PORT_ACT_TX		BIT(8)
+#define  YT921X_LEDx_PORT_ACT_RX		BIT(7)
+#define  YT921X_LEDx_PORT_ACT_1000M		BIT(6)
+#define  YT921X_LEDx_PORT_ACT_100M		BIT(5)
+#define  YT921X_LEDx_PORT_ACT_10M		BIT(4)
+#define  YT921X_LEDx_PORT_ACT_COLLISION_BLINK	BIT(3)
+#define  YT921X_LEDx_PORT_ACT_1000M_BLINK	BIT(2)
+#define  YT921X_LEDx_PORT_ACT_100M_BLINK	BIT(1)
+#define  YT921X_LEDx_PORT_ACT_10M_BLINK		BIT(0)
+#define YT921X_LED_SER_CTRL		0xd0100
+#define  YT921X_LED_SER_CTRL_UNK		GENMASK(25, 24)	/* delay? */
+#define  YT921X_LED_SER_CTRL_ACTIVE_LOW		BIT(4)
+#define  YT921X_LED_SER_CTRL_GRP_NUM_M		GENMASK(1, 0)	/* #grp - 1 */
+#define   YT921X_LED_SER_CTRL_GRP_NUM(x)		FIELD_PREP(YT921X_LED_SER_CTRL_GRP_NUM_M, (x))
+#define YT921X_LED_SER_MAPnm(grp, port)	(0xd0104 + 8 * (2 - (grp)) + 4 * ((port) / 5))
+#define  YT921X_LED_SER_MAP_DSTn_PORT_M(port)	GENMASK(6 * ((port) % 5) + 5, 6 * ((port) % 5) + 2)
+#define   YT921X_LED_SER_MAP_DSTn_PORT(port, x)		((x) << (6 * ((port) % 5) + 2))
+#define  YT921X_LED_SER_MAP_DSTn_LED_M(port)	GENMASK(6 * ((port) % 5) + 1, 6 * ((port) % 5))
+#define   YT921X_LED_SER_MAP_DSTn_LED(port, x)		((x) << (6 * ((port) % 5)))
+#define YT921X_LED_PAR_PORTS		0xd01c4
+#define YT921X_LED_PAR_INV		0xd01c8
+#define  YT921X_LED_PAR_INV_INVnm(grp, port)	BIT(10 * (grp) + (port))
+#define YT921X_LED_PAR_MAPn(port)	(0xd01d0 + 4 * (port))
+#define  YT921X_LED_PAR_MAP_DSTn_PORT_M(grp)	GENMASK(6 * (grp) + 5, 6 * (grp) + 2)
+#define   YT921X_LED_PAR_MAP_DSTn_PORT(grp, x)		((x) << (6 * (grp) + 2))
+#define  YT921X_LED_PAR_MAP_DSTn_LED_M(grp)	GENMASK(6 * (grp) + 1, 6 * (grp))
+#define   YT921X_LED_PAR_MAP_DSTn_LED(grp, x)		((x) << (6 * (grp)))
+
+#define YT921X_LED_BLINK_MIN	64
+#define YT921X_LED_BLINK_DEF	512
+#define YT921X_LED_BLINK_MAX	2048
+
+/* 2 * lcm(2, 3, 4, 6) */
+#define YT921X_LED_DUTY_DENOM		24
+#define YT921X_LED_DUTY(nom, denom)	(YT921X_LED_DUTY_DENOM * (nom) / (denom))
+
+struct yt921x_priv;
+
+struct yt921x_led {
+	struct led_classdev cdev;
+	struct yt921x_port *port;
+	unsigned char group;
+
+	bool use_cycle:1;
+	bool use_duty:1;
+};
+
+#if IS_ENABLED(CONFIG_NET_DSA_YT921X_LEDS)
+
+void yt921x_leds_remove(struct yt921x_priv *priv);
+int yt921x_leds_setup(struct yt921x_priv *priv);
+
+#else
+
+static inline void yt921x_leds_remove(struct yt921x_priv *priv) {}
+
+static inline int yt921x_leds_setup(struct yt921x_priv *priv)
+{
+	return 0;
+}
+
+#endif
+
+#endif
diff --git a/drivers/net/dsa/motorcomm/smi.c b/drivers/net/dsa/motorcomm/smi.c
new file mode 100644
index 00000000000000..9054896e4cd12b
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.c
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#include <linux/iopoll.h>
+
+#include "chip.h"
+#include "smi.h"
+
+#define YT921X_POLL_SLEEP_US	10000
+#define YT921X_POLL_TIMEOUT_US	100000
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp)
+{
+	lockdep_assert_held_once(&priv->reg_lock);
+
+	return priv->reg_ops->read(priv->reg_ctx, reg, valp);
+}
+
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val)
+{
+	lockdep_assert_held_once(&priv->reg_lock);
+
+	return priv->reg_ops->write(priv->reg_ctx, reg, val);
+}
+
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp)
+{
+	u32 val;
+	int res;
+	int ret;
+
+	ret = read_poll_timeout(yt921x_reg_read, res,
+				res || (val & mask) == *valp,
+				YT921X_POLL_SLEEP_US, YT921X_POLL_TIMEOUT_US,
+				false, priv, reg, &val);
+	if (ret)
+		return ret;
+	if (res)
+		return res;
+
+	*valp = val;
+	return 0;
+}
+
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask, u32 val)
+{
+	int res;
+	u32 v;
+	u32 u;
+
+	res = yt921x_reg_read(priv, reg, &v);
+	if (res)
+		return res;
+
+	u = v;
+	u &= ~mask;
+	u |= val;
+	if (u == v)
+		return 0;
+
+	return yt921x_reg_write(priv, reg, u);
+}
+
+int
+yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+		 unsigned int num_regs)
+{
+	int res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		res = yt921x_reg_read(priv, reg + 4 * i, &vals[i]);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+int
+yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+		  unsigned int num_regs)
+{
+	int res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		res = yt921x_reg_write(priv, reg + 4 * i, vals[i]);
+		if (res)
+			return res;
+	}
+
+	return 0;
+}
+
+int
+yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			const u32 *vals, unsigned int num_regs)
+{
+	bool changed = false;
+	u32 vs[4];
+	int res;
+
+	if (WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs)))
+		return -EINVAL;
+
+	res = yt921x_regs_read(priv, reg, vs, num_regs);
+	if (res)
+		return res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		u32 u = vs[i];
+
+		u &= ~masks[i];
+		u |= vals[i];
+		if (u != vs[i])
+			changed = true;
+
+		vs[i] = u;
+	}
+
+	if (!changed)
+		return 0;
+
+	return yt921x_regs_write(priv, reg, vs, num_regs);
+}
+
+int
+yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+		       unsigned int num_regs)
+{
+	bool changed = false;
+	u32 vs[4];
+	int res;
+
+	if (WARN_ON_ONCE(num_regs > ARRAY_SIZE(vs)))
+		return -EINVAL;
+
+	res = yt921x_regs_read(priv, reg, vs, num_regs);
+	if (res)
+		return res;
+
+	for (unsigned int i = 0; i < num_regs; i++) {
+		u32 u = vs[i];
+
+		u &= ~masks[i];
+		if (u != vs[i])
+			changed = true;
+
+		vs[i] = u;
+	}
+
+	if (!changed)
+		return 0;
+
+	return yt921x_regs_write(priv, reg, vs, num_regs);
+}
diff --git a/drivers/net/dsa/motorcomm/smi.h b/drivers/net/dsa/motorcomm/smi.h
new file mode 100644
index 00000000000000..2e956065eb90ee
--- /dev/null
+++ b/drivers/net/dsa/motorcomm/smi.h
@@ -0,0 +1,88 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2026 David Yang
+ */
+
+#ifndef _YT_SMI_H
+#define _YT_SMI_H
+
+#include <linux/types.h>
+#include <linux/wordpart.h>
+
+struct yt921x_priv;
+
+int yt921x_reg_read(struct yt921x_priv *priv, u32 reg, u32 *valp);
+int yt921x_reg_write(struct yt921x_priv *priv, u32 reg, u32 val);
+int yt921x_reg_wait(struct yt921x_priv *priv, u32 reg, u32 mask, u32 *valp);
+int yt921x_reg_update_bits(struct yt921x_priv *priv, u32 reg, u32 mask,
+			   u32 val);
+
+static inline int
+yt921x_reg_set_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+	return yt921x_reg_update_bits(priv, reg, 0, mask);
+}
+
+static inline int
+yt921x_reg_clear_bits(struct yt921x_priv *priv, u32 reg, u32 mask)
+{
+	return yt921x_reg_update_bits(priv, reg, mask, 0);
+}
+
+static inline int
+yt921x_reg_toggle_bits(struct yt921x_priv *priv, u32 reg, u32 mask, bool set)
+{
+	return yt921x_reg_update_bits(priv, reg, mask, !set ? 0 : mask);
+}
+
+/* Some multi-word registers, like VLANn_CTRL, should be treated as a single
+ * long register. More specifically, writes to parts of its words won't become
+ * visible, until the last word is written.
+ *
+ * Here we require full read and write operations over these registers to
+ * eliminate potential issues, although partial reads/writes are also possible.
+ */
+
+static inline void update_ctrls_unaligned(u32 *lo, u32 *hi, u64 mask, u64 val)
+{
+	*lo &= ~lower_32_bits(mask);
+	*hi &= ~upper_32_bits(mask);
+	*lo |= lower_32_bits(val);
+	*hi |= upper_32_bits(val);
+}
+
+int yt921x_regs_read(struct yt921x_priv *priv, u32 reg, u32 *vals,
+		     unsigned int num_regs);
+int yt921x_regs_write(struct yt921x_priv *priv, u32 reg, const u32 *vals,
+		      unsigned int num_regs);
+int yt921x_regs_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			    const u32 *vals, unsigned int num_regs);
+int yt921x_regs_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			   unsigned int num_regs);
+
+static inline int
+yt921x_reg64_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+	return yt921x_regs_write(priv, reg, vals, 2);
+}
+
+static inline int
+yt921x_reg64_update_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks,
+			 const u32 *vals)
+{
+	return yt921x_regs_update_bits(priv, reg, masks, vals, 2);
+}
+
+static inline int
+yt921x_reg64_clear_bits(struct yt921x_priv *priv, u32 reg, const u32 *masks)
+{
+	return yt921x_regs_clear_bits(priv, reg, masks, 2);
+}
+
+static inline int
+yt921x_reg96_write(struct yt921x_priv *priv, u32 reg, const u32 *vals)
+{
+	return yt921x_regs_write(priv, reg, vals, 3);
+}
+
+#endif

3/2 2026/07/25 02:31 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 20991
							output: 19
							thoughts: 867
						

Thoughts:
**Analyzing the WorthFuzzing Potential of the Motorcomm YT9215 LED Driver Patch**

Okay, so I have a patch here that's adding LED support to the Motorcomm YT9215 Ethernet switch chip driver. The code is located in `drivers/net/dsa/motorcomm/`. The patch renames a file and introduces `leds.c` and `smi.c`. My initial thought is: this is for a *specific* switch chip, the YT9215. The question becomes, can I even *reach* this driver within a virtualized environment like QEMU?

Typically, these DSA (Distributed Switch Architecture) switches are hardware devices, hooked up through MDIO or SPI. My experience tells me that these aren't easily emulated or fuzzed in a standard QEMU setup. I remember the instructions, "Return WorthFuzzing=false if the patch only contains...vendor-specific PCIe switch...". This seems like it *could* fall into that category, as this is a DSA switch chip communicating via MDIO.

But, I know MDIO devices *can* be fuzzed, theoretically. Is it possible with *this* particular chip? Usually, MDIO devices are not emulated, unless there's some kind of dummy MDIO bus setup. Wait, I recall that Syzkaller *has* some MDIO/PHY fuzzing capabilities, though maybe it's very limited or even non-existent.

Okay, let's back up. The instructions don't *explicitly* exclude MDIO/I2C/SPI devices unless they're tied to "vendor-specific PCIe switch...". Also, I remember the other line: "Code paths that are impossible to reach in virtualized environments...". Can *this* DSA switch be reached in QEMU? These usually require Device Tree nodes to bind. Can Syzkaller inject those nodes through `syz_devlink` or similar? No, usually not. Syzkaller doesn't generally inject arbitrary device trees, though it can load some overlays if configured.

This is a platform driver that registers itself as an MDIO device. I have to look at `drivers/net/dsa/motorcomm/chip.c` to see how it registers. Ah, here it is:

```c
static struct mdio_driver yt921x_mdio_driver = {
	.mdiodrv.driver = {
		.name = YT921X_NAME,
		.of_match_table = yt921x_of_match,
	},
	.probe  = yt921x_mdio_probe,
	.remove = yt921x_mdio_remove,
};
```

So it's an MDIO driver. Can an MDIO driver like this actually be probed in QEMU *without* specific hardware? Typically, MDIO devices are probed when the MDIO bus scans them or via the device tree. Without either, the probe won't be called. Could Syzkaller trigger a probe somehow, maybe through netlink or sysfs? Probably not.

But wait! This patch *adds* LED support to the DSA switch! LEDs are exposed via the LED subsystem and `/sys/class/leds/`. If the device *is* probed, I should be able to control the LEDs via sysfs. *But can it be probed in the first place?*

I need to see if there's any existing Syzkaller support for MDIO or DSA. I'll use `default_api:grepper` to search for `yt921x` in the kernel source to see if there's a virtual driver, or if it's purely hardware-dependent. That will be the key to assessing the fuzzing potential here.



4/2 2026/07/25 02:32 tool grepper
0m Args:
{
  "Expression": "yt921x"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 2618 lines.\nUse more precise expression if possible.\n\nDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml-3----\nDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml:4:$id: http://devicetree.org/schemas/net/dsa/motorcomm,yt921x.yaml#\nDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml-5-$schema: http://devicetree.org/meta-schemas/core.yaml#\n--\nMAINTAINERS=18240=S:\tMaintained\nMAINTAINERS:18241:F:\tDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml\nMAINTAINERS-18242-F:\tdrivers/net/dsa/motorcomm/\nMAINTAINERS:18243:F:\tnet/dsa/tag_yt921x.c\nMAINTAINERS-18244-\n--\ndrivers/net/dsa/motorcomm/Makefile-1-# SPDX-License-Identifier: ISC\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 += smi.o\n--\ndrivers/net/dsa/motorcomm/chip.c-31-\ndrivers/net/dsa/motorcomm/chip.c:32:struct yt921x_mib_desc {\ndrivers/net/dsa/motorcomm/chip.c-33-\tunsigned int size;\n--\ndrivers/net/dsa/motorcomm/chip.c-40-\ndrivers/net/dsa/motorcomm/chip.c:41:/* Must agree with yt921x_mib\ndrivers/net/dsa/motorcomm/chip.c-42- *\n--\ndrivers/net/dsa/motorcomm/chip.c-46- */\ndrivers/net/dsa/motorcomm/chip.c:47:static const struct yt921x_mib_desc yt921x_mib_descs[] = {\ndrivers/net/dsa/motorcomm/chip.c-48-\tMIB_DESC(1, YT921X_MIB_DATA_RX_BROADCAST, NULL),\n--\ndrivers/net/dsa/motorcomm/chip.c-98-\ndrivers/net/dsa/motorcomm/chip.c:99:struct yt921x_info {\ndrivers/net/dsa/motorcomm/chip.c-100-\tconst char *name;\n--\ndrivers/net/dsa/motorcomm/chip.c-106-\tu16 internal_mask;\ndrivers/net/dsa/motorcomm/chip.c:107:\t/* TODO: see comments in yt921x_dsa_phylink_get_caps() */\ndrivers/net/dsa/motorcomm/chip.c-108-\tu16 external_mask;\n--\ndrivers/net/dsa/motorcomm/chip.c-115-\ndrivers/net/dsa/motorcomm/chip.c:116:static const struct yt921x_info yt921x_infos[] = {\ndrivers/net/dsa/motorcomm/chip.c-117-\t{\n--\ndrivers/net/dsa/motorcomm/chip.c-164-\ndrivers/net/dsa/motorcomm/chip.c:165:struct yt921x_reg_mdio {\ndrivers/net/dsa/motorcomm/chip.c-166-\tstruct mii_bus *bus;\n--\ndrivers/net/dsa/motorcomm/chip.c-181-\ndrivers/net/dsa/motorcomm/chip.c:182:#define to_yt921x_priv(_ds) container_of_const(_ds, struct yt921x_priv, ds)\ndrivers/net/dsa/motorcomm/chip.c-183-#define to_device(priv) ((priv)-\u003eds.dev)\n--\ndrivers/net/dsa/motorcomm/chip.c=190=static u32 ethaddr_lo2_to_u32(const unsigned char *addr)\n--\ndrivers/net/dsa/motorcomm/chip.c-194-\ndrivers/net/dsa/motorcomm/chip.c:195:static int yt921x_reg_mdio_read(void *context, u32 reg, u32 *valp)\ndrivers/net/dsa/motorcomm/chip.c-196-{\ndrivers/net/dsa/motorcomm/chip.c:197:\tstruct yt921x_reg_mdio *mdio = context;\ndrivers/net/dsa/motorcomm/chip.c-198-\tstruct mii_bus *bus = mdio-\u003ebus;\n--\ndrivers/net/dsa/motorcomm/chip.c-235-\ndrivers/net/dsa/motorcomm/chip.c:236:static int yt921x_reg_mdio_write(void *context, u32 reg, u32 val)\ndrivers/net/dsa/motorcomm/chip.c-237-{\ndrivers/net/dsa/motorcomm/chip.c:238:\tstruct yt921x_reg_mdio *mdio = context;\ndrivers/net/dsa/motorcomm/chip.c-239-\tstruct mii_bus *bus = mdio-\u003ebus;\n--\ndrivers/net/dsa/motorcomm/chip.c-271-\ndrivers/net/dsa/motorcomm/chip.c:272:static const struct yt921x_reg_ops yt921x_reg_ops_mdio = {\ndrivers/net/dsa/motorcomm/chip.c:273:\t.read = yt921x_reg_mdio_read,\ndrivers/net/dsa/motorcomm/chip.c:274:\t.write = yt921x_reg_mdio_write,\ndrivers/net/dsa/motorcomm/chip.c-275-};\n--\ndrivers/net/dsa/motorcomm/chip.c-278-\ndrivers/net/dsa/motorcomm/chip.c:279:static int yt921x_intif_wait(struct yt921x_priv *priv)\ndrivers/net/dsa/motorcomm/chip.c-280-{\n--\ndrivers/net/dsa/motorcomm/chip.c-282-\ndrivers/net/dsa/motorcomm/chip.c:283:\treturn yt921x_reg_wait(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START,\ndrivers/net/dsa/motorcomm/chip.c-284-\t\t\t       \u0026val);\n--\ndrivers/net/dsa/motorcomm/chip.c=287=static int\ndrivers/net/dsa/motorcomm/chip.c:288:yt921x_intif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\ndrivers/net/dsa/motorcomm/chip.c-289-{\n--\ndrivers/net/dsa/motorcomm/chip.c-295-\ndrivers/net/dsa/motorcomm/chip.c:296:\tres = yt921x_intif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-297-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-303-\t       YT921X_MBUS_CTRL_READ;\ndrivers/net/dsa/motorcomm/chip.c:304:\tres = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);\ndrivers/net/dsa/motorcomm/chip.c-305-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-306-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:307:\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);\ndrivers/net/dsa/motorcomm/chip.c-308-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-310-\ndrivers/net/dsa/motorcomm/chip.c:311:\tres = yt921x_intif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-312-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-313-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:314:\tres = yt921x_reg_read(priv, YT921X_INT_MBUS_DIN, \u0026val);\ndrivers/net/dsa/motorcomm/chip.c-315-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c=326=static int\ndrivers/net/dsa/motorcomm/chip.c:327:yt921x_intif_write(struct yt921x_priv *priv, int port, int reg, u16 val)\ndrivers/net/dsa/motorcomm/chip.c-328-{\n--\ndrivers/net/dsa/motorcomm/chip.c-332-\ndrivers/net/dsa/motorcomm/chip.c:333:\tres = yt921x_intif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-334-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-340-\t       YT921X_MBUS_CTRL_WRITE;\ndrivers/net/dsa/motorcomm/chip.c:341:\tres = yt921x_reg_update_bits(priv, YT921X_INT_MBUS_CTRL, mask, ctrl);\ndrivers/net/dsa/motorcomm/chip.c-342-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-343-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:344:\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_DOUT, val);\ndrivers/net/dsa/motorcomm/chip.c-345-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-346-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:347:\tres = yt921x_reg_write(priv, YT921X_INT_MBUS_OP, YT921X_MBUS_OP_START);\ndrivers/net/dsa/motorcomm/chip.c-348-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-350-\ndrivers/net/dsa/motorcomm/chip.c:351:\treturn yt921x_intif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-352-}\ndrivers/net/dsa/motorcomm/chip.c-353-\ndrivers/net/dsa/motorcomm/chip.c:354:static int yt921x_mbus_int_read(struct mii_bus *mbus, int port, int reg)\ndrivers/net/dsa/motorcomm/chip.c-355-{\ndrivers/net/dsa/motorcomm/chip.c:356:\tstruct yt921x_priv *priv = mbus-\u003epriv;\ndrivers/net/dsa/motorcomm/chip.c-357-\tu16 val;\n--\ndrivers/net/dsa/motorcomm/chip.c-363-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:364:\tres = yt921x_intif_read(priv, port, reg, \u0026val);\ndrivers/net/dsa/motorcomm/chip.c-365-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=372=static int\ndrivers/net/dsa/motorcomm/chip.c:373:yt921x_mbus_int_write(struct mii_bus *mbus, int port, int reg, u16 data)\ndrivers/net/dsa/motorcomm/chip.c-374-{\ndrivers/net/dsa/motorcomm/chip.c:375:\tstruct yt921x_priv *priv = mbus-\u003epriv;\ndrivers/net/dsa/motorcomm/chip.c-376-\tint res;\n--\ndrivers/net/dsa/motorcomm/chip.c-381-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:382:\tres = yt921x_intif_write(priv, port, reg, data);\ndrivers/net/dsa/motorcomm/chip.c-383-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=388=static int\ndrivers/net/dsa/motorcomm/chip.c:389:yt921x_mbus_int_init(struct yt921x_priv *priv, struct device_node *mnp)\ndrivers/net/dsa/motorcomm/chip.c-390-{\n--\ndrivers/net/dsa/motorcomm/chip.c-401-\tmbus-\u003epriv = priv;\ndrivers/net/dsa/motorcomm/chip.c:402:\tmbus-\u003eread = yt921x_mbus_int_read;\ndrivers/net/dsa/motorcomm/chip.c:403:\tmbus-\u003ewrite = yt921x_mbus_int_write;\ndrivers/net/dsa/motorcomm/chip.c-404-\tmbus-\u003eparent = dev;\n--\ndrivers/net/dsa/motorcomm/chip.c-415-\ndrivers/net/dsa/motorcomm/chip.c:416:static int yt921x_extif_wait(struct yt921x_priv *priv)\ndrivers/net/dsa/motorcomm/chip.c-417-{\n--\ndrivers/net/dsa/motorcomm/chip.c-419-\ndrivers/net/dsa/motorcomm/chip.c:420:\treturn yt921x_reg_wait(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START,\ndrivers/net/dsa/motorcomm/chip.c-421-\t\t\t       \u0026val);\n--\ndrivers/net/dsa/motorcomm/chip.c=424=static int\ndrivers/net/dsa/motorcomm/chip.c:425:yt921x_extif_read(struct yt921x_priv *priv, int port, int reg, u16 *valp)\ndrivers/net/dsa/motorcomm/chip.c-426-{\n--\ndrivers/net/dsa/motorcomm/chip.c-432-\ndrivers/net/dsa/motorcomm/chip.c:433:\tres = yt921x_extif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-434-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-440-\t       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_READ;\ndrivers/net/dsa/motorcomm/chip.c:441:\tres = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);\ndrivers/net/dsa/motorcomm/chip.c-442-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-443-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:444:\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);\ndrivers/net/dsa/motorcomm/chip.c-445-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-447-\ndrivers/net/dsa/motorcomm/chip.c:448:\tres = yt921x_extif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-449-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-450-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:451:\tres = yt921x_reg_read(priv, YT921X_EXT_MBUS_DIN, \u0026val);\ndrivers/net/dsa/motorcomm/chip.c-452-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c=463=static int\ndrivers/net/dsa/motorcomm/chip.c:464:yt921x_extif_write(struct yt921x_priv *priv, int port, int reg, u16 val)\ndrivers/net/dsa/motorcomm/chip.c-465-{\n--\ndrivers/net/dsa/motorcomm/chip.c-469-\ndrivers/net/dsa/motorcomm/chip.c:470:\tres = yt921x_extif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-471-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-477-\t       YT921X_MBUS_CTRL_TYPE_C22 | YT921X_MBUS_CTRL_WRITE;\ndrivers/net/dsa/motorcomm/chip.c:478:\tres = yt921x_reg_update_bits(priv, YT921X_EXT_MBUS_CTRL, mask, ctrl);\ndrivers/net/dsa/motorcomm/chip.c-479-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-480-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:481:\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_DOUT, val);\ndrivers/net/dsa/motorcomm/chip.c-482-\tif (res)\ndrivers/net/dsa/motorcomm/chip.c-483-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:484:\tres = yt921x_reg_write(priv, YT921X_EXT_MBUS_OP, YT921X_MBUS_OP_START);\ndrivers/net/dsa/motorcomm/chip.c-485-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-487-\ndrivers/net/dsa/motorcomm/chip.c:488:\treturn yt921x_extif_wait(priv);\ndrivers/net/dsa/motorcomm/chip.c-489-}\ndrivers/net/dsa/motorcomm/chip.c-490-\ndrivers/net/dsa/motorcomm/chip.c:491:static int yt921x_mbus_ext_read(struct mii_bus *mbus, int port, int reg)\ndrivers/net/dsa/motorcomm/chip.c-492-{\ndrivers/net/dsa/motorcomm/chip.c:493:\tstruct yt921x_priv *priv = mbus-\u003epriv;\ndrivers/net/dsa/motorcomm/chip.c-494-\tu16 val;\n--\ndrivers/net/dsa/motorcomm/chip.c-497-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:498:\tres = yt921x_extif_read(priv, port, reg, \u0026val);\ndrivers/net/dsa/motorcomm/chip.c-499-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=506=static int\ndrivers/net/dsa/motorcomm/chip.c:507:yt921x_mbus_ext_write(struct mii_bus *mbus, int port, int reg, u16 data)\ndrivers/net/dsa/motorcomm/chip.c-508-{\ndrivers/net/dsa/motorcomm/chip.c:509:\tstruct yt921x_priv *priv = mbus-\u003epriv;\ndrivers/net/dsa/motorcomm/chip.c-510-\tint res;\n--\ndrivers/net/dsa/motorcomm/chip.c-512-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:513:\tres = yt921x_extif_write(priv, port, reg, data);\ndrivers/net/dsa/motorcomm/chip.c-514-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=519=static int\ndrivers/net/dsa/motorcomm/chip.c:520:yt921x_mbus_ext_init(struct yt921x_priv *priv, struct device_node *mnp)\ndrivers/net/dsa/motorcomm/chip.c-521-{\n--\ndrivers/net/dsa/motorcomm/chip.c-533-\t/* TODO: c45? */\ndrivers/net/dsa/motorcomm/chip.c:534:\tmbus-\u003eread = yt921x_mbus_ext_read;\ndrivers/net/dsa/motorcomm/chip.c:535:\tmbus-\u003ewrite = yt921x_mbus_ext_write;\ndrivers/net/dsa/motorcomm/chip.c-536-\tmbus-\u003eparent = dev;\n--\ndrivers/net/dsa/motorcomm/chip.c-547-/* Read and handle overflow of 32bit MIBs. MIB buffer must be zeroed before. */\ndrivers/net/dsa/motorcomm/chip.c:548:static int yt921x_read_mib(struct yt921x_priv *priv, int port)\ndrivers/net/dsa/motorcomm/chip.c-549-{\ndrivers/net/dsa/motorcomm/chip.c:550:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c-551-\tstruct device *dev = to_device(priv);\ndrivers/net/dsa/motorcomm/chip.c:552:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-553-\tint res = 0;\ndrivers/net/dsa/motorcomm/chip.c-554-\ndrivers/net/dsa/motorcomm/chip.c:555:\t/* Reading of yt921x_port::mib is not protected by a lock and it's vain\ndrivers/net/dsa/motorcomm/chip.c-556-\t * to keep its consistency, since we have to read registers one by one\n--\ndrivers/net/dsa/motorcomm/chip.c-562-\ndrivers/net/dsa/motorcomm/chip.c:563:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:564:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-565-\t\tu32 reg = YT921X_MIBn_DATA0(port) + desc-\u003eoffset;\n--\ndrivers/net/dsa/motorcomm/chip.c-569-\ndrivers/net/dsa/motorcomm/chip.c:570:\t\tres = yt921x_reg_read(priv, reg, \u0026val0);\ndrivers/net/dsa/motorcomm/chip.c-571-\t\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-582-\ndrivers/net/dsa/motorcomm/chip.c:583:\t\t\tres = yt921x_reg_read(priv, reg + 4, \u0026val1);\ndrivers/net/dsa/motorcomm/chip.c-584-\t\t\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-606-\ndrivers/net/dsa/motorcomm/chip.c:607:static void yt921x_poll_mib(struct work_struct *work)\ndrivers/net/dsa/motorcomm/chip.c-608-{\ndrivers/net/dsa/motorcomm/chip.c:609:\tstruct yt921x_port *pp = container_of_const(work, struct yt921x_port,\ndrivers/net/dsa/motorcomm/chip.c-610-\t\t\t\t\t\t    mib_read.work);\ndrivers/net/dsa/motorcomm/chip.c:611:\tstruct yt921x_priv *priv = (void *)(pp - pp-\u003eindex) -\ndrivers/net/dsa/motorcomm/chip.c:612:\t\t\t\t   offsetof(struct yt921x_priv, ports);\ndrivers/net/dsa/motorcomm/chip.c-613-\tunsigned long delay = YT921X_STATS_INTERVAL_JIFFIES;\n--\ndrivers/net/dsa/motorcomm/chip.c-617-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:618:\tres = yt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-619-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=626=static void\ndrivers/net/dsa/motorcomm/chip.c:627:yt921x_dsa_get_strings(struct dsa_switch *ds, int port, u32 stringset,\ndrivers/net/dsa/motorcomm/chip.c-628-\t\t       uint8_t *data)\n--\ndrivers/net/dsa/motorcomm/chip.c-632-\ndrivers/net/dsa/motorcomm/chip.c:633:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:634:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-635-\n--\ndrivers/net/dsa/motorcomm/chip.c=641=static void\ndrivers/net/dsa/motorcomm/chip.c:642:yt921x_dsa_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data)\ndrivers/net/dsa/motorcomm/chip.c-643-{\ndrivers/net/dsa/motorcomm/chip.c:644:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:645:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:646:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-647-\tsize_t j;\n--\ndrivers/net/dsa/motorcomm/chip.c-649-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:650:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-651-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c-653-\tj = 0;\ndrivers/net/dsa/motorcomm/chip.c:654:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:655:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-656-\n--\ndrivers/net/dsa/motorcomm/chip.c-664-\ndrivers/net/dsa/motorcomm/chip.c:665:static int yt921x_dsa_get_sset_count(struct dsa_switch *ds, int port, int sset)\ndrivers/net/dsa/motorcomm/chip.c-666-{\n--\ndrivers/net/dsa/motorcomm/chip.c-671-\ndrivers/net/dsa/motorcomm/chip.c:672:\tfor (size_t i = 0; i \u003c ARRAY_SIZE(yt921x_mib_descs); i++) {\ndrivers/net/dsa/motorcomm/chip.c:673:\t\tconst struct yt921x_mib_desc *desc = \u0026yt921x_mib_descs[i];\ndrivers/net/dsa/motorcomm/chip.c-674-\n--\ndrivers/net/dsa/motorcomm/chip.c=682=static void\ndrivers/net/dsa/motorcomm/chip.c:683:yt921x_dsa_get_eth_mac_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-684-\t\t\t     struct ethtool_eth_mac_stats *mac_stats)\ndrivers/net/dsa/motorcomm/chip.c-685-{\ndrivers/net/dsa/motorcomm/chip.c:686:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:687:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:688:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-689-\ndrivers/net/dsa/motorcomm/chip.c-690-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:691:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-692-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=718=static void\ndrivers/net/dsa/motorcomm/chip.c:719:yt921x_dsa_get_eth_ctrl_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-720-\t\t\t      struct ethtool_eth_ctrl_stats *ctrl_stats)\ndrivers/net/dsa/motorcomm/chip.c-721-{\ndrivers/net/dsa/motorcomm/chip.c:722:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:723:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:724:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-725-\ndrivers/net/dsa/motorcomm/chip.c-726-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:727:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-728-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c-734-\ndrivers/net/dsa/motorcomm/chip.c:735:static const struct ethtool_rmon_hist_range yt921x_rmon_ranges[] = {\ndrivers/net/dsa/motorcomm/chip.c-736-\t{ 0, 64 },\n--\ndrivers/net/dsa/motorcomm/chip.c=746=static void\ndrivers/net/dsa/motorcomm/chip.c:747:yt921x_dsa_get_rmon_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-748-\t\t\t  struct ethtool_rmon_stats *rmon_stats,\n--\ndrivers/net/dsa/motorcomm/chip.c-750-{\ndrivers/net/dsa/motorcomm/chip.c:751:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:752:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:753:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-754-\ndrivers/net/dsa/motorcomm/chip.c-755-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:756:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-757-\tmutex_unlock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c-758-\ndrivers/net/dsa/motorcomm/chip.c:759:\t*ranges = yt921x_rmon_ranges;\ndrivers/net/dsa/motorcomm/chip.c-760-\n--\ndrivers/net/dsa/motorcomm/chip.c=783=static void\ndrivers/net/dsa/motorcomm/chip.c:784:yt921x_dsa_get_stats64(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-785-\t\t       struct rtnl_link_stats64 *stats)\ndrivers/net/dsa/motorcomm/chip.c-786-{\ndrivers/net/dsa/motorcomm/chip.c:787:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:788:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:789:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-790-\n--\ndrivers/net/dsa/motorcomm/chip.c=819=static void\ndrivers/net/dsa/motorcomm/chip.c:820:yt921x_dsa_get_pause_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-821-\t\t\t   struct ethtool_pause_stats *pause_stats)\ndrivers/net/dsa/motorcomm/chip.c-822-{\ndrivers/net/dsa/motorcomm/chip.c:823:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:824:\tstruct yt921x_port *pp = \u0026priv-\u003eports[port];\ndrivers/net/dsa/motorcomm/chip.c:825:\tstruct yt921x_mib *mib = \u0026pp-\u003emib;\ndrivers/net/dsa/motorcomm/chip.c-826-\ndrivers/net/dsa/motorcomm/chip.c-827-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:828:\tyt921x_read_mib(priv, port);\ndrivers/net/dsa/motorcomm/chip.c-829-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=835=static int\ndrivers/net/dsa/motorcomm/chip.c:836:yt921x_set_eee(struct yt921x_priv *priv, int port, struct ethtool_keee *e)\ndrivers/net/dsa/motorcomm/chip.c-837-{\n--\ndrivers/net/dsa/motorcomm/chip.c-849-\tif (!!new_mask != !!priv-\u003eeee_ports_mask) {\ndrivers/net/dsa/motorcomm/chip.c:850:\t\tres = yt921x_reg_toggle_bits(priv, YT921X_PON_STRAP_FUNC,\ndrivers/net/dsa/motorcomm/chip.c-851-\t\t\t\t\t     YT921X_PON_STRAP_EEE, !!new_mask);\n--\ndrivers/net/dsa/motorcomm/chip.c-853-\t\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:854:\t\tres = yt921x_reg_toggle_bits(priv, YT921X_PON_STRAP_VAL,\ndrivers/net/dsa/motorcomm/chip.c-855-\t\t\t\t\t     YT921X_PON_STRAP_EEE, !!new_mask);\n--\ndrivers/net/dsa/motorcomm/chip.c-862-\t/* Enable / disable port EEE */\ndrivers/net/dsa/motorcomm/chip.c:863:\tres = yt921x_reg_toggle_bits(priv, YT921X_EEE_CTRL,\ndrivers/net/dsa/motorcomm/chip.c-864-\t\t\t\t     YT921X_EEE_CTRL_ENn(port), enable);\n--\ndrivers/net/dsa/motorcomm/chip.c-866-\t\treturn res;\ndrivers/net/dsa/motorcomm/chip.c:867:\tres = yt921x_reg_toggle_bits(priv, YT921X_EEEn_VAL(port),\ndrivers/net/dsa/motorcomm/chip.c-868-\t\t\t\t     YT921X_EEE_VAL_DATA, enable);\n--\ndrivers/net/dsa/motorcomm/chip.c=875=static int\ndrivers/net/dsa/motorcomm/chip.c:876:yt921x_dsa_set_mac_eee(struct dsa_switch *ds, int port, struct ethtool_keee *e)\ndrivers/net/dsa/motorcomm/chip.c-877-{\ndrivers/net/dsa/motorcomm/chip.c:878:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-879-\tint res;\n--\ndrivers/net/dsa/motorcomm/chip.c-881-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:882:\tres = yt921x_set_eee(priv, port, e);\ndrivers/net/dsa/motorcomm/chip.c-883-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c-887-\ndrivers/net/dsa/motorcomm/chip.c:888:static int yt921x_mtu_fetch(struct yt921x_priv *priv, int port)\ndrivers/net/dsa/motorcomm/chip.c-889-{\n--\ndrivers/net/dsa/motorcomm/chip.c=895=static int\ndrivers/net/dsa/motorcomm/chip.c:896:yt921x_dsa_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\ndrivers/net/dsa/motorcomm/chip.c-897-{\n--\ndrivers/net/dsa/motorcomm/chip.c-901-\ndrivers/net/dsa/motorcomm/chip.c:902:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-903-\tstruct dsa_port *dp = dsa_to_port(ds, port);\n--\ndrivers/net/dsa/motorcomm/chip.c-911-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:912:\tres = yt921x_reg_update_bits(priv, YT921X_MACn_FRAME(port),\ndrivers/net/dsa/motorcomm/chip.c-913-\t\t\t\t     YT921X_MAC_FRAME_SIZE_M,\n--\ndrivers/net/dsa/motorcomm/chip.c-919-\ndrivers/net/dsa/motorcomm/chip.c:920:static int yt921x_dsa_port_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/motorcomm/chip.c-921-{\n--\ndrivers/net/dsa/motorcomm/chip.c=953=static u64 token2burst(u32 token, int unit, int C)\n--\ndrivers/net/dsa/motorcomm/chip.c-957-\ndrivers/net/dsa/motorcomm/chip.c:958:struct yt921x_marker {\ndrivers/net/dsa/motorcomm/chip.c-959-\tu32 cir;\n--\ndrivers/net/dsa/motorcomm/chip.c=969=static int\ndrivers/net/dsa/motorcomm/chip.c:970:yt921x_marker_tfm(struct yt921x_marker *marker, u64 rate, u64 burst,\ndrivers/net/dsa/motorcomm/chip.c-971-\t\t  unsigned int flags, unsigned int slot_ns, u32 cir_max,\ndrivers/net/dsa/motorcomm/chip.c:972:\t\t  u32 cbs_max, int unit_max, struct yt921x_priv *priv, int port,\ndrivers/net/dsa/motorcomm/chip.c-973-\t\t  struct netlink_ext_ack *extack)\n--\ndrivers/net/dsa/motorcomm/chip.c-977-\tstruct device *dev = to_device(priv);\ndrivers/net/dsa/motorcomm/chip.c:978:\tstruct yt921x_marker m;\ndrivers/net/dsa/motorcomm/chip.c-979-\tu64 burst_est;\n--\ndrivers/net/dsa/motorcomm/chip.c-999-\telse\ndrivers/net/dsa/motorcomm/chip.c:1000:\t\tburst_sug += ETH_HLEN + yt921x_mtu_fetch(priv, port) +\ndrivers/net/dsa/motorcomm/chip.c-1001-\t\t\t     ETH_FCS_LEN;\n--\ndrivers/net/dsa/motorcomm/chip.c=1059=static int\ndrivers/net/dsa/motorcomm/chip.c:1060:yt921x_marker_tfm_police(struct yt921x_marker *marker,\ndrivers/net/dsa/motorcomm/chip.c-1061-\t\t\t const struct flow_action_police *police,\ndrivers/net/dsa/motorcomm/chip.c:1062:\t\t\t unsigned int flags, struct yt921x_priv *priv, int port,\ndrivers/net/dsa/motorcomm/chip.c-1063-\t\t\t struct netlink_ext_ack *extack)\n--\ndrivers/net/dsa/motorcomm/chip.c-1073-\ndrivers/net/dsa/motorcomm/chip.c:1074:\treturn yt921x_marker_tfm(marker, rate, burst, flags,\ndrivers/net/dsa/motorcomm/chip.c-1075-\t\t\t\t priv-\u003emeter_slot_ns, YT921X_METER_CIR_MAX,\n--\ndrivers/net/dsa/motorcomm/chip.c=1080=static int\ndrivers/net/dsa/motorcomm/chip.c:1081:yt921x_marker_tfm_shape(struct yt921x_marker *marker, u64 rate, u64 burst,\ndrivers/net/dsa/motorcomm/chip.c:1082:\t\t\tunsigned int flags, struct yt921x_priv *priv, int port,\ndrivers/net/dsa/motorcomm/chip.c-1083-\t\t\tstruct netlink_ext_ack *extack)\ndrivers/net/dsa/motorcomm/chip.c-1084-{\ndrivers/net/dsa/motorcomm/chip.c:1085:\treturn yt921x_marker_tfm(marker, rate, burst, flags,\ndrivers/net/dsa/motorcomm/chip.c-1086-\t\t\t\t priv-\u003eport_shape_slot_ns, YT921X_SHAPE_CIR_MAX,\n--\ndrivers/net/dsa/motorcomm/chip.c=1091=static int\ndrivers/net/dsa/motorcomm/chip.c:1092:yt921x_police_validate(const struct flow_action_police *police,\ndrivers/net/dsa/motorcomm/chip.c-1093-\t\t       const struct flow_action *action,\n--\ndrivers/net/dsa/motorcomm/chip.c=1127=static int\ndrivers/net/dsa/motorcomm/chip.c:1128:yt921x_meter_config(struct yt921x_priv *priv, unsigned int id,\ndrivers/net/dsa/motorcomm/chip.c:1129:\t\t    const struct yt921x_marker *marker)\ndrivers/net/dsa/motorcomm/chip.c-1130-{\n--\ndrivers/net/dsa/motorcomm/chip.c-1147-\ndrivers/net/dsa/motorcomm/chip.c:1148:\treturn yt921x_reg96_write(priv, YT921X_METERn_CTRL(id), ctrls);\ndrivers/net/dsa/motorcomm/chip.c-1149-}\ndrivers/net/dsa/motorcomm/chip.c-1150-\ndrivers/net/dsa/motorcomm/chip.c:1151:static void yt921x_dsa_port_policer_del(struct dsa_switch *ds, int port)\ndrivers/net/dsa/motorcomm/chip.c-1152-{\ndrivers/net/dsa/motorcomm/chip.c:1153:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c-1154-\tstruct device *dev = to_device(priv);\n--\ndrivers/net/dsa/motorcomm/chip.c-1157-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:1158:\tres = yt921x_reg_write(priv, YT921X_PORTn_METER(port), 0);\ndrivers/net/dsa/motorcomm/chip.c-1159-\tmutex_unlock(\u0026priv-\u003ereg_lock);\n--\ndrivers/net/dsa/motorcomm/chip.c=1166=static int\ndrivers/net/dsa/motorcomm/chip.c:1167:yt921x_dsa_port_policer_add(struct dsa_switch *ds, int port,\ndrivers/net/dsa/motorcomm/chip.c-1168-\t\t\t    const struct flow_action_police *police,\n--\ndrivers/net/dsa/motorcomm/chip.c-1170-{\ndrivers/net/dsa/motorcomm/chip.c:1171:\tstruct yt921x_priv *priv = to_yt921x_priv(ds);\ndrivers/net/dsa/motorcomm/chip.c:1172:\tstruct yt921x_marker marker;\ndrivers/net/dsa/motorcomm/chip.c-1173-\tu32 ctrl;\n--\ndrivers/net/dsa/motorcomm/chip.c-1175-\ndrivers/net/dsa/motorcomm/chip.c:1176:\tres = yt921x_police_validate(police, NULL, NULL, extack);\ndrivers/net/dsa/motorcomm/chip.c-1177-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-1179-\ndrivers/net/dsa/motorcomm/chip.c:1180:\tres = yt921x_marker_tfm_police(\u0026marker, police, 0, priv, port, extack);\ndrivers/net/dsa/motorcomm/chip.c-1181-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-1184-\tmutex_lock(\u0026priv-\u003ereg_lock);\ndrivers/net/dsa/motorcomm/chip.c:1185:\tres = yt921x_meter_config(priv, port + YT921X_METER_NUM, \u0026marker);\ndrivers/net/dsa/motorcomm/chip.c-1186-\tif (res)\n--\ndrivers/net/dsa/motorcomm/chip.c-1189-\tctrl = YT921X_PORT_METER_ID(port) | YT921X_PORT_METER_EN;\ndrivers/net/dsa/motorcomm/chip.c:1190:\tres = yt921x_reg_write(priv, YT921X_PORTn_METER(port), ctrl);\ndrivers/net/dsa/motorcomm/chip.c-1191-end:\n--\n\n"
}

5/2 2026/07/25 02:32 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 35901
							output: 22
							thoughts: 821
						

Thoughts:
**Analyzing the Reachability of a DSA Driver in Syzkaller**

Okay, so I'm looking at this patch related to the Motorcomm YT9215 DSA driver. My immediate thought is, "Can syzkaller even touch this?" The code registers an MDIO driver in `drivers/net/dsa/motorcomm/chip.c`. Specifically, `yt921x_mdio_driver` is registered. This is where I start to think about syzkaller's limitations. It doesn't have a built-in method to create arbitrary MDIO devices, unless there's a specific pseudo-device, or maybe some Device Tree magic. While syzkaller supports things like `mac80211_hwsim`, `vkms`, etc., does it support MDIO devices? I should check if there's any syzkaller description for DSA or MDIO directly. I'll probably use `default_api:grepper` and search in `sys/linux/` for `yt921x`, or check the syzkaller configs for `CONFIG_NET_DSA_YT921X`.

But, wait a minute, the instructions here specify that it's impossible to reach a DSA switch driver within a virtualized environment like QEMU. DSA drivers are often platform-specific or depend on MDIO/I2C/SPI interfaces. QEMU definitely doesn't emulate the Motorcomm YT9215 hardware. But, can I instantiate a DSA switch via a dummy MDIO bus? There's `dsa_loop`, which is a dummy DSA switch, but `yt921x` is a specific hardware driver.

How can I probe `yt921x` in QEMU? No way. It requires an MDIO bus and a Device Tree node matching `motorcomm,yt921x`, and as far as I know, syzkaller doesn't inject arbitrary Device Tree nodes. So, no luck there.

Hang on... the patch author is `syz-cluster <triage@syzkaller.com>`. This is a *simulated* patch. Okay, let's go back and look at the patch again. It adds LED support to the `yt921x` driver. Hmm, is it possible that syzkaller *can* reach this? I need to figure out if `yt921x` is a real driver in the kernel, and therefore, if there's any way to execute the added `drivers/net/dsa/motorcomm/leds.c` code.

If I can't reach this code, it's definitely `WorthFuzzing=false`. Given that this is a hardware-specific driver for a physical switch chip that's *not* emulated in QEMU, it's practically impossible to reach. Let me just double check one more time if there's *any* QEMU emulation for `yt921x`... just to be completely sure. Nope. Verdict: `WorthFuzzing=false`.



6/2 2026/07/25 02:32 tool grepper
0m Args:
{
  "Expression": "motorcomm,yt921x"
}

Results:
{
  "Output": "Documentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml-3----\nDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml:4:$id: http://devicetree.org/schemas/net/dsa/motorcomm,yt921x.yaml#\nDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml-5-$schema: http://devicetree.org/meta-schemas/core.yaml#\n--\nMAINTAINERS=18240=S:\tMaintained\nMAINTAINERS:18241:F:\tDocumentation/devicetree/bindings/net/dsa/motorcomm,yt921x.yaml\nMAINTAINERS-18242-F:\tdrivers/net/dsa/motorcomm/\n"
}

7/2 2026/07/25 02:32 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 37628
							output: 30
							thoughts: 628
						

Thoughts:
**Analyzing the Reachability of the `motorcomm,yt921x` Driver**

Okay, so the device tree binding is `motorcomm,yt921x`. My first thought is, can we even reach this driver? Usually, hardware-specific drivers like this, that aren't emulated in QEMU and lack virtual counterparts, can't be fuzzed by syzkaller because they need actual hardware. I'm thinking, could syzkaller perhaps probe MDIO drivers by registering a dummy bus and device? That's a possibility, but I know syzkaller doesn't have a generic MDIO fuzzer.

Let me check. I need to find the syzkaller documentation. I can't read the descriptions directly, but I can't use the `default_api:grepper` to search for `mdio` in `sys/linux/` . I know from experience that syzkaller doesn't normally fuzz arbitrary MDIO hardware drivers because they depend on device tree nodes for binding. What if it's reachable via I2C or SPI? Same problem: device tree or board info is required. And what about PCI? PCI drivers *can* be probed if QEMU emulates the PCI device, but QEMU doesn't emulate `yt921x`.

Wait, I just realized, `yt921x` *is* an MDIO driver. Looking at the code:

```c
static struct mdio_driver yt921x_mdio_driver = {
	.mdiodrv.driver = {
		.name = YT921X_NAME,
		.of_match_table = yt921x_of_match,
	},
	.probe  = yt921x_mdio_probe,
	.remove = yt921x_mdio_remove,
};
```

This confirms it. Since it's an MDIO driver for specific hardware switch, and there is no QEMU emulation for Motorcomm YT9215, the `probe` function is never going to be called in a virtualized environment. So these code paths are unreachable in virtual environments.

Just to be absolutely sure, let me double-check if there's any way to instantiate an MDIO device from userspace. `SIOCSMIIREG` exists, but that's for reading/writing registers, not creating devices. Unlike I2C, MDIO doesn't have a `/sys/bus/mdio_bus/devices/new_device` for creating devices. Wait, does MDIO have something similar? Let me check if the MDIO bus has `new_device`.



8/2 2026/07/25 02:32 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "new_device",
  "PathPrefix": "drivers/net/mdio/"
}

Results:
{
  "error": "no matches"
}

9/2 2026/07/25 02:32 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 38880
							output: 35
							thoughts: 35
						

Thoughts:
Okay, here's my interpretation of those thoughts, presented as my own mental process, given my expertise:

**Checking for MDIO Bus Driver Configuration**

Hmm, no sign of `new_device` being defined or used directly within the `drivers/net/mdio/` directory. That's a bit odd. I was expecting to find something related to device instantiation there. It suggests the MDIO bus itself, the fundamental infrastructure for accessing PHYs, might be handling the device creation. Given that context, my next logical step is to dive into `drivers/net/phy/mdio_bus.c`. That's where I'd expect to find the core MDIO bus driver implementation, and potentially, the functions or structures responsible for attaching new PHY devices to the bus. I'm guessing that's where the `new_device` logic, or something functionally equivalent, will reside.



10/2 2026/07/25 02:32 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "new_device",
  "PathPrefix": "drivers/net/phy/mdio_bus.c"
}

Results:
{
  "error": "no matches"
}

11/2 2026/07/25 02:32 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 39153
							output: 34
							thoughts: 208
						

Thoughts:
**Unfuzzable Driver: YT921x**

Okay, so it's clear: there's absolutely no way to instantiate an MDIO device, specifically the one required by the `yt921x` driver, from userspace. This means I can't even *begin* to probe this driver in a virtualized environment. Without dedicated hardware or a very specific QEMU setup with emulation of the Motorcomm YT9215 (which doesn't exist), this driver is simply unreachable. Since fuzzing relies on environment reachability, this is a clear roadblock.

Let me just refresh the instructions in my mind: "Return WorthFuzzing=false if the patch only contains code paths that are impossible to reach in virtualized environments, even when using software emulations."

Yep, it's a perfect fit. This `yt921x` driver is a hardware-specific MDIO driver for a DSA switch chip. It's fundamentally tied to hardware and just *can't* be probed in environments like QEMU. Given this, I'm confident in returning `WorthFuzzing=false`.

I'll just double-check that it is an MDIO driver. Just to be sure. Alright, confirmed! I'm good to go with the assessment.



12/2 2026/07/25 02:32 tool grepper
0m Args:
{
  "Expression": "mdio_driver",
  "PathPrefix": "drivers/net/dsa/motorcomm/"
}

Results:
{
  "Output": "drivers/net/dsa/motorcomm/chip.c=4770=MODULE_DEVICE_TABLE(of, yt921x_of_match);\ndrivers/net/dsa/motorcomm/chip.c-4771-\ndrivers/net/dsa/motorcomm/chip.c:4772:static struct mdio_driver yt921x_mdio_driver = {\ndrivers/net/dsa/motorcomm/chip.c-4773-\t.probe = yt921x_mdio_probe,\n--\ndrivers/net/dsa/motorcomm/chip.c-4781-\ndrivers/net/dsa/motorcomm/chip.c:4782:mdio_module_driver(yt921x_mdio_driver);\ndrivers/net/dsa/motorcomm/chip.c-4783-\n"
}

13/2 2026/07/25 02:32 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 39894
							output: 102
							thoughts: 30
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**MDIO Driver and Fuzzing Considerations**

Right, so we're dealing with an MDIO driver. No surprises there, but that’s the starting point. Given what I know about this driver, and based on my prior understanding of its role, the complexities of the system it is interacting with, and the potential impact of fuzzing at this stage, I'm confident in making a call here. Using `set-results`, I'm going to return `WorthFuzzing=false`. Basically, I’m saying that based on my analysis of this driver and its role in the greater scheme of things, fuzzing it isn't likely to yield significant results *at this juncture*. Further down the line, depending on findings, the driver may become relevant to fuzz, but for now, I'll pass on the fuzz campaign.



14/2 2026/07/25 02:32 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT9215 DSA switch driver, which is a hardware-specific MDIO device. Since there is no QEMU emulation for this hardware and MDIO devices cannot be arbitrarily instantiated from userspace (unlike I2C), the driver cannot be probed and its code paths are impossible to reach in virtualized environments.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch modifies the Motorcomm YT9215 DSA switch driver, which is a hardware-specific MDIO device. Since there is no QEMU emulation for this hardware and MDIO devices cannot be arbitrarily instantiated from userspace (unlike I2C), the driver cannot be probed and its code paths are impossible to reach in virtualized environments.",
  "WorthFuzzing": false
}

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