AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch adds a new DSA switch driver and a tag driver for the Microchip LAN9645x hardware. The switch driver requires specific regmaps provided by a parent device, which does not exist in the kernel, making it impossible to probe. Even if probed, it requires physical hardware that is not emulated in virtualized environments like QEMU/GCE. The tag driver is also unreachable because no virtual DSA switch (like `dsa_loop`) supports changing its tag protocol to `lan9645x` dynamically. Thus, the code cannot be executed or fuzzed.",
  "WorthFuzzing": false
}

1/1 2026/07/02 11:57 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 7b076893bcffa3d7d71366927f42b557cbffcf5f\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Thu Jul 2 11:57:33 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nnew file mode 100644\nindex 00000000000000..043fb48922b41d\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\n@@ -0,0 +1,111 @@\n+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause\n+%YAML 1.2\n+---\n+$id: http://devicetree.org/schemas/net/dsa/microchip,lan96455s-switch.yaml#\n+$schema: http://devicetree.org/meta-schemas/core.yaml#\n+\n+title: Microchip LAN9645x Ethernet switch\n+\n+maintainers:\n+  - Jens Emil Schulz Østergaard \u003cjensemil.schulzostergaard@microchip.com\u003e\n+\n+description:\n+  The LAN9645x switch is a multi-port Gigabit AVB/TSN Ethernet switch with\n+  five integrated 10/100/1000Base-T PHYs. In addition to the integrated PHYs,\n+  it supports up to 2 RGMII/RMII, up to 2 BASE-X/SERDES/2.5GBASE-X and one\n+  Quad-SGMII interfaces.\n+\n+properties:\n+  compatible:\n+    oneOf:\n+      - enum:\n+          - microchip,lan96455s-switch\n+      - items:\n+          - enum:\n+              - microchip,lan96455f-switch\n+              - microchip,lan96457f-switch\n+              - microchip,lan96459f-switch\n+              - microchip,lan96457s-switch\n+              - microchip,lan96459s-switch\n+          - const: microchip,lan96455s-switch\n+\n+  reg:\n+    maxItems: 1\n+\n+  ethernet-ports:\n+    type: object\n+    patternProperties:\n+      \"^ethernet-port@[0-8]$\":\n+        type: object\n+        description: Ethernet switch ports\n+\n+        $ref: dsa-port.yaml#\n+        unevaluatedProperties: false\n+\n+        properties:\n+          rx-internal-delay-ps:\n+            const: 2000\n+\n+          tx-internal-delay-ps:\n+            const: 2000\n+\n+$ref: dsa.yaml#/$defs/ethernet-ports\n+\n+required:\n+  - compatible\n+  - reg\n+  - ethernet-ports\n+\n+unevaluatedProperties: false\n+\n+examples:\n+  - |\n+    ethernet-switch@4000 {\n+        compatible = \"microchip,lan96459f-switch\", \"microchip,lan96455s-switch\";\n+        reg = \u003c0x4000 0x244\u003e;\n+\n+        ethernet-ports {\n+            #address-cells = \u003c1\u003e;\n+            #size-cells = \u003c0\u003e;\n+\n+            ethernet-port@0 {\n+                reg = \u003c0\u003e;\n+                phy-mode = \"gmii\";\n+                phy-handle = \u003c\u0026cuphy0\u003e;\n+            };\n+\n+            ethernet-port@1 {\n+                reg = \u003c1\u003e;\n+                phy-mode = \"gmii\";\n+                phy-handle = \u003c\u0026cuphy1\u003e;\n+            };\n+\n+            ethernet-port@2 {\n+                reg = \u003c2\u003e;\n+                phy-mode = \"gmii\";\n+                phy-handle = \u003c\u0026cuphy2\u003e;\n+            };\n+\n+            ethernet-port@3 {\n+                reg = \u003c3\u003e;\n+                phy-mode = \"gmii\";\n+                phy-handle = \u003c\u0026cuphy3\u003e;\n+            };\n+\n+            ethernet-port@7 {\n+                reg = \u003c7\u003e;\n+                phy-mode = \"rgmii\";\n+                ethernet = \u003c\u0026cpu_host_port\u003e;\n+                rx-internal-delay-ps = \u003c2000\u003e;\n+                tx-internal-delay-ps = \u003c2000\u003e;\n+\n+                fixed-link {\n+                    speed = \u003c1000\u003e;\n+                    full-duplex;\n+                    pause;\n+                };\n+            };\n+        };\n+    };\n+...\n+\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 15011f5752a994..86618efffa7780 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -17627,6 +17627,16 @@ L:\tnetdev@vger.kernel.org\n S:\tMaintained\n F:\tdrivers/net/phy/microchip_t1.c\n \n+MICROCHIP LAN9645X ETHERNET SWITCH DRIVER\n+M:\tJens Emil Schulz Østergaard \u003cjensemil.schulzostergaard@microchip.com\u003e\n+M:\tUNGLinuxDriver@microchip.com\n+L:\tnetdev@vger.kernel.org\n+S:\tMaintained\n+F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\n+F:\tdrivers/net/dsa/microchip/lan9645x/*\n+F:\tinclude/linux/dsa/lan9645x.h\n+F:\tnet/dsa/tag_lan9645x.c\n+\n MICROCHIP LAN966X ETHERNET DRIVER\n M:\tHoratiu Vultur \u003choratiu.vultur@microchip.com\u003e\n M:\tUNGLinuxDriver@microchip.com\ndiff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig\nindex 4ab567c5bbafc6..91431ef6c425cd 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/microchip/lan9645x/Kconfig\"\n+\n source \"drivers/net/dsa/mv88e6xxx/Kconfig\"\n \n source \"drivers/net/dsa/mxl862xx/Kconfig\"\ndiff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile\nindex 9347cfb3d0b5e7..e75f17888f75d0 100644\n--- a/drivers/net/dsa/microchip/Makefile\n+++ b/drivers/net/dsa/microchip/Makefile\n@@ -12,3 +12,4 @@ endif\n obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)\t+= ksz9477_i2c.o\n obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI)\t\t+= ksz_spi.o\n obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)\t+= ksz8863_smi.o\n+obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X)\t+= lan9645x/\ndiff --git a/drivers/net/dsa/microchip/lan9645x/Kconfig b/drivers/net/dsa/microchip/lan9645x/Kconfig\nnew file mode 100644\nindex 00000000000000..4d9fdf34104eb5\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/Kconfig\n@@ -0,0 +1,11 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+config NET_DSA_MICROCHIP_LAN9645X\n+\ttristate \"Microchip Lan9645x switch support\"\n+\tdepends on NET_DSA\n+\tselect NET_DSA_TAG_LAN9645X\n+\thelp\n+\t  This driver adds DSA support for Microchip Lan9645x switch chips.\n+\t  The lan9645x switch is a multi-port Gigabit AVB/TSN Ethernet Switch\n+\t  with five integrated 10/100/1000Base-T PHYs. In addition to the\n+\t  integrated PHYs, it supports up to 2 RGMII/RMII, up to 2\n+\t  BASE-X/SERDES/2.5GBASE-X and one Quad-SGMII/Quad-USGMII interfaces.\ndiff --git a/drivers/net/dsa/microchip/lan9645x/Makefile b/drivers/net/dsa/microchip/lan9645x/Makefile\nnew file mode 100644\nindex 00000000000000..cd994943c1c059\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/Makefile\n@@ -0,0 +1,12 @@\n+# SPDX-License-Identifier: GPL-2.0-only\n+obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X) += mchp-lan9645x.o\n+\n+mchp-lan9645x-objs := \\\n+\tlan9645x_mac.o \\\n+\tlan9645x_main.o \\\n+\tlan9645x_mdb.o \\\n+\tlan9645x_npi.o \\\n+\tlan9645x_phylink.o \\\n+\tlan9645x_port.o \\\n+\tlan9645x_stats.o \\\n+\tlan9645x_vlan.o \\\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_mac.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_mac.c\nnew file mode 100644\nindex 00000000000000..aefb3c58370a5b\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_mac.c\n@@ -0,0 +1,307 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \"lan9645x_main.h\"\n+\n+#define CMD_IDLE\t\t0\n+#define CMD_LEARN\t\t1\n+#define CMD_FORGET\t\t2\n+#define CMD_AGE\t\t\t3\n+#define CMD_GET_NEXT\t\t4\n+#define CMD_INIT\t\t5\n+#define CMD_READ\t\t6\n+#define CMD_WRITE\t\t7\n+#define CMD_SYNC_GET_NEXT\t8\n+\n+static int lan9645x_mac_wait_for_completion(struct lan9645x *lan9645x,\n+\t\t\t\t\t    u32 *maca)\n+{\n+\tu32 val = 0;\n+\tint err;\n+\n+\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\n+\n+\terr = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,\n+\t\t\t\t       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==\n+\t\t\t\t       CMD_IDLE);\n+\tif (err)\n+\t\treturn err;\n+\n+\tif (maca)\n+\t\t*maca = val;\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_mac_select(struct lan9645x *lan9645x,\n+\t\t\t\tconst unsigned char *addr, u16 vid)\n+{\n+\tu64 maddr = ether_addr_to_u64(addr);\n+\n+\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\n+\n+\tlan_wr(ANA_MACHDATA_VID_SET(vid) |\n+\t       ANA_MACHDATA_MACHDATA_SET(maddr \u003e\u003e 32),\n+\t       lan9645x,\n+\t       ANA_MACHDATA);\n+\n+\tlan_wr(maddr \u0026 GENMASK(31, 0),\n+\t       lan9645x,\n+\t       ANA_MACLDATA);\n+}\n+\n+static int __lan9645x_mact_forget(struct lan9645x *lan9645x,\n+\t\t\t\t  const unsigned char mac[ETH_ALEN],\n+\t\t\t\t  unsigned int vid,\n+\t\t\t\t  enum macaccess_entry_type type)\n+{\n+\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\n+\n+\tlan9645x_mac_select(lan9645x, mac, vid);\n+\n+\tlan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |\n+\t       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_FORGET),\n+\t       lan9645x,\n+\t       ANA_MACACCESS);\n+\n+\treturn lan9645x_mac_wait_for_completion(lan9645x, NULL);\n+}\n+\n+int lan9645x_mact_forget(struct lan9645x *lan9645x,\n+\t\t\t const unsigned char mac[ETH_ALEN], unsigned int vid,\n+\t\t\t enum macaccess_entry_type type)\n+{\n+\tint err;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emact_lock);\n+\terr = __lan9645x_mact_forget(lan9645x, mac, vid, type);\n+\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\n+\n+\treturn err;\n+}\n+\n+static bool lan9645x_mac_ports_use_cpu(struct lan9645x *lan9645x,\n+\t\t\t\t       const unsigned char *mac,\n+\t\t\t\t       enum macaccess_entry_type type)\n+{\n+\tu32 mc_ports;\n+\n+\tswitch (type) {\n+\tcase ENTRYTYPE_MACV4:\n+\t\tmc_ports = (mac[1] \u003c\u003c 8) | mac[2];\n+\t\tbreak;\n+\tcase ENTRYTYPE_MACV6:\n+\t\tmc_ports = (mac[0] \u003c\u003c 8) | mac[1];\n+\t\tbreak;\n+\tdefault:\n+\t\treturn false;\n+\t}\n+\n+\treturn !!(mc_ports \u0026 BIT(lan9645x-\u003enum_phys_ports));\n+}\n+\n+static int __lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\n+\t\t\t\t\t  const unsigned char *addr, u16 vid,\n+\t\t\t\t\t  enum macaccess_entry_type type,\n+\t\t\t\t\t  bool cpu_copy)\n+{\n+\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\n+\n+\tlan9645x_mac_select(lan9645x, addr, vid);\n+\n+\tlan_wr(ANA_MACACCESS_VALID_SET(1) |\n+\t       ANA_MACACCESS_DEST_IDX_SET(port) |\n+\t       ANA_MACACCESS_MAC_CPU_COPY_SET(cpu_copy) |\n+\t       ANA_MACACCESS_ENTRYTYPE_SET(type) |\n+\t       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_LEARN),\n+\t       lan9645x, ANA_MACACCESS);\n+\n+\treturn lan9645x_mac_wait_for_completion(lan9645x, NULL);\n+}\n+\n+static int __lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\n+\t\t\t\t const unsigned char *addr, u16 vid,\n+\t\t\t\t enum macaccess_entry_type type)\n+{\n+\tbool cpu_copy = lan9645x_mac_ports_use_cpu(lan9645x, addr, type);\n+\n+\treturn __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,\n+\t\t\t\t\t      cpu_copy);\n+}\n+\n+int lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\n+\t\t\tconst unsigned char *addr, u16 vid,\n+\t\t\tenum macaccess_entry_type type)\n+{\n+\tint err;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emact_lock);\n+\terr = __lan9645x_mact_learn(lan9645x, port, addr, vid, type);\n+\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\n+\n+\treturn err;\n+}\n+\n+int lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\n+\t\t\t\t const unsigned char *addr, u16 vid,\n+\t\t\t\t enum macaccess_entry_type type, bool cpu_copy)\n+{\n+\tint err;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emact_lock);\n+\terr = __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,\n+\t\t\t\t\t     cpu_copy);\n+\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\n+\n+\treturn err;\n+}\n+\n+int lan9645x_mact_flush(struct lan9645x *lan9645x, int port)\n+{\n+\tint err;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emact_lock);\n+\t/* MAC table entries with dst index matching port are aged on scan. */\n+\tlan_wr(ANA_ANAGEFIL_PID_EN_SET(1) |\n+\t       ANA_ANAGEFIL_PID_VAL_SET(port),\n+\t       lan9645x, ANA_ANAGEFIL);\n+\n+\t/* Flushing requires two scans. First sets AGE_FLAG=1, second removes\n+\t * entries with AGE_FLAG=1.\n+\t */\n+\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),\n+\t       lan9645x,\n+\t       ANA_MACACCESS);\n+\n+\terr = lan9645x_mac_wait_for_completion(lan9645x, NULL);\n+\tif (err)\n+\t\tgoto mact_unlock;\n+\n+\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),\n+\t       lan9645x,\n+\t       ANA_MACACCESS);\n+\n+\terr = lan9645x_mac_wait_for_completion(lan9645x, NULL);\n+\n+mact_unlock:\n+\tlan_wr(0, lan9645x, ANA_ANAGEFIL);\n+\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\n+\treturn err;\n+}\n+\n+int lan9645x_mac_init(struct lan9645x *lan9645x)\n+{\n+\tu32 val;\n+\tint err;\n+\n+\t/* Clear the MAC table */\n+\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_INIT), lan9645x,\n+\t       ANA_MACACCESS);\n+\n+\terr = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,\n+\t\t\t\t       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==\n+\t\t\t\t       CMD_IDLE);\n+\tif (err) {\n+\t\tdev_err(lan9645x-\u003edev, \"MAC table clear timeout\\n\");\n+\t\treturn err;\n+\t}\n+\n+\tmutex_init(\u0026lan9645x-\u003emact_lock);\n+\treturn 0;\n+}\n+\n+void lan9645x_mac_deinit(struct lan9645x *lan9645x)\n+{\n+\tmutex_destroy(\u0026lan9645x-\u003emact_lock);\n+}\n+\n+int lan9645x_mact_dsa_dump(struct lan9645x *lan9645x, int port,\n+\t\t\t   dsa_fdb_dump_cb_t *cb, void *data)\n+{\n+\tu8 mac[ETH_ALEN] __aligned(2);\n+\tu32 mach, macl, maca;\n+\tint err = 0;\n+\tu32 autoage;\n+\tu64 addr;\n+\tu16 vid;\n+\tu8 type;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emact_lock);\n+\n+\t/* The aging filter works both for aging scans and GET_NEXT table scans.\n+\t * With it, the HW table iteration only stops at entries matching our\n+\t * filter. Since DSA calls us for each port on a table dump, this helps\n+\t * avoid unnecessary work.\n+\t *\n+\t * Disable automatic aging temporarily. First save current state.\n+\t */\n+\tautoage = lan_rd(lan9645x, ANA_AUTOAGE);\n+\n+\t/* Disable aging */\n+\tlan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(0),\n+\t\tANA_AUTOAGE_AGE_PERIOD,\n+\t\tlan9645x, ANA_AUTOAGE);\n+\n+\t/* Setup filter on our port */\n+\tlan_wr(ANA_ANAGEFIL_PID_EN_SET(1) |\n+\t       ANA_ANAGEFIL_PID_VAL_SET(port),\n+\t       lan9645x, ANA_ANAGEFIL);\n+\n+\tlan_wr(0, lan9645x, ANA_MACHDATA);\n+\tlan_wr(0, lan9645x, ANA_MACLDATA);\n+\n+\ttype = ENTRYTYPE_NORMAL;\n+\n+\twhile (1) {\n+\t\t/* NOTE: we rely on mach, macl and type being set correctly in\n+\t\t * the registers from previous round, vis a vis the GET_NEXT\n+\t\t * semantics, so locking entire loop is important.\n+\t\t */\n+\t\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_GET_NEXT) |\n+\t\t       ANA_MACACCESS_ENTRYTYPE_SET(type),\n+\t\t       lan9645x, ANA_MACACCESS);\n+\n+\t\terr = lan9645x_mac_wait_for_completion(lan9645x, \u0026maca);\n+\t\tif (err)\n+\t\t\tbreak;\n+\n+\t\tif (ANA_MACACCESS_VALID_GET(maca) == 0)\n+\t\t\tbreak;\n+\n+\t\ttype = ANA_MACACCESS_ENTRYTYPE_GET(maca);\n+\t\tmach = lan_rd(lan9645x, ANA_MACHDATA);\n+\t\tmacl = lan_rd(lan9645x, ANA_MACLDATA);\n+\n+\t\t/* Only dynamic entries are surfaced through the user port dump.\n+\t\t * ENTRYTYPE_LOCKED entries are already reported by the bridge\n+\t\t * master's ndo_fdb_dump as NTF_MASTER, so we avoid duplicating\n+\t\t * them as NTF_SELF.\n+\t\t * Entries toward the host (NTF_SELF) have DEST_IDX == the CPU\n+\t\t * port module and are filtered out by the DEST_IDX check.\n+\t\t */\n+\t\tif (ANA_MACACCESS_DEST_IDX_GET(maca) == port \u0026\u0026\n+\t\t    type == ENTRYTYPE_NORMAL) {\n+\t\t\taddr = (u64)ANA_MACHDATA_MACHDATA_GET(mach) \u003c\u003c 32 |\n+\t\t\t       macl;\n+\t\t\tu64_to_ether_addr(addr, mac);\n+\t\t\tvid = ANA_MACHDATA_VID_GET(mach);\n+\t\t\tif (vid \u003e VLAN_MAX)\n+\t\t\t\tvid = 0;\n+\n+\t\t\terr = cb(mac, vid, false, data);\n+\t\t\tif (err)\n+\t\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\t/* Remove aging filters and restore aging */\n+\tlan_wr(0, lan9645x, ANA_ANAGEFIL);\n+\tlan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(ANA_AUTOAGE_AGE_PERIOD_GET(autoage)),\n+\t\tANA_AUTOAGE_AGE_PERIOD,\n+\t\tlan9645x, ANA_AUTOAGE);\n+\n+\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\n+\n+\treturn err;\n+}\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c\nnew file mode 100644\nindex 00000000000000..2e97178a416f6b\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c\n@@ -0,0 +1,1041 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \u003clinux/platform_device.h\u003e\n+\n+#include \"lan9645x_main.h\"\n+#include \"lan9645x_stats.h\"\n+\n+static const char *lan9645x_resource_names[NUM_TARGETS + 1] = {\n+\t[TARGET_GCB]          = \"gcb\",\n+\t[TARGET_QS]           = \"qs\",\n+\t[TARGET_CHIP_TOP]     = \"chip_top\",\n+\t[TARGET_REW]          = \"rew\",\n+\t[TARGET_SYS]          = \"sys\",\n+\t[TARGET_HSIO]         = \"hsio\",\n+\t[TARGET_DEV]          = \"dev\",\n+\t[TARGET_DEV + 1]      = \"dev1\",\n+\t[TARGET_DEV + 2]      = \"dev2\",\n+\t[TARGET_DEV + 3]      = \"dev3\",\n+\t[TARGET_DEV + 4]      = \"dev4\",\n+\t[TARGET_DEV + 5]      = \"dev5\",\n+\t[TARGET_DEV + 6]      = \"dev6\",\n+\t[TARGET_DEV + 7]      = \"dev7\",\n+\t[TARGET_DEV + 8]      = \"dev8\",\n+\t[TARGET_QSYS]         = \"qsys\",\n+\t[TARGET_AFI]          = \"afi\",\n+\t[TARGET_ANA]          = \"ana\",\n+\t[NUM_TARGETS]         = NULL,\n+};\n+\n+static int lan9645x_tag_npi_setup(struct dsa_switch *ds)\n+{\n+\tstruct dsa_port *dp, *first_cpu_dp = NULL;\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\n+\tdsa_switch_for_each_user_port(dp, ds) {\n+\t\tif (dp-\u003ecpu_dp-\u003eds != ds) {\n+\t\t\tdev_err(ds-\u003edev,\n+\t\t\t\t\"NPI port on a remote switch is not supported\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tif (first_cpu_dp \u0026\u0026 dp-\u003ecpu_dp != first_cpu_dp) {\n+\t\t\tdev_err(ds-\u003edev, \"Multiple NPI ports not supported\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\n+\t\tfirst_cpu_dp = dp-\u003ecpu_dp;\n+\t}\n+\n+\tif (!first_cpu_dp)\n+\t\treturn -EINVAL;\n+\n+\tlan9645x_npi_port_init(lan9645x, first_cpu_dp);\n+\n+\treturn 0;\n+}\n+\n+static enum dsa_tag_protocol lan9645x_get_tag_protocol(struct dsa_switch *ds,\n+\t\t\t\t\t\t       int port,\n+\t\t\t\t\t\t       enum dsa_tag_protocol tp)\n+{\n+\treturn DSA_TAG_PROTO_LAN9645X;\n+}\n+\n+static void lan9645x_teardown(struct dsa_switch *ds)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\n+\tdestroy_workqueue(lan9645x-\u003eowq);\n+\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\n+\tlan9645x_mac_deinit(lan9645x);\n+\tlan9645x_mdb_deinit(lan9645x);\n+\tlan9645x_stats_deinit(lan9645x);\n+\tmutex_destroy(\u0026lan9645x-\u003eport_mux_lock);\n+\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\n+}\n+\n+static int lan9645x_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\n+{\n+\treturn lan9645x_port_set_maxlen(ds-\u003epriv, port, new_mtu);\n+}\n+\n+static int lan9645x_get_max_mtu(struct dsa_switch *ds, int port)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tint max_mtu;\n+\n+\t/* Actual MAC max MTU is around 16KB. We set 10000 - overhead which\n+\t * should be sufficient for all jumbo frames. Larger frames can cause\n+\t * problems especially with flow control, since we only have 160K queue\n+\t * buffer.\n+\t */\n+\tmax_mtu = 10000 - ETH_HLEN - ETH_FCS_LEN;\n+\n+\tif (port == lan9645x-\u003enpi) {\n+\t\tmax_mtu -= LAN9645X_IFH_LEN;\n+\t\tmax_mtu -= LAN9645X_LONG_PREFIX_LEN;\n+\t}\n+\n+\treturn max_mtu;\n+}\n+\n+static int lan9645x_reset_switch(struct lan9645x *lan9645x)\n+{\n+\tint val = 0;\n+\tint err;\n+\n+\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan9645x, SYS_RESET_CFG);\n+\tlan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan9645x, SYS_RAM_INIT);\n+\terr = lan9645x_rd_poll_timeout(lan9645x, SYS_RAM_INIT, val,\n+\t\t\t\t       SYS_RAM_INIT_RAM_INIT_GET(val) == 0);\n+\tif (err) {\n+\t\tdev_err(lan9645x-\u003edev, \"Failed to init chip RAM.\\n\");\n+\t\treturn err;\n+\t}\n+\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan9645x, SYS_RESET_CFG);\n+\n+\treturn 0;\n+}\n+\n+static int lan9645x_setup(struct dsa_switch *ds)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct device *dev = lan9645x-\u003edev;\n+\tint supported, used = 0;\n+\tstruct dsa_port *dp;\n+\tu32 front_ports;\n+\tint err;\n+\n+\tlan9645x-\u003enum_phys_ports = ds-\u003enum_ports;\n+\tfront_ports = dsa_user_ports(ds);\n+\tsupported = lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis;\n+\n+\tdsa_switch_for_each_available_port(dp, ds)\n+\t\tused++;\n+\n+\tif (used \u003e supported) {\n+\t\tdev_err(ds-\u003edev,\n+\t\t\t\"%d physical ports in use in DT, SKU supports at most %d\\n\",\n+\t\t\tused, supported);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\terr = lan9645x_reset_switch(lan9645x);\n+\tif (err)\n+\t\treturn err;\n+\n+\terr = lan9645x_tag_npi_setup(ds);\n+\tif (err) {\n+\t\tdev_err(dev, \"Failed to setup NPI port.\\n\");\n+\t\treturn err;\n+\t}\n+\n+\tmutex_init(\u0026lan9645x-\u003eport_mux_lock);\n+\tmutex_init(\u0026lan9645x-\u003efwd_domain_lock);\n+\terr = lan9645x_vlan_init(lan9645x);\n+\tif (err)\n+\t\tgoto err_mutex;\n+\terr = lan9645x_mac_init(lan9645x);\n+\tif (err)\n+\t\tgoto err_mutex;\n+\tlan9645x_mdb_init(lan9645x);\n+\n+\t/* Link Aggregation Mode: NETDEV_LAG_HASH_L2 */\n+\tlan_wr(ANA_AGGR_CFG_AC_SMAC_ENA |\n+\t       ANA_AGGR_CFG_AC_DMAC_ENA,\n+\t       lan9645x, ANA_AGGR_CFG);\n+\n+\t/* Flush queues */\n+\tlan_wr(GENMASK(1, 0), lan9645x, QS_XTR_FLUSH);\n+\n+\t/* Allow to drain */\n+\tusleep_range(1000, 2000);\n+\n+\t/* All Queues normal */\n+\tlan_wr(0x0, lan9645x, QS_XTR_FLUSH);\n+\n+\t/* Set MAC age time to default value, the entry is aged after\n+\t * 2 * AGE_PERIOD\n+\t */\n+\tlan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),\n+\t       lan9645x, ANA_AUTOAGE);\n+\n+\t/* Disable learning for frames discarded by VLAN ingress filtering */\n+\tlan_rmw(ANA_ADVLEARN_VLAN_CHK_SET(1),\n+\t\tANA_ADVLEARN_VLAN_CHK,\n+\t\tlan9645x, ANA_ADVLEARN);\n+\n+\t/* Queue system frame ageing. We target 2s ageing.\n+\t *\n+\t * Register unit is 1024 cycles.\n+\t *\n+\t * ASIC: 165.625 Mhz  ~ 6.0377 ns period\n+\t *\n+\t * 1024 * 6.0377 ns =~ 6182 ns\n+\t * val = 2000000000ns / 6182ns\n+\t */\n+\tlan_wr(SYS_FRM_AGING_AGE_TX_ENA_SET(1) |\n+\t       SYS_FRM_AGING_MAX_AGE_SET((2000000000 / 6182)),\n+\t       lan9645x,  SYS_FRM_AGING);\n+\n+\t/* Setup flooding PGIDs for IPv4/IPv6 multicast. Control and dataplane\n+\t * use the same masks. Control frames are redirected to CPU, and\n+\t * the network stack is responsible for forwarding these.\n+\t * The dataplane is forwarding according to the offloaded MDB entries.\n+\t */\n+\tlan_wr(ANA_FLOODING_IPMC_FLD_MC4_DATA_SET(PGID_MCIPV4) |\n+\t       ANA_FLOODING_IPMC_FLD_MC4_CTRL_SET(PGID_MC) |\n+\t       ANA_FLOODING_IPMC_FLD_MC6_DATA_SET(PGID_MCIPV6) |\n+\t       ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),\n+\t       lan9645x, ANA_FLOODING_IPMC);\n+\n+\t/* There are 8 priorities */\n+\tfor (int prio = 0; prio \u003c 8; ++prio)\n+\t\tlan_wr(ANA_FLOODING_FLD_MULTICAST_SET(PGID_MC) |\n+\t\t       ANA_FLOODING_FLD_UNICAST_SET(PGID_UC) |\n+\t\t       ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),\n+\t\t       lan9645x, ANA_FLOODING(prio));\n+\n+\t/* Allow VLAN table to control whether cpu copy from the pgid table is\n+\t * enabled. Index PGID_ENTRIES is CPU src pgid, so we skip it as the\n+\t * configuration makes little sense here.\n+\t */\n+\tfor (int i = 0; i \u003c PGID_ENTRIES; ++i)\n+\t\tlan_wr(ANA_PGID_CFG_OBEY_VLAN_SET(1),\n+\t\t       lan9645x, ANA_PGID_CFG(i));\n+\n+\t/* Disable bridging by default */\n+\tfor (int p = 0; p \u003c lan9645x-\u003enum_phys_ports; p++) {\n+\t\tlan_wr(0, lan9645x, ANA_PGID(PGID_SRC + p));\n+\n+\t\t/* Do not forward BPDU frames to the front ports and copy them\n+\t\t * to CPU\n+\t\t */\n+\t\tlan_wr(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA,\n+\t\t       lan9645x, ANA_CPU_FWD_BPDU_CFG(p));\n+\t}\n+\n+\tfor (int i = 0; i \u003c 16; i++) {\n+\t\t/* The register instance number corresponds to the\n+\t\t * address of the extracted frame. For instance:\n+\t\t * CPUQ_8021_CFG[4].CPUQ_BPDU_VAL\n+\t\t * is the cpu extraction queue used for BPDU frames\n+\t\t * with address 01-80-C2-00-00-04\n+\t\t */\n+\t\tlan_rmw(ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_SET(LAN9645X_CPUQ_TRAP),\n+\t\t\tANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL,\n+\t\t\tlan9645x, ANA_CPUQ_8021_CFG(i));\n+\t}\n+\n+\t/* Reserve ~1700 bytes of buffer memory per (port, prio) for source\n+\t * tracking (resource 0, indices 0..95) and destination tracking\n+\t * (resource 2, indices 512..607). These are access watermarks, not\n+\t * pre-allocations: a flow draws from its reservation first, then\n+\t * from the shared pool. Keeping the reservation above a max-size\n+\t * Ethernet frame prevents a single frame from spilling into the\n+\t * shared pool, and cause pause frames to be emitted without actual\n+\t * congestion.\n+\t */\n+\tfor (int i = 0; i \u003c= QSYS_Q_RSRV; ++i) {\n+\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(i));\n+\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(512 + i));\n+\t}\n+\n+\tlan9645x_port_cpu_init(lan9645x);\n+\n+\t/* Multicast to all front ports */\n+\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MC));\n+\n+\t/* IP multicast to all front ports */\n+\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV4));\n+\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV6));\n+\n+\t/* Unicast to all front ports */\n+\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_UC));\n+\n+\t/* Broadcast to cpu and all front ports */\n+\tlan_wr(BIT(lan9645x-\u003enum_phys_ports) | front_ports, lan9645x,\n+\t       ANA_PGID(PGID_BC));\n+\n+\tlan9645x_port_set_tail_drop_wm(lan9645x);\n+\n+\tlan9645x-\u003eowq = alloc_ordered_workqueue(\"%s-owq\", 0,\n+\t\t\t\t\t\tdev_name(lan9645x-\u003edev));\n+\tif (!lan9645x-\u003eowq) {\n+\t\terr = -ENOMEM;\n+\t\tgoto err_mac;\n+\t}\n+\n+\tlan9645x_stats_init(lan9645x);\n+\n+\tds-\u003emtu_enforcement_ingress = true;\n+\tds-\u003eassisted_learning_on_cpu_port = true;\n+\tds-\u003efdb_isolation = true;\n+\n+\t/* ANA_AUTOAGE_AGE_PERIOD is a seconds-based field and entries are\n+\t * aged after 2 * AGE_PERIOD, giving (2 * FIELD_MAX) seconds of\n+\t * maximum aging.\n+\t */\n+\tds-\u003eageing_time_max = 2U * MSEC_PER_SEC *\n+\t\t\t      FIELD_MAX(ANA_AUTOAGE_AGE_PERIOD);\n+\n+\tdev_info(lan9645x-\u003edev,\n+\t\t \"SKU features: max_ports=%d\\n\",\n+\t\t lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis);\n+\n+\treturn 0;\n+\n+err_mac:\n+\tlan9645x_mac_deinit(lan9645x);\n+\tlan9645x_mdb_deinit(lan9645x);\n+err_mutex:\n+\tmutex_destroy(\u0026lan9645x-\u003eport_mux_lock);\n+\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\n+\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\n+\treturn err;\n+}\n+\n+static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,\n+\t\t\t\t\t   struct phylink_config *config)\n+{\n+\tlan9645x_phylink_get_caps(ds-\u003epriv, port, config);\n+}\n+\n+static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)\n+{\n+\tu32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emact_lock);\n+\n+\t/* Entry must suffer two aging scans before it is removed, so it is\n+\t * aged after 2*AGE_PERIOD, and the unit is in seconds.\n+\t * An age period of 0 disables automatic aging.\n+\t */\n+\tlan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(msecs ? age_secs : 0),\n+\t\tANA_AUTOAGE_AGE_PERIOD,\n+\t\tlan9645x, ANA_AUTOAGE);\n+\n+\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\n+\treturn 0;\n+}\n+\n+static int lan9645x_port_pre_bridge_flags(struct dsa_switch *ds, int port,\n+\t\t\t\t\t  struct switchdev_brport_flags flags,\n+\t\t\t\t\t  struct netlink_ext_ack *extack)\n+{\n+\tif (flags.mask \u0026\n+\t    ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD))\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_port_pgid_set(struct lan9645x *lan9645x, u16 pgid,\n+\t\t\t\t   int chip_port, bool enabled)\n+{\n+\tu32 reg_msk, port_msk;\n+\n+\tWARN_ON(chip_port \u003e lan9645x-\u003enum_phys_ports);\n+\n+\tport_msk = ANA_PGID_PGID_SET(enabled ? BIT(chip_port) : 0);\n+\treg_msk = ANA_PGID_PGID_SET(BIT(chip_port));\n+\n+\tlan_rmw(port_msk, reg_msk, lan9645x, ANA_PGID(pgid));\n+}\n+\n+static void lan9645x_port_set_learning(struct lan9645x *lan9645x, int port,\n+\t\t\t\t       bool enabled)\n+{\n+\tstruct lan9645x_port *p = lan9645x_to_port(lan9645x, port);\n+\n+\tp-\u003elearn_ena = enabled;\n+\n+\tenabled = enabled \u0026\u0026 (p-\u003estp_state == BR_STATE_LEARNING ||\n+\t\t\t      p-\u003estp_state == BR_STATE_FORWARDING);\n+\n+\tlan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled), ANA_PORT_CFG_LEARN_ENA,\n+\t\tlan9645x, ANA_PORT_CFG(port));\n+}\n+\n+static int lan9645x_port_bridge_flags(struct dsa_switch *ds, int port,\n+\t\t\t\t      struct switchdev_brport_flags f,\n+\t\t\t\t      struct netlink_ext_ack *extack)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\n+\tif (WARN_ON(port == lan9645x-\u003enpi))\n+\t\treturn -EINVAL;\n+\n+\tif (f.mask \u0026 BR_LEARNING)\n+\t\tlan9645x_port_set_learning(lan9645x, port,\n+\t\t\t\t\t   !!(f.val \u0026 BR_LEARNING));\n+\n+\tif (f.mask \u0026 BR_FLOOD)\n+\t\tlan9645x_port_pgid_set(lan9645x, PGID_UC, port,\n+\t\t\t\t       !!(f.val \u0026 BR_FLOOD));\n+\n+\tif (f.mask \u0026 BR_MCAST_FLOOD) {\n+\t\tbool ena = !!(f.val \u0026 BR_MCAST_FLOOD);\n+\n+\t\tlan9645x_port_pgid_set(lan9645x, PGID_MC, port, ena);\n+\t\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV4, port, ena);\n+\t\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV6, port, ena);\n+\t}\n+\n+\tif (f.mask \u0026 BR_BCAST_FLOOD)\n+\t\tlan9645x_port_pgid_set(lan9645x, PGID_BC, port,\n+\t\t\t\t       !!(f.val \u0026 BR_BCAST_FLOOD));\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_update_fwd_mask(struct lan9645x *lan9645x)\n+{\n+\tstruct lan9645x_port *p;\n+\tstruct dsa_port *dp;\n+\n+\tlockdep_assert_held(\u0026lan9645x-\u003efwd_domain_lock);\n+\n+\t/* Updates the source port PGIDs, making sure frames from p\n+\t * are only forwarded to ports q != p, where q is relevant to forward\n+\t */\n+\tdsa_switch_for_each_available_port(dp, lan9645x-\u003eds) {\n+\t\tu32 mask = 0;\n+\n+\t\tp = lan9645x_to_port(lan9645x, dp-\u003eindex);\n+\n+\t\tif (lan9645x_port_is_bridged(p) \u0026\u0026\n+\t\t    (lan9645x-\u003ebridge_fwd_mask \u0026 BIT(dp-\u003eindex))) {\n+\t\t\tmask = lan9645x-\u003ebridge_mask \u0026\n+\t\t\t       lan9645x-\u003ebridge_fwd_mask \u0026 ~BIT(dp-\u003eindex);\n+\t\t}\n+\n+\t\tlan_wr(mask, lan9645x, ANA_PGID(PGID_SRC + dp-\u003eindex));\n+\t}\n+}\n+\n+static void __lan9645x_port_mark_host_flood(struct lan9645x *lan9645x, int port,\n+\t\t\t\t\t    bool uc, bool mc)\n+{\n+\tlockdep_assert_held(\u0026lan9645x-\u003efwd_domain_lock);\n+\n+\tif (uc)\n+\t\tlan9645x-\u003ehost_flood_uc_mask |= BIT(port);\n+\telse\n+\t\tlan9645x-\u003ehost_flood_uc_mask \u0026= ~BIT(port);\n+\n+\tif (mc)\n+\t\tlan9645x-\u003ehost_flood_mc_mask |= BIT(port);\n+\telse\n+\t\tlan9645x-\u003ehost_flood_mc_mask \u0026= ~BIT(port);\n+}\n+\n+static void __lan9645x_port_set_host_flood(struct lan9645x *lan9645x)\n+{\n+\tbool mc_ena, uc_ena;\n+\tu16 unbridged;\n+\n+\tlockdep_assert_held(\u0026lan9645x-\u003efwd_domain_lock);\n+\n+\t/* We want promiscuous and all_multi to affect standalone ports, for\n+\t * debug and test purposes.\n+\t *\n+\t * However, the linux bridge is incredibly eager to put bridged ports in\n+\t * promiscuous mode.\n+\t *\n+\t * This is unfortunate since lan9645x flood masks are global and not per\n+\t * ingress port. When some port triggers unknown uc/mc to the CPU, the\n+\t * traffic from any port is forwarded to the CPU.\n+\t *\n+\t * If the host CPU is weak, this can cause tremendous stress. Therefore,\n+\t * we compromise by ignoring this host flood request for bridged ports.\n+\t */\n+\tunbridged = ~lan9645x-\u003ebridge_mask \u0026 GENMASK(NUM_PHYS_PORTS - 1, 0);\n+\n+\tuc_ena = !!(lan9645x-\u003ehost_flood_uc_mask \u0026 unbridged);\n+\tlan9645x_port_pgid_set(lan9645x, PGID_UC, lan9645x-\u003enum_phys_ports,\n+\t\t\t       uc_ena);\n+\n+\tmc_ena = !!(lan9645x-\u003ehost_flood_mc_mask \u0026 unbridged);\n+\tlan9645x_port_pgid_set(lan9645x, PGID_MC, lan9645x-\u003enum_phys_ports,\n+\t\t\t       mc_ena);\n+\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV4, lan9645x-\u003enum_phys_ports,\n+\t\t\t       mc_ena);\n+\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV6, lan9645x-\u003enum_phys_ports,\n+\t\t\t       mc_ena);\n+}\n+\n+static void lan9645x_host_flood_work_fn(struct work_struct *work)\n+{\n+\tstruct lan9645x_port *p = container_of(work, struct lan9645x_port,\n+\t\t\t\t\t       host_flood_work);\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tu8 req;\n+\n+\treq = READ_ONCE(p-\u003ehost_flood_req);\n+\n+\tmutex_lock(\u0026lan9645x-\u003efwd_domain_lock);\n+\t__lan9645x_port_mark_host_flood(lan9645x, p-\u003echip_port,\n+\t\t\t\t\treq \u0026 LAN9645X_HOST_FLOOD_UC,\n+\t\t\t\t\treq \u0026 LAN9645X_HOST_FLOOD_MC);\n+\t__lan9645x_port_set_host_flood(lan9645x);\n+\tmutex_unlock(\u0026lan9645x-\u003efwd_domain_lock);\n+}\n+\n+/* Called in atomic context. */\n+static void lan9645x_port_set_host_flood(struct dsa_switch *ds, int port,\n+\t\t\t\t\t bool uc, bool mc)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\n+\tWRITE_ONCE(p-\u003ehost_flood_req,\n+\t\t   (uc ? LAN9645X_HOST_FLOOD_UC : 0) |\n+\t\t   (mc ? LAN9645X_HOST_FLOOD_MC : 0));\n+\tqueue_work(lan9645x-\u003eowq, \u0026p-\u003ehost_flood_work);\n+}\n+\n+static int lan9645x_port_bridge_join(struct dsa_switch *ds, int port,\n+\t\t\t\t     struct dsa_bridge bridge,\n+\t\t\t\t     bool *tx_fwd_offload,\n+\t\t\t\t     struct netlink_ext_ack *extack)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\n+\tmutex_lock(\u0026lan9645x-\u003efwd_domain_lock);\n+\tif (lan9645x-\u003ebridge \u0026\u0026 lan9645x-\u003ebridge != bridge.dev) {\n+\t\tmutex_unlock(\u0026lan9645x-\u003efwd_domain_lock);\n+\t\tNL_SET_ERR_MSG_MOD(extack, \"Only one bridge supported\");\n+\t\treturn -EBUSY;\n+\t}\n+\n+\t/* First bridged port sets bridge dev */\n+\tif (!lan9645x-\u003ebridge_mask)\n+\t\tlan9645x-\u003ebridge = bridge.dev;\n+\n+\tlan9645x-\u003ebridge_mask |= BIT(p-\u003echip_port);\n+\t__lan9645x_port_set_host_flood(lan9645x);\n+\tlan9645x_vlan_clear_hostmode(p);\n+\n+\tmutex_unlock(\u0026lan9645x-\u003efwd_domain_lock);\n+\n+\t/* Later: stp_state_set updates forwarding */\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_port_bridge_stp_state_set(struct dsa_switch *ds, int port,\n+\t\t\t\t\t       u8 state)\n+{\n+\tstruct lan9645x *lan9645x;\n+\tstruct lan9645x_port *p;\n+\tbool learn_ena;\n+\n+\tlan9645x = ds-\u003epriv;\n+\tp = lan9645x_to_port(lan9645x, port);\n+\n+\tmutex_lock(\u0026lan9645x-\u003efwd_domain_lock);\n+\n+\tp-\u003estp_state = state;\n+\n+\tif (state == BR_STATE_FORWARDING)\n+\t\tlan9645x-\u003ebridge_fwd_mask |= BIT(p-\u003echip_port);\n+\telse\n+\t\tlan9645x-\u003ebridge_fwd_mask \u0026= ~BIT(p-\u003echip_port);\n+\n+\tlearn_ena = (state == BR_STATE_LEARNING ||\n+\t\t     state == BR_STATE_FORWARDING) \u0026\u0026 p-\u003elearn_ena;\n+\n+\tlan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(learn_ena),\n+\t\tANA_PORT_CFG_LEARN_ENA, lan9645x,\n+\t\tANA_PORT_CFG(p-\u003echip_port));\n+\n+\tlan9645x_update_fwd_mask(lan9645x);\n+\tmutex_unlock(\u0026lan9645x-\u003efwd_domain_lock);\n+}\n+\n+static void lan9645x_port_bridge_leave(struct dsa_switch *ds, int port,\n+\t\t\t\t       struct dsa_bridge bridge)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\n+\tmutex_lock(\u0026lan9645x-\u003efwd_domain_lock);\n+\n+\tlan9645x-\u003ebridge_mask \u0026= ~BIT(p-\u003echip_port);\n+\n+\t/* Last port leaving clears bridge dev */\n+\tif (!lan9645x-\u003ebridge_mask)\n+\t\tlan9645x-\u003ebridge = NULL;\n+\n+\t__lan9645x_port_set_host_flood(lan9645x);\n+\tlan9645x_vlan_set_hostmode(p);\n+\tlan9645x_update_fwd_mask(lan9645x);\n+\n+\tmutex_unlock(\u0026lan9645x-\u003efwd_domain_lock);\n+}\n+\n+static int lan9645x_port_vlan_filtering(struct dsa_switch *ds, int port,\n+\t\t\t\t\tbool enabled,\n+\t\t\t\t\tstruct netlink_ext_ack *extack)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\tp-\u003evlan_aware = enabled;\n+\tlan9645x_vlan_port_apply(p);\n+\n+\treturn 0;\n+}\n+\n+static int lan9645x_port_vlan_add(struct dsa_switch *ds, int port,\n+\t\t\t\t  const struct switchdev_obj_port_vlan *vlan,\n+\t\t\t\t  struct netlink_ext_ack *extack)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\tbool pvid, untagged;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\tpvid = !!(vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_PVID);\n+\tuntagged = !!(vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_UNTAGGED);\n+\n+\treturn lan9645x_vlan_port_add_vlan(p, vlan-\u003evid, pvid, untagged,\n+\t\t\t\t\t   extack);\n+}\n+\n+static int lan9645x_port_vlan_del(struct dsa_switch *ds, int port,\n+\t\t\t\t  const struct switchdev_obj_port_vlan *vlan)\n+{\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\treturn lan9645x_vlan_port_del_vlan(p, vlan-\u003evid);\n+}\n+\n+static void lan9645x_port_fast_age(struct dsa_switch *ds, int port)\n+{\n+\tlan9645x_mact_flush(ds-\u003epriv, port);\n+}\n+\n+static int lan9645x_fdb_dump(struct dsa_switch *ds, int port,\n+\t\t\t     dsa_fdb_dump_cb_t *cb, void *data)\n+{\n+\treturn lan9645x_mact_dsa_dump(ds-\u003epriv, port, cb, data);\n+}\n+\n+static struct net_device *lan9645x_db2bridge(struct dsa_db db)\n+{\n+\tswitch (db.type) {\n+\tcase DSA_DB_PORT:\n+\tcase DSA_DB_LAG:\n+\t\treturn NULL;\n+\tcase DSA_DB_BRIDGE:\n+\t\treturn db.bridge.dev;\n+\tdefault:\n+\t\treturn ERR_PTR(-EOPNOTSUPP);\n+\t}\n+}\n+\n+static int lan9645x_fdb_add(struct dsa_switch *ds, int port,\n+\t\t\t    const unsigned char *addr, u16 vid,\n+\t\t\t    struct dsa_db db)\n+{\n+\tstruct net_device *br = lan9645x_db2bridge(db);\n+\tstruct dsa_port *dp = dsa_to_port(ds, port);\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tint dest;\n+\n+\tif (IS_ERR(br))\n+\t\treturn PTR_ERR(br);\n+\n+\tif (dsa_port_is_cpu(dp) \u0026\u0026 !br \u0026\u0026\n+\t    dsa_fdb_present_in_other_db(ds, port, addr, vid, db))\n+\t\treturn 0;\n+\n+\tif (!vid)\n+\t\tvid = lan9645x_vlan_unaware_pvid(!!br);\n+\n+\tdest = dsa_port_is_cpu(dp) ? PGID_CPU : port;\n+\n+\treturn lan9645x_mact_learn(lan9645x, dest, addr, vid, ENTRYTYPE_LOCKED);\n+}\n+\n+static int lan9645x_fdb_del(struct dsa_switch *ds, int port,\n+\t\t\t    const unsigned char *addr, u16 vid,\n+\t\t\t    struct dsa_db db)\n+{\n+\tstruct net_device *br = lan9645x_db2bridge(db);\n+\tstruct dsa_port *dp = dsa_to_port(ds, port);\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\n+\tif (IS_ERR(br))\n+\t\treturn PTR_ERR(br);\n+\n+\tif (dsa_port_is_cpu(dp) \u0026\u0026 !br \u0026\u0026\n+\t    dsa_fdb_present_in_other_db(ds, port, addr, vid, db))\n+\t\treturn 0;\n+\n+\tif (!vid)\n+\t\tvid = lan9645x_vlan_unaware_pvid(!!br);\n+\n+\treturn lan9645x_mact_forget(lan9645x, addr, vid, ENTRYTYPE_LOCKED);\n+}\n+\n+static int lan9645x_mdb_add(struct dsa_switch *ds, int port,\n+\t\t\t    const struct switchdev_obj_port_mdb *mdb,\n+\t\t\t    struct dsa_db db)\n+{\n+\tstruct net_device *bridge_dev = lan9645x_db2bridge(db);\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\n+\tdev_dbg(lan9645x-\u003edev, \"port=%d addr=%pM vid=%u\\n\", port, mdb-\u003eaddr,\n+\t\tmdb-\u003evid);\n+\n+\tif (IS_ERR(bridge_dev))\n+\t\treturn PTR_ERR(bridge_dev);\n+\n+\tif (dsa_is_cpu_port(ds, port) \u0026\u0026 !bridge_dev \u0026\u0026\n+\t    dsa_mdb_present_in_other_db(ds, port, mdb, db))\n+\t\treturn 0;\n+\n+\tif (port == lan9645x-\u003enpi)\n+\t\tport = lan9645x-\u003enum_phys_ports;\n+\n+\treturn lan9645x_mdb_port_add(lan9645x, port, mdb, bridge_dev);\n+}\n+\n+static int lan9645x_mdb_del(struct dsa_switch *ds, int port,\n+\t\t\t    const struct switchdev_obj_port_mdb *mdb,\n+\t\t\t    struct dsa_db db)\n+{\n+\tstruct net_device *bridge_dev = lan9645x_db2bridge(db);\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tint err;\n+\n+\tdev_dbg(lan9645x-\u003edev, \"port=%d addr=%pM vid=%u\\n\", port, mdb-\u003eaddr,\n+\t\tmdb-\u003evid);\n+\n+\tif (IS_ERR(bridge_dev))\n+\t\treturn PTR_ERR(bridge_dev);\n+\n+\tif (dsa_is_cpu_port(ds, port) \u0026\u0026 !bridge_dev \u0026\u0026\n+\t    dsa_mdb_present_in_other_db(ds, port, mdb, db))\n+\t\treturn 0;\n+\n+\tif (port == lan9645x-\u003enpi)\n+\t\tport = lan9645x-\u003enum_phys_ports;\n+\n+\terr = lan9645x_mdb_port_del(lan9645x, port, mdb, bridge_dev);\n+\tif (err == -ENOENT) {\n+\t\tdev_dbg(lan9645x-\u003edev,\n+\t\t\t\"mdb not found port=%d addr=%pM vid=%u\\n\", port,\n+\t\t\tmdb-\u003eaddr, mdb-\u003evid);\n+\t\treturn 0;\n+\t}\n+\n+\treturn err;\n+}\n+\n+static void lan9645x_get_strings(struct dsa_switch *ds, int port, u32 stringset,\n+\t\t\t\t uint8_t *data)\n+{\n+\tlan9645x_stats_get_strings(ds-\u003epriv, port, stringset, data);\n+}\n+\n+static void lan9645x_get_ethtool_stats(struct dsa_switch *ds, int port,\n+\t\t\t\t       uint64_t *data)\n+{\n+\tlan9645x_stats_get_ethtool_stats(ds-\u003epriv, port, data);\n+}\n+\n+static int lan9645x_get_sset_count(struct dsa_switch *ds, int port, int sset)\n+{\n+\treturn lan9645x_stats_get_sset_count(ds-\u003epriv, port, sset);\n+}\n+\n+static void lan9645x_get_eth_mac_stats(struct dsa_switch *ds, int port,\n+\t\t\t\t       struct ethtool_eth_mac_stats *mac_stats)\n+{\n+\tlan9645x_stats_get_eth_mac_stats(ds-\u003epriv, port, mac_stats);\n+}\n+\n+static void\n+lan9645x_get_rmon_stats(struct dsa_switch *ds, int port,\n+\t\t\tstruct ethtool_rmon_stats *rmon_stats,\n+\t\t\tconst struct ethtool_rmon_hist_range **ranges)\n+{\n+\tlan9645x_stats_get_rmon_stats(ds-\u003epriv, port, rmon_stats, ranges);\n+}\n+\n+static void lan9645x_get_stats64(struct dsa_switch *ds, int port,\n+\t\t\t\t struct rtnl_link_stats64 *s)\n+{\n+\tlan9645x_stats_get_stats64(ds-\u003epriv, port, s);\n+}\n+\n+static void lan9645x_get_pause_stats(struct dsa_switch *ds, int port,\n+\t\t\t\t     struct ethtool_pause_stats *pause_stats)\n+{\n+\tlan9645x_stats_get_pause_stats(ds-\u003epriv, port, pause_stats);\n+}\n+\n+static void lan9645x_get_mm_stats(struct dsa_switch *ds, int port,\n+\t\t\t\t  struct ethtool_mm_stats *stats)\n+{\n+\tlan9645x_stats_get_mm_stats(ds-\u003epriv, port, stats);\n+}\n+\n+static void lan9645x_get_eth_phy_stats(struct dsa_switch *ds, int port,\n+\t\t\t\t       struct ethtool_eth_phy_stats *phy_stats)\n+{\n+\tlan9645x_stats_get_eth_phy_stats(ds-\u003epriv, port, phy_stats);\n+}\n+\n+static void\n+lan9645x_get_eth_ctrl_stats(struct dsa_switch *ds, int port,\n+\t\t\t    struct ethtool_eth_ctrl_stats *ctrl_stats)\n+{\n+\tlan9645x_stats_get_eth_ctrl_stats(ds-\u003epriv, port, ctrl_stats);\n+}\n+\n+static const struct dsa_switch_ops lan9645x_switch_ops = {\n+\t.get_tag_protocol\t\t= lan9645x_get_tag_protocol,\n+\n+\t.setup\t\t\t\t= lan9645x_setup,\n+\t.teardown\t\t\t= lan9645x_teardown,\n+\t.port_setup\t\t\t= lan9645x_port_setup,\n+\n+\t/* Phylink integration */\n+\t.phylink_get_caps\t\t= lan9645x_port_phylink_get_caps,\n+\n+\t/* MTU  */\n+\t.port_change_mtu\t\t= lan9645x_change_mtu,\n+\t.port_max_mtu\t\t\t= lan9645x_get_max_mtu,\n+\n+\t/* Bridge integration */\n+\t.set_ageing_time\t\t= lan9645x_set_ageing_time,\n+\t.port_pre_bridge_flags\t\t= lan9645x_port_pre_bridge_flags,\n+\t.port_bridge_flags\t\t= lan9645x_port_bridge_flags,\n+\t.port_bridge_join\t\t= lan9645x_port_bridge_join,\n+\t.port_bridge_leave\t\t= lan9645x_port_bridge_leave,\n+\t.port_stp_state_set\t\t= lan9645x_port_bridge_stp_state_set,\n+\t.port_set_host_flood\t\t= lan9645x_port_set_host_flood,\n+\n+\t/* VLAN integration */\n+\t.port_vlan_filtering\t\t= lan9645x_port_vlan_filtering,\n+\t.port_vlan_add\t\t\t= lan9645x_port_vlan_add,\n+\t.port_vlan_del\t\t\t= lan9645x_port_vlan_del,\n+\n+\t/* MAC table integration */\n+\t.port_fast_age\t\t\t= lan9645x_port_fast_age,\n+\t.port_fdb_dump\t\t\t= lan9645x_fdb_dump,\n+\t.port_fdb_add\t\t\t= lan9645x_fdb_add,\n+\t.port_fdb_del\t\t\t= lan9645x_fdb_del,\n+\n+\t/* Multicast database */\n+\t.port_mdb_add\t\t\t= lan9645x_mdb_add,\n+\t.port_mdb_del\t\t\t= lan9645x_mdb_del,\n+\n+\t/* Port statistics counters. */\n+\t.get_strings\t\t\t= lan9645x_get_strings,\n+\t.get_ethtool_stats\t\t= lan9645x_get_ethtool_stats,\n+\t.get_sset_count\t\t\t= lan9645x_get_sset_count,\n+\t.get_eth_mac_stats\t\t= lan9645x_get_eth_mac_stats,\n+\t.get_rmon_stats\t\t\t= lan9645x_get_rmon_stats,\n+\t.get_stats64\t\t\t= lan9645x_get_stats64,\n+\t.get_pause_stats\t\t= lan9645x_get_pause_stats,\n+\t.get_mm_stats\t\t\t= lan9645x_get_mm_stats,\n+\t.get_eth_phy_stats\t\t= lan9645x_get_eth_phy_stats,\n+\t.get_eth_ctrl_stats\t\t= lan9645x_get_eth_ctrl_stats,\n+};\n+\n+static int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)\n+{\n+\tconst char *resource_name;\n+\tstruct regmap *tgt_map;\n+\n+\tfor (int i = 0; i \u003c NUM_TARGETS; i++) {\n+\t\tresource_name = lan9645x_resource_names[i];\n+\t\tif (!resource_name)\n+\t\t\tcontinue;\n+\n+\t\ttgt_map = dev_get_regmap(lan9645x-\u003edev-\u003eparent, resource_name);\n+\t\tif (IS_ERR_OR_NULL(tgt_map)) {\n+\t\t\tdev_err(lan9645x-\u003edev, \"Failed to get regmap=%d\\n\", i);\n+\t\t\treturn -ENODEV;\n+\t\t}\n+\n+\t\tlan9645x-\u003ermap[i] = tgt_map;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_set_feat_dis(struct lan9645x *lan9645x)\n+{\n+\tu32 feat_dis;\n+\n+\t/* The features which can be physically disabled on some SKUs are:\n+\t * 1) Number of ports can be 5, 7 or 9. Any ports can be used, the chip\n+\t *    tracks how many are active.\n+\t * 2) HSR/PRP. The duplicate discard table can be disabled.\n+\t * 3) TAS, frame preemption and PSFP can be disabled.\n+\t */\n+\tfeat_dis = lan_rd(lan9645x, GCB_FEAT_DISABLE);\n+\n+\tlan9645x-\u003enum_port_dis =\n+\t\tGCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_GET(feat_dis);\n+}\n+\n+static int lan9645x_probe(struct platform_device *pdev)\n+{\n+\tstruct device *dev = \u0026pdev-\u003edev;\n+\tstruct lan9645x *lan9645x;\n+\tstruct dsa_switch *ds;\n+\tint err = 0;\n+\n+\tlan9645x = devm_kzalloc(dev, sizeof(*lan9645x), GFP_KERNEL);\n+\tif (!lan9645x)\n+\t\treturn dev_err_probe(dev, -ENOMEM,\n+\t\t\t\t     \"Failed to allocate LAN9645X\");\n+\n+\tdev_set_drvdata(dev, lan9645x);\n+\tlan9645x-\u003edev = dev;\n+\n+\terr = lan9645x_request_target_regmaps(lan9645x);\n+\tif (err)\n+\t\treturn dev_err_probe(dev, err, \"Failed to request regmaps\");\n+\n+\tds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);\n+\tif (!ds)\n+\t\treturn dev_err_probe(dev, -ENOMEM,\n+\t\t\t\t     \"Failed to allocate DSA switch\");\n+\n+\tlan9645x-\u003eports = devm_kcalloc(lan9645x-\u003edev, NUM_PHYS_PORTS,\n+\t\t\t\t       sizeof(struct lan9645x_port *),\n+\t\t\t\t       GFP_KERNEL);\n+\tif (!lan9645x-\u003eports)\n+\t\treturn dev_err_probe(dev, -ENOMEM,\n+\t\t\t\t     \"Failed to allocate switch ports\");\n+\n+\tfor (int port = 0; port \u003c NUM_PHYS_PORTS; port++) {\n+\t\tstruct lan9645x_port *p;\n+\n+\t\tp = devm_kzalloc(lan9645x-\u003edev, sizeof(*p), GFP_KERNEL);\n+\t\tif (!p)\n+\t\t\treturn dev_err_probe(dev, -ENOMEM,\n+\t\t\t\t\t     \"Failed to allocate switch port\");\n+\n+\t\tp-\u003elan9645x = lan9645x;\n+\t\tp-\u003echip_port = port;\n+\t\tINIT_WORK(\u0026p-\u003ehost_flood_work, lan9645x_host_flood_work_fn);\n+\t\tlan9645x-\u003eports[port] = p;\n+\t}\n+\n+\tds-\u003edev = dev;\n+\tds-\u003enum_ports = NUM_PHYS_PORTS;\n+\tds-\u003enum_tx_queues = NUM_PRIO_QUEUES;\n+\tds-\u003edscp_prio_mapping_is_global = true;\n+\n+\tds-\u003eops = \u0026lan9645x_switch_ops;\n+\tds-\u003ephylink_mac_ops = \u0026lan9645x_phylink_mac_ops;\n+\tds-\u003epriv = lan9645x;\n+\n+\tlan9645x-\u003eds = ds;\n+\tlan9645x-\u003eshared_queue_sz = LAN9645X_BUFFER_MEMORY;\n+\tlan9645x-\u003enpi = -1;\n+\n+\tlan9645x_set_feat_dis(lan9645x);\n+\n+\terr = lan9645x_stats_alloc(lan9645x);\n+\tif (err)\n+\t\treturn dev_err_probe(dev, err, \"Failed to allocate stats\");\n+\n+\terr = dsa_register_switch(ds);\n+\tif (err) {\n+\t\tlan9645x_stats_free(lan9645x);\n+\t\treturn dev_err_probe(dev, err, \"Failed to register DSA switch\");\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_remove(struct platform_device *pdev)\n+{\n+\tstruct lan9645x *lan9645x = dev_get_drvdata(\u0026pdev-\u003edev);\n+\n+\tif (!lan9645x)\n+\t\treturn;\n+\n+\t/* Calls lan9645x DSA .teardown */\n+\tdsa_unregister_switch(lan9645x-\u003eds);\n+\tlan9645x_stats_free(lan9645x);\n+\tdev_set_drvdata(\u0026pdev-\u003edev, NULL);\n+}\n+\n+static void lan9645x_shutdown(struct platform_device *pdev)\n+{\n+\tstruct lan9645x *lan9645x = dev_get_drvdata(\u0026pdev-\u003edev);\n+\n+\tif (!lan9645x)\n+\t\treturn;\n+\n+\tdsa_switch_shutdown(lan9645x-\u003eds);\n+\n+\tdev_set_drvdata(\u0026pdev-\u003edev, NULL);\n+}\n+\n+static const struct of_device_id lan9645x_switch_of_match[] = {\n+\t{ .compatible = \"microchip,lan96455s-switch\" },\n+\t{},\n+};\n+MODULE_DEVICE_TABLE(of, lan9645x_switch_of_match);\n+\n+static struct platform_driver lan9645x_switch_driver = {\n+\t.driver = {\n+\t\t.name = \"lan96455s-switch\",\n+\t\t.of_match_table = lan9645x_switch_of_match,\n+\t},\n+\t.probe = lan9645x_probe,\n+\t.remove = lan9645x_remove,\n+\t.shutdown = lan9645x_shutdown,\n+};\n+module_platform_driver(lan9645x_switch_driver);\n+\n+MODULE_DESCRIPTION(\"Lan9645x Switch Driver\");\n+MODULE_AUTHOR(\"Jens Emil Schulz Østergaard \u003cjensemil.schulzostergaard@microchip.com\u003e\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h\nnew file mode 100644\nindex 00000000000000..7c6cad0da4f135\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h\n@@ -0,0 +1,441 @@\n+/* SPDX-License-Identifier: GPL-2.0+ */\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#ifndef __LAN9645X_MAIN_H__\n+#define __LAN9645X_MAIN_H__\n+\n+#include \u003clinux/dsa/lan9645x.h\u003e\n+#include \u003clinux/if_bridge.h\u003e\n+#include \u003clinux/if_vlan.h\u003e\n+#include \u003clinux/regmap.h\u003e\n+#include \u003cnet/dsa.h\u003e\n+\n+#include \"lan9645x_regs.h\"\n+\n+/* Port modules 0-8 are front (user) ports. The chip additionally has two\n+ * logical CPU port modules at indices 9 and 10. These are not the DSA CPU port.\n+ * The CPU port modules are logical ports in the chip intended for management.\n+ *\n+ * The frame delivery mechanism can vary: direct register injection/extraction,\n+ * or a front port can be used as the management port, called a Node Processor\n+ * Interface (NPI) in the datasheet.\n+ *\n+ * LAN9645X uses the NPI approach, so the DSA CPU port is a front port\n+ * (see lan9645x-\u003enpi) configured as NPI port.\n+ *\n+ * Therefore the CPU datapath has two port module indices of interest,\n+ * lan9645x-\u003enpi and the cpu port module at index 9.\n+ */\n+#define NUM_PHYS_PORTS\t\t9\n+#define NUM_PRIO_QUEUES\t\t8\n+#define LAN9645X_NUM_TC\t\t8\n+\n+#define QS_SRC_BUF_RSV\t\t1700\n+\n+/* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO\n+ * See QSYS:RES_CTRL[*]:RES_CFG description\n+ */\n+#define QSYS_Q_RSRV\t\t\t95\n+\n+#define LAN9645X_ISDX_MAX\t\t128\n+#define LAN9645X_ESDX_MAX\t\t128\n+#define LAN9645X_SFID_MAX\t\t128\n+\n+/* Reserved VLAN IDs. */\n+#define UNAWARE_PVID\t\t\t0\n+#define HOST_PVID\t\t\t4095\n+#define VLAN_MAX\t\t\t(HOST_PVID - 1)\n+\n+/* 160KiB / 1.25Mbit */\n+#define LAN9645X_BUFFER_MEMORY\t(160 * 1024)\n+\n+/* Port Group Identifiers (PGID) are port-masks applied to all frames.\n+ * The replicated registers are organized like so in HW:\n+ *\n+ * 0-63:         Destination analysis\n+ * 64-79:        Aggregation analysis\n+ * 80-(80+10-1): Source port analysis\n+ *\n+ * Destination: By default the first 9 port masks == BIT(port_num). Never change\n+ * these except for aggregation. Remaining dst masks are for L2 MC and\n+ * flooding. (See FLOODING and FLOODING_IPMC).\n+ *\n+ * Aggregation: Used to pick a port within an aggregation group. If no\n+ * aggregation is configured, these are all-ones.\n+ *\n+ * Source: Control which ports a given source port can forward to. A frame that\n+ * is received on port n, uses mask 80+n as a mask to filter out destination\n+ * ports. The default values are that all bits are set except for the index\n+ * number (no loopback).\n+ *\n+ * We reserve destination PGIDs at the end of the range.\n+ */\n+\n+#define PGID_AGGR\t\t\t64\n+#define PGID_SRC\t\t\t80\n+#define PGID_ENTRIES\t\t\t89\n+\n+#define PGID_AGGR_NUM\t\t\t(PGID_SRC - PGID_AGGR)\n+\n+/* General purpose PGIDs. */\n+#define PGID_GP_START\t\t\tNUM_PHYS_PORTS\n+#define PGID_GP_END\t\t\tPGID_MRP\n+\n+/* Reserved PGIDs.\n+ * PGID_MRP is a blackhole PGID\n+ */\n+#define PGID_MRP\t\t\t(PGID_AGGR - 7)\n+#define PGID_CPU\t\t\t(PGID_AGGR - 6)\n+#define PGID_UC\t\t\t\t(PGID_AGGR - 5)\n+#define PGID_BC\t\t\t\t(PGID_AGGR - 4)\n+#define PGID_MC\t\t\t\t(PGID_AGGR - 3)\n+#define PGID_MCIPV4\t\t\t(PGID_AGGR - 2)\n+#define PGID_MCIPV6\t\t\t(PGID_AGGR - 1)\n+\n+/* Flooding PGIDS:\n+ * PGID_UC\n+ * PGID_MC*\n+ * PGID_BC\n+ */\n+\n+#define GWM_MULTIPLIER_BIT\t\tBIT(8)\n+#define LAN9645X_BUFFER_CELL_SZ\t\t64\n+\n+#define RD_SLEEP_US\t\t\t3\n+#define RD_SLEEPTIMEOUT_US\t\t100000\n+#define SLOW_RD_SLEEP_US\t\t1000\n+#define SLOW_RD_SLEEPTIMEOUT_US\t\t4000000\n+\n+#define lan9645x_rd_poll_timeout(_lan9645x, _reg_macro, _val, _cond)     \\\n+\tregmap_read_poll_timeout(lan_rmap((_lan9645x), _reg_macro),\t\\\n+\t\t\t\t lan_rel_addr(_reg_macro), (_val),\t\\\n+\t\t\t\t (_cond), RD_SLEEP_US, RD_SLEEPTIMEOUT_US)\n+\n+#define lan9645x_rd_poll_slow(_lan9645x, _reg_macro, _val, _cond)\t\\\n+\tregmap_read_poll_timeout(lan_rmap((_lan9645x), _reg_macro),\t\\\n+\t\t\t\t lan_rel_addr(_reg_macro), (_val),\t\\\n+\t\t\t\t (_cond), SLOW_RD_SLEEP_US,\t\t\\\n+\t\t\t\t SLOW_RD_SLEEPTIMEOUT_US)\n+\n+#define LAN9645X_HOST_FLOOD_UC\t\tBIT(0)\n+#define LAN9645X_HOST_FLOOD_MC\t\tBIT(1)\n+\n+/* NPI port prefix config encoding\n+ *\n+ * 0: No CPU extraction header (normal frames)\n+ * 1: CPU extraction header without prefix\n+ * 2: CPU extraction header with short prefix\n+ * 3: CPU extraction header with long prefix\n+ */\n+enum lan9645x_tag_prefix {\n+\tLAN9645X_TAG_PREFIX_DISABLED = 0,\n+\tLAN9645X_TAG_PREFIX_NONE = 1,\n+\tLAN9645X_TAG_PREFIX_SHORT = 2,\n+\tLAN9645X_TAG_PREFIX_LONG = 3,\n+};\n+\n+enum {\n+\tLAN9645X_SPEED_DISABLED = 0,\n+\tLAN9645X_SPEED_10 = 1,\n+\tLAN9645X_SPEED_100 = 2,\n+\tLAN9645X_SPEED_1000 = 3,\n+\tLAN9645X_SPEED_2500 = 4,\n+};\n+\n+/* Rewriter VLAN port tagging encoding for REW:PORT[0-10]:TAG_CFG.TAG_CFG\n+ *\n+ * 0: Port tagging disabled.\n+ * 1: Tag all frames, except when VID=PORT_VLAN_CFG.PORT_VID or VID=0.\n+ * 2: Tag all frames, except when VID=0.\n+ * 3: Tag all frames.\n+ */\n+enum lan9645x_vlan_port_tag {\n+\tLAN9645X_TAG_DISABLED = 0,\n+\tLAN9645X_TAG_NO_PVID_NO_UNAWARE = 1,\n+\tLAN9645X_TAG_NO_UNAWARE = 2,\n+\tLAN9645X_TAG_ALL = 3,\n+};\n+\n+struct lan9645x_vlan {\n+\tu32 portmask: 10, /* ports 0-8 + CPU port module */\n+\t    untagged: 9, /* ports 0-8 */\n+\t    src_chk: 1,\n+\t    mir: 1,\n+\t    lrn_dis: 1,\n+\t    prv_vlan: 1,\n+\t    fld_dis: 1,\n+\t    s_fwd_ena: 1;\n+};\n+\n+/* MAC table entry types.\n+ * ENTRYTYPE_NORMAL is subject to aging.\n+ * ENTRYTYPE_LOCKED is not subject to aging.\n+ * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.\n+ * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.\n+ */\n+enum macaccess_entry_type {\n+\tENTRYTYPE_NORMAL = 0,\n+\tENTRYTYPE_LOCKED,\n+\tENTRYTYPE_MACV4,\n+\tENTRYTYPE_MACV6,\n+};\n+\n+struct lan9645x {\n+\tstruct device *dev;\n+\tstruct dsa_switch *ds;\n+\tstruct regmap *rmap[NUM_TARGETS];\n+\n+\tu16 host_flood_uc_mask;\n+\tu16 host_flood_mc_mask;\n+\n+\tstruct workqueue_struct *owq;\n+\n+\tint shared_queue_sz;\n+\n+\t/* NPI chip_port */\n+\tint npi;\n+\n+\tu8 num_phys_ports;\n+\tstruct lan9645x_port **ports;\n+\n+\tstruct mutex port_mux_lock; /* serialize port muxing */\n+\n+\t/* Forwarding Database */\n+\tstruct net_device *bridge; /* Only support single bridge */\n+\tu16 bridge_mask; /* Mask for bridged ports */\n+\tu16 bridge_fwd_mask; /* Mask for forwarding bridged ports */\n+\tstruct mutex fwd_domain_lock; /* lock forwarding configuration */\n+\tstruct mutex mact_lock; /* serialize mac table register access */\n+\n+\t/* VLAN entries */\n+\tstruct lan9645x_vlan vlans[VLAN_N_VID];\n+\n+\t/* Multicast Forwarding Database */\n+\tstruct list_head mdb_entries;\n+\tstruct list_head pgid_entries;\n+\t/* lock for mdb_entries and pgid_entries. Must be taken before mact_lock\n+\t * if both are taken.\n+\t */\n+\tstruct mutex mdb_lock;\n+\n+\t/* Statistics  */\n+\tstruct lan9645x_stats *stats;\n+\n+\tint num_port_dis;\n+};\n+\n+struct lan9645x_port {\n+\tstruct lan9645x *lan9645x;\n+\n+\tu8 chip_port;\n+\tu8 stp_state;\n+\tbool learn_ena;\n+\n+\tbool vlan_aware;\n+\tu16 pvid;\n+\n+\tbool rx_internal_delay;\n+\tbool tx_internal_delay;\n+\n+\tstruct work_struct host_flood_work;\n+\t/* Packed host flood request deposited by port_set_host_flood (atomic\n+\t * context) and consumed by host_flood_work_fn.\n+\t */\n+\tu8 host_flood_req;\n+};\n+\n+extern const struct phylink_mac_ops lan9645x_phylink_mac_ops;\n+\n+/* PFC_CFG.FC_LINK_SPEED encoding */\n+static inline int lan9645x_speed_fc_enc(int speed)\n+{\n+\tswitch (speed) {\n+\tcase LAN9645X_SPEED_10:\n+\t\treturn 3;\n+\tcase LAN9645X_SPEED_100:\n+\t\treturn 2;\n+\tcase LAN9645X_SPEED_1000:\n+\t\treturn 1;\n+\tcase LAN9645X_SPEED_2500:\n+\t\treturn 0;\n+\tdefault:\n+\t\tWARN_ON_ONCE(1);\n+\t\treturn 1;\n+\t}\n+}\n+\n+/* Watermark encode. See QSYS:RES_CTRL[*]:RES_CFG.WM_HIGH for details.\n+ * Returns lowest encoded number which will fit request/ is larger than request.\n+ * Or the maximum representable value, if request is too large.\n+ */\n+static inline u32 lan9645x_wm_enc(u32 value)\n+{\n+\tvalue = DIV_ROUND_UP(value, LAN9645X_BUFFER_CELL_SZ);\n+\n+\tif (value \u003e= GWM_MULTIPLIER_BIT) {\n+\t\tvalue = DIV_ROUND_UP(value, 16);\n+\t\tif (value \u003e= GWM_MULTIPLIER_BIT)\n+\t\t\tvalue = (GWM_MULTIPLIER_BIT - 1);\n+\t\tvalue |= GWM_MULTIPLIER_BIT;\n+\t}\n+\n+\treturn value;\n+}\n+\n+static inline struct lan9645x_port *lan9645x_to_port(struct lan9645x *lan9645x,\n+\t\t\t\t\t\t     int port)\n+{\n+\treturn lan9645x-\u003eports[port];\n+}\n+\n+static inline bool lan9645x_port_is_bridged(struct lan9645x_port *p)\n+{\n+\treturn p \u0026\u0026 (p-\u003elan9645x-\u003ebridge_mask \u0026 BIT(p-\u003echip_port));\n+}\n+\n+static inline struct regmap *lan_tgt2rmap(struct lan9645x *lan9645x,\n+\t\t\t\t\t  enum lan9645x_target t, int tinst)\n+{\n+\treturn lan9645x-\u003ermap[t + tinst];\n+}\n+\n+static inline u32 __lan_rel_addr(int gbase, int ginst, int gcnt,\n+\t\t\t\t int gwidth, int raddr, int rinst,\n+\t\t\t\t int rcnt, int rwidth)\n+{\n+\tWARN_ON(ginst \u003e= gcnt);\n+\tWARN_ON(rinst \u003e= rcnt);\n+\treturn gbase + ginst * gwidth + raddr + rinst * rwidth;\n+}\n+\n+/* Get register address relative to target instance */\n+static inline u32 lan_rel_addr(enum lan9645x_target t, int tinst, int tcnt,\n+\t\t\t       int gbase, int ginst, int gcnt, int gwidth,\n+\t\t\t       int raddr, int rinst, int rcnt, int rwidth)\n+{\n+\tWARN_ON(tinst \u003e= tcnt);\n+\treturn __lan_rel_addr(gbase, ginst, gcnt, gwidth, raddr, rinst,\n+\t\t\t      rcnt, rwidth);\n+}\n+\n+static inline u32 lan_rd(struct lan9645x *lan9645x, enum lan9645x_target t,\n+\t\t\t int tinst, int tcnt, int gbase, int ginst,\n+\t\t\t int gcnt, int gwidth, int raddr, int rinst,\n+\t\t\t int rcnt, int rwidth)\n+{\n+\tu32 addr, val = 0;\n+\n+\taddr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,\n+\t\t\t    raddr, rinst, rcnt, rwidth);\n+\n+\tWARN_ON_ONCE(regmap_read(lan_tgt2rmap(lan9645x, t, tinst), addr, \u0026val));\n+\n+\treturn val;\n+}\n+\n+static inline int lan_bulk_rd(void *val, size_t val_count,\n+\t\t\t      struct lan9645x *lan9645x,\n+\t\t\t      enum lan9645x_target t, int tinst, int tcnt,\n+\t\t\t      int gbase, int ginst, int gcnt, int gwidth,\n+\t\t\t      int raddr, int rinst, int rcnt, int rwidth)\n+{\n+\tu32 addr;\n+\n+\taddr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,\n+\t\t\t    raddr, rinst, rcnt, rwidth);\n+\n+\treturn regmap_bulk_read(lan_tgt2rmap(lan9645x, t, tinst), addr, val,\n+\t\t\t\tval_count);\n+}\n+\n+static inline struct regmap *lan_rmap(struct lan9645x *lan9645x,\n+\t\t\t\t      enum lan9645x_target t, int tinst,\n+\t\t\t\t      int tcnt, int gbase, int ginst,\n+\t\t\t\t      int gcnt, int gwidth, int raddr,\n+\t\t\t\t      int rinst, int rcnt, int rwidth)\n+{\n+\treturn lan_tgt2rmap(lan9645x, t, tinst);\n+}\n+\n+static inline void lan_wr(u32 val, struct lan9645x *lan9645x,\n+\t\t\t  enum lan9645x_target t, int tinst, int tcnt,\n+\t\t\t  int gbase, int ginst, int gcnt, int gwidth,\n+\t\t\t  int raddr, int rinst, int rcnt, int rwidth)\n+{\n+\tu32 addr;\n+\n+\taddr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,\n+\t\t\t    raddr, rinst, rcnt, rwidth);\n+\n+\tWARN_ON_ONCE(regmap_write(lan_tgt2rmap(lan9645x, t, tinst), addr, val));\n+}\n+\n+static inline void lan_rmw(u32 val, u32 mask, struct lan9645x *lan9645x,\n+\t\t\t   enum lan9645x_target t, int tinst, int tcnt,\n+\t\t\t   int gbase, int ginst, int gcnt, int gwidth,\n+\t\t\t   int raddr, int rinst, int rcnt, int rwidth)\n+{\n+\tu32 addr;\n+\n+\taddr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,\n+\t\t\t    raddr, rinst, rcnt, rwidth);\n+\n+\tWARN_ON_ONCE(regmap_update_bits(lan_tgt2rmap(lan9645x, t, tinst),\n+\t\t\t\t\taddr, mask, val));\n+}\n+\n+/* lan9645x_npi.c */\n+void lan9645x_npi_port_init(struct lan9645x *lan9645x,\n+\t\t\t    struct dsa_port *cpu_port);\n+void lan9645x_npi_port_deinit(struct lan9645x *lan9645x, int port);\n+\n+/* lan9645x_port.c */\n+int lan9645x_port_setup(struct dsa_switch *ds, int port);\n+void lan9645x_port_set_tail_drop_wm(struct lan9645x *lan9645x);\n+int lan9645x_port_set_maxlen(struct lan9645x *lan9645x, int port, size_t sdu);\n+void lan9645x_port_cpu_init(struct lan9645x *lan9645x);\n+\n+/* lan9645x_phylink.c */\n+void lan9645x_phylink_get_caps(struct lan9645x *lan9645x, int port,\n+\t\t\t       struct phylink_config *c);\n+void lan9645x_phylink_port_down(struct lan9645x *lan9645x, int port);\n+\n+/* VLAN lan9645x_vlan.c */\n+int lan9645x_vlan_init(struct lan9645x *lan9645x);\n+u16 lan9645x_vlan_unaware_pvid(bool is_bridged);\n+void lan9645x_vlan_port_apply(struct lan9645x_port *p);\n+int lan9645x_vlan_port_add_vlan(struct lan9645x_port *p, u16 vid, bool pvid,\n+\t\t\t\tbool untagged,\n+\t\t\t\tstruct netlink_ext_ack *extack);\n+int lan9645x_vlan_port_del_vlan(struct lan9645x_port *p, u16 vid);\n+void lan9645x_vlan_set_hostmode(struct lan9645x_port *p);\n+void lan9645x_vlan_clear_hostmode(struct lan9645x_port *p);\n+\n+/* MAC table: lan9645x_mac.c */\n+int lan9645x_mact_flush(struct lan9645x *lan9645x, int port);\n+int lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\n+\t\t\tconst unsigned char *addr, u16 vid,\n+\t\t\tenum macaccess_entry_type type);\n+int lan9645x_mact_forget(struct lan9645x *lan9645x,\n+\t\t\t const unsigned char mac[ETH_ALEN], unsigned int vid,\n+\t\t\t enum macaccess_entry_type type);\n+int lan9645x_mac_init(struct lan9645x *lan9645x);\n+void lan9645x_mac_deinit(struct lan9645x *lan9645x);\n+int lan9645x_mact_dsa_dump(struct lan9645x *lan9645x, int port,\n+\t\t\t   dsa_fdb_dump_cb_t *cb, void *data);\n+int lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\n+\t\t\t\t const unsigned char *addr, u16 vid,\n+\t\t\t\t enum macaccess_entry_type type, bool cpu_copy);\n+\n+/* Multicast Database lan9645x_mdb.c */\n+int lan9645x_mdb_port_add(struct lan9645x *lan9645x, int port,\n+\t\t\t  const struct switchdev_obj_port_mdb *mdb,\n+\t\t\t  struct net_device *bridge);\n+int lan9645x_mdb_port_del(struct lan9645x *lan9645x, int port,\n+\t\t\t  const struct switchdev_obj_port_mdb *mdb,\n+\t\t\t  struct net_device *bridge);\n+void lan9645x_mdb_init(struct lan9645x *lan9645x);\n+void lan9645x_mdb_deinit(struct lan9645x *lan9645x);\n+\n+#endif /* __LAN9645X_MAIN_H__ */\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_mdb.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_mdb.c\nnew file mode 100644\nindex 00000000000000..ea37bb660273cd\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_mdb.c\n@@ -0,0 +1,398 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \"lan9645x_main.h\"\n+\n+/* HW ignores dest_idx for IPv4/IPv6 types, so we use this dummy index */\n+#define IP_ENTRY_PGID\t\t0\n+#define PGID_INDEX(pgid)\t((pgid) ? (pgid)-\u003eindex : IP_ENTRY_PGID)\n+\n+struct lan9645x_pgid_entry {\n+\tstruct list_head list;\n+\tint index;\n+\trefcount_t refcount;\n+\tu16 ports;\n+};\n+\n+struct lan9645x_mdb_entry {\n+\tstruct list_head list;\n+\tunsigned char mac[ETH_ALEN];\n+\tu16 vid;\n+\tu16 ports;\n+\tstruct lan9645x_pgid_entry *pgid;\n+};\n+\n+void lan9645x_mdb_init(struct lan9645x *lan9645x)\n+{\n+\tINIT_LIST_HEAD(\u0026lan9645x-\u003emdb_entries);\n+\tINIT_LIST_HEAD(\u0026lan9645x-\u003epgid_entries);\n+\tmutex_init(\u0026lan9645x-\u003emdb_lock);\n+\n+\t/* Use CPU queues to communicate frame classification to the CPU */\n+\tlan_rmw(ANA_CPUQ_CFG_CPUQ_IGMP_SET(LAN9645X_CPUQ_TRAP) |\n+\t\tANA_CPUQ_CFG_CPUQ_MLD_SET(LAN9645X_CPUQ_TRAP) |\n+\t\tANA_CPUQ_CFG_CPUQ_IPMC_CTRL_SET(LAN9645X_CPUQ_COPY),\n+\t\tANA_CPUQ_CFG_CPUQ_IGMP |\n+\t\tANA_CPUQ_CFG_CPUQ_MLD |\n+\t\tANA_CPUQ_CFG_CPUQ_IPMC_CTRL,\n+\t\tlan9645x, ANA_CPUQ_CFG);\n+}\n+\n+static enum macaccess_entry_type lan9645x_mdb_classify(const unsigned char *mac)\n+{\n+\tif (ether_addr_is_ipv4_mcast(mac))\n+\t\treturn ENTRYTYPE_MACV4;\n+\tif (ether_addr_is_ipv6_mcast(mac))\n+\t\treturn ENTRYTYPE_MACV6;\n+\treturn ENTRYTYPE_LOCKED;\n+}\n+\n+static struct lan9645x_mdb_entry *\n+lan9645x_mdb_entry_lookup(struct lan9645x *lan9645x, const unsigned char *mac,\n+\t\t\t  u16 vid)\n+{\n+\tstruct lan9645x_mdb_entry *mdb;\n+\n+\tlist_for_each_entry(mdb, \u0026lan9645x-\u003emdb_entries, list) {\n+\t\tif (ether_addr_equal(mdb-\u003emac, mac) \u0026\u0026 mdb-\u003evid == vid)\n+\t\t\treturn mdb;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static struct lan9645x_mdb_entry *\n+lan9645x_mdb_entry_alloc(struct lan9645x *lan9645x,\n+\t\t\t const unsigned char addr[ETH_ALEN], u16 vid)\n+{\n+\tstruct lan9645x_mdb_entry *mdb_entry;\n+\n+\tmdb_entry = kzalloc_obj(*mdb_entry);\n+\tif (!mdb_entry)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tether_addr_copy(mdb_entry-\u003emac, addr);\n+\tmdb_entry-\u003evid = vid;\n+\n+\tlist_add_tail(\u0026mdb_entry-\u003elist, \u0026lan9645x-\u003emdb_entries);\n+\n+\tdev_dbg(lan9645x-\u003edev, \"vid=%u addr=%pM\\n\", mdb_entry-\u003evid,\n+\t\tmdb_entry-\u003emac);\n+\n+\treturn mdb_entry;\n+}\n+\n+static void lan9645x_mdb_encode_mac(unsigned char *dst, unsigned char *mac,\n+\t\t\t\t    u16 ports, enum macaccess_entry_type type)\n+{\n+\tether_addr_copy(dst, mac);\n+\n+\t/* The HW encodes the portmask in the high bits of the mac for ip\n+\t * multicast entries, to save on the limited PGID resources.\n+\t *\n+\t * IPv4 Multicast DMAC: 0x01005Exxxxxx\n+\t * IPv6 Multicast DMAC: 0x3333xxxxxxxx\n+\t *\n+\t * which gives us 24 or 16 bits to encode the portmask.\n+\t */\n+\tif (type == ENTRYTYPE_MACV4) {\n+\t\tdst[0] = 0;\n+\t\tdst[1] = ports \u003e\u003e 8;\n+\t\tdst[2] = ports \u0026 0xff;\n+\t} else if (type == ENTRYTYPE_MACV6) {\n+\t\tdst[0] = ports \u003e\u003e 8;\n+\t\tdst[1] = ports \u0026 0xff;\n+\t}\n+}\n+\n+static void lan9645x_pgid_entry_put(struct lan9645x *lan9645x,\n+\t\t\t\t    struct lan9645x_pgid_entry *pgid_entry)\n+{\n+\tif (!pgid_entry)\n+\t\treturn;\n+\n+\tif (!refcount_dec_and_test(\u0026pgid_entry-\u003erefcount))\n+\t\treturn;\n+\n+\tdev_dbg(lan9645x-\u003edev, \"pgid=%d ports=0x%x\", pgid_entry-\u003eindex,\n+\t\tpgid_entry-\u003eports);\n+\t/* We leave the PGID written in HW, as no entry is pointing to it. */\n+\tlist_del(\u0026pgid_entry-\u003elist);\n+\tkfree(pgid_entry);\n+}\n+\n+static void lan9645x_mdb_entry_dealloc(struct lan9645x *lan9645x,\n+\t\t\t\t       struct lan9645x_mdb_entry *mdb_entry)\n+{\n+\tdev_dbg(lan9645x-\u003edev, \"vid=%u addr=%pM\\n\", mdb_entry-\u003evid,\n+\t\tmdb_entry-\u003emac);\n+\tlist_del(\u0026mdb_entry-\u003elist);\n+\tlan9645x_pgid_entry_put(lan9645x, mdb_entry-\u003epgid);\n+\tkfree(mdb_entry);\n+}\n+\n+static struct lan9645x_pgid_entry *\n+lan9645x_mdb_pgid_entry_lookup(struct lan9645x *lan9645x, u16 ports)\n+{\n+\tstruct lan9645x_pgid_entry *pgid_entry;\n+\n+\tlist_for_each_entry(pgid_entry, \u0026lan9645x-\u003epgid_entries, list) {\n+\t\tif (pgid_entry-\u003eports == ports \u0026\u0026\n+\t\t    refcount_inc_not_zero(\u0026pgid_entry-\u003erefcount))\n+\t\t\treturn pgid_entry;\n+\t}\n+\n+\treturn NULL;\n+}\n+\n+static struct lan9645x_pgid_entry *\n+lan9645x_pgid_entry_alloc(struct lan9645x *lan9645x, int index, u16 ports)\n+{\n+\tstruct lan9645x_pgid_entry *pgid_entry;\n+\n+\tpgid_entry = kzalloc_obj(*pgid_entry);\n+\tif (!pgid_entry)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tpgid_entry-\u003eports = ports;\n+\tpgid_entry-\u003eindex = index;\n+\trefcount_set(\u0026pgid_entry-\u003erefcount, 1);\n+\n+\tlist_add_tail(\u0026pgid_entry-\u003elist, \u0026lan9645x-\u003epgid_entries);\n+\n+\tdev_dbg(lan9645x-\u003edev, \"index=%d ports=0x%x\", pgid_entry-\u003eindex,\n+\t\tpgid_entry-\u003eports);\n+\n+\tlan_rmw(ANA_PGID_PGID_SET(pgid_entry-\u003eports),\n+\t\tANA_PGID_PGID, lan9645x,\n+\t\tANA_PGID(pgid_entry-\u003eindex));\n+\n+\treturn pgid_entry;\n+}\n+\n+static struct lan9645x_pgid_entry *\n+lan9645x_mdb_pgid_entry_create(struct lan9645x *lan9645x, u16 ports)\n+{\n+\tstruct lan9645x_pgid_entry *pgid_entry = NULL;\n+\tint index;\n+\n+\tfor (index = PGID_GP_START; index \u003c PGID_GP_END; index++) {\n+\t\tbool used = false;\n+\n+\t\tlist_for_each_entry(pgid_entry, \u0026lan9645x-\u003epgid_entries, list) {\n+\t\t\tif (pgid_entry-\u003eindex == index) {\n+\t\t\t\tused = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\n+\t\tif (!used)\n+\t\t\treturn lan9645x_pgid_entry_alloc(lan9645x, index,\n+\t\t\t\t\t\t\t ports);\n+\t}\n+\n+\treturn ERR_PTR(-ENOSPC);\n+}\n+\n+static struct lan9645x_pgid_entry *\n+lan9645x_mdb_pgid_entry_get(struct lan9645x *lan9645x, u16 ports,\n+\t\t\t    enum macaccess_entry_type type)\n+{\n+\tstruct lan9645x_pgid_entry *pgid_entry;\n+\tu16 pgid_ports;\n+\n+\tif (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6 || !ports)\n+\t\treturn NULL;\n+\n+\t/* CPU port module forwarding is handled by cpu_copy flag on mac table\n+\t * entry. So we can strip the CPU port module here to allow better PGID\n+\t * sharing.\n+\t */\n+\tpgid_ports = ports \u0026 ~BIT(lan9645x-\u003enum_phys_ports);\n+\n+\tpgid_entry = lan9645x_mdb_pgid_entry_lookup(lan9645x, pgid_ports);\n+\tif (!pgid_entry)\n+\t\treturn lan9645x_mdb_pgid_entry_create(lan9645x, pgid_ports);\n+\n+\treturn pgid_entry;\n+}\n+\n+static int lan9645x_mdb_update_dest(struct lan9645x *lan9645x,\n+\t\t\t\t    struct lan9645x_mdb_entry *mdb_entry,\n+\t\t\t\t    enum macaccess_entry_type type,\n+\t\t\t\t    struct lan9645x_pgid_entry *new_pgid,\n+\t\t\t\t    u16 new_ports)\n+{\n+\tunsigned char mac[ETH_ALEN] __aligned(2);\n+\tstruct lan9645x_pgid_entry *old_pgid;\n+\tint err, pgid_index;\n+\tbool cpu_copy;\n+\n+\told_pgid = mdb_entry-\u003epgid;\n+\tlan9645x_mdb_encode_mac(mac, mdb_entry-\u003emac, new_ports, type);\n+\tcpu_copy = !!(new_ports \u0026 BIT(lan9645x-\u003enum_phys_ports));\n+\tpgid_index = PGID_INDEX(new_pgid);\n+\n+\t/* For IP multicast, the hardware lookup uses the DMAC\n+\t * (01:00:5E:.. / 33:33:..) as the (mac, vid) key, not the encoded mac.\n+\t * Therefore, this CMD_LEARN will atomically rewrite the existing\n+\t * hardware entry. We intentionally do not do a forget before learn\n+\t * sequence, as that would not be atomic, and leave a forwarding gap.\n+\t */\n+\terr = lan9645x_mact_learn_cpu_copy(lan9645x, pgid_index, mac,\n+\t\t\t\t\t   mdb_entry-\u003evid, type, cpu_copy);\n+\tif (err) {\n+\t\tlan9645x_pgid_entry_put(lan9645x, new_pgid);\n+\t\treturn err;\n+\t}\n+\tmdb_entry-\u003epgid = new_pgid;\n+\tmdb_entry-\u003eports = new_ports;\n+\tlan9645x_pgid_entry_put(lan9645x, old_pgid);\n+\treturn 0;\n+}\n+\n+static int __lan9645x_mdb_add(struct lan9645x *lan9645x, int chip_port,\n+\t\t\t      const unsigned char addr[ETH_ALEN], u16 vid,\n+\t\t\t      enum macaccess_entry_type type)\n+{\n+\tstruct lan9645x_pgid_entry *new_pgid;\n+\tstruct lan9645x_mdb_entry *mdb_entry;\n+\tu16 new_ports;\n+\tint err;\n+\n+\tmdb_entry = lan9645x_mdb_entry_lookup(lan9645x, addr, vid);\n+\tif (!mdb_entry) {\n+\t\tmdb_entry = lan9645x_mdb_entry_alloc(lan9645x, addr, vid);\n+\t\tif (IS_ERR(mdb_entry))\n+\t\t\treturn PTR_ERR(mdb_entry);\n+\t}\n+\n+\tif (mdb_entry-\u003eports \u0026 BIT(chip_port))\n+\t\treturn 0;\n+\n+\tnew_ports = mdb_entry-\u003eports | BIT(chip_port);\n+\n+\t/* Update PGID ptr for non-IP entries (L2 multicast) */\n+\tnew_pgid = lan9645x_mdb_pgid_entry_get(lan9645x, new_ports, type);\n+\tif (IS_ERR(new_pgid)) {\n+\t\t/* Out of PGIDs or mem. Continue forwarding to old port\n+\t\t * group, or remove if fresh mdb_entry.\n+\t\t */\n+\t\tif (!mdb_entry-\u003eports)\n+\t\t\tlan9645x_mdb_entry_dealloc(lan9645x, mdb_entry);\n+\n+\t\treturn PTR_ERR(new_pgid);\n+\t}\n+\n+\terr = lan9645x_mdb_update_dest(lan9645x, mdb_entry, type, new_pgid,\n+\t\t\t\t       new_ports);\n+\tif (err \u0026\u0026 !mdb_entry-\u003eports)\n+\t\tlan9645x_mdb_entry_dealloc(lan9645x, mdb_entry);\n+\n+\treturn err;\n+}\n+\n+static int __lan9645x_mdb_del(struct lan9645x *lan9645x, int chip_port,\n+\t\t\t      const unsigned char addr[ETH_ALEN], u16 vid,\n+\t\t\t      enum macaccess_entry_type type)\n+{\n+\tstruct lan9645x_pgid_entry *new_pgid;\n+\tstruct lan9645x_mdb_entry *mdb_entry;\n+\tu16 new_ports;\n+\tint err;\n+\n+\tmdb_entry = lan9645x_mdb_entry_lookup(lan9645x, addr, vid);\n+\tif (!mdb_entry)\n+\t\treturn -ENOENT;\n+\n+\tif (!(mdb_entry-\u003eports \u0026 BIT(chip_port)))\n+\t\treturn 0;\n+\n+\tnew_ports = mdb_entry-\u003eports \u0026 ~BIT(chip_port);\n+\n+\tif (!new_ports) {\n+\t\t/* For IP multicast hardware uses DMAC as key (mac,vid) not\n+\t\t * encoded mac.\n+\t\t */\n+\t\terr = lan9645x_mact_forget(lan9645x, mdb_entry-\u003emac,\n+\t\t\t\t\t   mdb_entry-\u003evid, type);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t\tlan9645x_mdb_entry_dealloc(lan9645x, mdb_entry);\n+\t\treturn 0;\n+\t}\n+\n+\t/* Update PGID ptr for non-IP entries (L2 multicast) */\n+\tnew_pgid = lan9645x_mdb_pgid_entry_get(lan9645x, new_ports, type);\n+\tif (IS_ERR(new_pgid))\n+\t\t/* Continue forwarding to old port group. */\n+\t\treturn PTR_ERR(new_pgid);\n+\n+\treturn lan9645x_mdb_update_dest(lan9645x, mdb_entry, type, new_pgid,\n+\t\t\t\t\tnew_ports);\n+}\n+\n+static int lan9645x_mdb_add(struct lan9645x *lan9645x, int chip_port,\n+\t\t\t    const unsigned char addr[ETH_ALEN], u16 vid,\n+\t\t\t    enum macaccess_entry_type type)\n+{\n+\tint err;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emdb_lock);\n+\terr = __lan9645x_mdb_add(lan9645x, chip_port, addr, vid, type);\n+\tmutex_unlock(\u0026lan9645x-\u003emdb_lock);\n+\treturn err;\n+}\n+\n+static int lan9645x_mdb_del(struct lan9645x *lan9645x, int chip_port,\n+\t\t\t    const unsigned char addr[ETH_ALEN], u16 vid,\n+\t\t\t    enum macaccess_entry_type type)\n+{\n+\tint err;\n+\n+\tmutex_lock(\u0026lan9645x-\u003emdb_lock);\n+\terr = __lan9645x_mdb_del(lan9645x, chip_port, addr, vid, type);\n+\tmutex_unlock(\u0026lan9645x-\u003emdb_lock);\n+\treturn err;\n+}\n+\n+int lan9645x_mdb_port_add(struct lan9645x *lan9645x, int port,\n+\t\t\t  const struct switchdev_obj_port_mdb *mdb,\n+\t\t\t  struct net_device *bridge)\n+{\n+\tenum macaccess_entry_type type;\n+\tu16 vid = mdb-\u003evid;\n+\n+\ttype = lan9645x_mdb_classify(mdb-\u003eaddr);\n+\n+\tif (!vid)\n+\t\tvid = lan9645x_vlan_unaware_pvid(!!bridge);\n+\n+\treturn lan9645x_mdb_add(lan9645x, port, mdb-\u003eaddr, vid, type);\n+}\n+\n+int lan9645x_mdb_port_del(struct lan9645x *lan9645x, int port,\n+\t\t\t  const struct switchdev_obj_port_mdb *mdb,\n+\t\t\t  struct net_device *bridge)\n+{\n+\tenum macaccess_entry_type type;\n+\tu16 vid = mdb-\u003evid;\n+\n+\ttype = lan9645x_mdb_classify(mdb-\u003eaddr);\n+\n+\tif (!vid)\n+\t\tvid = lan9645x_vlan_unaware_pvid(!!bridge);\n+\n+\treturn lan9645x_mdb_del(lan9645x, port, mdb-\u003eaddr, vid, type);\n+}\n+\n+void lan9645x_mdb_deinit(struct lan9645x *lan9645x)\n+{\n+\tstruct lan9645x_mdb_entry *mdb, *tmp;\n+\n+\tlist_for_each_entry_safe(mdb, tmp, \u0026lan9645x-\u003emdb_entries, list)\n+\t\tlan9645x_mdb_entry_dealloc(lan9645x, mdb);\n+\n+\tmutex_destroy(\u0026lan9645x-\u003emdb_lock);\n+}\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_npi.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_npi.c\nnew file mode 100644\nindex 00000000000000..7e286101f055aa\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_npi.c\n@@ -0,0 +1,85 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+#include \u003cnet/addrconf.h\u003e\n+\n+#include \"lan9645x_main.h\"\n+\n+void lan9645x_npi_port_init(struct lan9645x *lan9645x,\n+\t\t\t    struct dsa_port *cpu_port)\n+{\n+\tint port = cpu_port-\u003eindex;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\tlan9645x-\u003enpi = port;\n+\n+\tdev_dbg(lan9645x-\u003edev, \"NPI port=%d\\n\", port);\n+\n+\t/* Any CPU extraction queue frames, are sent to external CPU on given\n+\t * port. Never send injected frames back to cpu.\n+\t */\n+\tlan_wr(QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK |\n+\t       QSYS_EXT_CPU_CFG_EXT_CPU_PORT_SET(p-\u003echip_port) |\n+\t       QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_SET(1) |\n+\t       QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_SET(1),\n+\t       lan9645x, QSYS_EXT_CPU_CFG);\n+\n+\t/* Configure IFH prefix mode for NPI port. We can not use an injection\n+\t * prefix, because it requires all frames sent on the port to contain\n+\t * the prefix. Frames without the prefix would get stuck in the queue\n+\t * system rendering the port becomes unusable. Since we do not control\n+\t * what is sent to the NPI port, no prefix is our only option.\n+\t */\n+\tlan_rmw(SYS_PORT_MODE_INCL_XTR_HDR_SET(LAN9645X_TAG_PREFIX_LONG) |\n+\t\tSYS_PORT_MODE_INCL_INJ_HDR_SET(LAN9645X_TAG_PREFIX_NONE),\n+\t\tSYS_PORT_MODE_INCL_XTR_HDR |\n+\t\tSYS_PORT_MODE_INCL_INJ_HDR,\n+\t\tlan9645x,\n+\t\tSYS_PORT_MODE(p-\u003echip_port));\n+\n+\t/* Rewriting and extraction with IFH does not play nice together. A VLAN\n+\t * tag pushed into the frame by REW will cause 4 bytes at the end of the\n+\t * extraction header to be overwritten with the top 4 bytes of the DMAC.\n+\t *\n+\t * We can not use REW_PORT_CFG_NO_REWRITE=1 as that disabled RTAGD\n+\t * setting in the IFH\n+\t */\n+\tlan_rmw(REW_TAG_CFG_TAG_CFG_SET(LAN9645X_TAG_DISABLED),\n+\t\tREW_TAG_CFG_TAG_CFG, lan9645x, REW_TAG_CFG(port));\n+\n+\t/* Clear rewriter port vid */\n+\tlan_wr(0, lan9645x, REW_PORT_VLAN_CFG(port));\n+\n+\t/* Make sure frames with src_port=\u003cCPU port module\u003e are not reflected\n+\t * back via the NPI port. This could happen if a frame is flooded for\n+\t * instance. The *_CPU_KILL_ENA flags above only have an effect when a\n+\t * frame is output due to a CPU forwarding decision such as trapping or\n+\t * cpu copy.\n+\t */\n+\tlan_rmw(0, BIT(port), lan9645x,\n+\t\tANA_PGID(PGID_SRC + lan9645x-\u003enum_phys_ports));\n+}\n+\n+void lan9645x_npi_port_deinit(struct lan9645x *lan9645x, int port)\n+{\n+\tstruct lan9645x_port *p;\n+\n+\tif (port \u003c 0)\n+\t\treturn;\n+\n+\tlan9645x-\u003enpi = -1;\n+\tp = lan9645x_to_port(lan9645x, port);\n+\n+\tlan_wr(QSYS_EXT_CPU_CFG_EXT_CPU_PORT_SET(0x1f) |\n+\t       QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_SET(1) |\n+\t       QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_SET(1),\n+\t       lan9645x, QSYS_EXT_CPU_CFG);\n+\n+\tlan_rmw(SYS_PORT_MODE_INCL_XTR_HDR_SET(LAN9645X_TAG_PREFIX_DISABLED) |\n+\t\tSYS_PORT_MODE_INCL_INJ_HDR_SET(LAN9645X_TAG_PREFIX_DISABLED),\n+\t\tSYS_PORT_MODE_INCL_XTR_HDR |\n+\t\tSYS_PORT_MODE_INCL_INJ_HDR,\n+\t\tlan9645x,\n+\t\tSYS_PORT_MODE(p-\u003echip_port));\n+}\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c\nnew file mode 100644\nindex 00000000000000..4f77038918af8e\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c\n@@ -0,0 +1,414 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \u003clinux/phy.h\u003e\n+#include \u003clinux/phy/phy.h\u003e\n+\n+#include \"lan9645x_main.h\"\n+\n+/* Port 4 or 7 is RGMII_0 and port 8 is RGMII_1 */\n+#define RGMII_IDX(port) ((port) == 8 ? 1 : 0)\n+\n+void lan9645x_phylink_get_caps(struct lan9645x *lan9645x, int port,\n+\t\t\t       struct phylink_config *c)\n+{\n+\tc-\u003emac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 |\n+\t\t\t      MAC_100 | MAC_1000FD;\n+\n+\tswitch (port) {\n+\tcase 0 ... 3:\n+\t\t__set_bit(PHY_INTERFACE_MODE_GMII, c-\u003esupported_interfaces);\n+\t\tbreak;\n+\tcase 4:\n+\t\t__set_bit(PHY_INTERFACE_MODE_GMII, c-\u003esupported_interfaces);\n+\t\tphy_interface_set_rgmii(c-\u003esupported_interfaces);\n+\t\tbreak;\n+\tcase 5 ... 6:\n+\t\t/* SerDes ports: QSGMII/SGMII/1000BASEX/2500BASEX modes\n+\t\t * require PCS support which is not yet implemented.\n+\t\t * With empty supported_interfaces, these will end up being\n+\t\t * marked unused by the DSA core, if they are declared in the\n+\t\t * DT.\n+\t\t */\n+\t\tbreak;\n+\tcase 7 ... 8:\n+\t\t/* QSGMII mode on ports 7-8 requires SerDes PCS support,\n+\t\t * which is not yet implemented.\n+\t\t */\n+\t\tphy_interface_set_rgmii(c-\u003esupported_interfaces);\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+}\n+\n+static void lan9645x_rgmii_set_speed(struct lan9645x *lan9645x, int port,\n+\t\t\t\t     int speed)\n+{\n+\tu8 tx_clk;\n+\n+\ttx_clk = speed == SPEED_1000 ? 1 :\n+\t\t speed == SPEED_100  ? 2 :\n+\t\t speed == SPEED_10   ? 3 : 0;\n+\n+\tlan_rmw(HSIO_RGMII_CFG_RGMII_RX_RST_SET(0) |\n+\t\tHSIO_RGMII_CFG_RGMII_TX_RST_SET(0) |\n+\t\tHSIO_RGMII_CFG_TX_CLK_CFG_SET(tx_clk),\n+\t\tHSIO_RGMII_CFG_RGMII_RX_RST |\n+\t\tHSIO_RGMII_CFG_RGMII_TX_RST |\n+\t\tHSIO_RGMII_CFG_TX_CLK_CFG,\n+\t\tlan9645x, HSIO_RGMII_CFG(RGMII_IDX(port)));\n+}\n+\n+static void lan9645x_rgmii_dll_config(struct lan9645x_port *p)\n+{\n+\tu32 rx_idx, tx_idx;\n+\n+\t/* DLL register layout:\n+\t * (N*2):   RGMII_N_RX\n+\t * (N*2)+1: RGMII_N_TX\n+\t */\n+\trx_idx = RGMII_IDX(p-\u003echip_port) * 2;\n+\ttx_idx = RGMII_IDX(p-\u003echip_port) * 2 + 1;\n+\n+\t/* Enable DLL in RGMII clock paths, deassert DLL reset, and start the\n+\t * delay tune FSM.\n+\t */\n+\tlan_rmw(HSIO_DLL_CFG_DLL_CLK_ENA_SET(1) |\n+\t\tHSIO_DLL_CFG_DLL_RST_SET(0) |\n+\t\tHSIO_DLL_CFG_DLL_ENA_SET(p-\u003erx_internal_delay) |\n+\t\tHSIO_DLL_CFG_DELAY_ENA_SET(p-\u003erx_internal_delay),\n+\t\tHSIO_DLL_CFG_DLL_CLK_ENA |\n+\t\tHSIO_DLL_CFG_DLL_RST |\n+\t\tHSIO_DLL_CFG_DLL_ENA |\n+\t\tHSIO_DLL_CFG_DELAY_ENA,\n+\t\tp-\u003elan9645x, HSIO_DLL_CFG(rx_idx));\n+\n+\tlan_rmw(HSIO_DLL_CFG_DLL_CLK_ENA_SET(1) |\n+\t\tHSIO_DLL_CFG_DLL_RST_SET(0) |\n+\t\tHSIO_DLL_CFG_DLL_ENA_SET(p-\u003etx_internal_delay) |\n+\t\tHSIO_DLL_CFG_DELAY_ENA_SET(p-\u003etx_internal_delay),\n+\t\tHSIO_DLL_CFG_DLL_CLK_ENA |\n+\t\tHSIO_DLL_CFG_DLL_RST |\n+\t\tHSIO_DLL_CFG_DLL_ENA |\n+\t\tHSIO_DLL_CFG_DELAY_ENA,\n+\t\tp-\u003elan9645x, HSIO_DLL_CFG(tx_idx));\n+}\n+\n+static struct lan9645x_port *\n+lan9645x_phylink_config_to_port(struct phylink_config *config)\n+{\n+\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n+\n+\treturn lan9645x_to_port(dp-\u003eds-\u003epriv, dp-\u003eindex);\n+}\n+\n+static int lan9645x_phylink_mac_prepare(struct phylink_config *config,\n+\t\t\t\t\tunsigned int mode,\n+\t\t\t\t\tphy_interface_t iface)\n+{\n+\tstruct lan9645x_port *p = lan9645x_phylink_config_to_port(config);\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tint port = p-\u003echip_port;\n+\tu32 hw_cfg, gmii_ena;\n+\tbool is_rgmii;\n+\n+\tif (port == 5 || port == 6 || port \u003e 8)\n+\t\treturn -EINVAL;\n+\n+\tis_rgmii = phy_interface_mode_is_rgmii(iface);\n+\n+\t/* RGMII_0 is a 2:1 mux shared between port 4 and port 7. Reject\n+\t * collisions by looking at current hardware state: the driver\n+\t * maintains the invariant that RGMII_0_CFG=1 iff port 4 owns\n+\t * RGMII_0, and for port 7 when GMII_ENA bit 7 is set this implies port\n+\t * 7 owns RGMII_0.\n+\t */\n+\tmutex_lock(\u0026lan9645x-\u003eport_mux_lock);\n+\n+\tif (is_rgmii) {\n+\t\thw_cfg = lan_rd(lan9645x, HSIO_HW_CFG);\n+\t\tgmii_ena = HSIO_HW_CFG_GMII_ENA_GET(hw_cfg);\n+\n+\t\tif ((port == 4 \u0026\u0026 (gmii_ena \u0026 BIT(7))) ||\n+\t\t    (port == 7 \u0026\u0026 (gmii_ena \u0026 BIT(4)) \u0026\u0026\n+\t\t     HSIO_HW_CFG_RGMII_0_CFG_GET(hw_cfg))) {\n+\t\t\tmutex_unlock(\u0026lan9645x-\u003eport_mux_lock);\n+\t\t\treturn -EBUSY;\n+\t\t}\n+\t}\n+\n+\tlan_rmw(HSIO_HW_CFG_GMII_ENA_SET(BIT(port)),\n+\t\tHSIO_HW_CFG_GMII_ENA_SET(BIT(port)), lan9645x, HSIO_HW_CFG);\n+\n+\tif (port == 4) {\n+\t\tlan_rmw(HSIO_HW_CFG_RGMII_0_CFG_SET(is_rgmii),\n+\t\t\tHSIO_HW_CFG_RGMII_0_CFG,\n+\t\t\tlan9645x, HSIO_HW_CFG);\n+\t} else if (port == 7 \u0026\u0026 is_rgmii) {\n+\t\tlan_rmw(HSIO_HW_CFG_RGMII_0_CFG_SET(0),\n+\t\t\tHSIO_HW_CFG_RGMII_0_CFG,\n+\t\t\tlan9645x, HSIO_HW_CFG);\n+\t}\n+\n+\tmutex_unlock(\u0026lan9645x-\u003eport_mux_lock);\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_phylink_mac_config(struct phylink_config *config,\n+\t\t\t\t\tunsigned int mode,\n+\t\t\t\t\tconst struct phylink_link_state *state)\n+{\n+\tstruct lan9645x_port *p = lan9645x_phylink_config_to_port(config);\n+\n+\tif (phy_interface_mode_is_rgmii(state-\u003einterface))\n+\t\tlan9645x_rgmii_dll_config(p);\n+}\n+\n+static bool lan9645x_port_is_cuphy(struct lan9645x *lan9645x, int port,\n+\t\t\t\t   phy_interface_t interface)\n+{\n+\treturn port \u003e= 0 \u0026\u0026 port \u003c= 4 \u0026\u0026 interface == PHY_INTERFACE_MODE_GMII;\n+}\n+\n+void lan9645x_phylink_port_down(struct lan9645x *lan9645x, int port)\n+{\n+\tstruct lan9645x_port *p = lan9645x_to_port(lan9645x, port);\n+\tu32 val;\n+\n+\t/* Disable MAC frame reception */\n+\tlan_rmw(DEV_MAC_ENA_CFG_RX_ENA_SET(0),\n+\t\tDEV_MAC_ENA_CFG_RX_ENA,\n+\t\tlan9645x, DEV_MAC_ENA_CFG(p-\u003echip_port));\n+\n+\t/* Disable traffic being sent to or from switch port */\n+\tlan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(0),\n+\t\tQSYS_SW_PORT_MODE_PORT_ENA,\n+\t\tlan9645x, QSYS_SW_PORT_MODE(p-\u003echip_port));\n+\n+\t/* Disable dequeuing from the egress queues  */\n+\tlan_rmw(QSYS_PORT_MODE_DEQUEUE_DIS_SET(1),\n+\t\tQSYS_PORT_MODE_DEQUEUE_DIS,\n+\t\tlan9645x, QSYS_PORT_MODE(p-\u003echip_port));\n+\n+\t/* Disable Flowcontrol */\n+\tlan_rmw(SYS_PAUSE_CFG_PAUSE_ENA_SET(0),\n+\t\tSYS_PAUSE_CFG_PAUSE_ENA,\n+\t\tlan9645x, SYS_PAUSE_CFG(p-\u003echip_port));\n+\n+\t/* Wait a worst case time 8ms (10K jumbo/10Mbit) */\n+\tusleep_range(8 * USEC_PER_MSEC, 9 * USEC_PER_MSEC);\n+\n+\t/* Disable HDX backpressure. */\n+\tlan_rmw(SYS_FRONT_PORT_MODE_HDX_MODE_SET(0),\n+\t\tSYS_FRONT_PORT_MODE_HDX_MODE,\n+\t\tlan9645x, SYS_FRONT_PORT_MODE(p-\u003echip_port));\n+\n+\t/* Flush the queues associated with the port */\n+\tlan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(3),\n+\t\tQSYS_SW_PORT_MODE_AGING_MODE,\n+\t\tlan9645x, QSYS_SW_PORT_MODE(p-\u003echip_port));\n+\n+\t/* Enable dequeuing from the egress queues */\n+\tlan_rmw(QSYS_PORT_MODE_DEQUEUE_DIS_SET(0),\n+\t\tQSYS_PORT_MODE_DEQUEUE_DIS,\n+\t\tlan9645x, QSYS_PORT_MODE(p-\u003echip_port));\n+\n+\t/* Wait until flushing is complete */\n+\tif (lan9645x_rd_poll_slow(lan9645x, QSYS_SW_STATUS(p-\u003echip_port),\n+\t\t\t\t  val, !QSYS_SW_STATUS_EQ_AVAIL_GET(val)))\n+\t\tdev_err(lan9645x-\u003edev, \"Flush timeout chip port %u\\n\", port);\n+\n+\t/* Disable MAC tx */\n+\tlan_rmw(DEV_MAC_ENA_CFG_TX_ENA_SET(0),\n+\t\tDEV_MAC_ENA_CFG_TX_ENA,\n+\t\tlan9645x, DEV_MAC_ENA_CFG(p-\u003echip_port));\n+\n+\t/* Reset the Port and MAC clock domains */\n+\tlan_rmw(DEV_CLOCK_CFG_PORT_RST_SET(1),\n+\t\tDEV_CLOCK_CFG_PORT_RST,\n+\t\tlan9645x, DEV_CLOCK_CFG(p-\u003echip_port));\n+\n+\t/* Wait before resetting MAC clock domains. */\n+\tusleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);\n+\n+\tlan_rmw(DEV_CLOCK_CFG_MAC_TX_RST_SET(1) |\n+\t\tDEV_CLOCK_CFG_MAC_RX_RST_SET(1) |\n+\t\tDEV_CLOCK_CFG_PORT_RST_SET(1),\n+\t\tDEV_CLOCK_CFG_MAC_TX_RST |\n+\t\tDEV_CLOCK_CFG_MAC_RX_RST |\n+\t\tDEV_CLOCK_CFG_PORT_RST,\n+\t\tlan9645x, DEV_CLOCK_CFG(p-\u003echip_port));\n+\n+\t/* Clear flushing */\n+\tlan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(1),\n+\t\tQSYS_SW_PORT_MODE_AGING_MODE,\n+\t\tlan9645x, QSYS_SW_PORT_MODE(p-\u003echip_port));\n+}\n+\n+static void lan9645x_phylink_mac_link_down(struct phylink_config *config,\n+\t\t\t\t\t   unsigned int link_an_mode,\n+\t\t\t\t\t   phy_interface_t interface)\n+{\n+\tstruct lan9645x_port *p = lan9645x_phylink_config_to_port(config);\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\n+\tlan9645x_phylink_port_down(lan9645x, p-\u003echip_port);\n+}\n+\n+static void lan9645x_phylink_mac_link_up(struct phylink_config *config,\n+\t\t\t\t\t struct phy_device *phydev,\n+\t\t\t\t\t unsigned int link_an_mode,\n+\t\t\t\t\t phy_interface_t interface, int speed,\n+\t\t\t\t\t int duplex, bool tx_pause,\n+\t\t\t\t\t bool rx_pause)\n+{\n+\tstruct lan9645x_port *p = lan9645x_phylink_config_to_port(config);\n+\tint rx_ifg1, rx_ifg2, tx_ifg, gtx_clk = 0;\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tint gspeed = LAN9645X_SPEED_DISABLED;\n+\tint port = p-\u003echip_port;\n+\tint mode = 0;\n+\tint fc_spd;\n+\n+\t/* Configure RGMII TX clock for the negotiated speed */\n+\tif (phy_interface_mode_is_rgmii(interface))\n+\t\tlan9645x_rgmii_set_speed(lan9645x, port, speed);\n+\n+\tif (duplex == DUPLEX_FULL) {\n+\t\tmode |= DEV_MAC_MODE_CFG_FDX_ENA_SET(1);\n+\t\ttx_ifg = 0x5;\n+\t\trx_ifg2 = 0x2;\n+\n+\t} else {\n+\t\ttx_ifg = 0x6;\n+\t\trx_ifg2 = 0x2;\n+\t}\n+\n+\tswitch (speed) {\n+\tcase SPEED_10:\n+\t\trx_ifg1 = 0x2;\n+\t\tgspeed = LAN9645X_SPEED_10;\n+\t\tbreak;\n+\tcase SPEED_100:\n+\t\trx_ifg1 = 0x1;\n+\t\tgspeed = LAN9645X_SPEED_100;\n+\t\tbreak;\n+\tcase SPEED_1000:\n+\t\tgspeed = LAN9645X_SPEED_1000;\n+\t\tmode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);\n+\t\tmode |= DEV_MAC_MODE_CFG_FDX_ENA_SET(1);\n+\t\ttx_ifg = 0x6;\n+\t\trx_ifg1 = 0x1;\n+\t\trx_ifg2 = 0x2;\n+\t\tgtx_clk = 1;\n+\t\tbreak;\n+\tcase SPEED_2500:\n+\t\tgspeed = LAN9645X_SPEED_2500;\n+\t\tmode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);\n+\t\tmode |= DEV_MAC_MODE_CFG_FDX_ENA_SET(1);\n+\t\ttx_ifg = 0x6;\n+\t\trx_ifg1 = 0x1;\n+\t\trx_ifg2 = 0x2;\n+\t\tbreak;\n+\tdefault:\n+\t\tdev_err(lan9645x-\u003edev, \"Unsupported speed on port %d: %d\\n\",\n+\t\t\tp-\u003echip_port, speed);\n+\t\treturn;\n+\t}\n+\n+\tfc_spd = lan9645x_speed_fc_enc(gspeed);\n+\n+\tlan_rmw(mode,\n+\t\tDEV_MAC_MODE_CFG_FDX_ENA |\n+\t\tDEV_MAC_MODE_CFG_GIGA_MODE_ENA,\n+\t\tlan9645x, DEV_MAC_MODE_CFG(p-\u003echip_port));\n+\n+\tlan_rmw(DEV_MAC_IFG_CFG_TX_IFG_SET(tx_ifg) |\n+\t\tDEV_MAC_IFG_CFG_RX_IFG1_SET(rx_ifg1) |\n+\t\tDEV_MAC_IFG_CFG_RX_IFG2_SET(rx_ifg2),\n+\t\tDEV_MAC_IFG_CFG_TX_IFG |\n+\t\tDEV_MAC_IFG_CFG_RX_IFG1 |\n+\t\tDEV_MAC_IFG_CFG_RX_IFG2,\n+\t\tlan9645x, DEV_MAC_IFG_CFG(p-\u003echip_port));\n+\n+\tif (lan9645x_port_is_cuphy(lan9645x, port, interface)) {\n+\t\tlan_rmw(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(gtx_clk),\n+\t\t\tCHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, lan9645x,\n+\t\t\tCHIP_TOP_CUPHY_PORT_CFG(p-\u003echip_port));\n+\t}\n+\n+\tlan_rmw(SYS_PAUSE_CFG_PAUSE_ENA_SET(1),\n+\t\tSYS_PAUSE_CFG_PAUSE_ENA,\n+\t\tlan9645x, SYS_PAUSE_CFG(p-\u003echip_port));\n+\n+\t/* Flow control */\n+\tlan_rmw(SYS_MAC_FC_CFG_FC_LINK_SPEED_SET(fc_spd) |\n+\t\tSYS_MAC_FC_CFG_FC_LATENCY_CFG_SET(0x7) |\n+\t\tSYS_MAC_FC_CFG_ZERO_PAUSE_ENA_SET(1) |\n+\t\tSYS_MAC_FC_CFG_PAUSE_VAL_CFG_SET(0xffff) |\n+\t\tSYS_MAC_FC_CFG_RX_FC_ENA_SET(rx_pause ? 1 : 0) |\n+\t\tSYS_MAC_FC_CFG_TX_FC_ENA_SET(tx_pause ? 1 : 0),\n+\t\tSYS_MAC_FC_CFG_FC_LINK_SPEED |\n+\t\tSYS_MAC_FC_CFG_FC_LATENCY_CFG |\n+\t\tSYS_MAC_FC_CFG_ZERO_PAUSE_ENA |\n+\t\tSYS_MAC_FC_CFG_PAUSE_VAL_CFG |\n+\t\tSYS_MAC_FC_CFG_RX_FC_ENA |\n+\t\tSYS_MAC_FC_CFG_TX_FC_ENA,\n+\t\tlan9645x, SYS_MAC_FC_CFG(p-\u003echip_port));\n+\n+\t/* Enable MAC module */\n+\tlan_wr(DEV_MAC_ENA_CFG_RX_ENA_SET(1) |\n+\t       DEV_MAC_ENA_CFG_TX_ENA_SET(1),\n+\t       lan9645x, DEV_MAC_ENA_CFG(p-\u003echip_port));\n+\n+\t/* port _must_ be taken out of reset before MAC. */\n+\tlan_rmw(DEV_CLOCK_CFG_PORT_RST_SET(0),\n+\t\tDEV_CLOCK_CFG_PORT_RST,\n+\t\tlan9645x, DEV_CLOCK_CFG(p-\u003echip_port));\n+\n+\t/* Take out the clock from reset. Note this write will set all these\n+\t * fields to zero:\n+\t *\n+\t * DEV_CLOCK_CFG[*].MAC_TX_RST\n+\t * DEV_CLOCK_CFG[*].MAC_RX_RST\n+\t * DEV_CLOCK_CFG[*].PCS_TX_RST\n+\t * DEV_CLOCK_CFG[*].PCS_RX_RST\n+\t * DEV_CLOCK_CFG[*].PORT_RST\n+\t * DEV_CLOCK_CFG[*].PHY_RST\n+\t *\n+\t * Note link_down will assert PORT_RST, MAC_RX_RST and MAC_TX_RST, so\n+\t * we are effectively taking the mac tx/rx clocks out of reset.\n+\t *\n+\t * This linkspeed field has a slightly different encoding from others:\n+\t *\n+\t * - 0 is no-link\n+\t * - 1 is both 2500/1000\n+\t * - 2 is 100mbit\n+\t * - 3 is 10mbit\n+\t *\n+\t */\n+\tlan_wr(DEV_CLOCK_CFG_LINK_SPEED_SET(fc_spd == 0 ? 1 : fc_spd),\n+\t       lan9645x,\n+\t       DEV_CLOCK_CFG(p-\u003echip_port));\n+\n+\t/* Core: Enable port for frame transfer */\n+\tlan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1) |\n+\t\tQSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(1) |\n+\t\tQSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(1) |\n+\t\tQSYS_SW_PORT_MODE_TX_PFC_ENA_SET(0),\n+\t\tQSYS_SW_PORT_MODE_PORT_ENA |\n+\t\tQSYS_SW_PORT_MODE_SCH_NEXT_CFG |\n+\t\tQSYS_SW_PORT_MODE_INGRESS_DROP_MODE |\n+\t\tQSYS_SW_PORT_MODE_TX_PFC_ENA,\n+\t\tlan9645x, QSYS_SW_PORT_MODE(p-\u003echip_port));\n+}\n+\n+const struct phylink_mac_ops lan9645x_phylink_mac_ops = {\n+\t.mac_prepare\t\t\t= lan9645x_phylink_mac_prepare,\n+\t.mac_config\t\t\t= lan9645x_phylink_mac_config,\n+\t.mac_link_down\t\t\t= lan9645x_phylink_mac_link_down,\n+\t.mac_link_up\t\t\t= lan9645x_phylink_mac_link_up,\n+};\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c\nnew file mode 100644\nindex 00000000000000..407d7eb1d0640a\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c\n@@ -0,0 +1,226 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \u003clinux/of_net.h\u003e\n+\n+#include \"lan9645x_main.h\"\n+\n+void lan9645x_port_cpu_init(struct lan9645x *lan9645x)\n+{\n+\t/* Map the 8 CPU extraction queues to the CPU port module (datasheet is\n+\t * wrong)\n+\t */\n+\tlan_wr(0, lan9645x, QSYS_CPU_GROUP_MAP);\n+\n+\t/* Set min-spacing of EOF to SOF on injected frames to 0, on cpu device\n+\t * 1. This is required when injecting with IFH.\n+\t * Default values emulates delay of std preamble/IFG setting on a front\n+\t * port.\n+\t */\n+\tlan_rmw(QS_INJ_CTRL_GAP_SIZE_SET(0),\n+\t\tQS_INJ_CTRL_GAP_SIZE,\n+\t\tlan9645x, QS_INJ_CTRL(1));\n+\n+\t/* Injection: Mode: manual injection | Byte_swap */\n+\tlan_wr(QS_INJ_GRP_CFG_MODE_SET(1) |\n+\t       QS_INJ_GRP_CFG_BYTE_SWAP_SET(1),\n+\t       lan9645x, QS_INJ_GRP_CFG(1));\n+\n+\tlan_rmw(QS_INJ_CTRL_GAP_SIZE_SET(0),\n+\t\tQS_INJ_CTRL_GAP_SIZE,\n+\t\tlan9645x, QS_INJ_CTRL(1));\n+\n+\tlan_wr(SYS_PORT_MODE_INCL_INJ_HDR_SET(1),\n+\t       lan9645x, SYS_PORT_MODE(lan9645x-\u003enum_phys_ports + 1));\n+\n+\t/* The CPU will only use its reserved buffer in the shared queue system\n+\t * and none of the shared buffer space, therefore we disable resource\n+\t * sharing in egress direction. We must not disable resource sharing in\n+\t * the ingress direction, because some traffic test scenarios require\n+\t * loads of buffer memory for frames initiated by the CPU.\n+\t */\n+\tlan_rmw(QSYS_EGR_NO_SHARING_EGR_NO_SHARING_SET(BIT(lan9645x-\u003enum_phys_ports)),\n+\t\tQSYS_EGR_NO_SHARING_EGR_NO_SHARING_SET(BIT(lan9645x-\u003enum_phys_ports)),\n+\t\tlan9645x, QSYS_EGR_NO_SHARING);\n+\n+\t/* The CPU should also discard frames forwarded to it if it has run\n+\t * out of the reserved buffer space. Otherwise they will be held back\n+\t * in the ingress queues with potential head-of-line blocking effects.\n+\t */\n+\tlan_rmw(QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_SET(BIT(lan9645x-\u003enum_phys_ports)),\n+\t\tQSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_SET(BIT(lan9645x-\u003enum_phys_ports)),\n+\t\tlan9645x, QSYS_EGR_DROP_MODE);\n+\n+\tlan_wr(BIT(lan9645x-\u003enum_phys_ports), lan9645x, ANA_PGID(PGID_CPU));\n+\n+\tlan_rmw(ANA_PORT_CFG_PORTID_VAL_SET(lan9645x-\u003enum_phys_ports) |\n+\t\tANA_PORT_CFG_RECV_ENA_SET(1),\n+\t\tANA_PORT_CFG_PORTID_VAL |\n+\t\tANA_PORT_CFG_RECV_ENA, lan9645x,\n+\t\tANA_PORT_CFG(lan9645x-\u003enum_phys_ports));\n+\n+\t/* Enable switching to/from cpu port. Keep default aging-mode. */\n+\tlan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1) |\n+\t\tQSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(1) |\n+\t\tQSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(1),\n+\t\tQSYS_SW_PORT_MODE_PORT_ENA |\n+\t\tQSYS_SW_PORT_MODE_SCH_NEXT_CFG |\n+\t\tQSYS_SW_PORT_MODE_INGRESS_DROP_MODE,\n+\t\tlan9645x, QSYS_SW_PORT_MODE(lan9645x-\u003enum_phys_ports));\n+\n+\t/* Transmit cpu frames as received without any tagging, timing or other\n+\t * updates. This does not affect CPU-over-NPI, only manual extraction.\n+\t * On the NPI port we need NO_REWRITE=0 for HSR/PRP.\n+\t */\n+\tlan_wr(REW_PORT_CFG_NO_REWRITE_SET(1),\n+\t       lan9645x, REW_PORT_CFG(lan9645x-\u003enum_phys_ports));\n+}\n+\n+void lan9645x_port_set_tail_drop_wm(struct lan9645x *lan9645x)\n+{\n+\tint shared_per_port;\n+\tstruct dsa_port *dp;\n+\n+\t/* Configure tail dropping watermark */\n+\tshared_per_port =\n+\t\tlan9645x-\u003eshared_queue_sz / (lan9645x-\u003enum_phys_ports + 1);\n+\n+\t/* The total memory size is divided by number of front ports plus CPU\n+\t * port.\n+\t */\n+\tdsa_switch_for_each_available_port(dp, lan9645x-\u003eds)\n+\t\tlan_wr(lan9645x_wm_enc(shared_per_port), lan9645x,\n+\t\t       SYS_ATOP(dp-\u003eindex));\n+\n+\t/* Tail dropping active based only on per port ATOP wm */\n+\tlan_wr(lan9645x_wm_enc(lan9645x-\u003eshared_queue_sz), lan9645x,\n+\t       SYS_ATOP_TOT_CFG);\n+}\n+\n+/* VLAN tag overhead is handled by DEV_MAC_TAGS_CFG */\n+int lan9645x_port_set_maxlen(struct lan9645x *lan9645x, int port, size_t sdu)\n+{\n+\tstruct lan9645x_port *p = lan9645x_to_port(lan9645x, port);\n+\tint maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;\n+\n+\tif (port == lan9645x-\u003enpi) {\n+\t\tmaxlen += LAN9645X_IFH_LEN;\n+\t\tmaxlen += LAN9645X_LONG_PREFIX_LEN;\n+\t}\n+\n+\tlan_wr(DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(maxlen), lan9645x,\n+\t       DEV_MAC_MAXLEN_CFG(p-\u003echip_port));\n+\n+\t/* Set Pause WM hysteresis */\n+\tlan_rmw(SYS_PAUSE_CFG_PAUSE_STOP_SET(lan9645x_wm_enc(4 * maxlen)) |\n+\t\tSYS_PAUSE_CFG_PAUSE_START_SET(lan9645x_wm_enc(6 * maxlen)),\n+\t\tSYS_PAUSE_CFG_PAUSE_START |\n+\t\tSYS_PAUSE_CFG_PAUSE_STOP,\n+\t\tlan9645x,\n+\t\tSYS_PAUSE_CFG(p-\u003echip_port));\n+\n+\treturn 0;\n+}\n+\n+static void lan9645x_parse_mac_delay(struct lan9645x *lan9645x, int port,\n+\t\t\t\t     struct device_node *dn, const char *name,\n+\t\t\t\t     bool *out)\n+{\n+\tu32 val;\n+\n+\tif (of_property_read_u32(dn, name, \u0026val))\n+\t\treturn;\n+\n+\tif (val != 0 \u0026\u0026 val != 2000) {\n+\t\tdev_warn(lan9645x-\u003edev,\n+\t\t\t \"port %d: %s only supports a 2ns delay (on/off), got %u ps\\n\",\n+\t\t\t port, name, val);\n+\t\treturn;\n+\t}\n+\n+\t*out = val == 2000;\n+}\n+\n+int lan9645x_port_setup(struct dsa_switch *ds, int port)\n+{\n+\tstruct dsa_port *dp = dsa_to_port(ds, port);\n+\tstruct lan9645x *lan9645x = ds-\u003epriv;\n+\tstruct lan9645x_port *p;\n+\n+\tp = lan9645x_to_port(lan9645x, port);\n+\n+\tif (dp-\u003edn) {\n+\t\tlan9645x_parse_mac_delay(lan9645x, port, dp-\u003edn,\n+\t\t\t\t\t \"rx-internal-delay-ps\",\n+\t\t\t\t\t \u0026p-\u003erx_internal_delay);\n+\n+\t\tlan9645x_parse_mac_delay(lan9645x, port, dp-\u003edn,\n+\t\t\t\t\t \"tx-internal-delay-ps\",\n+\t\t\t\t\t \u0026p-\u003etx_internal_delay);\n+\t}\n+\n+\t/* Disable learning on port */\n+\tlan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(0),\n+\t\tANA_PORT_CFG_LEARN_ENA,\n+\t\tlan9645x, ANA_PORT_CFG(p-\u003echip_port));\n+\n+\tlan9645x_port_set_maxlen(lan9645x, port, ETH_DATA_LEN);\n+\n+\t/* Load HDX backoff seed (fixed per-port, one-shot strobe) */\n+\tlan_rmw(DEV_MAC_HDX_CFG_SEED_SET(p-\u003echip_port) |\n+\t\tDEV_MAC_HDX_CFG_SEED_LOAD_SET(1),\n+\t\tDEV_MAC_HDX_CFG_SEED |\n+\t\tDEV_MAC_HDX_CFG_SEED_LOAD, lan9645x,\n+\t\tDEV_MAC_HDX_CFG(p-\u003echip_port));\n+\n+\tlan_rmw(DEV_MAC_HDX_CFG_SEED_LOAD_SET(0),\n+\t\tDEV_MAC_HDX_CFG_SEED_LOAD, lan9645x,\n+\t\tDEV_MAC_HDX_CFG(p-\u003echip_port));\n+\n+\t/* Set SMAC of Pause frame (00:00:00:00:00:00) */\n+\tlan_wr(0, lan9645x, DEV_FC_MAC_LOW_CFG(p-\u003echip_port));\n+\tlan_wr(0, lan9645x, DEV_FC_MAC_HIGH_CFG(p-\u003echip_port));\n+\n+\tlan9645x_phylink_port_down(lan9645x, port);\n+\n+\t/* Drop frames with multicast source address */\n+\tlan_rmw(ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(1),\n+\t\tANA_DROP_CFG_DROP_MC_SMAC_ENA, lan9645x,\n+\t\tANA_DROP_CFG(p-\u003echip_port));\n+\n+\tlan_rmw(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(1) |\n+\t\tDEV_MAC_TAGS_CFG_PB_ENA_SET(1) |\n+\t\tDEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(1) |\n+\t\tDEV_MAC_TAGS_CFG_TAG_ID_SET(ETH_P_8021AD),\n+\t\tDEV_MAC_TAGS_CFG_VLAN_AWR_ENA |\n+\t\tDEV_MAC_TAGS_CFG_PB_ENA |\n+\t\tDEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA |\n+\t\tDEV_MAC_TAGS_CFG_TAG_ID,\n+\t\tlan9645x, DEV_MAC_TAGS_CFG(p-\u003echip_port));\n+\n+\t/* Enable receiving frames on the port, and activate auto-learning of\n+\t * MAC addresses. LEARNAUTO is ignored when LEARN_ENA=0.\n+\t */\n+\tlan_rmw(ANA_PORT_CFG_LEARNAUTO_SET(1) |\n+\t\tANA_PORT_CFG_RECV_ENA_SET(1) |\n+\t\tANA_PORT_CFG_PORTID_VAL_SET(p-\u003echip_port),\n+\t\tANA_PORT_CFG_LEARNAUTO |\n+\t\tANA_PORT_CFG_RECV_ENA |\n+\t\tANA_PORT_CFG_PORTID_VAL,\n+\t\tlan9645x, ANA_PORT_CFG(p-\u003echip_port));\n+\n+\tif (p-\u003echip_port != lan9645x-\u003enpi) {\n+\t\tlan9645x_vlan_set_hostmode(p);\n+\n+\t\tlan_rmw(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_SET(true) |\n+\t\t\tANA_CPU_FWD_CFG_MLD_REDIR_ENA_SET(true) |\n+\t\t\tANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_SET(true),\n+\t\t\tANA_CPU_FWD_CFG_IGMP_REDIR_ENA |\n+\t\t\tANA_CPU_FWD_CFG_MLD_REDIR_ENA |\n+\t\t\tANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA,\n+\t\t\tlan9645x, ANA_CPU_FWD_CFG(p-\u003echip_port));\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_regs.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_regs.h\nnew file mode 100644\nindex 00000000000000..198c7aed87c121\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_regs.h\n@@ -0,0 +1,1937 @@\n+/* SPDX-License-Identifier: GPL-2.0+\n+ *\n+ * Copyright (c) 2026 Microchip Technology Inc.\n+ */\n+\n+/* This file is autogenerated by cml-utils 2026-06-01 15:09:18 +0200.\n+ * Commit ID: 1d14b97555bf4fa63fec33701c1aed00d0315013\n+ */\n+\n+#ifndef _LAN9645X_REGS_H_\n+#define _LAN9645X_REGS_H_\n+\n+#include \u003clinux/bitfield.h\u003e\n+#include \u003clinux/types.h\u003e\n+#include \u003clinux/bug.h\u003e\n+\n+enum lan9645x_target {\n+\tTARGET_AFI = 0,\n+\tTARGET_ANA = 1,\n+\tTARGET_CHIP_TOP = 2,\n+\tTARGET_DEV = 5,\n+\tTARGET_GCB = 16,\n+\tTARGET_HSIO = 17,\n+\tTARGET_QS = 26,\n+\tTARGET_QSYS = 27,\n+\tTARGET_REW = 28,\n+\tTARGET_SYS = 29,\n+\tNUM_TARGETS = 38\n+};\n+\n+#define __REG(...)    __VA_ARGS__\n+\n+/*      AFI:PORT_TBL:PORT_FRM_OUT */\n+#define AFI_PORT_FRM_OUT(g)       __REG(TARGET_AFI,\\\n+\t\t\t\t\t0, 1, 6272, g, 11, 8, 0, 0, 1, 4)\n+\n+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT             GENMASK(26, 16)\n+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT_SET(x)\\\n+\tFIELD_PREP(AFI_PORT_FRM_OUT_FRM_OUT_CNT, x)\n+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT_GET(x)\\\n+\tFIELD_GET(AFI_PORT_FRM_OUT_FRM_OUT_CNT, x)\n+\n+/*      AFI:PORT_TBL:PORT_CFG */\n+#define AFI_PORT_CFG(g)           __REG(TARGET_AFI,\\\n+\t\t\t\t\t0, 1, 6272, g, 11, 8, 4, 0, 1, 4)\n+\n+#define AFI_PORT_CFG_FRM_OUT_MAX                 GENMASK(9, 0)\n+#define AFI_PORT_CFG_FRM_OUT_MAX_SET(x)\\\n+\tFIELD_PREP(AFI_PORT_CFG_FRM_OUT_MAX, x)\n+#define AFI_PORT_CFG_FRM_OUT_MAX_GET(x)\\\n+\tFIELD_GET(AFI_PORT_CFG_FRM_OUT_MAX, x)\n+\n+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ             BIT(16)\n+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ_SET(x)\\\n+\tFIELD_PREP(AFI_PORT_CFG_FC_SKIP_TTI_INJ, x)\n+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ_GET(x)\\\n+\tFIELD_GET(AFI_PORT_CFG_FC_SKIP_TTI_INJ, x)\n+\n+/*      ANA:ANA:ADVLEARN */\n+#define ANA_ADVLEARN              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27136, 0, 1, 284, 0, 0, 1, 4)\n+\n+#define ANA_ADVLEARN_VLAN_CHK                    BIT(0)\n+#define ANA_ADVLEARN_VLAN_CHK_SET(x)\\\n+\tFIELD_PREP(ANA_ADVLEARN_VLAN_CHK, x)\n+#define ANA_ADVLEARN_VLAN_CHK_GET(x)\\\n+\tFIELD_GET(ANA_ADVLEARN_VLAN_CHK, x)\n+\n+/*      ANA:ANA:VLANMASK */\n+#define ANA_VLANMASK              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27136, 0, 1, 284, 8, 0, 1, 4)\n+\n+#define ANA_VLANMASK_VLANMASK                    GENMASK(9, 0)\n+#define ANA_VLANMASK_VLANMASK_SET(x)\\\n+\tFIELD_PREP(ANA_VLANMASK_VLANMASK, x)\n+#define ANA_VLANMASK_VLANMASK_GET(x)\\\n+\tFIELD_GET(ANA_VLANMASK_VLANMASK, x)\n+\n+/*      ANA:ANA:ANAGEFIL */\n+#define ANA_ANAGEFIL              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27136, 0, 1, 284, 12, 0, 1, 4)\n+\n+#define ANA_ANAGEFIL_AGE_LOCKED                  BIT(20)\n+#define ANA_ANAGEFIL_AGE_LOCKED_SET(x)\\\n+\tFIELD_PREP(ANA_ANAGEFIL_AGE_LOCKED, x)\n+#define ANA_ANAGEFIL_AGE_LOCKED_GET(x)\\\n+\tFIELD_GET(ANA_ANAGEFIL_AGE_LOCKED, x)\n+\n+#define ANA_ANAGEFIL_PID_EN                      BIT(19)\n+#define ANA_ANAGEFIL_PID_EN_SET(x)\\\n+\tFIELD_PREP(ANA_ANAGEFIL_PID_EN, x)\n+#define ANA_ANAGEFIL_PID_EN_GET(x)\\\n+\tFIELD_GET(ANA_ANAGEFIL_PID_EN, x)\n+\n+#define ANA_ANAGEFIL_PID_VAL                     GENMASK(18, 14)\n+#define ANA_ANAGEFIL_PID_VAL_SET(x)\\\n+\tFIELD_PREP(ANA_ANAGEFIL_PID_VAL, x)\n+#define ANA_ANAGEFIL_PID_VAL_GET(x)\\\n+\tFIELD_GET(ANA_ANAGEFIL_PID_VAL, x)\n+\n+#define ANA_ANAGEFIL_VID_EN                      BIT(13)\n+#define ANA_ANAGEFIL_VID_EN_SET(x)\\\n+\tFIELD_PREP(ANA_ANAGEFIL_VID_EN, x)\n+#define ANA_ANAGEFIL_VID_EN_GET(x)\\\n+\tFIELD_GET(ANA_ANAGEFIL_VID_EN, x)\n+\n+#define ANA_ANAGEFIL_VID_VAL                     GENMASK(12, 0)\n+#define ANA_ANAGEFIL_VID_VAL_SET(x)\\\n+\tFIELD_PREP(ANA_ANAGEFIL_VID_VAL, x)\n+#define ANA_ANAGEFIL_VID_VAL_GET(x)\\\n+\tFIELD_GET(ANA_ANAGEFIL_VID_VAL, x)\n+\n+/*      ANA:ANA:AUTOAGE */\n+#define ANA_AUTOAGE               __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27136, 0, 1, 284, 44, 0, 1, 4)\n+\n+#define ANA_AUTOAGE_AGE_FAST                     BIT(21)\n+#define ANA_AUTOAGE_AGE_FAST_SET(x)\\\n+\tFIELD_PREP(ANA_AUTOAGE_AGE_FAST, x)\n+#define ANA_AUTOAGE_AGE_FAST_GET(x)\\\n+\tFIELD_GET(ANA_AUTOAGE_AGE_FAST, x)\n+\n+#define ANA_AUTOAGE_AGE_PERIOD                   GENMASK(20, 1)\n+#define ANA_AUTOAGE_AGE_PERIOD_SET(x)\\\n+\tFIELD_PREP(ANA_AUTOAGE_AGE_PERIOD, x)\n+#define ANA_AUTOAGE_AGE_PERIOD_GET(x)\\\n+\tFIELD_GET(ANA_AUTOAGE_AGE_PERIOD, x)\n+\n+#define ANA_AUTOAGE_AUTOAGE_LOCKED               BIT(0)\n+#define ANA_AUTOAGE_AUTOAGE_LOCKED_SET(x)\\\n+\tFIELD_PREP(ANA_AUTOAGE_AUTOAGE_LOCKED, x)\n+#define ANA_AUTOAGE_AUTOAGE_LOCKED_GET(x)\\\n+\tFIELD_GET(ANA_AUTOAGE_AUTOAGE_LOCKED, x)\n+\n+/*      ANA:ANA:FLOODING */\n+#define ANA_FLOODING(r)           __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27136, 0, 1, 284, 68, r, 8, 4)\n+\n+#define ANA_FLOODING_FLD_UNICAST                 GENMASK(17, 12)\n+#define ANA_FLOODING_FLD_UNICAST_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_FLD_UNICAST, x)\n+#define ANA_FLOODING_FLD_UNICAST_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_FLD_UNICAST, x)\n+\n+#define ANA_FLOODING_FLD_BROADCAST               GENMASK(11, 6)\n+#define ANA_FLOODING_FLD_BROADCAST_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_FLD_BROADCAST, x)\n+#define ANA_FLOODING_FLD_BROADCAST_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_FLD_BROADCAST, x)\n+\n+#define ANA_FLOODING_FLD_MULTICAST               GENMASK(5, 0)\n+#define ANA_FLOODING_FLD_MULTICAST_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_FLD_MULTICAST, x)\n+#define ANA_FLOODING_FLD_MULTICAST_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_FLD_MULTICAST, x)\n+\n+/*      ANA:ANA:FLOODING_IPMC */\n+#define ANA_FLOODING_IPMC         __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27136, 0, 1, 284, 100, 0, 1, 4)\n+\n+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL           GENMASK(23, 18)\n+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_IPMC_FLD_MC4_CTRL, x)\n+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_IPMC_FLD_MC4_CTRL, x)\n+\n+#define ANA_FLOODING_IPMC_FLD_MC4_DATA           GENMASK(17, 12)\n+#define ANA_FLOODING_IPMC_FLD_MC4_DATA_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_IPMC_FLD_MC4_DATA, x)\n+#define ANA_FLOODING_IPMC_FLD_MC4_DATA_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_IPMC_FLD_MC4_DATA, x)\n+\n+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL           GENMASK(11, 6)\n+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_IPMC_FLD_MC6_CTRL, x)\n+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_IPMC_FLD_MC6_CTRL, x)\n+\n+#define ANA_FLOODING_IPMC_FLD_MC6_DATA           GENMASK(5, 0)\n+#define ANA_FLOODING_IPMC_FLD_MC6_DATA_SET(x)\\\n+\tFIELD_PREP(ANA_FLOODING_IPMC_FLD_MC6_DATA, x)\n+#define ANA_FLOODING_IPMC_FLD_MC6_DATA_GET(x)\\\n+\tFIELD_GET(ANA_FLOODING_IPMC_FLD_MC6_DATA, x)\n+\n+/*      ANA:PGID:PGID */\n+#define ANA_PGID(g)               __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27648, g, 90, 8, 0, 0, 1, 4)\n+\n+#define ANA_PGID_PGID                            GENMASK(9, 0)\n+#define ANA_PGID_PGID_SET(x)\\\n+\tFIELD_PREP(ANA_PGID_PGID, x)\n+#define ANA_PGID_PGID_GET(x)\\\n+\tFIELD_GET(ANA_PGID_PGID, x)\n+\n+/*      ANA:PGID:PGID_CFG */\n+#define ANA_PGID_CFG(g)           __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 27648, g, 90, 8, 4, 0, 1, 4)\n+\n+#define ANA_PGID_CFG_SAN_ENA                     BIT(4)\n+#define ANA_PGID_CFG_SAN_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_PGID_CFG_SAN_ENA, x)\n+#define ANA_PGID_CFG_SAN_ENA_GET(x)\\\n+\tFIELD_GET(ANA_PGID_CFG_SAN_ENA, x)\n+\n+#define ANA_PGID_CFG_CPUQ_DST_PGID               GENMASK(3, 1)\n+#define ANA_PGID_CFG_CPUQ_DST_PGID_SET(x)\\\n+\tFIELD_PREP(ANA_PGID_CFG_CPUQ_DST_PGID, x)\n+#define ANA_PGID_CFG_CPUQ_DST_PGID_GET(x)\\\n+\tFIELD_GET(ANA_PGID_CFG_CPUQ_DST_PGID, x)\n+\n+#define ANA_PGID_CFG_OBEY_VLAN                   BIT(0)\n+#define ANA_PGID_CFG_OBEY_VLAN_SET(x)\\\n+\tFIELD_PREP(ANA_PGID_CFG_OBEY_VLAN, x)\n+#define ANA_PGID_CFG_OBEY_VLAN_GET(x)\\\n+\tFIELD_GET(ANA_PGID_CFG_OBEY_VLAN, x)\n+\n+/*      ANA:ANA_TABLES:MACHDATA */\n+#define ANA_MACHDATA              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 44, 0, 1, 4)\n+\n+#define ANA_MACHDATA_VID                         GENMASK(28, 16)\n+#define ANA_MACHDATA_VID_SET(x)\\\n+\tFIELD_PREP(ANA_MACHDATA_VID, x)\n+#define ANA_MACHDATA_VID_GET(x)\\\n+\tFIELD_GET(ANA_MACHDATA_VID, x)\n+\n+#define ANA_MACHDATA_MACHDATA                    GENMASK(15, 0)\n+#define ANA_MACHDATA_MACHDATA_SET(x)\\\n+\tFIELD_PREP(ANA_MACHDATA_MACHDATA, x)\n+#define ANA_MACHDATA_MACHDATA_GET(x)\\\n+\tFIELD_GET(ANA_MACHDATA_MACHDATA, x)\n+\n+/*      ANA:ANA_TABLES:MACLDATA */\n+#define ANA_MACLDATA              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 48, 0, 1, 4)\n+\n+/*      ANA:ANA_TABLES:MACACCESS */\n+#define ANA_MACACCESS             __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 52, 0, 1, 4)\n+\n+#define ANA_MACACCESS_CHANGE2SW                  BIT(17)\n+#define ANA_MACACCESS_CHANGE2SW_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_CHANGE2SW, x)\n+#define ANA_MACACCESS_CHANGE2SW_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_CHANGE2SW, x)\n+\n+#define ANA_MACACCESS_MAC_CPU_COPY               BIT(16)\n+#define ANA_MACACCESS_MAC_CPU_COPY_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_MAC_CPU_COPY, x)\n+#define ANA_MACACCESS_MAC_CPU_COPY_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_MAC_CPU_COPY, x)\n+\n+#define ANA_MACACCESS_SRC_KILL                   BIT(15)\n+#define ANA_MACACCESS_SRC_KILL_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_SRC_KILL, x)\n+#define ANA_MACACCESS_SRC_KILL_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_SRC_KILL, x)\n+\n+#define ANA_MACACCESS_IGNORE_VLAN                BIT(14)\n+#define ANA_MACACCESS_IGNORE_VLAN_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_IGNORE_VLAN, x)\n+#define ANA_MACACCESS_IGNORE_VLAN_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_IGNORE_VLAN, x)\n+\n+#define ANA_MACACCESS_AGED_FLAG                  BIT(13)\n+#define ANA_MACACCESS_AGED_FLAG_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_AGED_FLAG, x)\n+#define ANA_MACACCESS_AGED_FLAG_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_AGED_FLAG, x)\n+\n+#define ANA_MACACCESS_VALID                      BIT(12)\n+#define ANA_MACACCESS_VALID_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_VALID, x)\n+#define ANA_MACACCESS_VALID_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_VALID, x)\n+\n+#define ANA_MACACCESS_ENTRYTYPE                  GENMASK(11, 10)\n+#define ANA_MACACCESS_ENTRYTYPE_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_ENTRYTYPE, x)\n+#define ANA_MACACCESS_ENTRYTYPE_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_ENTRYTYPE, x)\n+\n+#define ANA_MACACCESS_DEST_IDX                   GENMASK(9, 4)\n+#define ANA_MACACCESS_DEST_IDX_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_DEST_IDX, x)\n+#define ANA_MACACCESS_DEST_IDX_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_DEST_IDX, x)\n+\n+#define ANA_MACACCESS_MAC_TABLE_CMD              GENMASK(3, 0)\n+#define ANA_MACACCESS_MAC_TABLE_CMD_SET(x)\\\n+\tFIELD_PREP(ANA_MACACCESS_MAC_TABLE_CMD, x)\n+#define ANA_MACACCESS_MAC_TABLE_CMD_GET(x)\\\n+\tFIELD_GET(ANA_MACACCESS_MAC_TABLE_CMD, x)\n+\n+/*      ANA:ANA_TABLES:MACTINDX */\n+#define ANA_MACTINDX              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 56, 0, 1, 4)\n+\n+#define ANA_MACTINDX_BUCKET                      GENMASK(12, 11)\n+#define ANA_MACTINDX_BUCKET_SET(x)\\\n+\tFIELD_PREP(ANA_MACTINDX_BUCKET, x)\n+#define ANA_MACTINDX_BUCKET_GET(x)\\\n+\tFIELD_GET(ANA_MACTINDX_BUCKET, x)\n+\n+#define ANA_MACTINDX_M_INDEX                     GENMASK(10, 0)\n+#define ANA_MACTINDX_M_INDEX_SET(x)\\\n+\tFIELD_PREP(ANA_MACTINDX_M_INDEX, x)\n+#define ANA_MACTINDX_M_INDEX_GET(x)\\\n+\tFIELD_GET(ANA_MACTINDX_M_INDEX, x)\n+\n+/*      ANA:ANA_TABLES:VLAN_PORT_MASK */\n+#define ANA_VLAN_PORT_MASK        __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 60, 0, 1, 4)\n+\n+#define ANA_VLAN_PORT_MASK_VLAN_PORT_MASK        GENMASK(9, 0)\n+#define ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK, x)\n+#define ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK, x)\n+\n+/*      ANA:ANA_TABLES:VLANACCESS */\n+#define ANA_VLANACCESS            __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 64, 0, 1, 4)\n+\n+#define ANA_VLANACCESS_VLAN_TBL_CMD              GENMASK(1, 0)\n+#define ANA_VLANACCESS_VLAN_TBL_CMD_SET(x)\\\n+\tFIELD_PREP(ANA_VLANACCESS_VLAN_TBL_CMD, x)\n+#define ANA_VLANACCESS_VLAN_TBL_CMD_GET(x)\\\n+\tFIELD_GET(ANA_VLANACCESS_VLAN_TBL_CMD, x)\n+\n+/*      ANA:ANA_TABLES:VLANTIDX */\n+#define ANA_VLANTIDX              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 23680, 0, 1, 128, 68, 0, 1, 4)\n+\n+#define ANA_VLANTIDX_VLAN_PGID_CPU_DIS           BIT(18)\n+#define ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_PGID_CPU_DIS, x)\n+#define ANA_VLANTIDX_VLAN_PGID_CPU_DIS_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_PGID_CPU_DIS, x)\n+\n+#define ANA_VLANTIDX_VLAN_SEC_FWD_ENA            BIT(17)\n+#define ANA_VLANTIDX_VLAN_SEC_FWD_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_SEC_FWD_ENA, x)\n+#define ANA_VLANTIDX_VLAN_SEC_FWD_ENA_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_SEC_FWD_ENA, x)\n+\n+#define ANA_VLANTIDX_VLAN_FLOOD_DIS              BIT(16)\n+#define ANA_VLANTIDX_VLAN_FLOOD_DIS_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_FLOOD_DIS, x)\n+#define ANA_VLANTIDX_VLAN_FLOOD_DIS_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_FLOOD_DIS, x)\n+\n+#define ANA_VLANTIDX_VLAN_PRIV_VLAN              BIT(15)\n+#define ANA_VLANTIDX_VLAN_PRIV_VLAN_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_PRIV_VLAN, x)\n+#define ANA_VLANTIDX_VLAN_PRIV_VLAN_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_PRIV_VLAN, x)\n+\n+#define ANA_VLANTIDX_VLAN_LEARN_DISABLED         BIT(14)\n+#define ANA_VLANTIDX_VLAN_LEARN_DISABLED_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_LEARN_DISABLED, x)\n+#define ANA_VLANTIDX_VLAN_LEARN_DISABLED_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_LEARN_DISABLED, x)\n+\n+#define ANA_VLANTIDX_VLAN_MIRROR                 BIT(13)\n+#define ANA_VLANTIDX_VLAN_MIRROR_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_MIRROR, x)\n+#define ANA_VLANTIDX_VLAN_MIRROR_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_MIRROR, x)\n+\n+#define ANA_VLANTIDX_VLAN_SRC_CHK                BIT(12)\n+#define ANA_VLANTIDX_VLAN_SRC_CHK_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_VLAN_SRC_CHK, x)\n+#define ANA_VLANTIDX_VLAN_SRC_CHK_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_VLAN_SRC_CHK, x)\n+\n+#define ANA_VLANTIDX_V_INDEX                     GENMASK(11, 0)\n+#define ANA_VLANTIDX_V_INDEX_SET(x)\\\n+\tFIELD_PREP(ANA_VLANTIDX_V_INDEX, x)\n+#define ANA_VLANTIDX_V_INDEX_GET(x)\\\n+\tFIELD_GET(ANA_VLANTIDX_V_INDEX, x)\n+\n+/*      ANA:PORT:VLAN_CFG */\n+#define ANA_VLAN_CFG(g)           __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 24576, g, 10, 256, 0, 0, 1, 4)\n+\n+#define ANA_VLAN_CFG_VLAN_PFC_ENA                BIT(21)\n+#define ANA_VLAN_CFG_VLAN_PFC_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_PFC_ENA, x)\n+#define ANA_VLAN_CFG_VLAN_PFC_ENA_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_PFC_ENA, x)\n+\n+#define ANA_VLAN_CFG_VLAN_AWARE_ENA              BIT(20)\n+#define ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_AWARE_ENA, x)\n+#define ANA_VLAN_CFG_VLAN_AWARE_ENA_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_AWARE_ENA, x)\n+\n+#define ANA_VLAN_CFG_VLAN_POP_CNT                GENMASK(19, 18)\n+#define ANA_VLAN_CFG_VLAN_POP_CNT_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_POP_CNT, x)\n+#define ANA_VLAN_CFG_VLAN_POP_CNT_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_POP_CNT, x)\n+\n+#define ANA_VLAN_CFG_VLAN_INNER_TAG_ENA          BIT(17)\n+#define ANA_VLAN_CFG_VLAN_INNER_TAG_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_INNER_TAG_ENA, x)\n+#define ANA_VLAN_CFG_VLAN_INNER_TAG_ENA_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_INNER_TAG_ENA, x)\n+\n+#define ANA_VLAN_CFG_VLAN_TAG_TYPE               BIT(16)\n+#define ANA_VLAN_CFG_VLAN_TAG_TYPE_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_TAG_TYPE, x)\n+#define ANA_VLAN_CFG_VLAN_TAG_TYPE_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_TAG_TYPE, x)\n+\n+#define ANA_VLAN_CFG_VLAN_PCP                    GENMASK(15, 13)\n+#define ANA_VLAN_CFG_VLAN_PCP_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_PCP, x)\n+#define ANA_VLAN_CFG_VLAN_PCP_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_PCP, x)\n+\n+#define ANA_VLAN_CFG_VLAN_DEI                    BIT(12)\n+#define ANA_VLAN_CFG_VLAN_DEI_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_DEI, x)\n+#define ANA_VLAN_CFG_VLAN_DEI_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_DEI, x)\n+\n+#define ANA_VLAN_CFG_VLAN_VID                    GENMASK(11, 0)\n+#define ANA_VLAN_CFG_VLAN_VID_SET(x)\\\n+\tFIELD_PREP(ANA_VLAN_CFG_VLAN_VID, x)\n+#define ANA_VLAN_CFG_VLAN_VID_GET(x)\\\n+\tFIELD_GET(ANA_VLAN_CFG_VLAN_VID, x)\n+\n+/*      ANA:PORT:DROP_CFG */\n+#define ANA_DROP_CFG(g)           __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 24576, g, 10, 256, 4, 0, 1, 4)\n+\n+#define ANA_DROP_CFG_DROP_UNTAGGED_ENA           BIT(6)\n+#define ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_UNTAGGED_ENA, x)\n+#define ANA_DROP_CFG_DROP_UNTAGGED_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_UNTAGGED_ENA, x)\n+\n+#define ANA_DROP_CFG_DROP_S_TAGGED_ENA           BIT(5)\n+#define ANA_DROP_CFG_DROP_S_TAGGED_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_S_TAGGED_ENA, x)\n+#define ANA_DROP_CFG_DROP_S_TAGGED_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_S_TAGGED_ENA, x)\n+\n+#define ANA_DROP_CFG_DROP_C_TAGGED_ENA           BIT(4)\n+#define ANA_DROP_CFG_DROP_C_TAGGED_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_C_TAGGED_ENA, x)\n+#define ANA_DROP_CFG_DROP_C_TAGGED_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_C_TAGGED_ENA, x)\n+\n+#define ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA      BIT(3)\n+#define ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA, x)\n+#define ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA, x)\n+\n+#define ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA      BIT(2)\n+#define ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, x)\n+#define ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, x)\n+\n+#define ANA_DROP_CFG_DROP_NULL_MAC_ENA           BIT(1)\n+#define ANA_DROP_CFG_DROP_NULL_MAC_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_NULL_MAC_ENA, x)\n+#define ANA_DROP_CFG_DROP_NULL_MAC_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_NULL_MAC_ENA, x)\n+\n+#define ANA_DROP_CFG_DROP_MC_SMAC_ENA            BIT(0)\n+#define ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x)\n+#define ANA_DROP_CFG_DROP_MC_SMAC_ENA_GET(x)\\\n+\tFIELD_GET(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x)\n+\n+/*      ANA:PORT:CPU_FWD_CFG */\n+#define ANA_CPU_FWD_CFG(g)        __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 24576, g, 10, 256, 96, 0, 1, 4)\n+\n+#define ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA         BIT(9)\n+#define ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA, x)\n+#define ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_SPV_COPY_ENA             BIT(8)\n+#define ANA_CPU_FWD_CFG_SPV_COPY_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_SPV_COPY_ENA, x)\n+#define ANA_CPU_FWD_CFG_SPV_COPY_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_SPV_COPY_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_VRAP_REDIR_ENA           BIT(7)\n+#define ANA_CPU_FWD_CFG_VRAP_REDIR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_VRAP_REDIR_ENA, x)\n+#define ANA_CPU_FWD_CFG_VRAP_REDIR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_VRAP_REDIR_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_MLD_REDIR_ENA            BIT(6)\n+#define ANA_CPU_FWD_CFG_MLD_REDIR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_MLD_REDIR_ENA, x)\n+#define ANA_CPU_FWD_CFG_MLD_REDIR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_MLD_REDIR_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_IGMP_REDIR_ENA           BIT(5)\n+#define ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA, x)\n+#define ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA       BIT(4)\n+#define ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA, x)\n+#define ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA             BIT(3)\n+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_SRC_COPY_ENA, x)\n+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_SRC_COPY_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA       BIT(2)\n+#define ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA, x)\n+#define ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA      BIT(1)\n+#define ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA, x)\n+#define ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA, x)\n+\n+#define ANA_CPU_FWD_CFG_OAM_ENA                  BIT(0)\n+#define ANA_CPU_FWD_CFG_OAM_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_CFG_OAM_ENA, x)\n+#define ANA_CPU_FWD_CFG_OAM_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_CFG_OAM_ENA, x)\n+\n+/*      ANA:PORT:CPU_FWD_BPDU_CFG */\n+#define ANA_CPU_FWD_BPDU_CFG(g)   __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 24576, g, 10, 256, 100, 0, 1, 4)\n+\n+#define ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA       GENMASK(31, 16)\n+#define ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA, x)\n+#define ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA, x)\n+\n+#define ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA      GENMASK(15, 0)\n+#define ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA, x)\n+#define ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA, x)\n+\n+/*      ANA:PORT:PORT_CFG */\n+#define ANA_PORT_CFG(g)           __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 24576, g, 10, 256, 112, 0, 1, 4)\n+\n+#define ANA_PORT_CFG_SRC_MIRROR_ENA              BIT(13)\n+#define ANA_PORT_CFG_SRC_MIRROR_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_SRC_MIRROR_ENA, x)\n+#define ANA_PORT_CFG_SRC_MIRROR_ENA_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_SRC_MIRROR_ENA, x)\n+\n+#define ANA_PORT_CFG_LIMIT_DROP                  BIT(12)\n+#define ANA_PORT_CFG_LIMIT_DROP_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LIMIT_DROP, x)\n+#define ANA_PORT_CFG_LIMIT_DROP_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LIMIT_DROP, x)\n+\n+#define ANA_PORT_CFG_LIMIT_CPU                   BIT(11)\n+#define ANA_PORT_CFG_LIMIT_CPU_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LIMIT_CPU, x)\n+#define ANA_PORT_CFG_LIMIT_CPU_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LIMIT_CPU, x)\n+\n+#define ANA_PORT_CFG_LOCKED_PORTMOVE_DROP        BIT(10)\n+#define ANA_PORT_CFG_LOCKED_PORTMOVE_DROP_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LOCKED_PORTMOVE_DROP, x)\n+#define ANA_PORT_CFG_LOCKED_PORTMOVE_DROP_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LOCKED_PORTMOVE_DROP, x)\n+\n+#define ANA_PORT_CFG_LOCKED_PORTMOVE_CPU         BIT(9)\n+#define ANA_PORT_CFG_LOCKED_PORTMOVE_CPU_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LOCKED_PORTMOVE_CPU, x)\n+#define ANA_PORT_CFG_LOCKED_PORTMOVE_CPU_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LOCKED_PORTMOVE_CPU, x)\n+\n+#define ANA_PORT_CFG_LEARNDROP                   BIT(8)\n+#define ANA_PORT_CFG_LEARNDROP_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LEARNDROP, x)\n+#define ANA_PORT_CFG_LEARNDROP_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LEARNDROP, x)\n+\n+#define ANA_PORT_CFG_LEARNCPU                    BIT(7)\n+#define ANA_PORT_CFG_LEARNCPU_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LEARNCPU, x)\n+#define ANA_PORT_CFG_LEARNCPU_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LEARNCPU, x)\n+\n+#define ANA_PORT_CFG_LEARNAUTO                   BIT(6)\n+#define ANA_PORT_CFG_LEARNAUTO_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LEARNAUTO, x)\n+#define ANA_PORT_CFG_LEARNAUTO_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LEARNAUTO, x)\n+\n+#define ANA_PORT_CFG_LEARN_ENA                   BIT(5)\n+#define ANA_PORT_CFG_LEARN_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_LEARN_ENA, x)\n+#define ANA_PORT_CFG_LEARN_ENA_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_LEARN_ENA, x)\n+\n+#define ANA_PORT_CFG_RECV_ENA                    BIT(4)\n+#define ANA_PORT_CFG_RECV_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_RECV_ENA, x)\n+#define ANA_PORT_CFG_RECV_ENA_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_RECV_ENA, x)\n+\n+#define ANA_PORT_CFG_PORTID_VAL                  GENMASK(3, 0)\n+#define ANA_PORT_CFG_PORTID_VAL_SET(x)\\\n+\tFIELD_PREP(ANA_PORT_CFG_PORTID_VAL, x)\n+#define ANA_PORT_CFG_PORTID_VAL_GET(x)\\\n+\tFIELD_GET(ANA_PORT_CFG_PORTID_VAL, x)\n+\n+/*      ANA:PFC:PFC_CFG */\n+#define ANA_PFC_CFG(g)            __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 28672, g, 9, 64, 0, 0, 1, 4)\n+\n+#define ANA_PFC_CFG_RX_PFC_ENA                   GENMASK(9, 2)\n+#define ANA_PFC_CFG_RX_PFC_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_PFC_CFG_RX_PFC_ENA, x)\n+#define ANA_PFC_CFG_RX_PFC_ENA_GET(x)\\\n+\tFIELD_GET(ANA_PFC_CFG_RX_PFC_ENA, x)\n+\n+#define ANA_PFC_CFG_FC_LINK_SPEED                GENMASK(1, 0)\n+#define ANA_PFC_CFG_FC_LINK_SPEED_SET(x)\\\n+\tFIELD_PREP(ANA_PFC_CFG_FC_LINK_SPEED, x)\n+#define ANA_PFC_CFG_FC_LINK_SPEED_GET(x)\\\n+\tFIELD_GET(ANA_PFC_CFG_FC_LINK_SPEED, x)\n+\n+/*      ANA:COMMON:AGGR_CFG */\n+#define ANA_AGGR_CFG              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 29248, 0, 1, 552, 0, 0, 1, 4)\n+\n+#define ANA_AGGR_CFG_AC_RND_ENA                  BIT(6)\n+#define ANA_AGGR_CFG_AC_RND_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_RND_ENA, x)\n+#define ANA_AGGR_CFG_AC_RND_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_RND_ENA, x)\n+\n+#define ANA_AGGR_CFG_AC_DMAC_ENA                 BIT(5)\n+#define ANA_AGGR_CFG_AC_DMAC_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_DMAC_ENA, x)\n+#define ANA_AGGR_CFG_AC_DMAC_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_DMAC_ENA, x)\n+\n+#define ANA_AGGR_CFG_AC_SMAC_ENA                 BIT(4)\n+#define ANA_AGGR_CFG_AC_SMAC_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_SMAC_ENA, x)\n+#define ANA_AGGR_CFG_AC_SMAC_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_SMAC_ENA, x)\n+\n+#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA         BIT(3)\n+#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA, x)\n+#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA, x)\n+\n+#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA           BIT(2)\n+#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA, x)\n+#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA, x)\n+\n+#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA           BIT(1)\n+#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA, x)\n+#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA, x)\n+\n+#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA           BIT(0)\n+#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_SET(x)\\\n+\tFIELD_PREP(ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, x)\n+#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_GET(x)\\\n+\tFIELD_GET(ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, x)\n+\n+/*      ANA:COMMON:CPUQ_CFG */\n+#define ANA_CPUQ_CFG              __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 29248, 0, 1, 552, 4, 0, 1, 4)\n+\n+#define ANA_CPUQ_CFG_CPUQ_MLD                    GENMASK(29, 27)\n+#define ANA_CPUQ_CFG_CPUQ_MLD_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_MLD, x)\n+#define ANA_CPUQ_CFG_CPUQ_MLD_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_MLD, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_IGMP                   GENMASK(26, 24)\n+#define ANA_CPUQ_CFG_CPUQ_IGMP_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_IGMP, x)\n+#define ANA_CPUQ_CFG_CPUQ_IGMP_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_IGMP, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL              GENMASK(23, 21)\n+#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_IPMC_CTRL, x)\n+#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_IPMC_CTRL, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE              GENMASK(20, 18)\n+#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_ALLBRIDGE, x)\n+#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_ALLBRIDGE, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE        GENMASK(17, 15)\n+#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE, x)\n+#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_SRC_COPY               GENMASK(14, 12)\n+#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_SRC_COPY, x)\n+#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_SRC_COPY, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_MAC_COPY               GENMASK(11, 9)\n+#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_MAC_COPY, x)\n+#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_MAC_COPY, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_LRN                    GENMASK(8, 6)\n+#define ANA_CPUQ_CFG_CPUQ_LRN_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_LRN, x)\n+#define ANA_CPUQ_CFG_CPUQ_LRN_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_LRN, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_MIRROR                 GENMASK(5, 3)\n+#define ANA_CPUQ_CFG_CPUQ_MIRROR_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_MIRROR, x)\n+#define ANA_CPUQ_CFG_CPUQ_MIRROR_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_MIRROR, x)\n+\n+#define ANA_CPUQ_CFG_CPUQ_SFLOW                  GENMASK(2, 0)\n+#define ANA_CPUQ_CFG_CPUQ_SFLOW_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_CFG_CPUQ_SFLOW, x)\n+#define ANA_CPUQ_CFG_CPUQ_SFLOW_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_CFG_CPUQ_SFLOW, x)\n+\n+/*      ANA:COMMON:CPUQ_8021_CFG */\n+#define ANA_CPUQ_8021_CFG(r)      __REG(TARGET_ANA,\\\n+\t\t\t\t\t0, 1, 29248, 0, 1, 552, 12, r, 16, 4)\n+\n+#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL          GENMASK(8, 6)\n+#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL, x)\n+#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL, x)\n+\n+#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL          GENMASK(5, 3)\n+#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL, x)\n+#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL, x)\n+\n+#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL           GENMASK(2, 0)\n+#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_SET(x)\\\n+\tFIELD_PREP(ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL, x)\n+#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_GET(x)\\\n+\tFIELD_GET(ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL, x)\n+\n+/*      CHIP_TOP:CUPHY_CFG:CUPHY_PORT_CFG */\n+#define CHIP_TOP_CUPHY_PORT_CFG(r) __REG(TARGET_CHIP_TOP,\\\n+\t\t\t\t\t0, 1, 12, 0, 1, 64, 20, r, 5, 4)\n+\n+#define CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA BIT(7)\n+#define CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA, x)\n+#define CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA, x)\n+\n+#define CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE        BIT(6)\n+#define CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE, x)\n+#define CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE, x)\n+\n+#define CHIP_TOP_CUPHY_PORT_CFG_MODE             GENMASK(5, 1)\n+#define CHIP_TOP_CUPHY_PORT_CFG_MODE_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_MODE, x)\n+#define CHIP_TOP_CUPHY_PORT_CFG_MODE_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_MODE, x)\n+\n+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA      BIT(0)\n+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, x)\n+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, x)\n+\n+/*      CHIP_TOP:CUPHY_CFG:CUPHY_LED_CFG */\n+#define CHIP_TOP_CUPHY_LED_CFG(r) __REG(TARGET_CHIP_TOP,\\\n+\t\t\t\t\t0, 1, 12, 0, 1, 64, 40, r, 5, 4)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS       BIT(11)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS, x)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE      BIT(10)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE, x)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE     GENMASK(9, 8)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE, x)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL      GENMASK(7, 6)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL, x)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY      GENMASK(5, 4)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY, x)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE    GENMASK(3, 2)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE, x)\n+\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE    GENMASK(1, 0)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE_SET(x)\\\n+\tFIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE, x)\n+#define CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE_GET(x)\\\n+\tFIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE, x)\n+\n+/*      DEV:PORT_MODE:CLOCK_CFG */\n+#define DEV_CLOCK_CFG(t)          __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 0, 0, 1, 20, 0, 0, 1, 4)\n+\n+#define DEV_CLOCK_CFG_MAC_TX_RST                 BIT(7)\n+#define DEV_CLOCK_CFG_MAC_TX_RST_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_MAC_TX_RST, x)\n+#define DEV_CLOCK_CFG_MAC_TX_RST_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_MAC_TX_RST, x)\n+\n+#define DEV_CLOCK_CFG_MAC_RX_RST                 BIT(6)\n+#define DEV_CLOCK_CFG_MAC_RX_RST_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_MAC_RX_RST, x)\n+#define DEV_CLOCK_CFG_MAC_RX_RST_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_MAC_RX_RST, x)\n+\n+#define DEV_CLOCK_CFG_PCS_TX_RST                 BIT(5)\n+#define DEV_CLOCK_CFG_PCS_TX_RST_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_PCS_TX_RST, x)\n+#define DEV_CLOCK_CFG_PCS_TX_RST_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_PCS_TX_RST, x)\n+\n+#define DEV_CLOCK_CFG_PCS_RX_RST                 BIT(4)\n+#define DEV_CLOCK_CFG_PCS_RX_RST_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_PCS_RX_RST, x)\n+#define DEV_CLOCK_CFG_PCS_RX_RST_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_PCS_RX_RST, x)\n+\n+#define DEV_CLOCK_CFG_PORT_RST                   BIT(3)\n+#define DEV_CLOCK_CFG_PORT_RST_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_PORT_RST, x)\n+#define DEV_CLOCK_CFG_PORT_RST_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_PORT_RST, x)\n+\n+#define DEV_CLOCK_CFG_PHY_RST                    BIT(2)\n+#define DEV_CLOCK_CFG_PHY_RST_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_PHY_RST, x)\n+#define DEV_CLOCK_CFG_PHY_RST_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_PHY_RST, x)\n+\n+#define DEV_CLOCK_CFG_LINK_SPEED                 GENMASK(1, 0)\n+#define DEV_CLOCK_CFG_LINK_SPEED_SET(x)\\\n+\tFIELD_PREP(DEV_CLOCK_CFG_LINK_SPEED, x)\n+#define DEV_CLOCK_CFG_LINK_SPEED_GET(x)\\\n+\tFIELD_GET(DEV_CLOCK_CFG_LINK_SPEED, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_ENA_CFG */\n+#define DEV_MAC_ENA_CFG(t)        __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 0, 0, 1, 4)\n+\n+#define DEV_MAC_ENA_CFG_RX_ENA                   BIT(4)\n+#define DEV_MAC_ENA_CFG_RX_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_ENA_CFG_RX_ENA, x)\n+#define DEV_MAC_ENA_CFG_RX_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_ENA_CFG_RX_ENA, x)\n+\n+#define DEV_MAC_ENA_CFG_TX_ENA                   BIT(0)\n+#define DEV_MAC_ENA_CFG_TX_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_ENA_CFG_TX_ENA, x)\n+#define DEV_MAC_ENA_CFG_TX_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_ENA_CFG_TX_ENA, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_MODE_CFG */\n+#define DEV_MAC_MODE_CFG(t)       __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 4, 0, 1, 4)\n+\n+#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA        BIT(8)\n+#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA, x)\n+#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA, x)\n+\n+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA           BIT(4)\n+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_MODE_CFG_GIGA_MODE_ENA, x)\n+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_MODE_CFG_GIGA_MODE_ENA, x)\n+\n+#define DEV_MAC_MODE_CFG_FDX_ENA                 BIT(0)\n+#define DEV_MAC_MODE_CFG_FDX_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_MODE_CFG_FDX_ENA, x)\n+#define DEV_MAC_MODE_CFG_FDX_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_MODE_CFG_FDX_ENA, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_MAXLEN_CFG */\n+#define DEV_MAC_MAXLEN_CFG(t)     __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 8, 0, 1, 4)\n+\n+#define DEV_MAC_MAXLEN_CFG_MAX_LEN               GENMASK(15, 0)\n+#define DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_MAXLEN_CFG_MAX_LEN, x)\n+#define DEV_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\\\n+\tFIELD_GET(DEV_MAC_MAXLEN_CFG_MAX_LEN, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_TAGS_CFG */\n+#define DEV_MAC_TAGS_CFG(t)       __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 12, 0, 1, 4)\n+\n+#define DEV_MAC_TAGS_CFG_TAG_ID                  GENMASK(31, 16)\n+#define DEV_MAC_TAGS_CFG_TAG_ID_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_TAGS_CFG_TAG_ID, x)\n+#define DEV_MAC_TAGS_CFG_TAG_ID_GET(x)\\\n+\tFIELD_GET(DEV_MAC_TAGS_CFG_TAG_ID, x)\n+\n+#define DEV_MAC_TAGS_CFG_PB_ENA                  BIT(1)\n+#define DEV_MAC_TAGS_CFG_PB_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_TAGS_CFG_PB_ENA, x)\n+#define DEV_MAC_TAGS_CFG_PB_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_TAGS_CFG_PB_ENA, x)\n+\n+#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA            BIT(0)\n+#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA, x)\n+#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA, x)\n+\n+#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA        BIT(2)\n+#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)\n+#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_IFG_CFG */\n+#define DEV_MAC_IFG_CFG(t)        __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 20, 0, 1, 4)\n+\n+#define DEV_MAC_IFG_CFG_OLD_IPG_CHECK            BIT(17)\n+#define DEV_MAC_IFG_CFG_OLD_IPG_CHECK_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_IFG_CFG_OLD_IPG_CHECK, x)\n+#define DEV_MAC_IFG_CFG_OLD_IPG_CHECK_GET(x)\\\n+\tFIELD_GET(DEV_MAC_IFG_CFG_OLD_IPG_CHECK, x)\n+\n+#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG           BIT(16)\n+#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_IFG_CFG_REDUCED_TX_IFG, x)\n+#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG_GET(x)\\\n+\tFIELD_GET(DEV_MAC_IFG_CFG_REDUCED_TX_IFG, x)\n+\n+#define DEV_MAC_IFG_CFG_TX_IFG                   GENMASK(12, 8)\n+#define DEV_MAC_IFG_CFG_TX_IFG_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_IFG_CFG_TX_IFG, x)\n+#define DEV_MAC_IFG_CFG_TX_IFG_GET(x)\\\n+\tFIELD_GET(DEV_MAC_IFG_CFG_TX_IFG, x)\n+\n+#define DEV_MAC_IFG_CFG_RX_IFG2                  GENMASK(7, 4)\n+#define DEV_MAC_IFG_CFG_RX_IFG2_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_IFG_CFG_RX_IFG2, x)\n+#define DEV_MAC_IFG_CFG_RX_IFG2_GET(x)\\\n+\tFIELD_GET(DEV_MAC_IFG_CFG_RX_IFG2, x)\n+\n+#define DEV_MAC_IFG_CFG_RX_IFG1                  GENMASK(3, 0)\n+#define DEV_MAC_IFG_CFG_RX_IFG1_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_IFG_CFG_RX_IFG1, x)\n+#define DEV_MAC_IFG_CFG_RX_IFG1_GET(x)\\\n+\tFIELD_GET(DEV_MAC_IFG_CFG_RX_IFG1, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_HDX_CFG */\n+#define DEV_MAC_HDX_CFG(t)        __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 24, 0, 1, 4)\n+\n+#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC          BIT(26)\n+#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_BYPASS_COL_SYNC, x)\n+#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_BYPASS_COL_SYNC, x)\n+\n+#define DEV_MAC_HDX_CFG_OB_ENA                   BIT(25)\n+#define DEV_MAC_HDX_CFG_OB_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_OB_ENA, x)\n+#define DEV_MAC_HDX_CFG_OB_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_OB_ENA, x)\n+\n+#define DEV_MAC_HDX_CFG_WEXC_DIS                 BIT(24)\n+#define DEV_MAC_HDX_CFG_WEXC_DIS_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_WEXC_DIS, x)\n+#define DEV_MAC_HDX_CFG_WEXC_DIS_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_WEXC_DIS, x)\n+\n+#define DEV_MAC_HDX_CFG_SEED                     GENMASK(23, 16)\n+#define DEV_MAC_HDX_CFG_SEED_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_SEED, x)\n+#define DEV_MAC_HDX_CFG_SEED_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_SEED, x)\n+\n+#define DEV_MAC_HDX_CFG_SEED_LOAD                BIT(12)\n+#define DEV_MAC_HDX_CFG_SEED_LOAD_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_SEED_LOAD, x)\n+#define DEV_MAC_HDX_CFG_SEED_LOAD_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_SEED_LOAD, x)\n+\n+#define DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA        BIT(8)\n+#define DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA, x)\n+#define DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA, x)\n+\n+#define DEV_MAC_HDX_CFG_LATE_COL_POS             GENMASK(6, 0)\n+#define DEV_MAC_HDX_CFG_LATE_COL_POS_SET(x)\\\n+\tFIELD_PREP(DEV_MAC_HDX_CFG_LATE_COL_POS, x)\n+#define DEV_MAC_HDX_CFG_LATE_COL_POS_GET(x)\\\n+\tFIELD_GET(DEV_MAC_HDX_CFG_LATE_COL_POS, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_FC_MAC_LOW_CFG */\n+#define DEV_FC_MAC_LOW_CFG(t)     __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 32, 0, 1, 4)\n+\n+#define DEV_FC_MAC_LOW_CFG_MAC_LOW               GENMASK(23, 0)\n+#define DEV_FC_MAC_LOW_CFG_MAC_LOW_SET(x)\\\n+\tFIELD_PREP(DEV_FC_MAC_LOW_CFG_MAC_LOW, x)\n+#define DEV_FC_MAC_LOW_CFG_MAC_LOW_GET(x)\\\n+\tFIELD_GET(DEV_FC_MAC_LOW_CFG_MAC_LOW, x)\n+\n+/*      DEV:MAC_CFG_STATUS:MAC_FC_MAC_HIGH_CFG */\n+#define DEV_FC_MAC_HIGH_CFG(t)    __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 20, 0, 1, 44, 36, 0, 1, 4)\n+\n+#define DEV_FC_MAC_HIGH_CFG_MAC_HIGH             GENMASK(23, 0)\n+#define DEV_FC_MAC_HIGH_CFG_MAC_HIGH_SET(x)\\\n+\tFIELD_PREP(DEV_FC_MAC_HIGH_CFG_MAC_HIGH, x)\n+#define DEV_FC_MAC_HIGH_CFG_MAC_HIGH_GET(x)\\\n+\tFIELD_GET(DEV_FC_MAC_HIGH_CFG_MAC_HIGH, x)\n+\n+/*      DEV:PCS1G_CFG_STATUS:PCS1G_CFG */\n+#define DEV_PCS1G_CFG(t)          __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 64, 0, 1, 68, 0, 0, 1, 4)\n+\n+#define DEV_PCS1G_CFG_LINK_STATUS_TYPE           BIT(4)\n+#define DEV_PCS1G_CFG_LINK_STATUS_TYPE_SET(x)\\\n+\tFIELD_PREP(DEV_PCS1G_CFG_LINK_STATUS_TYPE, x)\n+#define DEV_PCS1G_CFG_LINK_STATUS_TYPE_GET(x)\\\n+\tFIELD_GET(DEV_PCS1G_CFG_LINK_STATUS_TYPE, x)\n+\n+#define DEV_PCS1G_CFG_AN_LINK_CTRL_ENA           BIT(1)\n+#define DEV_PCS1G_CFG_AN_LINK_CTRL_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_PCS1G_CFG_AN_LINK_CTRL_ENA, x)\n+#define DEV_PCS1G_CFG_AN_LINK_CTRL_ENA_GET(x)\\\n+\tFIELD_GET(DEV_PCS1G_CFG_AN_LINK_CTRL_ENA, x)\n+\n+#define DEV_PCS1G_CFG_PCS_ENA                    BIT(0)\n+#define DEV_PCS1G_CFG_PCS_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_PCS1G_CFG_PCS_ENA, x)\n+#define DEV_PCS1G_CFG_PCS_ENA_GET(x)\\\n+\tFIELD_GET(DEV_PCS1G_CFG_PCS_ENA, x)\n+\n+/*      DEV:PCS1G_CFG_STATUS:PCS1G_SD_CFG */\n+#define DEV_PCS1G_SD_CFG(t)       __REG(TARGET_DEV,\\\n+\t\t\t\t\tt, 9, 64, 0, 1, 68, 8, 0, 1, 4)\n+\n+#define DEV_PCS1G_SD_CFG_SD_SEL                  BIT(8)\n+#define DEV_PCS1G_SD_CFG_SD_SEL_SET(x)\\\n+\tFIELD_PREP(DEV_PCS1G_SD_CFG_SD_SEL, x)\n+#define DEV_PCS1G_SD_CFG_SD_SEL_GET(x)\\\n+\tFIELD_GET(DEV_PCS1G_SD_CFG_SD_SEL, x)\n+\n+#define DEV_PCS1G_SD_CFG_SD_POL                  BIT(4)\n+#define DEV_PCS1G_SD_CFG_SD_POL_SET(x)\\\n+\tFIELD_PREP(DEV_PCS1G_SD_CFG_SD_POL, x)\n+#define DEV_PCS1G_SD_CFG_SD_POL_GET(x)\\\n+\tFIELD_GET(DEV_PCS1G_SD_CFG_SD_POL, x)\n+\n+#define DEV_PCS1G_SD_CFG_SD_ENA                  BIT(0)\n+#define DEV_PCS1G_SD_CFG_SD_ENA_SET(x)\\\n+\tFIELD_PREP(DEV_PCS1G_SD_CFG_SD_ENA, x)\n+#define DEV_PCS1G_SD_CFG_SD_ENA_GET(x)\\\n+\tFIELD_GET(DEV_PCS1G_SD_CFG_SD_ENA, x)\n+\n+/*      DEVCPU_GCB:CHIP_REGS:FEAT_DISABLE */\n+#define GCB_FEAT_DISABLE          __REG(TARGET_GCB,\\\n+\t\t\t\t\t0, 1, 0, 0, 1, 28, 20, 0, 1, 4)\n+\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS     BIT(0)\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS    BIT(1)\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS BIT(2)\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS BIT(3)\n+#define GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS     BIT(4)\n+#define GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_DD_DIS             BIT(5)\n+#define GCB_FEAT_DISABLE_FEAT_DD_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_DD_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_DD_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_DD_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_TSN_DIS            BIT(6)\n+#define GCB_FEAT_DISABLE_FEAT_TSN_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_TSN_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_TSN_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_TSN_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_PTP_DIS            BIT(7)\n+#define GCB_FEAT_DISABLE_FEAT_PTP_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_PTP_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_PTP_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_PTP_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_FRER_DIS           BIT(8)\n+#define GCB_FEAT_DISABLE_FEAT_FRER_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_FRER_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_FRER_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_FRER_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS      GENMASK(14, 12)\n+#define GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS         GENMASK(16, 15)\n+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_RGMII_DIS          GENMASK(18, 17)\n+#define GCB_FEAT_DISABLE_FEAT_RGMII_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_RGMII_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_RGMII_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_RGMII_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_SGMII_DIS          GENMASK(20, 19)\n+#define GCB_FEAT_DISABLE_FEAT_SGMII_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_SGMII_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_SGMII_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_SGMII_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_QSGMII_DIS         BIT(21)\n+#define GCB_FEAT_DISABLE_FEAT_QSGMII_DIS_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_QSGMII_DIS, x)\n+#define GCB_FEAT_DISABLE_FEAT_QSGMII_DIS_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_QSGMII_DIS, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED       BIT(22)\n+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED, x)\n+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED, x)\n+\n+#define GCB_FEAT_DISABLE_FEAT_WDT_ENABLED        BIT(25)\n+#define GCB_FEAT_DISABLE_FEAT_WDT_ENABLED_SET(x)\\\n+\tFIELD_PREP(GCB_FEAT_DISABLE_FEAT_WDT_ENABLED, x)\n+#define GCB_FEAT_DISABLE_FEAT_WDT_ENABLED_GET(x)\\\n+\tFIELD_GET(GCB_FEAT_DISABLE_FEAT_WDT_ENABLED, x)\n+\n+/*      HSIO:HW_CFGSTAT:HW_CFG */\n+#define HSIO_HW_CFG               __REG(TARGET_HSIO,\\\n+\t\t\t\t\t0, 1, 72, 0, 1, 44, 0, 0, 1, 4)\n+\n+#define HSIO_HW_CFG_RGMII_0_CFG                  BIT(10)\n+#define HSIO_HW_CFG_RGMII_0_CFG_SET(x)\\\n+\tFIELD_PREP(HSIO_HW_CFG_RGMII_0_CFG, x)\n+#define HSIO_HW_CFG_RGMII_0_CFG_GET(x)\\\n+\tFIELD_GET(HSIO_HW_CFG_RGMII_0_CFG, x)\n+\n+#define HSIO_HW_CFG_GMII_ENA                     GENMASK(9, 1)\n+#define HSIO_HW_CFG_GMII_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_HW_CFG_GMII_ENA, x)\n+#define HSIO_HW_CFG_GMII_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_HW_CFG_GMII_ENA, x)\n+\n+#define HSIO_HW_CFG_QSGMII_ENA                   BIT(0)\n+#define HSIO_HW_CFG_QSGMII_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_HW_CFG_QSGMII_ENA, x)\n+#define HSIO_HW_CFG_QSGMII_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_HW_CFG_QSGMII_ENA, x)\n+\n+/*      HSIO:HW_CFGSTAT:RGMII_CFG */\n+#define HSIO_RGMII_CFG(r)         __REG(TARGET_HSIO,\\\n+\t\t\t\t\t0, 1, 72, 0, 1, 44, 12, r, 2, 4)\n+\n+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS         BIT(15)\n+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_RX_LINK_STATUS, x)\n+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_RX_LINK_STATUS, x)\n+\n+#define HSIO_RGMII_CFG_IB_RX_DUPLEX              BIT(14)\n+#define HSIO_RGMII_CFG_IB_RX_DUPLEX_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_RX_DUPLEX, x)\n+#define HSIO_RGMII_CFG_IB_RX_DUPLEX_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_RX_DUPLEX, x)\n+\n+#define HSIO_RGMII_CFG_IB_RX_SPEED               GENMASK(13, 12)\n+#define HSIO_RGMII_CFG_IB_RX_SPEED_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_RX_SPEED, x)\n+#define HSIO_RGMII_CFG_IB_RX_SPEED_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_RX_SPEED, x)\n+\n+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS         BIT(11)\n+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_TX_LINK_STATUS, x)\n+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_TX_LINK_STATUS, x)\n+\n+#define HSIO_RGMII_CFG_IB_TX_FDX                 BIT(10)\n+#define HSIO_RGMII_CFG_IB_TX_FDX_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_TX_FDX, x)\n+#define HSIO_RGMII_CFG_IB_TX_FDX_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_TX_FDX, x)\n+\n+#define HSIO_RGMII_CFG_IB_TX_MII_SPD             BIT(9)\n+#define HSIO_RGMII_CFG_IB_TX_MII_SPD_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_TX_MII_SPD, x)\n+#define HSIO_RGMII_CFG_IB_TX_MII_SPD_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_TX_MII_SPD, x)\n+\n+#define HSIO_RGMII_CFG_IB_TX_SPD_1G              BIT(8)\n+#define HSIO_RGMII_CFG_IB_TX_SPD_1G_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_TX_SPD_1G, x)\n+#define HSIO_RGMII_CFG_IB_TX_SPD_1G_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_TX_SPD_1G, x)\n+\n+#define HSIO_RGMII_CFG_IB_TX_ENA                 BIT(7)\n+#define HSIO_RGMII_CFG_IB_TX_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_TX_ENA, x)\n+#define HSIO_RGMII_CFG_IB_TX_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_TX_ENA, x)\n+\n+#define HSIO_RGMII_CFG_IB_RX_ENA                 BIT(6)\n+#define HSIO_RGMII_CFG_IB_RX_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_RX_ENA, x)\n+#define HSIO_RGMII_CFG_IB_RX_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_RX_ENA, x)\n+\n+#define HSIO_RGMII_CFG_IB_ENA                    BIT(5)\n+#define HSIO_RGMII_CFG_IB_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_IB_ENA, x)\n+#define HSIO_RGMII_CFG_IB_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_IB_ENA, x)\n+\n+#define HSIO_RGMII_CFG_TX_CLK_CFG                GENMASK(4, 2)\n+#define HSIO_RGMII_CFG_TX_CLK_CFG_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_TX_CLK_CFG, x)\n+#define HSIO_RGMII_CFG_TX_CLK_CFG_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_TX_CLK_CFG, x)\n+\n+#define HSIO_RGMII_CFG_RGMII_TX_RST              BIT(1)\n+#define HSIO_RGMII_CFG_RGMII_TX_RST_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_RGMII_TX_RST, x)\n+#define HSIO_RGMII_CFG_RGMII_TX_RST_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_RGMII_TX_RST, x)\n+\n+#define HSIO_RGMII_CFG_RGMII_RX_RST              BIT(0)\n+#define HSIO_RGMII_CFG_RGMII_RX_RST_SET(x)\\\n+\tFIELD_PREP(HSIO_RGMII_CFG_RGMII_RX_RST, x)\n+#define HSIO_RGMII_CFG_RGMII_RX_RST_GET(x)\\\n+\tFIELD_GET(HSIO_RGMII_CFG_RGMII_RX_RST, x)\n+\n+/*      HSIO:HW_CFGSTAT:DLL_CFG */\n+#define HSIO_DLL_CFG(r)           __REG(TARGET_HSIO,\\\n+\t\t\t\t\t0, 1, 72, 0, 1, 44, 28, r, 4, 4)\n+\n+#define HSIO_DLL_CFG_DLL_CLK_ENA                 BIT(20)\n+#define HSIO_DLL_CFG_DLL_CLK_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_DLL_CLK_ENA, x)\n+#define HSIO_DLL_CFG_DLL_CLK_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_DLL_CLK_ENA, x)\n+\n+#define HSIO_DLL_CFG_BIST_PASS                   BIT(19)\n+#define HSIO_DLL_CFG_BIST_PASS_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_BIST_PASS, x)\n+#define HSIO_DLL_CFG_BIST_PASS_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_BIST_PASS, x)\n+\n+#define HSIO_DLL_CFG_BIST_END                    BIT(18)\n+#define HSIO_DLL_CFG_BIST_END_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_BIST_END, x)\n+#define HSIO_DLL_CFG_BIST_END_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_BIST_END, x)\n+\n+#define HSIO_DLL_CFG_BIST_START                  BIT(17)\n+#define HSIO_DLL_CFG_BIST_START_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_BIST_START, x)\n+#define HSIO_DLL_CFG_BIST_START_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_BIST_START, x)\n+\n+#define HSIO_DLL_CFG_TAP_SEL                     GENMASK(16, 10)\n+#define HSIO_DLL_CFG_TAP_SEL_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_TAP_SEL, x)\n+#define HSIO_DLL_CFG_TAP_SEL_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_TAP_SEL, x)\n+\n+#define HSIO_DLL_CFG_TAP_ADJ                     GENMASK(9, 3)\n+#define HSIO_DLL_CFG_TAP_ADJ_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_TAP_ADJ, x)\n+#define HSIO_DLL_CFG_TAP_ADJ_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_TAP_ADJ, x)\n+\n+#define HSIO_DLL_CFG_DELAY_ENA                   BIT(2)\n+#define HSIO_DLL_CFG_DELAY_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_DELAY_ENA, x)\n+#define HSIO_DLL_CFG_DELAY_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_DELAY_ENA, x)\n+\n+#define HSIO_DLL_CFG_DLL_ENA                     BIT(1)\n+#define HSIO_DLL_CFG_DLL_ENA_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_DLL_ENA, x)\n+#define HSIO_DLL_CFG_DLL_ENA_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_DLL_ENA, x)\n+\n+#define HSIO_DLL_CFG_DLL_RST                     BIT(0)\n+#define HSIO_DLL_CFG_DLL_RST_SET(x)\\\n+\tFIELD_PREP(HSIO_DLL_CFG_DLL_RST, x)\n+#define HSIO_DLL_CFG_DLL_RST_GET(x)\\\n+\tFIELD_GET(HSIO_DLL_CFG_DLL_RST, x)\n+\n+/*      DEVCPU_QS:XTR:XTR_FLUSH */\n+#define QS_XTR_FLUSH              __REG(TARGET_QS,\\\n+\t\t\t\t\t0, 1, 0, 0, 1, 36, 24, 0, 1, 4)\n+\n+#define QS_XTR_FLUSH_FLUSH                       GENMASK(1, 0)\n+#define QS_XTR_FLUSH_FLUSH_SET(x)\\\n+\tFIELD_PREP(QS_XTR_FLUSH_FLUSH, x)\n+#define QS_XTR_FLUSH_FLUSH_GET(x)\\\n+\tFIELD_GET(QS_XTR_FLUSH_FLUSH, x)\n+\n+/*      DEVCPU_QS:INJ:INJ_GRP_CFG */\n+#define QS_INJ_GRP_CFG(r)         __REG(TARGET_QS,\\\n+\t\t\t\t\t0, 1, 36, 0, 1, 40, 0, r, 2, 4)\n+\n+#define QS_INJ_GRP_CFG_MODE                      GENMASK(3, 2)\n+#define QS_INJ_GRP_CFG_MODE_SET(x)\\\n+\tFIELD_PREP(QS_INJ_GRP_CFG_MODE, x)\n+#define QS_INJ_GRP_CFG_MODE_GET(x)\\\n+\tFIELD_GET(QS_INJ_GRP_CFG_MODE, x)\n+\n+#define QS_INJ_GRP_CFG_BYTE_SWAP                 BIT(0)\n+#define QS_INJ_GRP_CFG_BYTE_SWAP_SET(x)\\\n+\tFIELD_PREP(QS_INJ_GRP_CFG_BYTE_SWAP, x)\n+#define QS_INJ_GRP_CFG_BYTE_SWAP_GET(x)\\\n+\tFIELD_GET(QS_INJ_GRP_CFG_BYTE_SWAP, x)\n+\n+/*      DEVCPU_QS:INJ:INJ_CTRL */\n+#define QS_INJ_CTRL(r)            __REG(TARGET_QS,\\\n+\t\t\t\t\t0, 1, 36, 0, 1, 40, 16, r, 2, 4)\n+\n+#define QS_INJ_CTRL_GAP_SIZE                     GENMASK(24, 21)\n+#define QS_INJ_CTRL_GAP_SIZE_SET(x)\\\n+\tFIELD_PREP(QS_INJ_CTRL_GAP_SIZE, x)\n+#define QS_INJ_CTRL_GAP_SIZE_GET(x)\\\n+\tFIELD_GET(QS_INJ_CTRL_GAP_SIZE, x)\n+\n+#define QS_INJ_CTRL_ABORT                        BIT(20)\n+#define QS_INJ_CTRL_ABORT_SET(x)\\\n+\tFIELD_PREP(QS_INJ_CTRL_ABORT, x)\n+#define QS_INJ_CTRL_ABORT_GET(x)\\\n+\tFIELD_GET(QS_INJ_CTRL_ABORT, x)\n+\n+#define QS_INJ_CTRL_EOF                          BIT(19)\n+#define QS_INJ_CTRL_EOF_SET(x)\\\n+\tFIELD_PREP(QS_INJ_CTRL_EOF, x)\n+#define QS_INJ_CTRL_EOF_GET(x)\\\n+\tFIELD_GET(QS_INJ_CTRL_EOF, x)\n+\n+#define QS_INJ_CTRL_SOF                          BIT(18)\n+#define QS_INJ_CTRL_SOF_SET(x)\\\n+\tFIELD_PREP(QS_INJ_CTRL_SOF, x)\n+#define QS_INJ_CTRL_SOF_GET(x)\\\n+\tFIELD_GET(QS_INJ_CTRL_SOF, x)\n+\n+#define QS_INJ_CTRL_VLD_BYTES                    GENMASK(17, 16)\n+#define QS_INJ_CTRL_VLD_BYTES_SET(x)\\\n+\tFIELD_PREP(QS_INJ_CTRL_VLD_BYTES, x)\n+#define QS_INJ_CTRL_VLD_BYTES_GET(x)\\\n+\tFIELD_GET(QS_INJ_CTRL_VLD_BYTES, x)\n+\n+/*      QSYS:SYSTEM:PORT_MODE */\n+#define QSYS_PORT_MODE(r)         __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 14336, 0, 1, 240, 0, r, 11, 4)\n+\n+#define QSYS_PORT_MODE_DEQUEUE_DIS               BIT(1)\n+#define QSYS_PORT_MODE_DEQUEUE_DIS_SET(x)\\\n+\tFIELD_PREP(QSYS_PORT_MODE_DEQUEUE_DIS, x)\n+#define QSYS_PORT_MODE_DEQUEUE_DIS_GET(x)\\\n+\tFIELD_GET(QSYS_PORT_MODE_DEQUEUE_DIS, x)\n+\n+#define QSYS_PORT_MODE_DEQUEUE_LATE              BIT(0)\n+#define QSYS_PORT_MODE_DEQUEUE_LATE_SET(x)\\\n+\tFIELD_PREP(QSYS_PORT_MODE_DEQUEUE_LATE, x)\n+#define QSYS_PORT_MODE_DEQUEUE_LATE_GET(x)\\\n+\tFIELD_GET(QSYS_PORT_MODE_DEQUEUE_LATE, x)\n+\n+/*      QSYS:SYSTEM:SWITCH_PORT_MODE */\n+#define QSYS_SW_PORT_MODE(r)      __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 14336, 0, 1, 240, 88, r, 10, 4)\n+\n+#define QSYS_SW_PORT_MODE_PORT_ENA               BIT(19)\n+#define QSYS_SW_PORT_MODE_PORT_ENA_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_PORT_ENA, x)\n+#define QSYS_SW_PORT_MODE_PORT_ENA_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_PORT_ENA, x)\n+\n+#define QSYS_SW_PORT_MODE_IDEQ_DIS               BIT(18)\n+#define QSYS_SW_PORT_MODE_IDEQ_DIS_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_IDEQ_DIS, x)\n+#define QSYS_SW_PORT_MODE_IDEQ_DIS_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_IDEQ_DIS, x)\n+\n+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG           GENMASK(17, 15)\n+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_SCH_NEXT_CFG, x)\n+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_SCH_NEXT_CFG, x)\n+\n+#define QSYS_SW_PORT_MODE_YEL_RSRVD              BIT(14)\n+#define QSYS_SW_PORT_MODE_YEL_RSRVD_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_YEL_RSRVD, x)\n+#define QSYS_SW_PORT_MODE_YEL_RSRVD_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_YEL_RSRVD, x)\n+\n+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE      BIT(13)\n+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_INGRESS_DROP_MODE, x)\n+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_INGRESS_DROP_MODE, x)\n+\n+#define QSYS_SW_PORT_MODE_TX_PFC_ENA             GENMASK(12, 5)\n+#define QSYS_SW_PORT_MODE_TX_PFC_ENA_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_TX_PFC_ENA, x)\n+#define QSYS_SW_PORT_MODE_TX_PFC_ENA_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_TX_PFC_ENA, x)\n+\n+#define QSYS_SW_PORT_MODE_TX_PFC_MODE            BIT(4)\n+#define QSYS_SW_PORT_MODE_TX_PFC_MODE_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_TX_PFC_MODE, x)\n+#define QSYS_SW_PORT_MODE_TX_PFC_MODE_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_TX_PFC_MODE, x)\n+\n+#define QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE      BIT(3)\n+#define QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE, x)\n+#define QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE, x)\n+\n+#define QSYS_SW_PORT_MODE_AGING_MODE             GENMASK(2, 1)\n+#define QSYS_SW_PORT_MODE_AGING_MODE_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_AGING_MODE, x)\n+#define QSYS_SW_PORT_MODE_AGING_MODE_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_AGING_MODE, x)\n+\n+#define QSYS_SW_PORT_MODE_HOL_PROTECTED          BIT(0)\n+#define QSYS_SW_PORT_MODE_HOL_PROTECTED_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_PORT_MODE_HOL_PROTECTED, x)\n+#define QSYS_SW_PORT_MODE_HOL_PROTECTED_GET(x)\\\n+\tFIELD_GET(QSYS_SW_PORT_MODE_HOL_PROTECTED, x)\n+\n+/*      QSYS:SYSTEM:EGR_NO_SHARING */\n+#define QSYS_EGR_NO_SHARING       __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 14336, 0, 1, 240, 176, 0, 1, 4)\n+\n+#define QSYS_EGR_NO_SHARING_EGR_NO_SHARING       GENMASK(9, 0)\n+#define QSYS_EGR_NO_SHARING_EGR_NO_SHARING_SET(x)\\\n+\tFIELD_PREP(QSYS_EGR_NO_SHARING_EGR_NO_SHARING, x)\n+#define QSYS_EGR_NO_SHARING_EGR_NO_SHARING_GET(x)\\\n+\tFIELD_GET(QSYS_EGR_NO_SHARING_EGR_NO_SHARING, x)\n+\n+/*      QSYS:SYSTEM:SW_STATUS */\n+#define QSYS_SW_STATUS(r)         __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 14336, 0, 1, 240, 180, r, 10, 4)\n+\n+#define QSYS_SW_STATUS_EQ_AVAIL                  GENMASK(7, 0)\n+#define QSYS_SW_STATUS_EQ_AVAIL_SET(x)\\\n+\tFIELD_PREP(QSYS_SW_STATUS_EQ_AVAIL, x)\n+#define QSYS_SW_STATUS_EQ_AVAIL_GET(x)\\\n+\tFIELD_GET(QSYS_SW_STATUS_EQ_AVAIL, x)\n+\n+/*      QSYS:SYSTEM:EXT_CPU_CFG */\n+#define QSYS_EXT_CPU_CFG          __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 14336, 0, 1, 240, 220, 0, 1, 4)\n+\n+#define QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA        BIT(14)\n+#define QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_SET(x)\\\n+\tFIELD_PREP(QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA, x)\n+#define QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_GET(x)\\\n+\tFIELD_GET(QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA, x)\n+\n+#define QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA        BIT(13)\n+#define QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_SET(x)\\\n+\tFIELD_PREP(QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA, x)\n+#define QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_GET(x)\\\n+\tFIELD_GET(QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA, x)\n+\n+#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT            GENMASK(12, 8)\n+#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_SET(x)\\\n+\tFIELD_PREP(QSYS_EXT_CPU_CFG_EXT_CPU_PORT, x)\n+#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_GET(x)\\\n+\tFIELD_GET(QSYS_EXT_CPU_CFG_EXT_CPU_PORT, x)\n+\n+#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK            GENMASK(7, 0)\n+#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_SET(x)\\\n+\tFIELD_PREP(QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK, x)\n+#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_GET(x)\\\n+\tFIELD_GET(QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK, x)\n+\n+/*      QSYS:SYSTEM:CPU_GROUP_MAP */\n+#define QSYS_CPU_GROUP_MAP        __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 14336, 0, 1, 240, 224, 0, 1, 4)\n+\n+#define QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP         GENMASK(7, 0)\n+#define QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP_SET(x)\\\n+\tFIELD_PREP(QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP, x)\n+#define QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP_GET(x)\\\n+\tFIELD_GET(QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP, x)\n+\n+/*      QSYS:RES_CTRL:RES_CFG */\n+#define QSYS_RES_CFG(g)           __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 16384, g, 1024, 8, 0, 0, 1, 4)\n+\n+#define QSYS_RES_CFG_WM_HIGH                     GENMASK(8, 0)\n+#define QSYS_RES_CFG_WM_HIGH_SET(x)\\\n+\tFIELD_PREP(QSYS_RES_CFG_WM_HIGH, x)\n+#define QSYS_RES_CFG_WM_HIGH_GET(x)\\\n+\tFIELD_GET(QSYS_RES_CFG_WM_HIGH, x)\n+\n+/*      QSYS:DROP_CFG:EGR_DROP_MODE */\n+#define QSYS_EGR_DROP_MODE        __REG(TARGET_QSYS,\\\n+\t\t\t\t\t0, 1, 12736, 0, 1, 8, 0, 0, 1, 4)\n+\n+#define QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE      GENMASK(9, 0)\n+#define QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_SET(x)\\\n+\tFIELD_PREP(QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE, x)\n+#define QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_GET(x)\\\n+\tFIELD_GET(QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE, x)\n+\n+/*      REW:PORT:PORT_VLAN_CFG */\n+#define REW_PORT_VLAN_CFG(g)      __REG(TARGET_REW,\\\n+\t\t\t\t\t0, 1, 4096, g, 11, 128, 0, 0, 1, 4)\n+\n+#define REW_PORT_VLAN_CFG_PORT_TPID              GENMASK(31, 16)\n+#define REW_PORT_VLAN_CFG_PORT_TPID_SET(x)\\\n+\tFIELD_PREP(REW_PORT_VLAN_CFG_PORT_TPID, x)\n+#define REW_PORT_VLAN_CFG_PORT_TPID_GET(x)\\\n+\tFIELD_GET(REW_PORT_VLAN_CFG_PORT_TPID, x)\n+\n+#define REW_PORT_VLAN_CFG_PORT_DEI               BIT(15)\n+#define REW_PORT_VLAN_CFG_PORT_DEI_SET(x)\\\n+\tFIELD_PREP(REW_PORT_VLAN_CFG_PORT_DEI, x)\n+#define REW_PORT_VLAN_CFG_PORT_DEI_GET(x)\\\n+\tFIELD_GET(REW_PORT_VLAN_CFG_PORT_DEI, x)\n+\n+#define REW_PORT_VLAN_CFG_PORT_PCP               GENMASK(14, 12)\n+#define REW_PORT_VLAN_CFG_PORT_PCP_SET(x)\\\n+\tFIELD_PREP(REW_PORT_VLAN_CFG_PORT_PCP, x)\n+#define REW_PORT_VLAN_CFG_PORT_PCP_GET(x)\\\n+\tFIELD_GET(REW_PORT_VLAN_CFG_PORT_PCP, x)\n+\n+#define REW_PORT_VLAN_CFG_PORT_VID               GENMASK(11, 0)\n+#define REW_PORT_VLAN_CFG_PORT_VID_SET(x)\\\n+\tFIELD_PREP(REW_PORT_VLAN_CFG_PORT_VID, x)\n+#define REW_PORT_VLAN_CFG_PORT_VID_GET(x)\\\n+\tFIELD_GET(REW_PORT_VLAN_CFG_PORT_VID, x)\n+\n+/*      REW:PORT:TAG_CFG */\n+#define REW_TAG_CFG(g)            __REG(TARGET_REW,\\\n+\t\t\t\t\t0, 1, 4096, g, 11, 128, 4, 0, 1, 4)\n+\n+#define REW_TAG_CFG_TAG_CFG                      GENMASK(8, 7)\n+#define REW_TAG_CFG_TAG_CFG_SET(x)\\\n+\tFIELD_PREP(REW_TAG_CFG_TAG_CFG, x)\n+#define REW_TAG_CFG_TAG_CFG_GET(x)\\\n+\tFIELD_GET(REW_TAG_CFG_TAG_CFG, x)\n+\n+#define REW_TAG_CFG_TAG_TPID_CFG                 GENMASK(6, 5)\n+#define REW_TAG_CFG_TAG_TPID_CFG_SET(x)\\\n+\tFIELD_PREP(REW_TAG_CFG_TAG_TPID_CFG, x)\n+#define REW_TAG_CFG_TAG_TPID_CFG_GET(x)\\\n+\tFIELD_GET(REW_TAG_CFG_TAG_TPID_CFG, x)\n+\n+#define REW_TAG_CFG_TAG_VID_CFG                  BIT(4)\n+#define REW_TAG_CFG_TAG_VID_CFG_SET(x)\\\n+\tFIELD_PREP(REW_TAG_CFG_TAG_VID_CFG, x)\n+#define REW_TAG_CFG_TAG_VID_CFG_GET(x)\\\n+\tFIELD_GET(REW_TAG_CFG_TAG_VID_CFG, x)\n+\n+#define REW_TAG_CFG_TAG_PCP_CFG                  GENMASK(3, 2)\n+#define REW_TAG_CFG_TAG_PCP_CFG_SET(x)\\\n+\tFIELD_PREP(REW_TAG_CFG_TAG_PCP_CFG, x)\n+#define REW_TAG_CFG_TAG_PCP_CFG_GET(x)\\\n+\tFIELD_GET(REW_TAG_CFG_TAG_PCP_CFG, x)\n+\n+#define REW_TAG_CFG_TAG_DEI_CFG                  GENMASK(1, 0)\n+#define REW_TAG_CFG_TAG_DEI_CFG_SET(x)\\\n+\tFIELD_PREP(REW_TAG_CFG_TAG_DEI_CFG, x)\n+#define REW_TAG_CFG_TAG_DEI_CFG_GET(x)\\\n+\tFIELD_GET(REW_TAG_CFG_TAG_DEI_CFG, x)\n+\n+/*      REW:PORT:PORT_CFG */\n+#define REW_PORT_CFG(g)           __REG(TARGET_REW,\\\n+\t\t\t\t\t0, 1, 4096, g, 11, 128, 8, 0, 1, 4)\n+\n+#define REW_PORT_CFG_ES0_EN                      BIT(4)\n+#define REW_PORT_CFG_ES0_EN_SET(x)\\\n+\tFIELD_PREP(REW_PORT_CFG_ES0_EN, x)\n+#define REW_PORT_CFG_ES0_EN_GET(x)\\\n+\tFIELD_GET(REW_PORT_CFG_ES0_EN, x)\n+\n+#define REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG       GENMASK(3, 2)\n+#define REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG_SET(x)\\\n+\tFIELD_PREP(REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG, x)\n+#define REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG_GET(x)\\\n+\tFIELD_GET(REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG, x)\n+\n+#define REW_PORT_CFG_FCS_UPDATE_CPU_ENA          BIT(1)\n+#define REW_PORT_CFG_FCS_UPDATE_CPU_ENA_SET(x)\\\n+\tFIELD_PREP(REW_PORT_CFG_FCS_UPDATE_CPU_ENA, x)\n+#define REW_PORT_CFG_FCS_UPDATE_CPU_ENA_GET(x)\\\n+\tFIELD_GET(REW_PORT_CFG_FCS_UPDATE_CPU_ENA, x)\n+\n+#define REW_PORT_CFG_NO_REWRITE                  BIT(0)\n+#define REW_PORT_CFG_NO_REWRITE_SET(x)\\\n+\tFIELD_PREP(REW_PORT_CFG_NO_REWRITE, x)\n+#define REW_PORT_CFG_NO_REWRITE_GET(x)\\\n+\tFIELD_GET(REW_PORT_CFG_NO_REWRITE, x)\n+\n+/*      SYS:SYSTEM:RESET_CFG */\n+#define SYS_RESET_CFG             __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4160, 0, 1, 184, 0, 0, 1, 4)\n+\n+#define SYS_RESET_CFG_CORE_ENA                   BIT(0)\n+#define SYS_RESET_CFG_CORE_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_RESET_CFG_CORE_ENA, x)\n+#define SYS_RESET_CFG_CORE_ENA_GET(x)\\\n+\tFIELD_GET(SYS_RESET_CFG_CORE_ENA, x)\n+\n+/*      SYS:SYSTEM:PORT_MODE */\n+#define SYS_PORT_MODE(r)          __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4160, 0, 1, 184, 48, r, 11, 4)\n+\n+#define SYS_PORT_MODE_PRP_LANID                  BIT(8)\n+#define SYS_PORT_MODE_PRP_LANID_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_PRP_LANID, x)\n+#define SYS_PORT_MODE_PRP_LANID_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_PRP_LANID, x)\n+\n+#define SYS_PORT_MODE_PRP_ENA                    BIT(7)\n+#define SYS_PORT_MODE_PRP_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_PRP_ENA, x)\n+#define SYS_PORT_MODE_PRP_ENA_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_PRP_ENA, x)\n+\n+#define SYS_PORT_MODE_INCL_INJ_HDR               GENMASK(6, 5)\n+#define SYS_PORT_MODE_INCL_INJ_HDR_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_INCL_INJ_HDR, x)\n+#define SYS_PORT_MODE_INCL_INJ_HDR_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_INCL_INJ_HDR, x)\n+\n+#define SYS_PORT_MODE_INCL_XTR_HDR               GENMASK(4, 3)\n+#define SYS_PORT_MODE_INCL_XTR_HDR_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_INCL_XTR_HDR, x)\n+#define SYS_PORT_MODE_INCL_XTR_HDR_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_INCL_XTR_HDR, x)\n+\n+#define SYS_PORT_MODE_INJ_HDR_ERR                BIT(2)\n+#define SYS_PORT_MODE_INJ_HDR_ERR_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_INJ_HDR_ERR, x)\n+#define SYS_PORT_MODE_INJ_HDR_ERR_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_INJ_HDR_ERR, x)\n+\n+#define SYS_PORT_MODE_PAD_DIS                    BIT(1)\n+#define SYS_PORT_MODE_PAD_DIS_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_PAD_DIS, x)\n+#define SYS_PORT_MODE_PAD_DIS_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_PAD_DIS, x)\n+\n+#define SYS_PORT_MODE_RTAG_CLEAR                 BIT(0)\n+#define SYS_PORT_MODE_RTAG_CLEAR_SET(x)\\\n+\tFIELD_PREP(SYS_PORT_MODE_RTAG_CLEAR, x)\n+#define SYS_PORT_MODE_RTAG_CLEAR_GET(x)\\\n+\tFIELD_GET(SYS_PORT_MODE_RTAG_CLEAR, x)\n+\n+/*      SYS:SYSTEM:FRONT_PORT_MODE */\n+#define SYS_FRONT_PORT_MODE(r)    __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4160, 0, 1, 184, 92, r, 9, 4)\n+\n+#define SYS_FRONT_PORT_MODE_HDX_MODE             BIT(1)\n+#define SYS_FRONT_PORT_MODE_HDX_MODE_SET(x)\\\n+\tFIELD_PREP(SYS_FRONT_PORT_MODE_HDX_MODE, x)\n+#define SYS_FRONT_PORT_MODE_HDX_MODE_GET(x)\\\n+\tFIELD_GET(SYS_FRONT_PORT_MODE_HDX_MODE, x)\n+\n+#define SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE        GENMASK(9, 8)\n+#define SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE_SET(x)\\\n+\tFIELD_PREP(SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE, x)\n+#define SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE_GET(x)\\\n+\tFIELD_GET(SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE, x)\n+\n+#define SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS     BIT(0)\n+#define SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS_SET(x)\\\n+\tFIELD_PREP(SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS, x)\n+#define SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS_GET(x)\\\n+\tFIELD_GET(SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS, x)\n+\n+/*      SYS:SYSTEM:FRM_AGING */\n+#define SYS_FRM_AGING             __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4160, 0, 1, 184, 128, 0, 1, 4)\n+\n+#define SYS_FRM_AGING_AGE_TX_ENA                 BIT(20)\n+#define SYS_FRM_AGING_AGE_TX_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_FRM_AGING_AGE_TX_ENA, x)\n+#define SYS_FRM_AGING_AGE_TX_ENA_GET(x)\\\n+\tFIELD_GET(SYS_FRM_AGING_AGE_TX_ENA, x)\n+\n+#define SYS_FRM_AGING_MAX_AGE                    GENMASK(19, 0)\n+#define SYS_FRM_AGING_MAX_AGE_SET(x)\\\n+\tFIELD_PREP(SYS_FRM_AGING_MAX_AGE, x)\n+#define SYS_FRM_AGING_MAX_AGE_GET(x)\\\n+\tFIELD_GET(SYS_FRM_AGING_MAX_AGE, x)\n+\n+/*      SYS:SYSTEM:STAT_CFG */\n+#define SYS_STAT_CFG              __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4160, 0, 1, 184, 132, 0, 1, 4)\n+\n+#define SYS_STAT_CFG_STAT_CLEAR_SHOT             GENMASK(16, 10)\n+#define SYS_STAT_CFG_STAT_CLEAR_SHOT_SET(x)\\\n+\tFIELD_PREP(SYS_STAT_CFG_STAT_CLEAR_SHOT, x)\n+#define SYS_STAT_CFG_STAT_CLEAR_SHOT_GET(x)\\\n+\tFIELD_GET(SYS_STAT_CFG_STAT_CLEAR_SHOT, x)\n+\n+#define SYS_STAT_CFG_STAT_VIEW                   GENMASK(9, 0)\n+#define SYS_STAT_CFG_STAT_VIEW_SET(x)\\\n+\tFIELD_PREP(SYS_STAT_CFG_STAT_VIEW, x)\n+#define SYS_STAT_CFG_STAT_VIEW_GET(x)\\\n+\tFIELD_GET(SYS_STAT_CFG_STAT_VIEW, x)\n+\n+/*      SYS:SYSTEM:SW_STATUS */\n+#define SYS_SW_STATUS(r)          __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4160, 0, 1, 184, 136, r, 10, 4)\n+\n+#define SYS_SW_STATUS_PORT_RX_PAUSED             BIT(0)\n+#define SYS_SW_STATUS_PORT_RX_PAUSED_SET(x)\\\n+\tFIELD_PREP(SYS_SW_STATUS_PORT_RX_PAUSED, x)\n+#define SYS_SW_STATUS_PORT_RX_PAUSED_GET(x)\\\n+\tFIELD_GET(SYS_SW_STATUS_PORT_RX_PAUSED, x)\n+\n+/*      SYS:PAUSE_CFG:PAUSE_CFG */\n+#define SYS_PAUSE_CFG(r)          __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4344, 0, 1, 124, 0, r, 10, 4)\n+\n+#define SYS_PAUSE_CFG_PAUSE_START                GENMASK(18, 10)\n+#define SYS_PAUSE_CFG_PAUSE_START_SET(x)\\\n+\tFIELD_PREP(SYS_PAUSE_CFG_PAUSE_START, x)\n+#define SYS_PAUSE_CFG_PAUSE_START_GET(x)\\\n+\tFIELD_GET(SYS_PAUSE_CFG_PAUSE_START, x)\n+\n+#define SYS_PAUSE_CFG_PAUSE_STOP                 GENMASK(9, 1)\n+#define SYS_PAUSE_CFG_PAUSE_STOP_SET(x)\\\n+\tFIELD_PREP(SYS_PAUSE_CFG_PAUSE_STOP, x)\n+#define SYS_PAUSE_CFG_PAUSE_STOP_GET(x)\\\n+\tFIELD_GET(SYS_PAUSE_CFG_PAUSE_STOP, x)\n+\n+#define SYS_PAUSE_CFG_PAUSE_ENA                  BIT(0)\n+#define SYS_PAUSE_CFG_PAUSE_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_PAUSE_CFG_PAUSE_ENA, x)\n+#define SYS_PAUSE_CFG_PAUSE_ENA_GET(x)\\\n+\tFIELD_GET(SYS_PAUSE_CFG_PAUSE_ENA, x)\n+\n+/*      SYS:PAUSE_CFG:ATOP */\n+#define SYS_ATOP(r)               __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4344, 0, 1, 124, 44, r, 10, 4)\n+\n+#define SYS_ATOP_ATOP                            GENMASK(8, 0)\n+#define SYS_ATOP_ATOP_SET(x)\\\n+\tFIELD_PREP(SYS_ATOP_ATOP, x)\n+#define SYS_ATOP_ATOP_GET(x)\\\n+\tFIELD_GET(SYS_ATOP_ATOP, x)\n+\n+/*      SYS:PAUSE_CFG:ATOP_TOT_CFG */\n+#define SYS_ATOP_TOT_CFG          __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4344, 0, 1, 124, 84, 0, 1, 4)\n+\n+#define SYS_ATOP_TOT_CFG_ATOP_TOT                GENMASK(8, 0)\n+#define SYS_ATOP_TOT_CFG_ATOP_TOT_SET(x)\\\n+\tFIELD_PREP(SYS_ATOP_TOT_CFG_ATOP_TOT, x)\n+#define SYS_ATOP_TOT_CFG_ATOP_TOT_GET(x)\\\n+\tFIELD_GET(SYS_ATOP_TOT_CFG_ATOP_TOT, x)\n+\n+/*      SYS:PAUSE_CFG:MAC_FC_CFG */\n+#define SYS_MAC_FC_CFG(r)         __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4344, 0, 1, 124, 88, r, 9, 4)\n+\n+#define SYS_MAC_FC_CFG_FC_LINK_SPEED             GENMASK(27, 26)\n+#define SYS_MAC_FC_CFG_FC_LINK_SPEED_SET(x)\\\n+\tFIELD_PREP(SYS_MAC_FC_CFG_FC_LINK_SPEED, x)\n+#define SYS_MAC_FC_CFG_FC_LINK_SPEED_GET(x)\\\n+\tFIELD_GET(SYS_MAC_FC_CFG_FC_LINK_SPEED, x)\n+\n+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG            GENMASK(25, 20)\n+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_SET(x)\\\n+\tFIELD_PREP(SYS_MAC_FC_CFG_FC_LATENCY_CFG, x)\n+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_GET(x)\\\n+\tFIELD_GET(SYS_MAC_FC_CFG_FC_LATENCY_CFG, x)\n+\n+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA            BIT(18)\n+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_MAC_FC_CFG_ZERO_PAUSE_ENA, x)\n+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_GET(x)\\\n+\tFIELD_GET(SYS_MAC_FC_CFG_ZERO_PAUSE_ENA, x)\n+\n+#define SYS_MAC_FC_CFG_TX_FC_ENA                 BIT(17)\n+#define SYS_MAC_FC_CFG_TX_FC_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_MAC_FC_CFG_TX_FC_ENA, x)\n+#define SYS_MAC_FC_CFG_TX_FC_ENA_GET(x)\\\n+\tFIELD_GET(SYS_MAC_FC_CFG_TX_FC_ENA, x)\n+\n+#define SYS_MAC_FC_CFG_RX_FC_ENA                 BIT(16)\n+#define SYS_MAC_FC_CFG_RX_FC_ENA_SET(x)\\\n+\tFIELD_PREP(SYS_MAC_FC_CFG_RX_FC_ENA, x)\n+#define SYS_MAC_FC_CFG_RX_FC_ENA_GET(x)\\\n+\tFIELD_GET(SYS_MAC_FC_CFG_RX_FC_ENA, x)\n+\n+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG             GENMASK(15, 0)\n+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_SET(x)\\\n+\tFIELD_PREP(SYS_MAC_FC_CFG_PAUSE_VAL_CFG, x)\n+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_GET(x)\\\n+\tFIELD_GET(SYS_MAC_FC_CFG_PAUSE_VAL_CFG, x)\n+\n+/*      SYS:STAT:CNT */\n+#define SYS_CNT(g)                __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 0, g, 896, 4, 0, 0, 1, 4)\n+\n+/*      SYS:RAM_CTRL:RAM_INIT */\n+#define SYS_RAM_INIT              __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4492, 0, 1, 4, 0, 0, 1, 4)\n+\n+#define SYS_RAM_INIT_RAM_TEST_OPT                GENMASK(4, 2)\n+#define SYS_RAM_INIT_RAM_TEST_OPT_SET(x)\\\n+\tFIELD_PREP(SYS_RAM_INIT_RAM_TEST_OPT, x)\n+#define SYS_RAM_INIT_RAM_TEST_OPT_GET(x)\\\n+\tFIELD_GET(SYS_RAM_INIT_RAM_TEST_OPT, x)\n+\n+#define SYS_RAM_INIT_RAM_INIT                    BIT(1)\n+#define SYS_RAM_INIT_RAM_INIT_SET(x)\\\n+\tFIELD_PREP(SYS_RAM_INIT_RAM_INIT, x)\n+#define SYS_RAM_INIT_RAM_INIT_GET(x)\\\n+\tFIELD_GET(SYS_RAM_INIT_RAM_INIT, x)\n+\n+#define SYS_RAM_INIT_RAM_CFG_HOOK                BIT(0)\n+#define SYS_RAM_INIT_RAM_CFG_HOOK_SET(x)\\\n+\tFIELD_PREP(SYS_RAM_INIT_RAM_CFG_HOOK, x)\n+#define SYS_RAM_INIT_RAM_CFG_HOOK_GET(x)\\\n+\tFIELD_GET(SYS_RAM_INIT_RAM_CFG_HOOK, x)\n+\n+/*      SYS:PTPPORT:PTP_RXDLY_CFG */\n+#define SYS_PTP_RXDLY_CFG(g)      __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4512, g, 11, 28, 8, 0, 1, 4)\n+\n+#define SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY          GENMASK(23, 0)\n+#define SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY_SET(x)\\\n+\tFIELD_PREP(SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY, x)\n+#define SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY_GET(x)\\\n+\tFIELD_GET(SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY, x)\n+\n+/*      SYS:PTPPORT:PTP_TXDLY_CFG */\n+#define SYS_PTP_TXDLY_CFG(g)      __REG(TARGET_SYS,\\\n+\t\t\t\t\t0, 1, 4512, g, 11, 28, 12, 0, 1, 4)\n+\n+#define SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY          GENMASK(23, 0)\n+#define SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY_SET(x)\\\n+\tFIELD_PREP(SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY, x)\n+#define SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY_GET(x)\\\n+\tFIELD_GET(SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY, x)\n+\n+#endif /* _LAN9645X_REGS_H_ */\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.c\nnew file mode 100644\nindex 00000000000000..e38f510eb8f664\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.c\n@@ -0,0 +1,929 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \u003clinux/spinlock.h\u003e\n+#include \u003clinux/workqueue.h\u003e\n+\n+#include \"lan9645x_main.h\"\n+#include \"lan9645x_stats.h\"\n+\n+#define LAN9645X_STATS_CHECK_DELAY\t(3 * HZ)\n+\n+static const u32 lan9645x_port_stats_layout[] = {\n+\t[SCNT_RX_OCT]              = 0x0,\n+\t[SCNT_RX_UC]               = 0x1,\n+\t[SCNT_RX_MC]               = 0x2,\n+\t[SCNT_RX_BC]               = 0x3,\n+\t[SCNT_RX_SHORT]            = 0x4,\n+\t[SCNT_RX_FRAG]             = 0x5,\n+\t[SCNT_RX_JABBER]           = 0x6,\n+\t[SCNT_RX_CRC]              = 0x7,\n+\t[SCNT_RX_SYMBOL_ERR]       = 0x8,\n+\t[SCNT_RX_SZ_64]            = 0x9,\n+\t[SCNT_RX_SZ_65_127]        = 0xa,\n+\t[SCNT_RX_SZ_128_255]       = 0xb,\n+\t[SCNT_RX_SZ_256_511]       = 0xc,\n+\t[SCNT_RX_SZ_512_1023]      = 0xd,\n+\t[SCNT_RX_SZ_1024_1526]     = 0xe,\n+\t[SCNT_RX_SZ_JUMBO]         = 0xf,\n+\t[SCNT_RX_PAUSE]            = 0x10,\n+\t[SCNT_RX_CONTROL]          = 0x11,\n+\t[SCNT_RX_LONG]             = 0x12,\n+\t[SCNT_RX_CAT_DROP]         = 0x13,\n+\t[SCNT_RX_RED_PRIO_0]       = 0x14,\n+\t[SCNT_RX_RED_PRIO_1]       = 0x15,\n+\t[SCNT_RX_RED_PRIO_2]       = 0x16,\n+\t[SCNT_RX_RED_PRIO_3]       = 0x17,\n+\t[SCNT_RX_RED_PRIO_4]       = 0x18,\n+\t[SCNT_RX_RED_PRIO_5]       = 0x19,\n+\t[SCNT_RX_RED_PRIO_6]       = 0x1a,\n+\t[SCNT_RX_RED_PRIO_7]       = 0x1b,\n+\t[SCNT_RX_YELLOW_PRIO_0]    = 0x1c,\n+\t[SCNT_RX_YELLOW_PRIO_1]    = 0x1d,\n+\t[SCNT_RX_YELLOW_PRIO_2]    = 0x1e,\n+\t[SCNT_RX_YELLOW_PRIO_3]    = 0x1f,\n+\t[SCNT_RX_YELLOW_PRIO_4]    = 0x20,\n+\t[SCNT_RX_YELLOW_PRIO_5]    = 0x21,\n+\t[SCNT_RX_YELLOW_PRIO_6]    = 0x22,\n+\t[SCNT_RX_YELLOW_PRIO_7]    = 0x23,\n+\t[SCNT_RX_GREEN_PRIO_0]     = 0x24,\n+\t[SCNT_RX_GREEN_PRIO_1]     = 0x25,\n+\t[SCNT_RX_GREEN_PRIO_2]     = 0x26,\n+\t[SCNT_RX_GREEN_PRIO_3]     = 0x27,\n+\t[SCNT_RX_GREEN_PRIO_4]     = 0x28,\n+\t[SCNT_RX_GREEN_PRIO_5]     = 0x29,\n+\t[SCNT_RX_GREEN_PRIO_6]     = 0x2a,\n+\t[SCNT_RX_GREEN_PRIO_7]     = 0x2b,\n+\t[SCNT_RX_ASSEMBLY_ERR]     = 0x2c,\n+\t[SCNT_RX_SMD_ERR]          = 0x2d,\n+\t[SCNT_RX_ASSEMBLY_OK]      = 0x2e,\n+\t[SCNT_RX_MERGE_FRAG]       = 0x2f,\n+\t[SCNT_RX_PMAC_OCT]         = 0x30,\n+\t[SCNT_RX_PMAC_UC]          = 0x31,\n+\t[SCNT_RX_PMAC_MC]          = 0x32,\n+\t[SCNT_RX_PMAC_BC]          = 0x33,\n+\t[SCNT_RX_PMAC_SHORT]       = 0x34,\n+\t[SCNT_RX_PMAC_FRAG]        = 0x35,\n+\t[SCNT_RX_PMAC_JABBER]      = 0x36,\n+\t[SCNT_RX_PMAC_CRC]         = 0x37,\n+\t[SCNT_RX_PMAC_SYMBOL_ERR]  = 0x38,\n+\t[SCNT_RX_PMAC_SZ_64]       = 0x39,\n+\t[SCNT_RX_PMAC_SZ_65_127]   = 0x3a,\n+\t[SCNT_RX_PMAC_SZ_128_255]  = 0x3b,\n+\t[SCNT_RX_PMAC_SZ_256_511]  = 0x3c,\n+\t[SCNT_RX_PMAC_SZ_512_1023] = 0x3d,\n+\t[SCNT_RX_PMAC_SZ_1024_1526] = 0x3e,\n+\t[SCNT_RX_PMAC_SZ_JUMBO]    = 0x3f,\n+\t[SCNT_RX_PMAC_PAUSE]       = 0x40,\n+\t[SCNT_RX_PMAC_CONTROL]     = 0x41,\n+\t[SCNT_RX_PMAC_LONG]        = 0x42,\n+\t[SCNT_TX_OCT]              = 0x80,\n+\t[SCNT_TX_UC]               = 0x81,\n+\t[SCNT_TX_MC]               = 0x82,\n+\t[SCNT_TX_BC]               = 0x83,\n+\t[SCNT_TX_COL]              = 0x84,\n+\t[SCNT_TX_DROP]             = 0x85,\n+\t[SCNT_TX_PAUSE]            = 0x86,\n+\t[SCNT_TX_SZ_64]            = 0x87,\n+\t[SCNT_TX_SZ_65_127]        = 0x88,\n+\t[SCNT_TX_SZ_128_255]       = 0x89,\n+\t[SCNT_TX_SZ_256_511]       = 0x8a,\n+\t[SCNT_TX_SZ_512_1023]      = 0x8b,\n+\t[SCNT_TX_SZ_1024_1526]     = 0x8c,\n+\t[SCNT_TX_SZ_JUMBO]         = 0x8d,\n+\t[SCNT_TX_YELLOW_PRIO_0]    = 0x8e,\n+\t[SCNT_TX_YELLOW_PRIO_1]    = 0x8f,\n+\t[SCNT_TX_YELLOW_PRIO_2]    = 0x90,\n+\t[SCNT_TX_YELLOW_PRIO_3]    = 0x91,\n+\t[SCNT_TX_YELLOW_PRIO_4]    = 0x92,\n+\t[SCNT_TX_YELLOW_PRIO_5]    = 0x93,\n+\t[SCNT_TX_YELLOW_PRIO_6]    = 0x94,\n+\t[SCNT_TX_YELLOW_PRIO_7]    = 0x95,\n+\t[SCNT_TX_GREEN_PRIO_0]     = 0x96,\n+\t[SCNT_TX_GREEN_PRIO_1]     = 0x97,\n+\t[SCNT_TX_GREEN_PRIO_2]     = 0x98,\n+\t[SCNT_TX_GREEN_PRIO_3]     = 0x99,\n+\t[SCNT_TX_GREEN_PRIO_4]     = 0x9a,\n+\t[SCNT_TX_GREEN_PRIO_5]     = 0x9b,\n+\t[SCNT_TX_GREEN_PRIO_6]     = 0x9c,\n+\t[SCNT_TX_GREEN_PRIO_7]     = 0x9d,\n+\t[SCNT_TX_AGED]             = 0x9e,\n+\t[SCNT_TX_LLCT]             = 0x9f,\n+\t[SCNT_TX_CT]               = 0xa0,\n+\t[SCNT_TX_BUFDROP]          = 0xa1,\n+\t[SCNT_TX_MM_HOLD]          = 0xa2,\n+\t[SCNT_TX_MERGE_FRAG]       = 0xa3,\n+\t[SCNT_TX_PMAC_OCT]         = 0xa4,\n+\t[SCNT_TX_PMAC_UC]          = 0xa5,\n+\t[SCNT_TX_PMAC_MC]          = 0xa6,\n+\t[SCNT_TX_PMAC_BC]          = 0xa7,\n+\t[SCNT_TX_PMAC_PAUSE]       = 0xa8,\n+\t[SCNT_TX_PMAC_SZ_64]       = 0xa9,\n+\t[SCNT_TX_PMAC_SZ_65_127]   = 0xaa,\n+\t[SCNT_TX_PMAC_SZ_128_255]  = 0xab,\n+\t[SCNT_TX_PMAC_SZ_256_511]  = 0xac,\n+\t[SCNT_TX_PMAC_SZ_512_1023] = 0xad,\n+\t[SCNT_TX_PMAC_SZ_1024_1526] = 0xae,\n+\t[SCNT_TX_PMAC_SZ_JUMBO]    = 0xaf,\n+\t[SCNT_DR_LOCAL]            = 0x100,\n+\t[SCNT_DR_TAIL]             = 0x101,\n+\t[SCNT_DR_YELLOW_PRIO_0]    = 0x102,\n+\t[SCNT_DR_YELLOW_PRIO_1]    = 0x103,\n+\t[SCNT_DR_YELLOW_PRIO_2]    = 0x104,\n+\t[SCNT_DR_YELLOW_PRIO_3]    = 0x105,\n+\t[SCNT_DR_YELLOW_PRIO_4]    = 0x106,\n+\t[SCNT_DR_YELLOW_PRIO_5]    = 0x107,\n+\t[SCNT_DR_YELLOW_PRIO_6]    = 0x108,\n+\t[SCNT_DR_YELLOW_PRIO_7]    = 0x109,\n+\t[SCNT_DR_GREEN_PRIO_0]     = 0x10a,\n+\t[SCNT_DR_GREEN_PRIO_1]     = 0x10b,\n+\t[SCNT_DR_GREEN_PRIO_2]     = 0x10c,\n+\t[SCNT_DR_GREEN_PRIO_3]     = 0x10d,\n+\t[SCNT_DR_GREEN_PRIO_4]     = 0x10e,\n+\t[SCNT_DR_GREEN_PRIO_5]     = 0x10f,\n+\t[SCNT_DR_GREEN_PRIO_6]     = 0x110,\n+\t[SCNT_DR_GREEN_PRIO_7]     = 0x111,\n+};\n+\n+struct lan9645x_ethtool_stat {\n+\tchar name[ETH_GSTRING_LEN];\n+\tu16 idx;\n+};\n+\n+static const struct lan9645x_ethtool_stat lan9645x_port_ethtool_stats[] = {\n+\t{ \"rx_cat_drop\",        SCNT_RX_CAT_DROP },\n+\t{ \"rx_red_prio_0\",      SCNT_RX_RED_PRIO_0 },\n+\t{ \"rx_red_prio_1\",      SCNT_RX_RED_PRIO_1 },\n+\t{ \"rx_red_prio_2\",      SCNT_RX_RED_PRIO_2 },\n+\t{ \"rx_red_prio_3\",      SCNT_RX_RED_PRIO_3 },\n+\t{ \"rx_red_prio_4\",      SCNT_RX_RED_PRIO_4 },\n+\t{ \"rx_red_prio_5\",      SCNT_RX_RED_PRIO_5 },\n+\t{ \"rx_red_prio_6\",      SCNT_RX_RED_PRIO_6 },\n+\t{ \"rx_red_prio_7\",      SCNT_RX_RED_PRIO_7 },\n+\t{ \"rx_yellow_prio_0\",   SCNT_RX_YELLOW_PRIO_0 },\n+\t{ \"rx_yellow_prio_1\",   SCNT_RX_YELLOW_PRIO_1 },\n+\t{ \"rx_yellow_prio_2\",   SCNT_RX_YELLOW_PRIO_2 },\n+\t{ \"rx_yellow_prio_3\",   SCNT_RX_YELLOW_PRIO_3 },\n+\t{ \"rx_yellow_prio_4\",   SCNT_RX_YELLOW_PRIO_4 },\n+\t{ \"rx_yellow_prio_5\",   SCNT_RX_YELLOW_PRIO_5 },\n+\t{ \"rx_yellow_prio_6\",   SCNT_RX_YELLOW_PRIO_6 },\n+\t{ \"rx_yellow_prio_7\",   SCNT_RX_YELLOW_PRIO_7 },\n+\t{ \"rx_green_prio_0\",    SCNT_RX_GREEN_PRIO_0 },\n+\t{ \"rx_green_prio_1\",    SCNT_RX_GREEN_PRIO_1 },\n+\t{ \"rx_green_prio_2\",    SCNT_RX_GREEN_PRIO_2 },\n+\t{ \"rx_green_prio_3\",    SCNT_RX_GREEN_PRIO_3 },\n+\t{ \"rx_green_prio_4\",    SCNT_RX_GREEN_PRIO_4 },\n+\t{ \"rx_green_prio_5\",    SCNT_RX_GREEN_PRIO_5 },\n+\t{ \"rx_green_prio_6\",    SCNT_RX_GREEN_PRIO_6 },\n+\t{ \"rx_green_prio_7\",    SCNT_RX_GREEN_PRIO_7 },\n+\t{ \"tx_drop\",            SCNT_TX_DROP },\n+\t{ \"tx_yellow_prio_0\",   SCNT_TX_YELLOW_PRIO_0 },\n+\t{ \"tx_yellow_prio_1\",   SCNT_TX_YELLOW_PRIO_1 },\n+\t{ \"tx_yellow_prio_2\",   SCNT_TX_YELLOW_PRIO_2 },\n+\t{ \"tx_yellow_prio_3\",   SCNT_TX_YELLOW_PRIO_3 },\n+\t{ \"tx_yellow_prio_4\",   SCNT_TX_YELLOW_PRIO_4 },\n+\t{ \"tx_yellow_prio_5\",   SCNT_TX_YELLOW_PRIO_5 },\n+\t{ \"tx_yellow_prio_6\",   SCNT_TX_YELLOW_PRIO_6 },\n+\t{ \"tx_yellow_prio_7\",   SCNT_TX_YELLOW_PRIO_7 },\n+\t{ \"tx_green_prio_0\",    SCNT_TX_GREEN_PRIO_0 },\n+\t{ \"tx_green_prio_1\",    SCNT_TX_GREEN_PRIO_1 },\n+\t{ \"tx_green_prio_2\",    SCNT_TX_GREEN_PRIO_2 },\n+\t{ \"tx_green_prio_3\",    SCNT_TX_GREEN_PRIO_3 },\n+\t{ \"tx_green_prio_4\",    SCNT_TX_GREEN_PRIO_4 },\n+\t{ \"tx_green_prio_5\",    SCNT_TX_GREEN_PRIO_5 },\n+\t{ \"tx_green_prio_6\",    SCNT_TX_GREEN_PRIO_6 },\n+\t{ \"tx_green_prio_7\",    SCNT_TX_GREEN_PRIO_7 },\n+\t{ \"tx_aged\",            SCNT_TX_AGED },\n+\t{ \"tx_bufdrop\",         SCNT_TX_BUFDROP },\n+\t{ \"dr_local\",           SCNT_DR_LOCAL },\n+\t{ \"dr_tail\",            SCNT_DR_TAIL },\n+\t{ \"dr_yellow_prio_0\",   SCNT_DR_YELLOW_PRIO_0 },\n+\t{ \"dr_yellow_prio_1\",   SCNT_DR_YELLOW_PRIO_1 },\n+\t{ \"dr_yellow_prio_2\",   SCNT_DR_YELLOW_PRIO_2 },\n+\t{ \"dr_yellow_prio_3\",   SCNT_DR_YELLOW_PRIO_3 },\n+\t{ \"dr_yellow_prio_4\",   SCNT_DR_YELLOW_PRIO_4 },\n+\t{ \"dr_yellow_prio_5\",   SCNT_DR_YELLOW_PRIO_5 },\n+\t{ \"dr_yellow_prio_6\",   SCNT_DR_YELLOW_PRIO_6 },\n+\t{ \"dr_yellow_prio_7\",   SCNT_DR_YELLOW_PRIO_7 },\n+\t{ \"dr_green_prio_0\",    SCNT_DR_GREEN_PRIO_0 },\n+\t{ \"dr_green_prio_1\",    SCNT_DR_GREEN_PRIO_1 },\n+\t{ \"dr_green_prio_2\",    SCNT_DR_GREEN_PRIO_2 },\n+\t{ \"dr_green_prio_3\",    SCNT_DR_GREEN_PRIO_3 },\n+\t{ \"dr_green_prio_4\",    SCNT_DR_GREEN_PRIO_4 },\n+\t{ \"dr_green_prio_5\",    SCNT_DR_GREEN_PRIO_5 },\n+\t{ \"dr_green_prio_6\",    SCNT_DR_GREEN_PRIO_6 },\n+\t{ \"dr_green_prio_7\",    SCNT_DR_GREEN_PRIO_7 },\n+};\n+\n+static const struct lan9645x_view_stats lan9645x_view_stat_cfgs[] = {\n+\t[LAN9645X_STAT_PORTS] = {\n+\t\t.name = \"ports\",\n+\t\t.type = LAN9645X_STAT_PORTS,\n+\t\t.layout = lan9645x_port_stats_layout,\n+\t\t.num_cnts = ARRAY_SIZE(lan9645x_port_stats_layout),\n+\t\t.num_indexes = NUM_PHYS_PORTS,\n+\t},\n+};\n+\n+static int __lan9645x_stats_view_idx_hw_read(struct lan9645x *lan9645x,\n+\t\t\t\t\t     enum lan9645x_view_stat_type vtype,\n+\t\t\t\t\t     int idx)\n+{\n+\tstruct lan9645x_stat_region region;\n+\tstruct lan9645x_view_stats *vstats;\n+\tu32 *region_buf;\n+\tint err;\n+\n+\tlockdep_assert_held(\u0026lan9645x-\u003estats-\u003ehw_lock);\n+\n+\tvstats = lan9645x_get_vstats(lan9645x, vtype);\n+\tif (!vstats || idx \u003c 0 || idx \u003e= vstats-\u003enum_indexes)\n+\t\treturn -EINVAL;\n+\n+\tlan_wr(SYS_STAT_CFG_STAT_VIEW_SET(idx), lan9645x, SYS_STAT_CFG);\n+\n+\tregion_buf = \u0026vstats-\u003ebuf[vstats-\u003enum_cnts * idx];\n+\n+\t/* Each region for this index contains counters which are at sequential\n+\t * addresses, so we can use bulk reads to ease lock pressure a bit.\n+\t */\n+\tfor (int r = 0; r \u003c vstats-\u003enum_regions; r++) {\n+\t\tregion = vstats-\u003eregions[r];\n+\t\terr = lan_bulk_rd(\u0026region_buf[region.cnts_base_idx], region.cnt,\n+\t\t\t\t  lan9645x, SYS_CNT(region.base_offset));\n+\t\tif (err) {\n+\t\t\tdev_err(lan9645x-\u003edev,\n+\t\t\t\t\"stats bulk read err vtype=%d idx=%d err=%d\\n\",\n+\t\t\t\tvtype, idx, err);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static void\n+__lan9645x_stats_view_idx_transfer(struct lan9645x *lan9645x,\n+\t\t\t\t   enum lan9645x_view_stat_type vtype, int idx)\n+{\n+\tstruct lan9645x_view_stats *vstats;\n+\tu64 *idx_counters;\n+\tu32 *region_buf;\n+\tint cntr;\n+\n+\tlockdep_assert_held(\u0026lan9645x-\u003estats-\u003esw_lock);\n+\n+\tvstats = lan9645x_get_vstats(lan9645x, vtype);\n+\tif (!vstats || idx \u003c 0 || idx \u003e= vstats-\u003enum_indexes)\n+\t\treturn;\n+\n+\tidx_counters = STATS_INDEX(vstats, idx);\n+\tregion_buf = \u0026vstats-\u003ebuf[vstats-\u003enum_cnts * idx];\n+\n+\tfor (cntr = 0; cntr \u003c vstats-\u003enum_cnts; cntr++)\n+\t\tlan9645x_stats_add_cnt(\u0026idx_counters[cntr], region_buf[cntr]);\n+}\n+\n+static void __lan9645x_stats_view_idx_update(struct lan9645x *lan9645x,\n+\t\t\t\t\t     enum lan9645x_view_stat_type vtype,\n+\t\t\t\t\t     int idx)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\n+\tlockdep_assert_held(\u0026s-\u003ehw_lock);\n+\n+\tif (!__lan9645x_stats_view_idx_hw_read(lan9645x, vtype, idx)) {\n+\t\tspin_lock(\u0026s-\u003esw_lock);\n+\t\t__lan9645x_stats_view_idx_transfer(lan9645x, vtype, idx);\n+\t\tspin_unlock(\u0026s-\u003esw_lock);\n+\t}\n+}\n+\n+static u64 *lan9645x_stats_view_idx_update(struct lan9645x *lan9645x,\n+\t\t\t\t\t   enum lan9645x_view_stat_type vtype,\n+\t\t\t\t\t   int idx)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\n+\tmutex_lock(\u0026s-\u003ehw_lock);\n+\t__lan9645x_stats_view_idx_update(lan9645x, vtype, idx);\n+\tmutex_unlock(\u0026s-\u003ehw_lock);\n+\n+\treturn STAT_COUNTERS(lan9645x, vtype, idx);\n+}\n+\n+static void lan9645x_stats_view_update(struct lan9645x *lan9645x,\n+\t\t\t\t       enum lan9645x_view_stat_type vtype)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tstruct lan9645x_view_stats *vstats;\n+\tint idx;\n+\n+\tvstats = lan9645x_get_vstats(lan9645x, vtype);\n+\tif (!vstats)\n+\t\treturn;\n+\n+\tswitch (vtype) {\n+\tcase LAN9645X_STAT_PORTS:\n+\t\tmutex_lock(\u0026s-\u003ehw_lock);\n+\t\tfor (idx = 0; idx \u003c vstats-\u003enum_indexes; idx++) {\n+\t\t\tif (dsa_is_unused_port(lan9645x-\u003eds, idx))\n+\t\t\t\tcontinue;\n+\t\t\t__lan9645x_stats_view_idx_update(lan9645x, vtype, idx);\n+\t\t}\n+\t\tmutex_unlock(\u0026s-\u003ehw_lock);\n+\t\treturn;\n+\tdefault:\n+\t\treturn;\n+\t}\n+}\n+\n+static void lan9645x_stats_update(struct lan9645x *lan9645x)\n+{\n+\tfor (int vtype = 0; vtype \u003c LAN9645X_STAT_NUM; vtype++)\n+\t\tlan9645x_stats_view_update(lan9645x, vtype);\n+}\n+\n+void lan9645x_stats_get_strings(struct lan9645x *lan9645x, int port,\n+\t\t\t\tu32 stringset, u8 *data)\n+{\n+\tint i;\n+\n+\tif (stringset != ETH_SS_STATS)\n+\t\treturn;\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(lan9645x_port_ethtool_stats); i++)\n+\t\tmemcpy(data + i * ETH_GSTRING_LEN,\n+\t\t       lan9645x_port_ethtool_stats[i].name, ETH_GSTRING_LEN);\n+}\n+\n+int lan9645x_stats_get_sset_count(struct lan9645x *lan9645x, int port, int sset)\n+{\n+\tif (sset != ETH_SS_STATS)\n+\t\treturn -EOPNOTSUPP;\n+\n+\treturn ARRAY_SIZE(lan9645x_port_ethtool_stats);\n+}\n+\n+void lan9645x_stats_get_ethtool_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t      u64 *data)\n+{\n+\tstruct lan9645x_stats *stats = lan9645x-\u003estats;\n+\tu64 *c;\n+\tint i;\n+\n+\tc = lan9645x_stats_view_idx_update(lan9645x, LAN9645X_STAT_PORTS, port);\n+\n+\tspin_lock(\u0026stats-\u003esw_lock);\n+\tfor (i = 0; i \u003c ARRAY_SIZE(lan9645x_port_ethtool_stats); i++)\n+\t\t*data++ = c[lan9645x_port_ethtool_stats[i].idx];\n+\tspin_unlock(\u0026stats-\u003esw_lock);\n+}\n+\n+static u64 *lan9645x_stats_port_update(struct lan9645x *lan9645x, int port)\n+{\n+\treturn lan9645x_stats_view_idx_update(lan9645x, LAN9645X_STAT_PORTS,\n+\t\t\t\t\t      port);\n+}\n+\n+void lan9645x_stats_get_eth_mac_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t      struct ethtool_eth_mac_stats *m)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = lan9645x_stats_port_update(lan9645x, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tswitch (m-\u003esrc) {\n+\tcase ETHTOOL_MAC_STATS_SRC_EMAC:\n+\t\tm-\u003eFramesTransmittedOK = c[SCNT_TX_UC] +\n+\t\t\t\t\t c[SCNT_TX_MC] +\n+\t\t\t\t\t c[SCNT_TX_BC];\n+\t\tm-\u003eSingleCollisionFrames = c[SCNT_TX_COL];\n+\t\tm-\u003eFramesReceivedOK = c[SCNT_RX_UC] +\n+\t\t\t\t      c[SCNT_RX_MC] +\n+\t\t\t\t      c[SCNT_RX_BC];\n+\t\tm-\u003eFrameCheckSequenceErrors = c[SCNT_RX_CRC];\n+\t\tm-\u003eOctetsTransmittedOK = c[SCNT_TX_OCT];\n+\t\tm-\u003eOctetsReceivedOK = c[SCNT_RX_OCT];\n+\t\tm-\u003eMulticastFramesXmittedOK = c[SCNT_TX_MC];\n+\t\tm-\u003eBroadcastFramesXmittedOK = c[SCNT_TX_BC];\n+\t\tm-\u003eMulticastFramesReceivedOK = c[SCNT_RX_MC];\n+\t\tm-\u003eBroadcastFramesReceivedOK = c[SCNT_RX_BC];\n+\t\tm-\u003eInRangeLengthErrors = c[SCNT_RX_FRAG] +\n+\t\t\t\t\t c[SCNT_RX_JABBER] +\n+\t\t\t\t\t c[SCNT_RX_CRC];\n+\t\tm-\u003eOutOfRangeLengthField = c[SCNT_RX_SHORT] +\n+\t\t\t\t\t   c[SCNT_RX_LONG];\n+\t\tm-\u003eFrameTooLongErrors = c[SCNT_RX_LONG];\n+\t\tbreak;\n+\tcase ETHTOOL_MAC_STATS_SRC_PMAC:\n+\t\tm-\u003eFramesTransmittedOK = c[SCNT_TX_PMAC_UC] +\n+\t\t\t\t\t c[SCNT_TX_PMAC_MC] +\n+\t\t\t\t\t c[SCNT_TX_PMAC_BC];\n+\t\tm-\u003eFramesReceivedOK = c[SCNT_RX_PMAC_UC] +\n+\t\t\t\t      c[SCNT_RX_PMAC_MC] +\n+\t\t\t\t      c[SCNT_RX_PMAC_BC];\n+\t\tm-\u003eFrameCheckSequenceErrors = c[SCNT_RX_PMAC_CRC];\n+\t\tm-\u003eOctetsTransmittedOK = c[SCNT_TX_PMAC_OCT];\n+\t\tm-\u003eOctetsReceivedOK = c[SCNT_RX_PMAC_OCT];\n+\t\tm-\u003eMulticastFramesXmittedOK = c[SCNT_TX_PMAC_MC];\n+\t\tm-\u003eBroadcastFramesXmittedOK = c[SCNT_TX_PMAC_BC];\n+\t\tm-\u003eMulticastFramesReceivedOK = c[SCNT_RX_PMAC_MC];\n+\t\tm-\u003eBroadcastFramesReceivedOK = c[SCNT_RX_PMAC_BC];\n+\t\tm-\u003eInRangeLengthErrors = c[SCNT_RX_PMAC_FRAG] +\n+\t\t\t\t\t c[SCNT_RX_PMAC_JABBER] +\n+\t\t\t\t\t c[SCNT_RX_PMAC_CRC];\n+\t\tm-\u003eOutOfRangeLengthField = c[SCNT_RX_PMAC_SHORT] +\n+\t\t\t\t\t   c[SCNT_RX_PMAC_LONG];\n+\t\tm-\u003eFrameTooLongErrors = c[SCNT_RX_PMAC_LONG];\n+\t\tbreak;\n+\tdefault:\n+\t\tm-\u003eFramesTransmittedOK = c[SCNT_TX_UC] +\n+\t\t\t\t\t c[SCNT_TX_MC] +\n+\t\t\t\t\t c[SCNT_TX_BC] +\n+\t\t\t\t\t c[SCNT_TX_PMAC_UC] +\n+\t\t\t\t\t c[SCNT_TX_PMAC_MC] +\n+\t\t\t\t\t c[SCNT_TX_PMAC_BC];\n+\t\tm-\u003eSingleCollisionFrames = c[SCNT_TX_COL];\n+\t\tm-\u003eFramesReceivedOK = c[SCNT_RX_UC] +\n+\t\t\t\t      c[SCNT_RX_MC] +\n+\t\t\t\t      c[SCNT_RX_BC] +\n+\t\t\t\t      c[SCNT_RX_PMAC_UC] +\n+\t\t\t\t      c[SCNT_RX_PMAC_MC] +\n+\t\t\t\t      c[SCNT_RX_PMAC_BC];\n+\t\tm-\u003eFrameCheckSequenceErrors = c[SCNT_RX_CRC] +\n+\t\t\t\t\t      c[SCNT_RX_PMAC_CRC];\n+\t\tm-\u003eOctetsTransmittedOK = c[SCNT_TX_OCT] +\n+\t\t\t\t\t c[SCNT_TX_PMAC_OCT];\n+\t\tm-\u003eOctetsReceivedOK = c[SCNT_RX_OCT] +\n+\t\t\t\t      c[SCNT_RX_PMAC_OCT];\n+\t\tm-\u003eMulticastFramesXmittedOK = c[SCNT_TX_MC] +\n+\t\t\t\t\t      c[SCNT_TX_PMAC_MC];\n+\t\tm-\u003eBroadcastFramesXmittedOK = c[SCNT_TX_BC] +\n+\t\t\t\t\t      c[SCNT_TX_PMAC_BC];\n+\t\tm-\u003eMulticastFramesReceivedOK = c[SCNT_RX_MC] +\n+\t\t\t\t\t       c[SCNT_RX_PMAC_MC];\n+\t\tm-\u003eBroadcastFramesReceivedOK = c[SCNT_RX_BC] +\n+\t\t\t\t\t       c[SCNT_RX_PMAC_BC];\n+\t\tm-\u003eInRangeLengthErrors = c[SCNT_RX_FRAG] +\n+\t\t\t\t\t c[SCNT_RX_JABBER] +\n+\t\t\t\t\t c[SCNT_RX_CRC] +\n+\t\t\t\t\t c[SCNT_RX_PMAC_FRAG] +\n+\t\t\t\t\t c[SCNT_RX_PMAC_JABBER] +\n+\t\t\t\t\t c[SCNT_RX_PMAC_CRC];\n+\t\tm-\u003eOutOfRangeLengthField = c[SCNT_RX_SHORT] +\n+\t\t\t\t\t   c[SCNT_RX_LONG] +\n+\t\t\t\t\t   c[SCNT_RX_PMAC_SHORT] +\n+\t\t\t\t\t   c[SCNT_RX_PMAC_LONG];\n+\t\tm-\u003eFrameTooLongErrors = c[SCNT_RX_LONG] +\n+\t\t\t\t\tc[SCNT_RX_PMAC_LONG];\n+\t\tbreak;\n+\t}\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+}\n+\n+static const struct ethtool_rmon_hist_range lan9645x_rmon_ranges[] = {\n+\t{    64,     64 },\n+\t{   65,    127 },\n+\t{  128,    255 },\n+\t{  256,    511 },\n+\t{  512,   1023 },\n+\t{ 1024,   1526 },\n+\t{ 1527, 0xffff },\n+\t{}\n+};\n+\n+void\n+lan9645x_stats_get_rmon_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t      struct ethtool_rmon_stats *r,\n+\t\t\t      const struct ethtool_rmon_hist_range **ranges)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = lan9645x_stats_port_update(lan9645x, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tswitch (r-\u003esrc) {\n+\tcase ETHTOOL_MAC_STATS_SRC_EMAC:\n+\t\tr-\u003eundersize_pkts = c[SCNT_RX_SHORT];\n+\t\tr-\u003eoversize_pkts = c[SCNT_RX_LONG];\n+\t\tr-\u003efragments = c[SCNT_RX_FRAG];\n+\t\tr-\u003ejabbers = c[SCNT_RX_JABBER];\n+\t\tr-\u003ehist[0] = c[SCNT_RX_SZ_64];\n+\t\tr-\u003ehist[1] = c[SCNT_RX_SZ_65_127];\n+\t\tr-\u003ehist[2] = c[SCNT_RX_SZ_128_255];\n+\t\tr-\u003ehist[3] = c[SCNT_RX_SZ_256_511];\n+\t\tr-\u003ehist[4] = c[SCNT_RX_SZ_512_1023];\n+\t\tr-\u003ehist[5] = c[SCNT_RX_SZ_1024_1526];\n+\t\tr-\u003ehist[6] = c[SCNT_RX_SZ_JUMBO];\n+\t\tr-\u003ehist_tx[0] = c[SCNT_TX_SZ_64];\n+\t\tr-\u003ehist_tx[1] = c[SCNT_TX_SZ_65_127];\n+\t\tr-\u003ehist_tx[2] = c[SCNT_TX_SZ_128_255];\n+\t\tr-\u003ehist_tx[3] = c[SCNT_TX_SZ_256_511];\n+\t\tr-\u003ehist_tx[4] = c[SCNT_TX_SZ_512_1023];\n+\t\tr-\u003ehist_tx[5] = c[SCNT_TX_SZ_1024_1526];\n+\t\tr-\u003ehist_tx[6] = c[SCNT_TX_SZ_JUMBO];\n+\t\tbreak;\n+\tcase ETHTOOL_MAC_STATS_SRC_PMAC:\n+\t\tr-\u003eundersize_pkts = c[SCNT_RX_PMAC_SHORT];\n+\t\tr-\u003eoversize_pkts = c[SCNT_RX_PMAC_LONG];\n+\t\tr-\u003efragments = c[SCNT_RX_PMAC_FRAG];\n+\t\tr-\u003ejabbers = c[SCNT_RX_PMAC_JABBER];\n+\t\tr-\u003ehist[0] = c[SCNT_RX_PMAC_SZ_64];\n+\t\tr-\u003ehist[1] = c[SCNT_RX_PMAC_SZ_65_127];\n+\t\tr-\u003ehist[2] = c[SCNT_RX_PMAC_SZ_128_255];\n+\t\tr-\u003ehist[3] = c[SCNT_RX_PMAC_SZ_256_511];\n+\t\tr-\u003ehist[4] = c[SCNT_RX_PMAC_SZ_512_1023];\n+\t\tr-\u003ehist[5] = c[SCNT_RX_PMAC_SZ_1024_1526];\n+\t\tr-\u003ehist[6] = c[SCNT_RX_PMAC_SZ_JUMBO];\n+\t\tr-\u003ehist_tx[0] = c[SCNT_TX_PMAC_SZ_64];\n+\t\tr-\u003ehist_tx[1] = c[SCNT_TX_PMAC_SZ_65_127];\n+\t\tr-\u003ehist_tx[2] = c[SCNT_TX_PMAC_SZ_128_255];\n+\t\tr-\u003ehist_tx[3] = c[SCNT_TX_PMAC_SZ_256_511];\n+\t\tr-\u003ehist_tx[4] = c[SCNT_TX_PMAC_SZ_512_1023];\n+\t\tr-\u003ehist_tx[5] = c[SCNT_TX_PMAC_SZ_1024_1526];\n+\t\tr-\u003ehist_tx[6] = c[SCNT_TX_PMAC_SZ_JUMBO];\n+\t\tbreak;\n+\tdefault:\n+\t\tr-\u003eundersize_pkts = c[SCNT_RX_SHORT] +\n+\t\t\t\t    c[SCNT_RX_PMAC_SHORT];\n+\t\tr-\u003eoversize_pkts = c[SCNT_RX_LONG] +\n+\t\t\t\t   c[SCNT_RX_PMAC_LONG];\n+\t\tr-\u003efragments = c[SCNT_RX_FRAG] +\n+\t\t\t       c[SCNT_RX_PMAC_FRAG];\n+\t\tr-\u003ejabbers = c[SCNT_RX_JABBER] +\n+\t\t\t     c[SCNT_RX_PMAC_JABBER];\n+\t\tr-\u003ehist[0] = c[SCNT_RX_SZ_64] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_64];\n+\t\tr-\u003ehist[1] = c[SCNT_RX_SZ_65_127] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_65_127];\n+\t\tr-\u003ehist[2] = c[SCNT_RX_SZ_128_255] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_128_255];\n+\t\tr-\u003ehist[3] = c[SCNT_RX_SZ_256_511] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_256_511];\n+\t\tr-\u003ehist[4] = c[SCNT_RX_SZ_512_1023] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_512_1023];\n+\t\tr-\u003ehist[5] = c[SCNT_RX_SZ_1024_1526] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_1024_1526];\n+\t\tr-\u003ehist[6] = c[SCNT_RX_SZ_JUMBO] +\n+\t\t\t     c[SCNT_RX_PMAC_SZ_JUMBO];\n+\t\tr-\u003ehist_tx[0] = c[SCNT_TX_SZ_64] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_64];\n+\t\tr-\u003ehist_tx[1] = c[SCNT_TX_SZ_65_127] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_65_127];\n+\t\tr-\u003ehist_tx[2] = c[SCNT_TX_SZ_128_255] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_128_255];\n+\t\tr-\u003ehist_tx[3] = c[SCNT_TX_SZ_256_511] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_256_511];\n+\t\tr-\u003ehist_tx[4] = c[SCNT_TX_SZ_512_1023] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_512_1023];\n+\t\tr-\u003ehist_tx[5] = c[SCNT_TX_SZ_1024_1526] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_1024_1526];\n+\t\tr-\u003ehist_tx[6] = c[SCNT_TX_SZ_JUMBO] +\n+\t\t\t\tc[SCNT_TX_PMAC_SZ_JUMBO];\n+\t\tbreak;\n+\t}\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+\n+\t*ranges = lan9645x_rmon_ranges;\n+}\n+\n+/* Called in atomic context */\n+void lan9645x_stats_get_stats64(struct lan9645x *lan9645x, int port,\n+\t\t\t\tstruct rtnl_link_stats64 *stats)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = STAT_COUNTERS(lan9645x, LAN9645X_STAT_PORTS, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tstats-\u003erx_bytes = c[SCNT_RX_OCT] + c[SCNT_RX_PMAC_OCT];\n+\n+\tstats-\u003erx_packets = c[SCNT_RX_SHORT] +\n+\t\t\t    c[SCNT_RX_FRAG] +\n+\t\t\t    c[SCNT_RX_JABBER] +\n+\t\t\t    c[SCNT_RX_SZ_64] +\n+\t\t\t    c[SCNT_RX_SZ_65_127] +\n+\t\t\t    c[SCNT_RX_SZ_128_255] +\n+\t\t\t    c[SCNT_RX_SZ_256_511] +\n+\t\t\t    c[SCNT_RX_SZ_512_1023] +\n+\t\t\t    c[SCNT_RX_SZ_1024_1526] +\n+\t\t\t    c[SCNT_RX_SZ_JUMBO] +\n+\t\t\t    c[SCNT_RX_LONG] +\n+\t\t\t    c[SCNT_RX_PMAC_SHORT] +\n+\t\t\t    c[SCNT_RX_PMAC_FRAG] +\n+\t\t\t    c[SCNT_RX_PMAC_JABBER] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_64] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_65_127] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_128_255] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_256_511] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_512_1023] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_1024_1526] +\n+\t\t\t    c[SCNT_RX_PMAC_SZ_JUMBO];\n+\n+\tstats-\u003emulticast = c[SCNT_RX_MC] + c[SCNT_RX_PMAC_MC];\n+\n+\tstats-\u003erx_errors = c[SCNT_RX_SHORT] +\n+\t\t\t   c[SCNT_RX_FRAG] +\n+\t\t\t   c[SCNT_RX_JABBER] +\n+\t\t\t   c[SCNT_RX_CRC] +\n+\t\t\t   c[SCNT_RX_SYMBOL_ERR] +\n+\t\t\t   c[SCNT_RX_LONG] +\n+\t\t\t   c[SCNT_RX_PMAC_SHORT] +\n+\t\t\t   c[SCNT_RX_PMAC_FRAG] +\n+\t\t\t   c[SCNT_RX_PMAC_JABBER] +\n+\t\t\t   c[SCNT_RX_PMAC_CRC] +\n+\t\t\t   c[SCNT_RX_PMAC_SYMBOL_ERR] +\n+\t\t\t   c[SCNT_RX_PMAC_LONG];\n+\n+\tstats-\u003erx_dropped = c[SCNT_RX_LONG] +\n+\t\t\t    c[SCNT_DR_LOCAL] +\n+\t\t\t    c[SCNT_DR_TAIL] +\n+\t\t\t    c[SCNT_RX_CAT_DROP] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_0] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_1] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_2] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_3] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_4] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_5] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_6] +\n+\t\t\t    c[SCNT_RX_RED_PRIO_7];\n+\n+\tfor (int i = 0; i \u003c LAN9645X_NUM_TC; i++) {\n+\t\tstats-\u003erx_dropped += c[SCNT_DR_YELLOW_PRIO_0 + i] +\n+\t\t\t\t     c[SCNT_DR_GREEN_PRIO_0 + i];\n+\t}\n+\n+\tstats-\u003etx_bytes = c[SCNT_TX_OCT] + c[SCNT_TX_PMAC_OCT];\n+\n+\tstats-\u003etx_packets = c[SCNT_TX_SZ_64] +\n+\t\t\t    c[SCNT_TX_SZ_65_127] +\n+\t\t\t    c[SCNT_TX_SZ_128_255] +\n+\t\t\t    c[SCNT_TX_SZ_256_511] +\n+\t\t\t    c[SCNT_TX_SZ_512_1023] +\n+\t\t\t    c[SCNT_TX_SZ_1024_1526] +\n+\t\t\t    c[SCNT_TX_SZ_JUMBO] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_64] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_65_127] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_128_255] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_256_511] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_512_1023] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_1024_1526] +\n+\t\t\t    c[SCNT_TX_PMAC_SZ_JUMBO];\n+\n+\tstats-\u003etx_dropped = c[SCNT_TX_DROP] +\n+\t\t\t    c[SCNT_TX_AGED] +\n+\t\t\t    c[SCNT_TX_BUFDROP];\n+\n+\tstats-\u003ecollisions = c[SCNT_TX_COL];\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+}\n+\n+void lan9645x_stats_get_eth_phy_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t      struct ethtool_eth_phy_stats *p)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = lan9645x_stats_port_update(lan9645x, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tswitch (p-\u003esrc) {\n+\tcase ETHTOOL_MAC_STATS_SRC_EMAC:\n+\t\tp-\u003eSymbolErrorDuringCarrier = c[SCNT_RX_SYMBOL_ERR];\n+\t\tbreak;\n+\tcase ETHTOOL_MAC_STATS_SRC_PMAC:\n+\t\tp-\u003eSymbolErrorDuringCarrier = c[SCNT_RX_PMAC_SYMBOL_ERR];\n+\t\tbreak;\n+\tdefault:\n+\t\tp-\u003eSymbolErrorDuringCarrier = c[SCNT_RX_SYMBOL_ERR] +\n+\t\t\t\t\t      c[SCNT_RX_PMAC_SYMBOL_ERR];\n+\t\tbreak;\n+\t}\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+}\n+\n+void\n+lan9645x_stats_get_eth_ctrl_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t  struct ethtool_eth_ctrl_stats *ctrl)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = lan9645x_stats_port_update(lan9645x, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tswitch (ctrl-\u003esrc) {\n+\tcase ETHTOOL_MAC_STATS_SRC_EMAC:\n+\t\tctrl-\u003eMACControlFramesReceived = c[SCNT_RX_CONTROL];\n+\t\tbreak;\n+\tcase ETHTOOL_MAC_STATS_SRC_PMAC:\n+\t\tctrl-\u003eMACControlFramesReceived = c[SCNT_RX_PMAC_CONTROL];\n+\t\tbreak;\n+\tdefault:\n+\t\tctrl-\u003eMACControlFramesReceived = c[SCNT_RX_CONTROL] +\n+\t\t\t\t\t\t c[SCNT_RX_PMAC_CONTROL];\n+\t\tbreak;\n+\t}\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+}\n+\n+void lan9645x_stats_get_pause_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t    struct ethtool_pause_stats *ps)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = lan9645x_stats_port_update(lan9645x, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tswitch (ps-\u003esrc) {\n+\tcase ETHTOOL_MAC_STATS_SRC_EMAC:\n+\t\tps-\u003etx_pause_frames = c[SCNT_TX_PAUSE];\n+\t\tps-\u003erx_pause_frames = c[SCNT_RX_PAUSE];\n+\t\tbreak;\n+\tcase ETHTOOL_MAC_STATS_SRC_PMAC:\n+\t\tps-\u003etx_pause_frames = c[SCNT_TX_PMAC_PAUSE];\n+\t\tps-\u003erx_pause_frames = c[SCNT_RX_PMAC_PAUSE];\n+\t\tbreak;\n+\tdefault:\n+\t\tps-\u003etx_pause_frames = c[SCNT_TX_PAUSE] + c[SCNT_TX_PMAC_PAUSE];\n+\t\tps-\u003erx_pause_frames = c[SCNT_RX_PAUSE] + c[SCNT_RX_PMAC_PAUSE];\n+\t\tbreak;\n+\t}\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+}\n+\n+void lan9645x_stats_get_mm_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t struct ethtool_mm_stats *stats)\n+{\n+\tstruct lan9645x_stats *s = lan9645x-\u003estats;\n+\tu64 *c;\n+\n+\tc = lan9645x_stats_port_update(lan9645x, port);\n+\n+\tspin_lock(\u0026s-\u003esw_lock);\n+\n+\tstats-\u003eMACMergeFrameAssErrorCount = c[SCNT_RX_ASSEMBLY_ERR];\n+\tstats-\u003eMACMergeFrameSmdErrorCount = c[SCNT_RX_SMD_ERR];\n+\tstats-\u003eMACMergeFrameAssOkCount = c[SCNT_RX_ASSEMBLY_OK];\n+\tstats-\u003eMACMergeFragCountRx = c[SCNT_RX_MERGE_FRAG];\n+\tstats-\u003eMACMergeFragCountTx = c[SCNT_TX_MERGE_FRAG];\n+\tstats-\u003eMACMergeHoldCount = c[SCNT_TX_MM_HOLD];\n+\n+\tspin_unlock(\u0026s-\u003esw_lock);\n+}\n+\n+static void lan9645x_check_stats_work(struct work_struct *work)\n+{\n+\tstruct delayed_work *del_work = to_delayed_work(work);\n+\tstruct lan9645x_stats *stats;\n+\n+\tstats = container_of(del_work, struct lan9645x_stats, work);\n+\n+\tlan9645x_stats_update(stats-\u003elan9645x);\n+\n+\tqueue_delayed_work(stats-\u003equeue, \u0026stats-\u003ework,\n+\t\t\t   LAN9645X_STATS_CHECK_DELAY);\n+}\n+\n+static int lan9645x_stats_prepare_regions(struct lan9645x *lan9645x,\n+\t\t\t\t\t  struct lan9645x_view_stats *vstat)\n+{\n+\tstruct lan9645x_stat_region *regions;\n+\tconst u32 *layout = vstat-\u003elayout;\n+\tsize_t num_regions = 1;\n+\tint i;\n+\n+\tfor (i = 1; i \u003c vstat-\u003enum_cnts; i++)\n+\t\tif (layout[i] != layout[i - 1] + 1)\n+\t\t\tnum_regions++;\n+\n+\tregions = devm_kcalloc(lan9645x-\u003edev, num_regions, sizeof(*regions),\n+\t\t\t       GFP_KERNEL);\n+\tif (!regions)\n+\t\treturn -ENOMEM;\n+\n+\tvstat-\u003enum_regions = num_regions;\n+\tvstat-\u003eregions = regions;\n+\n+\tregions[0].base_offset = layout[0];\n+\tregions[0].cnts_base_idx = 0;\n+\tregions[0].cnt = 1;\n+\n+\tfor (i = 1, num_regions = 0; i \u003c vstat-\u003enum_cnts; i++) {\n+\t\tif (layout[i] != layout[i - 1] + 1) {\n+\t\t\tnum_regions++;\n+\t\t\tregions[num_regions].base_offset = layout[i];\n+\t\t\tregions[num_regions].cnts_base_idx = i;\n+\t\t\tregions[num_regions].cnt = 1;\n+\t\t} else {\n+\t\t\tregions[num_regions].cnt++;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int lan9645x_view_stat_init(struct lan9645x *lan9645x,\n+\t\t\t\t   struct lan9645x_view_stats *vstat,\n+\t\t\t\t   const struct lan9645x_view_stats *cfg)\n+{\n+\tsize_t total = cfg-\u003enum_cnts * cfg-\u003enum_indexes;\n+\tint err;\n+\n+\tmemcpy(vstat, cfg, sizeof(*cfg));\n+\n+\tvstat-\u003ecnts = devm_kcalloc(lan9645x-\u003edev, total, sizeof(u64),\n+\t\t\t\t   GFP_KERNEL);\n+\tif (!vstat-\u003ecnts)\n+\t\treturn -ENOMEM;\n+\n+\tvstat-\u003ebuf = devm_kcalloc(lan9645x-\u003edev, total, sizeof(u32),\n+\t\t\t\t  GFP_KERNEL);\n+\tif (!vstat-\u003ebuf)\n+\t\treturn -ENOMEM;\n+\n+\terr = lan9645x_stats_prepare_regions(lan9645x, vstat);\n+\tif (err)\n+\t\treturn err;\n+\n+\tvstat-\u003estats = lan9645x-\u003estats;\n+\n+\treturn 0;\n+}\n+\n+int lan9645x_stats_alloc(struct lan9645x *lan9645x)\n+{\n+\tconst struct lan9645x_view_stats *vs;\n+\tstruct lan9645x_stats *stats;\n+\tint err, i;\n+\n+\tlan9645x-\u003estats = devm_kzalloc(lan9645x-\u003edev, sizeof(*stats),\n+\t\t\t\t       GFP_KERNEL);\n+\tif (!lan9645x-\u003estats)\n+\t\treturn -ENOMEM;\n+\n+\tstats = lan9645x-\u003estats;\n+\tstats-\u003elan9645x = lan9645x;\n+\n+\tfor (i = 0; i \u003c ARRAY_SIZE(lan9645x_view_stat_cfgs); i++) {\n+\t\tvs = \u0026lan9645x_view_stat_cfgs[i];\n+\n+\t\tif (!vs-\u003enum_cnts)\n+\t\t\tcontinue;\n+\n+\t\terr = lan9645x_view_stat_init(lan9645x, \u0026stats-\u003eview[vs-\u003etype],\n+\t\t\t\t\t      vs);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\tstats-\u003equeue = alloc_ordered_workqueue(\"%s-stats\", 0,\n+\t\t\t\t\t       dev_name(lan9645x-\u003edev));\n+\tif (!stats-\u003equeue)\n+\t\treturn -ENOMEM;\n+\n+\tmutex_init(\u0026stats-\u003ehw_lock);\n+\tspin_lock_init(\u0026stats-\u003esw_lock);\n+\tINIT_DELAYED_WORK(\u0026stats-\u003ework, lan9645x_check_stats_work);\n+\n+\treturn 0;\n+}\n+\n+void lan9645x_stats_free(struct lan9645x *lan9645x)\n+{\n+\tcancel_delayed_work_sync(\u0026lan9645x-\u003estats-\u003ework);\n+\tdestroy_workqueue(lan9645x-\u003estats-\u003equeue);\n+\tmutex_destroy(\u0026lan9645x-\u003estats-\u003ehw_lock);\n+}\n+\n+void lan9645x_stats_init(struct lan9645x *lan9645x)\n+{\n+\tstruct lan9645x_stats *stats = lan9645x-\u003estats;\n+\n+\tqueue_delayed_work(stats-\u003equeue, \u0026stats-\u003ework,\n+\t\t\t   LAN9645X_STATS_CHECK_DELAY);\n+}\n+\n+void lan9645x_stats_deinit(struct lan9645x *lan9645x)\n+{\n+\tcancel_delayed_work_sync(\u0026lan9645x-\u003estats-\u003ework);\n+}\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.h\nnew file mode 100644\nindex 00000000000000..cd5db16258a09f\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.h\n@@ -0,0 +1,279 @@\n+/* SPDX-License-Identifier: GPL-2.0+ */\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#ifndef _LAN9645X_STATS_H_\n+#define _LAN9645X_STATS_H_\n+\n+#include \"lan9645x_main.h\"\n+\n+#define STATS_INDEX(vstats, idx) (\u0026(vstats)-\u003ecnts[(vstats)-\u003enum_cnts * (idx)])\n+\n+#define STAT_COUNTERS(lan9645x, type, idx) \\\n+\tSTATS_INDEX(lan9645x_get_vstats(lan9645x, type), idx)\n+\n+/* Counter indices into stat layout structs */\n+#define SCNT_FRER_SID_IN_PKT             0\n+#define SCNT_ISDX_GREEN_OCT              1\n+#define SCNT_ISDX_GREEN_PKT              2\n+#define SCNT_ISDX_YELLOW_OCT             3\n+#define SCNT_ISDX_YELLOW_PKT             4\n+#define SCNT_ISDX_RED_OCT                5\n+#define SCNT_ISDX_RED_PKT                6\n+#define SCNT_ISDX_DROP_GREEN_OCT         7\n+#define SCNT_ISDX_DROP_GREEN_PKT         8\n+#define SCNT_ISDX_DROP_YELLOW_OCT        9\n+#define SCNT_ISDX_DROP_YELLOW_PKT        10\n+\n+#define SCNT_SF_MATCHING_FRAMES_COUNT    0\n+#define SCNT_SF_NOT_PASSING_FRAMES_COUNT 1\n+#define SCNT_SF_NOT_PASSING_SDU_COUNT    2\n+#define SCNT_SF_RED_FRAMES_COUNT         3\n+#define SCNT_SF_STREAM_BLOCK_COUNT       4\n+\n+#define SCNT_ESDX_GREEN_OCT              0\n+#define SCNT_ESDX_GREEN_PKT              1\n+#define SCNT_ESDX_YELLOW_OCT             2\n+#define SCNT_ESDX_YELLOW_PKT             3\n+\n+#define SCNT_RX_OCT                      0\n+#define SCNT_RX_UC                       1\n+#define SCNT_RX_MC                       2\n+#define SCNT_RX_BC                       3\n+#define SCNT_RX_SHORT                    4\n+#define SCNT_RX_FRAG                     5\n+#define SCNT_RX_JABBER                   6\n+#define SCNT_RX_CRC                      7\n+#define SCNT_RX_SYMBOL_ERR               8\n+#define SCNT_RX_SZ_64                    9\n+#define SCNT_RX_SZ_65_127                10\n+#define SCNT_RX_SZ_128_255               11\n+#define SCNT_RX_SZ_256_511               12\n+#define SCNT_RX_SZ_512_1023              13\n+#define SCNT_RX_SZ_1024_1526             14\n+#define SCNT_RX_SZ_JUMBO                 15\n+#define SCNT_RX_PAUSE                    16\n+#define SCNT_RX_CONTROL                  17\n+#define SCNT_RX_LONG                     18\n+#define SCNT_RX_CAT_DROP                 19\n+#define SCNT_RX_RED_PRIO_0               20\n+#define SCNT_RX_RED_PRIO_1               21\n+#define SCNT_RX_RED_PRIO_2               22\n+#define SCNT_RX_RED_PRIO_3               23\n+#define SCNT_RX_RED_PRIO_4               24\n+#define SCNT_RX_RED_PRIO_5               25\n+#define SCNT_RX_RED_PRIO_6               26\n+#define SCNT_RX_RED_PRIO_7               27\n+#define SCNT_RX_YELLOW_PRIO_0            28\n+#define SCNT_RX_YELLOW_PRIO_1            29\n+#define SCNT_RX_YELLOW_PRIO_2            30\n+#define SCNT_RX_YELLOW_PRIO_3            31\n+#define SCNT_RX_YELLOW_PRIO_4            32\n+#define SCNT_RX_YELLOW_PRIO_5            33\n+#define SCNT_RX_YELLOW_PRIO_6            34\n+#define SCNT_RX_YELLOW_PRIO_7            35\n+#define SCNT_RX_GREEN_PRIO_0             36\n+#define SCNT_RX_GREEN_PRIO_1             37\n+#define SCNT_RX_GREEN_PRIO_2             38\n+#define SCNT_RX_GREEN_PRIO_3             39\n+#define SCNT_RX_GREEN_PRIO_4             40\n+#define SCNT_RX_GREEN_PRIO_5             41\n+#define SCNT_RX_GREEN_PRIO_6             42\n+#define SCNT_RX_GREEN_PRIO_7             43\n+#define SCNT_RX_ASSEMBLY_ERR             44\n+#define SCNT_RX_SMD_ERR                  45\n+#define SCNT_RX_ASSEMBLY_OK              46\n+#define SCNT_RX_MERGE_FRAG               47\n+#define SCNT_RX_PMAC_OCT                 48\n+#define SCNT_RX_PMAC_UC                  49\n+#define SCNT_RX_PMAC_MC                  50\n+#define SCNT_RX_PMAC_BC                  51\n+#define SCNT_RX_PMAC_SHORT               52\n+#define SCNT_RX_PMAC_FRAG                53\n+#define SCNT_RX_PMAC_JABBER              54\n+#define SCNT_RX_PMAC_CRC                 55\n+#define SCNT_RX_PMAC_SYMBOL_ERR          56\n+#define SCNT_RX_PMAC_SZ_64               57\n+#define SCNT_RX_PMAC_SZ_65_127           58\n+#define SCNT_RX_PMAC_SZ_128_255          59\n+#define SCNT_RX_PMAC_SZ_256_511          60\n+#define SCNT_RX_PMAC_SZ_512_1023         61\n+#define SCNT_RX_PMAC_SZ_1024_1526        62\n+#define SCNT_RX_PMAC_SZ_JUMBO            63\n+#define SCNT_RX_PMAC_PAUSE               64\n+#define SCNT_RX_PMAC_CONTROL             65\n+#define SCNT_RX_PMAC_LONG                66\n+#define SCNT_TX_OCT                      67\n+#define SCNT_TX_UC                       68\n+#define SCNT_TX_MC                       69\n+#define SCNT_TX_BC                       70\n+#define SCNT_TX_COL                      71\n+#define SCNT_TX_DROP                     72\n+#define SCNT_TX_PAUSE                    73\n+#define SCNT_TX_SZ_64                    74\n+#define SCNT_TX_SZ_65_127                75\n+#define SCNT_TX_SZ_128_255               76\n+#define SCNT_TX_SZ_256_511               77\n+#define SCNT_TX_SZ_512_1023              78\n+#define SCNT_TX_SZ_1024_1526             79\n+#define SCNT_TX_SZ_JUMBO                 80\n+#define SCNT_TX_YELLOW_PRIO_0            81\n+#define SCNT_TX_YELLOW_PRIO_1            82\n+#define SCNT_TX_YELLOW_PRIO_2            83\n+#define SCNT_TX_YELLOW_PRIO_3            84\n+#define SCNT_TX_YELLOW_PRIO_4            85\n+#define SCNT_TX_YELLOW_PRIO_5            86\n+#define SCNT_TX_YELLOW_PRIO_6            87\n+#define SCNT_TX_YELLOW_PRIO_7            88\n+#define SCNT_TX_GREEN_PRIO_0             89\n+#define SCNT_TX_GREEN_PRIO_1             90\n+#define SCNT_TX_GREEN_PRIO_2             91\n+#define SCNT_TX_GREEN_PRIO_3             92\n+#define SCNT_TX_GREEN_PRIO_4             93\n+#define SCNT_TX_GREEN_PRIO_5             94\n+#define SCNT_TX_GREEN_PRIO_6             95\n+#define SCNT_TX_GREEN_PRIO_7             96\n+#define SCNT_TX_AGED                     97\n+#define SCNT_TX_LLCT                     98\n+#define SCNT_TX_CT                       99\n+#define SCNT_TX_BUFDROP                  100\n+#define SCNT_TX_MM_HOLD                  101\n+#define SCNT_TX_MERGE_FRAG               102\n+#define SCNT_TX_PMAC_OCT                 103\n+#define SCNT_TX_PMAC_UC                  104\n+#define SCNT_TX_PMAC_MC                  105\n+#define SCNT_TX_PMAC_BC                  106\n+#define SCNT_TX_PMAC_PAUSE               107\n+#define SCNT_TX_PMAC_SZ_64               108\n+#define SCNT_TX_PMAC_SZ_65_127           109\n+#define SCNT_TX_PMAC_SZ_128_255          110\n+#define SCNT_TX_PMAC_SZ_256_511          111\n+#define SCNT_TX_PMAC_SZ_512_1023         112\n+#define SCNT_TX_PMAC_SZ_1024_1526        113\n+#define SCNT_TX_PMAC_SZ_JUMBO            114\n+#define SCNT_DR_LOCAL                    115\n+#define SCNT_DR_TAIL                     116\n+#define SCNT_DR_YELLOW_PRIO_0            117\n+#define SCNT_DR_YELLOW_PRIO_1            118\n+#define SCNT_DR_YELLOW_PRIO_2            119\n+#define SCNT_DR_YELLOW_PRIO_3            120\n+#define SCNT_DR_YELLOW_PRIO_4            121\n+#define SCNT_DR_YELLOW_PRIO_5            122\n+#define SCNT_DR_YELLOW_PRIO_6            123\n+#define SCNT_DR_YELLOW_PRIO_7            124\n+#define SCNT_DR_GREEN_PRIO_0             125\n+#define SCNT_DR_GREEN_PRIO_1             126\n+#define SCNT_DR_GREEN_PRIO_2             127\n+#define SCNT_DR_GREEN_PRIO_3             128\n+#define SCNT_DR_GREEN_PRIO_4             129\n+#define SCNT_DR_GREEN_PRIO_5             130\n+#define SCNT_DR_GREEN_PRIO_6             131\n+#define SCNT_DR_GREEN_PRIO_7             132\n+\n+enum lan9645x_view_stat_type {\n+\tLAN9645X_STAT_PORTS = 0,\n+\tLAN9645X_STAT_ISDX,\n+\tLAN9645X_STAT_ESDX,\n+\tLAN9645X_STAT_SFID,\n+\n+\tLAN9645X_STAT_NUM,\n+};\n+\n+struct lan9645x_stat_region {\n+\tu32 base_offset;\n+\tu32 cnt;\n+\tu32 cnts_base_idx;\n+};\n+\n+/* Counters are organized by indices/views such as\n+ *\n+ * - physical ports\n+ * - isdx\n+ * - esdx\n+ * - frer\n+ * - sfid\n+ *\n+ * Each view contains regions, which is a linear address range of related\n+ * stats. I.e. the ports index has RX, TX and Drop regions.\n+ *\n+ *\n+ * and you have a given counter replicated per index.\n+ */\n+struct lan9645x_view_stats {\n+\t/* HW register offsets indexed by SCNT_*, used for bulk reading */\n+\tconst u32 *layout;\n+\t/* Region description for this view, used for bulk reading */\n+\tstruct lan9645x_stat_region *regions;\n+\tstruct lan9645x_stats *stats;\n+\tchar name[16];\n+\t/* 64bit software counters with the same addr layout hw */\n+\tu64 *cnts;\n+\t/* Buffer for bulk reading counter regions from hw */\n+\tu32 *buf;\n+\t/* Number of counters per index in view */\n+\tu32 num_cnts;\n+\t/* Number of indexes in view */\n+\tu32 num_indexes;\n+\t/* Number of counter regions with counters at sequential addresses */\n+\tsize_t num_regions;\n+\tenum lan9645x_view_stat_type type;\n+};\n+\n+struct lan9645x_stats {\n+\tstruct lan9645x *lan9645x;\n+\tstruct mutex hw_lock; /* lock r/w to stat registers and u32 buf */\n+\tspinlock_t sw_lock; /* lock access to u64 software counters */\n+\tstruct delayed_work work;\n+\tstruct workqueue_struct *queue;\n+\n+\tstruct lan9645x_view_stats view[LAN9645X_STAT_NUM];\n+};\n+\n+static inline struct lan9645x_view_stats *\n+lan9645x_get_vstats(struct lan9645x *lan9645x,\n+\t\t    enum lan9645x_view_stat_type type)\n+{\n+\tif (WARN_ON(!(type \u003c LAN9645X_STAT_NUM)))\n+\t\treturn NULL;\n+\n+\treturn \u0026lan9645x-\u003estats-\u003eview[type];\n+}\n+\n+/* Add a possibly wrapping 32 bit value to a 64 bit counter */\n+static inline void lan9645x_stats_add_cnt(u64 *cnt, u32 val)\n+{\n+\tif (val \u003c (*cnt \u0026 U32_MAX))\n+\t\t*cnt += (u64)1 \u003c\u003c 32; /* value has wrapped */\n+\n+\t*cnt = (*cnt \u0026 ~(u64)U32_MAX) + val;\n+}\n+\n+int lan9645x_stats_alloc(struct lan9645x *lan9645x);\n+void lan9645x_stats_free(struct lan9645x *lan9645x);\n+void lan9645x_stats_init(struct lan9645x *lan9645x);\n+void lan9645x_stats_deinit(struct lan9645x *lan9645x);\n+void lan9645x_stats_get_strings(struct lan9645x *lan9645x, int port,\n+\t\t\t\tu32 stringset, u8 *data);\n+int lan9645x_stats_get_sset_count(struct lan9645x *lan9645x, int port,\n+\t\t\t\t  int sset);\n+void lan9645x_stats_get_ethtool_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t      uint64_t *data);\n+void lan9645x_stats_get_eth_mac_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t      struct ethtool_eth_mac_stats *mac_stats);\n+void\n+lan9645x_stats_get_rmon_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t      struct ethtool_rmon_stats *rmon_stats,\n+\t\t\t      const struct ethtool_rmon_hist_range **ranges);\n+void lan9645x_stats_get_stats64(struct lan9645x *lan9645x, int port,\n+\t\t\t\tstruct rtnl_link_stats64 *s);\n+void lan9645x_stats_get_mm_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t struct ethtool_mm_stats *stats);\n+void lan9645x_stats_get_pause_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t    struct ethtool_pause_stats *ps);\n+void\n+lan9645x_stats_get_eth_ctrl_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t  struct ethtool_eth_ctrl_stats *ctrl_stats);\n+void lan9645x_stats_get_eth_phy_stats(struct lan9645x *lan9645x, int port,\n+\t\t\t\t      struct ethtool_eth_phy_stats *phy_stats);\n+\n+#endif\ndiff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c\nnew file mode 100644\nindex 00000000000000..e2116132b4d488\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c\n@@ -0,0 +1,403 @@\n+// SPDX-License-Identifier: GPL-2.0+\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \"lan9645x_main.h\"\n+\n+#define VLANACCESS_CMD_IDLE\t\t0\n+#define VLANACCESS_CMD_READ\t\t1\n+#define VLANACCESS_CMD_WRITE\t\t2\n+#define VLANACCESS_CMD_INIT\t\t3\n+\n+struct lan9645x_vlan_port_info {\n+\tint untagged;\n+\tint tagged;\n+\tu16 untagged_vid;\n+};\n+\n+/* Calculate VLAN state of a port, across all VLANS. */\n+static void lan9645x_vlan_port_get_info(struct lan9645x *lan9645x, int port,\n+\t\t\t\t\tstruct lan9645x_vlan_port_info *info)\n+{\n+\tu16 vid;\n+\n+\tinfo-\u003euntagged = 0;\n+\tinfo-\u003etagged = 0;\n+\tinfo-\u003euntagged_vid = 0;\n+\n+\tfor (vid = 1; vid \u003c= VLAN_MAX; vid++) {\n+\t\tstruct lan9645x_vlan *v = \u0026lan9645x-\u003evlans[vid];\n+\n+\t\tif (!(v-\u003eportmask \u0026 BIT(port)))\n+\t\t\tcontinue;\n+\n+\t\tif (v-\u003euntagged \u0026 BIT(port)) {\n+\t\t\tinfo-\u003euntagged++;\n+\t\t\tinfo-\u003euntagged_vid = vid;\n+\t\t} else {\n+\t\t\tinfo-\u003etagged++;\n+\t\t}\n+\n+\t\t/* VLAN composition is invalid, so break early. */\n+\t\tif (info-\u003euntagged \u003e 1 \u0026\u0026 info-\u003etagged)\n+\t\t\tbreak;\n+\t}\n+}\n+\n+static int lan9645x_vlan_wait_for_completion(struct lan9645x *lan9645x)\n+{\n+\tu32 val;\n+\n+\treturn lan9645x_rd_poll_timeout(lan9645x, ANA_VLANACCESS, val,\n+\t\t\t\t\tANA_VLANACCESS_VLAN_TBL_CMD_GET(val) ==\n+\t\t\t\t\tVLANACCESS_CMD_IDLE);\n+}\n+\n+static int lan9645x_vlan_hw_wr(struct lan9645x *lan9645x, u16 vid)\n+{\n+\tstruct lan9645x_vlan *v = \u0026lan9645x-\u003evlans[vid];\n+\tbool cpu_dis = !(v-\u003eportmask \u0026 BIT(lan9645x-\u003enum_phys_ports));\n+\tu32 val;\n+\tint err;\n+\n+\tval = ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(cpu_dis) |\n+\t      ANA_VLANTIDX_V_INDEX_SET(vid) |\n+\t      ANA_VLANTIDX_VLAN_SEC_FWD_ENA_SET(v-\u003es_fwd_ena) |\n+\t      ANA_VLANTIDX_VLAN_FLOOD_DIS_SET(v-\u003efld_dis) |\n+\t      ANA_VLANTIDX_VLAN_PRIV_VLAN_SET(v-\u003eprv_vlan) |\n+\t      ANA_VLANTIDX_VLAN_LEARN_DISABLED_SET(v-\u003elrn_dis) |\n+\t      ANA_VLANTIDX_VLAN_MIRROR_SET(v-\u003emir) |\n+\t      ANA_VLANTIDX_VLAN_SRC_CHK_SET(v-\u003esrc_chk);\n+\n+\tlan_wr(val, lan9645x, ANA_VLANTIDX);\n+\tlan_wr(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(v-\u003eportmask),\n+\t       lan9645x, ANA_VLAN_PORT_MASK);\n+\tlan_wr(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_WRITE),\n+\t       lan9645x, ANA_VLANACCESS);\n+\n+\t/* The VLAN access engine completes in a fixed ~1us vs the polling\n+\t * timeout of 100_000 us. A timeout here therefore likely means the\n+\t * register bus itself is dead, not that the VLAN op failed. There is no\n+\t * meaningful recovery at runtime, so this function logs via dev_err()\n+\t * and runtime callers discard the return value. Only\n+\t * lan9645x_vlan_init() treats this as fatal so that probe fails early\n+\t * on a broken bus.\n+\t */\n+\terr = lan9645x_vlan_wait_for_completion(lan9645x);\n+\tif (err)\n+\t\tdev_err(lan9645x-\u003edev, \"Vlan set mask failed\\n\");\n+\n+\treturn err;\n+}\n+\n+u16 lan9645x_vlan_unaware_pvid(bool is_bridged)\n+{\n+\treturn is_bridged ? UNAWARE_PVID : HOST_PVID;\n+}\n+\n+static u16 lan9645x_vlan_port_get_pvid(struct lan9645x_port *port)\n+{\n+\tbool is_bridged = lan9645x_port_is_bridged(port);\n+\n+\tif (is_bridged \u0026\u0026 port-\u003evlan_aware)\n+\t\treturn port-\u003epvid;\n+\telse\n+\t\treturn lan9645x_vlan_unaware_pvid(is_bridged);\n+}\n+\n+/* Dynamically choose the egress tagging mode based on the port vlan state:\n+ *\n+ * Standalone:\n+ * TAG_NO_PVID_NO_UNAWARE with PORT_VID=HOST_PVID. This avoids leaking the\n+ * internal HOST_PVID tag on ingress mirrored frames while leaving normal\n+ * egress frames untagged.\n+ *\n+ * Bridged, VLAN-aware:\n+ *  - N untagged, 0 tagged: TAG_DISABLED\n+ *  - 1 untagged, N tagged: TAG_NO_PVID_NO_UNAWARE\n+ *  - 0 untagged, N tagged: TAG_ALL\n+ *\n+ * Bridged, VLAN-unaware:\n+ *   TAG_DISABLED\n+ */\n+static void\n+lan9645x_vlan_port_apply_egress(struct lan9645x_port *p,\n+\t\t\t\tstruct lan9645x_vlan_port_info *info)\n+{\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tenum lan9645x_vlan_port_tag tag_cfg;\n+\tu16 port_vid = UNAWARE_PVID;\n+\n+\tif (!lan9645x_port_is_bridged(p)) {\n+\t\ttag_cfg = LAN9645X_TAG_NO_PVID_NO_UNAWARE;\n+\t\tport_vid = HOST_PVID;\n+\t} else if (p-\u003evlan_aware) {\n+\t\tstruct lan9645x_vlan_port_info _info;\n+\n+\t\tif (!info) {\n+\t\t\tlan9645x_vlan_port_get_info(lan9645x, p-\u003echip_port,\n+\t\t\t\t\t\t    \u0026_info);\n+\t\t\tinfo = \u0026_info;\n+\t\t}\n+\n+\t\tif (info-\u003euntagged == 1 \u0026\u0026 info-\u003etagged) {\n+\t\t\ttag_cfg = LAN9645X_TAG_NO_PVID_NO_UNAWARE;\n+\t\t\tport_vid = info-\u003euntagged_vid;\n+\t\t} else if (info-\u003euntagged) {\n+\t\t\ttag_cfg = LAN9645X_TAG_DISABLED;\n+\t\t} else {\n+\t\t\ttag_cfg = LAN9645X_TAG_ALL;\n+\t\t}\n+\t} else {\n+\t\ttag_cfg = LAN9645X_TAG_DISABLED;\n+\t}\n+\n+\t/* TAG_TPID_CFG encoding:\n+\t *\n+\t * 0: Use 0x8100.\n+\t * 1: Use 0x88A8.\n+\t * 2: Use custom value from PORT_VLAN_CFG.PORT_TPID.\n+\t * 3: Use PORT_VLAN_CFG.PORT_TPID, unless ingress tag was a C-tag\n+\t *    (EtherType = 0x8100)\n+\t *\n+\t * Use 3 and PORT_VLAN_CFG.PORT_TPID=0x88a8 to ensure stags are not\n+\t * rewritten to ctags on egress.\n+\t */\n+\tlan_rmw(REW_TAG_CFG_TAG_TPID_CFG_SET(3) |\n+\t\tREW_TAG_CFG_TAG_CFG_SET(tag_cfg),\n+\t\tREW_TAG_CFG_TAG_TPID_CFG |\n+\t\tREW_TAG_CFG_TAG_CFG,\n+\t\tlan9645x, REW_TAG_CFG(p-\u003echip_port));\n+\n+\tlan_rmw(REW_PORT_VLAN_CFG_PORT_TPID_SET(ETH_P_8021AD) |\n+\t\tREW_PORT_VLAN_CFG_PORT_VID_SET(port_vid),\n+\t\tREW_PORT_VLAN_CFG_PORT_TPID |\n+\t\tREW_PORT_VLAN_CFG_PORT_VID,\n+\t\tlan9645x, REW_PORT_VLAN_CFG(p-\u003echip_port));\n+}\n+\n+static void lan9645x_vlan_port_apply_ingress(struct lan9645x_port *p)\n+{\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tu16 pvid;\n+\tu32 val;\n+\n+\tpvid = lan9645x_vlan_port_get_pvid(p);\n+\n+\t/* Default vlan to classify for untagged frames (may be zero), and set\n+\t * their tag type to C-tag.\n+\t */\n+\tval = ANA_VLAN_CFG_VLAN_VID_SET(pvid) |\n+\t      ANA_VLAN_CFG_VLAN_TAG_TYPE_SET(0);\n+\tif (p-\u003evlan_aware)\n+\t\tval |= ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |\n+\t\t       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1);\n+\n+\tlan_rmw(val,\n+\t\tANA_VLAN_CFG_VLAN_VID |\n+\t\tANA_VLAN_CFG_VLAN_AWARE_ENA |\n+\t\tANA_VLAN_CFG_VLAN_POP_CNT |\n+\t\tANA_VLAN_CFG_VLAN_TAG_TYPE,\n+\t\tlan9645x, ANA_VLAN_CFG(p-\u003echip_port));\n+\n+\tval = 0;\n+\tif (p-\u003evlan_aware \u0026\u0026 !pvid)\n+\t\t/* If port is vlan-aware and tagged, drop untagged and priority\n+\t\t * tagged frames.\n+\t\t */\n+\t\tval = ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(1) |\n+\t\t      ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(1) |\n+\t\t      ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(1);\n+\n+\tlan_rmw(val,\n+\t\tANA_DROP_CFG_DROP_UNTAGGED_ENA |\n+\t\tANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |\n+\t\tANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,\n+\t\tlan9645x, ANA_DROP_CFG(p-\u003echip_port));\n+}\n+\n+void lan9645x_vlan_port_apply(struct lan9645x_port *p)\n+{\n+\tlan9645x_vlan_port_apply_ingress(p);\n+\tlan9645x_vlan_port_apply_egress(p, NULL);\n+}\n+\n+static struct lan9645x_vlan *lan9645x_vlan_port_modify(struct lan9645x_port *p,\n+\t\t\t\t\t\t       u16 vid, bool pvid,\n+\t\t\t\t\t\t       bool untagged)\n+{\n+\tstruct lan9645x_vlan *v = \u0026p-\u003elan9645x-\u003evlans[vid];\n+\n+\tif (untagged)\n+\t\tv-\u003euntagged |= BIT(p-\u003echip_port);\n+\telse\n+\t\tv-\u003euntagged \u0026= ~BIT(p-\u003echip_port);\n+\n+\tif (pvid)\n+\t\tp-\u003epvid = vid;\n+\telse if (p-\u003epvid == vid)\n+\t\tp-\u003epvid = 0;\n+\n+\treturn v;\n+}\n+\n+static int lan9645x_vlan_cpu_add(struct lan9645x_port *p, u16 vid, bool pvid,\n+\t\t\t\t bool untagged)\n+{\n+\tstruct lan9645x_vlan *v;\n+\n+\tv = lan9645x_vlan_port_modify(p, vid, pvid, untagged);\n+\tv-\u003eportmask |= BIT(p-\u003elan9645x-\u003enum_phys_ports) | BIT(p-\u003echip_port);\n+\tlan9645x_vlan_hw_wr(p-\u003elan9645x, vid);\n+\tlan9645x_vlan_port_apply_ingress(p);\n+\n+\treturn 0;\n+}\n+\n+int lan9645x_vlan_port_add_vlan(struct lan9645x_port *p, u16 vid, bool pvid,\n+\t\t\t\tbool untagged, struct netlink_ext_ack *extack)\n+{\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tstruct lan9645x_vlan_port_info info;\n+\tstruct lan9645x_vlan old_vlan;\n+\tstruct lan9645x_vlan *v;\n+\tu16 old_pvid;\n+\n+\t/* Kernel VLAN core adds vid 0, which collides with our UNAWARE_PVID.\n+\t * We handle priority tagged frames by other means.\n+\t */\n+\tif (!vid)\n+\t\treturn 0;\n+\n+\tif (vid \u003e VLAN_MAX) {\n+\t\tNL_SET_ERR_MSG_MOD(extack, \"VLAN 4095 reserved.\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (p-\u003echip_port == lan9645x-\u003enpi)\n+\t\treturn lan9645x_vlan_cpu_add(p, vid, pvid, untagged);\n+\n+\told_vlan = lan9645x-\u003evlans[vid];\n+\told_pvid = p-\u003epvid;\n+\n+\tv = lan9645x_vlan_port_modify(p, vid, pvid, untagged);\n+\tv-\u003eportmask |= BIT(p-\u003echip_port);\n+\n+\tlan9645x_vlan_port_get_info(lan9645x, p-\u003echip_port, \u0026info);\n+\n+\tif (info.untagged \u003e 1 \u0026\u0026 info.tagged) {\n+\t\t*v = old_vlan;\n+\t\tp-\u003epvid = old_pvid;\n+\t\tNL_SET_ERR_MSG_MOD(extack, \"Only support 1 untagged port VLAN\");\n+\t\treturn -EBUSY;\n+\t}\n+\n+\tlan9645x_vlan_hw_wr(lan9645x, vid);\n+\tlan9645x_vlan_port_apply_ingress(p);\n+\tlan9645x_vlan_port_apply_egress(p, \u0026info);\n+\n+\treturn 0;\n+}\n+\n+static int lan9645x_vlan_cpu_del(struct lan9645x_port *p, u16 vid)\n+{\n+\tstruct lan9645x_vlan *v;\n+\n+\tv = lan9645x_vlan_port_modify(p, vid, false, false);\n+\tv-\u003eportmask \u0026= ~BIT(p-\u003elan9645x-\u003enum_phys_ports) \u0026 ~BIT(p-\u003echip_port);\n+\tlan9645x_vlan_hw_wr(p-\u003elan9645x, vid);\n+\tlan9645x_vlan_port_apply_ingress(p);\n+\n+\treturn 0;\n+}\n+\n+int lan9645x_vlan_port_del_vlan(struct lan9645x_port *p, u16 vid)\n+{\n+\tstruct lan9645x *lan9645x = p-\u003elan9645x;\n+\tstruct lan9645x_vlan *v;\n+\n+\tif (!vid)\n+\t\treturn 0;\n+\n+\tif (vid \u003e VLAN_MAX)\n+\t\treturn -EINVAL;\n+\n+\tif (p-\u003echip_port == lan9645x-\u003enpi)\n+\t\treturn lan9645x_vlan_cpu_del(p, vid);\n+\n+\tv = lan9645x_vlan_port_modify(p, vid, false, false);\n+\tv-\u003eportmask \u0026= ~BIT(p-\u003echip_port);\n+\tlan9645x_vlan_hw_wr(lan9645x, vid);\n+\tlan9645x_vlan_port_apply(p);\n+\n+\treturn 0;\n+}\n+\n+void lan9645x_vlan_set_hostmode(struct lan9645x_port *p)\n+{\n+\tp-\u003evlan_aware = false;\n+\tp-\u003elan9645x-\u003evlans[HOST_PVID].portmask |= BIT(p-\u003echip_port);\n+\tlan9645x_vlan_hw_wr(p-\u003elan9645x, HOST_PVID);\n+\tlan9645x_vlan_port_apply(p);\n+}\n+\n+void lan9645x_vlan_clear_hostmode(struct lan9645x_port *p)\n+{\n+\tp-\u003elan9645x-\u003evlans[HOST_PVID].portmask \u0026= ~BIT(p-\u003echip_port);\n+\tlan9645x_vlan_hw_wr(p-\u003elan9645x, HOST_PVID);\n+\tlan9645x_vlan_port_apply(p);\n+}\n+\n+int lan9645x_vlan_init(struct lan9645x *lan9645x)\n+{\n+\tu32 all_phys_ports, all_ports;\n+\tstruct dsa_port *dp;\n+\tu16 vid;\n+\tint err;\n+\n+\tall_phys_ports = GENMASK(lan9645x-\u003enum_phys_ports - 1, 0);\n+\tall_ports = all_phys_ports | BIT(lan9645x-\u003enum_phys_ports);\n+\n+\t/* Clear VLAN table, by default all ports are members of all VLANS */\n+\tlan_wr(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_INIT),\n+\t       lan9645x, ANA_VLANACCESS);\n+\n+\terr = lan9645x_vlan_wait_for_completion(lan9645x);\n+\tif (err) {\n+\t\tdev_err(lan9645x-\u003edev, \"Vlan clear table failed\\n\");\n+\t\treturn err;\n+\t}\n+\n+\tfor (vid = 1; vid \u003c VLAN_N_VID; vid++) {\n+\t\terr = lan9645x_vlan_hw_wr(lan9645x, vid);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\t/* Set all the ports + cpu to be part of HOST_PVID and UNAWARE_PVID */\n+\tlan9645x-\u003evlans[HOST_PVID].portmask = all_ports;\n+\terr = lan9645x_vlan_hw_wr(lan9645x, HOST_PVID);\n+\tif (err)\n+\t\treturn err;\n+\n+\tlan9645x-\u003evlans[UNAWARE_PVID].portmask = all_ports;\n+\terr = lan9645x_vlan_hw_wr(lan9645x, UNAWARE_PVID);\n+\tif (err)\n+\t\treturn err;\n+\n+\t/* Configure the CPU port module to be vlan aware */\n+\tlan_wr(ANA_VLAN_CFG_VLAN_VID_SET(UNAWARE_PVID) |\n+\t       ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |\n+\t       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1),\n+\t       lan9645x, ANA_VLAN_CFG(lan9645x-\u003enum_phys_ports));\n+\n+\t/* Set vlan ingress filter mask to all ports */\n+\tlan_wr(all_ports, lan9645x, ANA_VLANMASK);\n+\n+\tdsa_switch_for_each_user_port(dp, lan9645x-\u003eds) {\n+\t\tlan_wr(0, lan9645x, REW_PORT_VLAN_CFG(dp-\u003eindex));\n+\t\tlan_wr(0, lan9645x, REW_TAG_CFG(dp-\u003eindex));\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/include/linux/dsa/lan9645x.h b/include/linux/dsa/lan9645x.h\nnew file mode 100644\nindex 00000000000000..9896fab649c4d6\n--- /dev/null\n+++ b/include/linux/dsa/lan9645x.h\n@@ -0,0 +1,144 @@\n+/* SPDX-License-Identifier: GPL-2.0\n+ * Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#ifndef _NET_DSA_TAG_LAN9645X_H_\n+#define _NET_DSA_TAG_LAN9645X_H_\n+\n+#include \u003cnet/dsa.h\u003e\n+\n+/* LAN9645x supports 3 different formats on an NPI port, long prefix, short\n+ * prefix and no prefix. The format can be configured asymmetrically on RX and\n+ * TX. We use long prefix on extraction (RX), and no prefix on injection.\n+ * The long prefix on extraction helps get through the conduit port on host\n+ * side, since it will see a broadcast MAC.\n+ *\n+ * The internal frame header (IFH) is 28 bytes, and the fields are documented\n+ * below.\n+ *\n+ * Long prefix, 16 bytes + IFH:\n+ * - DMAC    = 0xFFFFFFFFFFFF on extraction.\n+ * - SMAC    = 0xFEFFFFFFFFFF on extraction.\n+ * - ETYPE   = 0x8880\n+ * - payload = 0x0011\n+ * - IFH\n+ *\n+ * Short prefix, 4 bytes + IFH:\n+ * - 0x8880\n+ * - 0x0011\n+ * - IFH\n+ *\n+ * No prefix:\n+ * - IFH\n+ *\n+ */\n+#define LAN9645X_IFH_TAG_TYPE_C\t0\n+#define LAN9645X_IFH_TAG_TYPE_S\t1\n+#define LAN9645X_IFH_LEN_U32\t\t7\n+#define LAN9645X_IFH_LEN\t\t(LAN9645X_IFH_LEN_U32 * sizeof(u32))\n+#define LAN9645X_IFH_BITS\t\t(LAN9645X_IFH_LEN * BITS_PER_BYTE)\n+#define LAN9645X_SHORT_PREFIX_LEN\t4\n+#define LAN9645X_LONG_PREFIX_LEN\t16\n+#define LAN9645X_TOTAL_TAG_LEN (LAN9645X_LONG_PREFIX_LEN + LAN9645X_IFH_LEN)\n+\n+#define IFH_INJ_TIMESTAMP\t\t192\n+#define IFH_BYPASS\t\t\t191\n+#define IFH_MASQ\t\t\t190\n+#define IFH_TIMESTAMP\t\t\t186\n+#define IFH_TIMESTAMP_NS\t\t194\n+#define IFH_TIMESTAMP_SUBNS\t\t186\n+#define IFH_MASQ_PORT\t\t\t186\n+#define IFH_RCT_INJ\t\t\t185\n+#define IFH_LEN\t\t\t\t171\n+#define IFH_WRDMODE\t\t\t169\n+#define IFH_RTAGD\t\t\t167\n+#define IFH_CUTTHRU\t\t\t166\n+#define IFH_REW_CMD\t\t\t156\n+#define IFH_REW_OAM\t\t\t155\n+#define IFH_PDU_TYPE\t\t\t151\n+#define IFH_FCS_UPD\t\t\t150\n+#define IFH_DP\t\t\t\t149\n+#define IFH_RTE_INB_UPDATE\t\t148\n+#define IFH_POP_CNT\t\t\t146\n+#define IFH_ETYPE_OFS\t\t\t144\n+#define IFH_SRCPORT\t\t\t140\n+#define IFH_SEQ_NUM\t\t\t120\n+#define IFH_TAG_TYPE\t\t\t119\n+#define IFH_TCI\t\t\t\t103\n+#define IFH_DSCP\t\t\t97\n+#define IFH_QOS_CLASS\t\t\t94\n+#define IFH_CPUQ\t\t\t86\n+#define IFH_LEARN_FLAGS\t\t\t84\n+#define IFH_SFLOW_ID\t\t\t80\n+#define IFH_ACL_HIT\t\t\t79\n+#define IFH_ACL_IDX\t\t\t73\n+#define IFH_ISDX\t\t\t65\n+#define IFH_DSTS\t\t\t55\n+#define IFH_FLOOD\t\t\t53\n+#define IFH_SEQ_OP\t\t\t51\n+#define IFH_IPV\t\t\t\t48\n+#define IFH_AFI\t\t\t\t47\n+#define IFH_RTP_ID\t\t\t37\n+#define IFH_RTP_SUBID\t\t\t36\n+#define IFH_PN_DATA_STATUS\t\t28\n+#define IFH_PN_TRANSF_STATUS_ZERO\t27\n+#define IFH_PN_CC\t\t\t11\n+#define IFH_DUPL_DISC_ENA\t\t10\n+#define IFH_RCT_AVAIL\t\t\t9\n+\n+#define IFH_INJ_TIMESTAMP_SZ\t\t32\n+#define IFH_BYPASS_SZ\t\t\t1\n+#define IFH_MASQ_SZ\t\t\t1\n+#define IFH_TIMESTAMP_SZ\t\t38\n+#define IFH_TIMESTAMP_NS_SZ\t\t30\n+#define IFH_TIMESTAMP_SUBNS_SZ\t\t8\n+#define IFH_MASQ_PORT_SZ\t\t4\n+#define IFH_RCT_INJ_SZ\t\t\t1\n+#define IFH_LEN_SZ\t\t\t14\n+#define IFH_WRDMODE_SZ\t\t\t2\n+#define IFH_RTAGD_SZ\t\t\t2\n+#define IFH_CUTTHRU_SZ\t\t\t1\n+#define IFH_REW_CMD_SZ\t\t\t10\n+#define IFH_REW_OAM_SZ\t\t\t1\n+#define IFH_PDU_TYPE_SZ\t\t\t4\n+#define IFH_FCS_UPD_SZ\t\t\t1\n+#define IFH_DP_SZ\t\t\t1\n+#define IFH_RTE_INB_UPDATE_SZ\t\t1\n+#define IFH_POP_CNT_SZ\t\t\t2\n+#define IFH_ETYPE_OFS_SZ\t\t2\n+#define IFH_SRCPORT_SZ\t\t\t4\n+#define IFH_SEQ_NUM_SZ\t\t\t16\n+#define IFH_TAG_TYPE_SZ\t\t\t1\n+#define IFH_TCI_SZ\t\t\t16\n+#define IFH_DSCP_SZ\t\t\t6\n+#define IFH_QOS_CLASS_SZ\t\t3\n+#define IFH_CPUQ_SZ\t\t\t8\n+#define IFH_LEARN_FLAGS_SZ\t\t2\n+#define IFH_SFLOW_ID_SZ\t\t\t4\n+#define IFH_ACL_HIT_SZ\t\t\t1\n+#define IFH_ACL_IDX_SZ\t\t\t6\n+#define IFH_ISDX_SZ\t\t\t8\n+#define IFH_DSTS_SZ\t\t\t10\n+#define IFH_FLOOD_SZ\t\t\t2\n+#define IFH_SEQ_OP_SZ\t\t\t2\n+#define IFH_IPV_SZ\t\t\t3\n+#define IFH_AFI_SZ\t\t\t1\n+#define IFH_RTP_ID_SZ\t\t\t10\n+#define IFH_RTP_SUBID_SZ\t\t1\n+#define IFH_PN_DATA_STATUS_SZ\t\t8\n+#define IFH_PN_TRANSF_STATUS_ZERO_SZ\t1\n+#define IFH_PN_CC_SZ\t\t\t16\n+#define IFH_DUPL_DISC_ENA_SZ\t\t1\n+#define IFH_RCT_AVAIL_SZ\t\t1\n+\n+/* Chip has 8 cpu queues. The cpu queues used by a frame is passed as a mask in\n+ * the IFH on extraction. We use this to avoid classifying BPDU, IGMP and MLD\n+ * frames in the tag driver.\n+ */\n+enum {\n+\tLAN9645X_CPUQ_DEF = 0,\n+\tLAN9645X_CPUQ_TRAP = 1,\n+\tLAN9645X_CPUQ_COPY = 2,\n+};\n+\n+#endif /* _NET_DSA_TAG_LAN9645X_H_ */\ndiff --git a/include/net/dsa.h b/include/net/dsa.h\nindex 8c16ef23cc102a..6ebd8c635d1716 100644\n--- a/include/net/dsa.h\n+++ b/include/net/dsa.h\n@@ -59,6 +59,7 @@ struct tc_action;\n #define DSA_TAG_PROTO_MXL_GSW1XX_VALUE\t\t31\n #define DSA_TAG_PROTO_MXL862_VALUE\t\t32\n #define DSA_TAG_PROTO_NETC_VALUE\t\t33\n+#define DSA_TAG_PROTO_LAN9645X_VALUE\t\t34\n \n enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_NONE\t\t= DSA_TAG_PROTO_NONE_VALUE,\n@@ -95,6 +96,7 @@ enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_MXL_GSW1XX\t= DSA_TAG_PROTO_MXL_GSW1XX_VALUE,\n \tDSA_TAG_PROTO_MXL862\t\t= DSA_TAG_PROTO_MXL862_VALUE,\n \tDSA_TAG_PROTO_NETC\t\t= DSA_TAG_PROTO_NETC_VALUE,\n+\tDSA_TAG_PROTO_LAN9645X\t\t= DSA_TAG_PROTO_LAN9645X_VALUE,\n };\n \n struct dsa_switch;\ndiff --git a/net/dsa/Kconfig b/net/dsa/Kconfig\nindex d5e725b90d7858..a0a0096e7e435f 100644\n--- a/net/dsa/Kconfig\n+++ b/net/dsa/Kconfig\n@@ -75,6 +75,17 @@ config NET_DSA_TAG_HELLCREEK\n \t  Say Y or M if you want to enable support for tagging frames\n \t  for the Hirschmann Hellcreek TSN switches.\n \n+config NET_DSA_TAG_LAN9645X\n+\ttristate \"Tag driver for Lan9645x switches\"\n+\thelp\n+\t  Say Y or M if you want to enable NPI tagging for the Lan9645x switches.\n+\t  In this mode, the frames over the Ethernet CPU port are prepended with\n+\t  a hardware-defined injection/extraction frame header.\n+\t  On injection a 28 byte internal frame header (IFH) is used. On\n+\t  extraction a 16 byte prefix is prepended before the internal frame\n+\t  header. This prefix starts with a broadcast MAC, to ease passage\n+\t  through the host side RX filter.\n+\n config NET_DSA_TAG_GSWIP\n \ttristate \"Tag driver for Lantiq / Intel GSWIP switches\"\n \thelp\ndiff --git a/net/dsa/Makefile b/net/dsa/Makefile\nindex b8c2667cd14aad..600975e0f2f7d6 100644\n--- a/net/dsa/Makefile\n+++ b/net/dsa/Makefile\n@@ -27,6 +27,7 @@ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o\n obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o\n obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o\n obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o\n+obj-$(CONFIG_NET_DSA_TAG_LAN9645X) += tag_lan9645x.o\n obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o\n obj-$(CONFIG_NET_DSA_TAG_MXL_862XX) += tag_mxl862xx.o\n obj-$(CONFIG_NET_DSA_TAG_MXL_GSW1XX) += tag_mxl-gsw1xx.o\ndiff --git a/net/dsa/tag_lan9645x.c b/net/dsa/tag_lan9645x.c\nnew file mode 100644\nindex 00000000000000..c9049e3620a128\n--- /dev/null\n+++ b/net/dsa/tag_lan9645x.c\n@@ -0,0 +1,311 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Copyright (C) 2026 Microchip Technology Inc.\n+ */\n+\n+#include \u003clinux/dsa/lan9645x.h\u003e\n+\n+#include \"tag.h\"\n+\n+#define LAN9645X_NAME \"lan9645x\"\n+\n+#define BTM_MSK(n)\t((u8)GENMASK(n, 0))\n+#define TOP_MSK(n)\t((u8)GENMASK(7, n))\n+\n+static inline void set_merge_mask(u8 *on_zero, u8 on_one, u8 mask)\n+{\n+\t*on_zero = *on_zero ^ ((*on_zero ^ on_one) \u0026 mask);\n+}\n+\n+/* The internal frame header (IFH) is a big-endian 28 byte unpadded bit array.\n+ * Frames can be prepended with an IFH on injection and extraction. There\n+ * are two field layouts, one for extraction and one for injection.\n+ *\n+ *    IFH bits go from high to low, for instance\n+ *    ifh[0]  = [223:216]\n+ *    ifh[27] = [7:0]\n+ *\n+ * Here is an example of setting a value starting at bit 13 of bit length 17.\n+ *\n+ * val    = 0x1ff\n+ * pos    = 13\n+ * length = 17\n+ *\n+ *\n+ * IFH[]   0                         23       24       25        26      27\n+ *\n+ *                                           end_u8           start_u8\n+ *      +--------+----------------+--------+--------+--------+--------+--------+\n+ *      |        |                |        |        |        |        |        |\n+ * IFH  |        | ....           |        |  vvvvvvvvvvvvvvvvvvv     |        |\n+ *      |        |                |        |  |     |        |  |     |        |\n+ *      +--------+----------------+--------+--+-----+--------+--+-----+--------+\n+ * Bits  223                       39    32 31|   24 23    16 15|    8 7      0\n+ *                                            |                 |\n+ *                                            |                 |\n+ *                                            |                 |\n+ *                                            v                 v\n+ *                                        end       = 29       pos        = 13\n+ *                                        end_rem   = 5        pos_rem    = 5\n+ *                                        end_u8    = 3        start_u8   = 1\n+ *                                        BTM_MSK(5)= 0x3f     TOP_MSK(5) = 0xe0\n+ *\n+ *\n+ * In end_u8 and start_u8 we must merge the existing IFH byte with the new\n+ * value. In the 'middle' bytes of the value we can overwrite the corresponding\n+ * IFH byte.\n+ */\n+static __always_inline void lan9645x_ifh_set(u8 *ifh, u32 val, size_t pos,\n+\t\t\t\t\t     size_t length)\n+{\n+\tsize_t end = (pos + length) - 1;\n+\tsize_t end_rem = end \u0026 0x7;\n+\tsize_t pos_rem = pos \u0026 0x7;\n+\tsize_t start_u8 = pos \u003e\u003e 3;\n+\tsize_t end_u8 = end \u003e\u003e 3;\n+\tu8 end_mask, start_mask;\n+\tsize_t vshift;\n+\tu8 *ptr;\n+\n+\tBUILD_BUG_ON_MSG(length \u003e 32, \"IFH field size wider than 32.\");\n+\tBUILD_BUG_ON_MSG(length == 0, \"IFH field size of 0.\");\n+\tBUILD_BUG_ON_MSG(pos + length \u003e LAN9645X_IFH_BITS,\n+\t\t\t \"IFH field overflows IFH\");\n+\n+\tend_mask = BTM_MSK(end_rem);\n+\tstart_mask = TOP_MSK(pos_rem);\n+\n+\tptr = \u0026ifh[LAN9645X_IFH_LEN - 1 - end_u8];\n+\n+\tif (end_u8 == start_u8)\n+\t\treturn set_merge_mask(ptr, val \u003c\u003c pos_rem,\n+\t\t\t\t      end_mask \u0026 start_mask);\n+\n+\tvshift = length - end_rem - 1;\n+\tset_merge_mask(ptr++, val \u003e\u003e vshift, end_mask);\n+\n+\tfor (size_t j = 1; j \u003c end_u8 - start_u8; j++) {\n+\t\tvshift -= 8;\n+\t\t*ptr++ = val \u003e\u003e vshift;\n+\t}\n+\n+\tset_merge_mask(ptr, val \u003c\u003c pos_rem, start_mask);\n+}\n+\n+static __always_inline u32 lan9645x_ifh_get(const u8 *ifh, size_t pos,\n+\t\t\t\t\t    size_t length)\n+{\n+\tsize_t end = (pos + length) - 1;\n+\tsize_t end_rem = end \u0026 0x7;\n+\tsize_t pos_rem = pos \u0026 0x7;\n+\tsize_t start_u8 = pos \u003e\u003e 3;\n+\tsize_t end_u8 = end \u003e\u003e 3;\n+\tu8 end_mask, start_mask;\n+\tconst u8 *ptr;\n+\tu32 val;\n+\n+\tBUILD_BUG_ON_MSG(length \u003e 32, \"IFH field size wider than 32.\");\n+\tBUILD_BUG_ON_MSG(length == 0, \"IFH field size of 0.\");\n+\tBUILD_BUG_ON_MSG(pos + length \u003e LAN9645X_IFH_BITS,\n+\t\t\t \"IFH field overflows IFH\");\n+\n+\tend_mask = BTM_MSK(end_rem);\n+\tstart_mask = TOP_MSK(pos_rem);\n+\n+\tptr = \u0026ifh[LAN9645X_IFH_LEN - 1 - end_u8];\n+\n+\tif (end_u8 == start_u8)\n+\t\treturn (*ptr \u0026 end_mask \u0026 start_mask) \u003e\u003e pos_rem;\n+\n+\tval = *ptr++ \u0026 end_mask;\n+\n+\tfor (size_t j = 1; j \u003c end_u8 - start_u8; j++)\n+\t\tval = val \u003c\u003c 8 | *ptr++;\n+\n+\treturn val \u003c\u003c (8 - pos_rem) | (*ptr \u0026 start_mask) \u003e\u003e pos_rem;\n+}\n+\n+static void lan9645x_xmit_get_vlan_info(struct sk_buff *skb,\n+\t\t\t\t\tstruct net_device *br,\n+\t\t\t\t\tu32 *vlan_tci, u32 *tag_type)\n+{\n+\tstruct vlan_ethhdr *hdr;\n+\tu16 proto, tci;\n+\n+\tif (!br || !br_vlan_enabled(br)) {\n+\t\t*vlan_tci = 0;\n+\t\t*tag_type = LAN9645X_IFH_TAG_TYPE_C;\n+\t\treturn;\n+\t}\n+\n+\thdr = (struct vlan_ethhdr *)skb_mac_header(skb);\n+\tbr_vlan_get_proto(br, \u0026proto);\n+\n+\tif (skb_headlen(skb) \u003e= VLAN_ETH_HLEN \u0026\u0026\n+\t    ntohs(hdr-\u003eh_vlan_proto) == proto) {\n+\t\tvlan_remove_tag(skb, \u0026tci);\n+\t\t*vlan_tci = tci;\n+\t} else {\n+\t\trcu_read_lock();\n+\t\tbr_vlan_get_pvid_rcu(br, \u0026tci);\n+\t\trcu_read_unlock();\n+\t\t*vlan_tci = tci;\n+\t}\n+\n+\t*tag_type = (proto != ETH_P_8021Q) ? LAN9645X_IFH_TAG_TYPE_S :\n+\t\t\t\t\t     LAN9645X_IFH_TAG_TYPE_C;\n+}\n+\n+static void lan9645x_offload_fwd_mark(struct sk_buff *skb, u32 cpuq)\n+{\n+\t/* Trapped frames must be forwarded by the stack. */\n+\tif (cpuq \u0026 BIT(LAN9645X_CPUQ_TRAP)) {\n+\t\tskb-\u003eoffload_fwd_mark = 0;\n+\t\treturn;\n+\t}\n+\n+\tdsa_default_offload_fwd_mark(skb);\n+}\n+\n+static struct sk_buff *lan9645x_xmit(struct sk_buff *skb,\n+\t\t\t\t     struct net_device *ndev)\n+{\n+\tstruct dsa_port *dp = dsa_user_to_port(ndev);\n+\tstruct dsa_switch *ds = dp-\u003eds;\n+\tu32 vlan_tci, tag_type;\n+\tu32 qos_class;\n+\tvoid *ifh;\n+\n+\tlan9645x_xmit_get_vlan_info(skb, dsa_port_bridge_dev_get(dp), \u0026vlan_tci,\n+\t\t\t\t    \u0026tag_type);\n+\n+\t/* We need to make sure frame has the proper size after IFH is stripped\n+\t * by hw.\n+\t */\n+\tif (__skb_put_padto(skb, ETH_ZLEN, false))\n+\t\treturn NULL;\n+\n+\tqos_class = netdev_get_num_tc(ndev) ?\n+\t\t    netdev_get_prio_tc_map(ndev, skb-\u003epriority) :\n+\t\t    skb-\u003epriority;\n+\n+\t/* Make room for IFH */\n+\tifh = skb_push(skb, LAN9645X_IFH_LEN);\n+\tmemset(ifh, 0, LAN9645X_IFH_LEN);\n+\n+\tlan9645x_ifh_set(ifh, 1, IFH_BYPASS, IFH_BYPASS_SZ);\n+\tlan9645x_ifh_set(ifh, ds-\u003enum_ports, IFH_SRCPORT, IFH_SRCPORT_SZ);\n+\tlan9645x_ifh_set(ifh, tag_type, IFH_TAG_TYPE, IFH_TAG_TYPE_SZ);\n+\tlan9645x_ifh_set(ifh, vlan_tci, IFH_TCI, IFH_TCI_SZ);\n+\tlan9645x_ifh_set(ifh, qos_class, IFH_QOS_CLASS, IFH_QOS_CLASS_SZ);\n+\tlan9645x_ifh_set(ifh, BIT(dp-\u003eindex), IFH_DSTS, IFH_DSTS_SZ);\n+\n+\treturn skb;\n+}\n+\n+static struct sk_buff *lan9645x_rcv(struct sk_buff *skb,\n+\t\t\t\t    struct net_device *ndev)\n+{\n+\tu32 src_port, qos_class, vlan_tci, tag_type, popcnt, etype_ofs, cpuq;\n+\tstruct dsa_port *dp;\n+\tu32 ifh_gap_len = 0;\n+\tu16 vlan_tpid;\n+\tu8 *ifh;\n+\n+\t/* DSA master already consumed DMAC,SMAC,ETYPE from long prefix. Go back\n+\t * to beginning of frame.\n+\t */\n+\tskb_push(skb, ETH_HLEN);\n+\n+\tif (unlikely(!pskb_may_pull(skb, LAN9645X_TOTAL_TAG_LEN)))\n+\t\treturn NULL;\n+\n+\t/* IFH starts after our long prefix */\n+\tifh = skb_pull(skb, LAN9645X_LONG_PREFIX_LEN);\n+\n+\tpopcnt = lan9645x_ifh_get(ifh, IFH_POP_CNT, IFH_POP_CNT_SZ);\n+\tetype_ofs = lan9645x_ifh_get(ifh, IFH_ETYPE_OFS, IFH_ETYPE_OFS_SZ);\n+\tsrc_port = lan9645x_ifh_get(ifh, IFH_SRCPORT, IFH_SRCPORT_SZ);\n+\ttag_type = lan9645x_ifh_get(ifh, IFH_TAG_TYPE, IFH_TAG_TYPE_SZ);\n+\tvlan_tci = lan9645x_ifh_get(ifh, IFH_TCI, IFH_TCI_SZ);\n+\tqos_class = lan9645x_ifh_get(ifh, IFH_QOS_CLASS, IFH_QOS_CLASS_SZ);\n+\tcpuq = lan9645x_ifh_get(ifh, IFH_CPUQ, IFH_CPUQ_SZ);\n+\n+\t/* Set skb-\u003edata at start of real header\n+\t *\n+\t * Since REW_PORT_NO_REWRITE=0 is required on the NPI port, we need to\n+\t * account for any tags popped by the hardware, as that will leave a gap\n+\t * between the IFH and DMAC.\n+\t */\n+\tif (popcnt == 0 \u0026\u0026 etype_ofs == 0)\n+\t\tifh_gap_len = 2 * VLAN_HLEN;\n+\telse if (popcnt == 3)\n+\t\tifh_gap_len = VLAN_HLEN;\n+\n+\tskb_pull(skb, LAN9645X_IFH_LEN);\n+\n+\tif (unlikely(!pskb_may_pull(skb, ifh_gap_len + ETH_HLEN)))\n+\t\treturn NULL;\n+\n+\tskb_pull(skb, ifh_gap_len);\n+\tskb_reset_mac_header(skb);\n+\tskb_set_network_header(skb, ETH_HLEN);\n+\tskb_reset_mac_len(skb);\n+\n+\t/* Reset skb-\u003edata past the actual ethernet header. */\n+\tskb_pull(skb, ETH_HLEN);\n+\n+\t/* We must deliver the skb so skb-\u003ecsum only covers the data beyond the\n+\t * real ethernet header. The fake ethernet header in the prefix is\n+\t * not part of skb-\u003ecsum already. We must subtract what remains of the\n+\t * prefix, the ifh and the gap.\n+\t */\n+\tskb_postpull_rcsum(skb,\n+\t\t\t   skb-\u003edata - LAN9645X_TOTAL_TAG_LEN - ifh_gap_len,\n+\t\t\t   LAN9645X_TOTAL_TAG_LEN + ifh_gap_len);\n+\n+\tskb-\u003edev = dsa_conduit_find_user(ndev, 0, src_port);\n+\tif (WARN_ON_ONCE(!skb-\u003edev)) {\n+\t\t/* This should never happen since we have disabled reflection\n+\t\t * back to the CPU.\n+\t\t */\n+\t\treturn NULL;\n+\t}\n+\n+\tlan9645x_offload_fwd_mark(skb, cpuq);\n+\n+\tskb-\u003epriority = qos_class;\n+\n+\t/* While we have REW_PORT_NO_REWRITE=0 on the NPI port, we still disable\n+\t * port VLAN tagging with REW_TAG_CFG. Any classified VID, different\n+\t * from a VID in the frame, will not be written to the frame, but is\n+\t * only communicated via the IFH. So for VLAN-aware ports we add the IFH\n+\t * vlan to the skb.\n+\t */\n+\tdp = dsa_user_to_port(skb-\u003edev);\n+\tvlan_tpid = tag_type ? ETH_P_8021AD : ETH_P_8021Q;\n+\n+\tif (dsa_port_is_vlan_filtering(dp) \u0026\u0026 vlan_tci) {\n+\t\tu16 port_pvid = 0;\n+\n+\t\tbr_vlan_get_pvid_rcu(skb-\u003edev, \u0026port_pvid);\n+\n+\t\tif ((vlan_tci \u0026 VLAN_VID_MASK) != port_pvid)\n+\t\t\t__vlan_hwaccel_put_tag(skb, htons(vlan_tpid), vlan_tci);\n+\t}\n+\n+\treturn skb;\n+}\n+\n+static const struct dsa_device_ops lan9645x_netdev_ops = {\n+\t.name = LAN9645X_NAME,\n+\t.proto = DSA_TAG_PROTO_LAN9645X,\n+\t.xmit = lan9645x_xmit,\n+\t.rcv = lan9645x_rcv,\n+\t.needed_headroom = LAN9645X_TOTAL_TAG_LEN,\n+};\n+\n+MODULE_DESCRIPTION(\"DSA tag driver for LAN9645x family of switches, using NPI port\");\n+MODULE_LICENSE(\"GPL\");\n+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9645X, LAN9645X_NAME);\n+\n+module_dsa_tag_driver(lan9645x_netdev_ops);\n"
}

2/1 2026/07/02 11:57 agent patch-evaluator
5m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch adds a new DSA switch driver and a tag driver for the Microchip LAN9645x hardware. The switch driver requires specific regmaps provided by a parent device, which does not exist in the kernel, making it impossible to probe. Even if probed, it requires physical hardware that is not emulated in virtualized environments like QEMU/GCE. The tag driver is also unreachable because no virtual DSA switch (like `dsa_loop`) supports changing its tag protocol to `lan9645x` dynamically. Thus, the code cannot be executed or fuzzed.",
  "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).

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.
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.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. 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 7b076893bcffa3d7d71366927f42b557cbffcf5f
Author: syz-cluster <triage@syzkaller.com>
Date:   Thu Jul 2 11:57:33 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml
new file mode 100644
index 00000000000000..043fb48922b41d
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/dsa/microchip,lan96455s-switch.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Microchip LAN9645x Ethernet switch
+
+maintainers:
+  - Jens Emil Schulz Østergaard <jensemil.schulzostergaard@microchip.com>
+
+description:
+  The LAN9645x switch is a multi-port Gigabit AVB/TSN Ethernet switch with
+  five integrated 10/100/1000Base-T PHYs. In addition to the integrated PHYs,
+  it supports up to 2 RGMII/RMII, up to 2 BASE-X/SERDES/2.5GBASE-X and one
+  Quad-SGMII interfaces.
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - microchip,lan96455s-switch
+      - items:
+          - enum:
+              - microchip,lan96455f-switch
+              - microchip,lan96457f-switch
+              - microchip,lan96459f-switch
+              - microchip,lan96457s-switch
+              - microchip,lan96459s-switch
+          - const: microchip,lan96455s-switch
+
+  reg:
+    maxItems: 1
+
+  ethernet-ports:
+    type: object
+    patternProperties:
+      "^ethernet-port@[0-8]$":
+        type: object
+        description: Ethernet switch ports
+
+        $ref: dsa-port.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          rx-internal-delay-ps:
+            const: 2000
+
+          tx-internal-delay-ps:
+            const: 2000
+
+$ref: dsa.yaml#/$defs/ethernet-ports
+
+required:
+  - compatible
+  - reg
+  - ethernet-ports
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    ethernet-switch@4000 {
+        compatible = "microchip,lan96459f-switch", "microchip,lan96455s-switch";
+        reg = <0x4000 0x244>;
+
+        ethernet-ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            ethernet-port@0 {
+                reg = <0>;
+                phy-mode = "gmii";
+                phy-handle = <&cuphy0>;
+            };
+
+            ethernet-port@1 {
+                reg = <1>;
+                phy-mode = "gmii";
+                phy-handle = <&cuphy1>;
+            };
+
+            ethernet-port@2 {
+                reg = <2>;
+                phy-mode = "gmii";
+                phy-handle = <&cuphy2>;
+            };
+
+            ethernet-port@3 {
+                reg = <3>;
+                phy-mode = "gmii";
+                phy-handle = <&cuphy3>;
+            };
+
+            ethernet-port@7 {
+                reg = <7>;
+                phy-mode = "rgmii";
+                ethernet = <&cpu_host_port>;
+                rx-internal-delay-ps = <2000>;
+                tx-internal-delay-ps = <2000>;
+
+                fixed-link {
+                    speed = <1000>;
+                    full-duplex;
+                    pause;
+                };
+            };
+        };
+    };
+...
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 15011f5752a994..86618efffa7780 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17627,6 +17627,16 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/phy/microchip_t1.c
 
+MICROCHIP LAN9645X ETHERNET SWITCH DRIVER
+M:	Jens Emil Schulz Østergaard <jensemil.schulzostergaard@microchip.com>
+M:	UNGLinuxDriver@microchip.com
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml
+F:	drivers/net/dsa/microchip/lan9645x/*
+F:	include/linux/dsa/lan9645x.h
+F:	net/dsa/tag_lan9645x.c
+
 MICROCHIP LAN966X ETHERNET DRIVER
 M:	Horatiu Vultur <horatiu.vultur@microchip.com>
 M:	UNGLinuxDriver@microchip.com
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 4ab567c5bbafc6..91431ef6c425cd 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/microchip/lan9645x/Kconfig"
+
 source "drivers/net/dsa/mv88e6xxx/Kconfig"
 
 source "drivers/net/dsa/mxl862xx/Kconfig"
diff --git a/drivers/net/dsa/microchip/Makefile b/drivers/net/dsa/microchip/Makefile
index 9347cfb3d0b5e7..e75f17888f75d0 100644
--- a/drivers/net/dsa/microchip/Makefile
+++ b/drivers/net/dsa/microchip/Makefile
@@ -12,3 +12,4 @@ endif
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ9477_I2C)	+= ksz9477_i2c.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ_SPI)		+= ksz_spi.o
 obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)	+= ksz8863_smi.o
+obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X)	+= lan9645x/
diff --git a/drivers/net/dsa/microchip/lan9645x/Kconfig b/drivers/net/dsa/microchip/lan9645x/Kconfig
new file mode 100644
index 00000000000000..4d9fdf34104eb5
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config NET_DSA_MICROCHIP_LAN9645X
+	tristate "Microchip Lan9645x switch support"
+	depends on NET_DSA
+	select NET_DSA_TAG_LAN9645X
+	help
+	  This driver adds DSA support for Microchip Lan9645x switch chips.
+	  The lan9645x switch is a multi-port Gigabit AVB/TSN Ethernet Switch
+	  with five integrated 10/100/1000Base-T PHYs. In addition to the
+	  integrated PHYs, it supports up to 2 RGMII/RMII, up to 2
+	  BASE-X/SERDES/2.5GBASE-X and one Quad-SGMII/Quad-USGMII interfaces.
diff --git a/drivers/net/dsa/microchip/lan9645x/Makefile b/drivers/net/dsa/microchip/lan9645x/Makefile
new file mode 100644
index 00000000000000..cd994943c1c059
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X) += mchp-lan9645x.o
+
+mchp-lan9645x-objs := \
+	lan9645x_mac.o \
+	lan9645x_main.o \
+	lan9645x_mdb.o \
+	lan9645x_npi.o \
+	lan9645x_phylink.o \
+	lan9645x_port.o \
+	lan9645x_stats.o \
+	lan9645x_vlan.o \
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_mac.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_mac.c
new file mode 100644
index 00000000000000..aefb3c58370a5b
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_mac.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include "lan9645x_main.h"
+
+#define CMD_IDLE		0
+#define CMD_LEARN		1
+#define CMD_FORGET		2
+#define CMD_AGE			3
+#define CMD_GET_NEXT		4
+#define CMD_INIT		5
+#define CMD_READ		6
+#define CMD_WRITE		7
+#define CMD_SYNC_GET_NEXT	8
+
+static int lan9645x_mac_wait_for_completion(struct lan9645x *lan9645x,
+					    u32 *maca)
+{
+	u32 val = 0;
+	int err;
+
+	lockdep_assert_held(&lan9645x->mact_lock);
+
+	err = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,
+				       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==
+				       CMD_IDLE);
+	if (err)
+		return err;
+
+	if (maca)
+		*maca = val;
+
+	return 0;
+}
+
+static void lan9645x_mac_select(struct lan9645x *lan9645x,
+				const unsigned char *addr, u16 vid)
+{
+	u64 maddr = ether_addr_to_u64(addr);
+
+	lockdep_assert_held(&lan9645x->mact_lock);
+
+	lan_wr(ANA_MACHDATA_VID_SET(vid) |
+	       ANA_MACHDATA_MACHDATA_SET(maddr >> 32),
+	       lan9645x,
+	       ANA_MACHDATA);
+
+	lan_wr(maddr & GENMASK(31, 0),
+	       lan9645x,
+	       ANA_MACLDATA);
+}
+
+static int __lan9645x_mact_forget(struct lan9645x *lan9645x,
+				  const unsigned char mac[ETH_ALEN],
+				  unsigned int vid,
+				  enum macaccess_entry_type type)
+{
+	lockdep_assert_held(&lan9645x->mact_lock);
+
+	lan9645x_mac_select(lan9645x, mac, vid);
+
+	lan_wr(ANA_MACACCESS_ENTRYTYPE_SET(type) |
+	       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_FORGET),
+	       lan9645x,
+	       ANA_MACACCESS);
+
+	return lan9645x_mac_wait_for_completion(lan9645x, NULL);
+}
+
+int lan9645x_mact_forget(struct lan9645x *lan9645x,
+			 const unsigned char mac[ETH_ALEN], unsigned int vid,
+			 enum macaccess_entry_type type)
+{
+	int err;
+
+	mutex_lock(&lan9645x->mact_lock);
+	err = __lan9645x_mact_forget(lan9645x, mac, vid, type);
+	mutex_unlock(&lan9645x->mact_lock);
+
+	return err;
+}
+
+static bool lan9645x_mac_ports_use_cpu(struct lan9645x *lan9645x,
+				       const unsigned char *mac,
+				       enum macaccess_entry_type type)
+{
+	u32 mc_ports;
+
+	switch (type) {
+	case ENTRYTYPE_MACV4:
+		mc_ports = (mac[1] << 8) | mac[2];
+		break;
+	case ENTRYTYPE_MACV6:
+		mc_ports = (mac[0] << 8) | mac[1];
+		break;
+	default:
+		return false;
+	}
+
+	return !!(mc_ports & BIT(lan9645x->num_phys_ports));
+}
+
+static int __lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,
+					  const unsigned char *addr, u16 vid,
+					  enum macaccess_entry_type type,
+					  bool cpu_copy)
+{
+	lockdep_assert_held(&lan9645x->mact_lock);
+
+	lan9645x_mac_select(lan9645x, addr, vid);
+
+	lan_wr(ANA_MACACCESS_VALID_SET(1) |
+	       ANA_MACACCESS_DEST_IDX_SET(port) |
+	       ANA_MACACCESS_MAC_CPU_COPY_SET(cpu_copy) |
+	       ANA_MACACCESS_ENTRYTYPE_SET(type) |
+	       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_LEARN),
+	       lan9645x, ANA_MACACCESS);
+
+	return lan9645x_mac_wait_for_completion(lan9645x, NULL);
+}
+
+static int __lan9645x_mact_learn(struct lan9645x *lan9645x, int port,
+				 const unsigned char *addr, u16 vid,
+				 enum macaccess_entry_type type)
+{
+	bool cpu_copy = lan9645x_mac_ports_use_cpu(lan9645x, addr, type);
+
+	return __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,
+					      cpu_copy);
+}
+
+int lan9645x_mact_learn(struct lan9645x *lan9645x, int port,
+			const unsigned char *addr, u16 vid,
+			enum macaccess_entry_type type)
+{
+	int err;
+
+	mutex_lock(&lan9645x->mact_lock);
+	err = __lan9645x_mact_learn(lan9645x, port, addr, vid, type);
+	mutex_unlock(&lan9645x->mact_lock);
+
+	return err;
+}
+
+int lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,
+				 const unsigned char *addr, u16 vid,
+				 enum macaccess_entry_type type, bool cpu_copy)
+{
+	int err;
+
+	mutex_lock(&lan9645x->mact_lock);
+	err = __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,
+					     cpu_copy);
+	mutex_unlock(&lan9645x->mact_lock);
+
+	return err;
+}
+
+int lan9645x_mact_flush(struct lan9645x *lan9645x, int port)
+{
+	int err;
+
+	mutex_lock(&lan9645x->mact_lock);
+	/* MAC table entries with dst index matching port are aged on scan. */
+	lan_wr(ANA_ANAGEFIL_PID_EN_SET(1) |
+	       ANA_ANAGEFIL_PID_VAL_SET(port),
+	       lan9645x, ANA_ANAGEFIL);
+
+	/* Flushing requires two scans. First sets AGE_FLAG=1, second removes
+	 * entries with AGE_FLAG=1.
+	 */
+	lan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),
+	       lan9645x,
+	       ANA_MACACCESS);
+
+	err = lan9645x_mac_wait_for_completion(lan9645x, NULL);
+	if (err)
+		goto mact_unlock;
+
+	lan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),
+	       lan9645x,
+	       ANA_MACACCESS);
+
+	err = lan9645x_mac_wait_for_completion(lan9645x, NULL);
+
+mact_unlock:
+	lan_wr(0, lan9645x, ANA_ANAGEFIL);
+	mutex_unlock(&lan9645x->mact_lock);
+	return err;
+}
+
+int lan9645x_mac_init(struct lan9645x *lan9645x)
+{
+	u32 val;
+	int err;
+
+	/* Clear the MAC table */
+	lan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_INIT), lan9645x,
+	       ANA_MACACCESS);
+
+	err = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,
+				       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==
+				       CMD_IDLE);
+	if (err) {
+		dev_err(lan9645x->dev, "MAC table clear timeout\n");
+		return err;
+	}
+
+	mutex_init(&lan9645x->mact_lock);
+	return 0;
+}
+
+void lan9645x_mac_deinit(struct lan9645x *lan9645x)
+{
+	mutex_destroy(&lan9645x->mact_lock);
+}
+
+int lan9645x_mact_dsa_dump(struct lan9645x *lan9645x, int port,
+			   dsa_fdb_dump_cb_t *cb, void *data)
+{
+	u8 mac[ETH_ALEN] __aligned(2);
+	u32 mach, macl, maca;
+	int err = 0;
+	u32 autoage;
+	u64 addr;
+	u16 vid;
+	u8 type;
+
+	mutex_lock(&lan9645x->mact_lock);
+
+	/* The aging filter works both for aging scans and GET_NEXT table scans.
+	 * With it, the HW table iteration only stops at entries matching our
+	 * filter. Since DSA calls us for each port on a table dump, this helps
+	 * avoid unnecessary work.
+	 *
+	 * Disable automatic aging temporarily. First save current state.
+	 */
+	autoage = lan_rd(lan9645x, ANA_AUTOAGE);
+
+	/* Disable aging */
+	lan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(0),
+		ANA_AUTOAGE_AGE_PERIOD,
+		lan9645x, ANA_AUTOAGE);
+
+	/* Setup filter on our port */
+	lan_wr(ANA_ANAGEFIL_PID_EN_SET(1) |
+	       ANA_ANAGEFIL_PID_VAL_SET(port),
+	       lan9645x, ANA_ANAGEFIL);
+
+	lan_wr(0, lan9645x, ANA_MACHDATA);
+	lan_wr(0, lan9645x, ANA_MACLDATA);
+
+	type = ENTRYTYPE_NORMAL;
+
+	while (1) {
+		/* NOTE: we rely on mach, macl and type being set correctly in
+		 * the registers from previous round, vis a vis the GET_NEXT
+		 * semantics, so locking entire loop is important.
+		 */
+		lan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_GET_NEXT) |
+		       ANA_MACACCESS_ENTRYTYPE_SET(type),
+		       lan9645x, ANA_MACACCESS);
+
+		err = lan9645x_mac_wait_for_completion(lan9645x, &maca);
+		if (err)
+			break;
+
+		if (ANA_MACACCESS_VALID_GET(maca) == 0)
+			break;
+
+		type = ANA_MACACCESS_ENTRYTYPE_GET(maca);
+		mach = lan_rd(lan9645x, ANA_MACHDATA);
+		macl = lan_rd(lan9645x, ANA_MACLDATA);
+
+		/* Only dynamic entries are surfaced through the user port dump.
+		 * ENTRYTYPE_LOCKED entries are already reported by the bridge
+		 * master's ndo_fdb_dump as NTF_MASTER, so we avoid duplicating
+		 * them as NTF_SELF.
+		 * Entries toward the host (NTF_SELF) have DEST_IDX == the CPU
+		 * port module and are filtered out by the DEST_IDX check.
+		 */
+		if (ANA_MACACCESS_DEST_IDX_GET(maca) == port &&
+		    type == ENTRYTYPE_NORMAL) {
+			addr = (u64)ANA_MACHDATA_MACHDATA_GET(mach) << 32 |
+			       macl;
+			u64_to_ether_addr(addr, mac);
+			vid = ANA_MACHDATA_VID_GET(mach);
+			if (vid > VLAN_MAX)
+				vid = 0;
+
+			err = cb(mac, vid, false, data);
+			if (err)
+				break;
+		}
+	}
+
+	/* Remove aging filters and restore aging */
+	lan_wr(0, lan9645x, ANA_ANAGEFIL);
+	lan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(ANA_AUTOAGE_AGE_PERIOD_GET(autoage)),
+		ANA_AUTOAGE_AGE_PERIOD,
+		lan9645x, ANA_AUTOAGE);
+
+	mutex_unlock(&lan9645x->mact_lock);
+
+	return err;
+}
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
new file mode 100644
index 00000000000000..2e97178a416f6b
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
@@ -0,0 +1,1041 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include <linux/platform_device.h>
+
+#include "lan9645x_main.h"
+#include "lan9645x_stats.h"
+
+static const char *lan9645x_resource_names[NUM_TARGETS + 1] = {
+	[TARGET_GCB]          = "gcb",
+	[TARGET_QS]           = "qs",
+	[TARGET_CHIP_TOP]     = "chip_top",
+	[TARGET_REW]          = "rew",
+	[TARGET_SYS]          = "sys",
+	[TARGET_HSIO]         = "hsio",
+	[TARGET_DEV]          = "dev",
+	[TARGET_DEV + 1]      = "dev1",
+	[TARGET_DEV + 2]      = "dev2",
+	[TARGET_DEV + 3]      = "dev3",
+	[TARGET_DEV + 4]      = "dev4",
+	[TARGET_DEV + 5]      = "dev5",
+	[TARGET_DEV + 6]      = "dev6",
+	[TARGET_DEV + 7]      = "dev7",
+	[TARGET_DEV + 8]      = "dev8",
+	[TARGET_QSYS]         = "qsys",
+	[TARGET_AFI]          = "afi",
+	[TARGET_ANA]          = "ana",
+	[NUM_TARGETS]         = NULL,
+};
+
+static int lan9645x_tag_npi_setup(struct dsa_switch *ds)
+{
+	struct dsa_port *dp, *first_cpu_dp = NULL;
+	struct lan9645x *lan9645x = ds->priv;
+
+	dsa_switch_for_each_user_port(dp, ds) {
+		if (dp->cpu_dp->ds != ds) {
+			dev_err(ds->dev,
+				"NPI port on a remote switch is not supported\n");
+			return -EINVAL;
+		}
+
+		if (first_cpu_dp && dp->cpu_dp != first_cpu_dp) {
+			dev_err(ds->dev, "Multiple NPI ports not supported\n");
+			return -EINVAL;
+		}
+
+		first_cpu_dp = dp->cpu_dp;
+	}
+
+	if (!first_cpu_dp)
+		return -EINVAL;
+
+	lan9645x_npi_port_init(lan9645x, first_cpu_dp);
+
+	return 0;
+}
+
+static enum dsa_tag_protocol lan9645x_get_tag_protocol(struct dsa_switch *ds,
+						       int port,
+						       enum dsa_tag_protocol tp)
+{
+	return DSA_TAG_PROTO_LAN9645X;
+}
+
+static void lan9645x_teardown(struct dsa_switch *ds)
+{
+	struct lan9645x *lan9645x = ds->priv;
+
+	destroy_workqueue(lan9645x->owq);
+	lan9645x_npi_port_deinit(lan9645x, lan9645x->npi);
+	lan9645x_mac_deinit(lan9645x);
+	lan9645x_mdb_deinit(lan9645x);
+	lan9645x_stats_deinit(lan9645x);
+	mutex_destroy(&lan9645x->port_mux_lock);
+	mutex_destroy(&lan9645x->fwd_domain_lock);
+}
+
+static int lan9645x_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
+{
+	return lan9645x_port_set_maxlen(ds->priv, port, new_mtu);
+}
+
+static int lan9645x_get_max_mtu(struct dsa_switch *ds, int port)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	int max_mtu;
+
+	/* Actual MAC max MTU is around 16KB. We set 10000 - overhead which
+	 * should be sufficient for all jumbo frames. Larger frames can cause
+	 * problems especially with flow control, since we only have 160K queue
+	 * buffer.
+	 */
+	max_mtu = 10000 - ETH_HLEN - ETH_FCS_LEN;
+
+	if (port == lan9645x->npi) {
+		max_mtu -= LAN9645X_IFH_LEN;
+		max_mtu -= LAN9645X_LONG_PREFIX_LEN;
+	}
+
+	return max_mtu;
+}
+
+static int lan9645x_reset_switch(struct lan9645x *lan9645x)
+{
+	int val = 0;
+	int err;
+
+	lan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan9645x, SYS_RESET_CFG);
+	lan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan9645x, SYS_RAM_INIT);
+	err = lan9645x_rd_poll_timeout(lan9645x, SYS_RAM_INIT, val,
+				       SYS_RAM_INIT_RAM_INIT_GET(val) == 0);
+	if (err) {
+		dev_err(lan9645x->dev, "Failed to init chip RAM.\n");
+		return err;
+	}
+	lan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan9645x, SYS_RESET_CFG);
+
+	return 0;
+}
+
+static int lan9645x_setup(struct dsa_switch *ds)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct device *dev = lan9645x->dev;
+	int supported, used = 0;
+	struct dsa_port *dp;
+	u32 front_ports;
+	int err;
+
+	lan9645x->num_phys_ports = ds->num_ports;
+	front_ports = dsa_user_ports(ds);
+	supported = lan9645x->num_phys_ports - lan9645x->num_port_dis;
+
+	dsa_switch_for_each_available_port(dp, ds)
+		used++;
+
+	if (used > supported) {
+		dev_err(ds->dev,
+			"%d physical ports in use in DT, SKU supports at most %d\n",
+			used, supported);
+		return -EINVAL;
+	}
+
+	err = lan9645x_reset_switch(lan9645x);
+	if (err)
+		return err;
+
+	err = lan9645x_tag_npi_setup(ds);
+	if (err) {
+		dev_err(dev, "Failed to setup NPI port.\n");
+		return err;
+	}
+
+	mutex_init(&lan9645x->port_mux_lock);
+	mutex_init(&lan9645x->fwd_domain_lock);
+	err = lan9645x_vlan_init(lan9645x);
+	if (err)
+		goto err_mutex;
+	err = lan9645x_mac_init(lan9645x);
+	if (err)
+		goto err_mutex;
+	lan9645x_mdb_init(lan9645x);
+
+	/* Link Aggregation Mode: NETDEV_LAG_HASH_L2 */
+	lan_wr(ANA_AGGR_CFG_AC_SMAC_ENA |
+	       ANA_AGGR_CFG_AC_DMAC_ENA,
+	       lan9645x, ANA_AGGR_CFG);
+
+	/* Flush queues */
+	lan_wr(GENMASK(1, 0), lan9645x, QS_XTR_FLUSH);
+
+	/* Allow to drain */
+	usleep_range(1000, 2000);
+
+	/* All Queues normal */
+	lan_wr(0x0, lan9645x, QS_XTR_FLUSH);
+
+	/* Set MAC age time to default value, the entry is aged after
+	 * 2 * AGE_PERIOD
+	 */
+	lan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),
+	       lan9645x, ANA_AUTOAGE);
+
+	/* Disable learning for frames discarded by VLAN ingress filtering */
+	lan_rmw(ANA_ADVLEARN_VLAN_CHK_SET(1),
+		ANA_ADVLEARN_VLAN_CHK,
+		lan9645x, ANA_ADVLEARN);
+
+	/* Queue system frame ageing. We target 2s ageing.
+	 *
+	 * Register unit is 1024 cycles.
+	 *
+	 * ASIC: 165.625 Mhz  ~ 6.0377 ns period
+	 *
+	 * 1024 * 6.0377 ns =~ 6182 ns
+	 * val = 2000000000ns / 6182ns
+	 */
+	lan_wr(SYS_FRM_AGING_AGE_TX_ENA_SET(1) |
+	       SYS_FRM_AGING_MAX_AGE_SET((2000000000 / 6182)),
+	       lan9645x,  SYS_FRM_AGING);
+
+	/* Setup flooding PGIDs for IPv4/IPv6 multicast. Control and dataplane
+	 * use the same masks. Control frames are redirected to CPU, and
+	 * the network stack is responsible for forwarding these.
+	 * The dataplane is forwarding according to the offloaded MDB entries.
+	 */
+	lan_wr(ANA_FLOODING_IPMC_FLD_MC4_DATA_SET(PGID_MCIPV4) |
+	       ANA_FLOODING_IPMC_FLD_MC4_CTRL_SET(PGID_MC) |
+	       ANA_FLOODING_IPMC_FLD_MC6_DATA_SET(PGID_MCIPV6) |
+	       ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),
+	       lan9645x, ANA_FLOODING_IPMC);
+
+	/* There are 8 priorities */
+	for (int prio = 0; prio < 8; ++prio)
+		lan_wr(ANA_FLOODING_FLD_MULTICAST_SET(PGID_MC) |
+		       ANA_FLOODING_FLD_UNICAST_SET(PGID_UC) |
+		       ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),
+		       lan9645x, ANA_FLOODING(prio));
+
+	/* Allow VLAN table to control whether cpu copy from the pgid table is
+	 * enabled. Index PGID_ENTRIES is CPU src pgid, so we skip it as the
+	 * configuration makes little sense here.
+	 */
+	for (int i = 0; i < PGID_ENTRIES; ++i)
+		lan_wr(ANA_PGID_CFG_OBEY_VLAN_SET(1),
+		       lan9645x, ANA_PGID_CFG(i));
+
+	/* Disable bridging by default */
+	for (int p = 0; p < lan9645x->num_phys_ports; p++) {
+		lan_wr(0, lan9645x, ANA_PGID(PGID_SRC + p));
+
+		/* Do not forward BPDU frames to the front ports and copy them
+		 * to CPU
+		 */
+		lan_wr(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA,
+		       lan9645x, ANA_CPU_FWD_BPDU_CFG(p));
+	}
+
+	for (int i = 0; i < 16; i++) {
+		/* The register instance number corresponds to the
+		 * address of the extracted frame. For instance:
+		 * CPUQ_8021_CFG[4].CPUQ_BPDU_VAL
+		 * is the cpu extraction queue used for BPDU frames
+		 * with address 01-80-C2-00-00-04
+		 */
+		lan_rmw(ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_SET(LAN9645X_CPUQ_TRAP),
+			ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL,
+			lan9645x, ANA_CPUQ_8021_CFG(i));
+	}
+
+	/* Reserve ~1700 bytes of buffer memory per (port, prio) for source
+	 * tracking (resource 0, indices 0..95) and destination tracking
+	 * (resource 2, indices 512..607). These are access watermarks, not
+	 * pre-allocations: a flow draws from its reservation first, then
+	 * from the shared pool. Keeping the reservation above a max-size
+	 * Ethernet frame prevents a single frame from spilling into the
+	 * shared pool, and cause pause frames to be emitted without actual
+	 * congestion.
+	 */
+	for (int i = 0; i <= QSYS_Q_RSRV; ++i) {
+		lan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(i));
+		lan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(512 + i));
+	}
+
+	lan9645x_port_cpu_init(lan9645x);
+
+	/* Multicast to all front ports */
+	lan_wr(front_ports, lan9645x, ANA_PGID(PGID_MC));
+
+	/* IP multicast to all front ports */
+	lan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV4));
+	lan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV6));
+
+	/* Unicast to all front ports */
+	lan_wr(front_ports, lan9645x, ANA_PGID(PGID_UC));
+
+	/* Broadcast to cpu and all front ports */
+	lan_wr(BIT(lan9645x->num_phys_ports) | front_ports, lan9645x,
+	       ANA_PGID(PGID_BC));
+
+	lan9645x_port_set_tail_drop_wm(lan9645x);
+
+	lan9645x->owq = alloc_ordered_workqueue("%s-owq", 0,
+						dev_name(lan9645x->dev));
+	if (!lan9645x->owq) {
+		err = -ENOMEM;
+		goto err_mac;
+	}
+
+	lan9645x_stats_init(lan9645x);
+
+	ds->mtu_enforcement_ingress = true;
+	ds->assisted_learning_on_cpu_port = true;
+	ds->fdb_isolation = true;
+
+	/* ANA_AUTOAGE_AGE_PERIOD is a seconds-based field and entries are
+	 * aged after 2 * AGE_PERIOD, giving (2 * FIELD_MAX) seconds of
+	 * maximum aging.
+	 */
+	ds->ageing_time_max = 2U * MSEC_PER_SEC *
+			      FIELD_MAX(ANA_AUTOAGE_AGE_PERIOD);
+
+	dev_info(lan9645x->dev,
+		 "SKU features: max_ports=%d\n",
+		 lan9645x->num_phys_ports - lan9645x->num_port_dis);
+
+	return 0;
+
+err_mac:
+	lan9645x_mac_deinit(lan9645x);
+	lan9645x_mdb_deinit(lan9645x);
+err_mutex:
+	mutex_destroy(&lan9645x->port_mux_lock);
+	mutex_destroy(&lan9645x->fwd_domain_lock);
+	lan9645x_npi_port_deinit(lan9645x, lan9645x->npi);
+	return err;
+}
+
+static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,
+					   struct phylink_config *config)
+{
+	lan9645x_phylink_get_caps(ds->priv, port, config);
+}
+
+static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
+{
+	u32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);
+	struct lan9645x *lan9645x = ds->priv;
+
+	mutex_lock(&lan9645x->mact_lock);
+
+	/* Entry must suffer two aging scans before it is removed, so it is
+	 * aged after 2*AGE_PERIOD, and the unit is in seconds.
+	 * An age period of 0 disables automatic aging.
+	 */
+	lan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(msecs ? age_secs : 0),
+		ANA_AUTOAGE_AGE_PERIOD,
+		lan9645x, ANA_AUTOAGE);
+
+	mutex_unlock(&lan9645x->mact_lock);
+	return 0;
+}
+
+static int lan9645x_port_pre_bridge_flags(struct dsa_switch *ds, int port,
+					  struct switchdev_brport_flags flags,
+					  struct netlink_ext_ack *extack)
+{
+	if (flags.mask &
+	    ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD))
+		return -EINVAL;
+
+	return 0;
+}
+
+static void lan9645x_port_pgid_set(struct lan9645x *lan9645x, u16 pgid,
+				   int chip_port, bool enabled)
+{
+	u32 reg_msk, port_msk;
+
+	WARN_ON(chip_port > lan9645x->num_phys_ports);
+
+	port_msk = ANA_PGID_PGID_SET(enabled ? BIT(chip_port) : 0);
+	reg_msk = ANA_PGID_PGID_SET(BIT(chip_port));
+
+	lan_rmw(port_msk, reg_msk, lan9645x, ANA_PGID(pgid));
+}
+
+static void lan9645x_port_set_learning(struct lan9645x *lan9645x, int port,
+				       bool enabled)
+{
+	struct lan9645x_port *p = lan9645x_to_port(lan9645x, port);
+
+	p->learn_ena = enabled;
+
+	enabled = enabled && (p->stp_state == BR_STATE_LEARNING ||
+			      p->stp_state == BR_STATE_FORWARDING);
+
+	lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled), ANA_PORT_CFG_LEARN_ENA,
+		lan9645x, ANA_PORT_CFG(port));
+}
+
+static int lan9645x_port_bridge_flags(struct dsa_switch *ds, int port,
+				      struct switchdev_brport_flags f,
+				      struct netlink_ext_ack *extack)
+{
+	struct lan9645x *lan9645x = ds->priv;
+
+	if (WARN_ON(port == lan9645x->npi))
+		return -EINVAL;
+
+	if (f.mask & BR_LEARNING)
+		lan9645x_port_set_learning(lan9645x, port,
+					   !!(f.val & BR_LEARNING));
+
+	if (f.mask & BR_FLOOD)
+		lan9645x_port_pgid_set(lan9645x, PGID_UC, port,
+				       !!(f.val & BR_FLOOD));
+
+	if (f.mask & BR_MCAST_FLOOD) {
+		bool ena = !!(f.val & BR_MCAST_FLOOD);
+
+		lan9645x_port_pgid_set(lan9645x, PGID_MC, port, ena);
+		lan9645x_port_pgid_set(lan9645x, PGID_MCIPV4, port, ena);
+		lan9645x_port_pgid_set(lan9645x, PGID_MCIPV6, port, ena);
+	}
+
+	if (f.mask & BR_BCAST_FLOOD)
+		lan9645x_port_pgid_set(lan9645x, PGID_BC, port,
+				       !!(f.val & BR_BCAST_FLOOD));
+
+	return 0;
+}
+
+static void lan9645x_update_fwd_mask(struct lan9645x *lan9645x)
+{
+	struct lan9645x_port *p;
+	struct dsa_port *dp;
+
+	lockdep_assert_held(&lan9645x->fwd_domain_lock);
+
+	/* Updates the source port PGIDs, making sure frames from p
+	 * are only forwarded to ports q != p, where q is relevant to forward
+	 */
+	dsa_switch_for_each_available_port(dp, lan9645x->ds) {
+		u32 mask = 0;
+
+		p = lan9645x_to_port(lan9645x, dp->index);
+
+		if (lan9645x_port_is_bridged(p) &&
+		    (lan9645x->bridge_fwd_mask & BIT(dp->index))) {
+			mask = lan9645x->bridge_mask &
+			       lan9645x->bridge_fwd_mask & ~BIT(dp->index);
+		}
+
+		lan_wr(mask, lan9645x, ANA_PGID(PGID_SRC + dp->index));
+	}
+}
+
+static void __lan9645x_port_mark_host_flood(struct lan9645x *lan9645x, int port,
+					    bool uc, bool mc)
+{
+	lockdep_assert_held(&lan9645x->fwd_domain_lock);
+
+	if (uc)
+		lan9645x->host_flood_uc_mask |= BIT(port);
+	else
+		lan9645x->host_flood_uc_mask &= ~BIT(port);
+
+	if (mc)
+		lan9645x->host_flood_mc_mask |= BIT(port);
+	else
+		lan9645x->host_flood_mc_mask &= ~BIT(port);
+}
+
+static void __lan9645x_port_set_host_flood(struct lan9645x *lan9645x)
+{
+	bool mc_ena, uc_ena;
+	u16 unbridged;
+
+	lockdep_assert_held(&lan9645x->fwd_domain_lock);
+
+	/* We want promiscuous and all_multi to affect standalone ports, for
+	 * debug and test purposes.
+	 *
+	 * However, the linux bridge is incredibly eager to put bridged ports in
+	 * promiscuous mode.
+	 *
+	 * This is unfortunate since lan9645x flood masks are global and not per
+	 * ingress port. When some port triggers unknown uc/mc to the CPU, the
+	 * traffic from any port is forwarded to the CPU.
+	 *
+	 * If the host CPU is weak, this can cause tremendous stress. Therefore,
+	 * we compromise by ignoring this host flood request for bridged ports.
+	 */
+	unbridged = ~lan9645x->bridge_mask & GENMASK(NUM_PHYS_PORTS - 1, 0);
+
+	uc_ena = !!(lan9645x->host_flood_uc_mask & unbridged);
+	lan9645x_port_pgid_set(lan9645x, PGID_UC, lan9645x->num_phys_ports,
+			       uc_ena);
+
+	mc_ena = !!(lan9645x->host_flood_mc_mask & unbridged);
+	lan9645x_port_pgid_set(lan9645x, PGID_MC, lan9645x->num_phys_ports,
+			       mc_ena);
+	lan9645x_port_pgid_set(lan9645x, PGID_MCIPV4, lan9645x->num_phys_ports,
+			       mc_ena);
+	lan9645x_port_pgid_set(lan9645x, PGID_MCIPV6, lan9645x->num_phys_ports,
+			       mc_ena);
+}
+
+static void lan9645x_host_flood_work_fn(struct work_struct *work)
+{
+	struct lan9645x_port *p = container_of(work, struct lan9645x_port,
+					       host_flood_work);
+	struct lan9645x *lan9645x = p->lan9645x;
+	u8 req;
+
+	req = READ_ONCE(p->host_flood_req);
+
+	mutex_lock(&lan9645x->fwd_domain_lock);
+	__lan9645x_port_mark_host_flood(lan9645x, p->chip_port,
+					req & LAN9645X_HOST_FLOOD_UC,
+					req & LAN9645X_HOST_FLOOD_MC);
+	__lan9645x_port_set_host_flood(lan9645x);
+	mutex_unlock(&lan9645x->fwd_domain_lock);
+}
+
+/* Called in atomic context. */
+static void lan9645x_port_set_host_flood(struct dsa_switch *ds, int port,
+					 bool uc, bool mc)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+
+	WRITE_ONCE(p->host_flood_req,
+		   (uc ? LAN9645X_HOST_FLOOD_UC : 0) |
+		   (mc ? LAN9645X_HOST_FLOOD_MC : 0));
+	queue_work(lan9645x->owq, &p->host_flood_work);
+}
+
+static int lan9645x_port_bridge_join(struct dsa_switch *ds, int port,
+				     struct dsa_bridge bridge,
+				     bool *tx_fwd_offload,
+				     struct netlink_ext_ack *extack)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+
+	mutex_lock(&lan9645x->fwd_domain_lock);
+	if (lan9645x->bridge && lan9645x->bridge != bridge.dev) {
+		mutex_unlock(&lan9645x->fwd_domain_lock);
+		NL_SET_ERR_MSG_MOD(extack, "Only one bridge supported");
+		return -EBUSY;
+	}
+
+	/* First bridged port sets bridge dev */
+	if (!lan9645x->bridge_mask)
+		lan9645x->bridge = bridge.dev;
+
+	lan9645x->bridge_mask |= BIT(p->chip_port);
+	__lan9645x_port_set_host_flood(lan9645x);
+	lan9645x_vlan_clear_hostmode(p);
+
+	mutex_unlock(&lan9645x->fwd_domain_lock);
+
+	/* Later: stp_state_set updates forwarding */
+
+	return 0;
+}
+
+static void lan9645x_port_bridge_stp_state_set(struct dsa_switch *ds, int port,
+					       u8 state)
+{
+	struct lan9645x *lan9645x;
+	struct lan9645x_port *p;
+	bool learn_ena;
+
+	lan9645x = ds->priv;
+	p = lan9645x_to_port(lan9645x, port);
+
+	mutex_lock(&lan9645x->fwd_domain_lock);
+
+	p->stp_state = state;
+
+	if (state == BR_STATE_FORWARDING)
+		lan9645x->bridge_fwd_mask |= BIT(p->chip_port);
+	else
+		lan9645x->bridge_fwd_mask &= ~BIT(p->chip_port);
+
+	learn_ena = (state == BR_STATE_LEARNING ||
+		     state == BR_STATE_FORWARDING) && p->learn_ena;
+
+	lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(learn_ena),
+		ANA_PORT_CFG_LEARN_ENA, lan9645x,
+		ANA_PORT_CFG(p->chip_port));
+
+	lan9645x_update_fwd_mask(lan9645x);
+	mutex_unlock(&lan9645x->fwd_domain_lock);
+}
+
+static void lan9645x_port_bridge_leave(struct dsa_switch *ds, int port,
+				       struct dsa_bridge bridge)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+
+	mutex_lock(&lan9645x->fwd_domain_lock);
+
+	lan9645x->bridge_mask &= ~BIT(p->chip_port);
+
+	/* Last port leaving clears bridge dev */
+	if (!lan9645x->bridge_mask)
+		lan9645x->bridge = NULL;
+
+	__lan9645x_port_set_host_flood(lan9645x);
+	lan9645x_vlan_set_hostmode(p);
+	lan9645x_update_fwd_mask(lan9645x);
+
+	mutex_unlock(&lan9645x->fwd_domain_lock);
+}
+
+static int lan9645x_port_vlan_filtering(struct dsa_switch *ds, int port,
+					bool enabled,
+					struct netlink_ext_ack *extack)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+	p->vlan_aware = enabled;
+	lan9645x_vlan_port_apply(p);
+
+	return 0;
+}
+
+static int lan9645x_port_vlan_add(struct dsa_switch *ds, int port,
+				  const struct switchdev_obj_port_vlan *vlan,
+				  struct netlink_ext_ack *extack)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+	bool pvid, untagged;
+
+	p = lan9645x_to_port(lan9645x, port);
+	pvid = !!(vlan->flags & BRIDGE_VLAN_INFO_PVID);
+	untagged = !!(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED);
+
+	return lan9645x_vlan_port_add_vlan(p, vlan->vid, pvid, untagged,
+					   extack);
+}
+
+static int lan9645x_port_vlan_del(struct dsa_switch *ds, int port,
+				  const struct switchdev_obj_port_vlan *vlan)
+{
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+	return lan9645x_vlan_port_del_vlan(p, vlan->vid);
+}
+
+static void lan9645x_port_fast_age(struct dsa_switch *ds, int port)
+{
+	lan9645x_mact_flush(ds->priv, port);
+}
+
+static int lan9645x_fdb_dump(struct dsa_switch *ds, int port,
+			     dsa_fdb_dump_cb_t *cb, void *data)
+{
+	return lan9645x_mact_dsa_dump(ds->priv, port, cb, data);
+}
+
+static struct net_device *lan9645x_db2bridge(struct dsa_db db)
+{
+	switch (db.type) {
+	case DSA_DB_PORT:
+	case DSA_DB_LAG:
+		return NULL;
+	case DSA_DB_BRIDGE:
+		return db.bridge.dev;
+	default:
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+}
+
+static int lan9645x_fdb_add(struct dsa_switch *ds, int port,
+			    const unsigned char *addr, u16 vid,
+			    struct dsa_db db)
+{
+	struct net_device *br = lan9645x_db2bridge(db);
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct lan9645x *lan9645x = ds->priv;
+	int dest;
+
+	if (IS_ERR(br))
+		return PTR_ERR(br);
+
+	if (dsa_port_is_cpu(dp) && !br &&
+	    dsa_fdb_present_in_other_db(ds, port, addr, vid, db))
+		return 0;
+
+	if (!vid)
+		vid = lan9645x_vlan_unaware_pvid(!!br);
+
+	dest = dsa_port_is_cpu(dp) ? PGID_CPU : port;
+
+	return lan9645x_mact_learn(lan9645x, dest, addr, vid, ENTRYTYPE_LOCKED);
+}
+
+static int lan9645x_fdb_del(struct dsa_switch *ds, int port,
+			    const unsigned char *addr, u16 vid,
+			    struct dsa_db db)
+{
+	struct net_device *br = lan9645x_db2bridge(db);
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct lan9645x *lan9645x = ds->priv;
+
+	if (IS_ERR(br))
+		return PTR_ERR(br);
+
+	if (dsa_port_is_cpu(dp) && !br &&
+	    dsa_fdb_present_in_other_db(ds, port, addr, vid, db))
+		return 0;
+
+	if (!vid)
+		vid = lan9645x_vlan_unaware_pvid(!!br);
+
+	return lan9645x_mact_forget(lan9645x, addr, vid, ENTRYTYPE_LOCKED);
+}
+
+static int lan9645x_mdb_add(struct dsa_switch *ds, int port,
+			    const struct switchdev_obj_port_mdb *mdb,
+			    struct dsa_db db)
+{
+	struct net_device *bridge_dev = lan9645x_db2bridge(db);
+	struct lan9645x *lan9645x = ds->priv;
+
+	dev_dbg(lan9645x->dev, "port=%d addr=%pM vid=%u\n", port, mdb->addr,
+		mdb->vid);
+
+	if (IS_ERR(bridge_dev))
+		return PTR_ERR(bridge_dev);
+
+	if (dsa_is_cpu_port(ds, port) && !bridge_dev &&
+	    dsa_mdb_present_in_other_db(ds, port, mdb, db))
+		return 0;
+
+	if (port == lan9645x->npi)
+		port = lan9645x->num_phys_ports;
+
+	return lan9645x_mdb_port_add(lan9645x, port, mdb, bridge_dev);
+}
+
+static int lan9645x_mdb_del(struct dsa_switch *ds, int port,
+			    const struct switchdev_obj_port_mdb *mdb,
+			    struct dsa_db db)
+{
+	struct net_device *bridge_dev = lan9645x_db2bridge(db);
+	struct lan9645x *lan9645x = ds->priv;
+	int err;
+
+	dev_dbg(lan9645x->dev, "port=%d addr=%pM vid=%u\n", port, mdb->addr,
+		mdb->vid);
+
+	if (IS_ERR(bridge_dev))
+		return PTR_ERR(bridge_dev);
+
+	if (dsa_is_cpu_port(ds, port) && !bridge_dev &&
+	    dsa_mdb_present_in_other_db(ds, port, mdb, db))
+		return 0;
+
+	if (port == lan9645x->npi)
+		port = lan9645x->num_phys_ports;
+
+	err = lan9645x_mdb_port_del(lan9645x, port, mdb, bridge_dev);
+	if (err == -ENOENT) {
+		dev_dbg(lan9645x->dev,
+			"mdb not found port=%d addr=%pM vid=%u\n", port,
+			mdb->addr, mdb->vid);
+		return 0;
+	}
+
+	return err;
+}
+
+static void lan9645x_get_strings(struct dsa_switch *ds, int port, u32 stringset,
+				 uint8_t *data)
+{
+	lan9645x_stats_get_strings(ds->priv, port, stringset, data);
+}
+
+static void lan9645x_get_ethtool_stats(struct dsa_switch *ds, int port,
+				       uint64_t *data)
+{
+	lan9645x_stats_get_ethtool_stats(ds->priv, port, data);
+}
+
+static int lan9645x_get_sset_count(struct dsa_switch *ds, int port, int sset)
+{
+	return lan9645x_stats_get_sset_count(ds->priv, port, sset);
+}
+
+static void lan9645x_get_eth_mac_stats(struct dsa_switch *ds, int port,
+				       struct ethtool_eth_mac_stats *mac_stats)
+{
+	lan9645x_stats_get_eth_mac_stats(ds->priv, port, mac_stats);
+}
+
+static void
+lan9645x_get_rmon_stats(struct dsa_switch *ds, int port,
+			struct ethtool_rmon_stats *rmon_stats,
+			const struct ethtool_rmon_hist_range **ranges)
+{
+	lan9645x_stats_get_rmon_stats(ds->priv, port, rmon_stats, ranges);
+}
+
+static void lan9645x_get_stats64(struct dsa_switch *ds, int port,
+				 struct rtnl_link_stats64 *s)
+{
+	lan9645x_stats_get_stats64(ds->priv, port, s);
+}
+
+static void lan9645x_get_pause_stats(struct dsa_switch *ds, int port,
+				     struct ethtool_pause_stats *pause_stats)
+{
+	lan9645x_stats_get_pause_stats(ds->priv, port, pause_stats);
+}
+
+static void lan9645x_get_mm_stats(struct dsa_switch *ds, int port,
+				  struct ethtool_mm_stats *stats)
+{
+	lan9645x_stats_get_mm_stats(ds->priv, port, stats);
+}
+
+static void lan9645x_get_eth_phy_stats(struct dsa_switch *ds, int port,
+				       struct ethtool_eth_phy_stats *phy_stats)
+{
+	lan9645x_stats_get_eth_phy_stats(ds->priv, port, phy_stats);
+}
+
+static void
+lan9645x_get_eth_ctrl_stats(struct dsa_switch *ds, int port,
+			    struct ethtool_eth_ctrl_stats *ctrl_stats)
+{
+	lan9645x_stats_get_eth_ctrl_stats(ds->priv, port, ctrl_stats);
+}
+
+static const struct dsa_switch_ops lan9645x_switch_ops = {
+	.get_tag_protocol		= lan9645x_get_tag_protocol,
+
+	.setup				= lan9645x_setup,
+	.teardown			= lan9645x_teardown,
+	.port_setup			= lan9645x_port_setup,
+
+	/* Phylink integration */
+	.phylink_get_caps		= lan9645x_port_phylink_get_caps,
+
+	/* MTU  */
+	.port_change_mtu		= lan9645x_change_mtu,
+	.port_max_mtu			= lan9645x_get_max_mtu,
+
+	/* Bridge integration */
+	.set_ageing_time		= lan9645x_set_ageing_time,
+	.port_pre_bridge_flags		= lan9645x_port_pre_bridge_flags,
+	.port_bridge_flags		= lan9645x_port_bridge_flags,
+	.port_bridge_join		= lan9645x_port_bridge_join,
+	.port_bridge_leave		= lan9645x_port_bridge_leave,
+	.port_stp_state_set		= lan9645x_port_bridge_stp_state_set,
+	.port_set_host_flood		= lan9645x_port_set_host_flood,
+
+	/* VLAN integration */
+	.port_vlan_filtering		= lan9645x_port_vlan_filtering,
+	.port_vlan_add			= lan9645x_port_vlan_add,
+	.port_vlan_del			= lan9645x_port_vlan_del,
+
+	/* MAC table integration */
+	.port_fast_age			= lan9645x_port_fast_age,
+	.port_fdb_dump			= lan9645x_fdb_dump,
+	.port_fdb_add			= lan9645x_fdb_add,
+	.port_fdb_del			= lan9645x_fdb_del,
+
+	/* Multicast database */
+	.port_mdb_add			= lan9645x_mdb_add,
+	.port_mdb_del			= lan9645x_mdb_del,
+
+	/* Port statistics counters. */
+	.get_strings			= lan9645x_get_strings,
+	.get_ethtool_stats		= lan9645x_get_ethtool_stats,
+	.get_sset_count			= lan9645x_get_sset_count,
+	.get_eth_mac_stats		= lan9645x_get_eth_mac_stats,
+	.get_rmon_stats			= lan9645x_get_rmon_stats,
+	.get_stats64			= lan9645x_get_stats64,
+	.get_pause_stats		= lan9645x_get_pause_stats,
+	.get_mm_stats			= lan9645x_get_mm_stats,
+	.get_eth_phy_stats		= lan9645x_get_eth_phy_stats,
+	.get_eth_ctrl_stats		= lan9645x_get_eth_ctrl_stats,
+};
+
+static int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)
+{
+	const char *resource_name;
+	struct regmap *tgt_map;
+
+	for (int i = 0; i < NUM_TARGETS; i++) {
+		resource_name = lan9645x_resource_names[i];
+		if (!resource_name)
+			continue;
+
+		tgt_map = dev_get_regmap(lan9645x->dev->parent, resource_name);
+		if (IS_ERR_OR_NULL(tgt_map)) {
+			dev_err(lan9645x->dev, "Failed to get regmap=%d\n", i);
+			return -ENODEV;
+		}
+
+		lan9645x->rmap[i] = tgt_map;
+	}
+
+	return 0;
+}
+
+static void lan9645x_set_feat_dis(struct lan9645x *lan9645x)
+{
+	u32 feat_dis;
+
+	/* The features which can be physically disabled on some SKUs are:
+	 * 1) Number of ports can be 5, 7 or 9. Any ports can be used, the chip
+	 *    tracks how many are active.
+	 * 2) HSR/PRP. The duplicate discard table can be disabled.
+	 * 3) TAS, frame preemption and PSFP can be disabled.
+	 */
+	feat_dis = lan_rd(lan9645x, GCB_FEAT_DISABLE);
+
+	lan9645x->num_port_dis =
+		GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_GET(feat_dis);
+}
+
+static int lan9645x_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct lan9645x *lan9645x;
+	struct dsa_switch *ds;
+	int err = 0;
+
+	lan9645x = devm_kzalloc(dev, sizeof(*lan9645x), GFP_KERNEL);
+	if (!lan9645x)
+		return dev_err_probe(dev, -ENOMEM,
+				     "Failed to allocate LAN9645X");
+
+	dev_set_drvdata(dev, lan9645x);
+	lan9645x->dev = dev;
+
+	err = lan9645x_request_target_regmaps(lan9645x);
+	if (err)
+		return dev_err_probe(dev, err, "Failed to request regmaps");
+
+	ds = devm_kzalloc(dev, sizeof(*ds), GFP_KERNEL);
+	if (!ds)
+		return dev_err_probe(dev, -ENOMEM,
+				     "Failed to allocate DSA switch");
+
+	lan9645x->ports = devm_kcalloc(lan9645x->dev, NUM_PHYS_PORTS,
+				       sizeof(struct lan9645x_port *),
+				       GFP_KERNEL);
+	if (!lan9645x->ports)
+		return dev_err_probe(dev, -ENOMEM,
+				     "Failed to allocate switch ports");
+
+	for (int port = 0; port < NUM_PHYS_PORTS; port++) {
+		struct lan9645x_port *p;
+
+		p = devm_kzalloc(lan9645x->dev, sizeof(*p), GFP_KERNEL);
+		if (!p)
+			return dev_err_probe(dev, -ENOMEM,
+					     "Failed to allocate switch port");
+
+		p->lan9645x = lan9645x;
+		p->chip_port = port;
+		INIT_WORK(&p->host_flood_work, lan9645x_host_flood_work_fn);
+		lan9645x->ports[port] = p;
+	}
+
+	ds->dev = dev;
+	ds->num_ports = NUM_PHYS_PORTS;
+	ds->num_tx_queues = NUM_PRIO_QUEUES;
+	ds->dscp_prio_mapping_is_global = true;
+
+	ds->ops = &lan9645x_switch_ops;
+	ds->phylink_mac_ops = &lan9645x_phylink_mac_ops;
+	ds->priv = lan9645x;
+
+	lan9645x->ds = ds;
+	lan9645x->shared_queue_sz = LAN9645X_BUFFER_MEMORY;
+	lan9645x->npi = -1;
+
+	lan9645x_set_feat_dis(lan9645x);
+
+	err = lan9645x_stats_alloc(lan9645x);
+	if (err)
+		return dev_err_probe(dev, err, "Failed to allocate stats");
+
+	err = dsa_register_switch(ds);
+	if (err) {
+		lan9645x_stats_free(lan9645x);
+		return dev_err_probe(dev, err, "Failed to register DSA switch");
+	}
+
+	return 0;
+}
+
+static void lan9645x_remove(struct platform_device *pdev)
+{
+	struct lan9645x *lan9645x = dev_get_drvdata(&pdev->dev);
+
+	if (!lan9645x)
+		return;
+
+	/* Calls lan9645x DSA .teardown */
+	dsa_unregister_switch(lan9645x->ds);
+	lan9645x_stats_free(lan9645x);
+	dev_set_drvdata(&pdev->dev, NULL);
+}
+
+static void lan9645x_shutdown(struct platform_device *pdev)
+{
+	struct lan9645x *lan9645x = dev_get_drvdata(&pdev->dev);
+
+	if (!lan9645x)
+		return;
+
+	dsa_switch_shutdown(lan9645x->ds);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+}
+
+static const struct of_device_id lan9645x_switch_of_match[] = {
+	{ .compatible = "microchip,lan96455s-switch" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, lan9645x_switch_of_match);
+
+static struct platform_driver lan9645x_switch_driver = {
+	.driver = {
+		.name = "lan96455s-switch",
+		.of_match_table = lan9645x_switch_of_match,
+	},
+	.probe = lan9645x_probe,
+	.remove = lan9645x_remove,
+	.shutdown = lan9645x_shutdown,
+};
+module_platform_driver(lan9645x_switch_driver);
+
+MODULE_DESCRIPTION("Lan9645x Switch Driver");
+MODULE_AUTHOR("Jens Emil Schulz Østergaard <jensemil.schulzostergaard@microchip.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h
new file mode 100644
index 00000000000000..7c6cad0da4f135
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h
@@ -0,0 +1,441 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#ifndef __LAN9645X_MAIN_H__
+#define __LAN9645X_MAIN_H__
+
+#include <linux/dsa/lan9645x.h>
+#include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
+#include <linux/regmap.h>
+#include <net/dsa.h>
+
+#include "lan9645x_regs.h"
+
+/* Port modules 0-8 are front (user) ports. The chip additionally has two
+ * logical CPU port modules at indices 9 and 10. These are not the DSA CPU port.
+ * The CPU port modules are logical ports in the chip intended for management.
+ *
+ * The frame delivery mechanism can vary: direct register injection/extraction,
+ * or a front port can be used as the management port, called a Node Processor
+ * Interface (NPI) in the datasheet.
+ *
+ * LAN9645X uses the NPI approach, so the DSA CPU port is a front port
+ * (see lan9645x->npi) configured as NPI port.
+ *
+ * Therefore the CPU datapath has two port module indices of interest,
+ * lan9645x->npi and the cpu port module at index 9.
+ */
+#define NUM_PHYS_PORTS		9
+#define NUM_PRIO_QUEUES		8
+#define LAN9645X_NUM_TC		8
+
+#define QS_SRC_BUF_RSV		1700
+
+/* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO
+ * See QSYS:RES_CTRL[*]:RES_CFG description
+ */
+#define QSYS_Q_RSRV			95
+
+#define LAN9645X_ISDX_MAX		128
+#define LAN9645X_ESDX_MAX		128
+#define LAN9645X_SFID_MAX		128
+
+/* Reserved VLAN IDs. */
+#define UNAWARE_PVID			0
+#define HOST_PVID			4095
+#define VLAN_MAX			(HOST_PVID - 1)
+
+/* 160KiB / 1.25Mbit */
+#define LAN9645X_BUFFER_MEMORY	(160 * 1024)
+
+/* Port Group Identifiers (PGID) are port-masks applied to all frames.
+ * The replicated registers are organized like so in HW:
+ *
+ * 0-63:         Destination analysis
+ * 64-79:        Aggregation analysis
+ * 80-(80+10-1): Source port analysis
+ *
+ * Destination: By default the first 9 port masks == BIT(port_num). Never change
+ * these except for aggregation. Remaining dst masks are for L2 MC and
+ * flooding. (See FLOODING and FLOODING_IPMC).
+ *
+ * Aggregation: Used to pick a port within an aggregation group. If no
+ * aggregation is configured, these are all-ones.
+ *
+ * Source: Control which ports a given source port can forward to. A frame that
+ * is received on port n, uses mask 80+n as a mask to filter out destination
+ * ports. The default values are that all bits are set except for the index
+ * number (no loopback).
+ *
+ * We reserve destination PGIDs at the end of the range.
+ */
+
+#define PGID_AGGR			64
+#define PGID_SRC			80
+#define PGID_ENTRIES			89
+
+#define PGID_AGGR_NUM			(PGID_SRC - PGID_AGGR)
+
+/* General purpose PGIDs. */
+#define PGID_GP_START			NUM_PHYS_PORTS
+#define PGID_GP_END			PGID_MRP
+
+/* Reserved PGIDs.
+ * PGID_MRP is a blackhole PGID
+ */
+#define PGID_MRP			(PGID_AGGR - 7)
+#define PGID_CPU			(PGID_AGGR - 6)
+#define PGID_UC				(PGID_AGGR - 5)
+#define PGID_BC				(PGID_AGGR - 4)
+#define PGID_MC				(PGID_AGGR - 3)
+#define PGID_MCIPV4			(PGID_AGGR - 2)
+#define PGID_MCIPV6			(PGID_AGGR - 1)
+
+/* Flooding PGIDS:
+ * PGID_UC
+ * PGID_MC*
+ * PGID_BC
+ */
+
+#define GWM_MULTIPLIER_BIT		BIT(8)
+#define LAN9645X_BUFFER_CELL_SZ		64
+
+#define RD_SLEEP_US			3
+#define RD_SLEEPTIMEOUT_US		100000
+#define SLOW_RD_SLEEP_US		1000
+#define SLOW_RD_SLEEPTIMEOUT_US		4000000
+
+#define lan9645x_rd_poll_timeout(_lan9645x, _reg_macro, _val, _cond)     \
+	regmap_read_poll_timeout(lan_rmap((_lan9645x), _reg_macro),	\
+				 lan_rel_addr(_reg_macro), (_val),	\
+				 (_cond), RD_SLEEP_US, RD_SLEEPTIMEOUT_US)
+
+#define lan9645x_rd_poll_slow(_lan9645x, _reg_macro, _val, _cond)	\
+	regmap_read_poll_timeout(lan_rmap((_lan9645x), _reg_macro),	\
+				 lan_rel_addr(_reg_macro), (_val),	\
+				 (_cond), SLOW_RD_SLEEP_US,		\
+				 SLOW_RD_SLEEPTIMEOUT_US)
+
+#define LAN9645X_HOST_FLOOD_UC		BIT(0)
+#define LAN9645X_HOST_FLOOD_MC		BIT(1)
+
+/* NPI port prefix config encoding
+ *
+ * 0: No CPU extraction header (normal frames)
+ * 1: CPU extraction header without prefix
+ * 2: CPU extraction header with short prefix
+ * 3: CPU extraction header with long prefix
+ */
+enum lan9645x_tag_prefix {
+	LAN9645X_TAG_PREFIX_DISABLED = 0,
+	LAN9645X_TAG_PREFIX_NONE = 1,
+	LAN9645X_TAG_PREFIX_SHORT = 2,
+	LAN9645X_TAG_PREFIX_LONG = 3,
+};
+
+enum {
+	LAN9645X_SPEED_DISABLED = 0,
+	LAN9645X_SPEED_10 = 1,
+	LAN9645X_SPEED_100 = 2,
+	LAN9645X_SPEED_1000 = 3,
+	LAN9645X_SPEED_2500 = 4,
+};
+
+/* Rewriter VLAN port tagging encoding for REW:PORT[0-10]:TAG_CFG.TAG_CFG
+ *
+ * 0: Port tagging disabled.
+ * 1: Tag all frames, except when VID=PORT_VLAN_CFG.PORT_VID or VID=0.
+ * 2: Tag all frames, except when VID=0.
+ * 3: Tag all frames.
+ */
+enum lan9645x_vlan_port_tag {
+	LAN9645X_TAG_DISABLED = 0,
+	LAN9645X_TAG_NO_PVID_NO_UNAWARE = 1,
+	LAN9645X_TAG_NO_UNAWARE = 2,
+	LAN9645X_TAG_ALL = 3,
+};
+
+struct lan9645x_vlan {
+	u32 portmask: 10, /* ports 0-8 + CPU port module */
+	    untagged: 9, /* ports 0-8 */
+	    src_chk: 1,
+	    mir: 1,
+	    lrn_dis: 1,
+	    prv_vlan: 1,
+	    fld_dis: 1,
+	    s_fwd_ena: 1;
+};
+
+/* MAC table entry types.
+ * ENTRYTYPE_NORMAL is subject to aging.
+ * ENTRYTYPE_LOCKED is not subject to aging.
+ * ENTRYTYPE_MACv4 is not subject to aging. For IPv4 multicast.
+ * ENTRYTYPE_MACv6 is not subject to aging. For IPv6 multicast.
+ */
+enum macaccess_entry_type {
+	ENTRYTYPE_NORMAL = 0,
+	ENTRYTYPE_LOCKED,
+	ENTRYTYPE_MACV4,
+	ENTRYTYPE_MACV6,
+};
+
+struct lan9645x {
+	struct device *dev;
+	struct dsa_switch *ds;
+	struct regmap *rmap[NUM_TARGETS];
+
+	u16 host_flood_uc_mask;
+	u16 host_flood_mc_mask;
+
+	struct workqueue_struct *owq;
+
+	int shared_queue_sz;
+
+	/* NPI chip_port */
+	int npi;
+
+	u8 num_phys_ports;
+	struct lan9645x_port **ports;
+
+	struct mutex port_mux_lock; /* serialize port muxing */
+
+	/* Forwarding Database */
+	struct net_device *bridge; /* Only support single bridge */
+	u16 bridge_mask; /* Mask for bridged ports */
+	u16 bridge_fwd_mask; /* Mask for forwarding bridged ports */
+	struct mutex fwd_domain_lock; /* lock forwarding configuration */
+	struct mutex mact_lock; /* serialize mac table register access */
+
+	/* VLAN entries */
+	struct lan9645x_vlan vlans[VLAN_N_VID];
+
+	/* Multicast Forwarding Database */
+	struct list_head mdb_entries;
+	struct list_head pgid_entries;
+	/* lock for mdb_entries and pgid_entries. Must be taken before mact_lock
+	 * if both are taken.
+	 */
+	struct mutex mdb_lock;
+
+	/* Statistics  */
+	struct lan9645x_stats *stats;
+
+	int num_port_dis;
+};
+
+struct lan9645x_port {
+	struct lan9645x *lan9645x;
+
+	u8 chip_port;
+	u8 stp_state;
+	bool learn_ena;
+
+	bool vlan_aware;
+	u16 pvid;
+
+	bool rx_internal_delay;
+	bool tx_internal_delay;
+
+	struct work_struct host_flood_work;
+	/* Packed host flood request deposited by port_set_host_flood (atomic
+	 * context) and consumed by host_flood_work_fn.
+	 */
+	u8 host_flood_req;
+};
+
+extern const struct phylink_mac_ops lan9645x_phylink_mac_ops;
+
+/* PFC_CFG.FC_LINK_SPEED encoding */
+static inline int lan9645x_speed_fc_enc(int speed)
+{
+	switch (speed) {
+	case LAN9645X_SPEED_10:
+		return 3;
+	case LAN9645X_SPEED_100:
+		return 2;
+	case LAN9645X_SPEED_1000:
+		return 1;
+	case LAN9645X_SPEED_2500:
+		return 0;
+	default:
+		WARN_ON_ONCE(1);
+		return 1;
+	}
+}
+
+/* Watermark encode. See QSYS:RES_CTRL[*]:RES_CFG.WM_HIGH for details.
+ * Returns lowest encoded number which will fit request/ is larger than request.
+ * Or the maximum representable value, if request is too large.
+ */
+static inline u32 lan9645x_wm_enc(u32 value)
+{
+	value = DIV_ROUND_UP(value, LAN9645X_BUFFER_CELL_SZ);
+
+	if (value >= GWM_MULTIPLIER_BIT) {
+		value = DIV_ROUND_UP(value, 16);
+		if (value >= GWM_MULTIPLIER_BIT)
+			value = (GWM_MULTIPLIER_BIT - 1);
+		value |= GWM_MULTIPLIER_BIT;
+	}
+
+	return value;
+}
+
+static inline struct lan9645x_port *lan9645x_to_port(struct lan9645x *lan9645x,
+						     int port)
+{
+	return lan9645x->ports[port];
+}
+
+static inline bool lan9645x_port_is_bridged(struct lan9645x_port *p)
+{
+	return p && (p->lan9645x->bridge_mask & BIT(p->chip_port));
+}
+
+static inline struct regmap *lan_tgt2rmap(struct lan9645x *lan9645x,
+					  enum lan9645x_target t, int tinst)
+{
+	return lan9645x->rmap[t + tinst];
+}
+
+static inline u32 __lan_rel_addr(int gbase, int ginst, int gcnt,
+				 int gwidth, int raddr, int rinst,
+				 int rcnt, int rwidth)
+{
+	WARN_ON(ginst >= gcnt);
+	WARN_ON(rinst >= rcnt);
+	return gbase + ginst * gwidth + raddr + rinst * rwidth;
+}
+
+/* Get register address relative to target instance */
+static inline u32 lan_rel_addr(enum lan9645x_target t, int tinst, int tcnt,
+			       int gbase, int ginst, int gcnt, int gwidth,
+			       int raddr, int rinst, int rcnt, int rwidth)
+{
+	WARN_ON(tinst >= tcnt);
+	return __lan_rel_addr(gbase, ginst, gcnt, gwidth, raddr, rinst,
+			      rcnt, rwidth);
+}
+
+static inline u32 lan_rd(struct lan9645x *lan9645x, enum lan9645x_target t,
+			 int tinst, int tcnt, int gbase, int ginst,
+			 int gcnt, int gwidth, int raddr, int rinst,
+			 int rcnt, int rwidth)
+{
+	u32 addr, val = 0;
+
+	addr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,
+			    raddr, rinst, rcnt, rwidth);
+
+	WARN_ON_ONCE(regmap_read(lan_tgt2rmap(lan9645x, t, tinst), addr, &val));
+
+	return val;
+}
+
+static inline int lan_bulk_rd(void *val, size_t val_count,
+			      struct lan9645x *lan9645x,
+			      enum lan9645x_target t, int tinst, int tcnt,
+			      int gbase, int ginst, int gcnt, int gwidth,
+			      int raddr, int rinst, int rcnt, int rwidth)
+{
+	u32 addr;
+
+	addr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,
+			    raddr, rinst, rcnt, rwidth);
+
+	return regmap_bulk_read(lan_tgt2rmap(lan9645x, t, tinst), addr, val,
+				val_count);
+}
+
+static inline struct regmap *lan_rmap(struct lan9645x *lan9645x,
+				      enum lan9645x_target t, int tinst,
+				      int tcnt, int gbase, int ginst,
+				      int gcnt, int gwidth, int raddr,
+				      int rinst, int rcnt, int rwidth)
+{
+	return lan_tgt2rmap(lan9645x, t, tinst);
+}
+
+static inline void lan_wr(u32 val, struct lan9645x *lan9645x,
+			  enum lan9645x_target t, int tinst, int tcnt,
+			  int gbase, int ginst, int gcnt, int gwidth,
+			  int raddr, int rinst, int rcnt, int rwidth)
+{
+	u32 addr;
+
+	addr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,
+			    raddr, rinst, rcnt, rwidth);
+
+	WARN_ON_ONCE(regmap_write(lan_tgt2rmap(lan9645x, t, tinst), addr, val));
+}
+
+static inline void lan_rmw(u32 val, u32 mask, struct lan9645x *lan9645x,
+			   enum lan9645x_target t, int tinst, int tcnt,
+			   int gbase, int ginst, int gcnt, int gwidth,
+			   int raddr, int rinst, int rcnt, int rwidth)
+{
+	u32 addr;
+
+	addr = lan_rel_addr(t, tinst, tcnt, gbase, ginst, gcnt, gwidth,
+			    raddr, rinst, rcnt, rwidth);
+
+	WARN_ON_ONCE(regmap_update_bits(lan_tgt2rmap(lan9645x, t, tinst),
+					addr, mask, val));
+}
+
+/* lan9645x_npi.c */
+void lan9645x_npi_port_init(struct lan9645x *lan9645x,
+			    struct dsa_port *cpu_port);
+void lan9645x_npi_port_deinit(struct lan9645x *lan9645x, int port);
+
+/* lan9645x_port.c */
+int lan9645x_port_setup(struct dsa_switch *ds, int port);
+void lan9645x_port_set_tail_drop_wm(struct lan9645x *lan9645x);
+int lan9645x_port_set_maxlen(struct lan9645x *lan9645x, int port, size_t sdu);
+void lan9645x_port_cpu_init(struct lan9645x *lan9645x);
+
+/* lan9645x_phylink.c */
+void lan9645x_phylink_get_caps(struct lan9645x *lan9645x, int port,
+			       struct phylink_config *c);
+void lan9645x_phylink_port_down(struct lan9645x *lan9645x, int port);
+
+/* VLAN lan9645x_vlan.c */
+int lan9645x_vlan_init(struct lan9645x *lan9645x);
+u16 lan9645x_vlan_unaware_pvid(bool is_bridged);
+void lan9645x_vlan_port_apply(struct lan9645x_port *p);
+int lan9645x_vlan_port_add_vlan(struct lan9645x_port *p, u16 vid, bool pvid,
+				bool untagged,
+				struct netlink_ext_ack *extack);
+int lan9645x_vlan_port_del_vlan(struct lan9645x_port *p, u16 vid);
+void lan9645x_vlan_set_hostmode(struct lan9645x_port *p);
+void lan9645x_vlan_clear_hostmode(struct lan9645x_port *p);
+
+/* MAC table: lan9645x_mac.c */
+int lan9645x_mact_flush(struct lan9645x *lan9645x, int port);
+int lan9645x_mact_learn(struct lan9645x *lan9645x, int port,
+			const unsigned char *addr, u16 vid,
+			enum macaccess_entry_type type);
+int lan9645x_mact_forget(struct lan9645x *lan9645x,
+			 const unsigned char mac[ETH_ALEN], unsigned int vid,
+			 enum macaccess_entry_type type);
+int lan9645x_mac_init(struct lan9645x *lan9645x);
+void lan9645x_mac_deinit(struct lan9645x *lan9645x);
+int lan9645x_mact_dsa_dump(struct lan9645x *lan9645x, int port,
+			   dsa_fdb_dump_cb_t *cb, void *data);
+int lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,
+				 const unsigned char *addr, u16 vid,
+				 enum macaccess_entry_type type, bool cpu_copy);
+
+/* Multicast Database lan9645x_mdb.c */
+int lan9645x_mdb_port_add(struct lan9645x *lan9645x, int port,
+			  const struct switchdev_obj_port_mdb *mdb,
+			  struct net_device *bridge);
+int lan9645x_mdb_port_del(struct lan9645x *lan9645x, int port,
+			  const struct switchdev_obj_port_mdb *mdb,
+			  struct net_device *bridge);
+void lan9645x_mdb_init(struct lan9645x *lan9645x);
+void lan9645x_mdb_deinit(struct lan9645x *lan9645x);
+
+#endif /* __LAN9645X_MAIN_H__ */
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_mdb.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_mdb.c
new file mode 100644
index 00000000000000..ea37bb660273cd
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_mdb.c
@@ -0,0 +1,398 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include "lan9645x_main.h"
+
+/* HW ignores dest_idx for IPv4/IPv6 types, so we use this dummy index */
+#define IP_ENTRY_PGID		0
+#define PGID_INDEX(pgid)	((pgid) ? (pgid)->index : IP_ENTRY_PGID)
+
+struct lan9645x_pgid_entry {
+	struct list_head list;
+	int index;
+	refcount_t refcount;
+	u16 ports;
+};
+
+struct lan9645x_mdb_entry {
+	struct list_head list;
+	unsigned char mac[ETH_ALEN];
+	u16 vid;
+	u16 ports;
+	struct lan9645x_pgid_entry *pgid;
+};
+
+void lan9645x_mdb_init(struct lan9645x *lan9645x)
+{
+	INIT_LIST_HEAD(&lan9645x->mdb_entries);
+	INIT_LIST_HEAD(&lan9645x->pgid_entries);
+	mutex_init(&lan9645x->mdb_lock);
+
+	/* Use CPU queues to communicate frame classification to the CPU */
+	lan_rmw(ANA_CPUQ_CFG_CPUQ_IGMP_SET(LAN9645X_CPUQ_TRAP) |
+		ANA_CPUQ_CFG_CPUQ_MLD_SET(LAN9645X_CPUQ_TRAP) |
+		ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_SET(LAN9645X_CPUQ_COPY),
+		ANA_CPUQ_CFG_CPUQ_IGMP |
+		ANA_CPUQ_CFG_CPUQ_MLD |
+		ANA_CPUQ_CFG_CPUQ_IPMC_CTRL,
+		lan9645x, ANA_CPUQ_CFG);
+}
+
+static enum macaccess_entry_type lan9645x_mdb_classify(const unsigned char *mac)
+{
+	if (ether_addr_is_ipv4_mcast(mac))
+		return ENTRYTYPE_MACV4;
+	if (ether_addr_is_ipv6_mcast(mac))
+		return ENTRYTYPE_MACV6;
+	return ENTRYTYPE_LOCKED;
+}
+
+static struct lan9645x_mdb_entry *
+lan9645x_mdb_entry_lookup(struct lan9645x *lan9645x, const unsigned char *mac,
+			  u16 vid)
+{
+	struct lan9645x_mdb_entry *mdb;
+
+	list_for_each_entry(mdb, &lan9645x->mdb_entries, list) {
+		if (ether_addr_equal(mdb->mac, mac) && mdb->vid == vid)
+			return mdb;
+	}
+
+	return NULL;
+}
+
+static struct lan9645x_mdb_entry *
+lan9645x_mdb_entry_alloc(struct lan9645x *lan9645x,
+			 const unsigned char addr[ETH_ALEN], u16 vid)
+{
+	struct lan9645x_mdb_entry *mdb_entry;
+
+	mdb_entry = kzalloc_obj(*mdb_entry);
+	if (!mdb_entry)
+		return ERR_PTR(-ENOMEM);
+
+	ether_addr_copy(mdb_entry->mac, addr);
+	mdb_entry->vid = vid;
+
+	list_add_tail(&mdb_entry->list, &lan9645x->mdb_entries);
+
+	dev_dbg(lan9645x->dev, "vid=%u addr=%pM\n", mdb_entry->vid,
+		mdb_entry->mac);
+
+	return mdb_entry;
+}
+
+static void lan9645x_mdb_encode_mac(unsigned char *dst, unsigned char *mac,
+				    u16 ports, enum macaccess_entry_type type)
+{
+	ether_addr_copy(dst, mac);
+
+	/* The HW encodes the portmask in the high bits of the mac for ip
+	 * multicast entries, to save on the limited PGID resources.
+	 *
+	 * IPv4 Multicast DMAC: 0x01005Exxxxxx
+	 * IPv6 Multicast DMAC: 0x3333xxxxxxxx
+	 *
+	 * which gives us 24 or 16 bits to encode the portmask.
+	 */
+	if (type == ENTRYTYPE_MACV4) {
+		dst[0] = 0;
+		dst[1] = ports >> 8;
+		dst[2] = ports & 0xff;
+	} else if (type == ENTRYTYPE_MACV6) {
+		dst[0] = ports >> 8;
+		dst[1] = ports & 0xff;
+	}
+}
+
+static void lan9645x_pgid_entry_put(struct lan9645x *lan9645x,
+				    struct lan9645x_pgid_entry *pgid_entry)
+{
+	if (!pgid_entry)
+		return;
+
+	if (!refcount_dec_and_test(&pgid_entry->refcount))
+		return;
+
+	dev_dbg(lan9645x->dev, "pgid=%d ports=0x%x", pgid_entry->index,
+		pgid_entry->ports);
+	/* We leave the PGID written in HW, as no entry is pointing to it. */
+	list_del(&pgid_entry->list);
+	kfree(pgid_entry);
+}
+
+static void lan9645x_mdb_entry_dealloc(struct lan9645x *lan9645x,
+				       struct lan9645x_mdb_entry *mdb_entry)
+{
+	dev_dbg(lan9645x->dev, "vid=%u addr=%pM\n", mdb_entry->vid,
+		mdb_entry->mac);
+	list_del(&mdb_entry->list);
+	lan9645x_pgid_entry_put(lan9645x, mdb_entry->pgid);
+	kfree(mdb_entry);
+}
+
+static struct lan9645x_pgid_entry *
+lan9645x_mdb_pgid_entry_lookup(struct lan9645x *lan9645x, u16 ports)
+{
+	struct lan9645x_pgid_entry *pgid_entry;
+
+	list_for_each_entry(pgid_entry, &lan9645x->pgid_entries, list) {
+		if (pgid_entry->ports == ports &&
+		    refcount_inc_not_zero(&pgid_entry->refcount))
+			return pgid_entry;
+	}
+
+	return NULL;
+}
+
+static struct lan9645x_pgid_entry *
+lan9645x_pgid_entry_alloc(struct lan9645x *lan9645x, int index, u16 ports)
+{
+	struct lan9645x_pgid_entry *pgid_entry;
+
+	pgid_entry = kzalloc_obj(*pgid_entry);
+	if (!pgid_entry)
+		return ERR_PTR(-ENOMEM);
+
+	pgid_entry->ports = ports;
+	pgid_entry->index = index;
+	refcount_set(&pgid_entry->refcount, 1);
+
+	list_add_tail(&pgid_entry->list, &lan9645x->pgid_entries);
+
+	dev_dbg(lan9645x->dev, "index=%d ports=0x%x", pgid_entry->index,
+		pgid_entry->ports);
+
+	lan_rmw(ANA_PGID_PGID_SET(pgid_entry->ports),
+		ANA_PGID_PGID, lan9645x,
+		ANA_PGID(pgid_entry->index));
+
+	return pgid_entry;
+}
+
+static struct lan9645x_pgid_entry *
+lan9645x_mdb_pgid_entry_create(struct lan9645x *lan9645x, u16 ports)
+{
+	struct lan9645x_pgid_entry *pgid_entry = NULL;
+	int index;
+
+	for (index = PGID_GP_START; index < PGID_GP_END; index++) {
+		bool used = false;
+
+		list_for_each_entry(pgid_entry, &lan9645x->pgid_entries, list) {
+			if (pgid_entry->index == index) {
+				used = true;
+				break;
+			}
+		}
+
+		if (!used)
+			return lan9645x_pgid_entry_alloc(lan9645x, index,
+							 ports);
+	}
+
+	return ERR_PTR(-ENOSPC);
+}
+
+static struct lan9645x_pgid_entry *
+lan9645x_mdb_pgid_entry_get(struct lan9645x *lan9645x, u16 ports,
+			    enum macaccess_entry_type type)
+{
+	struct lan9645x_pgid_entry *pgid_entry;
+	u16 pgid_ports;
+
+	if (type == ENTRYTYPE_MACV4 || type == ENTRYTYPE_MACV6 || !ports)
+		return NULL;
+
+	/* CPU port module forwarding is handled by cpu_copy flag on mac table
+	 * entry. So we can strip the CPU port module here to allow better PGID
+	 * sharing.
+	 */
+	pgid_ports = ports & ~BIT(lan9645x->num_phys_ports);
+
+	pgid_entry = lan9645x_mdb_pgid_entry_lookup(lan9645x, pgid_ports);
+	if (!pgid_entry)
+		return lan9645x_mdb_pgid_entry_create(lan9645x, pgid_ports);
+
+	return pgid_entry;
+}
+
+static int lan9645x_mdb_update_dest(struct lan9645x *lan9645x,
+				    struct lan9645x_mdb_entry *mdb_entry,
+				    enum macaccess_entry_type type,
+				    struct lan9645x_pgid_entry *new_pgid,
+				    u16 new_ports)
+{
+	unsigned char mac[ETH_ALEN] __aligned(2);
+	struct lan9645x_pgid_entry *old_pgid;
+	int err, pgid_index;
+	bool cpu_copy;
+
+	old_pgid = mdb_entry->pgid;
+	lan9645x_mdb_encode_mac(mac, mdb_entry->mac, new_ports, type);
+	cpu_copy = !!(new_ports & BIT(lan9645x->num_phys_ports));
+	pgid_index = PGID_INDEX(new_pgid);
+
+	/* For IP multicast, the hardware lookup uses the DMAC
+	 * (01:00:5E:.. / 33:33:..) as the (mac, vid) key, not the encoded mac.
+	 * Therefore, this CMD_LEARN will atomically rewrite the existing
+	 * hardware entry. We intentionally do not do a forget before learn
+	 * sequence, as that would not be atomic, and leave a forwarding gap.
+	 */
+	err = lan9645x_mact_learn_cpu_copy(lan9645x, pgid_index, mac,
+					   mdb_entry->vid, type, cpu_copy);
+	if (err) {
+		lan9645x_pgid_entry_put(lan9645x, new_pgid);
+		return err;
+	}
+	mdb_entry->pgid = new_pgid;
+	mdb_entry->ports = new_ports;
+	lan9645x_pgid_entry_put(lan9645x, old_pgid);
+	return 0;
+}
+
+static int __lan9645x_mdb_add(struct lan9645x *lan9645x, int chip_port,
+			      const unsigned char addr[ETH_ALEN], u16 vid,
+			      enum macaccess_entry_type type)
+{
+	struct lan9645x_pgid_entry *new_pgid;
+	struct lan9645x_mdb_entry *mdb_entry;
+	u16 new_ports;
+	int err;
+
+	mdb_entry = lan9645x_mdb_entry_lookup(lan9645x, addr, vid);
+	if (!mdb_entry) {
+		mdb_entry = lan9645x_mdb_entry_alloc(lan9645x, addr, vid);
+		if (IS_ERR(mdb_entry))
+			return PTR_ERR(mdb_entry);
+	}
+
+	if (mdb_entry->ports & BIT(chip_port))
+		return 0;
+
+	new_ports = mdb_entry->ports | BIT(chip_port);
+
+	/* Update PGID ptr for non-IP entries (L2 multicast) */
+	new_pgid = lan9645x_mdb_pgid_entry_get(lan9645x, new_ports, type);
+	if (IS_ERR(new_pgid)) {
+		/* Out of PGIDs or mem. Continue forwarding to old port
+		 * group, or remove if fresh mdb_entry.
+		 */
+		if (!mdb_entry->ports)
+			lan9645x_mdb_entry_dealloc(lan9645x, mdb_entry);
+
+		return PTR_ERR(new_pgid);
+	}
+
+	err = lan9645x_mdb_update_dest(lan9645x, mdb_entry, type, new_pgid,
+				       new_ports);
+	if (err && !mdb_entry->ports)
+		lan9645x_mdb_entry_dealloc(lan9645x, mdb_entry);
+
+	return err;
+}
+
+static int __lan9645x_mdb_del(struct lan9645x *lan9645x, int chip_port,
+			      const unsigned char addr[ETH_ALEN], u16 vid,
+			      enum macaccess_entry_type type)
+{
+	struct lan9645x_pgid_entry *new_pgid;
+	struct lan9645x_mdb_entry *mdb_entry;
+	u16 new_ports;
+	int err;
+
+	mdb_entry = lan9645x_mdb_entry_lookup(lan9645x, addr, vid);
+	if (!mdb_entry)
+		return -ENOENT;
+
+	if (!(mdb_entry->ports & BIT(chip_port)))
+		return 0;
+
+	new_ports = mdb_entry->ports & ~BIT(chip_port);
+
+	if (!new_ports) {
+		/* For IP multicast hardware uses DMAC as key (mac,vid) not
+		 * encoded mac.
+		 */
+		err = lan9645x_mact_forget(lan9645x, mdb_entry->mac,
+					   mdb_entry->vid, type);
+		if (err)
+			return err;
+		lan9645x_mdb_entry_dealloc(lan9645x, mdb_entry);
+		return 0;
+	}
+
+	/* Update PGID ptr for non-IP entries (L2 multicast) */
+	new_pgid = lan9645x_mdb_pgid_entry_get(lan9645x, new_ports, type);
+	if (IS_ERR(new_pgid))
+		/* Continue forwarding to old port group. */
+		return PTR_ERR(new_pgid);
+
+	return lan9645x_mdb_update_dest(lan9645x, mdb_entry, type, new_pgid,
+					new_ports);
+}
+
+static int lan9645x_mdb_add(struct lan9645x *lan9645x, int chip_port,
+			    const unsigned char addr[ETH_ALEN], u16 vid,
+			    enum macaccess_entry_type type)
+{
+	int err;
+
+	mutex_lock(&lan9645x->mdb_lock);
+	err = __lan9645x_mdb_add(lan9645x, chip_port, addr, vid, type);
+	mutex_unlock(&lan9645x->mdb_lock);
+	return err;
+}
+
+static int lan9645x_mdb_del(struct lan9645x *lan9645x, int chip_port,
+			    const unsigned char addr[ETH_ALEN], u16 vid,
+			    enum macaccess_entry_type type)
+{
+	int err;
+
+	mutex_lock(&lan9645x->mdb_lock);
+	err = __lan9645x_mdb_del(lan9645x, chip_port, addr, vid, type);
+	mutex_unlock(&lan9645x->mdb_lock);
+	return err;
+}
+
+int lan9645x_mdb_port_add(struct lan9645x *lan9645x, int port,
+			  const struct switchdev_obj_port_mdb *mdb,
+			  struct net_device *bridge)
+{
+	enum macaccess_entry_type type;
+	u16 vid = mdb->vid;
+
+	type = lan9645x_mdb_classify(mdb->addr);
+
+	if (!vid)
+		vid = lan9645x_vlan_unaware_pvid(!!bridge);
+
+	return lan9645x_mdb_add(lan9645x, port, mdb->addr, vid, type);
+}
+
+int lan9645x_mdb_port_del(struct lan9645x *lan9645x, int port,
+			  const struct switchdev_obj_port_mdb *mdb,
+			  struct net_device *bridge)
+{
+	enum macaccess_entry_type type;
+	u16 vid = mdb->vid;
+
+	type = lan9645x_mdb_classify(mdb->addr);
+
+	if (!vid)
+		vid = lan9645x_vlan_unaware_pvid(!!bridge);
+
+	return lan9645x_mdb_del(lan9645x, port, mdb->addr, vid, type);
+}
+
+void lan9645x_mdb_deinit(struct lan9645x *lan9645x)
+{
+	struct lan9645x_mdb_entry *mdb, *tmp;
+
+	list_for_each_entry_safe(mdb, tmp, &lan9645x->mdb_entries, list)
+		lan9645x_mdb_entry_dealloc(lan9645x, mdb);
+
+	mutex_destroy(&lan9645x->mdb_lock);
+}
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_npi.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_npi.c
new file mode 100644
index 00000000000000..7e286101f055aa
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_npi.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+#include <net/addrconf.h>
+
+#include "lan9645x_main.h"
+
+void lan9645x_npi_port_init(struct lan9645x *lan9645x,
+			    struct dsa_port *cpu_port)
+{
+	int port = cpu_port->index;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+	lan9645x->npi = port;
+
+	dev_dbg(lan9645x->dev, "NPI port=%d\n", port);
+
+	/* Any CPU extraction queue frames, are sent to external CPU on given
+	 * port. Never send injected frames back to cpu.
+	 */
+	lan_wr(QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK |
+	       QSYS_EXT_CPU_CFG_EXT_CPU_PORT_SET(p->chip_port) |
+	       QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_SET(1) |
+	       QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_SET(1),
+	       lan9645x, QSYS_EXT_CPU_CFG);
+
+	/* Configure IFH prefix mode for NPI port. We can not use an injection
+	 * prefix, because it requires all frames sent on the port to contain
+	 * the prefix. Frames without the prefix would get stuck in the queue
+	 * system rendering the port becomes unusable. Since we do not control
+	 * what is sent to the NPI port, no prefix is our only option.
+	 */
+	lan_rmw(SYS_PORT_MODE_INCL_XTR_HDR_SET(LAN9645X_TAG_PREFIX_LONG) |
+		SYS_PORT_MODE_INCL_INJ_HDR_SET(LAN9645X_TAG_PREFIX_NONE),
+		SYS_PORT_MODE_INCL_XTR_HDR |
+		SYS_PORT_MODE_INCL_INJ_HDR,
+		lan9645x,
+		SYS_PORT_MODE(p->chip_port));
+
+	/* Rewriting and extraction with IFH does not play nice together. A VLAN
+	 * tag pushed into the frame by REW will cause 4 bytes at the end of the
+	 * extraction header to be overwritten with the top 4 bytes of the DMAC.
+	 *
+	 * We can not use REW_PORT_CFG_NO_REWRITE=1 as that disabled RTAGD
+	 * setting in the IFH
+	 */
+	lan_rmw(REW_TAG_CFG_TAG_CFG_SET(LAN9645X_TAG_DISABLED),
+		REW_TAG_CFG_TAG_CFG, lan9645x, REW_TAG_CFG(port));
+
+	/* Clear rewriter port vid */
+	lan_wr(0, lan9645x, REW_PORT_VLAN_CFG(port));
+
+	/* Make sure frames with src_port=<CPU port module> are not reflected
+	 * back via the NPI port. This could happen if a frame is flooded for
+	 * instance. The *_CPU_KILL_ENA flags above only have an effect when a
+	 * frame is output due to a CPU forwarding decision such as trapping or
+	 * cpu copy.
+	 */
+	lan_rmw(0, BIT(port), lan9645x,
+		ANA_PGID(PGID_SRC + lan9645x->num_phys_ports));
+}
+
+void lan9645x_npi_port_deinit(struct lan9645x *lan9645x, int port)
+{
+	struct lan9645x_port *p;
+
+	if (port < 0)
+		return;
+
+	lan9645x->npi = -1;
+	p = lan9645x_to_port(lan9645x, port);
+
+	lan_wr(QSYS_EXT_CPU_CFG_EXT_CPU_PORT_SET(0x1f) |
+	       QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_SET(1) |
+	       QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_SET(1),
+	       lan9645x, QSYS_EXT_CPU_CFG);
+
+	lan_rmw(SYS_PORT_MODE_INCL_XTR_HDR_SET(LAN9645X_TAG_PREFIX_DISABLED) |
+		SYS_PORT_MODE_INCL_INJ_HDR_SET(LAN9645X_TAG_PREFIX_DISABLED),
+		SYS_PORT_MODE_INCL_XTR_HDR |
+		SYS_PORT_MODE_INCL_INJ_HDR,
+		lan9645x,
+		SYS_PORT_MODE(p->chip_port));
+}
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c
new file mode 100644
index 00000000000000..4f77038918af8e
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
+
+#include "lan9645x_main.h"
+
+/* Port 4 or 7 is RGMII_0 and port 8 is RGMII_1 */
+#define RGMII_IDX(port) ((port) == 8 ? 1 : 0)
+
+void lan9645x_phylink_get_caps(struct lan9645x *lan9645x, int port,
+			       struct phylink_config *c)
+{
+	c->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 |
+			      MAC_100 | MAC_1000FD;
+
+	switch (port) {
+	case 0 ... 3:
+		__set_bit(PHY_INTERFACE_MODE_GMII, c->supported_interfaces);
+		break;
+	case 4:
+		__set_bit(PHY_INTERFACE_MODE_GMII, c->supported_interfaces);
+		phy_interface_set_rgmii(c->supported_interfaces);
+		break;
+	case 5 ... 6:
+		/* SerDes ports: QSGMII/SGMII/1000BASEX/2500BASEX modes
+		 * require PCS support which is not yet implemented.
+		 * With empty supported_interfaces, these will end up being
+		 * marked unused by the DSA core, if they are declared in the
+		 * DT.
+		 */
+		break;
+	case 7 ... 8:
+		/* QSGMII mode on ports 7-8 requires SerDes PCS support,
+		 * which is not yet implemented.
+		 */
+		phy_interface_set_rgmii(c->supported_interfaces);
+		break;
+	default:
+		break;
+	}
+}
+
+static void lan9645x_rgmii_set_speed(struct lan9645x *lan9645x, int port,
+				     int speed)
+{
+	u8 tx_clk;
+
+	tx_clk = speed == SPEED_1000 ? 1 :
+		 speed == SPEED_100  ? 2 :
+		 speed == SPEED_10   ? 3 : 0;
+
+	lan_rmw(HSIO_RGMII_CFG_RGMII_RX_RST_SET(0) |
+		HSIO_RGMII_CFG_RGMII_TX_RST_SET(0) |
+		HSIO_RGMII_CFG_TX_CLK_CFG_SET(tx_clk),
+		HSIO_RGMII_CFG_RGMII_RX_RST |
+		HSIO_RGMII_CFG_RGMII_TX_RST |
+		HSIO_RGMII_CFG_TX_CLK_CFG,
+		lan9645x, HSIO_RGMII_CFG(RGMII_IDX(port)));
+}
+
+static void lan9645x_rgmii_dll_config(struct lan9645x_port *p)
+{
+	u32 rx_idx, tx_idx;
+
+	/* DLL register layout:
+	 * (N*2):   RGMII_N_RX
+	 * (N*2)+1: RGMII_N_TX
+	 */
+	rx_idx = RGMII_IDX(p->chip_port) * 2;
+	tx_idx = RGMII_IDX(p->chip_port) * 2 + 1;
+
+	/* Enable DLL in RGMII clock paths, deassert DLL reset, and start the
+	 * delay tune FSM.
+	 */
+	lan_rmw(HSIO_DLL_CFG_DLL_CLK_ENA_SET(1) |
+		HSIO_DLL_CFG_DLL_RST_SET(0) |
+		HSIO_DLL_CFG_DLL_ENA_SET(p->rx_internal_delay) |
+		HSIO_DLL_CFG_DELAY_ENA_SET(p->rx_internal_delay),
+		HSIO_DLL_CFG_DLL_CLK_ENA |
+		HSIO_DLL_CFG_DLL_RST |
+		HSIO_DLL_CFG_DLL_ENA |
+		HSIO_DLL_CFG_DELAY_ENA,
+		p->lan9645x, HSIO_DLL_CFG(rx_idx));
+
+	lan_rmw(HSIO_DLL_CFG_DLL_CLK_ENA_SET(1) |
+		HSIO_DLL_CFG_DLL_RST_SET(0) |
+		HSIO_DLL_CFG_DLL_ENA_SET(p->tx_internal_delay) |
+		HSIO_DLL_CFG_DELAY_ENA_SET(p->tx_internal_delay),
+		HSIO_DLL_CFG_DLL_CLK_ENA |
+		HSIO_DLL_CFG_DLL_RST |
+		HSIO_DLL_CFG_DLL_ENA |
+		HSIO_DLL_CFG_DELAY_ENA,
+		p->lan9645x, HSIO_DLL_CFG(tx_idx));
+}
+
+static struct lan9645x_port *
+lan9645x_phylink_config_to_port(struct phylink_config *config)
+{
+	struct dsa_port *dp = dsa_phylink_to_port(config);
+
+	return lan9645x_to_port(dp->ds->priv, dp->index);
+}
+
+static int lan9645x_phylink_mac_prepare(struct phylink_config *config,
+					unsigned int mode,
+					phy_interface_t iface)
+{
+	struct lan9645x_port *p = lan9645x_phylink_config_to_port(config);
+	struct lan9645x *lan9645x = p->lan9645x;
+	int port = p->chip_port;
+	u32 hw_cfg, gmii_ena;
+	bool is_rgmii;
+
+	if (port == 5 || port == 6 || port > 8)
+		return -EINVAL;
+
+	is_rgmii = phy_interface_mode_is_rgmii(iface);
+
+	/* RGMII_0 is a 2:1 mux shared between port 4 and port 7. Reject
+	 * collisions by looking at current hardware state: the driver
+	 * maintains the invariant that RGMII_0_CFG=1 iff port 4 owns
+	 * RGMII_0, and for port 7 when GMII_ENA bit 7 is set this implies port
+	 * 7 owns RGMII_0.
+	 */
+	mutex_lock(&lan9645x->port_mux_lock);
+
+	if (is_rgmii) {
+		hw_cfg = lan_rd(lan9645x, HSIO_HW_CFG);
+		gmii_ena = HSIO_HW_CFG_GMII_ENA_GET(hw_cfg);
+
+		if ((port == 4 && (gmii_ena & BIT(7))) ||
+		    (port == 7 && (gmii_ena & BIT(4)) &&
+		     HSIO_HW_CFG_RGMII_0_CFG_GET(hw_cfg))) {
+			mutex_unlock(&lan9645x->port_mux_lock);
+			return -EBUSY;
+		}
+	}
+
+	lan_rmw(HSIO_HW_CFG_GMII_ENA_SET(BIT(port)),
+		HSIO_HW_CFG_GMII_ENA_SET(BIT(port)), lan9645x, HSIO_HW_CFG);
+
+	if (port == 4) {
+		lan_rmw(HSIO_HW_CFG_RGMII_0_CFG_SET(is_rgmii),
+			HSIO_HW_CFG_RGMII_0_CFG,
+			lan9645x, HSIO_HW_CFG);
+	} else if (port == 7 && is_rgmii) {
+		lan_rmw(HSIO_HW_CFG_RGMII_0_CFG_SET(0),
+			HSIO_HW_CFG_RGMII_0_CFG,
+			lan9645x, HSIO_HW_CFG);
+	}
+
+	mutex_unlock(&lan9645x->port_mux_lock);
+
+	return 0;
+}
+
+static void lan9645x_phylink_mac_config(struct phylink_config *config,
+					unsigned int mode,
+					const struct phylink_link_state *state)
+{
+	struct lan9645x_port *p = lan9645x_phylink_config_to_port(config);
+
+	if (phy_interface_mode_is_rgmii(state->interface))
+		lan9645x_rgmii_dll_config(p);
+}
+
+static bool lan9645x_port_is_cuphy(struct lan9645x *lan9645x, int port,
+				   phy_interface_t interface)
+{
+	return port >= 0 && port <= 4 && interface == PHY_INTERFACE_MODE_GMII;
+}
+
+void lan9645x_phylink_port_down(struct lan9645x *lan9645x, int port)
+{
+	struct lan9645x_port *p = lan9645x_to_port(lan9645x, port);
+	u32 val;
+
+	/* Disable MAC frame reception */
+	lan_rmw(DEV_MAC_ENA_CFG_RX_ENA_SET(0),
+		DEV_MAC_ENA_CFG_RX_ENA,
+		lan9645x, DEV_MAC_ENA_CFG(p->chip_port));
+
+	/* Disable traffic being sent to or from switch port */
+	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(0),
+		QSYS_SW_PORT_MODE_PORT_ENA,
+		lan9645x, QSYS_SW_PORT_MODE(p->chip_port));
+
+	/* Disable dequeuing from the egress queues  */
+	lan_rmw(QSYS_PORT_MODE_DEQUEUE_DIS_SET(1),
+		QSYS_PORT_MODE_DEQUEUE_DIS,
+		lan9645x, QSYS_PORT_MODE(p->chip_port));
+
+	/* Disable Flowcontrol */
+	lan_rmw(SYS_PAUSE_CFG_PAUSE_ENA_SET(0),
+		SYS_PAUSE_CFG_PAUSE_ENA,
+		lan9645x, SYS_PAUSE_CFG(p->chip_port));
+
+	/* Wait a worst case time 8ms (10K jumbo/10Mbit) */
+	usleep_range(8 * USEC_PER_MSEC, 9 * USEC_PER_MSEC);
+
+	/* Disable HDX backpressure. */
+	lan_rmw(SYS_FRONT_PORT_MODE_HDX_MODE_SET(0),
+		SYS_FRONT_PORT_MODE_HDX_MODE,
+		lan9645x, SYS_FRONT_PORT_MODE(p->chip_port));
+
+	/* Flush the queues associated with the port */
+	lan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(3),
+		QSYS_SW_PORT_MODE_AGING_MODE,
+		lan9645x, QSYS_SW_PORT_MODE(p->chip_port));
+
+	/* Enable dequeuing from the egress queues */
+	lan_rmw(QSYS_PORT_MODE_DEQUEUE_DIS_SET(0),
+		QSYS_PORT_MODE_DEQUEUE_DIS,
+		lan9645x, QSYS_PORT_MODE(p->chip_port));
+
+	/* Wait until flushing is complete */
+	if (lan9645x_rd_poll_slow(lan9645x, QSYS_SW_STATUS(p->chip_port),
+				  val, !QSYS_SW_STATUS_EQ_AVAIL_GET(val)))
+		dev_err(lan9645x->dev, "Flush timeout chip port %u\n", port);
+
+	/* Disable MAC tx */
+	lan_rmw(DEV_MAC_ENA_CFG_TX_ENA_SET(0),
+		DEV_MAC_ENA_CFG_TX_ENA,
+		lan9645x, DEV_MAC_ENA_CFG(p->chip_port));
+
+	/* Reset the Port and MAC clock domains */
+	lan_rmw(DEV_CLOCK_CFG_PORT_RST_SET(1),
+		DEV_CLOCK_CFG_PORT_RST,
+		lan9645x, DEV_CLOCK_CFG(p->chip_port));
+
+	/* Wait before resetting MAC clock domains. */
+	usleep_range(USEC_PER_MSEC, 2 * USEC_PER_MSEC);
+
+	lan_rmw(DEV_CLOCK_CFG_MAC_TX_RST_SET(1) |
+		DEV_CLOCK_CFG_MAC_RX_RST_SET(1) |
+		DEV_CLOCK_CFG_PORT_RST_SET(1),
+		DEV_CLOCK_CFG_MAC_TX_RST |
+		DEV_CLOCK_CFG_MAC_RX_RST |
+		DEV_CLOCK_CFG_PORT_RST,
+		lan9645x, DEV_CLOCK_CFG(p->chip_port));
+
+	/* Clear flushing */
+	lan_rmw(QSYS_SW_PORT_MODE_AGING_MODE_SET(1),
+		QSYS_SW_PORT_MODE_AGING_MODE,
+		lan9645x, QSYS_SW_PORT_MODE(p->chip_port));
+}
+
+static void lan9645x_phylink_mac_link_down(struct phylink_config *config,
+					   unsigned int link_an_mode,
+					   phy_interface_t interface)
+{
+	struct lan9645x_port *p = lan9645x_phylink_config_to_port(config);
+	struct lan9645x *lan9645x = p->lan9645x;
+
+	lan9645x_phylink_port_down(lan9645x, p->chip_port);
+}
+
+static void lan9645x_phylink_mac_link_up(struct phylink_config *config,
+					 struct phy_device *phydev,
+					 unsigned int link_an_mode,
+					 phy_interface_t interface, int speed,
+					 int duplex, bool tx_pause,
+					 bool rx_pause)
+{
+	struct lan9645x_port *p = lan9645x_phylink_config_to_port(config);
+	int rx_ifg1, rx_ifg2, tx_ifg, gtx_clk = 0;
+	struct lan9645x *lan9645x = p->lan9645x;
+	int gspeed = LAN9645X_SPEED_DISABLED;
+	int port = p->chip_port;
+	int mode = 0;
+	int fc_spd;
+
+	/* Configure RGMII TX clock for the negotiated speed */
+	if (phy_interface_mode_is_rgmii(interface))
+		lan9645x_rgmii_set_speed(lan9645x, port, speed);
+
+	if (duplex == DUPLEX_FULL) {
+		mode |= DEV_MAC_MODE_CFG_FDX_ENA_SET(1);
+		tx_ifg = 0x5;
+		rx_ifg2 = 0x2;
+
+	} else {
+		tx_ifg = 0x6;
+		rx_ifg2 = 0x2;
+	}
+
+	switch (speed) {
+	case SPEED_10:
+		rx_ifg1 = 0x2;
+		gspeed = LAN9645X_SPEED_10;
+		break;
+	case SPEED_100:
+		rx_ifg1 = 0x1;
+		gspeed = LAN9645X_SPEED_100;
+		break;
+	case SPEED_1000:
+		gspeed = LAN9645X_SPEED_1000;
+		mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);
+		mode |= DEV_MAC_MODE_CFG_FDX_ENA_SET(1);
+		tx_ifg = 0x6;
+		rx_ifg1 = 0x1;
+		rx_ifg2 = 0x2;
+		gtx_clk = 1;
+		break;
+	case SPEED_2500:
+		gspeed = LAN9645X_SPEED_2500;
+		mode |= DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(1);
+		mode |= DEV_MAC_MODE_CFG_FDX_ENA_SET(1);
+		tx_ifg = 0x6;
+		rx_ifg1 = 0x1;
+		rx_ifg2 = 0x2;
+		break;
+	default:
+		dev_err(lan9645x->dev, "Unsupported speed on port %d: %d\n",
+			p->chip_port, speed);
+		return;
+	}
+
+	fc_spd = lan9645x_speed_fc_enc(gspeed);
+
+	lan_rmw(mode,
+		DEV_MAC_MODE_CFG_FDX_ENA |
+		DEV_MAC_MODE_CFG_GIGA_MODE_ENA,
+		lan9645x, DEV_MAC_MODE_CFG(p->chip_port));
+
+	lan_rmw(DEV_MAC_IFG_CFG_TX_IFG_SET(tx_ifg) |
+		DEV_MAC_IFG_CFG_RX_IFG1_SET(rx_ifg1) |
+		DEV_MAC_IFG_CFG_RX_IFG2_SET(rx_ifg2),
+		DEV_MAC_IFG_CFG_TX_IFG |
+		DEV_MAC_IFG_CFG_RX_IFG1 |
+		DEV_MAC_IFG_CFG_RX_IFG2,
+		lan9645x, DEV_MAC_IFG_CFG(p->chip_port));
+
+	if (lan9645x_port_is_cuphy(lan9645x, port, interface)) {
+		lan_rmw(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(gtx_clk),
+			CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, lan9645x,
+			CHIP_TOP_CUPHY_PORT_CFG(p->chip_port));
+	}
+
+	lan_rmw(SYS_PAUSE_CFG_PAUSE_ENA_SET(1),
+		SYS_PAUSE_CFG_PAUSE_ENA,
+		lan9645x, SYS_PAUSE_CFG(p->chip_port));
+
+	/* Flow control */
+	lan_rmw(SYS_MAC_FC_CFG_FC_LINK_SPEED_SET(fc_spd) |
+		SYS_MAC_FC_CFG_FC_LATENCY_CFG_SET(0x7) |
+		SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_SET(1) |
+		SYS_MAC_FC_CFG_PAUSE_VAL_CFG_SET(0xffff) |
+		SYS_MAC_FC_CFG_RX_FC_ENA_SET(rx_pause ? 1 : 0) |
+		SYS_MAC_FC_CFG_TX_FC_ENA_SET(tx_pause ? 1 : 0),
+		SYS_MAC_FC_CFG_FC_LINK_SPEED |
+		SYS_MAC_FC_CFG_FC_LATENCY_CFG |
+		SYS_MAC_FC_CFG_ZERO_PAUSE_ENA |
+		SYS_MAC_FC_CFG_PAUSE_VAL_CFG |
+		SYS_MAC_FC_CFG_RX_FC_ENA |
+		SYS_MAC_FC_CFG_TX_FC_ENA,
+		lan9645x, SYS_MAC_FC_CFG(p->chip_port));
+
+	/* Enable MAC module */
+	lan_wr(DEV_MAC_ENA_CFG_RX_ENA_SET(1) |
+	       DEV_MAC_ENA_CFG_TX_ENA_SET(1),
+	       lan9645x, DEV_MAC_ENA_CFG(p->chip_port));
+
+	/* port _must_ be taken out of reset before MAC. */
+	lan_rmw(DEV_CLOCK_CFG_PORT_RST_SET(0),
+		DEV_CLOCK_CFG_PORT_RST,
+		lan9645x, DEV_CLOCK_CFG(p->chip_port));
+
+	/* Take out the clock from reset. Note this write will set all these
+	 * fields to zero:
+	 *
+	 * DEV_CLOCK_CFG[*].MAC_TX_RST
+	 * DEV_CLOCK_CFG[*].MAC_RX_RST
+	 * DEV_CLOCK_CFG[*].PCS_TX_RST
+	 * DEV_CLOCK_CFG[*].PCS_RX_RST
+	 * DEV_CLOCK_CFG[*].PORT_RST
+	 * DEV_CLOCK_CFG[*].PHY_RST
+	 *
+	 * Note link_down will assert PORT_RST, MAC_RX_RST and MAC_TX_RST, so
+	 * we are effectively taking the mac tx/rx clocks out of reset.
+	 *
+	 * This linkspeed field has a slightly different encoding from others:
+	 *
+	 * - 0 is no-link
+	 * - 1 is both 2500/1000
+	 * - 2 is 100mbit
+	 * - 3 is 10mbit
+	 *
+	 */
+	lan_wr(DEV_CLOCK_CFG_LINK_SPEED_SET(fc_spd == 0 ? 1 : fc_spd),
+	       lan9645x,
+	       DEV_CLOCK_CFG(p->chip_port));
+
+	/* Core: Enable port for frame transfer */
+	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1) |
+		QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(1) |
+		QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(1) |
+		QSYS_SW_PORT_MODE_TX_PFC_ENA_SET(0),
+		QSYS_SW_PORT_MODE_PORT_ENA |
+		QSYS_SW_PORT_MODE_SCH_NEXT_CFG |
+		QSYS_SW_PORT_MODE_INGRESS_DROP_MODE |
+		QSYS_SW_PORT_MODE_TX_PFC_ENA,
+		lan9645x, QSYS_SW_PORT_MODE(p->chip_port));
+}
+
+const struct phylink_mac_ops lan9645x_phylink_mac_ops = {
+	.mac_prepare			= lan9645x_phylink_mac_prepare,
+	.mac_config			= lan9645x_phylink_mac_config,
+	.mac_link_down			= lan9645x_phylink_mac_link_down,
+	.mac_link_up			= lan9645x_phylink_mac_link_up,
+};
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
new file mode 100644
index 00000000000000..407d7eb1d0640a
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_port.c
@@ -0,0 +1,226 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include <linux/of_net.h>
+
+#include "lan9645x_main.h"
+
+void lan9645x_port_cpu_init(struct lan9645x *lan9645x)
+{
+	/* Map the 8 CPU extraction queues to the CPU port module (datasheet is
+	 * wrong)
+	 */
+	lan_wr(0, lan9645x, QSYS_CPU_GROUP_MAP);
+
+	/* Set min-spacing of EOF to SOF on injected frames to 0, on cpu device
+	 * 1. This is required when injecting with IFH.
+	 * Default values emulates delay of std preamble/IFG setting on a front
+	 * port.
+	 */
+	lan_rmw(QS_INJ_CTRL_GAP_SIZE_SET(0),
+		QS_INJ_CTRL_GAP_SIZE,
+		lan9645x, QS_INJ_CTRL(1));
+
+	/* Injection: Mode: manual injection | Byte_swap */
+	lan_wr(QS_INJ_GRP_CFG_MODE_SET(1) |
+	       QS_INJ_GRP_CFG_BYTE_SWAP_SET(1),
+	       lan9645x, QS_INJ_GRP_CFG(1));
+
+	lan_rmw(QS_INJ_CTRL_GAP_SIZE_SET(0),
+		QS_INJ_CTRL_GAP_SIZE,
+		lan9645x, QS_INJ_CTRL(1));
+
+	lan_wr(SYS_PORT_MODE_INCL_INJ_HDR_SET(1),
+	       lan9645x, SYS_PORT_MODE(lan9645x->num_phys_ports + 1));
+
+	/* The CPU will only use its reserved buffer in the shared queue system
+	 * and none of the shared buffer space, therefore we disable resource
+	 * sharing in egress direction. We must not disable resource sharing in
+	 * the ingress direction, because some traffic test scenarios require
+	 * loads of buffer memory for frames initiated by the CPU.
+	 */
+	lan_rmw(QSYS_EGR_NO_SHARING_EGR_NO_SHARING_SET(BIT(lan9645x->num_phys_ports)),
+		QSYS_EGR_NO_SHARING_EGR_NO_SHARING_SET(BIT(lan9645x->num_phys_ports)),
+		lan9645x, QSYS_EGR_NO_SHARING);
+
+	/* The CPU should also discard frames forwarded to it if it has run
+	 * out of the reserved buffer space. Otherwise they will be held back
+	 * in the ingress queues with potential head-of-line blocking effects.
+	 */
+	lan_rmw(QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_SET(BIT(lan9645x->num_phys_ports)),
+		QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_SET(BIT(lan9645x->num_phys_ports)),
+		lan9645x, QSYS_EGR_DROP_MODE);
+
+	lan_wr(BIT(lan9645x->num_phys_ports), lan9645x, ANA_PGID(PGID_CPU));
+
+	lan_rmw(ANA_PORT_CFG_PORTID_VAL_SET(lan9645x->num_phys_ports) |
+		ANA_PORT_CFG_RECV_ENA_SET(1),
+		ANA_PORT_CFG_PORTID_VAL |
+		ANA_PORT_CFG_RECV_ENA, lan9645x,
+		ANA_PORT_CFG(lan9645x->num_phys_ports));
+
+	/* Enable switching to/from cpu port. Keep default aging-mode. */
+	lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1) |
+		QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(1) |
+		QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(1),
+		QSYS_SW_PORT_MODE_PORT_ENA |
+		QSYS_SW_PORT_MODE_SCH_NEXT_CFG |
+		QSYS_SW_PORT_MODE_INGRESS_DROP_MODE,
+		lan9645x, QSYS_SW_PORT_MODE(lan9645x->num_phys_ports));
+
+	/* Transmit cpu frames as received without any tagging, timing or other
+	 * updates. This does not affect CPU-over-NPI, only manual extraction.
+	 * On the NPI port we need NO_REWRITE=0 for HSR/PRP.
+	 */
+	lan_wr(REW_PORT_CFG_NO_REWRITE_SET(1),
+	       lan9645x, REW_PORT_CFG(lan9645x->num_phys_ports));
+}
+
+void lan9645x_port_set_tail_drop_wm(struct lan9645x *lan9645x)
+{
+	int shared_per_port;
+	struct dsa_port *dp;
+
+	/* Configure tail dropping watermark */
+	shared_per_port =
+		lan9645x->shared_queue_sz / (lan9645x->num_phys_ports + 1);
+
+	/* The total memory size is divided by number of front ports plus CPU
+	 * port.
+	 */
+	dsa_switch_for_each_available_port(dp, lan9645x->ds)
+		lan_wr(lan9645x_wm_enc(shared_per_port), lan9645x,
+		       SYS_ATOP(dp->index));
+
+	/* Tail dropping active based only on per port ATOP wm */
+	lan_wr(lan9645x_wm_enc(lan9645x->shared_queue_sz), lan9645x,
+	       SYS_ATOP_TOT_CFG);
+}
+
+/* VLAN tag overhead is handled by DEV_MAC_TAGS_CFG */
+int lan9645x_port_set_maxlen(struct lan9645x *lan9645x, int port, size_t sdu)
+{
+	struct lan9645x_port *p = lan9645x_to_port(lan9645x, port);
+	int maxlen = sdu + ETH_HLEN + ETH_FCS_LEN;
+
+	if (port == lan9645x->npi) {
+		maxlen += LAN9645X_IFH_LEN;
+		maxlen += LAN9645X_LONG_PREFIX_LEN;
+	}
+
+	lan_wr(DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(maxlen), lan9645x,
+	       DEV_MAC_MAXLEN_CFG(p->chip_port));
+
+	/* Set Pause WM hysteresis */
+	lan_rmw(SYS_PAUSE_CFG_PAUSE_STOP_SET(lan9645x_wm_enc(4 * maxlen)) |
+		SYS_PAUSE_CFG_PAUSE_START_SET(lan9645x_wm_enc(6 * maxlen)),
+		SYS_PAUSE_CFG_PAUSE_START |
+		SYS_PAUSE_CFG_PAUSE_STOP,
+		lan9645x,
+		SYS_PAUSE_CFG(p->chip_port));
+
+	return 0;
+}
+
+static void lan9645x_parse_mac_delay(struct lan9645x *lan9645x, int port,
+				     struct device_node *dn, const char *name,
+				     bool *out)
+{
+	u32 val;
+
+	if (of_property_read_u32(dn, name, &val))
+		return;
+
+	if (val != 0 && val != 2000) {
+		dev_warn(lan9645x->dev,
+			 "port %d: %s only supports a 2ns delay (on/off), got %u ps\n",
+			 port, name, val);
+		return;
+	}
+
+	*out = val == 2000;
+}
+
+int lan9645x_port_setup(struct dsa_switch *ds, int port)
+{
+	struct dsa_port *dp = dsa_to_port(ds, port);
+	struct lan9645x *lan9645x = ds->priv;
+	struct lan9645x_port *p;
+
+	p = lan9645x_to_port(lan9645x, port);
+
+	if (dp->dn) {
+		lan9645x_parse_mac_delay(lan9645x, port, dp->dn,
+					 "rx-internal-delay-ps",
+					 &p->rx_internal_delay);
+
+		lan9645x_parse_mac_delay(lan9645x, port, dp->dn,
+					 "tx-internal-delay-ps",
+					 &p->tx_internal_delay);
+	}
+
+	/* Disable learning on port */
+	lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(0),
+		ANA_PORT_CFG_LEARN_ENA,
+		lan9645x, ANA_PORT_CFG(p->chip_port));
+
+	lan9645x_port_set_maxlen(lan9645x, port, ETH_DATA_LEN);
+
+	/* Load HDX backoff seed (fixed per-port, one-shot strobe) */
+	lan_rmw(DEV_MAC_HDX_CFG_SEED_SET(p->chip_port) |
+		DEV_MAC_HDX_CFG_SEED_LOAD_SET(1),
+		DEV_MAC_HDX_CFG_SEED |
+		DEV_MAC_HDX_CFG_SEED_LOAD, lan9645x,
+		DEV_MAC_HDX_CFG(p->chip_port));
+
+	lan_rmw(DEV_MAC_HDX_CFG_SEED_LOAD_SET(0),
+		DEV_MAC_HDX_CFG_SEED_LOAD, lan9645x,
+		DEV_MAC_HDX_CFG(p->chip_port));
+
+	/* Set SMAC of Pause frame (00:00:00:00:00:00) */
+	lan_wr(0, lan9645x, DEV_FC_MAC_LOW_CFG(p->chip_port));
+	lan_wr(0, lan9645x, DEV_FC_MAC_HIGH_CFG(p->chip_port));
+
+	lan9645x_phylink_port_down(lan9645x, port);
+
+	/* Drop frames with multicast source address */
+	lan_rmw(ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(1),
+		ANA_DROP_CFG_DROP_MC_SMAC_ENA, lan9645x,
+		ANA_DROP_CFG(p->chip_port));
+
+	lan_rmw(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(1) |
+		DEV_MAC_TAGS_CFG_PB_ENA_SET(1) |
+		DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(1) |
+		DEV_MAC_TAGS_CFG_TAG_ID_SET(ETH_P_8021AD),
+		DEV_MAC_TAGS_CFG_VLAN_AWR_ENA |
+		DEV_MAC_TAGS_CFG_PB_ENA |
+		DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA |
+		DEV_MAC_TAGS_CFG_TAG_ID,
+		lan9645x, DEV_MAC_TAGS_CFG(p->chip_port));
+
+	/* Enable receiving frames on the port, and activate auto-learning of
+	 * MAC addresses. LEARNAUTO is ignored when LEARN_ENA=0.
+	 */
+	lan_rmw(ANA_PORT_CFG_LEARNAUTO_SET(1) |
+		ANA_PORT_CFG_RECV_ENA_SET(1) |
+		ANA_PORT_CFG_PORTID_VAL_SET(p->chip_port),
+		ANA_PORT_CFG_LEARNAUTO |
+		ANA_PORT_CFG_RECV_ENA |
+		ANA_PORT_CFG_PORTID_VAL,
+		lan9645x, ANA_PORT_CFG(p->chip_port));
+
+	if (p->chip_port != lan9645x->npi) {
+		lan9645x_vlan_set_hostmode(p);
+
+		lan_rmw(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_SET(true) |
+			ANA_CPU_FWD_CFG_MLD_REDIR_ENA_SET(true) |
+			ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_SET(true),
+			ANA_CPU_FWD_CFG_IGMP_REDIR_ENA |
+			ANA_CPU_FWD_CFG_MLD_REDIR_ENA |
+			ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA,
+			lan9645x, ANA_CPU_FWD_CFG(p->chip_port));
+	}
+
+	return 0;
+}
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_regs.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_regs.h
new file mode 100644
index 00000000000000..198c7aed87c121
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_regs.h
@@ -0,0 +1,1937 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright (c) 2026 Microchip Technology Inc.
+ */
+
+/* This file is autogenerated by cml-utils 2026-06-01 15:09:18 +0200.
+ * Commit ID: 1d14b97555bf4fa63fec33701c1aed00d0315013
+ */
+
+#ifndef _LAN9645X_REGS_H_
+#define _LAN9645X_REGS_H_
+
+#include <linux/bitfield.h>
+#include <linux/types.h>
+#include <linux/bug.h>
+
+enum lan9645x_target {
+	TARGET_AFI = 0,
+	TARGET_ANA = 1,
+	TARGET_CHIP_TOP = 2,
+	TARGET_DEV = 5,
+	TARGET_GCB = 16,
+	TARGET_HSIO = 17,
+	TARGET_QS = 26,
+	TARGET_QSYS = 27,
+	TARGET_REW = 28,
+	TARGET_SYS = 29,
+	NUM_TARGETS = 38
+};
+
+#define __REG(...)    __VA_ARGS__
+
+/*      AFI:PORT_TBL:PORT_FRM_OUT */
+#define AFI_PORT_FRM_OUT(g)       __REG(TARGET_AFI,\
+					0, 1, 6272, g, 11, 8, 0, 0, 1, 4)
+
+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT             GENMASK(26, 16)
+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT_SET(x)\
+	FIELD_PREP(AFI_PORT_FRM_OUT_FRM_OUT_CNT, x)
+#define AFI_PORT_FRM_OUT_FRM_OUT_CNT_GET(x)\
+	FIELD_GET(AFI_PORT_FRM_OUT_FRM_OUT_CNT, x)
+
+/*      AFI:PORT_TBL:PORT_CFG */
+#define AFI_PORT_CFG(g)           __REG(TARGET_AFI,\
+					0, 1, 6272, g, 11, 8, 4, 0, 1, 4)
+
+#define AFI_PORT_CFG_FRM_OUT_MAX                 GENMASK(9, 0)
+#define AFI_PORT_CFG_FRM_OUT_MAX_SET(x)\
+	FIELD_PREP(AFI_PORT_CFG_FRM_OUT_MAX, x)
+#define AFI_PORT_CFG_FRM_OUT_MAX_GET(x)\
+	FIELD_GET(AFI_PORT_CFG_FRM_OUT_MAX, x)
+
+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ             BIT(16)
+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ_SET(x)\
+	FIELD_PREP(AFI_PORT_CFG_FC_SKIP_TTI_INJ, x)
+#define AFI_PORT_CFG_FC_SKIP_TTI_INJ_GET(x)\
+	FIELD_GET(AFI_PORT_CFG_FC_SKIP_TTI_INJ, x)
+
+/*      ANA:ANA:ADVLEARN */
+#define ANA_ADVLEARN              __REG(TARGET_ANA,\
+					0, 1, 27136, 0, 1, 284, 0, 0, 1, 4)
+
+#define ANA_ADVLEARN_VLAN_CHK                    BIT(0)
+#define ANA_ADVLEARN_VLAN_CHK_SET(x)\
+	FIELD_PREP(ANA_ADVLEARN_VLAN_CHK, x)
+#define ANA_ADVLEARN_VLAN_CHK_GET(x)\
+	FIELD_GET(ANA_ADVLEARN_VLAN_CHK, x)
+
+/*      ANA:ANA:VLANMASK */
+#define ANA_VLANMASK              __REG(TARGET_ANA,\
+					0, 1, 27136, 0, 1, 284, 8, 0, 1, 4)
+
+#define ANA_VLANMASK_VLANMASK                    GENMASK(9, 0)
+#define ANA_VLANMASK_VLANMASK_SET(x)\
+	FIELD_PREP(ANA_VLANMASK_VLANMASK, x)
+#define ANA_VLANMASK_VLANMASK_GET(x)\
+	FIELD_GET(ANA_VLANMASK_VLANMASK, x)
+
+/*      ANA:ANA:ANAGEFIL */
+#define ANA_ANAGEFIL              __REG(TARGET_ANA,\
+					0, 1, 27136, 0, 1, 284, 12, 0, 1, 4)
+
+#define ANA_ANAGEFIL_AGE_LOCKED                  BIT(20)
+#define ANA_ANAGEFIL_AGE_LOCKED_SET(x)\
+	FIELD_PREP(ANA_ANAGEFIL_AGE_LOCKED, x)
+#define ANA_ANAGEFIL_AGE_LOCKED_GET(x)\
+	FIELD_GET(ANA_ANAGEFIL_AGE_LOCKED, x)
+
+#define ANA_ANAGEFIL_PID_EN                      BIT(19)
+#define ANA_ANAGEFIL_PID_EN_SET(x)\
+	FIELD_PREP(ANA_ANAGEFIL_PID_EN, x)
+#define ANA_ANAGEFIL_PID_EN_GET(x)\
+	FIELD_GET(ANA_ANAGEFIL_PID_EN, x)
+
+#define ANA_ANAGEFIL_PID_VAL                     GENMASK(18, 14)
+#define ANA_ANAGEFIL_PID_VAL_SET(x)\
+	FIELD_PREP(ANA_ANAGEFIL_PID_VAL, x)
+#define ANA_ANAGEFIL_PID_VAL_GET(x)\
+	FIELD_GET(ANA_ANAGEFIL_PID_VAL, x)
+
+#define ANA_ANAGEFIL_VID_EN                      BIT(13)
+#define ANA_ANAGEFIL_VID_EN_SET(x)\
+	FIELD_PREP(ANA_ANAGEFIL_VID_EN, x)
+#define ANA_ANAGEFIL_VID_EN_GET(x)\
+	FIELD_GET(ANA_ANAGEFIL_VID_EN, x)
+
+#define ANA_ANAGEFIL_VID_VAL                     GENMASK(12, 0)
+#define ANA_ANAGEFIL_VID_VAL_SET(x)\
+	FIELD_PREP(ANA_ANAGEFIL_VID_VAL, x)
+#define ANA_ANAGEFIL_VID_VAL_GET(x)\
+	FIELD_GET(ANA_ANAGEFIL_VID_VAL, x)
+
+/*      ANA:ANA:AUTOAGE */
+#define ANA_AUTOAGE               __REG(TARGET_ANA,\
+					0, 1, 27136, 0, 1, 284, 44, 0, 1, 4)
+
+#define ANA_AUTOAGE_AGE_FAST                     BIT(21)
+#define ANA_AUTOAGE_AGE_FAST_SET(x)\
+	FIELD_PREP(ANA_AUTOAGE_AGE_FAST, x)
+#define ANA_AUTOAGE_AGE_FAST_GET(x)\
+	FIELD_GET(ANA_AUTOAGE_AGE_FAST, x)
+
+#define ANA_AUTOAGE_AGE_PERIOD                   GENMASK(20, 1)
+#define ANA_AUTOAGE_AGE_PERIOD_SET(x)\
+	FIELD_PREP(ANA_AUTOAGE_AGE_PERIOD, x)
+#define ANA_AUTOAGE_AGE_PERIOD_GET(x)\
+	FIELD_GET(ANA_AUTOAGE_AGE_PERIOD, x)
+
+#define ANA_AUTOAGE_AUTOAGE_LOCKED               BIT(0)
+#define ANA_AUTOAGE_AUTOAGE_LOCKED_SET(x)\
+	FIELD_PREP(ANA_AUTOAGE_AUTOAGE_LOCKED, x)
+#define ANA_AUTOAGE_AUTOAGE_LOCKED_GET(x)\
+	FIELD_GET(ANA_AUTOAGE_AUTOAGE_LOCKED, x)
+
+/*      ANA:ANA:FLOODING */
+#define ANA_FLOODING(r)           __REG(TARGET_ANA,\
+					0, 1, 27136, 0, 1, 284, 68, r, 8, 4)
+
+#define ANA_FLOODING_FLD_UNICAST                 GENMASK(17, 12)
+#define ANA_FLOODING_FLD_UNICAST_SET(x)\
+	FIELD_PREP(ANA_FLOODING_FLD_UNICAST, x)
+#define ANA_FLOODING_FLD_UNICAST_GET(x)\
+	FIELD_GET(ANA_FLOODING_FLD_UNICAST, x)
+
+#define ANA_FLOODING_FLD_BROADCAST               GENMASK(11, 6)
+#define ANA_FLOODING_FLD_BROADCAST_SET(x)\
+	FIELD_PREP(ANA_FLOODING_FLD_BROADCAST, x)
+#define ANA_FLOODING_FLD_BROADCAST_GET(x)\
+	FIELD_GET(ANA_FLOODING_FLD_BROADCAST, x)
+
+#define ANA_FLOODING_FLD_MULTICAST               GENMASK(5, 0)
+#define ANA_FLOODING_FLD_MULTICAST_SET(x)\
+	FIELD_PREP(ANA_FLOODING_FLD_MULTICAST, x)
+#define ANA_FLOODING_FLD_MULTICAST_GET(x)\
+	FIELD_GET(ANA_FLOODING_FLD_MULTICAST, x)
+
+/*      ANA:ANA:FLOODING_IPMC */
+#define ANA_FLOODING_IPMC         __REG(TARGET_ANA,\
+					0, 1, 27136, 0, 1, 284, 100, 0, 1, 4)
+
+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL           GENMASK(23, 18)
+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC4_CTRL, x)
+#define ANA_FLOODING_IPMC_FLD_MC4_CTRL_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC4_CTRL, x)
+
+#define ANA_FLOODING_IPMC_FLD_MC4_DATA           GENMASK(17, 12)
+#define ANA_FLOODING_IPMC_FLD_MC4_DATA_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC4_DATA, x)
+#define ANA_FLOODING_IPMC_FLD_MC4_DATA_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC4_DATA, x)
+
+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL           GENMASK(11, 6)
+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC6_CTRL, x)
+#define ANA_FLOODING_IPMC_FLD_MC6_CTRL_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC6_CTRL, x)
+
+#define ANA_FLOODING_IPMC_FLD_MC6_DATA           GENMASK(5, 0)
+#define ANA_FLOODING_IPMC_FLD_MC6_DATA_SET(x)\
+	FIELD_PREP(ANA_FLOODING_IPMC_FLD_MC6_DATA, x)
+#define ANA_FLOODING_IPMC_FLD_MC6_DATA_GET(x)\
+	FIELD_GET(ANA_FLOODING_IPMC_FLD_MC6_DATA, x)
+
+/*      ANA:PGID:PGID */
+#define ANA_PGID(g)               __REG(TARGET_ANA,\
+					0, 1, 27648, g, 90, 8, 0, 0, 1, 4)
+
+#define ANA_PGID_PGID                            GENMASK(9, 0)
+#define ANA_PGID_PGID_SET(x)\
+	FIELD_PREP(ANA_PGID_PGID, x)
+#define ANA_PGID_PGID_GET(x)\
+	FIELD_GET(ANA_PGID_PGID, x)
+
+/*      ANA:PGID:PGID_CFG */
+#define ANA_PGID_CFG(g)           __REG(TARGET_ANA,\
+					0, 1, 27648, g, 90, 8, 4, 0, 1, 4)
+
+#define ANA_PGID_CFG_SAN_ENA                     BIT(4)
+#define ANA_PGID_CFG_SAN_ENA_SET(x)\
+	FIELD_PREP(ANA_PGID_CFG_SAN_ENA, x)
+#define ANA_PGID_CFG_SAN_ENA_GET(x)\
+	FIELD_GET(ANA_PGID_CFG_SAN_ENA, x)
+
+#define ANA_PGID_CFG_CPUQ_DST_PGID               GENMASK(3, 1)
+#define ANA_PGID_CFG_CPUQ_DST_PGID_SET(x)\
+	FIELD_PREP(ANA_PGID_CFG_CPUQ_DST_PGID, x)
+#define ANA_PGID_CFG_CPUQ_DST_PGID_GET(x)\
+	FIELD_GET(ANA_PGID_CFG_CPUQ_DST_PGID, x)
+
+#define ANA_PGID_CFG_OBEY_VLAN                   BIT(0)
+#define ANA_PGID_CFG_OBEY_VLAN_SET(x)\
+	FIELD_PREP(ANA_PGID_CFG_OBEY_VLAN, x)
+#define ANA_PGID_CFG_OBEY_VLAN_GET(x)\
+	FIELD_GET(ANA_PGID_CFG_OBEY_VLAN, x)
+
+/*      ANA:ANA_TABLES:MACHDATA */
+#define ANA_MACHDATA              __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 44, 0, 1, 4)
+
+#define ANA_MACHDATA_VID                         GENMASK(28, 16)
+#define ANA_MACHDATA_VID_SET(x)\
+	FIELD_PREP(ANA_MACHDATA_VID, x)
+#define ANA_MACHDATA_VID_GET(x)\
+	FIELD_GET(ANA_MACHDATA_VID, x)
+
+#define ANA_MACHDATA_MACHDATA                    GENMASK(15, 0)
+#define ANA_MACHDATA_MACHDATA_SET(x)\
+	FIELD_PREP(ANA_MACHDATA_MACHDATA, x)
+#define ANA_MACHDATA_MACHDATA_GET(x)\
+	FIELD_GET(ANA_MACHDATA_MACHDATA, x)
+
+/*      ANA:ANA_TABLES:MACLDATA */
+#define ANA_MACLDATA              __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 48, 0, 1, 4)
+
+/*      ANA:ANA_TABLES:MACACCESS */
+#define ANA_MACACCESS             __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 52, 0, 1, 4)
+
+#define ANA_MACACCESS_CHANGE2SW                  BIT(17)
+#define ANA_MACACCESS_CHANGE2SW_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_CHANGE2SW, x)
+#define ANA_MACACCESS_CHANGE2SW_GET(x)\
+	FIELD_GET(ANA_MACACCESS_CHANGE2SW, x)
+
+#define ANA_MACACCESS_MAC_CPU_COPY               BIT(16)
+#define ANA_MACACCESS_MAC_CPU_COPY_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_MAC_CPU_COPY, x)
+#define ANA_MACACCESS_MAC_CPU_COPY_GET(x)\
+	FIELD_GET(ANA_MACACCESS_MAC_CPU_COPY, x)
+
+#define ANA_MACACCESS_SRC_KILL                   BIT(15)
+#define ANA_MACACCESS_SRC_KILL_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_SRC_KILL, x)
+#define ANA_MACACCESS_SRC_KILL_GET(x)\
+	FIELD_GET(ANA_MACACCESS_SRC_KILL, x)
+
+#define ANA_MACACCESS_IGNORE_VLAN                BIT(14)
+#define ANA_MACACCESS_IGNORE_VLAN_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_IGNORE_VLAN, x)
+#define ANA_MACACCESS_IGNORE_VLAN_GET(x)\
+	FIELD_GET(ANA_MACACCESS_IGNORE_VLAN, x)
+
+#define ANA_MACACCESS_AGED_FLAG                  BIT(13)
+#define ANA_MACACCESS_AGED_FLAG_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_AGED_FLAG, x)
+#define ANA_MACACCESS_AGED_FLAG_GET(x)\
+	FIELD_GET(ANA_MACACCESS_AGED_FLAG, x)
+
+#define ANA_MACACCESS_VALID                      BIT(12)
+#define ANA_MACACCESS_VALID_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_VALID, x)
+#define ANA_MACACCESS_VALID_GET(x)\
+	FIELD_GET(ANA_MACACCESS_VALID, x)
+
+#define ANA_MACACCESS_ENTRYTYPE                  GENMASK(11, 10)
+#define ANA_MACACCESS_ENTRYTYPE_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_ENTRYTYPE, x)
+#define ANA_MACACCESS_ENTRYTYPE_GET(x)\
+	FIELD_GET(ANA_MACACCESS_ENTRYTYPE, x)
+
+#define ANA_MACACCESS_DEST_IDX                   GENMASK(9, 4)
+#define ANA_MACACCESS_DEST_IDX_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_DEST_IDX, x)
+#define ANA_MACACCESS_DEST_IDX_GET(x)\
+	FIELD_GET(ANA_MACACCESS_DEST_IDX, x)
+
+#define ANA_MACACCESS_MAC_TABLE_CMD              GENMASK(3, 0)
+#define ANA_MACACCESS_MAC_TABLE_CMD_SET(x)\
+	FIELD_PREP(ANA_MACACCESS_MAC_TABLE_CMD, x)
+#define ANA_MACACCESS_MAC_TABLE_CMD_GET(x)\
+	FIELD_GET(ANA_MACACCESS_MAC_TABLE_CMD, x)
+
+/*      ANA:ANA_TABLES:MACTINDX */
+#define ANA_MACTINDX              __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 56, 0, 1, 4)
+
+#define ANA_MACTINDX_BUCKET                      GENMASK(12, 11)
+#define ANA_MACTINDX_BUCKET_SET(x)\
+	FIELD_PREP(ANA_MACTINDX_BUCKET, x)
+#define ANA_MACTINDX_BUCKET_GET(x)\
+	FIELD_GET(ANA_MACTINDX_BUCKET, x)
+
+#define ANA_MACTINDX_M_INDEX                     GENMASK(10, 0)
+#define ANA_MACTINDX_M_INDEX_SET(x)\
+	FIELD_PREP(ANA_MACTINDX_M_INDEX, x)
+#define ANA_MACTINDX_M_INDEX_GET(x)\
+	FIELD_GET(ANA_MACTINDX_M_INDEX, x)
+
+/*      ANA:ANA_TABLES:VLAN_PORT_MASK */
+#define ANA_VLAN_PORT_MASK        __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 60, 0, 1, 4)
+
+#define ANA_VLAN_PORT_MASK_VLAN_PORT_MASK        GENMASK(9, 0)
+#define ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(x)\
+	FIELD_PREP(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK, x)
+#define ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_GET(x)\
+	FIELD_GET(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK, x)
+
+/*      ANA:ANA_TABLES:VLANACCESS */
+#define ANA_VLANACCESS            __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 64, 0, 1, 4)
+
+#define ANA_VLANACCESS_VLAN_TBL_CMD              GENMASK(1, 0)
+#define ANA_VLANACCESS_VLAN_TBL_CMD_SET(x)\
+	FIELD_PREP(ANA_VLANACCESS_VLAN_TBL_CMD, x)
+#define ANA_VLANACCESS_VLAN_TBL_CMD_GET(x)\
+	FIELD_GET(ANA_VLANACCESS_VLAN_TBL_CMD, x)
+
+/*      ANA:ANA_TABLES:VLANTIDX */
+#define ANA_VLANTIDX              __REG(TARGET_ANA,\
+					0, 1, 23680, 0, 1, 128, 68, 0, 1, 4)
+
+#define ANA_VLANTIDX_VLAN_PGID_CPU_DIS           BIT(18)
+#define ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_PGID_CPU_DIS, x)
+#define ANA_VLANTIDX_VLAN_PGID_CPU_DIS_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_PGID_CPU_DIS, x)
+
+#define ANA_VLANTIDX_VLAN_SEC_FWD_ENA            BIT(17)
+#define ANA_VLANTIDX_VLAN_SEC_FWD_ENA_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_SEC_FWD_ENA, x)
+#define ANA_VLANTIDX_VLAN_SEC_FWD_ENA_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_SEC_FWD_ENA, x)
+
+#define ANA_VLANTIDX_VLAN_FLOOD_DIS              BIT(16)
+#define ANA_VLANTIDX_VLAN_FLOOD_DIS_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_FLOOD_DIS, x)
+#define ANA_VLANTIDX_VLAN_FLOOD_DIS_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_FLOOD_DIS, x)
+
+#define ANA_VLANTIDX_VLAN_PRIV_VLAN              BIT(15)
+#define ANA_VLANTIDX_VLAN_PRIV_VLAN_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_PRIV_VLAN, x)
+#define ANA_VLANTIDX_VLAN_PRIV_VLAN_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_PRIV_VLAN, x)
+
+#define ANA_VLANTIDX_VLAN_LEARN_DISABLED         BIT(14)
+#define ANA_VLANTIDX_VLAN_LEARN_DISABLED_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_LEARN_DISABLED, x)
+#define ANA_VLANTIDX_VLAN_LEARN_DISABLED_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_LEARN_DISABLED, x)
+
+#define ANA_VLANTIDX_VLAN_MIRROR                 BIT(13)
+#define ANA_VLANTIDX_VLAN_MIRROR_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_MIRROR, x)
+#define ANA_VLANTIDX_VLAN_MIRROR_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_MIRROR, x)
+
+#define ANA_VLANTIDX_VLAN_SRC_CHK                BIT(12)
+#define ANA_VLANTIDX_VLAN_SRC_CHK_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_VLAN_SRC_CHK, x)
+#define ANA_VLANTIDX_VLAN_SRC_CHK_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_VLAN_SRC_CHK, x)
+
+#define ANA_VLANTIDX_V_INDEX                     GENMASK(11, 0)
+#define ANA_VLANTIDX_V_INDEX_SET(x)\
+	FIELD_PREP(ANA_VLANTIDX_V_INDEX, x)
+#define ANA_VLANTIDX_V_INDEX_GET(x)\
+	FIELD_GET(ANA_VLANTIDX_V_INDEX, x)
+
+/*      ANA:PORT:VLAN_CFG */
+#define ANA_VLAN_CFG(g)           __REG(TARGET_ANA,\
+					0, 1, 24576, g, 10, 256, 0, 0, 1, 4)
+
+#define ANA_VLAN_CFG_VLAN_PFC_ENA                BIT(21)
+#define ANA_VLAN_CFG_VLAN_PFC_ENA_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_PFC_ENA, x)
+#define ANA_VLAN_CFG_VLAN_PFC_ENA_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_PFC_ENA, x)
+
+#define ANA_VLAN_CFG_VLAN_AWARE_ENA              BIT(20)
+#define ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_AWARE_ENA, x)
+#define ANA_VLAN_CFG_VLAN_AWARE_ENA_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_AWARE_ENA, x)
+
+#define ANA_VLAN_CFG_VLAN_POP_CNT                GENMASK(19, 18)
+#define ANA_VLAN_CFG_VLAN_POP_CNT_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_POP_CNT, x)
+#define ANA_VLAN_CFG_VLAN_POP_CNT_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_POP_CNT, x)
+
+#define ANA_VLAN_CFG_VLAN_INNER_TAG_ENA          BIT(17)
+#define ANA_VLAN_CFG_VLAN_INNER_TAG_ENA_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_INNER_TAG_ENA, x)
+#define ANA_VLAN_CFG_VLAN_INNER_TAG_ENA_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_INNER_TAG_ENA, x)
+
+#define ANA_VLAN_CFG_VLAN_TAG_TYPE               BIT(16)
+#define ANA_VLAN_CFG_VLAN_TAG_TYPE_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_TAG_TYPE, x)
+#define ANA_VLAN_CFG_VLAN_TAG_TYPE_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_TAG_TYPE, x)
+
+#define ANA_VLAN_CFG_VLAN_PCP                    GENMASK(15, 13)
+#define ANA_VLAN_CFG_VLAN_PCP_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_PCP, x)
+#define ANA_VLAN_CFG_VLAN_PCP_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_PCP, x)
+
+#define ANA_VLAN_CFG_VLAN_DEI                    BIT(12)
+#define ANA_VLAN_CFG_VLAN_DEI_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_DEI, x)
+#define ANA_VLAN_CFG_VLAN_DEI_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_DEI, x)
+
+#define ANA_VLAN_CFG_VLAN_VID                    GENMASK(11, 0)
+#define ANA_VLAN_CFG_VLAN_VID_SET(x)\
+	FIELD_PREP(ANA_VLAN_CFG_VLAN_VID, x)
+#define ANA_VLAN_CFG_VLAN_VID_GET(x)\
+	FIELD_GET(ANA_VLAN_CFG_VLAN_VID, x)
+
+/*      ANA:PORT:DROP_CFG */
+#define ANA_DROP_CFG(g)           __REG(TARGET_ANA,\
+					0, 1, 24576, g, 10, 256, 4, 0, 1, 4)
+
+#define ANA_DROP_CFG_DROP_UNTAGGED_ENA           BIT(6)
+#define ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_UNTAGGED_ENA, x)
+#define ANA_DROP_CFG_DROP_UNTAGGED_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_UNTAGGED_ENA, x)
+
+#define ANA_DROP_CFG_DROP_S_TAGGED_ENA           BIT(5)
+#define ANA_DROP_CFG_DROP_S_TAGGED_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_S_TAGGED_ENA, x)
+#define ANA_DROP_CFG_DROP_S_TAGGED_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_S_TAGGED_ENA, x)
+
+#define ANA_DROP_CFG_DROP_C_TAGGED_ENA           BIT(4)
+#define ANA_DROP_CFG_DROP_C_TAGGED_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_C_TAGGED_ENA, x)
+#define ANA_DROP_CFG_DROP_C_TAGGED_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_C_TAGGED_ENA, x)
+
+#define ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA      BIT(3)
+#define ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA, x)
+#define ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA, x)
+
+#define ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA      BIT(2)
+#define ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, x)
+#define ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA, x)
+
+#define ANA_DROP_CFG_DROP_NULL_MAC_ENA           BIT(1)
+#define ANA_DROP_CFG_DROP_NULL_MAC_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_NULL_MAC_ENA, x)
+#define ANA_DROP_CFG_DROP_NULL_MAC_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_NULL_MAC_ENA, x)
+
+#define ANA_DROP_CFG_DROP_MC_SMAC_ENA            BIT(0)
+#define ANA_DROP_CFG_DROP_MC_SMAC_ENA_SET(x)\
+	FIELD_PREP(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x)
+#define ANA_DROP_CFG_DROP_MC_SMAC_ENA_GET(x)\
+	FIELD_GET(ANA_DROP_CFG_DROP_MC_SMAC_ENA, x)
+
+/*      ANA:PORT:CPU_FWD_CFG */
+#define ANA_CPU_FWD_CFG(g)        __REG(TARGET_ANA,\
+					0, 1, 24576, g, 10, 256, 96, 0, 1, 4)
+
+#define ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA         BIT(9)
+#define ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA, x)
+#define ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_NO_HSR_REDIR_ENA, x)
+
+#define ANA_CPU_FWD_CFG_SPV_COPY_ENA             BIT(8)
+#define ANA_CPU_FWD_CFG_SPV_COPY_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_SPV_COPY_ENA, x)
+#define ANA_CPU_FWD_CFG_SPV_COPY_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_SPV_COPY_ENA, x)
+
+#define ANA_CPU_FWD_CFG_VRAP_REDIR_ENA           BIT(7)
+#define ANA_CPU_FWD_CFG_VRAP_REDIR_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_VRAP_REDIR_ENA, x)
+#define ANA_CPU_FWD_CFG_VRAP_REDIR_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_VRAP_REDIR_ENA, x)
+
+#define ANA_CPU_FWD_CFG_MLD_REDIR_ENA            BIT(6)
+#define ANA_CPU_FWD_CFG_MLD_REDIR_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_MLD_REDIR_ENA, x)
+#define ANA_CPU_FWD_CFG_MLD_REDIR_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_MLD_REDIR_ENA, x)
+
+#define ANA_CPU_FWD_CFG_IGMP_REDIR_ENA           BIT(5)
+#define ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA, x)
+#define ANA_CPU_FWD_CFG_IGMP_REDIR_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_IGMP_REDIR_ENA, x)
+
+#define ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA       BIT(4)
+#define ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA, x)
+#define ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_IPMC_CTRL_COPY_ENA, x)
+
+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA             BIT(3)
+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_SRC_COPY_ENA, x)
+#define ANA_CPU_FWD_CFG_SRC_COPY_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_SRC_COPY_ENA, x)
+
+#define ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA       BIT(2)
+#define ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA, x)
+#define ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_ALLBRIDGE_DROP_ENA, x)
+
+#define ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA      BIT(1)
+#define ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA, x)
+#define ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_ALLBRIDGE_REDIR_ENA, x)
+
+#define ANA_CPU_FWD_CFG_OAM_ENA                  BIT(0)
+#define ANA_CPU_FWD_CFG_OAM_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_CFG_OAM_ENA, x)
+#define ANA_CPU_FWD_CFG_OAM_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_CFG_OAM_ENA, x)
+
+/*      ANA:PORT:CPU_FWD_BPDU_CFG */
+#define ANA_CPU_FWD_BPDU_CFG(g)   __REG(TARGET_ANA,\
+					0, 1, 24576, g, 10, 256, 100, 0, 1, 4)
+
+#define ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA       GENMASK(31, 16)
+#define ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA, x)
+#define ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_BPDU_CFG_BPDU_DROP_ENA, x)
+
+#define ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA      GENMASK(15, 0)
+#define ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_SET(x)\
+	FIELD_PREP(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA, x)
+#define ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA_GET(x)\
+	FIELD_GET(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA, x)
+
+/*      ANA:PORT:PORT_CFG */
+#define ANA_PORT_CFG(g)           __REG(TARGET_ANA,\
+					0, 1, 24576, g, 10, 256, 112, 0, 1, 4)
+
+#define ANA_PORT_CFG_SRC_MIRROR_ENA              BIT(13)
+#define ANA_PORT_CFG_SRC_MIRROR_ENA_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_SRC_MIRROR_ENA, x)
+#define ANA_PORT_CFG_SRC_MIRROR_ENA_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_SRC_MIRROR_ENA, x)
+
+#define ANA_PORT_CFG_LIMIT_DROP                  BIT(12)
+#define ANA_PORT_CFG_LIMIT_DROP_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LIMIT_DROP, x)
+#define ANA_PORT_CFG_LIMIT_DROP_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LIMIT_DROP, x)
+
+#define ANA_PORT_CFG_LIMIT_CPU                   BIT(11)
+#define ANA_PORT_CFG_LIMIT_CPU_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LIMIT_CPU, x)
+#define ANA_PORT_CFG_LIMIT_CPU_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LIMIT_CPU, x)
+
+#define ANA_PORT_CFG_LOCKED_PORTMOVE_DROP        BIT(10)
+#define ANA_PORT_CFG_LOCKED_PORTMOVE_DROP_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LOCKED_PORTMOVE_DROP, x)
+#define ANA_PORT_CFG_LOCKED_PORTMOVE_DROP_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LOCKED_PORTMOVE_DROP, x)
+
+#define ANA_PORT_CFG_LOCKED_PORTMOVE_CPU         BIT(9)
+#define ANA_PORT_CFG_LOCKED_PORTMOVE_CPU_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LOCKED_PORTMOVE_CPU, x)
+#define ANA_PORT_CFG_LOCKED_PORTMOVE_CPU_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LOCKED_PORTMOVE_CPU, x)
+
+#define ANA_PORT_CFG_LEARNDROP                   BIT(8)
+#define ANA_PORT_CFG_LEARNDROP_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LEARNDROP, x)
+#define ANA_PORT_CFG_LEARNDROP_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LEARNDROP, x)
+
+#define ANA_PORT_CFG_LEARNCPU                    BIT(7)
+#define ANA_PORT_CFG_LEARNCPU_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LEARNCPU, x)
+#define ANA_PORT_CFG_LEARNCPU_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LEARNCPU, x)
+
+#define ANA_PORT_CFG_LEARNAUTO                   BIT(6)
+#define ANA_PORT_CFG_LEARNAUTO_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LEARNAUTO, x)
+#define ANA_PORT_CFG_LEARNAUTO_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LEARNAUTO, x)
+
+#define ANA_PORT_CFG_LEARN_ENA                   BIT(5)
+#define ANA_PORT_CFG_LEARN_ENA_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_LEARN_ENA, x)
+#define ANA_PORT_CFG_LEARN_ENA_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_LEARN_ENA, x)
+
+#define ANA_PORT_CFG_RECV_ENA                    BIT(4)
+#define ANA_PORT_CFG_RECV_ENA_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_RECV_ENA, x)
+#define ANA_PORT_CFG_RECV_ENA_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_RECV_ENA, x)
+
+#define ANA_PORT_CFG_PORTID_VAL                  GENMASK(3, 0)
+#define ANA_PORT_CFG_PORTID_VAL_SET(x)\
+	FIELD_PREP(ANA_PORT_CFG_PORTID_VAL, x)
+#define ANA_PORT_CFG_PORTID_VAL_GET(x)\
+	FIELD_GET(ANA_PORT_CFG_PORTID_VAL, x)
+
+/*      ANA:PFC:PFC_CFG */
+#define ANA_PFC_CFG(g)            __REG(TARGET_ANA,\
+					0, 1, 28672, g, 9, 64, 0, 0, 1, 4)
+
+#define ANA_PFC_CFG_RX_PFC_ENA                   GENMASK(9, 2)
+#define ANA_PFC_CFG_RX_PFC_ENA_SET(x)\
+	FIELD_PREP(ANA_PFC_CFG_RX_PFC_ENA, x)
+#define ANA_PFC_CFG_RX_PFC_ENA_GET(x)\
+	FIELD_GET(ANA_PFC_CFG_RX_PFC_ENA, x)
+
+#define ANA_PFC_CFG_FC_LINK_SPEED                GENMASK(1, 0)
+#define ANA_PFC_CFG_FC_LINK_SPEED_SET(x)\
+	FIELD_PREP(ANA_PFC_CFG_FC_LINK_SPEED, x)
+#define ANA_PFC_CFG_FC_LINK_SPEED_GET(x)\
+	FIELD_GET(ANA_PFC_CFG_FC_LINK_SPEED, x)
+
+/*      ANA:COMMON:AGGR_CFG */
+#define ANA_AGGR_CFG              __REG(TARGET_ANA,\
+					0, 1, 29248, 0, 1, 552, 0, 0, 1, 4)
+
+#define ANA_AGGR_CFG_AC_RND_ENA                  BIT(6)
+#define ANA_AGGR_CFG_AC_RND_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_RND_ENA, x)
+#define ANA_AGGR_CFG_AC_RND_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_RND_ENA, x)
+
+#define ANA_AGGR_CFG_AC_DMAC_ENA                 BIT(5)
+#define ANA_AGGR_CFG_AC_DMAC_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_DMAC_ENA, x)
+#define ANA_AGGR_CFG_AC_DMAC_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_DMAC_ENA, x)
+
+#define ANA_AGGR_CFG_AC_SMAC_ENA                 BIT(4)
+#define ANA_AGGR_CFG_AC_SMAC_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_SMAC_ENA, x)
+#define ANA_AGGR_CFG_AC_SMAC_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_SMAC_ENA, x)
+
+#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA         BIT(3)
+#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA, x)
+#define ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_IP6_FLOW_LBL_ENA, x)
+
+#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA           BIT(2)
+#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA, x)
+#define ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_IP6_TCPUDP_ENA, x)
+
+#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA           BIT(1)
+#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA, x)
+#define ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_IP4_SIPDIP_ENA, x)
+
+#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA           BIT(0)
+#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_SET(x)\
+	FIELD_PREP(ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, x)
+#define ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA_GET(x)\
+	FIELD_GET(ANA_AGGR_CFG_AC_IP4_TCPUDP_ENA, x)
+
+/*      ANA:COMMON:CPUQ_CFG */
+#define ANA_CPUQ_CFG              __REG(TARGET_ANA,\
+					0, 1, 29248, 0, 1, 552, 4, 0, 1, 4)
+
+#define ANA_CPUQ_CFG_CPUQ_MLD                    GENMASK(29, 27)
+#define ANA_CPUQ_CFG_CPUQ_MLD_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_MLD, x)
+#define ANA_CPUQ_CFG_CPUQ_MLD_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_MLD, x)
+
+#define ANA_CPUQ_CFG_CPUQ_IGMP                   GENMASK(26, 24)
+#define ANA_CPUQ_CFG_CPUQ_IGMP_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_IGMP, x)
+#define ANA_CPUQ_CFG_CPUQ_IGMP_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_IGMP, x)
+
+#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL              GENMASK(23, 21)
+#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_IPMC_CTRL, x)
+#define ANA_CPUQ_CFG_CPUQ_IPMC_CTRL_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_IPMC_CTRL, x)
+
+#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE              GENMASK(20, 18)
+#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_ALLBRIDGE, x)
+#define ANA_CPUQ_CFG_CPUQ_ALLBRIDGE_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_ALLBRIDGE, x)
+
+#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE        GENMASK(17, 15)
+#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE, x)
+#define ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_LOCKED_PORTMOVE, x)
+
+#define ANA_CPUQ_CFG_CPUQ_SRC_COPY               GENMASK(14, 12)
+#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_SRC_COPY, x)
+#define ANA_CPUQ_CFG_CPUQ_SRC_COPY_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_SRC_COPY, x)
+
+#define ANA_CPUQ_CFG_CPUQ_MAC_COPY               GENMASK(11, 9)
+#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_MAC_COPY, x)
+#define ANA_CPUQ_CFG_CPUQ_MAC_COPY_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_MAC_COPY, x)
+
+#define ANA_CPUQ_CFG_CPUQ_LRN                    GENMASK(8, 6)
+#define ANA_CPUQ_CFG_CPUQ_LRN_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_LRN, x)
+#define ANA_CPUQ_CFG_CPUQ_LRN_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_LRN, x)
+
+#define ANA_CPUQ_CFG_CPUQ_MIRROR                 GENMASK(5, 3)
+#define ANA_CPUQ_CFG_CPUQ_MIRROR_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_MIRROR, x)
+#define ANA_CPUQ_CFG_CPUQ_MIRROR_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_MIRROR, x)
+
+#define ANA_CPUQ_CFG_CPUQ_SFLOW                  GENMASK(2, 0)
+#define ANA_CPUQ_CFG_CPUQ_SFLOW_SET(x)\
+	FIELD_PREP(ANA_CPUQ_CFG_CPUQ_SFLOW, x)
+#define ANA_CPUQ_CFG_CPUQ_SFLOW_GET(x)\
+	FIELD_GET(ANA_CPUQ_CFG_CPUQ_SFLOW, x)
+
+/*      ANA:COMMON:CPUQ_8021_CFG */
+#define ANA_CPUQ_8021_CFG(r)      __REG(TARGET_ANA,\
+					0, 1, 29248, 0, 1, 552, 12, r, 16, 4)
+
+#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL          GENMASK(8, 6)
+#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_SET(x)\
+	FIELD_PREP(ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL, x)
+#define ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL_GET(x)\
+	FIELD_GET(ANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL, x)
+
+#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL          GENMASK(5, 3)
+#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_SET(x)\
+	FIELD_PREP(ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL, x)
+#define ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL_GET(x)\
+	FIELD_GET(ANA_CPUQ_8021_CFG_CPUQ_GARP_VAL, x)
+
+#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL           GENMASK(2, 0)
+#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_SET(x)\
+	FIELD_PREP(ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL, x)
+#define ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL_GET(x)\
+	FIELD_GET(ANA_CPUQ_8021_CFG_CPUQ_CCM_VAL, x)
+
+/*      CHIP_TOP:CUPHY_CFG:CUPHY_PORT_CFG */
+#define CHIP_TOP_CUPHY_PORT_CFG(r) __REG(TARGET_CHIP_TOP,\
+					0, 1, 12, 0, 1, 64, 20, r, 5, 4)
+
+#define CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA BIT(7)
+#define CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA, x)
+#define CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_AUTO_SQUELCH_ENA, x)
+
+#define CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE        BIT(6)
+#define CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE, x)
+#define CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_COMA_MODE, x)
+
+#define CHIP_TOP_CUPHY_PORT_CFG_MODE             GENMASK(5, 1)
+#define CHIP_TOP_CUPHY_PORT_CFG_MODE_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_MODE, x)
+#define CHIP_TOP_CUPHY_PORT_CFG_MODE_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_MODE, x)
+
+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA      BIT(0)
+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, x)
+#define CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_PORT_CFG_GTX_CLK_ENA, x)
+
+/*      CHIP_TOP:CUPHY_CFG:CUPHY_LED_CFG */
+#define CHIP_TOP_CUPHY_LED_CFG(r) __REG(TARGET_CHIP_TOP,\
+					0, 1, 12, 0, 1, 64, 40, r, 5, 4)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS       BIT(11)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_ECO_DIS, x)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE      BIT(10)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_EEE_MODE, x)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE     GENMASK(9, 8)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_MODE, x)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL      GENMASK(7, 6)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_TEST_VAL, x)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY      GENMASK(5, 4)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_POLARITY, x)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE    GENMASK(3, 2)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_DRIVE_MODE, x)
+
+#define CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE    GENMASK(1, 0)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE_SET(x)\
+	FIELD_PREP(CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE, x)
+#define CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE_GET(x)\
+	FIELD_GET(CHIP_TOP_CUPHY_LED_CFG_LED_BLINK_MODE, x)
+
+/*      DEV:PORT_MODE:CLOCK_CFG */
+#define DEV_CLOCK_CFG(t)          __REG(TARGET_DEV,\
+					t, 9, 0, 0, 1, 20, 0, 0, 1, 4)
+
+#define DEV_CLOCK_CFG_MAC_TX_RST                 BIT(7)
+#define DEV_CLOCK_CFG_MAC_TX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_MAC_TX_RST, x)
+#define DEV_CLOCK_CFG_MAC_TX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_MAC_TX_RST, x)
+
+#define DEV_CLOCK_CFG_MAC_RX_RST                 BIT(6)
+#define DEV_CLOCK_CFG_MAC_RX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_MAC_RX_RST, x)
+#define DEV_CLOCK_CFG_MAC_RX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_MAC_RX_RST, x)
+
+#define DEV_CLOCK_CFG_PCS_TX_RST                 BIT(5)
+#define DEV_CLOCK_CFG_PCS_TX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PCS_TX_RST, x)
+#define DEV_CLOCK_CFG_PCS_TX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PCS_TX_RST, x)
+
+#define DEV_CLOCK_CFG_PCS_RX_RST                 BIT(4)
+#define DEV_CLOCK_CFG_PCS_RX_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PCS_RX_RST, x)
+#define DEV_CLOCK_CFG_PCS_RX_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PCS_RX_RST, x)
+
+#define DEV_CLOCK_CFG_PORT_RST                   BIT(3)
+#define DEV_CLOCK_CFG_PORT_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PORT_RST, x)
+#define DEV_CLOCK_CFG_PORT_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PORT_RST, x)
+
+#define DEV_CLOCK_CFG_PHY_RST                    BIT(2)
+#define DEV_CLOCK_CFG_PHY_RST_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_PHY_RST, x)
+#define DEV_CLOCK_CFG_PHY_RST_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_PHY_RST, x)
+
+#define DEV_CLOCK_CFG_LINK_SPEED                 GENMASK(1, 0)
+#define DEV_CLOCK_CFG_LINK_SPEED_SET(x)\
+	FIELD_PREP(DEV_CLOCK_CFG_LINK_SPEED, x)
+#define DEV_CLOCK_CFG_LINK_SPEED_GET(x)\
+	FIELD_GET(DEV_CLOCK_CFG_LINK_SPEED, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_ENA_CFG */
+#define DEV_MAC_ENA_CFG(t)        __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 0, 0, 1, 4)
+
+#define DEV_MAC_ENA_CFG_RX_ENA                   BIT(4)
+#define DEV_MAC_ENA_CFG_RX_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_ENA_CFG_RX_ENA, x)
+#define DEV_MAC_ENA_CFG_RX_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_ENA_CFG_RX_ENA, x)
+
+#define DEV_MAC_ENA_CFG_TX_ENA                   BIT(0)
+#define DEV_MAC_ENA_CFG_TX_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_ENA_CFG_TX_ENA, x)
+#define DEV_MAC_ENA_CFG_TX_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_ENA_CFG_TX_ENA, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_MODE_CFG */
+#define DEV_MAC_MODE_CFG(t)       __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 4, 0, 1, 4)
+
+#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA        BIT(8)
+#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA, x)
+#define DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_MODE_CFG_FC_WORD_SYNC_ENA, x)
+
+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA           BIT(4)
+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_MODE_CFG_GIGA_MODE_ENA, x)
+#define DEV_MAC_MODE_CFG_GIGA_MODE_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_MODE_CFG_GIGA_MODE_ENA, x)
+
+#define DEV_MAC_MODE_CFG_FDX_ENA                 BIT(0)
+#define DEV_MAC_MODE_CFG_FDX_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_MODE_CFG_FDX_ENA, x)
+#define DEV_MAC_MODE_CFG_FDX_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_MODE_CFG_FDX_ENA, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
+#define DEV_MAC_MAXLEN_CFG(t)     __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 8, 0, 1, 4)
+
+#define DEV_MAC_MAXLEN_CFG_MAX_LEN               GENMASK(15, 0)
+#define DEV_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
+	FIELD_PREP(DEV_MAC_MAXLEN_CFG_MAX_LEN, x)
+#define DEV_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
+	FIELD_GET(DEV_MAC_MAXLEN_CFG_MAX_LEN, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_TAGS_CFG */
+#define DEV_MAC_TAGS_CFG(t)       __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 12, 0, 1, 4)
+
+#define DEV_MAC_TAGS_CFG_TAG_ID                  GENMASK(31, 16)
+#define DEV_MAC_TAGS_CFG_TAG_ID_SET(x)\
+	FIELD_PREP(DEV_MAC_TAGS_CFG_TAG_ID, x)
+#define DEV_MAC_TAGS_CFG_TAG_ID_GET(x)\
+	FIELD_GET(DEV_MAC_TAGS_CFG_TAG_ID, x)
+
+#define DEV_MAC_TAGS_CFG_PB_ENA                  BIT(1)
+#define DEV_MAC_TAGS_CFG_PB_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_TAGS_CFG_PB_ENA, x)
+#define DEV_MAC_TAGS_CFG_PB_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_TAGS_CFG_PB_ENA, x)
+
+#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA            BIT(0)
+#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA, x)
+#define DEV_MAC_TAGS_CFG_VLAN_AWR_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_TAGS_CFG_VLAN_AWR_ENA, x)
+
+#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA        BIT(2)
+#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)
+#define DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_TAGS_CFG_VLAN_LEN_AWR_ENA, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_IFG_CFG */
+#define DEV_MAC_IFG_CFG(t)        __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 20, 0, 1, 4)
+
+#define DEV_MAC_IFG_CFG_OLD_IPG_CHECK            BIT(17)
+#define DEV_MAC_IFG_CFG_OLD_IPG_CHECK_SET(x)\
+	FIELD_PREP(DEV_MAC_IFG_CFG_OLD_IPG_CHECK, x)
+#define DEV_MAC_IFG_CFG_OLD_IPG_CHECK_GET(x)\
+	FIELD_GET(DEV_MAC_IFG_CFG_OLD_IPG_CHECK, x)
+
+#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG           BIT(16)
+#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG_SET(x)\
+	FIELD_PREP(DEV_MAC_IFG_CFG_REDUCED_TX_IFG, x)
+#define DEV_MAC_IFG_CFG_REDUCED_TX_IFG_GET(x)\
+	FIELD_GET(DEV_MAC_IFG_CFG_REDUCED_TX_IFG, x)
+
+#define DEV_MAC_IFG_CFG_TX_IFG                   GENMASK(12, 8)
+#define DEV_MAC_IFG_CFG_TX_IFG_SET(x)\
+	FIELD_PREP(DEV_MAC_IFG_CFG_TX_IFG, x)
+#define DEV_MAC_IFG_CFG_TX_IFG_GET(x)\
+	FIELD_GET(DEV_MAC_IFG_CFG_TX_IFG, x)
+
+#define DEV_MAC_IFG_CFG_RX_IFG2                  GENMASK(7, 4)
+#define DEV_MAC_IFG_CFG_RX_IFG2_SET(x)\
+	FIELD_PREP(DEV_MAC_IFG_CFG_RX_IFG2, x)
+#define DEV_MAC_IFG_CFG_RX_IFG2_GET(x)\
+	FIELD_GET(DEV_MAC_IFG_CFG_RX_IFG2, x)
+
+#define DEV_MAC_IFG_CFG_RX_IFG1                  GENMASK(3, 0)
+#define DEV_MAC_IFG_CFG_RX_IFG1_SET(x)\
+	FIELD_PREP(DEV_MAC_IFG_CFG_RX_IFG1, x)
+#define DEV_MAC_IFG_CFG_RX_IFG1_GET(x)\
+	FIELD_GET(DEV_MAC_IFG_CFG_RX_IFG1, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_HDX_CFG */
+#define DEV_MAC_HDX_CFG(t)        __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 24, 0, 1, 4)
+
+#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC          BIT(26)
+#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_BYPASS_COL_SYNC, x)
+#define DEV_MAC_HDX_CFG_BYPASS_COL_SYNC_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_BYPASS_COL_SYNC, x)
+
+#define DEV_MAC_HDX_CFG_OB_ENA                   BIT(25)
+#define DEV_MAC_HDX_CFG_OB_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_OB_ENA, x)
+#define DEV_MAC_HDX_CFG_OB_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_OB_ENA, x)
+
+#define DEV_MAC_HDX_CFG_WEXC_DIS                 BIT(24)
+#define DEV_MAC_HDX_CFG_WEXC_DIS_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_WEXC_DIS, x)
+#define DEV_MAC_HDX_CFG_WEXC_DIS_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_WEXC_DIS, x)
+
+#define DEV_MAC_HDX_CFG_SEED                     GENMASK(23, 16)
+#define DEV_MAC_HDX_CFG_SEED_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_SEED, x)
+#define DEV_MAC_HDX_CFG_SEED_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_SEED, x)
+
+#define DEV_MAC_HDX_CFG_SEED_LOAD                BIT(12)
+#define DEV_MAC_HDX_CFG_SEED_LOAD_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_SEED_LOAD, x)
+#define DEV_MAC_HDX_CFG_SEED_LOAD_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_SEED_LOAD, x)
+
+#define DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA        BIT(8)
+#define DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA, x)
+#define DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_RETRY_EXC_COL_ENA, x)
+
+#define DEV_MAC_HDX_CFG_LATE_COL_POS             GENMASK(6, 0)
+#define DEV_MAC_HDX_CFG_LATE_COL_POS_SET(x)\
+	FIELD_PREP(DEV_MAC_HDX_CFG_LATE_COL_POS, x)
+#define DEV_MAC_HDX_CFG_LATE_COL_POS_GET(x)\
+	FIELD_GET(DEV_MAC_HDX_CFG_LATE_COL_POS, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_FC_MAC_LOW_CFG */
+#define DEV_FC_MAC_LOW_CFG(t)     __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 32, 0, 1, 4)
+
+#define DEV_FC_MAC_LOW_CFG_MAC_LOW               GENMASK(23, 0)
+#define DEV_FC_MAC_LOW_CFG_MAC_LOW_SET(x)\
+	FIELD_PREP(DEV_FC_MAC_LOW_CFG_MAC_LOW, x)
+#define DEV_FC_MAC_LOW_CFG_MAC_LOW_GET(x)\
+	FIELD_GET(DEV_FC_MAC_LOW_CFG_MAC_LOW, x)
+
+/*      DEV:MAC_CFG_STATUS:MAC_FC_MAC_HIGH_CFG */
+#define DEV_FC_MAC_HIGH_CFG(t)    __REG(TARGET_DEV,\
+					t, 9, 20, 0, 1, 44, 36, 0, 1, 4)
+
+#define DEV_FC_MAC_HIGH_CFG_MAC_HIGH             GENMASK(23, 0)
+#define DEV_FC_MAC_HIGH_CFG_MAC_HIGH_SET(x)\
+	FIELD_PREP(DEV_FC_MAC_HIGH_CFG_MAC_HIGH, x)
+#define DEV_FC_MAC_HIGH_CFG_MAC_HIGH_GET(x)\
+	FIELD_GET(DEV_FC_MAC_HIGH_CFG_MAC_HIGH, x)
+
+/*      DEV:PCS1G_CFG_STATUS:PCS1G_CFG */
+#define DEV_PCS1G_CFG(t)          __REG(TARGET_DEV,\
+					t, 9, 64, 0, 1, 68, 0, 0, 1, 4)
+
+#define DEV_PCS1G_CFG_LINK_STATUS_TYPE           BIT(4)
+#define DEV_PCS1G_CFG_LINK_STATUS_TYPE_SET(x)\
+	FIELD_PREP(DEV_PCS1G_CFG_LINK_STATUS_TYPE, x)
+#define DEV_PCS1G_CFG_LINK_STATUS_TYPE_GET(x)\
+	FIELD_GET(DEV_PCS1G_CFG_LINK_STATUS_TYPE, x)
+
+#define DEV_PCS1G_CFG_AN_LINK_CTRL_ENA           BIT(1)
+#define DEV_PCS1G_CFG_AN_LINK_CTRL_ENA_SET(x)\
+	FIELD_PREP(DEV_PCS1G_CFG_AN_LINK_CTRL_ENA, x)
+#define DEV_PCS1G_CFG_AN_LINK_CTRL_ENA_GET(x)\
+	FIELD_GET(DEV_PCS1G_CFG_AN_LINK_CTRL_ENA, x)
+
+#define DEV_PCS1G_CFG_PCS_ENA                    BIT(0)
+#define DEV_PCS1G_CFG_PCS_ENA_SET(x)\
+	FIELD_PREP(DEV_PCS1G_CFG_PCS_ENA, x)
+#define DEV_PCS1G_CFG_PCS_ENA_GET(x)\
+	FIELD_GET(DEV_PCS1G_CFG_PCS_ENA, x)
+
+/*      DEV:PCS1G_CFG_STATUS:PCS1G_SD_CFG */
+#define DEV_PCS1G_SD_CFG(t)       __REG(TARGET_DEV,\
+					t, 9, 64, 0, 1, 68, 8, 0, 1, 4)
+
+#define DEV_PCS1G_SD_CFG_SD_SEL                  BIT(8)
+#define DEV_PCS1G_SD_CFG_SD_SEL_SET(x)\
+	FIELD_PREP(DEV_PCS1G_SD_CFG_SD_SEL, x)
+#define DEV_PCS1G_SD_CFG_SD_SEL_GET(x)\
+	FIELD_GET(DEV_PCS1G_SD_CFG_SD_SEL, x)
+
+#define DEV_PCS1G_SD_CFG_SD_POL                  BIT(4)
+#define DEV_PCS1G_SD_CFG_SD_POL_SET(x)\
+	FIELD_PREP(DEV_PCS1G_SD_CFG_SD_POL, x)
+#define DEV_PCS1G_SD_CFG_SD_POL_GET(x)\
+	FIELD_GET(DEV_PCS1G_SD_CFG_SD_POL, x)
+
+#define DEV_PCS1G_SD_CFG_SD_ENA                  BIT(0)
+#define DEV_PCS1G_SD_CFG_SD_ENA_SET(x)\
+	FIELD_PREP(DEV_PCS1G_SD_CFG_SD_ENA, x)
+#define DEV_PCS1G_SD_CFG_SD_ENA_GET(x)\
+	FIELD_GET(DEV_PCS1G_SD_CFG_SD_ENA, x)
+
+/*      DEVCPU_GCB:CHIP_REGS:FEAT_DISABLE */
+#define GCB_FEAT_DISABLE          __REG(TARGET_GCB,\
+					0, 1, 0, 0, 1, 28, 20, 0, 1, 4)
+
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS     BIT(0)
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_EEPROM_CFG_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS    BIT(1)
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_EEPROM_BOOT_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS BIT(2)
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_EEPROM_FW_PATCH_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS BIT(3)
+#define GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_MMU_BACKDOOR_WR_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS     BIT(4)
+#define GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_MGMT_IF_WR_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_DD_DIS             BIT(5)
+#define GCB_FEAT_DISABLE_FEAT_DD_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_DD_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_DD_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_DD_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_TSN_DIS            BIT(6)
+#define GCB_FEAT_DISABLE_FEAT_TSN_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_TSN_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_TSN_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_TSN_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_PTP_DIS            BIT(7)
+#define GCB_FEAT_DISABLE_FEAT_PTP_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_PTP_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_PTP_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_PTP_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_FRER_DIS           BIT(8)
+#define GCB_FEAT_DISABLE_FEAT_FRER_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_FRER_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_FRER_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_FRER_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS      GENMASK(14, 12)
+#define GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS         GENMASK(16, 15)
+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_NUM_CU_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_RGMII_DIS          GENMASK(18, 17)
+#define GCB_FEAT_DISABLE_FEAT_RGMII_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_RGMII_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_RGMII_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_RGMII_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_SGMII_DIS          GENMASK(20, 19)
+#define GCB_FEAT_DISABLE_FEAT_SGMII_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_SGMII_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_SGMII_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_SGMII_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_QSGMII_DIS         BIT(21)
+#define GCB_FEAT_DISABLE_FEAT_QSGMII_DIS_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_QSGMII_DIS, x)
+#define GCB_FEAT_DISABLE_FEAT_QSGMII_DIS_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_QSGMII_DIS, x)
+
+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED       BIT(22)
+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED, x)
+#define GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_NUM_CU_FIXED, x)
+
+#define GCB_FEAT_DISABLE_FEAT_WDT_ENABLED        BIT(25)
+#define GCB_FEAT_DISABLE_FEAT_WDT_ENABLED_SET(x)\
+	FIELD_PREP(GCB_FEAT_DISABLE_FEAT_WDT_ENABLED, x)
+#define GCB_FEAT_DISABLE_FEAT_WDT_ENABLED_GET(x)\
+	FIELD_GET(GCB_FEAT_DISABLE_FEAT_WDT_ENABLED, x)
+
+/*      HSIO:HW_CFGSTAT:HW_CFG */
+#define HSIO_HW_CFG               __REG(TARGET_HSIO,\
+					0, 1, 72, 0, 1, 44, 0, 0, 1, 4)
+
+#define HSIO_HW_CFG_RGMII_0_CFG                  BIT(10)
+#define HSIO_HW_CFG_RGMII_0_CFG_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_RGMII_0_CFG, x)
+#define HSIO_HW_CFG_RGMII_0_CFG_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_RGMII_0_CFG, x)
+
+#define HSIO_HW_CFG_GMII_ENA                     GENMASK(9, 1)
+#define HSIO_HW_CFG_GMII_ENA_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_GMII_ENA, x)
+#define HSIO_HW_CFG_GMII_ENA_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_GMII_ENA, x)
+
+#define HSIO_HW_CFG_QSGMII_ENA                   BIT(0)
+#define HSIO_HW_CFG_QSGMII_ENA_SET(x)\
+	FIELD_PREP(HSIO_HW_CFG_QSGMII_ENA, x)
+#define HSIO_HW_CFG_QSGMII_ENA_GET(x)\
+	FIELD_GET(HSIO_HW_CFG_QSGMII_ENA, x)
+
+/*      HSIO:HW_CFGSTAT:RGMII_CFG */
+#define HSIO_RGMII_CFG(r)         __REG(TARGET_HSIO,\
+					0, 1, 72, 0, 1, 44, 12, r, 2, 4)
+
+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS         BIT(15)
+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_RX_LINK_STATUS, x)
+#define HSIO_RGMII_CFG_IB_RX_LINK_STATUS_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_RX_LINK_STATUS, x)
+
+#define HSIO_RGMII_CFG_IB_RX_DUPLEX              BIT(14)
+#define HSIO_RGMII_CFG_IB_RX_DUPLEX_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_RX_DUPLEX, x)
+#define HSIO_RGMII_CFG_IB_RX_DUPLEX_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_RX_DUPLEX, x)
+
+#define HSIO_RGMII_CFG_IB_RX_SPEED               GENMASK(13, 12)
+#define HSIO_RGMII_CFG_IB_RX_SPEED_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_RX_SPEED, x)
+#define HSIO_RGMII_CFG_IB_RX_SPEED_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_RX_SPEED, x)
+
+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS         BIT(11)
+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_TX_LINK_STATUS, x)
+#define HSIO_RGMII_CFG_IB_TX_LINK_STATUS_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_TX_LINK_STATUS, x)
+
+#define HSIO_RGMII_CFG_IB_TX_FDX                 BIT(10)
+#define HSIO_RGMII_CFG_IB_TX_FDX_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_TX_FDX, x)
+#define HSIO_RGMII_CFG_IB_TX_FDX_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_TX_FDX, x)
+
+#define HSIO_RGMII_CFG_IB_TX_MII_SPD             BIT(9)
+#define HSIO_RGMII_CFG_IB_TX_MII_SPD_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_TX_MII_SPD, x)
+#define HSIO_RGMII_CFG_IB_TX_MII_SPD_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_TX_MII_SPD, x)
+
+#define HSIO_RGMII_CFG_IB_TX_SPD_1G              BIT(8)
+#define HSIO_RGMII_CFG_IB_TX_SPD_1G_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_TX_SPD_1G, x)
+#define HSIO_RGMII_CFG_IB_TX_SPD_1G_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_TX_SPD_1G, x)
+
+#define HSIO_RGMII_CFG_IB_TX_ENA                 BIT(7)
+#define HSIO_RGMII_CFG_IB_TX_ENA_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_TX_ENA, x)
+#define HSIO_RGMII_CFG_IB_TX_ENA_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_TX_ENA, x)
+
+#define HSIO_RGMII_CFG_IB_RX_ENA                 BIT(6)
+#define HSIO_RGMII_CFG_IB_RX_ENA_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_RX_ENA, x)
+#define HSIO_RGMII_CFG_IB_RX_ENA_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_RX_ENA, x)
+
+#define HSIO_RGMII_CFG_IB_ENA                    BIT(5)
+#define HSIO_RGMII_CFG_IB_ENA_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_IB_ENA, x)
+#define HSIO_RGMII_CFG_IB_ENA_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_IB_ENA, x)
+
+#define HSIO_RGMII_CFG_TX_CLK_CFG                GENMASK(4, 2)
+#define HSIO_RGMII_CFG_TX_CLK_CFG_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_TX_CLK_CFG, x)
+#define HSIO_RGMII_CFG_TX_CLK_CFG_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_TX_CLK_CFG, x)
+
+#define HSIO_RGMII_CFG_RGMII_TX_RST              BIT(1)
+#define HSIO_RGMII_CFG_RGMII_TX_RST_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_RGMII_TX_RST, x)
+#define HSIO_RGMII_CFG_RGMII_TX_RST_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_RGMII_TX_RST, x)
+
+#define HSIO_RGMII_CFG_RGMII_RX_RST              BIT(0)
+#define HSIO_RGMII_CFG_RGMII_RX_RST_SET(x)\
+	FIELD_PREP(HSIO_RGMII_CFG_RGMII_RX_RST, x)
+#define HSIO_RGMII_CFG_RGMII_RX_RST_GET(x)\
+	FIELD_GET(HSIO_RGMII_CFG_RGMII_RX_RST, x)
+
+/*      HSIO:HW_CFGSTAT:DLL_CFG */
+#define HSIO_DLL_CFG(r)           __REG(TARGET_HSIO,\
+					0, 1, 72, 0, 1, 44, 28, r, 4, 4)
+
+#define HSIO_DLL_CFG_DLL_CLK_ENA                 BIT(20)
+#define HSIO_DLL_CFG_DLL_CLK_ENA_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_DLL_CLK_ENA, x)
+#define HSIO_DLL_CFG_DLL_CLK_ENA_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_DLL_CLK_ENA, x)
+
+#define HSIO_DLL_CFG_BIST_PASS                   BIT(19)
+#define HSIO_DLL_CFG_BIST_PASS_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_BIST_PASS, x)
+#define HSIO_DLL_CFG_BIST_PASS_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_BIST_PASS, x)
+
+#define HSIO_DLL_CFG_BIST_END                    BIT(18)
+#define HSIO_DLL_CFG_BIST_END_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_BIST_END, x)
+#define HSIO_DLL_CFG_BIST_END_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_BIST_END, x)
+
+#define HSIO_DLL_CFG_BIST_START                  BIT(17)
+#define HSIO_DLL_CFG_BIST_START_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_BIST_START, x)
+#define HSIO_DLL_CFG_BIST_START_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_BIST_START, x)
+
+#define HSIO_DLL_CFG_TAP_SEL                     GENMASK(16, 10)
+#define HSIO_DLL_CFG_TAP_SEL_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_TAP_SEL, x)
+#define HSIO_DLL_CFG_TAP_SEL_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_TAP_SEL, x)
+
+#define HSIO_DLL_CFG_TAP_ADJ                     GENMASK(9, 3)
+#define HSIO_DLL_CFG_TAP_ADJ_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_TAP_ADJ, x)
+#define HSIO_DLL_CFG_TAP_ADJ_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_TAP_ADJ, x)
+
+#define HSIO_DLL_CFG_DELAY_ENA                   BIT(2)
+#define HSIO_DLL_CFG_DELAY_ENA_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_DELAY_ENA, x)
+#define HSIO_DLL_CFG_DELAY_ENA_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_DELAY_ENA, x)
+
+#define HSIO_DLL_CFG_DLL_ENA                     BIT(1)
+#define HSIO_DLL_CFG_DLL_ENA_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_DLL_ENA, x)
+#define HSIO_DLL_CFG_DLL_ENA_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_DLL_ENA, x)
+
+#define HSIO_DLL_CFG_DLL_RST                     BIT(0)
+#define HSIO_DLL_CFG_DLL_RST_SET(x)\
+	FIELD_PREP(HSIO_DLL_CFG_DLL_RST, x)
+#define HSIO_DLL_CFG_DLL_RST_GET(x)\
+	FIELD_GET(HSIO_DLL_CFG_DLL_RST, x)
+
+/*      DEVCPU_QS:XTR:XTR_FLUSH */
+#define QS_XTR_FLUSH              __REG(TARGET_QS,\
+					0, 1, 0, 0, 1, 36, 24, 0, 1, 4)
+
+#define QS_XTR_FLUSH_FLUSH                       GENMASK(1, 0)
+#define QS_XTR_FLUSH_FLUSH_SET(x)\
+	FIELD_PREP(QS_XTR_FLUSH_FLUSH, x)
+#define QS_XTR_FLUSH_FLUSH_GET(x)\
+	FIELD_GET(QS_XTR_FLUSH_FLUSH, x)
+
+/*      DEVCPU_QS:INJ:INJ_GRP_CFG */
+#define QS_INJ_GRP_CFG(r)         __REG(TARGET_QS,\
+					0, 1, 36, 0, 1, 40, 0, r, 2, 4)
+
+#define QS_INJ_GRP_CFG_MODE                      GENMASK(3, 2)
+#define QS_INJ_GRP_CFG_MODE_SET(x)\
+	FIELD_PREP(QS_INJ_GRP_CFG_MODE, x)
+#define QS_INJ_GRP_CFG_MODE_GET(x)\
+	FIELD_GET(QS_INJ_GRP_CFG_MODE, x)
+
+#define QS_INJ_GRP_CFG_BYTE_SWAP                 BIT(0)
+#define QS_INJ_GRP_CFG_BYTE_SWAP_SET(x)\
+	FIELD_PREP(QS_INJ_GRP_CFG_BYTE_SWAP, x)
+#define QS_INJ_GRP_CFG_BYTE_SWAP_GET(x)\
+	FIELD_GET(QS_INJ_GRP_CFG_BYTE_SWAP, x)
+
+/*      DEVCPU_QS:INJ:INJ_CTRL */
+#define QS_INJ_CTRL(r)            __REG(TARGET_QS,\
+					0, 1, 36, 0, 1, 40, 16, r, 2, 4)
+
+#define QS_INJ_CTRL_GAP_SIZE                     GENMASK(24, 21)
+#define QS_INJ_CTRL_GAP_SIZE_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_GAP_SIZE, x)
+#define QS_INJ_CTRL_GAP_SIZE_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_GAP_SIZE, x)
+
+#define QS_INJ_CTRL_ABORT                        BIT(20)
+#define QS_INJ_CTRL_ABORT_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_ABORT, x)
+#define QS_INJ_CTRL_ABORT_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_ABORT, x)
+
+#define QS_INJ_CTRL_EOF                          BIT(19)
+#define QS_INJ_CTRL_EOF_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_EOF, x)
+#define QS_INJ_CTRL_EOF_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_EOF, x)
+
+#define QS_INJ_CTRL_SOF                          BIT(18)
+#define QS_INJ_CTRL_SOF_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_SOF, x)
+#define QS_INJ_CTRL_SOF_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_SOF, x)
+
+#define QS_INJ_CTRL_VLD_BYTES                    GENMASK(17, 16)
+#define QS_INJ_CTRL_VLD_BYTES_SET(x)\
+	FIELD_PREP(QS_INJ_CTRL_VLD_BYTES, x)
+#define QS_INJ_CTRL_VLD_BYTES_GET(x)\
+	FIELD_GET(QS_INJ_CTRL_VLD_BYTES, x)
+
+/*      QSYS:SYSTEM:PORT_MODE */
+#define QSYS_PORT_MODE(r)         __REG(TARGET_QSYS,\
+					0, 1, 14336, 0, 1, 240, 0, r, 11, 4)
+
+#define QSYS_PORT_MODE_DEQUEUE_DIS               BIT(1)
+#define QSYS_PORT_MODE_DEQUEUE_DIS_SET(x)\
+	FIELD_PREP(QSYS_PORT_MODE_DEQUEUE_DIS, x)
+#define QSYS_PORT_MODE_DEQUEUE_DIS_GET(x)\
+	FIELD_GET(QSYS_PORT_MODE_DEQUEUE_DIS, x)
+
+#define QSYS_PORT_MODE_DEQUEUE_LATE              BIT(0)
+#define QSYS_PORT_MODE_DEQUEUE_LATE_SET(x)\
+	FIELD_PREP(QSYS_PORT_MODE_DEQUEUE_LATE, x)
+#define QSYS_PORT_MODE_DEQUEUE_LATE_GET(x)\
+	FIELD_GET(QSYS_PORT_MODE_DEQUEUE_LATE, x)
+
+/*      QSYS:SYSTEM:SWITCH_PORT_MODE */
+#define QSYS_SW_PORT_MODE(r)      __REG(TARGET_QSYS,\
+					0, 1, 14336, 0, 1, 240, 88, r, 10, 4)
+
+#define QSYS_SW_PORT_MODE_PORT_ENA               BIT(19)
+#define QSYS_SW_PORT_MODE_PORT_ENA_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_PORT_ENA, x)
+#define QSYS_SW_PORT_MODE_PORT_ENA_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_PORT_ENA, x)
+
+#define QSYS_SW_PORT_MODE_IDEQ_DIS               BIT(18)
+#define QSYS_SW_PORT_MODE_IDEQ_DIS_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_IDEQ_DIS, x)
+#define QSYS_SW_PORT_MODE_IDEQ_DIS_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_IDEQ_DIS, x)
+
+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG           GENMASK(17, 15)
+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_SCH_NEXT_CFG, x)
+#define QSYS_SW_PORT_MODE_SCH_NEXT_CFG_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_SCH_NEXT_CFG, x)
+
+#define QSYS_SW_PORT_MODE_YEL_RSRVD              BIT(14)
+#define QSYS_SW_PORT_MODE_YEL_RSRVD_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_YEL_RSRVD, x)
+#define QSYS_SW_PORT_MODE_YEL_RSRVD_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_YEL_RSRVD, x)
+
+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE      BIT(13)
+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_INGRESS_DROP_MODE, x)
+#define QSYS_SW_PORT_MODE_INGRESS_DROP_MODE_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_INGRESS_DROP_MODE, x)
+
+#define QSYS_SW_PORT_MODE_TX_PFC_ENA             GENMASK(12, 5)
+#define QSYS_SW_PORT_MODE_TX_PFC_ENA_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_TX_PFC_ENA, x)
+#define QSYS_SW_PORT_MODE_TX_PFC_ENA_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_TX_PFC_ENA, x)
+
+#define QSYS_SW_PORT_MODE_TX_PFC_MODE            BIT(4)
+#define QSYS_SW_PORT_MODE_TX_PFC_MODE_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_TX_PFC_MODE, x)
+#define QSYS_SW_PORT_MODE_TX_PFC_MODE_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_TX_PFC_MODE, x)
+
+#define QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE      BIT(3)
+#define QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE, x)
+#define QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_FWD_TWOCYCLE_MODE, x)
+
+#define QSYS_SW_PORT_MODE_AGING_MODE             GENMASK(2, 1)
+#define QSYS_SW_PORT_MODE_AGING_MODE_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_AGING_MODE, x)
+#define QSYS_SW_PORT_MODE_AGING_MODE_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_AGING_MODE, x)
+
+#define QSYS_SW_PORT_MODE_HOL_PROTECTED          BIT(0)
+#define QSYS_SW_PORT_MODE_HOL_PROTECTED_SET(x)\
+	FIELD_PREP(QSYS_SW_PORT_MODE_HOL_PROTECTED, x)
+#define QSYS_SW_PORT_MODE_HOL_PROTECTED_GET(x)\
+	FIELD_GET(QSYS_SW_PORT_MODE_HOL_PROTECTED, x)
+
+/*      QSYS:SYSTEM:EGR_NO_SHARING */
+#define QSYS_EGR_NO_SHARING       __REG(TARGET_QSYS,\
+					0, 1, 14336, 0, 1, 240, 176, 0, 1, 4)
+
+#define QSYS_EGR_NO_SHARING_EGR_NO_SHARING       GENMASK(9, 0)
+#define QSYS_EGR_NO_SHARING_EGR_NO_SHARING_SET(x)\
+	FIELD_PREP(QSYS_EGR_NO_SHARING_EGR_NO_SHARING, x)
+#define QSYS_EGR_NO_SHARING_EGR_NO_SHARING_GET(x)\
+	FIELD_GET(QSYS_EGR_NO_SHARING_EGR_NO_SHARING, x)
+
+/*      QSYS:SYSTEM:SW_STATUS */
+#define QSYS_SW_STATUS(r)         __REG(TARGET_QSYS,\
+					0, 1, 14336, 0, 1, 240, 180, r, 10, 4)
+
+#define QSYS_SW_STATUS_EQ_AVAIL                  GENMASK(7, 0)
+#define QSYS_SW_STATUS_EQ_AVAIL_SET(x)\
+	FIELD_PREP(QSYS_SW_STATUS_EQ_AVAIL, x)
+#define QSYS_SW_STATUS_EQ_AVAIL_GET(x)\
+	FIELD_GET(QSYS_SW_STATUS_EQ_AVAIL, x)
+
+/*      QSYS:SYSTEM:EXT_CPU_CFG */
+#define QSYS_EXT_CPU_CFG          __REG(TARGET_QSYS,\
+					0, 1, 14336, 0, 1, 240, 220, 0, 1, 4)
+
+#define QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA        BIT(14)
+#define QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_SET(x)\
+	FIELD_PREP(QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA, x)
+#define QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA_GET(x)\
+	FIELD_GET(QSYS_EXT_CPU_CFG_EXT_CPU_KILL_ENA, x)
+
+#define QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA        BIT(13)
+#define QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_SET(x)\
+	FIELD_PREP(QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA, x)
+#define QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA_GET(x)\
+	FIELD_GET(QSYS_EXT_CPU_CFG_INT_CPU_KILL_ENA, x)
+
+#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT            GENMASK(12, 8)
+#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_SET(x)\
+	FIELD_PREP(QSYS_EXT_CPU_CFG_EXT_CPU_PORT, x)
+#define QSYS_EXT_CPU_CFG_EXT_CPU_PORT_GET(x)\
+	FIELD_GET(QSYS_EXT_CPU_CFG_EXT_CPU_PORT, x)
+
+#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK            GENMASK(7, 0)
+#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_SET(x)\
+	FIELD_PREP(QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK, x)
+#define QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK_GET(x)\
+	FIELD_GET(QSYS_EXT_CPU_CFG_EXT_CPUQ_MSK, x)
+
+/*      QSYS:SYSTEM:CPU_GROUP_MAP */
+#define QSYS_CPU_GROUP_MAP        __REG(TARGET_QSYS,\
+					0, 1, 14336, 0, 1, 240, 224, 0, 1, 4)
+
+#define QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP         GENMASK(7, 0)
+#define QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP_SET(x)\
+	FIELD_PREP(QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP, x)
+#define QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP_GET(x)\
+	FIELD_GET(QSYS_CPU_GROUP_MAP_CPU_GROUP_MAP, x)
+
+/*      QSYS:RES_CTRL:RES_CFG */
+#define QSYS_RES_CFG(g)           __REG(TARGET_QSYS,\
+					0, 1, 16384, g, 1024, 8, 0, 0, 1, 4)
+
+#define QSYS_RES_CFG_WM_HIGH                     GENMASK(8, 0)
+#define QSYS_RES_CFG_WM_HIGH_SET(x)\
+	FIELD_PREP(QSYS_RES_CFG_WM_HIGH, x)
+#define QSYS_RES_CFG_WM_HIGH_GET(x)\
+	FIELD_GET(QSYS_RES_CFG_WM_HIGH, x)
+
+/*      QSYS:DROP_CFG:EGR_DROP_MODE */
+#define QSYS_EGR_DROP_MODE        __REG(TARGET_QSYS,\
+					0, 1, 12736, 0, 1, 8, 0, 0, 1, 4)
+
+#define QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE      GENMASK(9, 0)
+#define QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_SET(x)\
+	FIELD_PREP(QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE, x)
+#define QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE_GET(x)\
+	FIELD_GET(QSYS_EGR_DROP_MODE_EGRESS_DROP_MODE, x)
+
+/*      REW:PORT:PORT_VLAN_CFG */
+#define REW_PORT_VLAN_CFG(g)      __REG(TARGET_REW,\
+					0, 1, 4096, g, 11, 128, 0, 0, 1, 4)
+
+#define REW_PORT_VLAN_CFG_PORT_TPID              GENMASK(31, 16)
+#define REW_PORT_VLAN_CFG_PORT_TPID_SET(x)\
+	FIELD_PREP(REW_PORT_VLAN_CFG_PORT_TPID, x)
+#define REW_PORT_VLAN_CFG_PORT_TPID_GET(x)\
+	FIELD_GET(REW_PORT_VLAN_CFG_PORT_TPID, x)
+
+#define REW_PORT_VLAN_CFG_PORT_DEI               BIT(15)
+#define REW_PORT_VLAN_CFG_PORT_DEI_SET(x)\
+	FIELD_PREP(REW_PORT_VLAN_CFG_PORT_DEI, x)
+#define REW_PORT_VLAN_CFG_PORT_DEI_GET(x)\
+	FIELD_GET(REW_PORT_VLAN_CFG_PORT_DEI, x)
+
+#define REW_PORT_VLAN_CFG_PORT_PCP               GENMASK(14, 12)
+#define REW_PORT_VLAN_CFG_PORT_PCP_SET(x)\
+	FIELD_PREP(REW_PORT_VLAN_CFG_PORT_PCP, x)
+#define REW_PORT_VLAN_CFG_PORT_PCP_GET(x)\
+	FIELD_GET(REW_PORT_VLAN_CFG_PORT_PCP, x)
+
+#define REW_PORT_VLAN_CFG_PORT_VID               GENMASK(11, 0)
+#define REW_PORT_VLAN_CFG_PORT_VID_SET(x)\
+	FIELD_PREP(REW_PORT_VLAN_CFG_PORT_VID, x)
+#define REW_PORT_VLAN_CFG_PORT_VID_GET(x)\
+	FIELD_GET(REW_PORT_VLAN_CFG_PORT_VID, x)
+
+/*      REW:PORT:TAG_CFG */
+#define REW_TAG_CFG(g)            __REG(TARGET_REW,\
+					0, 1, 4096, g, 11, 128, 4, 0, 1, 4)
+
+#define REW_TAG_CFG_TAG_CFG                      GENMASK(8, 7)
+#define REW_TAG_CFG_TAG_CFG_SET(x)\
+	FIELD_PREP(REW_TAG_CFG_TAG_CFG, x)
+#define REW_TAG_CFG_TAG_CFG_GET(x)\
+	FIELD_GET(REW_TAG_CFG_TAG_CFG, x)
+
+#define REW_TAG_CFG_TAG_TPID_CFG                 GENMASK(6, 5)
+#define REW_TAG_CFG_TAG_TPID_CFG_SET(x)\
+	FIELD_PREP(REW_TAG_CFG_TAG_TPID_CFG, x)
+#define REW_TAG_CFG_TAG_TPID_CFG_GET(x)\
+	FIELD_GET(REW_TAG_CFG_TAG_TPID_CFG, x)
+
+#define REW_TAG_CFG_TAG_VID_CFG                  BIT(4)
+#define REW_TAG_CFG_TAG_VID_CFG_SET(x)\
+	FIELD_PREP(REW_TAG_CFG_TAG_VID_CFG, x)
+#define REW_TAG_CFG_TAG_VID_CFG_GET(x)\
+	FIELD_GET(REW_TAG_CFG_TAG_VID_CFG, x)
+
+#define REW_TAG_CFG_TAG_PCP_CFG                  GENMASK(3, 2)
+#define REW_TAG_CFG_TAG_PCP_CFG_SET(x)\
+	FIELD_PREP(REW_TAG_CFG_TAG_PCP_CFG, x)
+#define REW_TAG_CFG_TAG_PCP_CFG_GET(x)\
+	FIELD_GET(REW_TAG_CFG_TAG_PCP_CFG, x)
+
+#define REW_TAG_CFG_TAG_DEI_CFG                  GENMASK(1, 0)
+#define REW_TAG_CFG_TAG_DEI_CFG_SET(x)\
+	FIELD_PREP(REW_TAG_CFG_TAG_DEI_CFG, x)
+#define REW_TAG_CFG_TAG_DEI_CFG_GET(x)\
+	FIELD_GET(REW_TAG_CFG_TAG_DEI_CFG, x)
+
+/*      REW:PORT:PORT_CFG */
+#define REW_PORT_CFG(g)           __REG(TARGET_REW,\
+					0, 1, 4096, g, 11, 128, 8, 0, 1, 4)
+
+#define REW_PORT_CFG_ES0_EN                      BIT(4)
+#define REW_PORT_CFG_ES0_EN_SET(x)\
+	FIELD_PREP(REW_PORT_CFG_ES0_EN, x)
+#define REW_PORT_CFG_ES0_EN_GET(x)\
+	FIELD_GET(REW_PORT_CFG_ES0_EN, x)
+
+#define REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG       GENMASK(3, 2)
+#define REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG_SET(x)\
+	FIELD_PREP(REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG, x)
+#define REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG_GET(x)\
+	FIELD_GET(REW_PORT_CFG_FCS_UPDATE_NONCPU_CFG, x)
+
+#define REW_PORT_CFG_FCS_UPDATE_CPU_ENA          BIT(1)
+#define REW_PORT_CFG_FCS_UPDATE_CPU_ENA_SET(x)\
+	FIELD_PREP(REW_PORT_CFG_FCS_UPDATE_CPU_ENA, x)
+#define REW_PORT_CFG_FCS_UPDATE_CPU_ENA_GET(x)\
+	FIELD_GET(REW_PORT_CFG_FCS_UPDATE_CPU_ENA, x)
+
+#define REW_PORT_CFG_NO_REWRITE                  BIT(0)
+#define REW_PORT_CFG_NO_REWRITE_SET(x)\
+	FIELD_PREP(REW_PORT_CFG_NO_REWRITE, x)
+#define REW_PORT_CFG_NO_REWRITE_GET(x)\
+	FIELD_GET(REW_PORT_CFG_NO_REWRITE, x)
+
+/*      SYS:SYSTEM:RESET_CFG */
+#define SYS_RESET_CFG             __REG(TARGET_SYS,\
+					0, 1, 4160, 0, 1, 184, 0, 0, 1, 4)
+
+#define SYS_RESET_CFG_CORE_ENA                   BIT(0)
+#define SYS_RESET_CFG_CORE_ENA_SET(x)\
+	FIELD_PREP(SYS_RESET_CFG_CORE_ENA, x)
+#define SYS_RESET_CFG_CORE_ENA_GET(x)\
+	FIELD_GET(SYS_RESET_CFG_CORE_ENA, x)
+
+/*      SYS:SYSTEM:PORT_MODE */
+#define SYS_PORT_MODE(r)          __REG(TARGET_SYS,\
+					0, 1, 4160, 0, 1, 184, 48, r, 11, 4)
+
+#define SYS_PORT_MODE_PRP_LANID                  BIT(8)
+#define SYS_PORT_MODE_PRP_LANID_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_PRP_LANID, x)
+#define SYS_PORT_MODE_PRP_LANID_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_PRP_LANID, x)
+
+#define SYS_PORT_MODE_PRP_ENA                    BIT(7)
+#define SYS_PORT_MODE_PRP_ENA_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_PRP_ENA, x)
+#define SYS_PORT_MODE_PRP_ENA_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_PRP_ENA, x)
+
+#define SYS_PORT_MODE_INCL_INJ_HDR               GENMASK(6, 5)
+#define SYS_PORT_MODE_INCL_INJ_HDR_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_INCL_INJ_HDR, x)
+#define SYS_PORT_MODE_INCL_INJ_HDR_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_INCL_INJ_HDR, x)
+
+#define SYS_PORT_MODE_INCL_XTR_HDR               GENMASK(4, 3)
+#define SYS_PORT_MODE_INCL_XTR_HDR_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_INCL_XTR_HDR, x)
+#define SYS_PORT_MODE_INCL_XTR_HDR_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_INCL_XTR_HDR, x)
+
+#define SYS_PORT_MODE_INJ_HDR_ERR                BIT(2)
+#define SYS_PORT_MODE_INJ_HDR_ERR_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_INJ_HDR_ERR, x)
+#define SYS_PORT_MODE_INJ_HDR_ERR_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_INJ_HDR_ERR, x)
+
+#define SYS_PORT_MODE_PAD_DIS                    BIT(1)
+#define SYS_PORT_MODE_PAD_DIS_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_PAD_DIS, x)
+#define SYS_PORT_MODE_PAD_DIS_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_PAD_DIS, x)
+
+#define SYS_PORT_MODE_RTAG_CLEAR                 BIT(0)
+#define SYS_PORT_MODE_RTAG_CLEAR_SET(x)\
+	FIELD_PREP(SYS_PORT_MODE_RTAG_CLEAR, x)
+#define SYS_PORT_MODE_RTAG_CLEAR_GET(x)\
+	FIELD_GET(SYS_PORT_MODE_RTAG_CLEAR, x)
+
+/*      SYS:SYSTEM:FRONT_PORT_MODE */
+#define SYS_FRONT_PORT_MODE(r)    __REG(TARGET_SYS,\
+					0, 1, 4160, 0, 1, 184, 92, r, 9, 4)
+
+#define SYS_FRONT_PORT_MODE_HDX_MODE             BIT(1)
+#define SYS_FRONT_PORT_MODE_HDX_MODE_SET(x)\
+	FIELD_PREP(SYS_FRONT_PORT_MODE_HDX_MODE, x)
+#define SYS_FRONT_PORT_MODE_HDX_MODE_GET(x)\
+	FIELD_GET(SYS_FRONT_PORT_MODE_HDX_MODE, x)
+
+#define SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE        GENMASK(9, 8)
+#define SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE_SET(x)\
+	FIELD_PREP(SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE, x)
+#define SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE_GET(x)\
+	FIELD_GET(SYS_FRONT_PORT_MODE_ADD_FRAG_SIZE, x)
+
+#define SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS     BIT(0)
+#define SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS_SET(x)\
+	FIELD_PREP(SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS, x)
+#define SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS_GET(x)\
+	FIELD_GET(SYS_FRONT_PORT_MODE_DONT_WAIT_FOR_TS, x)
+
+/*      SYS:SYSTEM:FRM_AGING */
+#define SYS_FRM_AGING             __REG(TARGET_SYS,\
+					0, 1, 4160, 0, 1, 184, 128, 0, 1, 4)
+
+#define SYS_FRM_AGING_AGE_TX_ENA                 BIT(20)
+#define SYS_FRM_AGING_AGE_TX_ENA_SET(x)\
+	FIELD_PREP(SYS_FRM_AGING_AGE_TX_ENA, x)
+#define SYS_FRM_AGING_AGE_TX_ENA_GET(x)\
+	FIELD_GET(SYS_FRM_AGING_AGE_TX_ENA, x)
+
+#define SYS_FRM_AGING_MAX_AGE                    GENMASK(19, 0)
+#define SYS_FRM_AGING_MAX_AGE_SET(x)\
+	FIELD_PREP(SYS_FRM_AGING_MAX_AGE, x)
+#define SYS_FRM_AGING_MAX_AGE_GET(x)\
+	FIELD_GET(SYS_FRM_AGING_MAX_AGE, x)
+
+/*      SYS:SYSTEM:STAT_CFG */
+#define SYS_STAT_CFG              __REG(TARGET_SYS,\
+					0, 1, 4160, 0, 1, 184, 132, 0, 1, 4)
+
+#define SYS_STAT_CFG_STAT_CLEAR_SHOT             GENMASK(16, 10)
+#define SYS_STAT_CFG_STAT_CLEAR_SHOT_SET(x)\
+	FIELD_PREP(SYS_STAT_CFG_STAT_CLEAR_SHOT, x)
+#define SYS_STAT_CFG_STAT_CLEAR_SHOT_GET(x)\
+	FIELD_GET(SYS_STAT_CFG_STAT_CLEAR_SHOT, x)
+
+#define SYS_STAT_CFG_STAT_VIEW                   GENMASK(9, 0)
+#define SYS_STAT_CFG_STAT_VIEW_SET(x)\
+	FIELD_PREP(SYS_STAT_CFG_STAT_VIEW, x)
+#define SYS_STAT_CFG_STAT_VIEW_GET(x)\
+	FIELD_GET(SYS_STAT_CFG_STAT_VIEW, x)
+
+/*      SYS:SYSTEM:SW_STATUS */
+#define SYS_SW_STATUS(r)          __REG(TARGET_SYS,\
+					0, 1, 4160, 0, 1, 184, 136, r, 10, 4)
+
+#define SYS_SW_STATUS_PORT_RX_PAUSED             BIT(0)
+#define SYS_SW_STATUS_PORT_RX_PAUSED_SET(x)\
+	FIELD_PREP(SYS_SW_STATUS_PORT_RX_PAUSED, x)
+#define SYS_SW_STATUS_PORT_RX_PAUSED_GET(x)\
+	FIELD_GET(SYS_SW_STATUS_PORT_RX_PAUSED, x)
+
+/*      SYS:PAUSE_CFG:PAUSE_CFG */
+#define SYS_PAUSE_CFG(r)          __REG(TARGET_SYS,\
+					0, 1, 4344, 0, 1, 124, 0, r, 10, 4)
+
+#define SYS_PAUSE_CFG_PAUSE_START                GENMASK(18, 10)
+#define SYS_PAUSE_CFG_PAUSE_START_SET(x)\
+	FIELD_PREP(SYS_PAUSE_CFG_PAUSE_START, x)
+#define SYS_PAUSE_CFG_PAUSE_START_GET(x)\
+	FIELD_GET(SYS_PAUSE_CFG_PAUSE_START, x)
+
+#define SYS_PAUSE_CFG_PAUSE_STOP                 GENMASK(9, 1)
+#define SYS_PAUSE_CFG_PAUSE_STOP_SET(x)\
+	FIELD_PREP(SYS_PAUSE_CFG_PAUSE_STOP, x)
+#define SYS_PAUSE_CFG_PAUSE_STOP_GET(x)\
+	FIELD_GET(SYS_PAUSE_CFG_PAUSE_STOP, x)
+
+#define SYS_PAUSE_CFG_PAUSE_ENA                  BIT(0)
+#define SYS_PAUSE_CFG_PAUSE_ENA_SET(x)\
+	FIELD_PREP(SYS_PAUSE_CFG_PAUSE_ENA, x)
+#define SYS_PAUSE_CFG_PAUSE_ENA_GET(x)\
+	FIELD_GET(SYS_PAUSE_CFG_PAUSE_ENA, x)
+
+/*      SYS:PAUSE_CFG:ATOP */
+#define SYS_ATOP(r)               __REG(TARGET_SYS,\
+					0, 1, 4344, 0, 1, 124, 44, r, 10, 4)
+
+#define SYS_ATOP_ATOP                            GENMASK(8, 0)
+#define SYS_ATOP_ATOP_SET(x)\
+	FIELD_PREP(SYS_ATOP_ATOP, x)
+#define SYS_ATOP_ATOP_GET(x)\
+	FIELD_GET(SYS_ATOP_ATOP, x)
+
+/*      SYS:PAUSE_CFG:ATOP_TOT_CFG */
+#define SYS_ATOP_TOT_CFG          __REG(TARGET_SYS,\
+					0, 1, 4344, 0, 1, 124, 84, 0, 1, 4)
+
+#define SYS_ATOP_TOT_CFG_ATOP_TOT                GENMASK(8, 0)
+#define SYS_ATOP_TOT_CFG_ATOP_TOT_SET(x)\
+	FIELD_PREP(SYS_ATOP_TOT_CFG_ATOP_TOT, x)
+#define SYS_ATOP_TOT_CFG_ATOP_TOT_GET(x)\
+	FIELD_GET(SYS_ATOP_TOT_CFG_ATOP_TOT, x)
+
+/*      SYS:PAUSE_CFG:MAC_FC_CFG */
+#define SYS_MAC_FC_CFG(r)         __REG(TARGET_SYS,\
+					0, 1, 4344, 0, 1, 124, 88, r, 9, 4)
+
+#define SYS_MAC_FC_CFG_FC_LINK_SPEED             GENMASK(27, 26)
+#define SYS_MAC_FC_CFG_FC_LINK_SPEED_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_FC_LINK_SPEED, x)
+#define SYS_MAC_FC_CFG_FC_LINK_SPEED_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_FC_LINK_SPEED, x)
+
+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG            GENMASK(25, 20)
+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_FC_LATENCY_CFG, x)
+#define SYS_MAC_FC_CFG_FC_LATENCY_CFG_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_FC_LATENCY_CFG, x)
+
+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA            BIT(18)
+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_ZERO_PAUSE_ENA, x)
+#define SYS_MAC_FC_CFG_ZERO_PAUSE_ENA_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_ZERO_PAUSE_ENA, x)
+
+#define SYS_MAC_FC_CFG_TX_FC_ENA                 BIT(17)
+#define SYS_MAC_FC_CFG_TX_FC_ENA_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_TX_FC_ENA, x)
+#define SYS_MAC_FC_CFG_TX_FC_ENA_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_TX_FC_ENA, x)
+
+#define SYS_MAC_FC_CFG_RX_FC_ENA                 BIT(16)
+#define SYS_MAC_FC_CFG_RX_FC_ENA_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_RX_FC_ENA, x)
+#define SYS_MAC_FC_CFG_RX_FC_ENA_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_RX_FC_ENA, x)
+
+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG             GENMASK(15, 0)
+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_SET(x)\
+	FIELD_PREP(SYS_MAC_FC_CFG_PAUSE_VAL_CFG, x)
+#define SYS_MAC_FC_CFG_PAUSE_VAL_CFG_GET(x)\
+	FIELD_GET(SYS_MAC_FC_CFG_PAUSE_VAL_CFG, x)
+
+/*      SYS:STAT:CNT */
+#define SYS_CNT(g)                __REG(TARGET_SYS,\
+					0, 1, 0, g, 896, 4, 0, 0, 1, 4)
+
+/*      SYS:RAM_CTRL:RAM_INIT */
+#define SYS_RAM_INIT              __REG(TARGET_SYS,\
+					0, 1, 4492, 0, 1, 4, 0, 0, 1, 4)
+
+#define SYS_RAM_INIT_RAM_TEST_OPT                GENMASK(4, 2)
+#define SYS_RAM_INIT_RAM_TEST_OPT_SET(x)\
+	FIELD_PREP(SYS_RAM_INIT_RAM_TEST_OPT, x)
+#define SYS_RAM_INIT_RAM_TEST_OPT_GET(x)\
+	FIELD_GET(SYS_RAM_INIT_RAM_TEST_OPT, x)
+
+#define SYS_RAM_INIT_RAM_INIT                    BIT(1)
+#define SYS_RAM_INIT_RAM_INIT_SET(x)\
+	FIELD_PREP(SYS_RAM_INIT_RAM_INIT, x)
+#define SYS_RAM_INIT_RAM_INIT_GET(x)\
+	FIELD_GET(SYS_RAM_INIT_RAM_INIT, x)
+
+#define SYS_RAM_INIT_RAM_CFG_HOOK                BIT(0)
+#define SYS_RAM_INIT_RAM_CFG_HOOK_SET(x)\
+	FIELD_PREP(SYS_RAM_INIT_RAM_CFG_HOOK, x)
+#define SYS_RAM_INIT_RAM_CFG_HOOK_GET(x)\
+	FIELD_GET(SYS_RAM_INIT_RAM_CFG_HOOK, x)
+
+/*      SYS:PTPPORT:PTP_RXDLY_CFG */
+#define SYS_PTP_RXDLY_CFG(g)      __REG(TARGET_SYS,\
+					0, 1, 4512, g, 11, 28, 8, 0, 1, 4)
+
+#define SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY          GENMASK(23, 0)
+#define SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY_SET(x)\
+	FIELD_PREP(SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY, x)
+#define SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY_GET(x)\
+	FIELD_GET(SYS_PTP_RXDLY_CFG_PTP_RX_IO_DLY, x)
+
+/*      SYS:PTPPORT:PTP_TXDLY_CFG */
+#define SYS_PTP_TXDLY_CFG(g)      __REG(TARGET_SYS,\
+					0, 1, 4512, g, 11, 28, 12, 0, 1, 4)
+
+#define SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY          GENMASK(23, 0)
+#define SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY_SET(x)\
+	FIELD_PREP(SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY, x)
+#define SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY_GET(x)\
+	FIELD_GET(SYS_PTP_TXDLY_CFG_PTP_TX_IO_DLY, x)
+
+#endif /* _LAN9645X_REGS_H_ */
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.c
new file mode 100644
index 00000000000000..e38f510eb8f664
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.c
@@ -0,0 +1,929 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include "lan9645x_main.h"
+#include "lan9645x_stats.h"
+
+#define LAN9645X_STATS_CHECK_DELAY	(3 * HZ)
+
+static const u32 lan9645x_port_stats_layout[] = {
+	[SCNT_RX_OCT]              = 0x0,
+	[SCNT_RX_UC]               = 0x1,
+	[SCNT_RX_MC]               = 0x2,
+	[SCNT_RX_BC]               = 0x3,
+	[SCNT_RX_SHORT]            = 0x4,
+	[SCNT_RX_FRAG]             = 0x5,
+	[SCNT_RX_JABBER]           = 0x6,
+	[SCNT_RX_CRC]              = 0x7,
+	[SCNT_RX_SYMBOL_ERR]       = 0x8,
+	[SCNT_RX_SZ_64]            = 0x9,
+	[SCNT_RX_SZ_65_127]        = 0xa,
+	[SCNT_RX_SZ_128_255]       = 0xb,
+	[SCNT_RX_SZ_256_511]       = 0xc,
+	[SCNT_RX_SZ_512_1023]      = 0xd,
+	[SCNT_RX_SZ_1024_1526]     = 0xe,
+	[SCNT_RX_SZ_JUMBO]         = 0xf,
+	[SCNT_RX_PAUSE]            = 0x10,
+	[SCNT_RX_CONTROL]          = 0x11,
+	[SCNT_RX_LONG]             = 0x12,
+	[SCNT_RX_CAT_DROP]         = 0x13,
+	[SCNT_RX_RED_PRIO_0]       = 0x14,
+	[SCNT_RX_RED_PRIO_1]       = 0x15,
+	[SCNT_RX_RED_PRIO_2]       = 0x16,
+	[SCNT_RX_RED_PRIO_3]       = 0x17,
+	[SCNT_RX_RED_PRIO_4]       = 0x18,
+	[SCNT_RX_RED_PRIO_5]       = 0x19,
+	[SCNT_RX_RED_PRIO_6]       = 0x1a,
+	[SCNT_RX_RED_PRIO_7]       = 0x1b,
+	[SCNT_RX_YELLOW_PRIO_0]    = 0x1c,
+	[SCNT_RX_YELLOW_PRIO_1]    = 0x1d,
+	[SCNT_RX_YELLOW_PRIO_2]    = 0x1e,
+	[SCNT_RX_YELLOW_PRIO_3]    = 0x1f,
+	[SCNT_RX_YELLOW_PRIO_4]    = 0x20,
+	[SCNT_RX_YELLOW_PRIO_5]    = 0x21,
+	[SCNT_RX_YELLOW_PRIO_6]    = 0x22,
+	[SCNT_RX_YELLOW_PRIO_7]    = 0x23,
+	[SCNT_RX_GREEN_PRIO_0]     = 0x24,
+	[SCNT_RX_GREEN_PRIO_1]     = 0x25,
+	[SCNT_RX_GREEN_PRIO_2]     = 0x26,
+	[SCNT_RX_GREEN_PRIO_3]     = 0x27,
+	[SCNT_RX_GREEN_PRIO_4]     = 0x28,
+	[SCNT_RX_GREEN_PRIO_5]     = 0x29,
+	[SCNT_RX_GREEN_PRIO_6]     = 0x2a,
+	[SCNT_RX_GREEN_PRIO_7]     = 0x2b,
+	[SCNT_RX_ASSEMBLY_ERR]     = 0x2c,
+	[SCNT_RX_SMD_ERR]          = 0x2d,
+	[SCNT_RX_ASSEMBLY_OK]      = 0x2e,
+	[SCNT_RX_MERGE_FRAG]       = 0x2f,
+	[SCNT_RX_PMAC_OCT]         = 0x30,
+	[SCNT_RX_PMAC_UC]          = 0x31,
+	[SCNT_RX_PMAC_MC]          = 0x32,
+	[SCNT_RX_PMAC_BC]          = 0x33,
+	[SCNT_RX_PMAC_SHORT]       = 0x34,
+	[SCNT_RX_PMAC_FRAG]        = 0x35,
+	[SCNT_RX_PMAC_JABBER]      = 0x36,
+	[SCNT_RX_PMAC_CRC]         = 0x37,
+	[SCNT_RX_PMAC_SYMBOL_ERR]  = 0x38,
+	[SCNT_RX_PMAC_SZ_64]       = 0x39,
+	[SCNT_RX_PMAC_SZ_65_127]   = 0x3a,
+	[SCNT_RX_PMAC_SZ_128_255]  = 0x3b,
+	[SCNT_RX_PMAC_SZ_256_511]  = 0x3c,
+	[SCNT_RX_PMAC_SZ_512_1023] = 0x3d,
+	[SCNT_RX_PMAC_SZ_1024_1526] = 0x3e,
+	[SCNT_RX_PMAC_SZ_JUMBO]    = 0x3f,
+	[SCNT_RX_PMAC_PAUSE]       = 0x40,
+	[SCNT_RX_PMAC_CONTROL]     = 0x41,
+	[SCNT_RX_PMAC_LONG]        = 0x42,
+	[SCNT_TX_OCT]              = 0x80,
+	[SCNT_TX_UC]               = 0x81,
+	[SCNT_TX_MC]               = 0x82,
+	[SCNT_TX_BC]               = 0x83,
+	[SCNT_TX_COL]              = 0x84,
+	[SCNT_TX_DROP]             = 0x85,
+	[SCNT_TX_PAUSE]            = 0x86,
+	[SCNT_TX_SZ_64]            = 0x87,
+	[SCNT_TX_SZ_65_127]        = 0x88,
+	[SCNT_TX_SZ_128_255]       = 0x89,
+	[SCNT_TX_SZ_256_511]       = 0x8a,
+	[SCNT_TX_SZ_512_1023]      = 0x8b,
+	[SCNT_TX_SZ_1024_1526]     = 0x8c,
+	[SCNT_TX_SZ_JUMBO]         = 0x8d,
+	[SCNT_TX_YELLOW_PRIO_0]    = 0x8e,
+	[SCNT_TX_YELLOW_PRIO_1]    = 0x8f,
+	[SCNT_TX_YELLOW_PRIO_2]    = 0x90,
+	[SCNT_TX_YELLOW_PRIO_3]    = 0x91,
+	[SCNT_TX_YELLOW_PRIO_4]    = 0x92,
+	[SCNT_TX_YELLOW_PRIO_5]    = 0x93,
+	[SCNT_TX_YELLOW_PRIO_6]    = 0x94,
+	[SCNT_TX_YELLOW_PRIO_7]    = 0x95,
+	[SCNT_TX_GREEN_PRIO_0]     = 0x96,
+	[SCNT_TX_GREEN_PRIO_1]     = 0x97,
+	[SCNT_TX_GREEN_PRIO_2]     = 0x98,
+	[SCNT_TX_GREEN_PRIO_3]     = 0x99,
+	[SCNT_TX_GREEN_PRIO_4]     = 0x9a,
+	[SCNT_TX_GREEN_PRIO_5]     = 0x9b,
+	[SCNT_TX_GREEN_PRIO_6]     = 0x9c,
+	[SCNT_TX_GREEN_PRIO_7]     = 0x9d,
+	[SCNT_TX_AGED]             = 0x9e,
+	[SCNT_TX_LLCT]             = 0x9f,
+	[SCNT_TX_CT]               = 0xa0,
+	[SCNT_TX_BUFDROP]          = 0xa1,
+	[SCNT_TX_MM_HOLD]          = 0xa2,
+	[SCNT_TX_MERGE_FRAG]       = 0xa3,
+	[SCNT_TX_PMAC_OCT]         = 0xa4,
+	[SCNT_TX_PMAC_UC]          = 0xa5,
+	[SCNT_TX_PMAC_MC]          = 0xa6,
+	[SCNT_TX_PMAC_BC]          = 0xa7,
+	[SCNT_TX_PMAC_PAUSE]       = 0xa8,
+	[SCNT_TX_PMAC_SZ_64]       = 0xa9,
+	[SCNT_TX_PMAC_SZ_65_127]   = 0xaa,
+	[SCNT_TX_PMAC_SZ_128_255]  = 0xab,
+	[SCNT_TX_PMAC_SZ_256_511]  = 0xac,
+	[SCNT_TX_PMAC_SZ_512_1023] = 0xad,
+	[SCNT_TX_PMAC_SZ_1024_1526] = 0xae,
+	[SCNT_TX_PMAC_SZ_JUMBO]    = 0xaf,
+	[SCNT_DR_LOCAL]            = 0x100,
+	[SCNT_DR_TAIL]             = 0x101,
+	[SCNT_DR_YELLOW_PRIO_0]    = 0x102,
+	[SCNT_DR_YELLOW_PRIO_1]    = 0x103,
+	[SCNT_DR_YELLOW_PRIO_2]    = 0x104,
+	[SCNT_DR_YELLOW_PRIO_3]    = 0x105,
+	[SCNT_DR_YELLOW_PRIO_4]    = 0x106,
+	[SCNT_DR_YELLOW_PRIO_5]    = 0x107,
+	[SCNT_DR_YELLOW_PRIO_6]    = 0x108,
+	[SCNT_DR_YELLOW_PRIO_7]    = 0x109,
+	[SCNT_DR_GREEN_PRIO_0]     = 0x10a,
+	[SCNT_DR_GREEN_PRIO_1]     = 0x10b,
+	[SCNT_DR_GREEN_PRIO_2]     = 0x10c,
+	[SCNT_DR_GREEN_PRIO_3]     = 0x10d,
+	[SCNT_DR_GREEN_PRIO_4]     = 0x10e,
+	[SCNT_DR_GREEN_PRIO_5]     = 0x10f,
+	[SCNT_DR_GREEN_PRIO_6]     = 0x110,
+	[SCNT_DR_GREEN_PRIO_7]     = 0x111,
+};
+
+struct lan9645x_ethtool_stat {
+	char name[ETH_GSTRING_LEN];
+	u16 idx;
+};
+
+static const struct lan9645x_ethtool_stat lan9645x_port_ethtool_stats[] = {
+	{ "rx_cat_drop",        SCNT_RX_CAT_DROP },
+	{ "rx_red_prio_0",      SCNT_RX_RED_PRIO_0 },
+	{ "rx_red_prio_1",      SCNT_RX_RED_PRIO_1 },
+	{ "rx_red_prio_2",      SCNT_RX_RED_PRIO_2 },
+	{ "rx_red_prio_3",      SCNT_RX_RED_PRIO_3 },
+	{ "rx_red_prio_4",      SCNT_RX_RED_PRIO_4 },
+	{ "rx_red_prio_5",      SCNT_RX_RED_PRIO_5 },
+	{ "rx_red_prio_6",      SCNT_RX_RED_PRIO_6 },
+	{ "rx_red_prio_7",      SCNT_RX_RED_PRIO_7 },
+	{ "rx_yellow_prio_0",   SCNT_RX_YELLOW_PRIO_0 },
+	{ "rx_yellow_prio_1",   SCNT_RX_YELLOW_PRIO_1 },
+	{ "rx_yellow_prio_2",   SCNT_RX_YELLOW_PRIO_2 },
+	{ "rx_yellow_prio_3",   SCNT_RX_YELLOW_PRIO_3 },
+	{ "rx_yellow_prio_4",   SCNT_RX_YELLOW_PRIO_4 },
+	{ "rx_yellow_prio_5",   SCNT_RX_YELLOW_PRIO_5 },
+	{ "rx_yellow_prio_6",   SCNT_RX_YELLOW_PRIO_6 },
+	{ "rx_yellow_prio_7",   SCNT_RX_YELLOW_PRIO_7 },
+	{ "rx_green_prio_0",    SCNT_RX_GREEN_PRIO_0 },
+	{ "rx_green_prio_1",    SCNT_RX_GREEN_PRIO_1 },
+	{ "rx_green_prio_2",    SCNT_RX_GREEN_PRIO_2 },
+	{ "rx_green_prio_3",    SCNT_RX_GREEN_PRIO_3 },
+	{ "rx_green_prio_4",    SCNT_RX_GREEN_PRIO_4 },
+	{ "rx_green_prio_5",    SCNT_RX_GREEN_PRIO_5 },
+	{ "rx_green_prio_6",    SCNT_RX_GREEN_PRIO_6 },
+	{ "rx_green_prio_7",    SCNT_RX_GREEN_PRIO_7 },
+	{ "tx_drop",            SCNT_TX_DROP },
+	{ "tx_yellow_prio_0",   SCNT_TX_YELLOW_PRIO_0 },
+	{ "tx_yellow_prio_1",   SCNT_TX_YELLOW_PRIO_1 },
+	{ "tx_yellow_prio_2",   SCNT_TX_YELLOW_PRIO_2 },
+	{ "tx_yellow_prio_3",   SCNT_TX_YELLOW_PRIO_3 },
+	{ "tx_yellow_prio_4",   SCNT_TX_YELLOW_PRIO_4 },
+	{ "tx_yellow_prio_5",   SCNT_TX_YELLOW_PRIO_5 },
+	{ "tx_yellow_prio_6",   SCNT_TX_YELLOW_PRIO_6 },
+	{ "tx_yellow_prio_7",   SCNT_TX_YELLOW_PRIO_7 },
+	{ "tx_green_prio_0",    SCNT_TX_GREEN_PRIO_0 },
+	{ "tx_green_prio_1",    SCNT_TX_GREEN_PRIO_1 },
+	{ "tx_green_prio_2",    SCNT_TX_GREEN_PRIO_2 },
+	{ "tx_green_prio_3",    SCNT_TX_GREEN_PRIO_3 },
+	{ "tx_green_prio_4",    SCNT_TX_GREEN_PRIO_4 },
+	{ "tx_green_prio_5",    SCNT_TX_GREEN_PRIO_5 },
+	{ "tx_green_prio_6",    SCNT_TX_GREEN_PRIO_6 },
+	{ "tx_green_prio_7",    SCNT_TX_GREEN_PRIO_7 },
+	{ "tx_aged",            SCNT_TX_AGED },
+	{ "tx_bufdrop",         SCNT_TX_BUFDROP },
+	{ "dr_local",           SCNT_DR_LOCAL },
+	{ "dr_tail",            SCNT_DR_TAIL },
+	{ "dr_yellow_prio_0",   SCNT_DR_YELLOW_PRIO_0 },
+	{ "dr_yellow_prio_1",   SCNT_DR_YELLOW_PRIO_1 },
+	{ "dr_yellow_prio_2",   SCNT_DR_YELLOW_PRIO_2 },
+	{ "dr_yellow_prio_3",   SCNT_DR_YELLOW_PRIO_3 },
+	{ "dr_yellow_prio_4",   SCNT_DR_YELLOW_PRIO_4 },
+	{ "dr_yellow_prio_5",   SCNT_DR_YELLOW_PRIO_5 },
+	{ "dr_yellow_prio_6",   SCNT_DR_YELLOW_PRIO_6 },
+	{ "dr_yellow_prio_7",   SCNT_DR_YELLOW_PRIO_7 },
+	{ "dr_green_prio_0",    SCNT_DR_GREEN_PRIO_0 },
+	{ "dr_green_prio_1",    SCNT_DR_GREEN_PRIO_1 },
+	{ "dr_green_prio_2",    SCNT_DR_GREEN_PRIO_2 },
+	{ "dr_green_prio_3",    SCNT_DR_GREEN_PRIO_3 },
+	{ "dr_green_prio_4",    SCNT_DR_GREEN_PRIO_4 },
+	{ "dr_green_prio_5",    SCNT_DR_GREEN_PRIO_5 },
+	{ "dr_green_prio_6",    SCNT_DR_GREEN_PRIO_6 },
+	{ "dr_green_prio_7",    SCNT_DR_GREEN_PRIO_7 },
+};
+
+static const struct lan9645x_view_stats lan9645x_view_stat_cfgs[] = {
+	[LAN9645X_STAT_PORTS] = {
+		.name = "ports",
+		.type = LAN9645X_STAT_PORTS,
+		.layout = lan9645x_port_stats_layout,
+		.num_cnts = ARRAY_SIZE(lan9645x_port_stats_layout),
+		.num_indexes = NUM_PHYS_PORTS,
+	},
+};
+
+static int __lan9645x_stats_view_idx_hw_read(struct lan9645x *lan9645x,
+					     enum lan9645x_view_stat_type vtype,
+					     int idx)
+{
+	struct lan9645x_stat_region region;
+	struct lan9645x_view_stats *vstats;
+	u32 *region_buf;
+	int err;
+
+	lockdep_assert_held(&lan9645x->stats->hw_lock);
+
+	vstats = lan9645x_get_vstats(lan9645x, vtype);
+	if (!vstats || idx < 0 || idx >= vstats->num_indexes)
+		return -EINVAL;
+
+	lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(idx), lan9645x, SYS_STAT_CFG);
+
+	region_buf = &vstats->buf[vstats->num_cnts * idx];
+
+	/* Each region for this index contains counters which are at sequential
+	 * addresses, so we can use bulk reads to ease lock pressure a bit.
+	 */
+	for (int r = 0; r < vstats->num_regions; r++) {
+		region = vstats->regions[r];
+		err = lan_bulk_rd(&region_buf[region.cnts_base_idx], region.cnt,
+				  lan9645x, SYS_CNT(region.base_offset));
+		if (err) {
+			dev_err(lan9645x->dev,
+				"stats bulk read err vtype=%d idx=%d err=%d\n",
+				vtype, idx, err);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static void
+__lan9645x_stats_view_idx_transfer(struct lan9645x *lan9645x,
+				   enum lan9645x_view_stat_type vtype, int idx)
+{
+	struct lan9645x_view_stats *vstats;
+	u64 *idx_counters;
+	u32 *region_buf;
+	int cntr;
+
+	lockdep_assert_held(&lan9645x->stats->sw_lock);
+
+	vstats = lan9645x_get_vstats(lan9645x, vtype);
+	if (!vstats || idx < 0 || idx >= vstats->num_indexes)
+		return;
+
+	idx_counters = STATS_INDEX(vstats, idx);
+	region_buf = &vstats->buf[vstats->num_cnts * idx];
+
+	for (cntr = 0; cntr < vstats->num_cnts; cntr++)
+		lan9645x_stats_add_cnt(&idx_counters[cntr], region_buf[cntr]);
+}
+
+static void __lan9645x_stats_view_idx_update(struct lan9645x *lan9645x,
+					     enum lan9645x_view_stat_type vtype,
+					     int idx)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+
+	lockdep_assert_held(&s->hw_lock);
+
+	if (!__lan9645x_stats_view_idx_hw_read(lan9645x, vtype, idx)) {
+		spin_lock(&s->sw_lock);
+		__lan9645x_stats_view_idx_transfer(lan9645x, vtype, idx);
+		spin_unlock(&s->sw_lock);
+	}
+}
+
+static u64 *lan9645x_stats_view_idx_update(struct lan9645x *lan9645x,
+					   enum lan9645x_view_stat_type vtype,
+					   int idx)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+
+	mutex_lock(&s->hw_lock);
+	__lan9645x_stats_view_idx_update(lan9645x, vtype, idx);
+	mutex_unlock(&s->hw_lock);
+
+	return STAT_COUNTERS(lan9645x, vtype, idx);
+}
+
+static void lan9645x_stats_view_update(struct lan9645x *lan9645x,
+				       enum lan9645x_view_stat_type vtype)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	struct lan9645x_view_stats *vstats;
+	int idx;
+
+	vstats = lan9645x_get_vstats(lan9645x, vtype);
+	if (!vstats)
+		return;
+
+	switch (vtype) {
+	case LAN9645X_STAT_PORTS:
+		mutex_lock(&s->hw_lock);
+		for (idx = 0; idx < vstats->num_indexes; idx++) {
+			if (dsa_is_unused_port(lan9645x->ds, idx))
+				continue;
+			__lan9645x_stats_view_idx_update(lan9645x, vtype, idx);
+		}
+		mutex_unlock(&s->hw_lock);
+		return;
+	default:
+		return;
+	}
+}
+
+static void lan9645x_stats_update(struct lan9645x *lan9645x)
+{
+	for (int vtype = 0; vtype < LAN9645X_STAT_NUM; vtype++)
+		lan9645x_stats_view_update(lan9645x, vtype);
+}
+
+void lan9645x_stats_get_strings(struct lan9645x *lan9645x, int port,
+				u32 stringset, u8 *data)
+{
+	int i;
+
+	if (stringset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(lan9645x_port_ethtool_stats); i++)
+		memcpy(data + i * ETH_GSTRING_LEN,
+		       lan9645x_port_ethtool_stats[i].name, ETH_GSTRING_LEN);
+}
+
+int lan9645x_stats_get_sset_count(struct lan9645x *lan9645x, int port, int sset)
+{
+	if (sset != ETH_SS_STATS)
+		return -EOPNOTSUPP;
+
+	return ARRAY_SIZE(lan9645x_port_ethtool_stats);
+}
+
+void lan9645x_stats_get_ethtool_stats(struct lan9645x *lan9645x, int port,
+				      u64 *data)
+{
+	struct lan9645x_stats *stats = lan9645x->stats;
+	u64 *c;
+	int i;
+
+	c = lan9645x_stats_view_idx_update(lan9645x, LAN9645X_STAT_PORTS, port);
+
+	spin_lock(&stats->sw_lock);
+	for (i = 0; i < ARRAY_SIZE(lan9645x_port_ethtool_stats); i++)
+		*data++ = c[lan9645x_port_ethtool_stats[i].idx];
+	spin_unlock(&stats->sw_lock);
+}
+
+static u64 *lan9645x_stats_port_update(struct lan9645x *lan9645x, int port)
+{
+	return lan9645x_stats_view_idx_update(lan9645x, LAN9645X_STAT_PORTS,
+					      port);
+}
+
+void lan9645x_stats_get_eth_mac_stats(struct lan9645x *lan9645x, int port,
+				      struct ethtool_eth_mac_stats *m)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = lan9645x_stats_port_update(lan9645x, port);
+
+	spin_lock(&s->sw_lock);
+
+	switch (m->src) {
+	case ETHTOOL_MAC_STATS_SRC_EMAC:
+		m->FramesTransmittedOK = c[SCNT_TX_UC] +
+					 c[SCNT_TX_MC] +
+					 c[SCNT_TX_BC];
+		m->SingleCollisionFrames = c[SCNT_TX_COL];
+		m->FramesReceivedOK = c[SCNT_RX_UC] +
+				      c[SCNT_RX_MC] +
+				      c[SCNT_RX_BC];
+		m->FrameCheckSequenceErrors = c[SCNT_RX_CRC];
+		m->OctetsTransmittedOK = c[SCNT_TX_OCT];
+		m->OctetsReceivedOK = c[SCNT_RX_OCT];
+		m->MulticastFramesXmittedOK = c[SCNT_TX_MC];
+		m->BroadcastFramesXmittedOK = c[SCNT_TX_BC];
+		m->MulticastFramesReceivedOK = c[SCNT_RX_MC];
+		m->BroadcastFramesReceivedOK = c[SCNT_RX_BC];
+		m->InRangeLengthErrors = c[SCNT_RX_FRAG] +
+					 c[SCNT_RX_JABBER] +
+					 c[SCNT_RX_CRC];
+		m->OutOfRangeLengthField = c[SCNT_RX_SHORT] +
+					   c[SCNT_RX_LONG];
+		m->FrameTooLongErrors = c[SCNT_RX_LONG];
+		break;
+	case ETHTOOL_MAC_STATS_SRC_PMAC:
+		m->FramesTransmittedOK = c[SCNT_TX_PMAC_UC] +
+					 c[SCNT_TX_PMAC_MC] +
+					 c[SCNT_TX_PMAC_BC];
+		m->FramesReceivedOK = c[SCNT_RX_PMAC_UC] +
+				      c[SCNT_RX_PMAC_MC] +
+				      c[SCNT_RX_PMAC_BC];
+		m->FrameCheckSequenceErrors = c[SCNT_RX_PMAC_CRC];
+		m->OctetsTransmittedOK = c[SCNT_TX_PMAC_OCT];
+		m->OctetsReceivedOK = c[SCNT_RX_PMAC_OCT];
+		m->MulticastFramesXmittedOK = c[SCNT_TX_PMAC_MC];
+		m->BroadcastFramesXmittedOK = c[SCNT_TX_PMAC_BC];
+		m->MulticastFramesReceivedOK = c[SCNT_RX_PMAC_MC];
+		m->BroadcastFramesReceivedOK = c[SCNT_RX_PMAC_BC];
+		m->InRangeLengthErrors = c[SCNT_RX_PMAC_FRAG] +
+					 c[SCNT_RX_PMAC_JABBER] +
+					 c[SCNT_RX_PMAC_CRC];
+		m->OutOfRangeLengthField = c[SCNT_RX_PMAC_SHORT] +
+					   c[SCNT_RX_PMAC_LONG];
+		m->FrameTooLongErrors = c[SCNT_RX_PMAC_LONG];
+		break;
+	default:
+		m->FramesTransmittedOK = c[SCNT_TX_UC] +
+					 c[SCNT_TX_MC] +
+					 c[SCNT_TX_BC] +
+					 c[SCNT_TX_PMAC_UC] +
+					 c[SCNT_TX_PMAC_MC] +
+					 c[SCNT_TX_PMAC_BC];
+		m->SingleCollisionFrames = c[SCNT_TX_COL];
+		m->FramesReceivedOK = c[SCNT_RX_UC] +
+				      c[SCNT_RX_MC] +
+				      c[SCNT_RX_BC] +
+				      c[SCNT_RX_PMAC_UC] +
+				      c[SCNT_RX_PMAC_MC] +
+				      c[SCNT_RX_PMAC_BC];
+		m->FrameCheckSequenceErrors = c[SCNT_RX_CRC] +
+					      c[SCNT_RX_PMAC_CRC];
+		m->OctetsTransmittedOK = c[SCNT_TX_OCT] +
+					 c[SCNT_TX_PMAC_OCT];
+		m->OctetsReceivedOK = c[SCNT_RX_OCT] +
+				      c[SCNT_RX_PMAC_OCT];
+		m->MulticastFramesXmittedOK = c[SCNT_TX_MC] +
+					      c[SCNT_TX_PMAC_MC];
+		m->BroadcastFramesXmittedOK = c[SCNT_TX_BC] +
+					      c[SCNT_TX_PMAC_BC];
+		m->MulticastFramesReceivedOK = c[SCNT_RX_MC] +
+					       c[SCNT_RX_PMAC_MC];
+		m->BroadcastFramesReceivedOK = c[SCNT_RX_BC] +
+					       c[SCNT_RX_PMAC_BC];
+		m->InRangeLengthErrors = c[SCNT_RX_FRAG] +
+					 c[SCNT_RX_JABBER] +
+					 c[SCNT_RX_CRC] +
+					 c[SCNT_RX_PMAC_FRAG] +
+					 c[SCNT_RX_PMAC_JABBER] +
+					 c[SCNT_RX_PMAC_CRC];
+		m->OutOfRangeLengthField = c[SCNT_RX_SHORT] +
+					   c[SCNT_RX_LONG] +
+					   c[SCNT_RX_PMAC_SHORT] +
+					   c[SCNT_RX_PMAC_LONG];
+		m->FrameTooLongErrors = c[SCNT_RX_LONG] +
+					c[SCNT_RX_PMAC_LONG];
+		break;
+	}
+
+	spin_unlock(&s->sw_lock);
+}
+
+static const struct ethtool_rmon_hist_range lan9645x_rmon_ranges[] = {
+	{    64,     64 },
+	{   65,    127 },
+	{  128,    255 },
+	{  256,    511 },
+	{  512,   1023 },
+	{ 1024,   1526 },
+	{ 1527, 0xffff },
+	{}
+};
+
+void
+lan9645x_stats_get_rmon_stats(struct lan9645x *lan9645x, int port,
+			      struct ethtool_rmon_stats *r,
+			      const struct ethtool_rmon_hist_range **ranges)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = lan9645x_stats_port_update(lan9645x, port);
+
+	spin_lock(&s->sw_lock);
+
+	switch (r->src) {
+	case ETHTOOL_MAC_STATS_SRC_EMAC:
+		r->undersize_pkts = c[SCNT_RX_SHORT];
+		r->oversize_pkts = c[SCNT_RX_LONG];
+		r->fragments = c[SCNT_RX_FRAG];
+		r->jabbers = c[SCNT_RX_JABBER];
+		r->hist[0] = c[SCNT_RX_SZ_64];
+		r->hist[1] = c[SCNT_RX_SZ_65_127];
+		r->hist[2] = c[SCNT_RX_SZ_128_255];
+		r->hist[3] = c[SCNT_RX_SZ_256_511];
+		r->hist[4] = c[SCNT_RX_SZ_512_1023];
+		r->hist[5] = c[SCNT_RX_SZ_1024_1526];
+		r->hist[6] = c[SCNT_RX_SZ_JUMBO];
+		r->hist_tx[0] = c[SCNT_TX_SZ_64];
+		r->hist_tx[1] = c[SCNT_TX_SZ_65_127];
+		r->hist_tx[2] = c[SCNT_TX_SZ_128_255];
+		r->hist_tx[3] = c[SCNT_TX_SZ_256_511];
+		r->hist_tx[4] = c[SCNT_TX_SZ_512_1023];
+		r->hist_tx[5] = c[SCNT_TX_SZ_1024_1526];
+		r->hist_tx[6] = c[SCNT_TX_SZ_JUMBO];
+		break;
+	case ETHTOOL_MAC_STATS_SRC_PMAC:
+		r->undersize_pkts = c[SCNT_RX_PMAC_SHORT];
+		r->oversize_pkts = c[SCNT_RX_PMAC_LONG];
+		r->fragments = c[SCNT_RX_PMAC_FRAG];
+		r->jabbers = c[SCNT_RX_PMAC_JABBER];
+		r->hist[0] = c[SCNT_RX_PMAC_SZ_64];
+		r->hist[1] = c[SCNT_RX_PMAC_SZ_65_127];
+		r->hist[2] = c[SCNT_RX_PMAC_SZ_128_255];
+		r->hist[3] = c[SCNT_RX_PMAC_SZ_256_511];
+		r->hist[4] = c[SCNT_RX_PMAC_SZ_512_1023];
+		r->hist[5] = c[SCNT_RX_PMAC_SZ_1024_1526];
+		r->hist[6] = c[SCNT_RX_PMAC_SZ_JUMBO];
+		r->hist_tx[0] = c[SCNT_TX_PMAC_SZ_64];
+		r->hist_tx[1] = c[SCNT_TX_PMAC_SZ_65_127];
+		r->hist_tx[2] = c[SCNT_TX_PMAC_SZ_128_255];
+		r->hist_tx[3] = c[SCNT_TX_PMAC_SZ_256_511];
+		r->hist_tx[4] = c[SCNT_TX_PMAC_SZ_512_1023];
+		r->hist_tx[5] = c[SCNT_TX_PMAC_SZ_1024_1526];
+		r->hist_tx[6] = c[SCNT_TX_PMAC_SZ_JUMBO];
+		break;
+	default:
+		r->undersize_pkts = c[SCNT_RX_SHORT] +
+				    c[SCNT_RX_PMAC_SHORT];
+		r->oversize_pkts = c[SCNT_RX_LONG] +
+				   c[SCNT_RX_PMAC_LONG];
+		r->fragments = c[SCNT_RX_FRAG] +
+			       c[SCNT_RX_PMAC_FRAG];
+		r->jabbers = c[SCNT_RX_JABBER] +
+			     c[SCNT_RX_PMAC_JABBER];
+		r->hist[0] = c[SCNT_RX_SZ_64] +
+			     c[SCNT_RX_PMAC_SZ_64];
+		r->hist[1] = c[SCNT_RX_SZ_65_127] +
+			     c[SCNT_RX_PMAC_SZ_65_127];
+		r->hist[2] = c[SCNT_RX_SZ_128_255] +
+			     c[SCNT_RX_PMAC_SZ_128_255];
+		r->hist[3] = c[SCNT_RX_SZ_256_511] +
+			     c[SCNT_RX_PMAC_SZ_256_511];
+		r->hist[4] = c[SCNT_RX_SZ_512_1023] +
+			     c[SCNT_RX_PMAC_SZ_512_1023];
+		r->hist[5] = c[SCNT_RX_SZ_1024_1526] +
+			     c[SCNT_RX_PMAC_SZ_1024_1526];
+		r->hist[6] = c[SCNT_RX_SZ_JUMBO] +
+			     c[SCNT_RX_PMAC_SZ_JUMBO];
+		r->hist_tx[0] = c[SCNT_TX_SZ_64] +
+				c[SCNT_TX_PMAC_SZ_64];
+		r->hist_tx[1] = c[SCNT_TX_SZ_65_127] +
+				c[SCNT_TX_PMAC_SZ_65_127];
+		r->hist_tx[2] = c[SCNT_TX_SZ_128_255] +
+				c[SCNT_TX_PMAC_SZ_128_255];
+		r->hist_tx[3] = c[SCNT_TX_SZ_256_511] +
+				c[SCNT_TX_PMAC_SZ_256_511];
+		r->hist_tx[4] = c[SCNT_TX_SZ_512_1023] +
+				c[SCNT_TX_PMAC_SZ_512_1023];
+		r->hist_tx[5] = c[SCNT_TX_SZ_1024_1526] +
+				c[SCNT_TX_PMAC_SZ_1024_1526];
+		r->hist_tx[6] = c[SCNT_TX_SZ_JUMBO] +
+				c[SCNT_TX_PMAC_SZ_JUMBO];
+		break;
+	}
+
+	spin_unlock(&s->sw_lock);
+
+	*ranges = lan9645x_rmon_ranges;
+}
+
+/* Called in atomic context */
+void lan9645x_stats_get_stats64(struct lan9645x *lan9645x, int port,
+				struct rtnl_link_stats64 *stats)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = STAT_COUNTERS(lan9645x, LAN9645X_STAT_PORTS, port);
+
+	spin_lock(&s->sw_lock);
+
+	stats->rx_bytes = c[SCNT_RX_OCT] + c[SCNT_RX_PMAC_OCT];
+
+	stats->rx_packets = c[SCNT_RX_SHORT] +
+			    c[SCNT_RX_FRAG] +
+			    c[SCNT_RX_JABBER] +
+			    c[SCNT_RX_SZ_64] +
+			    c[SCNT_RX_SZ_65_127] +
+			    c[SCNT_RX_SZ_128_255] +
+			    c[SCNT_RX_SZ_256_511] +
+			    c[SCNT_RX_SZ_512_1023] +
+			    c[SCNT_RX_SZ_1024_1526] +
+			    c[SCNT_RX_SZ_JUMBO] +
+			    c[SCNT_RX_LONG] +
+			    c[SCNT_RX_PMAC_SHORT] +
+			    c[SCNT_RX_PMAC_FRAG] +
+			    c[SCNT_RX_PMAC_JABBER] +
+			    c[SCNT_RX_PMAC_SZ_64] +
+			    c[SCNT_RX_PMAC_SZ_65_127] +
+			    c[SCNT_RX_PMAC_SZ_128_255] +
+			    c[SCNT_RX_PMAC_SZ_256_511] +
+			    c[SCNT_RX_PMAC_SZ_512_1023] +
+			    c[SCNT_RX_PMAC_SZ_1024_1526] +
+			    c[SCNT_RX_PMAC_SZ_JUMBO];
+
+	stats->multicast = c[SCNT_RX_MC] + c[SCNT_RX_PMAC_MC];
+
+	stats->rx_errors = c[SCNT_RX_SHORT] +
+			   c[SCNT_RX_FRAG] +
+			   c[SCNT_RX_JABBER] +
+			   c[SCNT_RX_CRC] +
+			   c[SCNT_RX_SYMBOL_ERR] +
+			   c[SCNT_RX_LONG] +
+			   c[SCNT_RX_PMAC_SHORT] +
+			   c[SCNT_RX_PMAC_FRAG] +
+			   c[SCNT_RX_PMAC_JABBER] +
+			   c[SCNT_RX_PMAC_CRC] +
+			   c[SCNT_RX_PMAC_SYMBOL_ERR] +
+			   c[SCNT_RX_PMAC_LONG];
+
+	stats->rx_dropped = c[SCNT_RX_LONG] +
+			    c[SCNT_DR_LOCAL] +
+			    c[SCNT_DR_TAIL] +
+			    c[SCNT_RX_CAT_DROP] +
+			    c[SCNT_RX_RED_PRIO_0] +
+			    c[SCNT_RX_RED_PRIO_1] +
+			    c[SCNT_RX_RED_PRIO_2] +
+			    c[SCNT_RX_RED_PRIO_3] +
+			    c[SCNT_RX_RED_PRIO_4] +
+			    c[SCNT_RX_RED_PRIO_5] +
+			    c[SCNT_RX_RED_PRIO_6] +
+			    c[SCNT_RX_RED_PRIO_7];
+
+	for (int i = 0; i < LAN9645X_NUM_TC; i++) {
+		stats->rx_dropped += c[SCNT_DR_YELLOW_PRIO_0 + i] +
+				     c[SCNT_DR_GREEN_PRIO_0 + i];
+	}
+
+	stats->tx_bytes = c[SCNT_TX_OCT] + c[SCNT_TX_PMAC_OCT];
+
+	stats->tx_packets = c[SCNT_TX_SZ_64] +
+			    c[SCNT_TX_SZ_65_127] +
+			    c[SCNT_TX_SZ_128_255] +
+			    c[SCNT_TX_SZ_256_511] +
+			    c[SCNT_TX_SZ_512_1023] +
+			    c[SCNT_TX_SZ_1024_1526] +
+			    c[SCNT_TX_SZ_JUMBO] +
+			    c[SCNT_TX_PMAC_SZ_64] +
+			    c[SCNT_TX_PMAC_SZ_65_127] +
+			    c[SCNT_TX_PMAC_SZ_128_255] +
+			    c[SCNT_TX_PMAC_SZ_256_511] +
+			    c[SCNT_TX_PMAC_SZ_512_1023] +
+			    c[SCNT_TX_PMAC_SZ_1024_1526] +
+			    c[SCNT_TX_PMAC_SZ_JUMBO];
+
+	stats->tx_dropped = c[SCNT_TX_DROP] +
+			    c[SCNT_TX_AGED] +
+			    c[SCNT_TX_BUFDROP];
+
+	stats->collisions = c[SCNT_TX_COL];
+
+	spin_unlock(&s->sw_lock);
+}
+
+void lan9645x_stats_get_eth_phy_stats(struct lan9645x *lan9645x, int port,
+				      struct ethtool_eth_phy_stats *p)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = lan9645x_stats_port_update(lan9645x, port);
+
+	spin_lock(&s->sw_lock);
+
+	switch (p->src) {
+	case ETHTOOL_MAC_STATS_SRC_EMAC:
+		p->SymbolErrorDuringCarrier = c[SCNT_RX_SYMBOL_ERR];
+		break;
+	case ETHTOOL_MAC_STATS_SRC_PMAC:
+		p->SymbolErrorDuringCarrier = c[SCNT_RX_PMAC_SYMBOL_ERR];
+		break;
+	default:
+		p->SymbolErrorDuringCarrier = c[SCNT_RX_SYMBOL_ERR] +
+					      c[SCNT_RX_PMAC_SYMBOL_ERR];
+		break;
+	}
+
+	spin_unlock(&s->sw_lock);
+}
+
+void
+lan9645x_stats_get_eth_ctrl_stats(struct lan9645x *lan9645x, int port,
+				  struct ethtool_eth_ctrl_stats *ctrl)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = lan9645x_stats_port_update(lan9645x, port);
+
+	spin_lock(&s->sw_lock);
+
+	switch (ctrl->src) {
+	case ETHTOOL_MAC_STATS_SRC_EMAC:
+		ctrl->MACControlFramesReceived = c[SCNT_RX_CONTROL];
+		break;
+	case ETHTOOL_MAC_STATS_SRC_PMAC:
+		ctrl->MACControlFramesReceived = c[SCNT_RX_PMAC_CONTROL];
+		break;
+	default:
+		ctrl->MACControlFramesReceived = c[SCNT_RX_CONTROL] +
+						 c[SCNT_RX_PMAC_CONTROL];
+		break;
+	}
+
+	spin_unlock(&s->sw_lock);
+}
+
+void lan9645x_stats_get_pause_stats(struct lan9645x *lan9645x, int port,
+				    struct ethtool_pause_stats *ps)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = lan9645x_stats_port_update(lan9645x, port);
+
+	spin_lock(&s->sw_lock);
+
+	switch (ps->src) {
+	case ETHTOOL_MAC_STATS_SRC_EMAC:
+		ps->tx_pause_frames = c[SCNT_TX_PAUSE];
+		ps->rx_pause_frames = c[SCNT_RX_PAUSE];
+		break;
+	case ETHTOOL_MAC_STATS_SRC_PMAC:
+		ps->tx_pause_frames = c[SCNT_TX_PMAC_PAUSE];
+		ps->rx_pause_frames = c[SCNT_RX_PMAC_PAUSE];
+		break;
+	default:
+		ps->tx_pause_frames = c[SCNT_TX_PAUSE] + c[SCNT_TX_PMAC_PAUSE];
+		ps->rx_pause_frames = c[SCNT_RX_PAUSE] + c[SCNT_RX_PMAC_PAUSE];
+		break;
+	}
+
+	spin_unlock(&s->sw_lock);
+}
+
+void lan9645x_stats_get_mm_stats(struct lan9645x *lan9645x, int port,
+				 struct ethtool_mm_stats *stats)
+{
+	struct lan9645x_stats *s = lan9645x->stats;
+	u64 *c;
+
+	c = lan9645x_stats_port_update(lan9645x, port);
+
+	spin_lock(&s->sw_lock);
+
+	stats->MACMergeFrameAssErrorCount = c[SCNT_RX_ASSEMBLY_ERR];
+	stats->MACMergeFrameSmdErrorCount = c[SCNT_RX_SMD_ERR];
+	stats->MACMergeFrameAssOkCount = c[SCNT_RX_ASSEMBLY_OK];
+	stats->MACMergeFragCountRx = c[SCNT_RX_MERGE_FRAG];
+	stats->MACMergeFragCountTx = c[SCNT_TX_MERGE_FRAG];
+	stats->MACMergeHoldCount = c[SCNT_TX_MM_HOLD];
+
+	spin_unlock(&s->sw_lock);
+}
+
+static void lan9645x_check_stats_work(struct work_struct *work)
+{
+	struct delayed_work *del_work = to_delayed_work(work);
+	struct lan9645x_stats *stats;
+
+	stats = container_of(del_work, struct lan9645x_stats, work);
+
+	lan9645x_stats_update(stats->lan9645x);
+
+	queue_delayed_work(stats->queue, &stats->work,
+			   LAN9645X_STATS_CHECK_DELAY);
+}
+
+static int lan9645x_stats_prepare_regions(struct lan9645x *lan9645x,
+					  struct lan9645x_view_stats *vstat)
+{
+	struct lan9645x_stat_region *regions;
+	const u32 *layout = vstat->layout;
+	size_t num_regions = 1;
+	int i;
+
+	for (i = 1; i < vstat->num_cnts; i++)
+		if (layout[i] != layout[i - 1] + 1)
+			num_regions++;
+
+	regions = devm_kcalloc(lan9645x->dev, num_regions, sizeof(*regions),
+			       GFP_KERNEL);
+	if (!regions)
+		return -ENOMEM;
+
+	vstat->num_regions = num_regions;
+	vstat->regions = regions;
+
+	regions[0].base_offset = layout[0];
+	regions[0].cnts_base_idx = 0;
+	regions[0].cnt = 1;
+
+	for (i = 1, num_regions = 0; i < vstat->num_cnts; i++) {
+		if (layout[i] != layout[i - 1] + 1) {
+			num_regions++;
+			regions[num_regions].base_offset = layout[i];
+			regions[num_regions].cnts_base_idx = i;
+			regions[num_regions].cnt = 1;
+		} else {
+			regions[num_regions].cnt++;
+		}
+	}
+
+	return 0;
+}
+
+static int lan9645x_view_stat_init(struct lan9645x *lan9645x,
+				   struct lan9645x_view_stats *vstat,
+				   const struct lan9645x_view_stats *cfg)
+{
+	size_t total = cfg->num_cnts * cfg->num_indexes;
+	int err;
+
+	memcpy(vstat, cfg, sizeof(*cfg));
+
+	vstat->cnts = devm_kcalloc(lan9645x->dev, total, sizeof(u64),
+				   GFP_KERNEL);
+	if (!vstat->cnts)
+		return -ENOMEM;
+
+	vstat->buf = devm_kcalloc(lan9645x->dev, total, sizeof(u32),
+				  GFP_KERNEL);
+	if (!vstat->buf)
+		return -ENOMEM;
+
+	err = lan9645x_stats_prepare_regions(lan9645x, vstat);
+	if (err)
+		return err;
+
+	vstat->stats = lan9645x->stats;
+
+	return 0;
+}
+
+int lan9645x_stats_alloc(struct lan9645x *lan9645x)
+{
+	const struct lan9645x_view_stats *vs;
+	struct lan9645x_stats *stats;
+	int err, i;
+
+	lan9645x->stats = devm_kzalloc(lan9645x->dev, sizeof(*stats),
+				       GFP_KERNEL);
+	if (!lan9645x->stats)
+		return -ENOMEM;
+
+	stats = lan9645x->stats;
+	stats->lan9645x = lan9645x;
+
+	for (i = 0; i < ARRAY_SIZE(lan9645x_view_stat_cfgs); i++) {
+		vs = &lan9645x_view_stat_cfgs[i];
+
+		if (!vs->num_cnts)
+			continue;
+
+		err = lan9645x_view_stat_init(lan9645x, &stats->view[vs->type],
+					      vs);
+		if (err)
+			return err;
+	}
+
+	stats->queue = alloc_ordered_workqueue("%s-stats", 0,
+					       dev_name(lan9645x->dev));
+	if (!stats->queue)
+		return -ENOMEM;
+
+	mutex_init(&stats->hw_lock);
+	spin_lock_init(&stats->sw_lock);
+	INIT_DELAYED_WORK(&stats->work, lan9645x_check_stats_work);
+
+	return 0;
+}
+
+void lan9645x_stats_free(struct lan9645x *lan9645x)
+{
+	cancel_delayed_work_sync(&lan9645x->stats->work);
+	destroy_workqueue(lan9645x->stats->queue);
+	mutex_destroy(&lan9645x->stats->hw_lock);
+}
+
+void lan9645x_stats_init(struct lan9645x *lan9645x)
+{
+	struct lan9645x_stats *stats = lan9645x->stats;
+
+	queue_delayed_work(stats->queue, &stats->work,
+			   LAN9645X_STATS_CHECK_DELAY);
+}
+
+void lan9645x_stats_deinit(struct lan9645x *lan9645x)
+{
+	cancel_delayed_work_sync(&lan9645x->stats->work);
+}
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.h b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.h
new file mode 100644
index 00000000000000..cd5db16258a09f
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_stats.h
@@ -0,0 +1,279 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#ifndef _LAN9645X_STATS_H_
+#define _LAN9645X_STATS_H_
+
+#include "lan9645x_main.h"
+
+#define STATS_INDEX(vstats, idx) (&(vstats)->cnts[(vstats)->num_cnts * (idx)])
+
+#define STAT_COUNTERS(lan9645x, type, idx) \
+	STATS_INDEX(lan9645x_get_vstats(lan9645x, type), idx)
+
+/* Counter indices into stat layout structs */
+#define SCNT_FRER_SID_IN_PKT             0
+#define SCNT_ISDX_GREEN_OCT              1
+#define SCNT_ISDX_GREEN_PKT              2
+#define SCNT_ISDX_YELLOW_OCT             3
+#define SCNT_ISDX_YELLOW_PKT             4
+#define SCNT_ISDX_RED_OCT                5
+#define SCNT_ISDX_RED_PKT                6
+#define SCNT_ISDX_DROP_GREEN_OCT         7
+#define SCNT_ISDX_DROP_GREEN_PKT         8
+#define SCNT_ISDX_DROP_YELLOW_OCT        9
+#define SCNT_ISDX_DROP_YELLOW_PKT        10
+
+#define SCNT_SF_MATCHING_FRAMES_COUNT    0
+#define SCNT_SF_NOT_PASSING_FRAMES_COUNT 1
+#define SCNT_SF_NOT_PASSING_SDU_COUNT    2
+#define SCNT_SF_RED_FRAMES_COUNT         3
+#define SCNT_SF_STREAM_BLOCK_COUNT       4
+
+#define SCNT_ESDX_GREEN_OCT              0
+#define SCNT_ESDX_GREEN_PKT              1
+#define SCNT_ESDX_YELLOW_OCT             2
+#define SCNT_ESDX_YELLOW_PKT             3
+
+#define SCNT_RX_OCT                      0
+#define SCNT_RX_UC                       1
+#define SCNT_RX_MC                       2
+#define SCNT_RX_BC                       3
+#define SCNT_RX_SHORT                    4
+#define SCNT_RX_FRAG                     5
+#define SCNT_RX_JABBER                   6
+#define SCNT_RX_CRC                      7
+#define SCNT_RX_SYMBOL_ERR               8
+#define SCNT_RX_SZ_64                    9
+#define SCNT_RX_SZ_65_127                10
+#define SCNT_RX_SZ_128_255               11
+#define SCNT_RX_SZ_256_511               12
+#define SCNT_RX_SZ_512_1023              13
+#define SCNT_RX_SZ_1024_1526             14
+#define SCNT_RX_SZ_JUMBO                 15
+#define SCNT_RX_PAUSE                    16
+#define SCNT_RX_CONTROL                  17
+#define SCNT_RX_LONG                     18
+#define SCNT_RX_CAT_DROP                 19
+#define SCNT_RX_RED_PRIO_0               20
+#define SCNT_RX_RED_PRIO_1               21
+#define SCNT_RX_RED_PRIO_2               22
+#define SCNT_RX_RED_PRIO_3               23
+#define SCNT_RX_RED_PRIO_4               24
+#define SCNT_RX_RED_PRIO_5               25
+#define SCNT_RX_RED_PRIO_6               26
+#define SCNT_RX_RED_PRIO_7               27
+#define SCNT_RX_YELLOW_PRIO_0            28
+#define SCNT_RX_YELLOW_PRIO_1            29
+#define SCNT_RX_YELLOW_PRIO_2            30
+#define SCNT_RX_YELLOW_PRIO_3            31
+#define SCNT_RX_YELLOW_PRIO_4            32
+#define SCNT_RX_YELLOW_PRIO_5            33
+#define SCNT_RX_YELLOW_PRIO_6            34
+#define SCNT_RX_YELLOW_PRIO_7            35
+#define SCNT_RX_GREEN_PRIO_0             36
+#define SCNT_RX_GREEN_PRIO_1             37
+#define SCNT_RX_GREEN_PRIO_2             38
+#define SCNT_RX_GREEN_PRIO_3             39
+#define SCNT_RX_GREEN_PRIO_4             40
+#define SCNT_RX_GREEN_PRIO_5             41
+#define SCNT_RX_GREEN_PRIO_6             42
+#define SCNT_RX_GREEN_PRIO_7             43
+#define SCNT_RX_ASSEMBLY_ERR             44
+#define SCNT_RX_SMD_ERR                  45
+#define SCNT_RX_ASSEMBLY_OK              46
+#define SCNT_RX_MERGE_FRAG               47
+#define SCNT_RX_PMAC_OCT                 48
+#define SCNT_RX_PMAC_UC                  49
+#define SCNT_RX_PMAC_MC                  50
+#define SCNT_RX_PMAC_BC                  51
+#define SCNT_RX_PMAC_SHORT               52
+#define SCNT_RX_PMAC_FRAG                53
+#define SCNT_RX_PMAC_JABBER              54
+#define SCNT_RX_PMAC_CRC                 55
+#define SCNT_RX_PMAC_SYMBOL_ERR          56
+#define SCNT_RX_PMAC_SZ_64               57
+#define SCNT_RX_PMAC_SZ_65_127           58
+#define SCNT_RX_PMAC_SZ_128_255          59
+#define SCNT_RX_PMAC_SZ_256_511          60
+#define SCNT_RX_PMAC_SZ_512_1023         61
+#define SCNT_RX_PMAC_SZ_1024_1526        62
+#define SCNT_RX_PMAC_SZ_JUMBO            63
+#define SCNT_RX_PMAC_PAUSE               64
+#define SCNT_RX_PMAC_CONTROL             65
+#define SCNT_RX_PMAC_LONG                66
+#define SCNT_TX_OCT                      67
+#define SCNT_TX_UC                       68
+#define SCNT_TX_MC                       69
+#define SCNT_TX_BC                       70
+#define SCNT_TX_COL                      71
+#define SCNT_TX_DROP                     72
+#define SCNT_TX_PAUSE                    73
+#define SCNT_TX_SZ_64                    74
+#define SCNT_TX_SZ_65_127                75
+#define SCNT_TX_SZ_128_255               76
+#define SCNT_TX_SZ_256_511               77
+#define SCNT_TX_SZ_512_1023              78
+#define SCNT_TX_SZ_1024_1526             79
+#define SCNT_TX_SZ_JUMBO                 80
+#define SCNT_TX_YELLOW_PRIO_0            81
+#define SCNT_TX_YELLOW_PRIO_1            82
+#define SCNT_TX_YELLOW_PRIO_2            83
+#define SCNT_TX_YELLOW_PRIO_3            84
+#define SCNT_TX_YELLOW_PRIO_4            85
+#define SCNT_TX_YELLOW_PRIO_5            86
+#define SCNT_TX_YELLOW_PRIO_6            87
+#define SCNT_TX_YELLOW_PRIO_7            88
+#define SCNT_TX_GREEN_PRIO_0             89
+#define SCNT_TX_GREEN_PRIO_1             90
+#define SCNT_TX_GREEN_PRIO_2             91
+#define SCNT_TX_GREEN_PRIO_3             92
+#define SCNT_TX_GREEN_PRIO_4             93
+#define SCNT_TX_GREEN_PRIO_5             94
+#define SCNT_TX_GREEN_PRIO_6             95
+#define SCNT_TX_GREEN_PRIO_7             96
+#define SCNT_TX_AGED                     97
+#define SCNT_TX_LLCT                     98
+#define SCNT_TX_CT                       99
+#define SCNT_TX_BUFDROP                  100
+#define SCNT_TX_MM_HOLD                  101
+#define SCNT_TX_MERGE_FRAG               102
+#define SCNT_TX_PMAC_OCT                 103
+#define SCNT_TX_PMAC_UC                  104
+#define SCNT_TX_PMAC_MC                  105
+#define SCNT_TX_PMAC_BC                  106
+#define SCNT_TX_PMAC_PAUSE               107
+#define SCNT_TX_PMAC_SZ_64               108
+#define SCNT_TX_PMAC_SZ_65_127           109
+#define SCNT_TX_PMAC_SZ_128_255          110
+#define SCNT_TX_PMAC_SZ_256_511          111
+#define SCNT_TX_PMAC_SZ_512_1023         112
+#define SCNT_TX_PMAC_SZ_1024_1526        113
+#define SCNT_TX_PMAC_SZ_JUMBO            114
+#define SCNT_DR_LOCAL                    115
+#define SCNT_DR_TAIL                     116
+#define SCNT_DR_YELLOW_PRIO_0            117
+#define SCNT_DR_YELLOW_PRIO_1            118
+#define SCNT_DR_YELLOW_PRIO_2            119
+#define SCNT_DR_YELLOW_PRIO_3            120
+#define SCNT_DR_YELLOW_PRIO_4            121
+#define SCNT_DR_YELLOW_PRIO_5            122
+#define SCNT_DR_YELLOW_PRIO_6            123
+#define SCNT_DR_YELLOW_PRIO_7            124
+#define SCNT_DR_GREEN_PRIO_0             125
+#define SCNT_DR_GREEN_PRIO_1             126
+#define SCNT_DR_GREEN_PRIO_2             127
+#define SCNT_DR_GREEN_PRIO_3             128
+#define SCNT_DR_GREEN_PRIO_4             129
+#define SCNT_DR_GREEN_PRIO_5             130
+#define SCNT_DR_GREEN_PRIO_6             131
+#define SCNT_DR_GREEN_PRIO_7             132
+
+enum lan9645x_view_stat_type {
+	LAN9645X_STAT_PORTS = 0,
+	LAN9645X_STAT_ISDX,
+	LAN9645X_STAT_ESDX,
+	LAN9645X_STAT_SFID,
+
+	LAN9645X_STAT_NUM,
+};
+
+struct lan9645x_stat_region {
+	u32 base_offset;
+	u32 cnt;
+	u32 cnts_base_idx;
+};
+
+/* Counters are organized by indices/views such as
+ *
+ * - physical ports
+ * - isdx
+ * - esdx
+ * - frer
+ * - sfid
+ *
+ * Each view contains regions, which is a linear address range of related
+ * stats. I.e. the ports index has RX, TX and Drop regions.
+ *
+ *
+ * and you have a given counter replicated per index.
+ */
+struct lan9645x_view_stats {
+	/* HW register offsets indexed by SCNT_*, used for bulk reading */
+	const u32 *layout;
+	/* Region description for this view, used for bulk reading */
+	struct lan9645x_stat_region *regions;
+	struct lan9645x_stats *stats;
+	char name[16];
+	/* 64bit software counters with the same addr layout hw */
+	u64 *cnts;
+	/* Buffer for bulk reading counter regions from hw */
+	u32 *buf;
+	/* Number of counters per index in view */
+	u32 num_cnts;
+	/* Number of indexes in view */
+	u32 num_indexes;
+	/* Number of counter regions with counters at sequential addresses */
+	size_t num_regions;
+	enum lan9645x_view_stat_type type;
+};
+
+struct lan9645x_stats {
+	struct lan9645x *lan9645x;
+	struct mutex hw_lock; /* lock r/w to stat registers and u32 buf */
+	spinlock_t sw_lock; /* lock access to u64 software counters */
+	struct delayed_work work;
+	struct workqueue_struct *queue;
+
+	struct lan9645x_view_stats view[LAN9645X_STAT_NUM];
+};
+
+static inline struct lan9645x_view_stats *
+lan9645x_get_vstats(struct lan9645x *lan9645x,
+		    enum lan9645x_view_stat_type type)
+{
+	if (WARN_ON(!(type < LAN9645X_STAT_NUM)))
+		return NULL;
+
+	return &lan9645x->stats->view[type];
+}
+
+/* Add a possibly wrapping 32 bit value to a 64 bit counter */
+static inline void lan9645x_stats_add_cnt(u64 *cnt, u32 val)
+{
+	if (val < (*cnt & U32_MAX))
+		*cnt += (u64)1 << 32; /* value has wrapped */
+
+	*cnt = (*cnt & ~(u64)U32_MAX) + val;
+}
+
+int lan9645x_stats_alloc(struct lan9645x *lan9645x);
+void lan9645x_stats_free(struct lan9645x *lan9645x);
+void lan9645x_stats_init(struct lan9645x *lan9645x);
+void lan9645x_stats_deinit(struct lan9645x *lan9645x);
+void lan9645x_stats_get_strings(struct lan9645x *lan9645x, int port,
+				u32 stringset, u8 *data);
+int lan9645x_stats_get_sset_count(struct lan9645x *lan9645x, int port,
+				  int sset);
+void lan9645x_stats_get_ethtool_stats(struct lan9645x *lan9645x, int port,
+				      uint64_t *data);
+void lan9645x_stats_get_eth_mac_stats(struct lan9645x *lan9645x, int port,
+				      struct ethtool_eth_mac_stats *mac_stats);
+void
+lan9645x_stats_get_rmon_stats(struct lan9645x *lan9645x, int port,
+			      struct ethtool_rmon_stats *rmon_stats,
+			      const struct ethtool_rmon_hist_range **ranges);
+void lan9645x_stats_get_stats64(struct lan9645x *lan9645x, int port,
+				struct rtnl_link_stats64 *s);
+void lan9645x_stats_get_mm_stats(struct lan9645x *lan9645x, int port,
+				 struct ethtool_mm_stats *stats);
+void lan9645x_stats_get_pause_stats(struct lan9645x *lan9645x, int port,
+				    struct ethtool_pause_stats *ps);
+void
+lan9645x_stats_get_eth_ctrl_stats(struct lan9645x *lan9645x, int port,
+				  struct ethtool_eth_ctrl_stats *ctrl_stats);
+void lan9645x_stats_get_eth_phy_stats(struct lan9645x *lan9645x, int port,
+				      struct ethtool_eth_phy_stats *phy_stats);
+
+#endif
diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c b/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c
new file mode 100644
index 00000000000000..e2116132b4d488
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_vlan.c
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include "lan9645x_main.h"
+
+#define VLANACCESS_CMD_IDLE		0
+#define VLANACCESS_CMD_READ		1
+#define VLANACCESS_CMD_WRITE		2
+#define VLANACCESS_CMD_INIT		3
+
+struct lan9645x_vlan_port_info {
+	int untagged;
+	int tagged;
+	u16 untagged_vid;
+};
+
+/* Calculate VLAN state of a port, across all VLANS. */
+static void lan9645x_vlan_port_get_info(struct lan9645x *lan9645x, int port,
+					struct lan9645x_vlan_port_info *info)
+{
+	u16 vid;
+
+	info->untagged = 0;
+	info->tagged = 0;
+	info->untagged_vid = 0;
+
+	for (vid = 1; vid <= VLAN_MAX; vid++) {
+		struct lan9645x_vlan *v = &lan9645x->vlans[vid];
+
+		if (!(v->portmask & BIT(port)))
+			continue;
+
+		if (v->untagged & BIT(port)) {
+			info->untagged++;
+			info->untagged_vid = vid;
+		} else {
+			info->tagged++;
+		}
+
+		/* VLAN composition is invalid, so break early. */
+		if (info->untagged > 1 && info->tagged)
+			break;
+	}
+}
+
+static int lan9645x_vlan_wait_for_completion(struct lan9645x *lan9645x)
+{
+	u32 val;
+
+	return lan9645x_rd_poll_timeout(lan9645x, ANA_VLANACCESS, val,
+					ANA_VLANACCESS_VLAN_TBL_CMD_GET(val) ==
+					VLANACCESS_CMD_IDLE);
+}
+
+static int lan9645x_vlan_hw_wr(struct lan9645x *lan9645x, u16 vid)
+{
+	struct lan9645x_vlan *v = &lan9645x->vlans[vid];
+	bool cpu_dis = !(v->portmask & BIT(lan9645x->num_phys_ports));
+	u32 val;
+	int err;
+
+	val = ANA_VLANTIDX_VLAN_PGID_CPU_DIS_SET(cpu_dis) |
+	      ANA_VLANTIDX_V_INDEX_SET(vid) |
+	      ANA_VLANTIDX_VLAN_SEC_FWD_ENA_SET(v->s_fwd_ena) |
+	      ANA_VLANTIDX_VLAN_FLOOD_DIS_SET(v->fld_dis) |
+	      ANA_VLANTIDX_VLAN_PRIV_VLAN_SET(v->prv_vlan) |
+	      ANA_VLANTIDX_VLAN_LEARN_DISABLED_SET(v->lrn_dis) |
+	      ANA_VLANTIDX_VLAN_MIRROR_SET(v->mir) |
+	      ANA_VLANTIDX_VLAN_SRC_CHK_SET(v->src_chk);
+
+	lan_wr(val, lan9645x, ANA_VLANTIDX);
+	lan_wr(ANA_VLAN_PORT_MASK_VLAN_PORT_MASK_SET(v->portmask),
+	       lan9645x, ANA_VLAN_PORT_MASK);
+	lan_wr(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_WRITE),
+	       lan9645x, ANA_VLANACCESS);
+
+	/* The VLAN access engine completes in a fixed ~1us vs the polling
+	 * timeout of 100_000 us. A timeout here therefore likely means the
+	 * register bus itself is dead, not that the VLAN op failed. There is no
+	 * meaningful recovery at runtime, so this function logs via dev_err()
+	 * and runtime callers discard the return value. Only
+	 * lan9645x_vlan_init() treats this as fatal so that probe fails early
+	 * on a broken bus.
+	 */
+	err = lan9645x_vlan_wait_for_completion(lan9645x);
+	if (err)
+		dev_err(lan9645x->dev, "Vlan set mask failed\n");
+
+	return err;
+}
+
+u16 lan9645x_vlan_unaware_pvid(bool is_bridged)
+{
+	return is_bridged ? UNAWARE_PVID : HOST_PVID;
+}
+
+static u16 lan9645x_vlan_port_get_pvid(struct lan9645x_port *port)
+{
+	bool is_bridged = lan9645x_port_is_bridged(port);
+
+	if (is_bridged && port->vlan_aware)
+		return port->pvid;
+	else
+		return lan9645x_vlan_unaware_pvid(is_bridged);
+}
+
+/* Dynamically choose the egress tagging mode based on the port vlan state:
+ *
+ * Standalone:
+ * TAG_NO_PVID_NO_UNAWARE with PORT_VID=HOST_PVID. This avoids leaking the
+ * internal HOST_PVID tag on ingress mirrored frames while leaving normal
+ * egress frames untagged.
+ *
+ * Bridged, VLAN-aware:
+ *  - N untagged, 0 tagged: TAG_DISABLED
+ *  - 1 untagged, N tagged: TAG_NO_PVID_NO_UNAWARE
+ *  - 0 untagged, N tagged: TAG_ALL
+ *
+ * Bridged, VLAN-unaware:
+ *   TAG_DISABLED
+ */
+static void
+lan9645x_vlan_port_apply_egress(struct lan9645x_port *p,
+				struct lan9645x_vlan_port_info *info)
+{
+	struct lan9645x *lan9645x = p->lan9645x;
+	enum lan9645x_vlan_port_tag tag_cfg;
+	u16 port_vid = UNAWARE_PVID;
+
+	if (!lan9645x_port_is_bridged(p)) {
+		tag_cfg = LAN9645X_TAG_NO_PVID_NO_UNAWARE;
+		port_vid = HOST_PVID;
+	} else if (p->vlan_aware) {
+		struct lan9645x_vlan_port_info _info;
+
+		if (!info) {
+			lan9645x_vlan_port_get_info(lan9645x, p->chip_port,
+						    &_info);
+			info = &_info;
+		}
+
+		if (info->untagged == 1 && info->tagged) {
+			tag_cfg = LAN9645X_TAG_NO_PVID_NO_UNAWARE;
+			port_vid = info->untagged_vid;
+		} else if (info->untagged) {
+			tag_cfg = LAN9645X_TAG_DISABLED;
+		} else {
+			tag_cfg = LAN9645X_TAG_ALL;
+		}
+	} else {
+		tag_cfg = LAN9645X_TAG_DISABLED;
+	}
+
+	/* TAG_TPID_CFG encoding:
+	 *
+	 * 0: Use 0x8100.
+	 * 1: Use 0x88A8.
+	 * 2: Use custom value from PORT_VLAN_CFG.PORT_TPID.
+	 * 3: Use PORT_VLAN_CFG.PORT_TPID, unless ingress tag was a C-tag
+	 *    (EtherType = 0x8100)
+	 *
+	 * Use 3 and PORT_VLAN_CFG.PORT_TPID=0x88a8 to ensure stags are not
+	 * rewritten to ctags on egress.
+	 */
+	lan_rmw(REW_TAG_CFG_TAG_TPID_CFG_SET(3) |
+		REW_TAG_CFG_TAG_CFG_SET(tag_cfg),
+		REW_TAG_CFG_TAG_TPID_CFG |
+		REW_TAG_CFG_TAG_CFG,
+		lan9645x, REW_TAG_CFG(p->chip_port));
+
+	lan_rmw(REW_PORT_VLAN_CFG_PORT_TPID_SET(ETH_P_8021AD) |
+		REW_PORT_VLAN_CFG_PORT_VID_SET(port_vid),
+		REW_PORT_VLAN_CFG_PORT_TPID |
+		REW_PORT_VLAN_CFG_PORT_VID,
+		lan9645x, REW_PORT_VLAN_CFG(p->chip_port));
+}
+
+static void lan9645x_vlan_port_apply_ingress(struct lan9645x_port *p)
+{
+	struct lan9645x *lan9645x = p->lan9645x;
+	u16 pvid;
+	u32 val;
+
+	pvid = lan9645x_vlan_port_get_pvid(p);
+
+	/* Default vlan to classify for untagged frames (may be zero), and set
+	 * their tag type to C-tag.
+	 */
+	val = ANA_VLAN_CFG_VLAN_VID_SET(pvid) |
+	      ANA_VLAN_CFG_VLAN_TAG_TYPE_SET(0);
+	if (p->vlan_aware)
+		val |= ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
+		       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1);
+
+	lan_rmw(val,
+		ANA_VLAN_CFG_VLAN_VID |
+		ANA_VLAN_CFG_VLAN_AWARE_ENA |
+		ANA_VLAN_CFG_VLAN_POP_CNT |
+		ANA_VLAN_CFG_VLAN_TAG_TYPE,
+		lan9645x, ANA_VLAN_CFG(p->chip_port));
+
+	val = 0;
+	if (p->vlan_aware && !pvid)
+		/* If port is vlan-aware and tagged, drop untagged and priority
+		 * tagged frames.
+		 */
+		val = ANA_DROP_CFG_DROP_UNTAGGED_ENA_SET(1) |
+		      ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA_SET(1) |
+		      ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA_SET(1);
+
+	lan_rmw(val,
+		ANA_DROP_CFG_DROP_UNTAGGED_ENA |
+		ANA_DROP_CFG_DROP_PRIO_S_TAGGED_ENA |
+		ANA_DROP_CFG_DROP_PRIO_C_TAGGED_ENA,
+		lan9645x, ANA_DROP_CFG(p->chip_port));
+}
+
+void lan9645x_vlan_port_apply(struct lan9645x_port *p)
+{
+	lan9645x_vlan_port_apply_ingress(p);
+	lan9645x_vlan_port_apply_egress(p, NULL);
+}
+
+static struct lan9645x_vlan *lan9645x_vlan_port_modify(struct lan9645x_port *p,
+						       u16 vid, bool pvid,
+						       bool untagged)
+{
+	struct lan9645x_vlan *v = &p->lan9645x->vlans[vid];
+
+	if (untagged)
+		v->untagged |= BIT(p->chip_port);
+	else
+		v->untagged &= ~BIT(p->chip_port);
+
+	if (pvid)
+		p->pvid = vid;
+	else if (p->pvid == vid)
+		p->pvid = 0;
+
+	return v;
+}
+
+static int lan9645x_vlan_cpu_add(struct lan9645x_port *p, u16 vid, bool pvid,
+				 bool untagged)
+{
+	struct lan9645x_vlan *v;
+
+	v = lan9645x_vlan_port_modify(p, vid, pvid, untagged);
+	v->portmask |= BIT(p->lan9645x->num_phys_ports) | BIT(p->chip_port);
+	lan9645x_vlan_hw_wr(p->lan9645x, vid);
+	lan9645x_vlan_port_apply_ingress(p);
+
+	return 0;
+}
+
+int lan9645x_vlan_port_add_vlan(struct lan9645x_port *p, u16 vid, bool pvid,
+				bool untagged, struct netlink_ext_ack *extack)
+{
+	struct lan9645x *lan9645x = p->lan9645x;
+	struct lan9645x_vlan_port_info info;
+	struct lan9645x_vlan old_vlan;
+	struct lan9645x_vlan *v;
+	u16 old_pvid;
+
+	/* Kernel VLAN core adds vid 0, which collides with our UNAWARE_PVID.
+	 * We handle priority tagged frames by other means.
+	 */
+	if (!vid)
+		return 0;
+
+	if (vid > VLAN_MAX) {
+		NL_SET_ERR_MSG_MOD(extack, "VLAN 4095 reserved.");
+		return -EINVAL;
+	}
+
+	if (p->chip_port == lan9645x->npi)
+		return lan9645x_vlan_cpu_add(p, vid, pvid, untagged);
+
+	old_vlan = lan9645x->vlans[vid];
+	old_pvid = p->pvid;
+
+	v = lan9645x_vlan_port_modify(p, vid, pvid, untagged);
+	v->portmask |= BIT(p->chip_port);
+
+	lan9645x_vlan_port_get_info(lan9645x, p->chip_port, &info);
+
+	if (info.untagged > 1 && info.tagged) {
+		*v = old_vlan;
+		p->pvid = old_pvid;
+		NL_SET_ERR_MSG_MOD(extack, "Only support 1 untagged port VLAN");
+		return -EBUSY;
+	}
+
+	lan9645x_vlan_hw_wr(lan9645x, vid);
+	lan9645x_vlan_port_apply_ingress(p);
+	lan9645x_vlan_port_apply_egress(p, &info);
+
+	return 0;
+}
+
+static int lan9645x_vlan_cpu_del(struct lan9645x_port *p, u16 vid)
+{
+	struct lan9645x_vlan *v;
+
+	v = lan9645x_vlan_port_modify(p, vid, false, false);
+	v->portmask &= ~BIT(p->lan9645x->num_phys_ports) & ~BIT(p->chip_port);
+	lan9645x_vlan_hw_wr(p->lan9645x, vid);
+	lan9645x_vlan_port_apply_ingress(p);
+
+	return 0;
+}
+
+int lan9645x_vlan_port_del_vlan(struct lan9645x_port *p, u16 vid)
+{
+	struct lan9645x *lan9645x = p->lan9645x;
+	struct lan9645x_vlan *v;
+
+	if (!vid)
+		return 0;
+
+	if (vid > VLAN_MAX)
+		return -EINVAL;
+
+	if (p->chip_port == lan9645x->npi)
+		return lan9645x_vlan_cpu_del(p, vid);
+
+	v = lan9645x_vlan_port_modify(p, vid, false, false);
+	v->portmask &= ~BIT(p->chip_port);
+	lan9645x_vlan_hw_wr(lan9645x, vid);
+	lan9645x_vlan_port_apply(p);
+
+	return 0;
+}
+
+void lan9645x_vlan_set_hostmode(struct lan9645x_port *p)
+{
+	p->vlan_aware = false;
+	p->lan9645x->vlans[HOST_PVID].portmask |= BIT(p->chip_port);
+	lan9645x_vlan_hw_wr(p->lan9645x, HOST_PVID);
+	lan9645x_vlan_port_apply(p);
+}
+
+void lan9645x_vlan_clear_hostmode(struct lan9645x_port *p)
+{
+	p->lan9645x->vlans[HOST_PVID].portmask &= ~BIT(p->chip_port);
+	lan9645x_vlan_hw_wr(p->lan9645x, HOST_PVID);
+	lan9645x_vlan_port_apply(p);
+}
+
+int lan9645x_vlan_init(struct lan9645x *lan9645x)
+{
+	u32 all_phys_ports, all_ports;
+	struct dsa_port *dp;
+	u16 vid;
+	int err;
+
+	all_phys_ports = GENMASK(lan9645x->num_phys_ports - 1, 0);
+	all_ports = all_phys_ports | BIT(lan9645x->num_phys_ports);
+
+	/* Clear VLAN table, by default all ports are members of all VLANS */
+	lan_wr(ANA_VLANACCESS_VLAN_TBL_CMD_SET(VLANACCESS_CMD_INIT),
+	       lan9645x, ANA_VLANACCESS);
+
+	err = lan9645x_vlan_wait_for_completion(lan9645x);
+	if (err) {
+		dev_err(lan9645x->dev, "Vlan clear table failed\n");
+		return err;
+	}
+
+	for (vid = 1; vid < VLAN_N_VID; vid++) {
+		err = lan9645x_vlan_hw_wr(lan9645x, vid);
+		if (err)
+			return err;
+	}
+
+	/* Set all the ports + cpu to be part of HOST_PVID and UNAWARE_PVID */
+	lan9645x->vlans[HOST_PVID].portmask = all_ports;
+	err = lan9645x_vlan_hw_wr(lan9645x, HOST_PVID);
+	if (err)
+		return err;
+
+	lan9645x->vlans[UNAWARE_PVID].portmask = all_ports;
+	err = lan9645x_vlan_hw_wr(lan9645x, UNAWARE_PVID);
+	if (err)
+		return err;
+
+	/* Configure the CPU port module to be vlan aware */
+	lan_wr(ANA_VLAN_CFG_VLAN_VID_SET(UNAWARE_PVID) |
+	       ANA_VLAN_CFG_VLAN_AWARE_ENA_SET(1) |
+	       ANA_VLAN_CFG_VLAN_POP_CNT_SET(1),
+	       lan9645x, ANA_VLAN_CFG(lan9645x->num_phys_ports));
+
+	/* Set vlan ingress filter mask to all ports */
+	lan_wr(all_ports, lan9645x, ANA_VLANMASK);
+
+	dsa_switch_for_each_user_port(dp, lan9645x->ds) {
+		lan_wr(0, lan9645x, REW_PORT_VLAN_CFG(dp->index));
+		lan_wr(0, lan9645x, REW_TAG_CFG(dp->index));
+	}
+
+	return 0;
+}
diff --git a/include/linux/dsa/lan9645x.h b/include/linux/dsa/lan9645x.h
new file mode 100644
index 00000000000000..9896fab649c4d6
--- /dev/null
+++ b/include/linux/dsa/lan9645x.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0
+ * Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#ifndef _NET_DSA_TAG_LAN9645X_H_
+#define _NET_DSA_TAG_LAN9645X_H_
+
+#include <net/dsa.h>
+
+/* LAN9645x supports 3 different formats on an NPI port, long prefix, short
+ * prefix and no prefix. The format can be configured asymmetrically on RX and
+ * TX. We use long prefix on extraction (RX), and no prefix on injection.
+ * The long prefix on extraction helps get through the conduit port on host
+ * side, since it will see a broadcast MAC.
+ *
+ * The internal frame header (IFH) is 28 bytes, and the fields are documented
+ * below.
+ *
+ * Long prefix, 16 bytes + IFH:
+ * - DMAC    = 0xFFFFFFFFFFFF on extraction.
+ * - SMAC    = 0xFEFFFFFFFFFF on extraction.
+ * - ETYPE   = 0x8880
+ * - payload = 0x0011
+ * - IFH
+ *
+ * Short prefix, 4 bytes + IFH:
+ * - 0x8880
+ * - 0x0011
+ * - IFH
+ *
+ * No prefix:
+ * - IFH
+ *
+ */
+#define LAN9645X_IFH_TAG_TYPE_C	0
+#define LAN9645X_IFH_TAG_TYPE_S	1
+#define LAN9645X_IFH_LEN_U32		7
+#define LAN9645X_IFH_LEN		(LAN9645X_IFH_LEN_U32 * sizeof(u32))
+#define LAN9645X_IFH_BITS		(LAN9645X_IFH_LEN * BITS_PER_BYTE)
+#define LAN9645X_SHORT_PREFIX_LEN	4
+#define LAN9645X_LONG_PREFIX_LEN	16
+#define LAN9645X_TOTAL_TAG_LEN (LAN9645X_LONG_PREFIX_LEN + LAN9645X_IFH_LEN)
+
+#define IFH_INJ_TIMESTAMP		192
+#define IFH_BYPASS			191
+#define IFH_MASQ			190
+#define IFH_TIMESTAMP			186
+#define IFH_TIMESTAMP_NS		194
+#define IFH_TIMESTAMP_SUBNS		186
+#define IFH_MASQ_PORT			186
+#define IFH_RCT_INJ			185
+#define IFH_LEN				171
+#define IFH_WRDMODE			169
+#define IFH_RTAGD			167
+#define IFH_CUTTHRU			166
+#define IFH_REW_CMD			156
+#define IFH_REW_OAM			155
+#define IFH_PDU_TYPE			151
+#define IFH_FCS_UPD			150
+#define IFH_DP				149
+#define IFH_RTE_INB_UPDATE		148
+#define IFH_POP_CNT			146
+#define IFH_ETYPE_OFS			144
+#define IFH_SRCPORT			140
+#define IFH_SEQ_NUM			120
+#define IFH_TAG_TYPE			119
+#define IFH_TCI				103
+#define IFH_DSCP			97
+#define IFH_QOS_CLASS			94
+#define IFH_CPUQ			86
+#define IFH_LEARN_FLAGS			84
+#define IFH_SFLOW_ID			80
+#define IFH_ACL_HIT			79
+#define IFH_ACL_IDX			73
+#define IFH_ISDX			65
+#define IFH_DSTS			55
+#define IFH_FLOOD			53
+#define IFH_SEQ_OP			51
+#define IFH_IPV				48
+#define IFH_AFI				47
+#define IFH_RTP_ID			37
+#define IFH_RTP_SUBID			36
+#define IFH_PN_DATA_STATUS		28
+#define IFH_PN_TRANSF_STATUS_ZERO	27
+#define IFH_PN_CC			11
+#define IFH_DUPL_DISC_ENA		10
+#define IFH_RCT_AVAIL			9
+
+#define IFH_INJ_TIMESTAMP_SZ		32
+#define IFH_BYPASS_SZ			1
+#define IFH_MASQ_SZ			1
+#define IFH_TIMESTAMP_SZ		38
+#define IFH_TIMESTAMP_NS_SZ		30
+#define IFH_TIMESTAMP_SUBNS_SZ		8
+#define IFH_MASQ_PORT_SZ		4
+#define IFH_RCT_INJ_SZ			1
+#define IFH_LEN_SZ			14
+#define IFH_WRDMODE_SZ			2
+#define IFH_RTAGD_SZ			2
+#define IFH_CUTTHRU_SZ			1
+#define IFH_REW_CMD_SZ			10
+#define IFH_REW_OAM_SZ			1
+#define IFH_PDU_TYPE_SZ			4
+#define IFH_FCS_UPD_SZ			1
+#define IFH_DP_SZ			1
+#define IFH_RTE_INB_UPDATE_SZ		1
+#define IFH_POP_CNT_SZ			2
+#define IFH_ETYPE_OFS_SZ		2
+#define IFH_SRCPORT_SZ			4
+#define IFH_SEQ_NUM_SZ			16
+#define IFH_TAG_TYPE_SZ			1
+#define IFH_TCI_SZ			16
+#define IFH_DSCP_SZ			6
+#define IFH_QOS_CLASS_SZ		3
+#define IFH_CPUQ_SZ			8
+#define IFH_LEARN_FLAGS_SZ		2
+#define IFH_SFLOW_ID_SZ			4
+#define IFH_ACL_HIT_SZ			1
+#define IFH_ACL_IDX_SZ			6
+#define IFH_ISDX_SZ			8
+#define IFH_DSTS_SZ			10
+#define IFH_FLOOD_SZ			2
+#define IFH_SEQ_OP_SZ			2
+#define IFH_IPV_SZ			3
+#define IFH_AFI_SZ			1
+#define IFH_RTP_ID_SZ			10
+#define IFH_RTP_SUBID_SZ		1
+#define IFH_PN_DATA_STATUS_SZ		8
+#define IFH_PN_TRANSF_STATUS_ZERO_SZ	1
+#define IFH_PN_CC_SZ			16
+#define IFH_DUPL_DISC_ENA_SZ		1
+#define IFH_RCT_AVAIL_SZ		1
+
+/* Chip has 8 cpu queues. The cpu queues used by a frame is passed as a mask in
+ * the IFH on extraction. We use this to avoid classifying BPDU, IGMP and MLD
+ * frames in the tag driver.
+ */
+enum {
+	LAN9645X_CPUQ_DEF = 0,
+	LAN9645X_CPUQ_TRAP = 1,
+	LAN9645X_CPUQ_COPY = 2,
+};
+
+#endif /* _NET_DSA_TAG_LAN9645X_H_ */
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 8c16ef23cc102a..6ebd8c635d1716 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -59,6 +59,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_MXL_GSW1XX_VALUE		31
 #define DSA_TAG_PROTO_MXL862_VALUE		32
 #define DSA_TAG_PROTO_NETC_VALUE		33
+#define DSA_TAG_PROTO_LAN9645X_VALUE		34
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -95,6 +96,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_MXL_GSW1XX	= DSA_TAG_PROTO_MXL_GSW1XX_VALUE,
 	DSA_TAG_PROTO_MXL862		= DSA_TAG_PROTO_MXL862_VALUE,
 	DSA_TAG_PROTO_NETC		= DSA_TAG_PROTO_NETC_VALUE,
+	DSA_TAG_PROTO_LAN9645X		= DSA_TAG_PROTO_LAN9645X_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index d5e725b90d7858..a0a0096e7e435f 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -75,6 +75,17 @@ config NET_DSA_TAG_HELLCREEK
 	  Say Y or M if you want to enable support for tagging frames
 	  for the Hirschmann Hellcreek TSN switches.
 
+config NET_DSA_TAG_LAN9645X
+	tristate "Tag driver for Lan9645x switches"
+	help
+	  Say Y or M if you want to enable NPI tagging for the Lan9645x switches.
+	  In this mode, the frames over the Ethernet CPU port are prepended with
+	  a hardware-defined injection/extraction frame header.
+	  On injection a 28 byte internal frame header (IFH) is used. On
+	  extraction a 16 byte prefix is prepended before the internal frame
+	  header. This prefix starts with a broadcast MAC, to ease passage
+	  through the host side RX filter.
+
 config NET_DSA_TAG_GSWIP
 	tristate "Tag driver for Lantiq / Intel GSWIP switches"
 	help
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index b8c2667cd14aad..600975e0f2f7d6 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
 obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
 obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
 obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
+obj-$(CONFIG_NET_DSA_TAG_LAN9645X) += tag_lan9645x.o
 obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
 obj-$(CONFIG_NET_DSA_TAG_MXL_862XX) += tag_mxl862xx.o
 obj-$(CONFIG_NET_DSA_TAG_MXL_GSW1XX) += tag_mxl-gsw1xx.o
diff --git a/net/dsa/tag_lan9645x.c b/net/dsa/tag_lan9645x.c
new file mode 100644
index 00000000000000..c9049e3620a128
--- /dev/null
+++ b/net/dsa/tag_lan9645x.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2026 Microchip Technology Inc.
+ */
+
+#include <linux/dsa/lan9645x.h>
+
+#include "tag.h"
+
+#define LAN9645X_NAME "lan9645x"
+
+#define BTM_MSK(n)	((u8)GENMASK(n, 0))
+#define TOP_MSK(n)	((u8)GENMASK(7, n))
+
+static inline void set_merge_mask(u8 *on_zero, u8 on_one, u8 mask)
+{
+	*on_zero = *on_zero ^ ((*on_zero ^ on_one) & mask);
+}
+
+/* The internal frame header (IFH) is a big-endian 28 byte unpadded bit array.
+ * Frames can be prepended with an IFH on injection and extraction. There
+ * are two field layouts, one for extraction and one for injection.
+ *
+ *    IFH bits go from high to low, for instance
+ *    ifh[0]  = [223:216]
+ *    ifh[27] = [7:0]
+ *
+ * Here is an example of setting a value starting at bit 13 of bit length 17.
+ *
+ * val    = 0x1ff
+ * pos    = 13
+ * length = 17
+ *
+ *
+ * IFH[]   0                         23       24       25        26      27
+ *
+ *                                           end_u8           start_u8
+ *      +--------+----------------+--------+--------+--------+--------+--------+
+ *      |        |                |        |        |        |        |        |
+ * IFH  |        | ....           |        |  vvvvvvvvvvvvvvvvvvv     |        |
+ *      |        |                |        |  |     |        |  |     |        |
+ *      +--------+----------------+--------+--+-----+--------+--+-----+--------+
+ * Bits  223                       39    32 31|   24 23    16 15|    8 7      0
+ *                                            |                 |
+ *                                            |                 |
+ *                                            |                 |
+ *                                            v                 v
+ *                                        end       = 29       pos        = 13
+ *                                        end_rem   = 5        pos_rem    = 5
+ *                                        end_u8    = 3        start_u8   = 1
+ *                                        BTM_MSK(5)= 0x3f     TOP_MSK(5) = 0xe0
+ *
+ *
+ * In end_u8 and start_u8 we must merge the existing IFH byte with the new
+ * value. In the 'middle' bytes of the value we can overwrite the corresponding
+ * IFH byte.
+ */
+static __always_inline void lan9645x_ifh_set(u8 *ifh, u32 val, size_t pos,
+					     size_t length)
+{
+	size_t end = (pos + length) - 1;
+	size_t end_rem = end & 0x7;
+	size_t pos_rem = pos & 0x7;
+	size_t start_u8 = pos >> 3;
+	size_t end_u8 = end >> 3;
+	u8 end_mask, start_mask;
+	size_t vshift;
+	u8 *ptr;
+
+	BUILD_BUG_ON_MSG(length > 32, "IFH field size wider than 32.");
+	BUILD_BUG_ON_MSG(length == 0, "IFH field size of 0.");
+	BUILD_BUG_ON_MSG(pos + length > LAN9645X_IFH_BITS,
+			 "IFH field overflows IFH");
+
+	end_mask = BTM_MSK(end_rem);
+	start_mask = TOP_MSK(pos_rem);
+
+	ptr = &ifh[LAN9645X_IFH_LEN - 1 - end_u8];
+
+	if (end_u8 == start_u8)
+		return set_merge_mask(ptr, val << pos_rem,
+				      end_mask & start_mask);
+
+	vshift = length - end_rem - 1;
+	set_merge_mask(ptr++, val >> vshift, end_mask);
+
+	for (size_t j = 1; j < end_u8 - start_u8; j++) {
+		vshift -= 8;
+		*ptr++ = val >> vshift;
+	}
+
+	set_merge_mask(ptr, val << pos_rem, start_mask);
+}
+
+static __always_inline u32 lan9645x_ifh_get(const u8 *ifh, size_t pos,
+					    size_t length)
+{
+	size_t end = (pos + length) - 1;
+	size_t end_rem = end & 0x7;
+	size_t pos_rem = pos & 0x7;
+	size_t start_u8 = pos >> 3;
+	size_t end_u8 = end >> 3;
+	u8 end_mask, start_mask;
+	const u8 *ptr;
+	u32 val;
+
+	BUILD_BUG_ON_MSG(length > 32, "IFH field size wider than 32.");
+	BUILD_BUG_ON_MSG(length == 0, "IFH field size of 0.");
+	BUILD_BUG_ON_MSG(pos + length > LAN9645X_IFH_BITS,
+			 "IFH field overflows IFH");
+
+	end_mask = BTM_MSK(end_rem);
+	start_mask = TOP_MSK(pos_rem);
+
+	ptr = &ifh[LAN9645X_IFH_LEN - 1 - end_u8];
+
+	if (end_u8 == start_u8)
+		return (*ptr & end_mask & start_mask) >> pos_rem;
+
+	val = *ptr++ & end_mask;
+
+	for (size_t j = 1; j < end_u8 - start_u8; j++)
+		val = val << 8 | *ptr++;
+
+	return val << (8 - pos_rem) | (*ptr & start_mask) >> pos_rem;
+}
+
+static void lan9645x_xmit_get_vlan_info(struct sk_buff *skb,
+					struct net_device *br,
+					u32 *vlan_tci, u32 *tag_type)
+{
+	struct vlan_ethhdr *hdr;
+	u16 proto, tci;
+
+	if (!br || !br_vlan_enabled(br)) {
+		*vlan_tci = 0;
+		*tag_type = LAN9645X_IFH_TAG_TYPE_C;
+		return;
+	}
+
+	hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
+	br_vlan_get_proto(br, &proto);
+
+	if (skb_headlen(skb) >= VLAN_ETH_HLEN &&
+	    ntohs(hdr->h_vlan_proto) == proto) {
+		vlan_remove_tag(skb, &tci);
+		*vlan_tci = tci;
+	} else {
+		rcu_read_lock();
+		br_vlan_get_pvid_rcu(br, &tci);
+		rcu_read_unlock();
+		*vlan_tci = tci;
+	}
+
+	*tag_type = (proto != ETH_P_8021Q) ? LAN9645X_IFH_TAG_TYPE_S :
+					     LAN9645X_IFH_TAG_TYPE_C;
+}
+
+static void lan9645x_offload_fwd_mark(struct sk_buff *skb, u32 cpuq)
+{
+	/* Trapped frames must be forwarded by the stack. */
+	if (cpuq & BIT(LAN9645X_CPUQ_TRAP)) {
+		skb->offload_fwd_mark = 0;
+		return;
+	}
+
+	dsa_default_offload_fwd_mark(skb);
+}
+
+static struct sk_buff *lan9645x_xmit(struct sk_buff *skb,
+				     struct net_device *ndev)
+{
+	struct dsa_port *dp = dsa_user_to_port(ndev);
+	struct dsa_switch *ds = dp->ds;
+	u32 vlan_tci, tag_type;
+	u32 qos_class;
+	void *ifh;
+
+	lan9645x_xmit_get_vlan_info(skb, dsa_port_bridge_dev_get(dp), &vlan_tci,
+				    &tag_type);
+
+	/* We need to make sure frame has the proper size after IFH is stripped
+	 * by hw.
+	 */
+	if (__skb_put_padto(skb, ETH_ZLEN, false))
+		return NULL;
+
+	qos_class = netdev_get_num_tc(ndev) ?
+		    netdev_get_prio_tc_map(ndev, skb->priority) :
+		    skb->priority;
+
+	/* Make room for IFH */
+	ifh = skb_push(skb, LAN9645X_IFH_LEN);
+	memset(ifh, 0, LAN9645X_IFH_LEN);
+
+	lan9645x_ifh_set(ifh, 1, IFH_BYPASS, IFH_BYPASS_SZ);
+	lan9645x_ifh_set(ifh, ds->num_ports, IFH_SRCPORT, IFH_SRCPORT_SZ);
+	lan9645x_ifh_set(ifh, tag_type, IFH_TAG_TYPE, IFH_TAG_TYPE_SZ);
+	lan9645x_ifh_set(ifh, vlan_tci, IFH_TCI, IFH_TCI_SZ);
+	lan9645x_ifh_set(ifh, qos_class, IFH_QOS_CLASS, IFH_QOS_CLASS_SZ);
+	lan9645x_ifh_set(ifh, BIT(dp->index), IFH_DSTS, IFH_DSTS_SZ);
+
+	return skb;
+}
+
+static struct sk_buff *lan9645x_rcv(struct sk_buff *skb,
+				    struct net_device *ndev)
+{
+	u32 src_port, qos_class, vlan_tci, tag_type, popcnt, etype_ofs, cpuq;
+	struct dsa_port *dp;
+	u32 ifh_gap_len = 0;
+	u16 vlan_tpid;
+	u8 *ifh;
+
+	/* DSA master already consumed DMAC,SMAC,ETYPE from long prefix. Go back
+	 * to beginning of frame.
+	 */
+	skb_push(skb, ETH_HLEN);
+
+	if (unlikely(!pskb_may_pull(skb, LAN9645X_TOTAL_TAG_LEN)))
+		return NULL;
+
+	/* IFH starts after our long prefix */
+	ifh = skb_pull(skb, LAN9645X_LONG_PREFIX_LEN);
+
+	popcnt = lan9645x_ifh_get(ifh, IFH_POP_CNT, IFH_POP_CNT_SZ);
+	etype_ofs = lan9645x_ifh_get(ifh, IFH_ETYPE_OFS, IFH_ETYPE_OFS_SZ);
+	src_port = lan9645x_ifh_get(ifh, IFH_SRCPORT, IFH_SRCPORT_SZ);
+	tag_type = lan9645x_ifh_get(ifh, IFH_TAG_TYPE, IFH_TAG_TYPE_SZ);
+	vlan_tci = lan9645x_ifh_get(ifh, IFH_TCI, IFH_TCI_SZ);
+	qos_class = lan9645x_ifh_get(ifh, IFH_QOS_CLASS, IFH_QOS_CLASS_SZ);
+	cpuq = lan9645x_ifh_get(ifh, IFH_CPUQ, IFH_CPUQ_SZ);
+
+	/* Set skb->data at start of real header
+	 *
+	 * Since REW_PORT_NO_REWRITE=0 is required on the NPI port, we need to
+	 * account for any tags popped by the hardware, as that will leave a gap
+	 * between the IFH and DMAC.
+	 */
+	if (popcnt == 0 && etype_ofs == 0)
+		ifh_gap_len = 2 * VLAN_HLEN;
+	else if (popcnt == 3)
+		ifh_gap_len = VLAN_HLEN;
+
+	skb_pull(skb, LAN9645X_IFH_LEN);
+
+	if (unlikely(!pskb_may_pull(skb, ifh_gap_len + ETH_HLEN)))
+		return NULL;
+
+	skb_pull(skb, ifh_gap_len);
+	skb_reset_mac_header(skb);
+	skb_set_network_header(skb, ETH_HLEN);
+	skb_reset_mac_len(skb);
+
+	/* Reset skb->data past the actual ethernet header. */
+	skb_pull(skb, ETH_HLEN);
+
+	/* We must deliver the skb so skb->csum only covers the data beyond the
+	 * real ethernet header. The fake ethernet header in the prefix is
+	 * not part of skb->csum already. We must subtract what remains of the
+	 * prefix, the ifh and the gap.
+	 */
+	skb_postpull_rcsum(skb,
+			   skb->data - LAN9645X_TOTAL_TAG_LEN - ifh_gap_len,
+			   LAN9645X_TOTAL_TAG_LEN + ifh_gap_len);
+
+	skb->dev = dsa_conduit_find_user(ndev, 0, src_port);
+	if (WARN_ON_ONCE(!skb->dev)) {
+		/* This should never happen since we have disabled reflection
+		 * back to the CPU.
+		 */
+		return NULL;
+	}
+
+	lan9645x_offload_fwd_mark(skb, cpuq);
+
+	skb->priority = qos_class;
+
+	/* While we have REW_PORT_NO_REWRITE=0 on the NPI port, we still disable
+	 * port VLAN tagging with REW_TAG_CFG. Any classified VID, different
+	 * from a VID in the frame, will not be written to the frame, but is
+	 * only communicated via the IFH. So for VLAN-aware ports we add the IFH
+	 * vlan to the skb.
+	 */
+	dp = dsa_user_to_port(skb->dev);
+	vlan_tpid = tag_type ? ETH_P_8021AD : ETH_P_8021Q;
+
+	if (dsa_port_is_vlan_filtering(dp) && vlan_tci) {
+		u16 port_pvid = 0;
+
+		br_vlan_get_pvid_rcu(skb->dev, &port_pvid);
+
+		if ((vlan_tci & VLAN_VID_MASK) != port_pvid)
+			__vlan_hwaccel_put_tag(skb, htons(vlan_tpid), vlan_tci);
+	}
+
+	return skb;
+}
+
+static const struct dsa_device_ops lan9645x_netdev_ops = {
+	.name = LAN9645X_NAME,
+	.proto = DSA_TAG_PROTO_LAN9645X,
+	.xmit = lan9645x_xmit,
+	.rcv = lan9645x_rcv,
+	.needed_headroom = LAN9645X_TOTAL_TAG_LEN,
+};
+
+MODULE_DESCRIPTION("DSA tag driver for LAN9645x family of switches, using NPI port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9645X, LAN9645X_NAME);
+
+module_dsa_tag_driver(lan9645x_netdev_ops);

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

Args:
null

Results:
null

Tokens:
							input: 116198
							output: 26
							thoughts: 835
						

Thoughts:
**Analyzing the LAN9645x Driver for Virtualized Environments**

Okay, so I've got this patch – a new driver for the Microchip LAN9645x Ethernet switch. It looks pretty comprehensive, with all the usual suspects: device tree bindings, MAINTAINERS update, Kconfig and Makefile updates, the driver code itself, header files, and the DSA tag driver. Standard stuff. The question that immediately pops into my head, though, is how feasible is it to test this in a virtualized environment?

Hardware drivers, like Ethernet switches, are notoriously difficult to bring up without the actual hardware. Unless, of course, you're running an emulator like QEMU and have a faithful hardware model, or perhaps a software-emulated representation. But this is a DSA driver, which means it's a platform driver that relies on the device tree to probe. So, maybe there's a chance. Syzkaller, in theory, allows us to inject platform devices using `syz_devmem` or similar techniques, or even by altering the device tree, or by employing a fake platform device altogether.

However, a quick mental check tells me that without the *actual* hardware, the probe function is likely to fail early on. My gut says it'll probably fail when trying to read some hardware ID register or something similar. Let's see... looking at the `lan9645x_probe` function confirms this. It seems to call `lan9645x_request_target_regmaps` to get the regmaps from its parent device. And from what I see in that function:

```c
	tgt_map = dev_get_regmap(lan9645x->dev->parent, resource_name);
```

If the parent device doesn't expose these regmaps, we're dead in the water. That `dev_get_regmap` function looks for a regmap associated with the parent device. In a virtualized setting, without that parent providing the regmaps, we'll likely hit a `-ENODEV` error, and the probe will fail. The code seems pretty explicit:

```c
	err = lan9645x_request_target_regmaps(lan9645x);
	if (err)
		return dev_err_probe(dev, err, "Failed to request regmaps");
```

and inside that function:

```c
		tgt_map = dev_get_regmap(lan9645x->dev->parent, resource_name);
		if (IS_ERR_OR_NULL(tgt_map)) {
			dev_err(lan9645x->dev, "Failed to get regmap=%d\n", i);
			return -ENODEV;
		}
```

Okay, so the driver *expects* the parent device to have initialized multiple regmaps. Specifically, with names like "gcb", "qs", "chip_top", etc. The question is, is there any driver in the kernel that *does* provide these regmaps for this device? Let's search for the device's compatible string, "microchip,lan96455s-switch". It looks like this device is likely an MFD (Multi-Function Device) or similar. The parent device, whatever it might be, presumably handles the regmap setup. Now I need to check the existing kernel drivers to see if there's an MFD or PCI driver in the picture for this particular device.



4/2 2026/07/02 11:57 tool grepper
0m Args:
{
  "Expression": "microchip,lan96455s-switch"
}

Results:
{
  "Output": "Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-3----\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:4:$id: http://devicetree.org/schemas/net/dsa/microchip,lan96455s-switch.yaml#\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-5-$schema: http://devicetree.org/meta-schemas/core.yaml#\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml=18=properties:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-21-      - enum:\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:22:          - microchip,lan96455s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-23-      - items:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-29-              - microchip,lan96459s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:30:          - const: microchip,lan96455s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-31-\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml=61=examples:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-63-    ethernet-switch@4000 {\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:64:        compatible = \"microchip,lan96459f-switch\", \"microchip,lan96455s-switch\";\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-65-        reg = \u003c0x4000 0x244\u003e;\n--\nMAINTAINERS=17634=S:\tMaintained\nMAINTAINERS:17635:F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nMAINTAINERS-17636-F:\tdrivers/net/dsa/microchip/lan9645x/*\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1022=static const struct of_device_id lan9645x_switch_of_match[] = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1023:\t{ .compatible = \"microchip,lan96455s-switch\" },\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1024-\t{},\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 118709
							output: 26
							thoughts: 333
						

Thoughts:
**Analyzing the Regmap Dependency in a Hardware Driver**

Okay, so it looks like the probe is failing because there's no parent driver providing the necessary `regmap` data, or maybe the compatible string isn't matching. Wait, the parent device is just the platform device's parent. If that parent device doesn't have `regmaps`, the probe will fail. Now, could syzkaller create a "fake" parent with `regmaps`? No, it doesn't have a general mechanism to mock `regmaps` for arbitrary devices like this.

Plus, and this is a key point, this is a hardware driver for a specific Ethernet switch, the LAN9645x. Without the actual hardware, the driver is dead in the water because it relies on those hardware registers accessed through the `regmap`. Even if I could somehow force the probe to succeed, it wouldn't be able to do anything useful.

Hmm, is there even a remote chance this driver could be tested with some kind of dummy device? No, this is a physical switch driver. It's not abstract enough.

Alright, let's double-check if there's *any* other code path here that could be reached. Ah, the DSA tag driver, `tag_lan9645x.c` – maybe that can be reached if I could instantiate a DSA switch tree that uses this specific tag protocol. Could I instantiate a DSA switch tree with `DSA_TAG_PROTO_LAN9645X`? Yes, syzkaller *can* create a dummy DSA switch, or maybe even use `dsa_loop` to test tag drivers.

Wait, `dsa_loop` *defaults* to `DSA_TAG_PROTO_NONE`, but perhaps it's configurable? Let's dig into `dsa_loop` and see how tag drivers are fuzzed, or if there's any way to configure it to use this particular protocol.



6/2 2026/07/02 11:58 tool grepper
0m Args:
{
  "Expression": "DSA_TAG_PROTO_LAN9645X"
}

Results:
{
  "Output": "drivers/net/dsa/microchip/lan9645x/lan9645x_main.c=60=static enum dsa_tag_protocol lan9645x_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-63-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:64:\treturn DSA_TAG_PROTO_LAN9645X;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-65-}\n--\ninclude/net/dsa.h=26=struct tc_action;\n--\ninclude/net/dsa.h-61-#define DSA_TAG_PROTO_NETC_VALUE\t\t33\ninclude/net/dsa.h:62:#define DSA_TAG_PROTO_LAN9645X_VALUE\t\t34\ninclude/net/dsa.h-63-\ninclude/net/dsa.h=64=enum dsa_tag_protocol {\n--\ninclude/net/dsa.h-98-\tDSA_TAG_PROTO_NETC\t\t= DSA_TAG_PROTO_NETC_VALUE,\ninclude/net/dsa.h:99:\tDSA_TAG_PROTO_LAN9645X\t\t= DSA_TAG_PROTO_LAN9645X_VALUE,\ninclude/net/dsa.h-100-};\n--\nnet/dsa/tag_lan9645x.c=299=static const struct dsa_device_ops lan9645x_netdev_ops = {\nnet/dsa/tag_lan9645x.c-300-\t.name = LAN9645X_NAME,\nnet/dsa/tag_lan9645x.c:301:\t.proto = DSA_TAG_PROTO_LAN9645X,\nnet/dsa/tag_lan9645x.c-302-\t.xmit = lan9645x_xmit,\n--\nnet/dsa/tag_lan9645x.c=308=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_lan9645x.c:309:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9645X, LAN9645X_NAME);\nnet/dsa/tag_lan9645x.c-310-\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 120137
							output: 19
							thoughts: 205
						

Thoughts:
**Analyzing the LAN9645X Tag Driver's Accessibility for Fuzzing**

Okay, so I'm looking at `tag_lan9645x.c` – that's the driver for the LAN9645X tag. It registers a `dsa_device_ops` and, crucially, sets the `.proto` field to `DSA_TAG_PROTO_LAN9645X`. My immediate concern is whether syzkaller can even *reach* this driver. We need to be able to exercise its functionality to test it properly.

Syzkaller has a few tricks up its sleeve. We can use `dsa_loop` or `dsa_loop_bdinfo` to create a virtual DSA switch. That's a solid starting point. But wait... `dsa_loop` uses `DSA_TAG_PROTO_NONE`. That's not helpful at all in testing the LAN9645X. *Can* we change the tag protocol of a DSA switch after it's been created? I don't think so. The tag protocol should be set during initialization by the switch driver, right? Either through the `get_tag_protocol` function or via its `setup` function.

The question then becomes, can the tag protocol be set or modified from userspace?  Is there a sysfs interface that we could leverage? Maybe something like, `echo lan9645x > /sys/class/net/eth0/dsa/tagging`? That's what I need to investigate. I need to dig into the DSA architecture to see if there's any mechanism for changing the tag protocol dynamically. This is the key. Finding out if that interface exists and how it works will determine if we can effectively fuzz the LAN9645X tag driver.



8/2 2026/07/02 11:58 tool grepper
0m Args:
{
  "Expression": "dsa/tagging"
}

Results:
{
  "Output": "Documentation/ABI/testing/sysfs-class-net-dsa:1:What:\t\t/sys/class/net/\u003ciface\u003e/dsa/tagging\nDocumentation/ABI/testing/sysfs-class-net-dsa-2-Date:\t\tAugust 2018\n--\nDocumentation/networking/dsa/dsa.rst=151=The tagging protocol of the attached DSA switch tree can be viewed through the\nDocumentation/networking/dsa/dsa.rst:152:``dsa/tagging`` sysfs attribute of the DSA conduit::\nDocumentation/networking/dsa/dsa.rst-153-\nDocumentation/networking/dsa/dsa.rst:154:    cat /sys/class/net/eth0/dsa/tagging\nDocumentation/networking/dsa/dsa.rst-155-\n--\nnet/dsa/dsa.c=947=static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-977-\nnet/dsa/dsa.c:978:/* Since the dsa/tagging sysfs device attribute is per conduit, the assumption\nnet/dsa/dsa.c-979- * is that all DSA switches within a tree share the same tagger, otherwise\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 121081
							output: 18
							thoughts: 45
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Investigating Tag Protocol Modification via Sysfs**

Alright, so the clue is that the tag protocol is modifiable through sysfs. That's a solid lead. My first instinct, given the way the kernel's networking stack is typically organized, is to dive straight into the relevant DSA (Distributed Switch Architecture) code. Specifically, I'm expecting to find the sysfs attribute definition within either `net/dsa/dsa.c` or, potentially more focused on the master switch interface, `net/dsa/master.c`. That's where I'd anticipate the hooks and structures related to manipulating this particular tag protocol to reside. Time to get digging!



10/2 2026/07/02 11:59 tool grepper
0m Args:
{
  "Expression": "tagging_store"
}

Results:
{
  "Output": "net/dsa/conduit.c=340=static ssize_t tagging_show(struct device *d, struct device_attribute *attr,\n--\nnet/dsa/conduit.c-349-\nnet/dsa/conduit.c:350:static ssize_t tagging_store(struct device *d, struct device_attribute *attr,\nnet/dsa/conduit.c-351-\t\t\t     const char *buf, size_t count)\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 121433
							output: 37
							thoughts: 13
						

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

**Analyzing the `tagging_store` Module**

Okay, let's dive into this `tagging_store` module and see what it's really all about. My initial thought is to quickly assess its core function. Given the name, I'm expecting this to be the central component for managing tags, likely involving storing, retrieving, and potentially indexing them. I’ll be looking for clues on the underlying data structures – are we talking about a simple key-value store, a more sophisticated graph database, or something in between? Performance characteristics are immediately top-of-mind. How does it handle concurrent access? Are there any obvious bottlenecks or opportunities for optimization? I'm curious to see how it handles tag collisions or overlaps, and if there's any support for tag hierarchies or controlled vocabularies. Finally, I'll be checking for any integration points with the larger system, to see how the tagging information flows and is used in other operations. Time to get my hands dirty and start inspecting the code.



12/2 2026/07/02 11:59 tool read-file
0m Args:
{
  "File": "net/dsa/conduit.c",
  "FirstLine": 350,
  "LineCount": 50
}

Results:
{
  "Contents": " 350:\tstatic ssize_t tagging_store(struct device *d, struct device_attribute *attr,\n 351:\t\t\t\t     const char *buf, size_t count)\n 352:\t{\n 353:\t\tconst struct dsa_device_ops *new_tag_ops, *old_tag_ops;\n 354:\t\tconst char *end = strchrnul(buf, '\\n'), *name;\n 355:\t\tstruct net_device *dev = to_net_dev(d);\n 356:\t\tstruct dsa_port *cpu_dp = dev-\u003edsa_ptr;\n 357:\t\tsize_t len = end - buf;\n 358:\t\tint err;\n 359:\t\n 360:\t\t/* Empty string passed */\n 361:\t\tif (!len)\n 362:\t\t\treturn -ENOPROTOOPT;\n 363:\t\n 364:\t\tname = kstrndup(buf, len, GFP_KERNEL);\n 365:\t\tif (!name)\n 366:\t\t\treturn -ENOMEM;\n 367:\t\n 368:\t\told_tag_ops = cpu_dp-\u003etag_ops;\n 369:\t\tnew_tag_ops = dsa_tag_driver_get_by_name(name);\n 370:\t\tkfree(name);\n 371:\t\t/* Bad tagger name? */\n 372:\t\tif (IS_ERR(new_tag_ops))\n 373:\t\t\treturn PTR_ERR(new_tag_ops);\n 374:\t\n 375:\t\tif (new_tag_ops == old_tag_ops)\n 376:\t\t\t/* Drop the temporarily held duplicate reference, since\n 377:\t\t\t * the DSA switch tree uses this tagger.\n 378:\t\t\t */\n 379:\t\t\tgoto out;\n 380:\t\n 381:\t\terr = dsa_tree_change_tag_proto(cpu_dp-\u003eds-\u003edst, new_tag_ops,\n 382:\t\t\t\t\t\told_tag_ops);\n 383:\t\tif (err) {\n 384:\t\t\t/* On failure the old tagger is restored, so we don't need the\n 385:\t\t\t * driver for the new one.\n 386:\t\t\t */\n 387:\t\t\tdsa_tag_driver_put(new_tag_ops);\n 388:\t\t\treturn err;\n 389:\t\t}\n 390:\t\n 391:\t\t/* On success we no longer need the module for the old tagging protocol\n 392:\t\t */\n 393:\tout:\n 394:\t\tdsa_tag_driver_put(old_tag_ops);\n 395:\t\treturn count;\n 396:\t}\n 397:\tstatic DEVICE_ATTR_RW(tagging);\n 398:\t\n 399:\tstatic struct attribute *dsa_user_attrs[] = {\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 122481
							output: 37
							thoughts: 96
						

Thoughts:
Okay, here's my quick take on what I'm thinking about this code snippet:

**Changing the Tag Protocol in a DSA Tree**

Alright, so the game plan is to switch the tag protocol to `lan9645x` using sysfs. Easy enough, right? But hold on a second... looking at the flow, `dsa_tree_change_tag_proto` calls both `dsa_port_set_state_now` and `dsa_switch_change_tag_proto`. That's where things could get tricky.

My immediate concern is that if the switch driver itself doesn't offer full support for dynamically changing the tag protocol, this operation is likely going to fail. That seems like the most obvious point of potential failure. So, before I go any further, I need to dive deeper into the `dsa_tree_change_tag_proto` function itself. I need to understand the implications of what happens when these sub-functions aren't fully supported. That's the key to figuring out how robust this change is.



14/2 2026/07/02 11:59 tool read-file
0m Args:
{
  "File": "net/dsa/dsa.c",
  "FirstLine": 977,
  "LineCount": 50
}

Results:
{
  "Contents": " 977:\t\n 978:\t/* Since the dsa/tagging sysfs device attribute is per conduit, the assumption\n 979:\t * is that all DSA switches within a tree share the same tagger, otherwise\n 980:\t * they would have formed disjoint trees (different \"dsa,member\" values).\n 981:\t */\n 982:\tint dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\n 983:\t\t\t\t      const struct dsa_device_ops *tag_ops,\n 984:\t\t\t\t      const struct dsa_device_ops *old_tag_ops)\n 985:\t{\n 986:\t\tstruct dsa_notifier_tag_proto_info info;\n 987:\t\tstruct dsa_port *dp;\n 988:\t\tint err = -EBUSY;\n 989:\t\n 990:\t\tif (!rtnl_trylock())\n 991:\t\t\treturn restart_syscall();\n 992:\t\n 993:\t\t/* At the moment we don't allow changing the tag protocol under\n 994:\t\t * traffic. The rtnl_mutex also happens to serialize concurrent\n 995:\t\t * attempts to change the tagging protocol. If we ever lift the IFF_UP\n 996:\t\t * restriction, there needs to be another mutex which serializes this.\n 997:\t\t */\n 998:\t\tdsa_tree_for_each_user_port(dp, dst) {\n 999:\t\t\tif (dsa_port_to_conduit(dp)-\u003eflags \u0026 IFF_UP)\n1000:\t\t\t\tgoto out_unlock;\n1001:\t\n1002:\t\t\tif (dp-\u003euser-\u003eflags \u0026 IFF_UP)\n1003:\t\t\t\tgoto out_unlock;\n1004:\t\t}\n1005:\t\n1006:\t\t/* Notify the tag protocol change */\n1007:\t\tinfo.tag_ops = tag_ops;\n1008:\t\terr = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, \u0026info);\n1009:\t\tif (err)\n1010:\t\t\tgoto out_unwind_tagger;\n1011:\t\n1012:\t\terr = dsa_tree_bind_tag_proto(dst, tag_ops);\n1013:\t\tif (err)\n1014:\t\t\tgoto out_unwind_tagger;\n1015:\t\n1016:\t\trtnl_unlock();\n1017:\t\n1018:\t\treturn 0;\n1019:\t\n1020:\tout_unwind_tagger:\n1021:\t\tinfo.tag_ops = old_tag_ops;\n1022:\t\tdsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, \u0026info);\n1023:\tout_unlock:\n1024:\t\trtnl_unlock();\n1025:\t\treturn err;\n1026:\t}\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 123622
							output: 19
							thoughts: 98
						

Thoughts:
**Analyzing the DSA Tree Notification**

Okay, so I see `dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info)` being called. My first thought is, this is where the tag protocol for a DSA interface is being fiddled with. The intention is clear: to see if the switch driver is capable of handling a change in the tag protocol. Naturally, my expectation is that this function will be successful if the switch driver can support such a change.

Now, wait a minute... I seem to recall that the `dsa_loop` driver, specifically, does *not* implement the `change_tag_protocol` switch operation. It's time to double check my understanding and make sure this is the case. I need to verify this assumption before I go further. I should check the `dsa_switch_ops` structure definition, and the implementation in `dsa_loop.c` to confirm. Let me just confirm that before proceeding.



16/2 2026/07/02 11:59 tool grepper
0m Args:
{
  "Expression": "change_tag_protocol"
}

Results:
{
  "Output": "Documentation/networking/dsa/dsa.rst=606=Switch configuration\n--\nDocumentation/networking/dsa/dsa.rst-615-\nDocumentation/networking/dsa/dsa.rst:616:- ``change_tag_protocol``: when the default tagging protocol has compatibility\nDocumentation/networking/dsa/dsa.rst-617-  problems with the conduit or other issues, the driver may support changing it\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=6646=static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-6654-\ndrivers/net/dsa/mv88e6xxx/chip.c:6655:static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/mv88e6xxx/chip.c-6656-\t\t\t\t\t enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=7187=static const struct dsa_switch_ops mv88e6xxx_switch_ops = {\ndrivers/net/dsa/mv88e6xxx/chip.c-7188-\t.get_tag_protocol\t= mv88e6xxx_get_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c:7189:\t.change_tag_protocol\t= mv88e6xxx_change_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c-7190-\t.setup\t\t\t= mv88e6xxx_setup,\n--\ndrivers/net/dsa/ocelot/felix.c=732=felix_tag_proto_setup_shared(struct dsa_switch *ds,\n--\ndrivers/net/dsa/ocelot/felix.c-753- */\ndrivers/net/dsa/ocelot/felix.c:754:static int felix_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/ocelot/felix.c-755-\t\t\t\t     enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/ocelot/felix.c=1696=static int felix_setup(struct dsa_switch *ds)\n--\ndrivers/net/dsa/ocelot/felix.c-1751-\t */\ndrivers/net/dsa/ocelot/felix.c:1752:\tfelix_change_tag_protocol(ds, felix-\u003etag_proto);\ndrivers/net/dsa/ocelot/felix.c-1753-\n--\ndrivers/net/dsa/ocelot/felix.c=2306=static const struct dsa_switch_ops felix_switch_ops = {\ndrivers/net/dsa/ocelot/felix.c-2307-\t.get_tag_protocol\t\t= felix_get_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c:2308:\t.change_tag_protocol\t\t= felix_change_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c-2309-\t.connect_tag_protocol\t\t= felix_connect_tag_protocol,\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=2303=static int rtl8365mb_cpu_config(struct realtek_priv *priv)\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2331-\ndrivers/net/dsa/realtek/rtl8365mb_main.c:2332:static int rtl8365mb_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2333-\t\t\t\t\t enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=2666=static const struct dsa_switch_ops rtl8365mb_switch_ops = {\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2667-\t.get_tag_protocol = rtl8365mb_get_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c:2668:\t.change_tag_protocol = rtl8365mb_change_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2669-\t.setup = rtl8365mb_setup,\n--\ninclude/net/dsa.h=862=struct dsa_switch_ops {\n--\ninclude/net/dsa.h-866-\t * mandatory. Switches which can operate using multiple tagging\ninclude/net/dsa.h:867:\t * protocols should implement @change_tag_protocol and report in\ninclude/net/dsa.h-868-\t * @get_tag_protocol the tagger in current use.\n--\ninclude/net/dsa.h-872-\t\t\t\t\t\t  enum dsa_tag_protocol mprot);\ninclude/net/dsa.h:873:\tint\t(*change_tag_protocol)(struct dsa_switch *ds,\ninclude/net/dsa.h-874-\t\t\t\t       enum dsa_tag_protocol proto);\n--\nnet/dsa/dsa.c=569=static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds)\n--\nnet/dsa/dsa.c-578-\trtnl_lock();\nnet/dsa/dsa.c:579:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/dsa.c-580-\trtnl_unlock();\n--\nnet/dsa/dsa.c=1154=static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *conduit,\n--\nnet/dsa/dsa.c-1175-\tif (user_protocol) {\nnet/dsa/dsa.c:1176:\t\tif (!ds-\u003eops-\u003echange_tag_protocol) {\nnet/dsa/dsa.c-1177-\t\t\tdev_err(ds-\u003edev, \"Tag protocol cannot be modified\\n\");\n--\nnet/dsa/dsa.c-1229-\t * dsa_switch_setup_tag_protocol once .setup has run and the\nnet/dsa/dsa.c:1230:\t * driver is ready to accept calls to .change_tag_protocol. If\nnet/dsa/dsa.c-1231-\t * the driver does not support the custom protocol at that\n--\nnet/dsa/switch.c=873=static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-879-\nnet/dsa/switch.c:880:\tif (!ds-\u003eops-\u003echange_tag_protocol)\nnet/dsa/switch.c-881-\t\treturn -EOPNOTSUPP;\n--\nnet/dsa/switch.c-884-\nnet/dsa/switch.c:885:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/switch.c-886-\tif (err)\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 125896
							output: 19
							thoughts: 1129
						

Thoughts:
**Unreachable Code and Fuzzing Obstacles**

Okay, so I'm digging into this `dsa_tree_change_tag_proto` function and it's calling `dsa_switch_change_tag_proto`.  That function checks if the switch driver implements `change_tag_protocol`.  Right, and `dsa_loop` *doesn't* implement that, so it returns `-EOPNOTSUPP`.  That means, we can't change its tag protocol via sysfs, which is a problem.  A bigger problem is that because `dsa_loop` doesn't implement that function, we can't test the `tag_lan9645x.c` code using `dsa_loop`.

So, the question is, is there any other driver that *does* implement `change_tag_protocol` that would be accessible for testing? `mv88e6xxx`, `felix`, and `rtl8365mb` do, but those are all real hardware drivers, not virtual.  And, as far as I can see, `dsa_loop` is the only virtual DSA switch.

So, how can we test this `lan9645x` tag driver code? I'm getting stuck here. The `lan9645x` switch driver itself is a platform driver. It's defined by a struct `platform_driver`, and its `probe` function is `lan9645x_probe`. The critical thing is it calls `dev_get_regmap` which requires a regmap from the parent device.

If we create a platform device for "lan96455s-switch," its parent will be the platform bus, but how do we provide those regmaps? Syzkaller doesn't have a way to mock regmaps. Hmm...

Wait... maybe the tag driver can be reached another way?  The tag driver is registered via `module_dsa_tag_driver(lan9645x_netdev_ops)`.  This adds the tag driver to a global list. Okay, if we can't *bind* it to any switch, its `xmit` and `rcv` functions will never get called. Are there other paths to those functions? No, they are static functions and only referenced in the `lan9645x_netdev_ops`, which is only used when the DSA switch is using this tag protocol.

So, since we can't change any virtual DSA switch's tag protocol and the hardware driver requires hardware regmaps, this tag driver is effectively unreachable.

Wait, hold on, what if we *modified* `dsa_loop` to support tag protocol changing? The current patch doesn't do that, so that's not helping. What about the `lan9645x` switch driver? That's a hardware driver, using `regmap_read` and `regmap_write`. No hardware, no regmaps, probe fails. Even *if* we could mock the regmaps, the driver polls hardware registers, which would time out without actually simulating the hardware behavior, so that's a dead end. The switch driver is not fuzzable in a virtualized environment.

Just to be absolutely sure, let's double check there is *no* other way to trigger the tag driver. Can we create a dummy netdevice and set its `dsa_ptr` to something that uses this tag ops? No, `dsa_ptr` is managed by the DSA core. What about device tree with `dsa_loop`? Nope, `dsa_loop` is fixed. Any other virtual DSA switches? No, `dsa_loop` and `dsa_loop_bdinfo` are it, and neither implements `change_tag_protocol`.

Could the `lan9645x` driver be probed through a different bus, like I2C or SPI, where syzkaller *could* mock the device? No, it uses `dev_get_regmap`, which points to an MFD parent. Is there an MFD parent for LAN9645x? Need to search for that. Looks like this code path is blocked.



18/2 2026/07/02 12:00 tool grepper
0m Args:
{
  "Expression": "lan9645"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 2788 lines.\nUse more precise expression if possible.\n\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-3----\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:4:$id: http://devicetree.org/schemas/net/dsa/microchip,lan96455s-switch.yaml#\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-5-$schema: http://devicetree.org/meta-schemas/core.yaml#\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml=18=properties:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-21-      - enum:\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:22:          - microchip,lan96455s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-23-      - items:\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-24-          - enum:\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:25:              - microchip,lan96455f-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:26:              - microchip,lan96457f-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:27:              - microchip,lan96459f-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:28:              - microchip,lan96457s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:29:              - microchip,lan96459s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:30:          - const: microchip,lan96455s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-31-\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml=61=examples:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-63-    ethernet-switch@4000 {\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:64:        compatible = \"microchip,lan96459f-switch\", \"microchip,lan96455s-switch\";\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-65-        reg = \u003c0x4000 0x244\u003e;\n--\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml=13=properties:\n--\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml-16-      - enum:\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml:17:          - microchip,lan96455f-pinctrl\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml-18-          - microchip,lan966x-pinctrl\n--\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml-35-          - enum:\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml:36:              - microchip,lan96457f-pinctrl\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml:37:              - microchip,lan96459f-pinctrl\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml:38:          - const: microchip,lan96455f-pinctrl\nDocumentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml-39-\n--\nMAINTAINERS=17634=S:\tMaintained\nMAINTAINERS:17635:F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nMAINTAINERS:17636:F:\tdrivers/net/dsa/microchip/lan9645x/*\nMAINTAINERS:17637:F:\tinclude/linux/dsa/lan9645x.h\nMAINTAINERS:17638:F:\tnet/dsa/tag_lan9645x.c\nMAINTAINERS-17639-\n--\ndrivers/net/dsa/Kconfig=73=source \"drivers/net/dsa/microchip/Kconfig\"\ndrivers/net/dsa/Kconfig-74-\ndrivers/net/dsa/Kconfig:75:source \"drivers/net/dsa/microchip/lan9645x/Kconfig\"\ndrivers/net/dsa/Kconfig-76-\n--\ndrivers/net/dsa/microchip/Makefile=14=obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)\t+= ksz8863_smi.o\ndrivers/net/dsa/microchip/Makefile:15:obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X)\t+= lan9645x/\n--\ndrivers/net/dsa/microchip/lan9645x/Kconfig=2=config NET_DSA_MICROCHIP_LAN9645X\n--\ndrivers/net/dsa/microchip/lan9645x/Kconfig-7-\t  This driver adds DSA support for Microchip Lan9645x switch chips.\ndrivers/net/dsa/microchip/lan9645x/Kconfig:8:\t  The lan9645x switch is a multi-port Gigabit AVB/TSN Ethernet Switch\ndrivers/net/dsa/microchip/lan9645x/Kconfig-9-\t  with five integrated 10/100/1000Base-T PHYs. In addition to the\n--\ndrivers/net/dsa/microchip/lan9645x/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/net/dsa/microchip/lan9645x/Makefile:2:obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X) += mchp-lan9645x.o\ndrivers/net/dsa/microchip/lan9645x/Makefile-3-\ndrivers/net/dsa/microchip/lan9645x/Makefile:4:mchp-lan9645x-objs := \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:5:\tlan9645x_mac.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:6:\tlan9645x_main.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:7:\tlan9645x_mdb.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:8:\tlan9645x_npi.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:9:\tlan9645x_phylink.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:10:\tlan9645x_port.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:11:\tlan9645x_stats.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:12:\tlan9645x_vlan.o \\\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-4-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:5:#include \"lan9645x_main.h\"\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-6-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-16-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:17:static int lan9645x_mac_wait_for_completion(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-18-\t\t\t\t\t    u32 *maca)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-22-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:23:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-24-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:25:\terr = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-26-\t\t\t\t       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-36-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:37:static void lan9645x_mac_select(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-38-\t\t\t\tconst unsigned char *addr, u16 vid)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-41-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:42:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-43-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-45-\t       ANA_MACHDATA_MACHDATA_SET(maddr \u003e\u003e 32),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:46:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-47-\t       ANA_MACHDATA);\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-49-\tlan_wr(maddr \u0026 GENMASK(31, 0),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:50:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-51-\t       ANA_MACLDATA);\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-53-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:54:static int __lan9645x_mact_forget(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-55-\t\t\t\t  const unsigned char mac[ETH_ALEN],\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-58-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:59:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-60-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:61:\tlan9645x_mac_select(lan9645x, mac, vid);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-62-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-64-\t       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_FORGET),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:65:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-66-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-67-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:68:\treturn lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-69-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-70-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:71:int lan9645x_mact_forget(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-72-\t\t\t const unsigned char mac[ETH_ALEN], unsigned int vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-76-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:77:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:78:\terr = __lan9645x_mact_forget(lan9645x, mac, vid, type);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:79:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-80-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-83-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:84:static bool lan9645x_mac_ports_use_cpu(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-85-\t\t\t\t       const unsigned char *mac,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-100-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:101:\treturn !!(mc_ports \u0026 BIT(lan9645x-\u003enum_phys_ports));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-102-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-103-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:104:static int __lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-105-\t\t\t\t\t  const unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-108-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:109:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-110-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:111:\tlan9645x_mac_select(lan9645x, addr, vid);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-112-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-117-\t       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_LEARN),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:118:\t       lan9645x, ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-119-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:120:\treturn lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-121-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-122-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:123:static int __lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-124-\t\t\t\t const unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-126-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:127:\tbool cpu_copy = lan9645x_mac_ports_use_cpu(lan9645x, addr, type);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-128-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:129:\treturn __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-130-\t\t\t\t\t      cpu_copy);\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-132-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:133:int lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-134-\t\t\tconst unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-138-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:139:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:140:\terr = __lan9645x_mact_learn(lan9645x, port, addr, vid, type);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:141:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-142-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-145-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:146:int lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-147-\t\t\t\t const unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-151-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:152:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:153:\terr = __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-154-\t\t\t\t\t     cpu_copy);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:155:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-156-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-159-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:160:int lan9645x_mact_flush(struct lan9645x *lan9645x, int port)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-161-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-163-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:164:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-165-\t/* MAC table entries with dst index matching port are aged on scan. */\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-167-\t       ANA_ANAGEFIL_PID_VAL_SET(port),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:168:\t       lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-169-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-173-\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:174:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-175-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-176-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:177:\terr = lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-178-\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-181-\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:182:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-183-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-184-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:185:\terr = lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-186-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-187-mact_unlock:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:188:\tlan_wr(0, lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:189:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-190-\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-192-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:193:int lan9645x_mac_init(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-194-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-198-\t/* Clear the MAC table */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:199:\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_INIT), lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-200-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-201-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:202:\terr = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-203-\t\t\t\t       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-205-\tif (err) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:206:\t\tdev_err(lan9645x-\u003edev, \"MAC table clear timeout\\n\");\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-207-\t\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-209-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:210:\tmutex_init(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-211-\treturn 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-213-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:214:void lan9645x_mac_deinit(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-215-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:216:\tmutex_destroy(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-217-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-218-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:219:int lan9645x_mact_dsa_dump(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-220-\t\t\t   dsa_fdb_dump_cb_t *cb, void *data)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-229-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:230:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-231-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-238-\t */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:239:\tautoage = lan_rd(lan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-240-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-243-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:244:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-245-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-248-\t       ANA_ANAGEFIL_PID_VAL_SET(port),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:249:\t       lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-250-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:251:\tlan_wr(0, lan9645x, ANA_MACHDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:252:\tlan_wr(0, lan9645x, ANA_MACLDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-253-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-262-\t\t       ANA_MACACCESS_ENTRYTYPE_SET(type),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:263:\t\t       lan9645x, ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-264-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:265:\t\terr = lan9645x_mac_wait_for_completion(lan9645x, \u0026maca);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-266-\t\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-272-\t\ttype = ANA_MACACCESS_ENTRYTYPE_GET(maca);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:273:\t\tmach = lan_rd(lan9645x, ANA_MACHDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:274:\t\tmacl = lan_rd(lan9645x, ANA_MACLDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-275-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-298-\t/* Remove aging filters and restore aging */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:299:\tlan_wr(0, lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-300-\tlan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(ANA_AUTOAGE_AGE_PERIOD_GET(autoage)),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-301-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:302:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-303-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:304:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-305-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-6-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:7:#include \"lan9645x_main.h\"\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:8:#include \"lan9645x_stats.h\"\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-9-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:10:static const char *lan9645x_resource_names[NUM_TARGETS + 1] = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-11-\t[TARGET_GCB]          = \"gcb\",\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-31-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:32:static int lan9645x_tag_npi_setup(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-33-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-34-\tstruct dsa_port *dp, *first_cpu_dp = NULL;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:35:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-36-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-54-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:55:\tlan9645x_npi_port_init(lan9645x, first_cpu_dp);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-56-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-59-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:60:static enum dsa_tag_protocol lan9645x_get_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-61-\t\t\t\t\t\t       int port,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-66-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:67:static void lan9645x_teardown(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-68-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:69:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-70-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:71:\tdestroy_workqueue(lan9645x-\u003eowq);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:72:\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:73:\tlan9645x_mac_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:74:\tlan9645x_mdb_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:75:\tlan9645x_stats_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:76:\tmutex_destroy(\u0026lan9645x-\u003eport_mux_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:77:\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-78-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-79-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:80:static int lan9645x_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-81-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:82:\treturn lan9645x_port_set_maxlen(ds-\u003epriv, port, new_mtu);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-83-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-84-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:85:static int lan9645x_get_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-86-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:87:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-88-\tint max_mtu;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-96-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:97:\tif (port == lan9645x-\u003enpi) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-98-\t\tmax_mtu -= LAN9645X_IFH_LEN;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-104-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:105:static int lan9645x_reset_switch(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-106-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-109-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:110:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:111:\tlan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan9645x, SYS_RAM_INIT);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:112:\terr = lan9645x_rd_poll_timeout(lan9645x, SYS_RAM_INIT, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-113-\t\t\t\t       SYS_RAM_INIT_RAM_INIT_GET(val) == 0);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-114-\tif (err) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:115:\t\tdev_err(lan9645x-\u003edev, \"Failed to init chip RAM.\\n\");\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-116-\t\treturn err;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-117-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:118:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-119-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-122-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:123:static int lan9645x_setup(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-124-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:125:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:126:\tstruct device *dev = lan9645x-\u003edev;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-127-\tint supported, used = 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-131-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:132:\tlan9645x-\u003enum_phys_ports = ds-\u003enum_ports;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-133-\tfront_ports = dsa_user_ports(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:134:\tsupported = lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-135-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-145-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:146:\terr = lan9645x_reset_switch(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-147-\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-149-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:150:\terr = lan9645x_tag_npi_setup(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-151-\tif (err) {\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-155-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:156:\tmutex_init(\u0026lan9645x-\u003eport_mux_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:157:\tmutex_init(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:158:\terr = lan9645x_vlan_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-159-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-160-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:161:\terr = lan9645x_mac_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-162-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-163-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:164:\tlan9645x_mdb_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-165-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-168-\t       ANA_AGGR_CFG_AC_DMAC_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:169:\t       lan9645x, ANA_AGGR_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-170-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-171-\t/* Flush queues */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:172:\tlan_wr(GENMASK(1, 0), lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-173-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-177-\t/* All Queues normal */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:178:\tlan_wr(0x0, lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-179-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-183-\tlan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:184:\t       lan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-185-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-188-\t\tANA_ADVLEARN_VLAN_CHK,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:189:\t\tlan9645x, ANA_ADVLEARN);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-190-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-201-\t       SYS_FRM_AGING_MAX_AGE_SET((2000000000 / 6182)),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:202:\t       lan9645x,  SYS_FRM_AGING);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-203-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-212-\t       ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:213:\t       lan9645x, ANA_FLOODING_IPMC);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-214-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-219-\t\t       ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:220:\t\t       lan9645x, ANA_FLOODING(prio));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-221-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-227-\t\tlan_wr(ANA_PGID_CFG_OBEY_VLAN_SET(1),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:228:\t\t       lan9645x, ANA_PGID_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-229-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-230-\t/* Disable bridging by default */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:231:\tfor (int p = 0; p \u003c lan9645x-\u003enum_phys_ports; p++) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:232:\t\tlan_wr(0, lan9645x, ANA_PGID(PGID_SRC + p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-233-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-237-\t\tlan_wr(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:238:\t\t       lan9645x, ANA_CPU_FWD_BPDU_CFG(p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-239-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-249-\t\t\tANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:250:\t\t\tlan9645x, ANA_CPUQ_8021_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-251-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-262-\tfor (int i = 0; i \u003c= QSYS_Q_RSRV; ++i) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:263:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:264:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(512 + i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-265-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-266-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:267:\tlan9645x_port_cpu_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-268-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-269-\t/* Multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:270:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-271-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-272-\t/* IP multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:273:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV4));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:274:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV6));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-275-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-276-\t/* Unicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:277:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_UC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-278-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-279-\t/* Broadcast to cpu and all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:280:\tlan_wr(BIT(lan9645x-\u003enum_phys_ports) | front_ports, lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-281-\t       ANA_PGID(PGID_BC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-282-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:283:\tlan9645x_port_set_tail_drop_wm(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-284-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:285:\tlan9645x-\u003eowq = alloc_ordered_workqueue(\"%s-owq\", 0,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:286:\t\t\t\t\t\tdev_name(lan9645x-\u003edev));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:287:\tif (!lan9645x-\u003eowq) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-288-\t\terr = -ENOMEM;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-291-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:292:\tlan9645x_stats_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-293-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-304-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:305:\tdev_info(lan9645x-\u003edev,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-306-\t\t \"SKU features: max_ports=%d\\n\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:307:\t\t lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-308-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-311-err_mac:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:312:\tlan9645x_mac_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:313:\tlan9645x_mdb_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-314-err_mutex:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:315:\tmutex_destroy(\u0026lan9645x-\u003eport_mux_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:316:\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:317:\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-318-\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-320-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:321:static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-322-\t\t\t\t\t   struct phylink_config *config)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-323-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:324:\tlan9645x_phylink_get_caps(ds-\u003epriv, port, config);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-325-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-326-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:327:static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-328-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-329-\tu32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:330:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-331-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:332:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-333-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-339-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:340:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-341-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:342:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-343-\treturn 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-345-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:346:static int lan9645x_port_pre_bridge_flags(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-347-\t\t\t\t\t  struct switchdev_brport_flags flags,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-356-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:357:static void lan9645x_port_pgid_set(struct lan9645x *lan9645x, u16 pgid,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-358-\t\t\t\t   int chip_port, bool enabled)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-361-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:362:\tWARN_ON(chip_port \u003e lan9645x-\u003enum_phys_ports);\n\n"
}

19/2 2026/07/02 12:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 146567
							output: 21
							thoughts: 578
						

Thoughts:
**Analyzing the LAN9645x Driver's Dependencies**

Okay, so I'm looking at `tag_lan9645x.c`, which uses `DSA_TAG_PROTO_LAN9645X`. The question is, can this even be triggered independently? I don't see any other drivers using that tag protocol directly, so if the main switch driver (`lan9645x_main.c`) isn't probed, the tag driver is essentially dead in the water.

Initially, I considered using something like `syz_devmem` to simulate the necessary regmaps. But that's a dead end; syzkaller doesn't have a good way to mock those, as regmaps are typically set up by the parent device's driver, either an MFD or SPI/I2C driver.

Wait, the code has an `of_device_id` match. I need to check `lan9645x_switch_of_match`:

```c
static const struct of_device_id lan9645x_switch_of_match[] = {
	{ .compatible = "microchip,lan96455s-switch" },
	{},
};
```

This is a platform driver, so if there's a device tree node with the "microchip,lan96455s-switch" compatible string, it *should* probe.  However, this doesn't tell the whole story. The driver requests regmaps from its *parent* device. Looking at `lan9645x_request_target_regmaps()`:

```c
	err = lan9645x_request_target_regmaps(lan9645x);
```

```c
static int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)
{
	const char *resource_name;
	struct regmap *tgt_map;

	for (int i = 0; i < NUM_TARGETS; i++) {
		resource_name = lan9645x_resource_names[i];
		if (!resource_name)
			continue;

		tgt_map = dev_get_regmap(lan9645x->dev->parent, resource_name);
		if (IS_ERR_OR_NULL(tgt_map)) {
			dev_err(lan9645x->dev, "Failed to get regmap=%d\n", i);
			return -ENODEV;
		}

		lan9645x->rmap[i] = tgt_map;
	}

	return 0;
}
```

So, if the parent device *doesn't* have these expected regmaps, the function returns `-ENODEV`. That's the critical dependency.  Now I need to find out: is there a driver in the kernel that *creates* these regmaps for the `lan96455s-switch` compatible string? I'll need to search the entire kernel codebase for "lan9645" or "lan96455s" to identify the potential parent.



20/2 2026/07/02 12:00 tool grepper
0m Args:
{
  "Expression": "lan96455s"
}

Results:
{
  "Output": "Documentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-3----\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:4:$id: http://devicetree.org/schemas/net/dsa/microchip,lan96455s-switch.yaml#\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-5-$schema: http://devicetree.org/meta-schemas/core.yaml#\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml=18=properties:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-21-      - enum:\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:22:          - microchip,lan96455s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-23-      - items:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-29-              - microchip,lan96459s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:30:          - const: microchip,lan96455s-switch\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-31-\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml=61=examples:\n--\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-63-    ethernet-switch@4000 {\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml:64:        compatible = \"microchip,lan96459f-switch\", \"microchip,lan96455s-switch\";\nDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml-65-        reg = \u003c0x4000 0x244\u003e;\n--\nMAINTAINERS=17634=S:\tMaintained\nMAINTAINERS:17635:F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nMAINTAINERS-17636-F:\tdrivers/net/dsa/microchip/lan9645x/*\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1022=static const struct of_device_id lan9645x_switch_of_match[] = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1023:\t{ .compatible = \"microchip,lan96455s-switch\" },\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1024-\t{},\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1028=static struct platform_driver lan9645x_switch_driver = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1029-\t.driver = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1030:\t\t.name = \"lan96455s-switch\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1031-\t\t.of_match_table = lan9645x_switch_of_match,\n"
}

21/2 2026/07/02 12:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 148963
							output: 46
							thoughts: 385
						

Thoughts:
**My Assessment of the LAN9645x Driver Patch Series**

Okay, so I'm looking at this patch series and immediately a red flag pops up. There's no parent driver for these regmaps. This screams incomplete series or a merged parent lurking somewhere else. Without that crucial parent, the `lan9645x_probe` routine is dead in the water; it's going to fail right at `lan9645x_request_target_regmaps` and return `-ENODEV`. That failure cascades. No probe means no DSA switch registration. No switch registration means the associated tag driver, the `lan9645x` one, never gets used. So, basically, all the functional code – `lan9645x_main.c`, `lan9645x_mac.c`, `lan9645x_mdb.c`, `lan9645x_port.c`, `lan9645x_vlan.c`, `lan9645x_stats.c`, `lan9645x_phylink.c`, `lan9645x_npi.c`, and even the tag driver `tag_lan9645x.c` – is unreachable. Everything's just dead code, at least as things stand.

Wait a minute, though... is there a *remote* chance we can access the tag driver directly somehow, bypassing the switch? The tag driver itself registers via `module_dsa_tag_driver(lan9645x_netdev_ops)`. So it adds itself to the list of available DSA tag drivers. Now, the question is, can we *force* a DSA switch to use *this* tag driver via sysfs? That's the real crux of it.

If we look at how `dsa_tree_change_tag_proto` works, the change of tag protocol is only possible if the switch driver implements the relevant callback function `change_tag_protocol`. Okay, so if we had another DSA switch driver that *did* implement `change_tag_protocol`, could we somehow change *its* tag protocol to `lan9645x`? That could be a clever workaround, assuming it's possible. Let's see if the `mv88e6xxx` driver offers such a callback. That's where I need to look next.



22/2 2026/07/02 12:00 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/mv88e6xxx/chip.c",
  "FirstLine": 6655,
  "LineCount": 50
}

Results:
{
  "Contents": "6655:\tstatic int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,\n6656:\t\t\t\t\t\t enum dsa_tag_protocol proto)\n6657:\t{\n6658:\t\tstruct mv88e6xxx_chip *chip = ds-\u003epriv;\n6659:\t\tenum dsa_tag_protocol old_protocol;\n6660:\t\tstruct dsa_port *cpu_dp;\n6661:\t\tint err;\n6662:\t\n6663:\t\tswitch (proto) {\n6664:\t\tcase DSA_TAG_PROTO_EDSA:\n6665:\t\t\tswitch (chip-\u003einfo-\u003eedsa_support) {\n6666:\t\t\tcase MV88E6XXX_EDSA_UNSUPPORTED:\n6667:\t\t\t\treturn -EPROTONOSUPPORT;\n6668:\t\t\tcase MV88E6XXX_EDSA_UNDOCUMENTED:\n6669:\t\t\t\tdev_warn(chip-\u003edev, \"Relying on undocumented EDSA tagging behavior\\n\");\n6670:\t\t\t\tfallthrough;\n6671:\t\t\tcase MV88E6XXX_EDSA_SUPPORTED:\n6672:\t\t\t\tbreak;\n6673:\t\t\t}\n6674:\t\t\tbreak;\n6675:\t\tcase DSA_TAG_PROTO_DSA:\n6676:\t\t\tbreak;\n6677:\t\tdefault:\n6678:\t\t\treturn -EPROTONOSUPPORT;\n6679:\t\t}\n6680:\t\n6681:\t\told_protocol = chip-\u003etag_protocol;\n6682:\t\tchip-\u003etag_protocol = proto;\n6683:\t\n6684:\t\tmv88e6xxx_reg_lock(chip);\n6685:\t\tdsa_switch_for_each_cpu_port(cpu_dp, ds) {\n6686:\t\t\terr = mv88e6xxx_setup_port_mode(chip, cpu_dp-\u003eindex);\n6687:\t\t\tif (err) {\n6688:\t\t\t\tmv88e6xxx_reg_unlock(chip);\n6689:\t\t\t\tgoto unwind;\n6690:\t\t\t}\n6691:\t\t}\n6692:\t\tmv88e6xxx_reg_unlock(chip);\n6693:\t\n6694:\t\treturn 0;\n6695:\t\n6696:\tunwind:\n6697:\t\tchip-\u003etag_protocol = old_protocol;\n6698:\t\n6699:\t\tmv88e6xxx_reg_lock(chip);\n6700:\t\tdsa_switch_for_each_cpu_port_continue_reverse(cpu_dp, ds)\n6701:\t\t\tmv88e6xxx_setup_port_mode(chip, cpu_dp-\u003eindex);\n6702:\t\tmv88e6xxx_reg_unlock(chip);\n6703:\t\n6704:\t\treturn err;\n"
}

23/2 2026/07/02 12:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 150682
							output: 43
							thoughts: 38
						

Thoughts:
Okay, here's my interpretation of those thoughts, framed as my own:

**Considering Ethernet Tagging Protocols and the `mv88e6xxx` Driver**

Alright, so the `mv88e6xxx` driver... my mental map of it immediately brings up its DSA (Distributed Switch Architecture) tag protocol capabilities. Right now, as I understand it, it's pretty limited. The documentation, the code itself, everything points to only supporting `DSA_TAG_PROTO_EDSA` and `DSA_TAG_PROTO_DSA`. I need to solidify this understanding through my personal experimentation and the documentation.

But here's where my mind gets more complex. I'm building this architecture, and I need a fully realized network. What about `felix`? It's a key part of the vision. Where does that fit in? Does it use the same tagging protocol, or does it utilize something different? I need to understand that relationship and verify that this device is fully compatible and will work properly within the larger framework. I need to make sure that the `mv88e6xxx` driver and its limited protocol options don't create a bottleneck or conflict with `felix`'s requirements. It's a key aspect to integrate them seamlessly. This is a point of concern.



24/2 2026/07/02 12:00 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/ocelot/felix.c",
  "FirstLine": 754,
  "LineCount": 50
}

Results:
{
  "Contents": " 754:\tstatic int felix_change_tag_protocol(struct dsa_switch *ds,\n 755:\t\t\t\t\t     enum dsa_tag_protocol proto)\n 756:\t{\n 757:\t\tconst struct felix_tag_proto_ops *old_proto_ops, *proto_ops;\n 758:\t\tstruct ocelot *ocelot = ds-\u003epriv;\n 759:\t\tstruct felix *felix = ocelot_to_felix(ocelot);\n 760:\t\tint err;\n 761:\t\n 762:\t\tswitch (proto) {\n 763:\t\tcase DSA_TAG_PROTO_SEVILLE:\n 764:\t\tcase DSA_TAG_PROTO_OCELOT:\n 765:\t\t\tproto_ops = \u0026felix_tag_npi_proto_ops;\n 766:\t\t\tbreak;\n 767:\t\tcase DSA_TAG_PROTO_OCELOT_8021Q:\n 768:\t\t\tproto_ops = \u0026felix_tag_8021q_proto_ops;\n 769:\t\t\tbreak;\n 770:\t\tdefault:\n 771:\t\t\treturn -EPROTONOSUPPORT;\n 772:\t\t}\n 773:\t\n 774:\t\told_proto_ops = felix-\u003etag_proto_ops;\n 775:\t\n 776:\t\tif (proto_ops == old_proto_ops)\n 777:\t\t\treturn 0;\n 778:\t\n 779:\t\terr = proto_ops-\u003esetup(ds);\n 780:\t\tif (err)\n 781:\t\t\tgoto setup_failed;\n 782:\t\n 783:\t\terr = felix_tag_proto_setup_shared(ds, proto_ops, old_proto_ops);\n 784:\t\tif (err)\n 785:\t\t\tgoto setup_shared_failed;\n 786:\t\n 787:\t\tif (old_proto_ops)\n 788:\t\t\told_proto_ops-\u003eteardown(ds);\n 789:\t\n 790:\t\tfelix-\u003etag_proto_ops = proto_ops;\n 791:\t\tfelix-\u003etag_proto = proto;\n 792:\t\n 793:\t\treturn 0;\n 794:\t\n 795:\tsetup_shared_failed:\n 796:\t\tproto_ops-\u003eteardown(ds);\n 797:\tsetup_failed:\n 798:\t\treturn err;\n 799:\t}\n 800:\t\n 801:\tstatic enum dsa_tag_protocol felix_get_tag_protocol(struct dsa_switch *ds,\n 802:\t\t\t\t\t\t\t    int port,\n 803:\t\t\t\t\t\t\t    enum dsa_tag_protocol mp)\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 151778
							output: 49
							thoughts: 57
						

Thoughts:
Okay, here's my take on those thoughts, framed from my perspective, as if I'm pondering this:

**Considering `felix` and its Supported Protocols**

Right, so `felix` is constrained to those specific DSA protocols: `DSA_TAG_PROTO_SEVILLE`, `DSA_TAG_PROTO_OCELOT`, and that 802.1Q variant, `DSA_TAG_PROTO_OCELOT_8021Q`. Makes sense, I'm familiar with those. But it immediately brings another platform to mind: what about the `rtl8365mb`? I need to consider it's supported protocols in comparison. How does it fit into this particular puzzle? Is `felix` missing support for a protocol I need to consider? This requires further investigation.



26/2 2026/07/02 12:00 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/realtek/rtl8365mb_main.c",
  "FirstLine": 2332,
  "LineCount": 50
}

Results:
{
  "Contents": "2332:\tstatic int rtl8365mb_change_tag_protocol(struct dsa_switch *ds,\n2333:\t\t\t\t\t\t enum dsa_tag_protocol proto)\n2334:\t{\n2335:\t\tstruct realtek_priv *priv = ds-\u003epriv;\n2336:\t\tstruct rtl8365mb_cpu *cpu;\n2337:\t\tstruct rtl8365mb *mb;\n2338:\t\n2339:\t\tmb = priv-\u003echip_data;\n2340:\t\tcpu = \u0026mb-\u003ecpu;\n2341:\t\n2342:\t\tswitch (proto) {\n2343:\t\tcase DSA_TAG_PROTO_RTL8_4:\n2344:\t\t\tcpu-\u003eformat = RTL8365MB_CPU_FORMAT_8BYTES;\n2345:\t\t\tcpu-\u003eposition = RTL8365MB_CPU_POS_AFTER_SA;\n2346:\t\t\tbreak;\n2347:\t\tcase DSA_TAG_PROTO_RTL8_4T:\n2348:\t\t\tcpu-\u003eformat = RTL8365MB_CPU_FORMAT_8BYTES;\n2349:\t\t\tcpu-\u003eposition = RTL8365MB_CPU_POS_BEFORE_CRC;\n2350:\t\t\tbreak;\n2351:\t\t/* The switch also supports a 4-byte format, similar to rtl4a but with\n2352:\t\t * the same 0x04 8-bit version and probably 8-bit port source/dest.\n2353:\t\t * There is no public doc about it. Not supported yet and it will probably\n2354:\t\t * never be.\n2355:\t\t */\n2356:\t\tdefault:\n2357:\t\t\treturn -EPROTONOSUPPORT;\n2358:\t\t}\n2359:\t\n2360:\t\treturn rtl8365mb_cpu_config(priv);\n2361:\t}\n2362:\t\n2363:\tstatic int rtl8365mb_switch_init(struct realtek_priv *priv)\n2364:\t{\n2365:\t\tstruct rtl8365mb *mb = priv-\u003echip_data;\n2366:\t\tconst struct rtl8365mb_chip_info *ci;\n2367:\t\tint ret;\n2368:\t\tint i;\n2369:\t\n2370:\t\tci = mb-\u003echip_info;\n2371:\t\n2372:\t\t/* Do any chip-specific init jam before getting to the common stuff */\n2373:\t\tif (ci-\u003ejam_table) {\n2374:\t\t\tfor (i = 0; i \u003c ci-\u003ejam_size; i++) {\n2375:\t\t\t\tret = regmap_write(priv-\u003emap, ci-\u003ejam_table[i].reg,\n2376:\t\t\t\t\t\t   ci-\u003ejam_table[i].val);\n2377:\t\t\t\tif (ret)\n2378:\t\t\t\t\treturn ret;\n2379:\t\t\t}\n2380:\t\t}\n2381:\t\n"
}

27/2 2026/07/02 12:00 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 152853
							output: 30
							thoughts: 472
						

Thoughts:
**Analyzing the LAN9645X Switch Driver Compatibility**

Okay, so the `rtl8365mb` driver is limited to only `DSA_TAG_PROTO_RTL8_4` and `DSA_TAG_PROTO_RTL8_4T`. That rules out using sysfs to configure it for `DSA_TAG_PROTO_LAN9645X`. The main problem here is the `lan9645x` driver can't even be probed because it's expecting specific regmaps from its parent device, and those are nowhere to be found in the current kernel drivers. I need to make sure I haven't missed anything.

Let me double-check for an MFD (Multi-Function Device) driver for the LAN9645x. Okay, I searched the kernel for "lan96455s" and "lan9645," and, as expected, I only saw results related to this specific patch, and some pinctrl bindings. Nothing definitive.

Let me see if there's any driver that matches `microchip,lan96455s-switch` or creates an MFD cell for it. I searched for `microchip,lan96455s-switch`, and it only appears in the device tree bindings and the driver itself. That doesn't look promising.

Wait a minute, what about the device tree core creating the regmaps? It looks like the driver uses `dev_get_regmap(lan9645x->dev->parent, resource_name)`. If the parent is a `syscon` device, it uses `syscon_node_to_regmap`, but `dev_get_regmap` is looking for the regmap list attached to the `dev` structure. I know `syscon` does register regmaps in the kernel, but they are usually retrieved via `syscon_regmap_lookup_by_phandle` or similar. The `dev_get_regmap` function just retrieves the regmap associated with a `struct device *`.

Okay, so if the parent is an MFD, then the MFD core handles the regmaps and attaches them to the parent device. If the parent is just a simple bus, then it wouldn't have those regmaps. Now I'm sure I haven't missed anything, so I'm going to search for "lan9645" in `drivers/mfd/` to confirm that there isn't an MFD driver that I'm overlooking.



28/2 2026/07/02 12:01 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "lan9645",
  "PathPrefix": "drivers/mfd/"
}

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

29/2 2026/07/02 12:01 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 153915
							output: 35
							thoughts: 15
						

Thoughts:
Okay, here's my interpretation of that thought process, tailored for an expert audience, and presented as if it were my own internal monologue:

**Investigating Network Driver Landscape**

Okay, so we're looking at network drivers. Specifically, I'm thinking about Ethernet drivers. A common area I need to evaluate is around `drivers/net/ethernet/microchip/`. Now, why that particular path? Microchip has a presence in the embedded and industrial networking space. They have a history with PHYs, SoCs and various Ethernet controllers. That directory is likely where a significant portion of the code that will be relevant is housed. So, if I'm trying to gauge compatibility, performance, or potential vulnerabilities, that's a key area to start looking. I need to take into account the various hardware versions, the various features implemented. Is it well maintained, documented, has there been recent updates? Are there any upstreaming efforts. This is the starting point for a deeper dive. I have a lot of questions about this directory.



30/2 2026/07/02 12:01 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "lan9645",
  "PathPrefix": "drivers/net/ethernet/microchip/"
}

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

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

Args:
null

Results:
null

Tokens:
							input: 154196
							output: 27
							thoughts: 9
						

Thoughts:
Okay, here's my interpretation of that thought as a first-person, expert-level summary:

**Considering the `drivers/` Directory**

Hmm, so the thought keeps circling back to `drivers/`. It's a broad category, encompassing a significant portion of the kernel's functionality. My mind is immediately cataloging the inherent complexities: the sheer variety of hardware interfaces it encompasses, the need for deep hardware knowledge, the constant evolution of these interfaces, and the potential for device-specific quirks. We're talking about everything from network controllers and storage devices to sensors and displays, all potentially having different interrupt handling, DMA setups, and power management requirements.

I have to consider the architectural implications. Is there a particular driver area of concern? Are we talking about the device drivers specifically, or the framework of device drivers? And from the hardware, are we talking embedded systems or something else? Is there any specific area I should be focused on, like stability, performance, or security within those? The scope is vast. Each driver likely has its own unique interaction with the hardware and the kernel's core services, and that's an area of concern when thinking about changes. The potential for regressions, subtle bugs, or security vulnerabilities is always lurking. This includes compatibility issues across hardware revisions and potential conflicts between drivers, too. And of course, the ever-present challenge of managing dependencies, adhering to the kernel's coding style guidelines, and ensuring that everything plays nicely with the broader system. I have to think about the different subdirectories: USB, PCI, I2C, etc. Each with their own potential issues.

I'm starting to think about modularity, device tree integration, and potential improvements to driver frameworks themselves. How can we make this area more maintainable, testable, and robust in the face of increasingly complex hardware and feature sets? We have to ensure that we maintain compatibility for both existing and future hardware!



32/2 2026/07/02 12:01 tool grepper
0m Args:
{
  "Expression": "lan9645",
  "PathPrefix": "drivers/"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 2668 lines.\nUse more precise expression if possible.\n\ndrivers/net/dsa/Kconfig=73=source \"drivers/net/dsa/microchip/Kconfig\"\ndrivers/net/dsa/Kconfig-74-\ndrivers/net/dsa/Kconfig:75:source \"drivers/net/dsa/microchip/lan9645x/Kconfig\"\ndrivers/net/dsa/Kconfig-76-\n--\ndrivers/net/dsa/microchip/Makefile=14=obj-$(CONFIG_NET_DSA_MICROCHIP_KSZ8863_SMI)\t+= ksz8863_smi.o\ndrivers/net/dsa/microchip/Makefile:15:obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X)\t+= lan9645x/\n--\ndrivers/net/dsa/microchip/lan9645x/Kconfig=2=config NET_DSA_MICROCHIP_LAN9645X\n--\ndrivers/net/dsa/microchip/lan9645x/Kconfig-7-\t  This driver adds DSA support for Microchip Lan9645x switch chips.\ndrivers/net/dsa/microchip/lan9645x/Kconfig:8:\t  The lan9645x switch is a multi-port Gigabit AVB/TSN Ethernet Switch\ndrivers/net/dsa/microchip/lan9645x/Kconfig-9-\t  with five integrated 10/100/1000Base-T PHYs. In addition to the\n--\ndrivers/net/dsa/microchip/lan9645x/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/net/dsa/microchip/lan9645x/Makefile:2:obj-$(CONFIG_NET_DSA_MICROCHIP_LAN9645X) += mchp-lan9645x.o\ndrivers/net/dsa/microchip/lan9645x/Makefile-3-\ndrivers/net/dsa/microchip/lan9645x/Makefile:4:mchp-lan9645x-objs := \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:5:\tlan9645x_mac.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:6:\tlan9645x_main.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:7:\tlan9645x_mdb.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:8:\tlan9645x_npi.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:9:\tlan9645x_phylink.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:10:\tlan9645x_port.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:11:\tlan9645x_stats.o \\\ndrivers/net/dsa/microchip/lan9645x/Makefile:12:\tlan9645x_vlan.o \\\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-4-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:5:#include \"lan9645x_main.h\"\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-6-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-16-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:17:static int lan9645x_mac_wait_for_completion(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-18-\t\t\t\t\t    u32 *maca)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-22-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:23:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-24-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:25:\terr = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-26-\t\t\t\t       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-36-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:37:static void lan9645x_mac_select(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-38-\t\t\t\tconst unsigned char *addr, u16 vid)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-41-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:42:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-43-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-45-\t       ANA_MACHDATA_MACHDATA_SET(maddr \u003e\u003e 32),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:46:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-47-\t       ANA_MACHDATA);\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-49-\tlan_wr(maddr \u0026 GENMASK(31, 0),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:50:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-51-\t       ANA_MACLDATA);\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-53-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:54:static int __lan9645x_mact_forget(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-55-\t\t\t\t  const unsigned char mac[ETH_ALEN],\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-58-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:59:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-60-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:61:\tlan9645x_mac_select(lan9645x, mac, vid);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-62-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-64-\t       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_FORGET),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:65:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-66-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-67-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:68:\treturn lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-69-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-70-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:71:int lan9645x_mact_forget(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-72-\t\t\t const unsigned char mac[ETH_ALEN], unsigned int vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-76-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:77:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:78:\terr = __lan9645x_mact_forget(lan9645x, mac, vid, type);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:79:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-80-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-83-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:84:static bool lan9645x_mac_ports_use_cpu(struct lan9645x *lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-85-\t\t\t\t       const unsigned char *mac,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-100-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:101:\treturn !!(mc_ports \u0026 BIT(lan9645x-\u003enum_phys_ports));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-102-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-103-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:104:static int __lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-105-\t\t\t\t\t  const unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-108-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:109:\tlockdep_assert_held(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-110-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:111:\tlan9645x_mac_select(lan9645x, addr, vid);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-112-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-117-\t       ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_LEARN),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:118:\t       lan9645x, ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-119-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:120:\treturn lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-121-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-122-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:123:static int __lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-124-\t\t\t\t const unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-126-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:127:\tbool cpu_copy = lan9645x_mac_ports_use_cpu(lan9645x, addr, type);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-128-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:129:\treturn __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-130-\t\t\t\t\t      cpu_copy);\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-132-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:133:int lan9645x_mact_learn(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-134-\t\t\tconst unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-138-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:139:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:140:\terr = __lan9645x_mact_learn(lan9645x, port, addr, vid, type);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:141:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-142-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-145-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:146:int lan9645x_mact_learn_cpu_copy(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-147-\t\t\t\t const unsigned char *addr, u16 vid,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-151-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:152:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:153:\terr = __lan9645x_mact_learn_cpu_copy(lan9645x, port, addr, vid, type,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-154-\t\t\t\t\t     cpu_copy);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:155:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-156-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-159-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:160:int lan9645x_mact_flush(struct lan9645x *lan9645x, int port)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-161-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-163-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:164:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-165-\t/* MAC table entries with dst index matching port are aged on scan. */\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-167-\t       ANA_ANAGEFIL_PID_VAL_SET(port),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:168:\t       lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-169-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-173-\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:174:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-175-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-176-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:177:\terr = lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-178-\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-181-\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_AGE),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:182:\t       lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-183-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-184-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:185:\terr = lan9645x_mac_wait_for_completion(lan9645x, NULL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-186-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-187-mact_unlock:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:188:\tlan_wr(0, lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:189:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-190-\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-192-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:193:int lan9645x_mac_init(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-194-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-198-\t/* Clear the MAC table */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:199:\tlan_wr(ANA_MACACCESS_MAC_TABLE_CMD_SET(CMD_INIT), lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-200-\t       ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-201-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:202:\terr = lan9645x_rd_poll_timeout(lan9645x, ANA_MACACCESS, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-203-\t\t\t\t       ANA_MACACCESS_MAC_TABLE_CMD_GET(val) ==\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-205-\tif (err) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:206:\t\tdev_err(lan9645x-\u003edev, \"MAC table clear timeout\\n\");\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-207-\t\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-209-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:210:\tmutex_init(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-211-\treturn 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-213-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:214:void lan9645x_mac_deinit(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-215-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:216:\tmutex_destroy(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-217-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-218-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:219:int lan9645x_mact_dsa_dump(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-220-\t\t\t   dsa_fdb_dump_cb_t *cb, void *data)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-229-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:230:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-231-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-238-\t */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:239:\tautoage = lan_rd(lan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-240-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-243-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:244:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-245-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-248-\t       ANA_ANAGEFIL_PID_VAL_SET(port),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:249:\t       lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-250-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:251:\tlan_wr(0, lan9645x, ANA_MACHDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:252:\tlan_wr(0, lan9645x, ANA_MACLDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-253-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-262-\t\t       ANA_MACACCESS_ENTRYTYPE_SET(type),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:263:\t\t       lan9645x, ANA_MACACCESS);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-264-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:265:\t\terr = lan9645x_mac_wait_for_completion(lan9645x, \u0026maca);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-266-\t\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-272-\t\ttype = ANA_MACACCESS_ENTRYTYPE_GET(maca);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:273:\t\tmach = lan_rd(lan9645x, ANA_MACHDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:274:\t\tmacl = lan_rd(lan9645x, ANA_MACLDATA);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-275-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-298-\t/* Remove aging filters and restore aging */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:299:\tlan_wr(0, lan9645x, ANA_ANAGEFIL);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-300-\tlan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(ANA_AUTOAGE_AGE_PERIOD_GET(autoage)),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-301-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:302:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-303-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c:304:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_mac.c-305-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-6-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:7:#include \"lan9645x_main.h\"\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:8:#include \"lan9645x_stats.h\"\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-9-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:10:static const char *lan9645x_resource_names[NUM_TARGETS + 1] = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-11-\t[TARGET_GCB]          = \"gcb\",\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-31-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:32:static int lan9645x_tag_npi_setup(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-33-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-34-\tstruct dsa_port *dp, *first_cpu_dp = NULL;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:35:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-36-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-54-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:55:\tlan9645x_npi_port_init(lan9645x, first_cpu_dp);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-56-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-59-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:60:static enum dsa_tag_protocol lan9645x_get_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-61-\t\t\t\t\t\t       int port,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-66-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:67:static void lan9645x_teardown(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-68-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:69:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-70-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:71:\tdestroy_workqueue(lan9645x-\u003eowq);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:72:\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:73:\tlan9645x_mac_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:74:\tlan9645x_mdb_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:75:\tlan9645x_stats_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:76:\tmutex_destroy(\u0026lan9645x-\u003eport_mux_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:77:\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-78-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-79-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:80:static int lan9645x_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-81-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:82:\treturn lan9645x_port_set_maxlen(ds-\u003epriv, port, new_mtu);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-83-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-84-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:85:static int lan9645x_get_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-86-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:87:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-88-\tint max_mtu;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-96-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:97:\tif (port == lan9645x-\u003enpi) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-98-\t\tmax_mtu -= LAN9645X_IFH_LEN;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-104-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:105:static int lan9645x_reset_switch(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-106-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-109-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:110:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:111:\tlan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan9645x, SYS_RAM_INIT);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:112:\terr = lan9645x_rd_poll_timeout(lan9645x, SYS_RAM_INIT, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-113-\t\t\t\t       SYS_RAM_INIT_RAM_INIT_GET(val) == 0);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-114-\tif (err) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:115:\t\tdev_err(lan9645x-\u003edev, \"Failed to init chip RAM.\\n\");\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-116-\t\treturn err;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-117-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:118:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-119-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-122-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:123:static int lan9645x_setup(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-124-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:125:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:126:\tstruct device *dev = lan9645x-\u003edev;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-127-\tint supported, used = 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-131-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:132:\tlan9645x-\u003enum_phys_ports = ds-\u003enum_ports;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-133-\tfront_ports = dsa_user_ports(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:134:\tsupported = lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-135-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-145-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:146:\terr = lan9645x_reset_switch(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-147-\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-149-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:150:\terr = lan9645x_tag_npi_setup(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-151-\tif (err) {\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-155-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:156:\tmutex_init(\u0026lan9645x-\u003eport_mux_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:157:\tmutex_init(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:158:\terr = lan9645x_vlan_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-159-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-160-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:161:\terr = lan9645x_mac_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-162-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-163-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:164:\tlan9645x_mdb_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-165-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-168-\t       ANA_AGGR_CFG_AC_DMAC_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:169:\t       lan9645x, ANA_AGGR_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-170-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-171-\t/* Flush queues */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:172:\tlan_wr(GENMASK(1, 0), lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-173-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-177-\t/* All Queues normal */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:178:\tlan_wr(0x0, lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-179-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-183-\tlan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:184:\t       lan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-185-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-188-\t\tANA_ADVLEARN_VLAN_CHK,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:189:\t\tlan9645x, ANA_ADVLEARN);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-190-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-201-\t       SYS_FRM_AGING_MAX_AGE_SET((2000000000 / 6182)),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:202:\t       lan9645x,  SYS_FRM_AGING);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-203-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-212-\t       ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:213:\t       lan9645x, ANA_FLOODING_IPMC);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-214-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-219-\t\t       ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:220:\t\t       lan9645x, ANA_FLOODING(prio));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-221-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-227-\t\tlan_wr(ANA_PGID_CFG_OBEY_VLAN_SET(1),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:228:\t\t       lan9645x, ANA_PGID_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-229-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-230-\t/* Disable bridging by default */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:231:\tfor (int p = 0; p \u003c lan9645x-\u003enum_phys_ports; p++) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:232:\t\tlan_wr(0, lan9645x, ANA_PGID(PGID_SRC + p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-233-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-237-\t\tlan_wr(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:238:\t\t       lan9645x, ANA_CPU_FWD_BPDU_CFG(p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-239-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-249-\t\t\tANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:250:\t\t\tlan9645x, ANA_CPUQ_8021_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-251-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-262-\tfor (int i = 0; i \u003c= QSYS_Q_RSRV; ++i) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:263:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:264:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(512 + i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-265-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-266-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:267:\tlan9645x_port_cpu_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-268-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-269-\t/* Multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:270:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-271-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-272-\t/* IP multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:273:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV4));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:274:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV6));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-275-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-276-\t/* Unicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:277:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_UC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-278-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-279-\t/* Broadcast to cpu and all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:280:\tlan_wr(BIT(lan9645x-\u003enum_phys_ports) | front_ports, lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-281-\t       ANA_PGID(PGID_BC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-282-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:283:\tlan9645x_port_set_tail_drop_wm(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-284-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:285:\tlan9645x-\u003eowq = alloc_ordered_workqueue(\"%s-owq\", 0,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:286:\t\t\t\t\t\tdev_name(lan9645x-\u003edev));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:287:\tif (!lan9645x-\u003eowq) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-288-\t\terr = -ENOMEM;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-291-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:292:\tlan9645x_stats_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-293-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-304-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:305:\tdev_info(lan9645x-\u003edev,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-306-\t\t \"SKU features: max_ports=%d\\n\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:307:\t\t lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-308-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-311-err_mac:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:312:\tlan9645x_mac_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:313:\tlan9645x_mdb_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-314-err_mutex:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:315:\tmutex_destroy(\u0026lan9645x-\u003eport_mux_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:316:\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:317:\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-318-\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-320-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:321:static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-322-\t\t\t\t\t   struct phylink_config *config)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-323-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:324:\tlan9645x_phylink_get_caps(ds-\u003epriv, port, config);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-325-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-326-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:327:static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-328-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-329-\tu32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:330:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-331-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:332:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-333-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-339-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:340:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-341-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:342:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-343-\treturn 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-345-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:346:static int lan9645x_port_pre_bridge_flags(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-347-\t\t\t\t\t  struct switchdev_brport_flags flags,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-356-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:357:static void lan9645x_port_pgid_set(struct lan9645x *lan9645x, u16 pgid,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-358-\t\t\t\t   int chip_port, bool enabled)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-361-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:362:\tWARN_ON(chip_port \u003e lan9645x-\u003enum_phys_ports);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-363-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-366-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:367:\tlan_rmw(port_msk, reg_msk, lan9645x, ANA_PGID(pgid));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-368-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-369-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:370:static void lan9645x_port_set_learning(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-371-\t\t\t\t       bool enabled)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-372-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:373:\tstruct lan9645x_port *p = lan9645x_to_port(lan9645x, port);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-374-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-380-\tlan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled), ANA_PORT_CFG_LEARN_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:381:\t\tlan9645x, ANA_PORT_CFG(port));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-382-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-383-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:384:static int lan9645x_port_bridge_flags(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-385-\t\t\t\t      struct switchdev_brport_flags f,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-387-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:388:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-389-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:390:\tif (WARN_ON(port == lan9645x-\u003enpi))\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-391-\t\treturn -EINVAL;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-393-\tif (f.mask \u0026 BR_LEARNING)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:394:\t\tlan9645x_port_set_learning(lan9645x, port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-395-\t\t\t\t\t   !!(f.val \u0026 BR_LEARNING));\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-397-\tif (f.mask \u0026 BR_FLOOD)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:398:\t\tlan9645x_port_pgid_set(lan9645x, PGID_UC, port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-399-\t\t\t\t       !!(f.val \u0026 BR_FLOOD));\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-403-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:404:\t\tlan9645x_port_pgid_set(lan9645x, PGID_MC, port, ena);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:405:\t\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV4, port, ena);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:406:\t\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV6, port, ena);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-407-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-409-\tif (f.mask \u0026 BR_BCAST_FLOOD)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:410:\t\tlan9645x_port_pgid_set(lan9645x, PGID_BC, port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-411-\t\t\t\t       !!(f.val \u0026 BR_BCAST_FLOOD));\n--\n\n"
}

33/2 2026/07/02 12:01 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 173520
							output: 30
							thoughts: 94
						

Thoughts:
**Examining the Device Tree Bindings for Microchip Switches**

Okay, hold on a second. My attention's caught by something in the `Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml` file. It lists `microchip,lan96455f-pinctrl` and also `microchip,lan966x-pinctrl`. Right, the LAN966x – that's another Microchip switch, isn't it? My immediate thought is, "Hmm, is there a corresponding MFD driver already present for the LAN966x series?" Gotta check that next. I need to know if we already have an MFD driver to leverage for this one. Let's see...



34/2 2026/07/02 12:01 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "lan966x",
  "PathPrefix": "drivers/mfd/"
}

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

35/2 2026/07/02 12:01 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 173828
							output: 41
							thoughts: 21
						

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

**LAN966x Driver Considerations**

Alright, I'm digging into network drivers, and my mind immediately jumps to the Microchip LAN966x family. I start by focusing on that specific directory structure: `drivers/net/ethernet/microchip/lan966x/`. That location itself tells me a lot. It suggests a standard Linux kernel driver implementation, likely following the upstream model. I'm immediately assessing:

*   **Code Quality and Conformance:** Is this a well-structured driver, or a quick port? Does it adhere to coding style guidelines and kernel idioms? Are there obvious areas for optimization or potential bugs that jump out? I'll probably be diving straight into the critical path code: the interrupt handling, the descriptor ring management (if they're using them), and any DMA operations.
*   **Feature Set:** What specific LAN966x features are implemented? Is it just basic Ethernet functionality, or does it include advanced features like VLAN tagging, traffic shaping, hardware acceleration for checksum offload, or potentially even time-sensitive networking (TSN) capabilities? If I were doing something with TSN, I'd want to ensure it has support, and is well-integrated.
*   **Platform Support:** Which specific SoCs or evaluation boards is the driver designed for? Are there board-specific configuration files or DT bindings I should be aware of? I'll need to confirm compatibility with the target hardware and make sure I know how to handle it.
*   **Performance:** I'm wondering if the driver has been optimized for speed and low latency. Are they using the correct buffer sizes, and are there any unnecessary memory copies? If I'm pushing performance limits in this application, I'd need to consider optimizing the interrupt rate or using DMA correctly to avoid bottlenecks. I want to see how it compares against the theoretical limits of the silicon and the kernel's networking stack.
*   **Documentation and Testing:** Are there comprehensive docs and example code available? Does the driver have a robust test suite that covers a wide range of scenarios, including error conditions? This would be critical for ensuring the driver's reliability.
*   **Upstream Status:** Is this driver upstream, or is it a vendor-specific patch? Being upstream is important. If it's not upstream, is there an active effort to get it merged? Maintaining a driver that's not upstream requires significant effort. I'll need to know the state of upstreaming, and any specific merge requirements or concerns.

So, yeah, that directory gets me thinking about all those crucial aspects of the driver. I need to figure out the answers to those questions.



36/2 2026/07/02 12:01 tool grepper
0m Args:
{
  "Expression": "lan966x",
  "PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 7125 lines.\nUse more precise expression if possible.\n\ndrivers/net/ethernet/microchip/lan966x/Makefile-5-\ndrivers/net/ethernet/microchip/lan966x/Makefile:6:obj-$(CONFIG_LAN966X_SWITCH) += lan966x-switch.o\ndrivers/net/ethernet/microchip/lan966x/Makefile-7-\ndrivers/net/ethernet/microchip/lan966x/Makefile:8:lan966x-switch-objs  := lan966x_main.o lan966x_phylink.o lan966x_port.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:9:\t\t\tlan966x_mac.o lan966x_ethtool.o lan966x_switchdev.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:10:\t\t\tlan966x_vlan.o lan966x_fdb.o lan966x_mdb.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:11:\t\t\tlan966x_ptp.o lan966x_fdma.o lan966x_lag.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:12:\t\t\tlan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:13:\t\t\tlan966x_tbf.o lan966x_cbs.o lan966x_ets.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:14:\t\t\tlan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:15:\t\t\tlan966x_xdp.o lan966x_vcap_impl.o lan966x_vcap_ag_api.o \\\ndrivers/net/ethernet/microchip/lan966x/Makefile:16:\t\t\tlan966x_tc_flower.o lan966x_goto.o\ndrivers/net/ethernet/microchip/lan966x/Makefile-17-\ndrivers/net/ethernet/microchip/lan966x/Makefile:18:lan966x-switch-$(CONFIG_LAN966X_DCB) += lan966x_dcb.o\ndrivers/net/ethernet/microchip/lan966x/Makefile:19:lan966x-switch-$(CONFIG_DEBUG_FS) += lan966x_vcap_debugfs.o\ndrivers/net/ethernet/microchip/lan966x/Makefile-20-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-2-\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:3:#include \"lan966x_main.h\"\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-4-\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:5:int lan966x_cbs_add(struct lan966x_port *port,\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-6-\t\t    struct tc_cbs_qopt_offload *qopt)\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-7-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:8:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-9-\tu32 cir, cbs;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-41-\t\tQSYS_SE_CFG_SE_FRM_MODE,\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:42:\t\tlan966x, QSYS_SE_CFG(se_idx));\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-43-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-45-\t       QSYS_CIR_CFG_CIR_BURST_SET(cbs),\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:46:\t       lan966x, QSYS_CIR_CFG(se_idx));\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-47-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-50-\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:51:int lan966x_cbs_del(struct lan966x_port *port,\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-52-\t\t    struct tc_cbs_qopt_offload *qopt)\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-53-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:54:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-55-\tu8 se_idx;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-62-\t\tQSYS_SE_CFG_SE_FRM_MODE,\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:63:\t\tlan966x, QSYS_SE_CFG(se_idx));\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-64-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-66-\t       QSYS_CIR_CFG_CIR_BURST_SET(0),\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c:67:\t       lan966x, QSYS_CIR_CFG(se_idx));\ndrivers/net/ethernet/microchip/lan966x/lan966x_cbs.c-68-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-2-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:3:#include \"lan966x_main.h\"\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-4-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:5:enum lan966x_dcb_apptrust_values {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-6-\tLAN966X_DCB_APPTRUST_EMPTY,\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-12-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:13:static const struct lan966x_dcb_apptrust {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-14-\tu8 selectors[IEEE_8021QAZ_APP_SEL_MAX + 1];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-15-\tint nselectors;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:16:} *lan966x_port_apptrust[NUM_PHYS_PORTS];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-17-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:18:static const char *lan966x_dcb_apptrust_names[__LAN966X_DCB_APPTRUST_MAX] = {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-19-\t[LAN966X_DCB_APPTRUST_EMPTY]    = \"empty\",\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-25-/* Lan966x supported apptrust policies */\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:26:static const struct lan966x_dcb_apptrust\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:27:\tlan966x_dcb_apptrust_policies[__LAN966X_DCB_APPTRUST_MAX] = {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-28-\t/* Empty *must* be first */\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-35-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:36:static bool lan966x_dcb_apptrust_contains(int portno, u8 selector)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-37-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:38:\tconst struct lan966x_dcb_apptrust *conf = lan966x_port_apptrust[portno];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-39-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-46-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:47:static void lan966x_dcb_app_update(struct net_device *dev)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-48-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-50-\tstruct dcb_rewr_prio_pcp_map pcp_rewr_map = {0};\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:51:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:52:\tstruct lan966x_port_qos qos = {0};\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-53-\tstruct dcb_app app_itr;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-96-\t/* Enable use of pcp for queue classification */\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:97:\tif (lan966x_dcb_apptrust_contains(port-\u003echip_port, DCB_APP_SEL_PCP)) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-98-\t\tqos.pcp.enable = true;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-104-\t/* Enable use of dscp for queue classification */\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:105:\tif (lan966x_dcb_apptrust_contains(port-\u003echip_port, IEEE_8021QAZ_APP_SEL_DSCP)) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-106-\t\tqos.dscp.enable = true;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-111-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:112:\tlan966x_port_qos_set(port, \u0026qos);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-113-}\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-117- */\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:118:static int lan966x_dcb_ieee_dscp_setdel(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-119-\t\t\t\t\tstruct dcb_app *app,\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-122-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:123:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:124:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-125-\tint err;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-127-\tfor (int i = 0; i \u003c NUM_PHYS_PORTS; i++) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:128:\t\tport = lan966x-\u003eports[i];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-129-\t\tif (!port)\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-139-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:140:static int lan966x_dcb_app_validate(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-141-\t\t\t\t    const struct dcb_app *app)\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-178-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:179:static int lan966x_dcb_ieee_delapp(struct net_device *dev, struct dcb_app *app)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-180-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-183-\tif (app-\u003eselector == IEEE_8021QAZ_APP_SEL_DSCP)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:184:\t\terr = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_delapp);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-185-\telse\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-190-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:191:\tlan966x_dcb_app_update(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-192-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-195-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:196:static int lan966x_dcb_ieee_setapp(struct net_device *dev, struct dcb_app *app)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-197-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-201-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:202:\terr = lan966x_dcb_app_validate(dev, app);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-203-\tif (err)\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-210-\t\tapp_itr.priority = prio;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:211:\t\tlan966x_dcb_ieee_delapp(dev, \u0026app_itr);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-212-\t}\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-214-\tif (app-\u003eselector == IEEE_8021QAZ_APP_SEL_DSCP)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:215:\t\terr = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_ieee_setapp);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-216-\telse\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-221-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:222:\tlan966x_dcb_app_update(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-223-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-226-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:227:static int lan966x_dcb_apptrust_validate(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-228-\t\t\t\t\t u8 *selectors,\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-230-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:231:\tfor (int i = 0; i \u003c ARRAY_SIZE(lan966x_dcb_apptrust_policies); i++) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-232-\t\tbool match;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-233-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:234:\t\tif (lan966x_dcb_apptrust_policies[i].nselectors != nselectors)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-235-\t\t\tcontinue;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-238-\t\tfor (int j = 0; j \u003c nselectors; j++) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:239:\t\t\tif (lan966x_dcb_apptrust_policies[i].selectors[j] !=\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-240-\t\t\t    *(selectors + j)) {\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-249-\tnetdev_err(dev, \"Valid apptrust configurations are:\\n\");\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:250:\tfor (int i = 0; i \u003c ARRAY_SIZE(lan966x_dcb_apptrust_names); i++)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:251:\t\tpr_info(\"order: %s\\n\", lan966x_dcb_apptrust_names[i]);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-252-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-255-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:256:static int lan966x_dcb_setapptrust(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-257-\t\t\t\t   u8 *selectors,\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-259-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:260:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-261-\tint idx;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-262-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:263:\tidx = lan966x_dcb_apptrust_validate(dev, selectors, nselectors);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-264-\tif (idx \u003c 0)\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-266-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:267:\tlan966x_port_apptrust[port-\u003echip_port] = \u0026lan966x_dcb_apptrust_policies[idx];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:268:\tlan966x_dcb_app_update(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-269-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-272-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:273:static int lan966x_dcb_getapptrust(struct net_device *dev, u8 *selectors,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-274-\t\t\t\t   int *nselectors)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-275-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:276:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:277:\tconst struct lan966x_dcb_apptrust *trust;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-278-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:279:\ttrust = lan966x_port_apptrust[port-\u003echip_port];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-280-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-286-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:287:static int lan966x_dcb_delrewr(struct net_device *dev, struct dcb_app *app)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-288-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-291-\tif (app-\u003eselector == IEEE_8021QAZ_APP_SEL_DSCP)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:292:\t\terr = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_delrewr);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-293-\telse\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-298-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:299:\tlan966x_dcb_app_update(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-300-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-303-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:304:static int lan966x_dcb_setrewr(struct net_device *dev, struct dcb_app *app)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-305-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-309-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:310:\terr = lan966x_dcb_app_validate(dev, app);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-311-\tif (err)\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-318-\t\tapp_itr.protocol = proto;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:319:\t\tlan966x_dcb_delrewr(dev, \u0026app_itr);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-320-\t}\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-322-\tif (app-\u003eselector == IEEE_8021QAZ_APP_SEL_DSCP)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:323:\t\terr = lan966x_dcb_ieee_dscp_setdel(dev, app, dcb_setrewr);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-324-\telse\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-329-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:330:\tlan966x_dcb_app_update(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-331-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-335-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:336:static const struct dcbnl_rtnl_ops lan966x_dcbnl_ops = {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:337:\t.ieee_setapp = lan966x_dcb_ieee_setapp,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:338:\t.ieee_delapp = lan966x_dcb_ieee_delapp,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:339:\t.dcbnl_setapptrust = lan966x_dcb_setapptrust,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:340:\t.dcbnl_getapptrust = lan966x_dcb_getapptrust,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:341:\t.dcbnl_setrewr = lan966x_dcb_setrewr,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:342:\t.dcbnl_delrewr = lan966x_dcb_delrewr,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-343-};\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-344-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:345:void lan966x_dcb_init(struct lan966x *lan966x)\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-346-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:347:\tfor (int p = 0; p \u003c lan966x-\u003enum_phys_ports; ++p) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:348:\t\tstruct lan966x_port *port;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-349-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:350:\t\tport = lan966x-\u003eports[p];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-351-\t\tif (!port)\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-353-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:354:\t\tport-\u003edev-\u003edcbnl_ops = \u0026lan966x_dcbnl_ops;\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-355-\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:356:\t\tlan966x_port_apptrust[port-\u003echip_port] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:357:\t\t\t\u0026lan966x_dcb_apptrust_policies[LAN966X_DCB_APPTRUST_DSCP_PCP];\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-358-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-361-\t\t */\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c:362:\t\tlan966x_port_qos_dscp_rewr_mode_set(port,\ndrivers/net/ethernet/microchip/lan966x/lan966x_dcb.c-363-\t\t\t\t\t\t    LAN966X_PORT_QOS_REWR_DSCP_ALL);\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-4-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:5:#include \"lan966x_main.h\"\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-6-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-10-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:11:static const struct lan966x_stat_layout lan966x_stats_layout[] = {\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-12-\t{ .name = \"rx_octets\", .offset = 0x00, },\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-147-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:148:/* The following numbers are indexes into lan966x_stats_layout[] */\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-149-#define SYS_COUNT_RX_OCT\t\t  0\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-284-/* Add a possibly wrapping 32 bit value to a 64 bit counter */\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:285:static void lan966x_add_cnt(u64 *cnt, u32 val)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-286-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-292-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:293:static void lan966x_stats_update(struct lan966x *lan966x)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-294-{\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-296-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:297:\tspin_lock(\u0026lan966x-\u003estats_lock);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-298-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:299:\tfor (i = 0; i \u003c lan966x-\u003enum_phys_ports; i++) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:300:\t\tuint idx = i * lan966x-\u003enum_stats;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-301-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-302-\t\tlan_wr(SYS_STAT_CFG_STAT_VIEW_SET(i),\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:303:\t\t       lan966x, SYS_STAT_CFG);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-304-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:305:\t\tfor (j = 0; j \u003c lan966x-\u003enum_stats; j++) {\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:306:\t\t\tu32 offset = lan966x-\u003estats_layout[j].offset;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-307-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:308:\t\t\tlan966x_add_cnt(\u0026lan966x-\u003estats[idx++],\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:309:\t\t\t\t\tlan_rd(lan966x, SYS_CNT(offset)));\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-310-\t\t}\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-312-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:313:\tspin_unlock(\u0026lan966x-\u003estats_lock);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-314-}\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-315-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:316:static int lan966x_get_sset_count(struct net_device *dev, int sset)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-317-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:318:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:319:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-320-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-323-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:324:\treturn lan966x-\u003enum_stats;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-325-}\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-326-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:327:static void lan966x_get_strings(struct net_device *netdev, u32 sset, u8 *data)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-328-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:329:\tstruct lan966x_port *port = netdev_priv(netdev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:330:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-331-\tint i;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-335-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:336:\tfor (i = 0; i \u003c lan966x-\u003enum_stats; i++)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-337-\t\tmemcpy(data + i * ETH_GSTRING_LEN,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:338:\t\t       lan966x-\u003estats_layout[i].name, ETH_GSTRING_LEN);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-339-}\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-340-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:341:static void lan966x_get_ethtool_stats(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-342-\t\t\t\t      struct ethtool_stats *stats, u64 *data)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-343-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:344:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:345:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-346-\tint i;\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-348-\t/* check and update now */\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:349:\tlan966x_stats_update(lan966x);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-350-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-351-\t/* Copy all counters */\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:352:\tfor (i = 0; i \u003c lan966x-\u003enum_stats; i++)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:353:\t\t*data++ = lan966x-\u003estats[port-\u003echip_port *\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:354:\t\t\t\t\t lan966x-\u003enum_stats + i];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-355-}\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-356-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:357:static void lan966x_get_eth_mac_stats(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-358-\t\t\t\t      struct ethtool_eth_mac_stats *mac_stats)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-359-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:360:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:361:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-362-\tu32 idx;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-363-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:364:\tlan966x_stats_update(lan966x);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-365-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:366:\tidx = port-\u003echip_port * lan966x-\u003enum_stats;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-367-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:368:\tspin_lock(\u0026lan966x-\u003estats_lock);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-369-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-370-\tmac_stats-\u003eFramesTransmittedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:371:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_UC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:372:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_MC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:373:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_BC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:374:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_UC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:375:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_MC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:376:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_BC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-377-\tmac_stats-\u003eSingleCollisionFrames =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:378:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_COL];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-379-\tmac_stats-\u003eFramesReceivedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:380:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_UC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:381:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_MC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:382:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_BC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-383-\tmac_stats-\u003eFrameCheckSequenceErrors =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:384:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_CRC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:385:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_CRC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-386-\tmac_stats-\u003eOctetsTransmittedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:387:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_OCT] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:388:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_OCT];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-389-\tmac_stats-\u003eFramesWithDeferredXmissions =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:390:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_MM_HOLD];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-391-\tmac_stats-\u003eOctetsReceivedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:392:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_OCT];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-393-\tmac_stats-\u003eMulticastFramesXmittedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:394:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_MC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:395:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_MC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-396-\tmac_stats-\u003eBroadcastFramesXmittedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:397:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_BC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:398:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_BC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-399-\tmac_stats-\u003eMulticastFramesReceivedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:400:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_MC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-401-\tmac_stats-\u003eBroadcastFramesReceivedOK =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:402:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_BC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-403-\tmac_stats-\u003eInRangeLengthErrors =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:404:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_FRAG] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:405:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_JABBER] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:406:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_CRC] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:407:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_FRAG] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:408:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_JABBER] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:409:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_CRC];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-410-\tmac_stats-\u003eOutOfRangeLengthField =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:411:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SHORT] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:412:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SHORT] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:413:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_LONG] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:414:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_LONG];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-415-\tmac_stats-\u003eFrameTooLongErrors =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:416:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_LONG] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:417:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_LONG];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-418-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:419:\tspin_unlock(\u0026lan966x-\u003estats_lock);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-420-}\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-421-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:422:static const struct ethtool_rmon_hist_range lan966x_rmon_ranges[] = {\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-423-\t{    0,    64 },\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-432-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:433:static void lan966x_get_eth_rmon_stats(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-434-\t\t\t\t       struct ethtool_rmon_stats *rmon_stats,\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-436-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:437:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:438:\tstruct lan966x *lan966x = port-\u003elan966x;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-439-\tu32 idx;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-440-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:441:\tlan966x_stats_update(lan966x);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-442-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:443:\tidx = port-\u003echip_port * lan966x-\u003enum_stats;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-444-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:445:\tspin_lock(\u0026lan966x-\u003estats_lock);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-446-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-447-\trmon_stats-\u003eundersize_pkts =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:448:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SHORT] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:449:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SHORT];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-450-\trmon_stats-\u003eoversize_pkts =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:451:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_LONG] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:452:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_LONG];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-453-\trmon_stats-\u003efragments =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:454:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_FRAG] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:455:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_FRAG];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-456-\trmon_stats-\u003ejabbers =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:457:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_JABBER] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:458:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_JABBER];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-459-\trmon_stats-\u003ehist[0] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:460:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_64] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:461:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_64];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-462-\trmon_stats-\u003ehist[1] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:463:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_65_127] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:464:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_65_127];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-465-\trmon_stats-\u003ehist[2] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:466:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_128_255] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:467:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_128_255];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-468-\trmon_stats-\u003ehist[3] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:469:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_256_511] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:470:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_256_511];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-471-\trmon_stats-\u003ehist[4] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:472:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_512_1023] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:473:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_512_1023];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-474-\trmon_stats-\u003ehist[5] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:475:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_1024_1526] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:476:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-477-\trmon_stats-\u003ehist[6] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:478:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_SZ_1024_1526] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:479:\t\tlan966x-\u003estats[idx + SYS_COUNT_RX_PMAC_SZ_1024_1526];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-480-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-481-\trmon_stats-\u003ehist_tx[0] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:482:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_64] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:483:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_64];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-484-\trmon_stats-\u003ehist_tx[1] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:485:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_65_127] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:486:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_65_127];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-487-\trmon_stats-\u003ehist_tx[2] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:488:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_128_255] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:489:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_128_255];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-490-\trmon_stats-\u003ehist_tx[3] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:491:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_256_511] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:492:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_256_511];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-493-\trmon_stats-\u003ehist_tx[4] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:494:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_512_1023] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:495:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_512_1023];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-496-\trmon_stats-\u003ehist_tx[5] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:497:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_1024_1526] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:498:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-499-\trmon_stats-\u003ehist_tx[6] =\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:500:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_SZ_1024_1526] +\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:501:\t\tlan966x-\u003estats[idx + SYS_COUNT_TX_PMAC_SZ_1024_1526];\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-502-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:503:\tspin_unlock(\u0026lan966x-\u003estats_lock);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-504-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:505:\t*ranges = lan966x_rmon_ranges;\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-506-}\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-507-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:508:static int lan966x_get_link_ksettings(struct net_device *ndev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-509-\t\t\t\t      struct ethtool_link_ksettings *cmd)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-510-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:511:\tstruct lan966x_port *port = netdev_priv(ndev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-512-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-515-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:516:static int lan966x_set_link_ksettings(struct net_device *ndev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-517-\t\t\t\t      const struct ethtool_link_ksettings *cmd)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-518-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:519:\tstruct lan966x_port *port = netdev_priv(ndev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-520-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-523-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:524:static void lan966x_get_pauseparam(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-525-\t\t\t\t   struct ethtool_pauseparam *pause)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-526-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:527:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-528-\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-531-\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:532:static int lan966x_set_pauseparam(struct net_device *dev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-533-\t\t\t\t  struct ethtool_pauseparam *pause)\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-534-{\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c:535:\tstruct lan966x_port *port = netdev_priv(dev);\ndrivers/net/ethernet/microchip/lan966x/lan966x_ethtool.c-536-\n\n"
}

37/2 2026/07/02 12:01 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 194692
							output: 30
							thoughts: 781
						

Thoughts:
**Analyzing the LAN9645x Driver's Virtualization Viability**

Okay, so I'm looking at this `lan9645x` driver, and immediately my mind is jumping around the kernel tree. First, I remember `lan966x` being a switch driver, but wait, it's a *switchdev* driver and in `drivers/net/ethernet/microchip/lan966x/`. That's different from `lan9645x`, which is a DSA driver, and living at `drivers/net/dsa/microchip/lan9645x/`.

My next thought is, is there an MFD driver for `lan9645x`? I went digging through the `drivers/` directory, and I am only finding entries under `drivers/net/dsa/microchip/lan9645x/` and a pinctrl binding file. This makes it pretty clear – there's no MFD driver, or even a parent driver, in the kernel's source tree. That's a red flag. If the parent isn't there, the `lan9645x` driver won't even be able to probe, right?

But wait! Could the device tree even create the parent without an MFD? Thinking it through, let's say the DT has a node like this:
```dts
    ethernet-switch@4000 {
        compatible = "microchip,lan96459f-switch", "microchip,lan96455s-switch";
        reg = <0x4000 0x244>;
```
I recall the DT bindings having `reg = <0x4000 0x244>`. But the driver uses `dev_get_regmap(lan9645x->dev->parent, resource_name)`. That means the parent device *needs* a regmap. If this node is a child of a `syscon` or `mfd` node, that parent could supply those regmaps.

The question then is, what driver matches the parent? It would need to provide things like "gcb", "qs", "chip_top", that sort of stuff. If that parent driver *doesn't* exist in the kernel, `lan9645x_probe` is doomed to fail every time.

Now, let me think about `dev_get_regmap` and `syscon`. I know that `syscon` registers regmaps, but those aren't attached to the `dev` structure in a way that `dev_get_regmap` can just *find* them by name. `dev_get_regmap` needs a specific name in the `dev`'s regmap list. Typically, this is set up by `devm_regmap_init` in the *parent* driver.

So, no parent driver = no regmaps. Therefore, no probing. No probing, means no fuzzing!

Finally, let's circle back to the original task. The instructions say to return `WorthFuzzing=false` if the code paths are unreachable in virtualized environments. Because this is a hardware driver for a *specific* switch, and it needs a parent providing those specific regmaps, and the parent is *nowhere* to be found in the current kernel, that sounds impossible to reach in a virtualized environment.

Now, the final thought, just in case: is there any chance the `lan966x` MFD driver could somehow be the source of these regmaps? Let's check if the `lan966x` code also acts as an MFD driver.



38/2 2026/07/02 12:01 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "lan966x",
  "PathPrefix": "drivers/mfd/"
}

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

39/2 2026/07/02 12:01 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 196326
							output: 42
							thoughts: 55
						

Thoughts:
**Analyzing the LAN966X Driver Initialization**

Okay, so the answer is a firm "no," whatever the initial question was. But wait... what about the parent device for the `lan966x`? That's the key. I need to understand how the driver gets its `regmaps`. Let's dig into the code. I'll head over to `drivers/net/ethernet/microchip/lan966x/lan966x_main.c` and focus on how the `lan966x`'s register maps are established. That's likely where the root of the answer lies. This'll tell me how the hardware abstraction is implemented.



40/2 2026/07/02 12:02 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "dev_get_regmap",
  "PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}

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

41/2 2026/07/02 12:02 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 196588
							output: 41
							thoughts: 16
						

Thoughts:
Okay, let's dive into this. Here's my thought process on how the `lan966x` retrieves its registers, summarized in the first person:

**Investigating the LAN966x Register Acquisition**

Alright, time to get to the heart of the matter – how the `lan966x` actually accesses its registers. I need to understand this process intimately. First, I need to know where the initialization function lives, and whether the driver itself creates the register map in memory.

I'll be looking for the standard access patterns - is it memory-mapped I/O, or does it utilize some kind of indirect access mechanism through a control register? I need to figure out what base address it's using, and whether any bus-specific configuration is involved (like I2C, SPI, or something custom). Maybe it relies on device tree bindings, and if so, how's that information propagated to the driver?

I'll start tracing the initialization sequence. I'll search for calls to functions that look like they're handling register reads or writes, paying close attention to any variables that seem to represent base addresses, register offsets, or even bus-specific configuration parameters.

I need to see if it's using any abstraction layers, like a register map structure or helper functions. This could give me a very high level overview of the architecture. I'm hoping it's well-documented (although I know that's not always the case!). Any inline comments would be gold at this point!

Ultimately, my goal is to build a mental model of *exactly* how the driver interacts with the hardware registers of the `lan966x`. I need to figure out the chain of events that leads to register access, from driver initialization to actual data manipulation. That's the key to understanding the deeper behavior of the hardware.



42/2 2026/07/02 12:02 tool grepper
0m Args:
{
  "Expression": "devm_ioremap",
  "PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}

Results:
{
  "Output": "drivers/net/ethernet/microchip/lan966x/lan966x_main.c=67=static int lan966x_create_targets(struct platform_device *pdev,\n--\ndrivers/net/ethernet/microchip/lan966x/lan966x_main.c-86-\ndrivers/net/ethernet/microchip/lan966x/lan966x_main.c:87:\t\tbegin[idx] = devm_ioremap(\u0026pdev-\u003edev,\ndrivers/net/ethernet/microchip/lan966x/lan966x_main.c-88-\t\t\t\t\t  iores[idx]-\u003estart,\n"
}

43/2 2026/07/02 12:02 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 197215
							output: 154
							thoughts: 925
						

Thoughts:
**Unreachable Code Paths: LAN9645x Driver Analysis**

Okay, so I've been digging into this patch. My initial thought is that the `lan966x` driver seems to directly use `devm_ioremap` for its resources, which is fine, but the `lan9645x` driver takes a different approach using `dev_get_regmap`. This means it *expects* a parent device to have already set up the regmaps. The problem? There isn't a corresponding parent device driver in the kernel that would do this for `lan9645x`. Right off the bat, that makes the `lan9645x` driver un-probed.

Even if we *could* get it to probe, we're dealing with a hardware driver. It's meant to interact with physical switch registers. Without the actual hardware, or at least a specific emulator for this Microchip device, the probe will fail reading the hardware ID, or it will just be a dud, essentially. And, as far as I know, syzkaller doesn't have an emulator for the LAN9645x. So, it's pretty much a dead end in virtualized environments like GCE or QEMU.

Just to be thorough, I quickly checked if there's any software emulation. Nope, nothing.

Therefore, `WorthFuzzing=false` is the conclusion. It's a hardware driver that's completely out of reach in our environment.

But, I need to make *absolutely* sure. What about the tag driver, `tag_lan9645x.c`? Could that be reached somehow? I remember from my earlier check that `dsa_loop` doesn't implement `change_tag_protocol`. Are there any other virtual DSA switches that could use it? No, there aren't. Can we instantiate the tag driver directly? No, it's only called when used by the DSA core.

Since we can't get the hardware switch to probe, and no virtual switch supports changing to it, the tag driver is also inaccessible.

Just to confirm, I quickly looked at `dsa_loop.c` and verified that it does not implement `change_tag_protocol`. In the code I see:
```c
static const struct dsa_switch_ops dsa_loop_driver = {
	.get_strings		= dsa_loop_get_strings,
	.get_ethtool_stats	= dsa_loop_get_ethtool_stats,
	.get_sset_count		= dsa_loop_get_sset_count,
	.get_rxnfc		= dsa_loop_get_rxnfc,
	.set_rxnfc		= dsa_loop_set_rxnfc,
	.port_bridge_join	= dsa_loop_port_bridge_join,
	.port_bridge_leave	= dsa_loop_port_bridge_leave,
	.port_stp_state_set	= dsa_loop_port_stp_state_set,
	.port_vlan_filtering	= dsa_loop_port_vlan_filtering,
	.port_vlan_add		= dsa_loop_port_vlan_add,
	.port_vlan_del		= dsa_loop_port_vlan_del,
	.phy_read		= dsa_loop_phy_read,
	.phy_write		= dsa_loop_phy_write,
};
```
So, as expected, `dsa_tree_change_tag_proto` would return `-EOPNOTSUPP`.

So, the entire patch is completely unreachable in a virtualized environment.

I'll go ahead and set `WorthFuzzing=false` and document the reasons.



44/2 2026/07/02 12:02 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch adds a new DSA switch driver and a tag driver for the Microchip LAN9645x hardware. The switch driver requires specific regmaps provided by a parent device, which does not exist in the kernel, making it impossible to probe. Even if probed, it requires physical hardware that is not emulated in virtualized environments like QEMU/GCE. The tag driver is also unreachable because no virtual DSA switch (like `dsa_loop`) supports changing its tag protocol to `lan9645x` dynamically. Thus, the code cannot be executed or fuzzed.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch adds a new DSA switch driver and a tag driver for the Microchip LAN9645x hardware. The switch driver requires specific regmaps provided by a parent device, which does not exist in the kernel, making it impossible to probe. Even if probed, it requires physical hardware that is not emulated in virtualized environments like QEMU/GCE. The tag driver is also unreachable because no virtual DSA switch (like `dsa_loop`) supports changing its tag protocol to `lan9645x` dynamically. Thus, the code cannot be executed or fuzzed.",
  "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)