| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/13 19:28 | flow | patch-triage |
13mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch adds a new DSA switch driver for Microchip LAN9645x. However, the driver's probe function expects its parent device to provide 18 specific regmaps (e.g., \"gcb\", \"qs\", \"chip_top\") via dev_get_regmap(). There is no MFD driver in the kernel that creates and attaches these regmaps. Without them, the probe function will always fail with -ENODEV. Consequently, the switch driver cannot be instantiated, and its associated tag driver (tag_lan9645x.c) will never be used, making the entire functional code unreachable.",
"WorthFuzzing": false
} |
| 1/1 | 2026/07/13 19:28 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit e437ea585ab396adaac98ebf8fc3a24ce68d6202\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Jul 13 19:28:53 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 f3218abefd0c6b..378f14ec65bfee 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -17622,6 +17622,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..6a14ba36616258\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c\n@@ -0,0 +1,1038 @@\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-\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-\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-\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..6423fa41533030\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h\n@@ -0,0 +1,439 @@\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+\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..836abc74b6f7a3\n--- /dev/null\n+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c\n@@ -0,0 +1,382 @@\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 ... 4:\n+\t\t__set_bit(PHY_INTERFACE_MODE_GMII, 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+\n+\tif (port == 5 || port == 6 || port \u003e 8)\n+\t\treturn -EINVAL;\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+\t/* DEV4 is cuphy-only, so RGMII_0 is always routed to DEV7 (its reset\n+\t * default); make it explicit on a DEV7 RGMII bring-up.\n+\t */\n+\tif (port == 7 \u0026\u0026 phy_interface_mode_is_rgmii(iface))\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+\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..2692c7ad56cbc8\n--- /dev/null\n+++ b/net/dsa/tag_lan9645x.c\n@@ -0,0 +1,316 @@\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))\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\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\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\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\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\tkfree_skb(skb);\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/13 19:28 | agent | patch-evaluator |
13mModel:gemini-3.1-pro-preview Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch adds a new DSA switch driver for Microchip LAN9645x. However, the driver's probe function expects its parent device to provide 18 specific regmaps (e.g., \"gcb\", \"qs\", \"chip_top\") via dev_get_regmap(). There is no MFD driver in the kernel that creates and attaches these regmaps. Without them, the probe function will always fail with -ENODEV. Consequently, the switch driver cannot be instantiated, and its associated tag driver (tag_lan9645x.c) will never be used, making the entire functional code unreachable.",
"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 e437ea585ab396adaac98ebf8fc3a24ce68d6202
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Jul 13 19:28:53 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 f3218abefd0c6b..378f14ec65bfee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17622,6 +17622,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..6a14ba36616258
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
@@ -0,0 +1,1038 @@
+// 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->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->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->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..6423fa41533030
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.h
@@ -0,0 +1,439 @@
+/* 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;
+
+ /* 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..836abc74b6f7a3
--- /dev/null
+++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_phylink.c
@@ -0,0 +1,382 @@
+// 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 ... 4:
+ __set_bit(PHY_INTERFACE_MODE_GMII, 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;
+
+ if (port == 5 || port == 6 || port > 8)
+ return -EINVAL;
+
+ lan_rmw(HSIO_HW_CFG_GMII_ENA_SET(BIT(port)),
+ HSIO_HW_CFG_GMII_ENA_SET(BIT(port)), lan9645x, HSIO_HW_CFG);
+
+ /* DEV4 is cuphy-only, so RGMII_0 is always routed to DEV7 (its reset
+ * default); make it explicit on a DEV7 RGMII bring-up.
+ */
+ if (port == 7 && phy_interface_mode_is_rgmii(iface))
+ lan_rmw(HSIO_HW_CFG_RGMII_0_CFG_SET(0),
+ HSIO_HW_CFG_RGMII_0_CFG,
+ lan9645x, HSIO_HW_CFG);
+
+ 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(®ion_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..2692c7ad56cbc8
--- /dev/null
+++ b/net/dsa/tag_lan9645x.c
@@ -0,0 +1,316 @@
+// 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))
+ 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))) {
+ kfree_skb(skb);
+ 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))) {
+ kfree_skb(skb);
+ 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.
+ */
+ kfree_skb(skb);
+ 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/13 19:28 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 115695 output: 33 thoughts: 904 Thoughts: **Analyzing the LAN9645x Ethernet Switch Driver for Potential Fuzzing** Okay, so we have a new patch adding support for the Microchip LAN9645x Ethernet switch. It includes the usual suspects: device tree bindings, MAINTAINERS update, Kconfig and Makefile changes, the driver itself, and a DSA tag driver. The core of this is a DSA driver, which implements the standard `dsa_switch_ops` and `dsa_device_ops` interfaces. Functionally, this code *should* be reachable if the driver is loaded and bound. However, a key question for fuzzing is: can this be reached in a virtualized environment like the one syzkaller uses? DSA drivers often rely on specific hardware access (SPI, I2C, MDIO, or memory-mapped registers). My initial thought is to check how the driver is probed to identify these dependencies. Looking at `lan9645x_main.c`, it's a platform driver, which is good. Syzkaller *can* generate platform devices and probe them. The probe function itself calls `lan9645x_request_target_regmaps`. Digging into `lan9645x_request_target_regmaps`, it's clear the driver retrieves regmaps from its *parent* device using `dev_get_regmap`. Now we're getting somewhere. This is the crucial point for fuzzing. If syzkaller creates a platform device for "microchip,lan96455s-switch," its parent will *likely* be NULL or, at the very least, lack the specific regmaps the driver needs. Thinking further, let's verify how `dev_get_regmap` behaves with a NULL parent. The code returns NULL when passed a NULL dev, which means that if `lan9645x->dev->parent` is NULL, `dev_get_regmap` will return NULL, causing the probe to fail with `-ENODEV`. This is what I expect. Now, the real question becomes: Can syzkaller create a device *with* a parent *that* has the necessary regmaps? My experience with syzkaller's pseudo-devices – the `syz_gen_sysfs` constructs and such – is that they generally don't model complex parent-child relationships with specialized regmaps attached to the parent. Let's see if this `dev_get_regmap` assumption holds. |
| 4/2 | 2026/07/13 19:29 | tool | grepper |
0mArgs:{
"Expression": "dev_get_regmap",
"PathPrefix": "drivers/base/regmap/"
}Results: {
"Output": "drivers/base/regmap/regmap.c=484=__releases(\u0026map-\u003eraw_spinlock)\n--\ndrivers/base/regmap/regmap.c-489-\ndrivers/base/regmap/regmap.c:490:static void dev_get_regmap_release(struct device *dev, void *res)\ndrivers/base/regmap/regmap.c-491-{\n--\ndrivers/base/regmap/regmap.c=575=int regmap_attach_dev(struct device *dev, struct regmap *map,\n--\ndrivers/base/regmap/regmap.c-589-\ndrivers/base/regmap/regmap.c:590:\t/* Add a devres resource for dev_get_regmap() */\ndrivers/base/regmap/regmap.c:591:\tm = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);\ndrivers/base/regmap/regmap.c-592-\tif (!m) {\n--\ndrivers/base/regmap/regmap.c=601=EXPORT_SYMBOL_GPL(regmap_attach_dev);\ndrivers/base/regmap/regmap.c-602-\ndrivers/base/regmap/regmap.c:603:static int dev_get_regmap_match(struct device *dev, void *res, void *data);\ndrivers/base/regmap/regmap.c-604-\ndrivers/base/regmap/regmap.c=605=static int regmap_detach_dev(struct device *dev, struct regmap *map)\n--\ndrivers/base/regmap/regmap.c-609-\ndrivers/base/regmap/regmap.c:610:\treturn devres_release(dev, dev_get_regmap_release,\ndrivers/base/regmap/regmap.c:611:\t\t\t dev_get_regmap_match, (void *)map-\u003ename);\ndrivers/base/regmap/regmap.c-612-}\n--\ndrivers/base/regmap/regmap.c=1487=EXPORT_SYMBOL_GPL(regmap_exit);\ndrivers/base/regmap/regmap.c-1488-\ndrivers/base/regmap/regmap.c:1489:static int dev_get_regmap_match(struct device *dev, void *res, void *data)\ndrivers/base/regmap/regmap.c-1490-{\n--\ndrivers/base/regmap/regmap.c-1504-/**\ndrivers/base/regmap/regmap.c:1505: * dev_get_regmap() - Obtain the regmap (if any) for a device\ndrivers/base/regmap/regmap.c-1506- *\n--\ndrivers/base/regmap/regmap.c-1515- */\ndrivers/base/regmap/regmap.c:1516:struct regmap *dev_get_regmap(struct device *dev, const char *name)\ndrivers/base/regmap/regmap.c-1517-{\ndrivers/base/regmap/regmap.c:1518:\tstruct regmap **r = devres_find(dev, dev_get_regmap_release,\ndrivers/base/regmap/regmap.c:1519:\t\t\t\t\tdev_get_regmap_match, (void *)name);\ndrivers/base/regmap/regmap.c-1520-\n--\ndrivers/base/regmap/regmap.c-1524-}\ndrivers/base/regmap/regmap.c:1525:EXPORT_SYMBOL_GPL(dev_get_regmap);\ndrivers/base/regmap/regmap.c-1526-\n"
} |
| 5/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 118107 output: 32 thoughts: 69 Thoughts: **Analyzing the Probe Function Call** Okay, so I'm looking at this `probe` function and it's calling `dev_get_regmap` with `lan9645x->dev->parent` as the first argument. Now, immediately a red flag pops up in my head. If `lan9645x->dev->parent` happens to be `NULL`, then `dev_get_regmap` is going to be pointing to bad memory, and, at best, return `NULL`, but probably crash the kernel. I need to be *absolutely certain* that we handle the `NULL` case or this code is going to be dangerously unstable. Let's see how `devres_find` would behave in this instance, and verify that it wouldn't cause a problem. |
| 6/2 | 2026/07/13 19:29 | tool | grepper |
0mArgs:{
"Expression": "devres_find",
"PathPrefix": "drivers/base/devres.c"
}Results: {
"Output": "drivers/base/devres.c=285=static struct devres *find_dr(struct device *dev, dr_release_t release,\n--\ndrivers/base/devres.c-305-/**\ndrivers/base/devres.c:306: * devres_find - Find device resource\ndrivers/base/devres.c-307- * @dev: Device to lookup resource from\n--\ndrivers/base/devres.c-318- */\ndrivers/base/devres.c:319:void *devres_find(struct device *dev, dr_release_t release,\ndrivers/base/devres.c-320-\t\t dr_match_t match, void *match_data)\n--\ndrivers/base/devres.c-330-}\ndrivers/base/devres.c:331:EXPORT_SYMBOL_GPL(devres_find);\ndrivers/base/devres.c-332-\n"
} |
| 7/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 118624 output: 36 thoughts: 21 Thoughts: Here's my analysis of the provided text, summarized in the first person as a series of thoughts: **Analyzing the devres_find Function** Okay, let's dive into the code. The task is clear: I need to understand the function `devres_find` within `drivers/base/devres.c`. Given that I'm dealing with device resources, I'm already anticipating this function likely handles locating and retrieving resources associated with a specific device. I'll need to pay close attention to the arguments it takes – I'm betting one will be the device pointer itself, and another, likely some sort of resource identifier or type. I'll also be watching to see how it interacts with the underlying data structures used to manage these resources, probably looking for a list or hash table of some kind. This will be the key to understanding how devices are managed from the driver. Time to dig in and see how the kernel handles this! |
| 8/2 | 2026/07/13 19:29 | tool | read-file |
0mArgs:{
"File": "drivers/base/devres.c",
"FirstLine": 319,
"LineCount": 20
}Results: {
"Contents": " 319:\tvoid *devres_find(struct device *dev, dr_release_t release,\n 320:\t\t\t dr_match_t match, void *match_data)\n 321:\t{\n 322:\t\tstruct devres *dr;\n 323:\t\n 324:\t\tguard(spinlock_irqsave)(\u0026dev-\u003edevres_lock);\n 325:\t\tdr = find_dr(dev, release, match, match_data);\n 326:\t\tif (dr)\n 327:\t\t\treturn dr-\u003edata;\n 328:\t\n 329:\t\treturn NULL;\n 330:\t}\n 331:\tEXPORT_SYMBOL_GPL(devres_find);\n 332:\t\n 333:\t/**\n 334:\t * devres_get - Find devres, if non-existent, add one atomically\n 335:\t * @dev: Device to lookup or add devres for\n 336:\t * @new_res: Pointer to new initialized devres to add if not found\n 337:\t * @match: Match function (optional)\n 338:\t * @match_data: Data for the match function\n"
} |
| 9/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 119197 output: 29 thoughts: 443 Thoughts: **Analyzing a Potential Kernel Crash** Okay, so I'm looking at this code and immediately see a potential null pointer dereference. If `dev` is NULL, then `guard(spinlock_irqsave)(&dev->devres_lock);` is going to cause a crash. That's the obvious initial thought. But wait... Aren't syzkaller's platform devices supposed to have a `dev->parent` set to something like `platform_bus`? I need to check how syzkaller actually *creates* these platform devices. Does it use `syz_gen_sysfs` or `syz_dev_create`, and crucially, do those functions consistently assign a parent with the necessary regmaps? Ah, right. If `dev->parent` *is* just `platform_bus` or something similar, it *won't* have those regmaps. In that case, `dev_get_regmap` will definitely return NULL. Then, `IS_ERR_OR_NULL(tgt_map)` will evaluate to true, and the probe function will fail with an `-ENODEV` error. That's a good defensive programming stance from the code's author, but it prevents the trigger if it's the expected state for syzkaller. Now, the real question is: Can syzkaller somehow provide those regmaps? This is crucial. I need to understand what those regmaps actually are, and what devices they are associated with. The regmap names are: "gcb", "qs", "chip_top", "rew", "sys", "hsio", "dev", "dev1", "dev2", "dev3", "dev4", "dev5", "dev6", "dev7", "dev8", "qsys", "afi", "ana". Those names are familiar. These regmaps *must* be attached to the parent device somehow. Typically, these are created by an MFD (Multi-Function Device) driver. This MFD driver creates the regmaps and then spawns the switch as a child device, which would contain `lan9645x->dev->parent`. I need to figure out which MFD driver is responsible. Let's search the kernel source for "lan96455s-switch" or "microchip,lan96455s-switch" to find that MFD driver, since that driver *should* provide the regmaps. |
| 10/2 | 2026/07/13 19:29 | tool | grepper |
0mArgs:{
"Expression": "lan96455s-switch",
"PathPrefix": ""
}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=17629=S:\tMaintained\nMAINTAINERS:17630:F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nMAINTAINERS-17631-F:\tdrivers/net/dsa/microchip/lan9645x/*\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1019=static const struct of_device_id lan9645x_switch_of_match[] = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1020:\t{ .compatible = \"microchip,lan96455s-switch\" },\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1021-\t{},\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1025=static struct platform_driver lan9645x_switch_driver = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1026-\t.driver = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1027:\t\t.name = \"lan96455s-switch\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1028-\t\t.of_match_table = lan9645x_switch_of_match,\n"
} |
| 11/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 121278 output: 30 thoughts: 66 Thoughts: **Investigating the Missing Regmap Creation** Okay, so I'm looking at this code and I'm stumped. There's no obvious Multi-Function Device (MFD) driver that's responsible for creating these register maps. That's a red flag. Where are they being initialized? Hmm... Maybe the register maps aren't directly generated by an MFD driver. Perhaps another driver, potentially associated with the underlying bus, is handling this. This means I need to broaden my search. Let's start by looking for any references to "lan9645x" or "lan96455s" within the `drivers/mfd` and `drivers/bus` directories. That should give me a better understanding of which driver is responsible. Let's see what turns up. |
| 12/2 | 2026/07/13 19:29 | tool | grepper |
0mError:no matches Args: {
"Expression": "lan9645",
"PathPrefix": "drivers/mfd/"
}Results: {
"error": "no matches"
} |
| 13/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 121560 output: 27 thoughts: 37 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **LAN9645 Driver Hunt** Alright, time to track down all instances of "lan9645" within the driver tree. My first instinct, and the efficient way, is to do a targeted search. I need to be precise, though. I want to look for the base part, but I **absolutely** want to exclude the `drivers/net/dsa/microchip/lan9645x/` directory. That sub-directory, I already know, should be handling the *x* variant, and I want to make sure I don't get sidetracked by that specific implementation. Let's see what turns up, I'm expecting to find either parent drivers or related code to handle the part and how it is connected to a Dsa switch or another external component. This search should point to the relevant locations very quickly. |
| 14/2 | 2026/07/13 19:29 | tool | grepper |
0mArgs:{
"Expression": "lan9645",
"PathPrefix": "drivers/"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 2647 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-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-77-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-78-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:79:static int lan9645x_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-80-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:81:\treturn lan9645x_port_set_maxlen(ds-\u003epriv, port, new_mtu);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-82-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-83-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:84:static int lan9645x_get_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-85-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:86:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-87-\tint max_mtu;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-95-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:96:\tif (port == lan9645x-\u003enpi) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-97-\t\tmax_mtu -= LAN9645X_IFH_LEN;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-103-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:104:static int lan9645x_reset_switch(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-105-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-108-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:109:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:110:\tlan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan9645x, SYS_RAM_INIT);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:111:\terr = lan9645x_rd_poll_timeout(lan9645x, SYS_RAM_INIT, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-112-\t\t\t\t SYS_RAM_INIT_RAM_INIT_GET(val) == 0);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-113-\tif (err) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:114:\t\tdev_err(lan9645x-\u003edev, \"Failed to init chip RAM.\\n\");\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-115-\t\treturn err;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-116-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:117:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-118-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-121-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:122:static int lan9645x_setup(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-123-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:124:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:125:\tstruct device *dev = lan9645x-\u003edev;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-126-\tint supported, used = 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-130-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:131:\tlan9645x-\u003enum_phys_ports = ds-\u003enum_ports;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-132-\tfront_ports = dsa_user_ports(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:133:\tsupported = lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-134-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-144-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:145:\terr = lan9645x_reset_switch(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-146-\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-148-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:149:\terr = lan9645x_tag_npi_setup(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-150-\tif (err) {\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-154-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:155:\tmutex_init(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:156:\terr = lan9645x_vlan_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-157-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-158-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:159:\terr = lan9645x_mac_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-160-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-161-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:162:\tlan9645x_mdb_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-163-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-166-\t ANA_AGGR_CFG_AC_DMAC_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:167:\t lan9645x, ANA_AGGR_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-168-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-169-\t/* Flush queues */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:170:\tlan_wr(GENMASK(1, 0), lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-171-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-175-\t/* All Queues normal */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:176:\tlan_wr(0x0, lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-177-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-181-\tlan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:182:\t lan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-183-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-186-\t\tANA_ADVLEARN_VLAN_CHK,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:187:\t\tlan9645x, ANA_ADVLEARN);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-188-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-199-\t SYS_FRM_AGING_MAX_AGE_SET((2000000000 / 6182)),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:200:\t lan9645x, SYS_FRM_AGING);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-201-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-210-\t ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:211:\t lan9645x, ANA_FLOODING_IPMC);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-212-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-217-\t\t ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:218:\t\t lan9645x, ANA_FLOODING(prio));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-219-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-225-\t\tlan_wr(ANA_PGID_CFG_OBEY_VLAN_SET(1),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:226:\t\t lan9645x, ANA_PGID_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-227-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-228-\t/* Disable bridging by default */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:229:\tfor (int p = 0; p \u003c lan9645x-\u003enum_phys_ports; p++) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:230:\t\tlan_wr(0, lan9645x, ANA_PGID(PGID_SRC + p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-231-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-235-\t\tlan_wr(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:236:\t\t lan9645x, ANA_CPU_FWD_BPDU_CFG(p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-237-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-247-\t\t\tANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:248:\t\t\tlan9645x, ANA_CPUQ_8021_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-249-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-260-\tfor (int i = 0; i \u003c= QSYS_Q_RSRV; ++i) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:261:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:262:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(512 + i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-263-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-264-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:265:\tlan9645x_port_cpu_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-266-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-267-\t/* Multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:268:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-269-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-270-\t/* IP multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:271:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV4));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:272:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV6));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-273-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-274-\t/* Unicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:275:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_UC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-276-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-277-\t/* Broadcast to cpu and all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:278:\tlan_wr(BIT(lan9645x-\u003enum_phys_ports) | front_ports, lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-279-\t ANA_PGID(PGID_BC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-280-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:281:\tlan9645x_port_set_tail_drop_wm(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-282-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:283:\tlan9645x-\u003eowq = alloc_ordered_workqueue(\"%s-owq\", 0,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:284:\t\t\t\t\t\tdev_name(lan9645x-\u003edev));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:285:\tif (!lan9645x-\u003eowq) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-286-\t\terr = -ENOMEM;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-289-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:290:\tlan9645x_stats_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-291-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-302-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:303:\tdev_info(lan9645x-\u003edev,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-304-\t\t \"SKU features: max_ports=%d\\n\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:305:\t\t lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-306-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-309-err_mac:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:310:\tlan9645x_mac_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:311:\tlan9645x_mdb_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-312-err_mutex:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:313:\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:314:\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-315-\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-317-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:318:static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-319-\t\t\t\t\t struct phylink_config *config)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-320-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:321:\tlan9645x_phylink_get_caps(ds-\u003epriv, port, config);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-322-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-323-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:324:static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-325-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-326-\tu32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:327:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-328-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:329:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-330-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-336-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:337:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-338-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:339:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-340-\treturn 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-342-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:343:static int lan9645x_port_pre_bridge_flags(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-344-\t\t\t\t\t struct switchdev_brport_flags flags,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-353-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:354:static void lan9645x_port_pgid_set(struct lan9645x *lan9645x, u16 pgid,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-355-\t\t\t\t int chip_port, bool enabled)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-358-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:359:\tWARN_ON(chip_port \u003e lan9645x-\u003enum_phys_ports);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-360-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-363-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:364:\tlan_rmw(port_msk, reg_msk, lan9645x, ANA_PGID(pgid));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-365-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-366-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:367:static void lan9645x_port_set_learning(struct lan9645x *lan9645x, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-368-\t\t\t\t bool enabled)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-369-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:370:\tstruct lan9645x_port *p = lan9645x_to_port(lan9645x, port);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-371-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-377-\tlan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(enabled), ANA_PORT_CFG_LEARN_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:378:\t\tlan9645x, ANA_PORT_CFG(port));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-379-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-380-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:381:static int lan9645x_port_bridge_flags(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-382-\t\t\t\t struct switchdev_brport_flags f,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-384-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:385:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-386-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:387:\tif (WARN_ON(port == lan9645x-\u003enpi))\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-388-\t\treturn -EINVAL;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-390-\tif (f.mask \u0026 BR_LEARNING)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:391:\t\tlan9645x_port_set_learning(lan9645x, port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-392-\t\t\t\t\t !!(f.val \u0026 BR_LEARNING));\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-394-\tif (f.mask \u0026 BR_FLOOD)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:395:\t\tlan9645x_port_pgid_set(lan9645x, PGID_UC, port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-396-\t\t\t\t !!(f.val \u0026 BR_FLOOD));\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-400-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:401:\t\tlan9645x_port_pgid_set(lan9645x, PGID_MC, port, ena);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:402:\t\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV4, port, ena);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:403:\t\tlan9645x_port_pgid_set(lan9645x, PGID_MCIPV6, port, ena);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-404-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-406-\tif (f.mask \u0026 BR_BCAST_FLOOD)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:407:\t\tlan9645x_port_pgid_set(lan9645x, PGID_BC, port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-408-\t\t\t\t !!(f.val \u0026 BR_BCAST_FLOOD));\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-412-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:413:static void lan9645x_update_fwd_mask(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-414-{\n\n"
} |
| 15/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 140695 output: 29 thoughts: 404 Thoughts: **Analyzing the LAN9645x Switch Driver** Okay, let's break this down. I'm looking at this driver code and immediately see it's a platform driver, which is pretty standard. The core of this seems to be the `lan9645x_switch_driver` structure with its `of_match_table`. I understand this means the driver will attempt to probe when a compatible device is detected, specifically one that matches "microchip,lan96455s-switch." Syzkaller could trigger this probe, right? It could use `syz_gen_sysfs` or even simulate a device tree node to instantiate this device, which seems like a valid test scenario. But then there's the `probe` function. It's calling `dev_get_regmap` and that's the crucial bit. It uses `lan9645x->dev->parent` which is clearly trying to find a parent for this switch. And the critical detail? If the parent is NULL, `dev_get_regmap` will return NULL, and the probe fails with `-ENODEV`. So, here's the issue. Can Syzkaller create a device with a parent device, and then associate the right regmaps to that parent to satisfy this? No, that's the sticking point. Syzkaller doesn't have that level of fine-grained control over parent-child relationships and regmap assignment. It's essentially blind to the parent's regmap requirement. Wait a second, could this driver be part of a larger, more complex patch series that *does* include a MFD (Multi-Function Device) driver? Maybe this switch is expected to be a child of an MFD controller? That would be the logical way to handle the required regmaps. I need to investigate if there are other files in the patch or if there are other drivers within the tree that might provide the necessary parent device. |
| 16/2 | 2026/07/13 19:29 | tool | grepper |
0mArgs:{
"Expression": "lan96455s-switch",
"PathPrefix": ""
}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=17629=S:\tMaintained\nMAINTAINERS:17630:F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nMAINTAINERS-17631-F:\tdrivers/net/dsa/microchip/lan9645x/*\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1019=static const struct of_device_id lan9645x_switch_of_match[] = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1020:\t{ .compatible = \"microchip,lan96455s-switch\" },\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1021-\t{},\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c=1025=static struct platform_driver lan9645x_switch_driver = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1026-\t.driver = {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:1027:\t\t.name = \"lan96455s-switch\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-1028-\t\t.of_match_table = lan9645x_switch_of_match,\n"
} |
| 17/2 | 2026/07/13 19:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 142632 output: 30 thoughts: 488 Thoughts: **Debugging the Missing MFD Driver Dependency** Okay, so I'm looking at this LAN9645x driver and it's complaining about a missing MFD driver. It expects its parent to provide the `regmap`s, which is a common pattern. Right, the driver is supposed to get its register map from the parent, but I don't see one defined. Could the parent be a syscon device? If the device tree includes a syscon node, and this switch is a child, maybe the syscon driver will create the `regmap` we need. But then, to retrieve it with `dev_get_regmap` using a specific name, the `regmap` *must* be registered with that exact name. Let's check `lan9645x_resource_names`... *scrolling through the array* ... Okay, so we've got "gcb", "qs", "chip_top", "rew", "sys", "hsio", and then a bunch of "dev" instances, along with "qsys", "afi", and "ana". These names are all quite specific. There's not any common name there. So, if there's no driver in the kernel that registers `regmap`s with these *specific* names and acts as a parent, then this driver isn't going to probe correctly. I'm wondering, however, if the MFD driver is in the kernel under some *other* name. It could be hiding in plain sight. Let's do a quick search within `drivers/mfd` for "gcb" and "chip_top". Maybe it's just being used under a different name. I'll need to double check the kernel source for any register map names that match. |
| 18/2 | 2026/07/13 19:30 | tool | grepper |
0mError:no matches Args: {
"Expression": "\"chip_top\"",
"PathPrefix": "drivers/mfd/"
}Results: {
"error": "no matches"
} |
| 19/2 | 2026/07/13 19:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 143547 output: 25 thoughts: 17 Thoughts: Okay, here's my attempt at summarizing that thought process, keeping in mind I'm speaking to a fellow expert: **Investigating the Lan9645 within the Kernel** Alright, time to dive in. I need to get a handle on the "lan9645" – presumably some kind of hardware component. My first instinct is, let's see where this thing is showing up across the *entire* kernel source. A comprehensive search is the best starting point. This initial scan will reveal any existing drivers, mentions in device tree bindings, documentation, configuration files, or really *anything* that might give me context on its role and how it's integrated. It’s a broad approach, but the foundation to understanding how this component is handled within the kernel. I'll need to use my usual set of search tools, likely `grep` or `find` combined with some powerful filtering to narrow things down once the initial results come in. Let's start the search and see what we find. |
| 20/2 | 2026/07/13 19:30 | tool | grepper |
0mArgs:{
"Expression": "lan9645",
"PathPrefix": ""
}Results: {
"Output": "\nFull output is too long, showing 500 out of 2767 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=17629=S:\tMaintained\nMAINTAINERS:17630:F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan96455s-switch.yaml\nMAINTAINERS:17631:F:\tdrivers/net/dsa/microchip/lan9645x/*\nMAINTAINERS:17632:F:\tinclude/linux/dsa/lan9645x.h\nMAINTAINERS:17633:F:\tnet/dsa/tag_lan9645x.c\nMAINTAINERS-17634-\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-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-77-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-78-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:79:static int lan9645x_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-80-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:81:\treturn lan9645x_port_set_maxlen(ds-\u003epriv, port, new_mtu);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-82-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-83-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:84:static int lan9645x_get_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-85-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:86:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-87-\tint max_mtu;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-95-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:96:\tif (port == lan9645x-\u003enpi) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-97-\t\tmax_mtu -= LAN9645X_IFH_LEN;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-103-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:104:static int lan9645x_reset_switch(struct lan9645x *lan9645x)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-105-{\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-108-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:109:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(0), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:110:\tlan_wr(SYS_RAM_INIT_RAM_INIT_SET(1), lan9645x, SYS_RAM_INIT);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:111:\terr = lan9645x_rd_poll_timeout(lan9645x, SYS_RAM_INIT, val,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-112-\t\t\t\t SYS_RAM_INIT_RAM_INIT_GET(val) == 0);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-113-\tif (err) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:114:\t\tdev_err(lan9645x-\u003edev, \"Failed to init chip RAM.\\n\");\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-115-\t\treturn err;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-116-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:117:\tlan_wr(SYS_RESET_CFG_CORE_ENA_SET(1), lan9645x, SYS_RESET_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-118-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-121-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:122:static int lan9645x_setup(struct dsa_switch *ds)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-123-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:124:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:125:\tstruct device *dev = lan9645x-\u003edev;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-126-\tint supported, used = 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-130-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:131:\tlan9645x-\u003enum_phys_ports = ds-\u003enum_ports;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-132-\tfront_ports = dsa_user_ports(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:133:\tsupported = lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-134-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-144-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:145:\terr = lan9645x_reset_switch(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-146-\tif (err)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-148-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:149:\terr = lan9645x_tag_npi_setup(ds);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-150-\tif (err) {\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-154-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:155:\tmutex_init(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:156:\terr = lan9645x_vlan_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-157-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-158-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:159:\terr = lan9645x_mac_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-160-\tif (err)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-161-\t\tgoto err_mutex;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:162:\tlan9645x_mdb_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-163-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-166-\t ANA_AGGR_CFG_AC_DMAC_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:167:\t lan9645x, ANA_AGGR_CFG);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-168-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-169-\t/* Flush queues */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:170:\tlan_wr(GENMASK(1, 0), lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-171-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-175-\t/* All Queues normal */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:176:\tlan_wr(0x0, lan9645x, QS_XTR_FLUSH);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-177-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-181-\tlan_wr(ANA_AUTOAGE_AGE_PERIOD_SET(BR_DEFAULT_AGEING_TIME / 2 / HZ),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:182:\t lan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-183-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-186-\t\tANA_ADVLEARN_VLAN_CHK,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:187:\t\tlan9645x, ANA_ADVLEARN);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-188-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-199-\t SYS_FRM_AGING_MAX_AGE_SET((2000000000 / 6182)),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:200:\t lan9645x, SYS_FRM_AGING);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-201-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-210-\t ANA_FLOODING_IPMC_FLD_MC6_CTRL_SET(PGID_MC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:211:\t lan9645x, ANA_FLOODING_IPMC);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-212-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-217-\t\t ANA_FLOODING_FLD_BROADCAST_SET(PGID_BC),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:218:\t\t lan9645x, ANA_FLOODING(prio));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-219-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-225-\t\tlan_wr(ANA_PGID_CFG_OBEY_VLAN_SET(1),\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:226:\t\t lan9645x, ANA_PGID_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-227-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-228-\t/* Disable bridging by default */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:229:\tfor (int p = 0; p \u003c lan9645x-\u003enum_phys_ports; p++) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:230:\t\tlan_wr(0, lan9645x, ANA_PGID(PGID_SRC + p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-231-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-235-\t\tlan_wr(ANA_CPU_FWD_BPDU_CFG_BPDU_REDIR_ENA,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:236:\t\t lan9645x, ANA_CPU_FWD_BPDU_CFG(p));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-237-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-247-\t\t\tANA_CPUQ_8021_CFG_CPUQ_BPDU_VAL,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:248:\t\t\tlan9645x, ANA_CPUQ_8021_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-249-\t}\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-260-\tfor (int i = 0; i \u003c= QSYS_Q_RSRV; ++i) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:261:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:262:\t\tlan_wr(QS_SRC_BUF_RSV / 64, lan9645x, QSYS_RES_CFG(512 + i));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-263-\t}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-264-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:265:\tlan9645x_port_cpu_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-266-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-267-\t/* Multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:268:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-269-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-270-\t/* IP multicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:271:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV4));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:272:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_MCIPV6));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-273-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-274-\t/* Unicast to all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:275:\tlan_wr(front_ports, lan9645x, ANA_PGID(PGID_UC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-276-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-277-\t/* Broadcast to cpu and all front ports */\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:278:\tlan_wr(BIT(lan9645x-\u003enum_phys_ports) | front_ports, lan9645x,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-279-\t ANA_PGID(PGID_BC));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-280-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:281:\tlan9645x_port_set_tail_drop_wm(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-282-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:283:\tlan9645x-\u003eowq = alloc_ordered_workqueue(\"%s-owq\", 0,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:284:\t\t\t\t\t\tdev_name(lan9645x-\u003edev));\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:285:\tif (!lan9645x-\u003eowq) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-286-\t\terr = -ENOMEM;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-289-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:290:\tlan9645x_stats_init(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-291-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-302-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:303:\tdev_info(lan9645x-\u003edev,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-304-\t\t \"SKU features: max_ports=%d\\n\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:305:\t\t lan9645x-\u003enum_phys_ports - lan9645x-\u003enum_port_dis);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-306-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-309-err_mac:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:310:\tlan9645x_mac_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:311:\tlan9645x_mdb_deinit(lan9645x);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-312-err_mutex:\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:313:\tmutex_destroy(\u0026lan9645x-\u003efwd_domain_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:314:\tlan9645x_npi_port_deinit(lan9645x, lan9645x-\u003enpi);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-315-\treturn err;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-317-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:318:static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-319-\t\t\t\t\t struct phylink_config *config)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-320-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:321:\tlan9645x_phylink_get_caps(ds-\u003epriv, port, config);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-322-}\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-323-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:324:static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-325-{\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-326-\tu32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:327:\tstruct lan9645x *lan9645x = ds-\u003epriv;\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-328-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:329:\tmutex_lock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-330-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-336-\t\tANA_AUTOAGE_AGE_PERIOD,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:337:\t\tlan9645x, ANA_AUTOAGE);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-338-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:339:\tmutex_unlock(\u0026lan9645x-\u003emact_lock);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-340-\treturn 0;\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-342-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:343:static int lan9645x_port_pre_bridge_flags(struct dsa_switch *ds, int port,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-344-\t\t\t\t\t struct switchdev_brport_flags flags,\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-353-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:354:static void lan9645x_port_pgid_set(struct lan9645x *lan9645x, u16 pgid,\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-355-\t\t\t\t int chip_port, bool enabled)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-358-\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:359:\tWARN_ON(chip_port \u003e lan9645x-\u003enum_phys_ports);\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-360-\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-363-\n\n"
} |
| 21/2 | 2026/07/13 19:30 | llm | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 162334 output: 26 thoughts: 547 Thoughts: **Analyzing the LAN9645x Switch Driver** Okay, let's break this down. Ah, right, I see the connection now. The documentation (`Documentation/devicetree/bindings/pinctrl/mscc,ocelot-pinctrl.yaml`) lists several `microchip,lan9645x-pinctrl` compatible strings, clearly linking this to the `mscc,ocelot-pinctrl.yaml` binding. The `lan966x` stuff is throwing me a bit, I know that's already a switch driver in `drivers/net/ethernet/microchip/lan966x/`, but this is specifically for LAN9645x and sounds like it's a DSA driver. So, if the device is a platform device and the device tree specifies `compatible = "microchip,lan96455s-switch"`, the driver *should* probe. My real concern is this `dev_get_regmap(lan9645x->dev->parent, resource_name)` call. That's the critical piece. I'm wondering if a regmap can be retrieved from the parent of the switch. Right, `dev_get_regmap` searches for a regmap attached to the device using `devres_find`. Usually, the process uses `syscon_node_to_regmap` to extract a regmap from a syscon node. Now I remember... `dev_get_regmap` is *typically* used when a driver, like a Multi-Function Device (MFD), creates a regmap and attaches it to its own `dev` using `devm_regmap_init`. Then, its children would call `dev_get_regmap(dev->parent, name)`. So, the crux of the matter: If there *isn't* an MFD driver in the kernel that matches the parent of *this* switch and creates these regmaps (naming them, potentially "gcb" or "chip_top", based on my experience), this driver is going to fail to probe! I need to check the kernel drivers for this. I must look for any driver that's creating a regmap named "gcb" or "chip_top" or some other obvious name and then attaching it to its device. That's the key to this whole puzzle. |
| 22/2 | 2026/07/13 19:31 | tool | grepper |
0mArgs:{
"Expression": "\"gcb\"",
"PathPrefix": "drivers/"
}Results: {
"Output": "drivers/misc/lan966x_pci.dtso=75=\t\t\t\treset: reset@e200400c {\n--\ndrivers/misc/lan966x_pci.dtso-77-\t\t\t\t\treg = \u003c0xe200400c 0x4\u003e, \u003c0xe00c0000 0xa8\u003e;\ndrivers/misc/lan966x_pci.dtso:78:\t\t\t\t\treg-names = \"gcb\",\"cpu\";\ndrivers/misc/lan966x_pci.dtso-79-\t\t\t\t\t#reset-cells = \u003c1\u003e;\n--\ndrivers/misc/lan966x_pci.dtso=136=\t\t\t\tswitch: switch@e0000000 {\n--\ndrivers/misc/lan966x_pci.dtso-139-\t\t\t\t\t \u003c0xe2000000 0x0800000\u003e;\ndrivers/misc/lan966x_pci.dtso:140:\t\t\t\t\treg-names = \"cpu\", \"gcb\";\ndrivers/misc/lan966x_pci.dtso-141-\n--\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\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-12-\t[TARGET_QS] = \"qs\",\n"
} |
| 23/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 163866 output: 30 thoughts: 85 Thoughts: Here's my thought process, as if I were considering this myself: **Investigating Potential Regmap Creation** Okay, so I'm looking at this `drivers/misc/lan966x_pci.dtso` file and I notice the `reg-names = "gcb","cpu"` entry. That rings a bell, but it's important to remember that this is a *device tree overlay*. This isn't necessarily a driver directly creating a regmap using `devm_regmap_init`. The naming suggests register map usage, but the context matters. I need to be sure before I jump to any conclusions about how the register map is being handled. My next step is to see if there's an MFD (Multi-Function Device) driver in play here for either the LAN966x or a similar device, the LAN9645x. That would be the typical structure if there's a need to share register space. That's where I would expect to see the regmap creation happening, likely to organize and access the relevant hardware registers. |
| 24/2 | 2026/07/13 19:31 | tool | grepper |
0mError:no matches Args: {
"Expression": "lan966x",
"PathPrefix": "drivers/mfd/"
}Results: {
"error": "no matches"
} |
| 25/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 164227 output: 43 thoughts: 27 Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue: **LAN966x Driver Deep Dive** Alright, let's see... the `drivers/net/ethernet/microchip/lan966x/` directory... Hmm, the LAN966x Ethernet driver. My immediate question is: is this driver implementing a regmap abstraction? It's crucial for register access on these types of devices, especially when dealing with the complexities of these sorts of advanced Ethernet controllers. Good register abstraction is key to portability and maintainability. It simplifies hardware access across different platforms and revisions. I hope they did it right, or I may have to get involved! |
| 26/2 | 2026/07/13 19:31 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}Results: {
"error": "no matches"
} |
| 27/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 164463 output: 55 thoughts: 283 Thoughts: **Analyzing the Regmap Dependency**
Okay, so I'm thinking, hold on a second. The code uses `dev_get_regmap`, which means the regmap *has* to be attached to the *parent* device, right? But is there actually a driver that attaches a regmap to its own device and then has *children*? That's the key question. I briefly considered `drivers/mfd/syscon.c`, but nope, that uses `syscon_node_to_regmap` which is different.
Alright, let's try a targeted search. I'm going to look for any driver that has "microchip,lan96455s-switch" as a *parent*. That seems like the most logical next step to figure out how the regmap is being attached.
Wait, looking closer at the device tree example in the patch, it seems like the device entry looks like this:
```yaml
ethernet-switch@4000 {
compatible = "microchip,lan96459f-switch", "microchip,lan96455s-switch";
reg = <0x4000 0x244>;
ethernet-ports {
```
Hang on...there's no indication of a *parent* with a regmap defined in this example! The "reg" property is defined for the switch itself. This is confusing.
So if the device itself defines a 'reg', why is it even calling `dev_get_regmap(lan9645x->dev->parent, resource_name)`? Something's not connecting here. I'm going to go back and re-examine the `lan9645x_request_target_regmaps` function in detail to see if I'm missing something, since I clearly am.
|
| 28/2 | 2026/07/13 19:31 | tool | read-file |
0mArgs:{
"File": "drivers/net/dsa/microchip/lan9645x/lan9645x_main.c",
"FirstLine": 910,
"LineCount": 30
}Results: {
"Contents": " 910:\t\t * 1) Number of ports can be 5, 7 or 9. Any ports can be used, the chip\n 911:\t\t * tracks how many are active.\n 912:\t\t * 2) HSR/PRP. The duplicate discard table can be disabled.\n 913:\t\t * 3) TAS, frame preemption and PSFP can be disabled.\n 914:\t\t */\n 915:\t\tfeat_dis = lan_rd(lan9645x, GCB_FEAT_DISABLE);\n 916:\t\n 917:\t\tlan9645x-\u003enum_port_dis =\n 918:\t\t\tGCB_FEAT_DISABLE_FEAT_NUM_PORTS_DIS_GET(feat_dis);\n 919:\t}\n 920:\t\n 921:\tstatic int lan9645x_probe(struct platform_device *pdev)\n 922:\t{\n 923:\t\tstruct device *dev = \u0026pdev-\u003edev;\n 924:\t\tstruct lan9645x *lan9645x;\n 925:\t\tstruct dsa_switch *ds;\n 926:\t\tint err = 0;\n 927:\t\n 928:\t\tlan9645x = devm_kzalloc(dev, sizeof(*lan9645x), GFP_KERNEL);\n 929:\t\tif (!lan9645x)\n 930:\t\t\treturn dev_err_probe(dev, -ENOMEM,\n 931:\t\t\t\t\t \"Failed to allocate LAN9645X\");\n 932:\t\n 933:\t\tdev_set_drvdata(dev, lan9645x);\n 934:\t\tlan9645x-\u003edev = dev;\n 935:\t\n 936:\t\terr = lan9645x_request_target_regmaps(lan9645x);\n 937:\t\tif (err)\n 938:\t\t\treturn dev_err_probe(dev, err, \"Failed to request regmaps\");\n 939:\t\n"
} |
| 29/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 165752 output: 55 thoughts: 21 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Analyzing `lan9645x_request_target_regmaps`** Okay, I'm revisiting `lan9645x_request_target_regmaps`. Time to refresh my understanding, considering I've been working with these LAN controllers for a while now. I need to make sure I haven't missed any subtle implications or edge cases related to register map requests, particularly regarding potential race conditions or contention. I should pay close attention to the sequencing of calls to ensure data integrity, especially in multi-threaded environments. I'm going to look for areas related to the handling of target addresses, memory boundaries, and any potential for overflow or underflow conditions. Let's see if there are any recent commits related to this function that I need to be aware of. I'll also try to envision scenarios where specific configurations might stress this function, perhaps with a large number of concurrent requests or unusual target addresses. A deeper dive might reveal opportunities for optimization. |
| 30/2 | 2026/07/13 19:31 | tool | read-file |
0mArgs:{
"File": "drivers/net/dsa/microchip/lan9645x/lan9645x_main.c",
"FirstLine": 880,
"LineCount": 30
}Results: {
"Contents": " 880:\t\t.get_eth_ctrl_stats\t\t= lan9645x_get_eth_ctrl_stats,\n 881:\t};\n 882:\t\n 883:\tstatic int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)\n 884:\t{\n 885:\t\tconst char *resource_name;\n 886:\t\tstruct regmap *tgt_map;\n 887:\t\n 888:\t\tfor (int i = 0; i \u003c NUM_TARGETS; i++) {\n 889:\t\t\tresource_name = lan9645x_resource_names[i];\n 890:\t\t\tif (!resource_name)\n 891:\t\t\t\tcontinue;\n 892:\t\n 893:\t\t\ttgt_map = dev_get_regmap(lan9645x-\u003edev-\u003eparent, resource_name);\n 894:\t\t\tif (IS_ERR_OR_NULL(tgt_map)) {\n 895:\t\t\t\tdev_err(lan9645x-\u003edev, \"Failed to get regmap=%d\\n\", i);\n 896:\t\t\t\treturn -ENODEV;\n 897:\t\t\t}\n 898:\t\n 899:\t\t\tlan9645x-\u003ermap[i] = tgt_map;\n 900:\t\t}\n 901:\t\n 902:\t\treturn 0;\n 903:\t}\n 904:\t\n 905:\tstatic void lan9645x_set_feat_dis(struct lan9645x *lan9645x)\n 906:\t{\n 907:\t\tu32 feat_dis;\n 908:\t\n 909:\t\t/* The features which can be physically disabled on some SKUs are:\n"
} |
| 31/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 166536 output: 32 thoughts: 215 Thoughts: **Debugging a Driver Probe Failure**
Okay, so I'm seeing this probe failing. Looking at the code:
```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;
}
```
It's precisely what I suspected. If `lan9645x->dev->parent` is NULL, `dev_get_regmap` will, of course, return NULL, and the probe will correctly fail, preventing further issues.
But, hang on... it also seems that *even if* the parent exists, the call can still return NULL. That makes me think that `lan9645x->dev->parent` might *not* have the expected regmaps. So, the question becomes, what driver in the kernel is actually responsible for creating those regmaps in the first place? I need to track down who creates these registers, and the relevant resource names to confirm that they exist and are correctly configured.
Let's start searching for that `lan9645x_resource_names`, or maybe even a broader search on "gcb" and "dev_get_regmap." This should help me identify the responsible driver and see if there are any obvious configuration issues or missing dependencies. It's a classic case of debugging by code archaeology.
|
| 32/2 | 2026/07/13 19:31 | tool | grepper |
0mArgs:{
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/mfd/"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 863 lines.\nUse more precise expression if possible.\n\ndrivers/mfd/88pm800.c=405=static int pm800_pages_init(struct pm80x_chip *chip)\n--\ndrivers/mfd/88pm800.c-423-\ndrivers/mfd/88pm800.c:424:\tsubchip-\u003eregmap_power = devm_regmap_init_i2c(subchip-\u003epower_page,\ndrivers/mfd/88pm800.c-425-\t\t\t\t\t\t \u0026pm80x_regmap_config);\n--\ndrivers/mfd/88pm800.c-442-\ndrivers/mfd/88pm800.c:443:\tsubchip-\u003eregmap_gpadc = devm_regmap_init_i2c(subchip-\u003egpadc_page,\ndrivers/mfd/88pm800.c-444-\t\t\t\t\t\t \u0026pm80x_regmap_config);\n--\ndrivers/mfd/88pm80x.c=51=int pm80x_init(struct i2c_client *client)\n--\ndrivers/mfd/88pm80x.c-62-\ndrivers/mfd/88pm80x.c:63:\tmap = devm_regmap_init_i2c(client, \u0026pm80x_regmap_config);\ndrivers/mfd/88pm80x.c-64-\tif (IS_ERR(map)) {\n--\ndrivers/mfd/88pm860x-core.c=1130=static int pm860x_probe(struct i2c_client *client)\n--\ndrivers/mfd/88pm860x-core.c-1157-\tchip-\u003eid = verify_addr(client);\ndrivers/mfd/88pm860x-core.c:1158:\tchip-\u003eregmap = devm_regmap_init_i2c(client, \u0026pm860x_regmap_config);\ndrivers/mfd/88pm860x-core.c-1159-\tif (IS_ERR(chip-\u003eregmap)) {\n--\ndrivers/mfd/88pm886.c=86=static int pm886_probe(struct i2c_client *client)\n--\ndrivers/mfd/88pm886.c-102-\ndrivers/mfd/88pm886.c:103:\tregmap = devm_regmap_init_i2c(client, \u0026pm886_regmap_config);\ndrivers/mfd/88pm886.c-104-\tif (IS_ERR(regmap))\n--\ndrivers/mfd/ac100.c=88=static int ac100_rsb_probe(struct sunxi_rsb_device *rdev)\n--\ndrivers/mfd/ac100.c-99-\ndrivers/mfd/ac100.c:100:\tac100-\u003eregmap = devm_regmap_init_sunxi_rsb(rdev, \u0026ac100_regmap_config);\ndrivers/mfd/ac100.c-101-\tif (IS_ERR(ac100-\u003eregmap)) {\n--\ndrivers/mfd/acer-ec-a500.c=140=static int a500_ec_probe(struct i2c_client *client)\n--\ndrivers/mfd/acer-ec-a500.c-144-\ndrivers/mfd/acer-ec-a500.c:145:\tregmap = devm_regmap_init(\u0026client-\u003edev, \u0026a500_ec_regmap_bus,\ndrivers/mfd/acer-ec-a500.c-146-\t\t\t\t client, \u0026a500_ec_regmap_config);\n--\ndrivers/mfd/act8945a.c=31=static int act8945a_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/act8945a.c-35-\ndrivers/mfd/act8945a.c:36:\tregmap = devm_regmap_init_i2c(i2c, \u0026act8945a_regmap_config);\ndrivers/mfd/act8945a.c-37-\tif (IS_ERR(regmap)) {\n--\ndrivers/mfd/adp5585.c=688=static int adp5585_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/adp5585.c-730-\ndrivers/mfd/adp5585.c:731:\tadp5585-\u003eregmap = devm_regmap_init_i2c(i2c, regmap_config);\ndrivers/mfd/adp5585.c-732-\tif (IS_ERR(adp5585-\u003eregmap))\n--\ndrivers/mfd/altera-a10sr.c=113=static int altr_a10sr_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/altera-a10sr.c-130-\ndrivers/mfd/altera-a10sr.c:131:\ta10sr-\u003eregmap = devm_regmap_init_spi(spi, \u0026altr_a10sr_regmap_config);\ndrivers/mfd/altera-a10sr.c-132-\tif (IS_ERR(a10sr-\u003eregmap)) {\n--\ndrivers/mfd/altera-sysmgr.c=126=static int sysmgr_probe(struct platform_device *pdev)\n--\ndrivers/mfd/altera-sysmgr.c-150-\t\t/* Need physical address for SMCC call */\ndrivers/mfd/altera-sysmgr.c:151:\t\tregmap = devm_regmap_init(dev, NULL,\ndrivers/mfd/altera-sysmgr.c-152-\t\t\t\t\t (void *)(uintptr_t)res-\u003estart,\n--\ndrivers/mfd/altera-sysmgr.c-159-\t\tsysmgr_config.max_register = resource_size(res) - 4;\ndrivers/mfd/altera-sysmgr.c:160:\t\tregmap = devm_regmap_init_mmio(dev, base, \u0026sysmgr_config);\ndrivers/mfd/altera-sysmgr.c-161-\t}\n--\ndrivers/mfd/arizona-i2c.c=23=static int arizona_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/arizona-i2c.c-64-\ndrivers/mfd/arizona-i2c.c:65:\tarizona-\u003eregmap = devm_regmap_init_i2c(i2c, regmap_config);\ndrivers/mfd/arizona-i2c.c-66-\tif (IS_ERR(arizona-\u003eregmap)) {\n--\ndrivers/mfd/arizona-spi.c=191=static int arizona_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/arizona-spi.c-228-\ndrivers/mfd/arizona-spi.c:229:\tarizona-\u003eregmap = devm_regmap_init_spi(spi, regmap_config);\ndrivers/mfd/arizona-spi.c-230-\tif (IS_ERR(arizona-\u003eregmap)) {\n--\ndrivers/mfd/as3711.c=119=static int as3711_i2c_probe(struct i2c_client *client)\n--\ndrivers/mfd/as3711.c-146-\ndrivers/mfd/as3711.c:147:\tas3711-\u003eregmap = devm_regmap_init_i2c(client, \u0026as3711_regmap_config);\ndrivers/mfd/as3711.c-148-\tif (IS_ERR(as3711-\u003eregmap)) {\n--\ndrivers/mfd/as3722.c=336=static int as3722_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/as3722.c-354-\ndrivers/mfd/as3722.c:355:\tas3722-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026as3722_regmap_config);\ndrivers/mfd/as3722.c-356-\tif (IS_ERR(as3722-\u003eregmap)) {\n--\ndrivers/mfd/atc260x-i2c.c=15=static int atc260x_i2c_probe(struct i2c_client *client)\n--\ndrivers/mfd/atc260x-i2c.c-33-\ndrivers/mfd/atc260x-i2c.c:34:\tatc260x-\u003eregmap = devm_regmap_init_i2c(client, \u0026regmap_cfg);\ndrivers/mfd/atc260x-i2c.c-35-\tif (IS_ERR(atc260x-\u003eregmap)) {\n--\ndrivers/mfd/atmel-hlcdc.c=80=static int atmel_hlcdc_probe(struct platform_device *pdev)\n--\ndrivers/mfd/atmel-hlcdc.c-130-\ndrivers/mfd/atmel-hlcdc.c:131:\thlcdc-\u003eregmap = devm_regmap_init(dev, NULL, hregmap,\ndrivers/mfd/atmel-hlcdc.c-132-\t\t\t\t\t \u0026atmel_hlcdc_regmap_config);\n--\ndrivers/mfd/axp20x-i2c.c=25=static int axp20x_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/axp20x-i2c.c-41-\ndrivers/mfd/axp20x-i2c.c:42:\taxp20x-\u003eregmap = devm_regmap_init_i2c(i2c, axp20x-\u003eregmap_cfg);\ndrivers/mfd/axp20x-i2c.c-43-\tif (IS_ERR(axp20x-\u003eregmap)) {\n--\ndrivers/mfd/axp20x-rsb.c=25=static int axp20x_rsb_probe(struct sunxi_rsb_device *rdev)\n--\ndrivers/mfd/axp20x-rsb.c-41-\ndrivers/mfd/axp20x-rsb.c:42:\taxp20x-\u003eregmap = devm_regmap_init_sunxi_rsb(rdev, axp20x-\u003eregmap_cfg);\ndrivers/mfd/axp20x-rsb.c-43-\tif (IS_ERR(axp20x-\u003eregmap)) {\n--\ndrivers/mfd/bcm590xx.c=90=static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri)\n--\ndrivers/mfd/bcm590xx.c-104-\ndrivers/mfd/bcm590xx.c:105:\tbcm590xx-\u003eregmap_pri = devm_regmap_init_i2c(i2c_pri,\ndrivers/mfd/bcm590xx.c-106-\t\t\t\t\t\t \u0026bcm590xx_regmap_config_pri);\n--\ndrivers/mfd/bcm590xx.c-121-\ndrivers/mfd/bcm590xx.c:122:\tbcm590xx-\u003eregmap_sec = devm_regmap_init_i2c(bcm590xx-\u003ei2c_sec,\ndrivers/mfd/bcm590xx.c-123-\t\t\t\t\t\t\u0026bcm590xx_regmap_config_sec);\n--\ndrivers/mfd/bd9571mwv.c=207=static int bd9571mwv_probe(struct i2c_client *client)\n--\ndrivers/mfd/bd9571mwv.c-241-\ndrivers/mfd/bd9571mwv.c:242:\tregmap = devm_regmap_init_i2c(client, regmap_config);\ndrivers/mfd/bd9571mwv.c-243-\tif (IS_ERR(regmap)) {\n--\ndrivers/mfd/bq257xx.c=80=static int bq257xx_probe(struct i2c_client *client)\n--\ndrivers/mfd/bq257xx.c-103-\ndrivers/mfd/bq257xx.c:104:\tddata-\u003eregmap = devm_regmap_init_i2c(client, rcfg);\ndrivers/mfd/bq257xx.c-105-\tif (IS_ERR(ddata-\u003eregmap)) {\n--\ndrivers/mfd/cs40l50-i2c.c=14=static int cs40l50_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/cs40l50-i2c.c-26-\ndrivers/mfd/cs40l50-i2c.c:27:\tcs40l50-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026cs40l50_regmap);\ndrivers/mfd/cs40l50-i2c.c-28-\tif (IS_ERR(cs40l50-\u003eregmap))\n--\ndrivers/mfd/cs40l50-spi.c=14=static int cs40l50_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/cs40l50-spi.c-26-\ndrivers/mfd/cs40l50-spi.c:27:\tcs40l50-\u003eregmap = devm_regmap_init_spi(spi, \u0026cs40l50_regmap);\ndrivers/mfd/cs40l50-spi.c-28-\tif (IS_ERR(cs40l50-\u003eregmap))\n--\ndrivers/mfd/cs42l43-i2c.c=37=static int cs42l43_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/cs42l43-i2c.c-50-\ndrivers/mfd/cs42l43-i2c.c:51:\tcs42l43-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026cs42l43_i2c_regmap);\ndrivers/mfd/cs42l43-i2c.c-52-\tif (IS_ERR(cs42l43-\u003eregmap))\n--\ndrivers/mfd/cs42l43-sdw.c=169=static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id)\n--\ndrivers/mfd/cs42l43-sdw.c-181-\ndrivers/mfd/cs42l43-sdw.c:182:\tcs42l43-\u003eregmap = devm_regmap_init_sdw(sdw, \u0026cs42l43_sdw_regmap);\ndrivers/mfd/cs42l43-sdw.c-183-\tif (IS_ERR(cs42l43-\u003eregmap))\n--\ndrivers/mfd/da9052-i2c.c=126=static int da9052_i2c_probe(struct i2c_client *client)\n--\ndrivers/mfd/da9052-i2c.c-141-\ndrivers/mfd/da9052-i2c.c:142:\tda9052-\u003eregmap = devm_regmap_init_i2c(client, \u0026da9052_regmap_config);\ndrivers/mfd/da9052-i2c.c-143-\tif (IS_ERR(da9052-\u003eregmap)) {\n--\ndrivers/mfd/da9052-spi.c=19=static int da9052_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/da9052-spi.c-46-\ndrivers/mfd/da9052-spi.c:47:\tda9052-\u003eregmap = devm_regmap_init_spi(spi, \u0026config);\ndrivers/mfd/da9052-spi.c-48-\tif (IS_ERR(da9052-\u003eregmap)) {\n--\ndrivers/mfd/da9055-i2c.c=17=static int da9055_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/da9055-i2c.c-25-\ndrivers/mfd/da9055-i2c.c:26:\tda9055-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026da9055_regmap_config);\ndrivers/mfd/da9055-i2c.c-27-\tif (IS_ERR(da9055-\u003eregmap)) {\n--\ndrivers/mfd/da9062-core.c=591=static int da9062_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/da9062-core.c-627-\ndrivers/mfd/da9062-core.c:628:\tchip-\u003eregmap = devm_regmap_init_i2c(i2c, config);\ndrivers/mfd/da9062-core.c-629-\tif (IS_ERR(chip-\u003eregmap)) {\n--\ndrivers/mfd/da9063-i2c.c=369=static int da9063_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/da9063-i2c.c-453-\ndrivers/mfd/da9063-i2c.c:454:\tda9063-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026da9063_regmap_config);\ndrivers/mfd/da9063-i2c.c-455-\tif (IS_ERR(da9063-\u003eregmap)) {\n--\ndrivers/mfd/da9150-core.c=395=static int da9150_probe(struct i2c_client *client)\n--\ndrivers/mfd/da9150-core.c-409-\ndrivers/mfd/da9150-core.c:410:\tda9150-\u003eregmap = devm_regmap_init_i2c(client, \u0026da9150_regmap_config);\ndrivers/mfd/da9150-core.c-411-\tif (IS_ERR(da9150-\u003eregmap)) {\n--\ndrivers/mfd/ene-kb3930.c=122=static int kb3930_probe(struct i2c_client *client)\n--\ndrivers/mfd/ene-kb3930.c-137-\ndrivers/mfd/ene-kb3930.c:138:\tddata-\u003eram_regmap = devm_regmap_init(dev, NULL, ddata,\ndrivers/mfd/ene-kb3930.c-139-\t\t\t\t\t \u0026kb3930_ram_regmap_config);\n--\ndrivers/mfd/exynos-lpass.c=116=static int exynos_lpass_probe(struct platform_device *pdev)\n--\ndrivers/mfd/exynos-lpass.c-134-\ndrivers/mfd/exynos-lpass.c:135:\tlpass-\u003etop = devm_regmap_init_mmio(dev, base_top,\ndrivers/mfd/exynos-lpass.c-136-\t\t\t\t\t \u0026exynos_lpass_reg_conf);\n--\ndrivers/mfd/fsl-imx25-tsadc.c=134=static int mx25_tsadc_probe(struct platform_device *pdev)\n--\ndrivers/mfd/fsl-imx25-tsadc.c-148-\ndrivers/mfd/fsl-imx25-tsadc.c:149:\ttsadc-\u003eregs = devm_regmap_init_mmio(dev, iomem,\ndrivers/mfd/fsl-imx25-tsadc.c-150-\t\t\t\t\t \u0026mx25_tsadc_regmap_config);\n--\ndrivers/mfd/gateworks-gsc.c=197=static int gsc_probe(struct i2c_client *client)\n--\ndrivers/mfd/gateworks-gsc.c-212-\ndrivers/mfd/gateworks-gsc.c:213:\tgsc-\u003eregmap = devm_regmap_init(dev, \u0026gsc_regmap_bus, client,\ndrivers/mfd/gateworks-gsc.c-214-\t\t\t\t \u0026gsc_regmap_config);\n--\ndrivers/mfd/hi6421-pmic-core.c=51=static int hi6421_pmic_probe(struct platform_device *pdev)\n--\ndrivers/mfd/hi6421-pmic-core.c-68-\ndrivers/mfd/hi6421-pmic-core.c:69:\tpmic-\u003eregmap = devm_regmap_init_mmio_clk(\u0026pdev-\u003edev, NULL, base,\ndrivers/mfd/hi6421-pmic-core.c-70-\t\t\t\t\t\t \u0026hi6421_regmap_config);\n--\ndrivers/mfd/hi6421-spmi-pmic.c=29=static int hi6421_spmi_pmic_probe(struct spmi_device *sdev)\n--\ndrivers/mfd/hi6421-spmi-pmic.c-34-\ndrivers/mfd/hi6421-spmi-pmic.c:35:\tregmap = devm_regmap_init_spmi_ext(sdev, \u0026regmap_config);\ndrivers/mfd/hi6421-spmi-pmic.c-36-\tif (IS_ERR(regmap))\n--\ndrivers/mfd/hi655x-pmic.c=90=static int hi655x_pmic_probe(struct platform_device *pdev)\n--\ndrivers/mfd/hi655x-pmic.c-105-\ndrivers/mfd/hi655x-pmic.c:106:\tpmic-\u003eregmap = devm_regmap_init_mmio_clk(dev, NULL, base,\ndrivers/mfd/hi655x-pmic.c-107-\t\t\t\t\t\t \u0026hi655x_regmap_config);\n--\ndrivers/mfd/intel-m10-bmc-pmci.c=382=static int m10bmc_pmci_probe(struct dfl_device *ddev)\n--\ndrivers/mfd/intel-m10-bmc-pmci.c-408-\tindirect_clear_cmd(ctx);\ndrivers/mfd/intel-m10-bmc-pmci.c:409:\tpmci-\u003em10bmc.regmap = devm_regmap_init(dev, NULL, ctx, \u0026m10bmc_pmci_regmap_config);\ndrivers/mfd/intel-m10-bmc-pmci.c-410-\n--\ndrivers/mfd/intel-m10-bmc-spi.c=61=static int intel_m10_bmc_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/intel-m10-bmc-spi.c-75-\ndrivers/mfd/intel-m10-bmc-spi.c:76:\tddata-\u003eregmap = devm_regmap_init_spi_avmm(spi, \u0026intel_m10bmc_regmap_config);\ndrivers/mfd/intel-m10-bmc-spi.c-77-\tif (IS_ERR(ddata-\u003eregmap)) {\n--\ndrivers/mfd/intel_soc_pmic_bxtwc.c=471=static int bxtwc_probe(struct platform_device *pdev)\n--\ndrivers/mfd/intel_soc_pmic_bxtwc.c-500-\ndrivers/mfd/intel_soc_pmic_bxtwc.c:501:\tpmic-\u003eregmap = devm_regmap_init(dev, NULL, pmic, \u0026bxtwc_regmap_config);\ndrivers/mfd/intel_soc_pmic_bxtwc.c-502-\tif (IS_ERR(pmic-\u003eregmap))\n--\ndrivers/mfd/intel_soc_pmic_chtdc_ti.c=108=static int chtdc_ti_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/intel_soc_pmic_chtdc_ti.c-119-\ndrivers/mfd/intel_soc_pmic_chtdc_ti.c:120:\tpmic-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026chtdc_ti_regmap_config);\ndrivers/mfd/intel_soc_pmic_chtdc_ti.c-121-\tif (IS_ERR(pmic-\u003eregmap))\n--\ndrivers/mfd/intel_soc_pmic_chtwc.c=187=static int cht_wc_probe(struct i2c_client *client)\n--\ndrivers/mfd/intel_soc_pmic_chtwc.c-216-\ndrivers/mfd/intel_soc_pmic_chtwc.c:217:\tpmic-\u003eregmap = devm_regmap_init(dev, NULL, client, \u0026cht_wc_regmap_cfg);\ndrivers/mfd/intel_soc_pmic_chtwc.c-218-\tif (IS_ERR(pmic-\u003eregmap))\n--\ndrivers/mfd/intel_soc_pmic_crc.c=167=static int crystal_cove_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/intel_soc_pmic_crc.c-184-\ndrivers/mfd/intel_soc_pmic_crc.c:185:\tpmic-\u003eregmap = devm_regmap_init_i2c(i2c, config-\u003eregmap_config);\ndrivers/mfd/intel_soc_pmic_crc.c-186-\tif (IS_ERR(pmic-\u003eregmap))\n--\ndrivers/mfd/intel_soc_pmic_mrfld.c=105=static int bcove_probe(struct platform_device *pdev)\n--\ndrivers/mfd/intel_soc_pmic_mrfld.c-122-\ndrivers/mfd/intel_soc_pmic_mrfld.c:123:\tpmic-\u003eregmap = devm_regmap_init(dev, NULL, pmic, \u0026bcove_regmap_config);\ndrivers/mfd/intel_soc_pmic_mrfld.c-124-\tif (IS_ERR(pmic-\u003eregmap))\n--\ndrivers/mfd/iqs62x.c=895=static int iqs62x_probe(struct i2c_client *client)\n--\ndrivers/mfd/iqs62x.c-915-\ndrivers/mfd/iqs62x.c:916:\tiqs62x-\u003eregmap = devm_regmap_init_i2c(client, \u0026iqs62x_regmap_config);\ndrivers/mfd/iqs62x.c-917-\tif (IS_ERR(iqs62x-\u003eregmap)) {\n--\ndrivers/mfd/khadas-mcu.c=87=static int khadas_mcu_probe(struct i2c_client *client)\n--\ndrivers/mfd/khadas-mcu.c-100-\ndrivers/mfd/khadas-mcu.c:101:\tddata-\u003eregmap = devm_regmap_init_i2c(client, \u0026khadas_mcu_regmap_config);\ndrivers/mfd/khadas-mcu.c-102-\tif (IS_ERR(ddata-\u003eregmap)) {\n--\ndrivers/mfd/lm3533-core.c=575=static int lm3533_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/lm3533-core.c-586-\ndrivers/mfd/lm3533-core.c:587:\tlm3533-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026regmap_config);\ndrivers/mfd/lm3533-core.c-588-\tif (IS_ERR(lm3533-\u003eregmap))\n--\ndrivers/mfd/lochnagar-i2c.c=268=static int lochnagar_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/lochnagar-i2c.c-312-\ndrivers/mfd/lochnagar-i2c.c:313:\tlochnagar-\u003eregmap = devm_regmap_init_i2c(i2c, config-\u003eregmap);\ndrivers/mfd/lochnagar-i2c.c-314-\tif (IS_ERR(lochnagar-\u003eregmap)) {\n--\ndrivers/mfd/lp3943.c=105=static int lp3943_probe(struct i2c_client *cl)\n--\ndrivers/mfd/lp3943.c-113-\ndrivers/mfd/lp3943.c:114:\tlp3943-\u003eregmap = devm_regmap_init_i2c(cl, \u0026lp3943_regmap_config);\ndrivers/mfd/lp3943.c-115-\tif (IS_ERR(lp3943-\u003eregmap))\n--\ndrivers/mfd/lp873x.c=26=static int lp873x_probe(struct i2c_client *client)\n--\ndrivers/mfd/lp873x.c-37-\ndrivers/mfd/lp873x.c:38:\tlp873-\u003eregmap = devm_regmap_init_i2c(client, \u0026lp873x_regmap_config);\ndrivers/mfd/lp873x.c-39-\tif (IS_ERR(lp873-\u003eregmap)) {\n--\ndrivers/mfd/lp87565.c=46=static int lp87565_probe(struct i2c_client *client)\n--\ndrivers/mfd/lp87565.c-57-\ndrivers/mfd/lp87565.c:58:\tlp87565-\u003eregmap = devm_regmap_init_i2c(client, \u0026lp87565_regmap_config);\ndrivers/mfd/lp87565.c-59-\tif (IS_ERR(lp87565-\u003eregmap)) {\n--\ndrivers/mfd/lp8788.c=169=static int lp8788_probe(struct i2c_client *cl)\n--\ndrivers/mfd/lp8788.c-178-\ndrivers/mfd/lp8788.c:179:\tlp-\u003eregmap = devm_regmap_init_i2c(cl, \u0026lp8788_regmap_config);\ndrivers/mfd/lp8788.c-180-\tif (IS_ERR(lp-\u003eregmap)) {\n--\ndrivers/mfd/madera-i2c.c=19=static int madera_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/madera-i2c.c-82-\ndrivers/mfd/madera-i2c.c:83:\tmadera-\u003eregmap = devm_regmap_init_i2c(i2c, regmap_16bit_config);\ndrivers/mfd/madera-i2c.c-84-\tif (IS_ERR(madera-\u003eregmap)) {\n--\ndrivers/mfd/madera-i2c.c-90-\ndrivers/mfd/madera-i2c.c:91:\tmadera-\u003eregmap_32bit = devm_regmap_init_i2c(i2c, regmap_32bit_config);\ndrivers/mfd/madera-i2c.c-92-\tif (IS_ERR(madera-\u003eregmap_32bit)) {\n--\ndrivers/mfd/madera-spi.c=19=static int madera_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/madera-spi.c-82-\ndrivers/mfd/madera-spi.c:83:\tmadera-\u003eregmap = devm_regmap_init_spi(spi, regmap_16bit_config);\ndrivers/mfd/madera-spi.c-84-\tif (IS_ERR(madera-\u003eregmap)) {\n--\ndrivers/mfd/madera-spi.c-90-\ndrivers/mfd/madera-spi.c:91:\tmadera-\u003eregmap_32bit = devm_regmap_init_spi(spi, regmap_32bit_config);\ndrivers/mfd/madera-spi.c-92-\tif (IS_ERR(madera-\u003eregmap_32bit)) {\n--\ndrivers/mfd/max14577.c=293=static int max77836_init(struct max14577 *max14577)\n--\ndrivers/mfd/max14577.c-305-\ndrivers/mfd/max14577.c:306:\tmax14577-\u003eregmap_pmic = devm_regmap_init_i2c(max14577-\u003ei2c_pmic,\ndrivers/mfd/max14577.c-307-\t\t\t\u0026max77836_pmic_regmap_config);\n--\ndrivers/mfd/max14577.c=359=static int max14577_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max14577.c-390-\ndrivers/mfd/max14577.c:391:\tmax14577-\u003eregmap = devm_regmap_init_i2c(i2c,\ndrivers/mfd/max14577.c-392-\t\t\t\u0026max14577_muic_regmap_config);\n--\ndrivers/mfd/max7360.c=119=static int max7360_probe(struct i2c_client *client)\n--\ndrivers/mfd/max7360.c-124-\ndrivers/mfd/max7360.c:125:\tregmap = devm_regmap_init_i2c(client, \u0026max7360_regmap_config);\ndrivers/mfd/max7360.c-126-\tif (IS_ERR(regmap))\n--\ndrivers/mfd/max77541.c=163=static int max77541_probe(struct i2c_client *client)\n--\ndrivers/mfd/max77541.c-178-\ndrivers/mfd/max77541.c:179:\tmax77541-\u003eregmap = devm_regmap_init_i2c(client,\ndrivers/mfd/max77541.c-180-\t\t\t\t\t\t\u0026max77541_regmap_config);\n--\ndrivers/mfd/max77620.c=497=static int max77620_probe(struct i2c_client *client)\n--\ndrivers/mfd/max77620.c-544-\ndrivers/mfd/max77620.c:545:\tchip-\u003ermap = devm_regmap_init_i2c(client, rmap_config);\ndrivers/mfd/max77620.c-546-\tif (IS_ERR(chip-\u003ermap)) {\n--\ndrivers/mfd/max77650.c=151=static int max77650_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max77650.c-159-\ndrivers/mfd/max77650.c:160:\tmap = devm_regmap_init_i2c(i2c, \u0026max77650_regmap_config);\ndrivers/mfd/max77650.c-161-\tif (IS_ERR(map)) {\n--\ndrivers/mfd/max77686.c=160=static int max77686_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max77686.c-193-\ndrivers/mfd/max77686.c:194:\tmax77686-\u003eregmap = devm_regmap_init_i2c(i2c, config);\ndrivers/mfd/max77686.c-195-\tif (IS_ERR(max77686-\u003eregmap)) {\n--\ndrivers/mfd/max77693.c=148=static int max77693_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max77693.c-165-\ndrivers/mfd/max77693.c:166:\tmax77693-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026max77693_regmap_config);\ndrivers/mfd/max77693.c-167-\tif (IS_ERR(max77693-\u003eregmap)) {\n--\ndrivers/mfd/max77693.c-196-\ndrivers/mfd/max77693.c:197:\tmax77693-\u003eregmap_haptic = devm_regmap_init_i2c(max77693-\u003ei2c_haptic,\ndrivers/mfd/max77693.c-198-\t\t\t\t\t\u0026max77693_regmap_haptic_config);\n--\ndrivers/mfd/max77693.c-210-\t */\ndrivers/mfd/max77693.c:211:\tmax77693-\u003eregmap_muic = devm_regmap_init_i2c(max77693-\u003ei2c_muic,\ndrivers/mfd/max77693.c-212-\t\t\t\t\t \u0026max77693_regmap_muic_config);\n--\ndrivers/mfd/max77705.c=81=static int max77705_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max77705.c-98-\ndrivers/mfd/max77705.c:99:\tmax77705-\u003eregmap = devm_regmap_init_i2c(i2c, \u0026max77705_regmap_config);\ndrivers/mfd/max77705.c-100-\tif (IS_ERR(max77705-\u003eregmap))\n--\ndrivers/mfd/max77714.c=104=static int max77714_probe(struct i2c_client *client)\n--\ndrivers/mfd/max77714.c-110-\ndrivers/mfd/max77714.c:111:\tregmap = devm_regmap_init_i2c(client, \u0026max77714_regmap_config);\ndrivers/mfd/max77714.c-112-\tif (IS_ERR(regmap))\n--\ndrivers/mfd/max77759.c=488=static int max77759_create_i2c_subdev(struct i2c_client *client,\n--\ndrivers/mfd/max77759.c-511-\ndrivers/mfd/max77759.c:512:\tregmap = devm_regmap_init_i2c(sub, sd-\u003ecfg);\ndrivers/mfd/max77759.c-513-\tif (IS_ERR(regmap))\n--\ndrivers/mfd/max77759.c=645=static int max77759_probe(struct i2c_client *client)\n--\ndrivers/mfd/max77759.c-657-\ndrivers/mfd/max77759.c:658:\tmax77759-\u003eregmap_top = devm_regmap_init_i2c(client,\ndrivers/mfd/max77759.c-659-\t\t\t\t\t\t \u0026max77759_regmap_config_top);\n--\ndrivers/mfd/max77843.c=67=static int max77843_chg_init(struct max77693_dev *max77843)\n--\ndrivers/mfd/max77843.c-78-\ndrivers/mfd/max77843.c:79:\tmax77843-\u003eregmap_chg = devm_regmap_init_i2c(max77843-\u003ei2c_chg,\ndrivers/mfd/max77843.c-80-\t\t\t\u0026max77843_charger_regmap_config);\n--\ndrivers/mfd/max77843.c=94=static int max77843_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max77843.c-110-\ndrivers/mfd/max77843.c:111:\tmax77843-\u003eregmap = devm_regmap_init_i2c(i2c,\ndrivers/mfd/max77843.c-112-\t\t\t\u0026max77843_regmap_config);\n--\ndrivers/mfd/max8907.c=183=static int max8907_i2c_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/max8907.c-204-\ti2c_set_clientdata(i2c, max8907);\ndrivers/mfd/max8907.c:205:\tmax8907-\u003eregmap_gen = devm_regmap_init_i2c(i2c,\ndrivers/mfd/max8907.c-206-\t\t\t\t\t\t\u0026max8907_regmap_gen_config);\n--\ndrivers/mfd/max8907.c-218-\ti2c_set_clientdata(max8907-\u003ei2c_rtc, max8907);\ndrivers/mfd/max8907.c:219:\tmax8907-\u003eregmap_rtc = devm_regmap_init_i2c(max8907-\u003ei2c_rtc,\ndrivers/mfd/max8907.c-220-\t\t\t\t\t\t\u0026max8907_regmap_rtc_config);\n--\ndrivers/mfd/mc13xxx-i2c.c=54=static int mc13xxx_i2c_probe(struct i2c_client *client)\n--\ndrivers/mfd/mc13xxx-i2c.c-66-\ndrivers/mfd/mc13xxx-i2c.c:67:\tmc13xxx-\u003eregmap = devm_regmap_init_i2c(client,\ndrivers/mfd/mc13xxx-i2c.c-68-\t\t\t\t\t \u0026mc13xxx_regmap_i2c_config);\n--\ndrivers/mfd/mc13xxx-spi.c=123=static int mc13xxx_spi_probe(struct spi_device *spi)\n--\ndrivers/mfd/mc13xxx-spi.c-142-\ndrivers/mfd/mc13xxx-spi.c:143:\tmc13xxx-\u003eregmap = devm_regmap_init(\u0026spi-\u003edev, \u0026regmap_mc13xxx_bus,\ndrivers/mfd/mc13xxx-spi.c-144-\t\t\t\t\t \u0026spi-\u003edev,\n--\ndrivers/mfd/motorola-cpcap.c=290=static int cpcap_probe(struct spi_device *spi)\n--\ndrivers/mfd/motorola-cpcap.c-309-\tcpcap-\u003eregmap_conf = \u0026cpcap_regmap_config;\ndrivers/mfd/motorola-cpcap.c:310:\tcpcap-\u003eregmap = devm_regmap_init_spi(spi, \u0026cpcap_regmap_config);\ndrivers/mfd/motorola-cpcap.c-311-\tif (IS_ERR(cpcap-\u003eregmap)) {\n--\ndrivers/mfd/mp2629.c=36=static int mp2629_probe(struct i2c_client *client)\n--\ndrivers/mfd/mp2629.c-47-\ndrivers/mfd/mp2629.c:48:\tddata-\u003eregmap = devm_regmap_init_i2c(client, \u0026mp2629_regmap_config);\ndrivers/mfd/mp2629.c-49-\tif (IS_ERR(ddata-\u003eregmap)) {\n--\ndrivers/mfd/mt6360-core.c=529=static int mt6360_probe(struct i2c_client *client)\n--\ndrivers/mfd/mt6360-core.c-554-\tcrc8_populate_msb(ddata-\u003ecrc8_tbl, MT6360_CRC8_POLYNOMIAL);\ndrivers/mfd/mt6360-core.c:555:\tddata-\u003eregmap = devm_regmap_init(ddata-\u003edev, \u0026mt6360_regmap_bus, ddata,\ndrivers/mfd/mt6360-core.c-556-\t\t\t\t\t \u0026mt6360_regmap_config);\n--\ndrivers/mfd/mt6370.c=230=static int mt6370_probe(struct i2c_client *i2c)\n--\ndrivers/mfd/mt6370.c-251-\ndrivers/mfd/mt6370.c:252:\tregmap = devm_regmap_init(dev, \u0026mt6370_regmap_bus,\ndrivers/mfd/mt6370.c-253-\t\t\t\t info, \u0026mt6370_regmap_config);\n--\ndrivers/mfd/ntxec.c=148=static int ntxec_probe(struct i2c_client *client)\n--\ndrivers/mfd/ntxec.c-161-\ndrivers/mfd/ntxec.c:162:\tec-\u003eregmap = devm_regmap_init_i2c(client, \u0026regmap_config);\ndrivers/mfd/ntxec.c-163-\tif (IS_ERR(ec-\u003eregmap)) {\n--\ndrivers/mfd/ntxec.c-185-\t\t/* Another regmap stacked on top of the other */\ndrivers/mfd/ntxec.c:186:\t\tec-\u003eregmap = devm_regmap_init(ec-\u003edev, NULL,\ndrivers/mfd/ntxec.c-187-\t\t\t\t\t ec-\u003eregmap,\n--\ndrivers/mfd/ocelot-spi.c=183=struct regmap *ocelot_spi_init_regmap(struct device *dev, const struct resource *res)\n--\n\n"
} |
| 33/2 | 2026/07/13 19:31 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 179777 output: 30 thoughts: 51 Thoughts: Here's my summary, as the thought process unfolds: **Digging into the Ocelot Driver Structure** Hold on a second! I need to take a closer look at these Ocelot drivers – specifically `drivers/mfd/ocelot-spi.c` and `drivers/mfd/ocelot-core.c`. My gut tells me there's something interesting within these. Let's start with `drivers/mfd/ocelot-core.c`. It's likely the core logic and resource management are centered there. |
| 34/2 | 2026/07/13 19:31 | tool | grepper |
0mError:no matches Args: {
"Expression": "lan9645",
"PathPrefix": "drivers/mfd/"
}Results: {
"error": "no matches"
} |
| 35/2 | 2026/07/13 19:31 | llm | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 179992 output: 30 thoughts: 46 Thoughts: **Investigating the LAN9645 and LAN966x Devices** Okay, so I started looking for the LAN9645 driver within the `drivers/mfd/` directory, expecting it to be there, but I got no results. That's a bit strange. Now, to troubleshoot, I'm going to broaden the scope slightly. My next step is to search for "lan966x" within the same directory. Let's see if that yields anything more fruitful. Perhaps there's a related driver or a shared component that's grouped under a slightly different naming convention. I'm keeping an open mind and using the "lan966x" search as a diagnostic tool. |
| 36/2 | 2026/07/13 19:33 | tool | grepper |
0mError:no matches Args: {
"Expression": "lan966x",
"PathPrefix": "drivers/mfd/"
}Results: {
"error": "no matches"
} |
| 37/2 | 2026/07/13 19:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 180235 output: 27 thoughts: 36 Thoughts: Okay, here's my interpretation of that thought process, assuming I'm an expert in embedded systems drivers: **Analyzing LAN966x Driver Dependencies** Alright, I need to get a clear picture of how the LAN966x is being used across this codebase. I want to specifically look for instances of "lan966x" within the `drivers/` directory. But, I need to be precise. I'm *not* interested in looking within the driver's *own* directory: `drivers/net/ethernet/microchip/lan966x/`. That's where the source code for the driver itself resides, so searching there would just yield the code itself and not tell me how other parts of the system interact with the driver. I need to know the *other* places where "lan966x" appears, such as in build scripts, other driver code, or device tree definitions. This targeted search will show me the points where it is referenced and used in this embedded environment. I'm expecting this will help me understand how the driver is being integrated and which components depend on it. |
| 38/2 | 2026/07/13 19:33 | tool | grepper |
0mArgs:{
"Expression": "lan966x",
"PathPrefix": "drivers/"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 8482 lines.\nUse more precise expression if possible.\n\ndrivers/clk/Makefile=69=obj-$(CONFIG_LMK04832)\t\t\t+= clk-lmk04832.o\ndrivers/clk/Makefile:70:obj-$(CONFIG_COMMON_CLK_LAN966X)\t+= clk-lan966x.o\ndrivers/clk/Makefile-71-obj-$(CONFIG_COMMON_CLK_LOCHNAGAR)\t+= clk-lochnagar.o\n--\ndrivers/clk/clk-lan966x.c-24-\ndrivers/clk/clk-lan966x.c:25:static const char * const lan966x_clk_names[] = {\ndrivers/clk/clk-lan966x.c-26-\t\"qspi0\", \"qspi1\", \"qspi2\", \"sdmmc0\",\n--\ndrivers/clk/clk-lan966x.c=32=static const char * const lan969x_clk_names[] = {\n--\ndrivers/clk/clk-lan966x.c-38-\ndrivers/clk/clk-lan966x.c:39:struct lan966x_gck {\ndrivers/clk/clk-lan966x.c-40-\tstruct clk_hw hw;\n--\ndrivers/clk/clk-lan966x.c-42-};\ndrivers/clk/clk-lan966x.c:43:#define to_lan966x_gck(hw) container_of(hw, struct lan966x_gck, hw)\ndrivers/clk/clk-lan966x.c-44-\ndrivers/clk/clk-lan966x.c:45:static const struct clk_parent_data lan966x_gck_pdata[] = {\ndrivers/clk/clk-lan966x.c-46-\t{ .fw_name = \"cpu\", },\n--\ndrivers/clk/clk-lan966x.c=51=static struct clk_init_data init = {\ndrivers/clk/clk-lan966x.c:52:\t.parent_data = lan966x_gck_pdata,\ndrivers/clk/clk-lan966x.c:53:\t.num_parents = ARRAY_SIZE(lan966x_gck_pdata),\ndrivers/clk/clk-lan966x.c-54-};\n--\ndrivers/clk/clk-lan966x.c=56=struct clk_gate_soc_desc {\n--\ndrivers/clk/clk-lan966x.c-60-\ndrivers/clk/clk-lan966x.c:61:static const struct clk_gate_soc_desc lan966x_clk_gate_desc[] = {\ndrivers/clk/clk-lan966x.c-62-\t{ \"uhphs\", 11 },\n--\ndrivers/clk/clk-lan966x.c=69=static const struct clk_gate_soc_desc lan969x_clk_gate_desc[] = {\n--\ndrivers/clk/clk-lan966x.c-75-\ndrivers/clk/clk-lan966x.c:76:struct lan966x_match_data {\ndrivers/clk/clk-lan966x.c-77-\tchar *name;\n--\ndrivers/clk/clk-lan966x.c-83-\ndrivers/clk/clk-lan966x.c:84:static struct lan966x_match_data lan966x_desc = {\ndrivers/clk/clk-lan966x.c:85:\t.name = \"lan966x\",\ndrivers/clk/clk-lan966x.c:86:\t.clk_name = lan966x_clk_names,\ndrivers/clk/clk-lan966x.c:87:\t.clk_gate_desc = lan966x_clk_gate_desc,\ndrivers/clk/clk-lan966x.c-88-\t.num_total_clks = 18,\n--\ndrivers/clk/clk-lan966x.c-91-\ndrivers/clk/clk-lan966x.c:92:static struct lan966x_match_data lan969x_desc = {\ndrivers/clk/clk-lan966x.c-93-\t.name = \"lan969x\",\n--\ndrivers/clk/clk-lan966x.c=101=static void __iomem *base;\ndrivers/clk/clk-lan966x.c-102-\ndrivers/clk/clk-lan966x.c:103:static int lan966x_gck_enable(struct clk_hw *hw)\ndrivers/clk/clk-lan966x.c-104-{\ndrivers/clk/clk-lan966x.c:105:\tstruct lan966x_gck *gck = to_lan966x_gck(hw);\ndrivers/clk/clk-lan966x.c-106-\tu32 val = readl(gck-\u003ereg);\n--\ndrivers/clk/clk-lan966x.c-113-\ndrivers/clk/clk-lan966x.c:114:static void lan966x_gck_disable(struct clk_hw *hw)\ndrivers/clk/clk-lan966x.c-115-{\ndrivers/clk/clk-lan966x.c:116:\tstruct lan966x_gck *gck = to_lan966x_gck(hw);\ndrivers/clk/clk-lan966x.c-117-\tu32 val = readl(gck-\u003ereg);\n--\ndrivers/clk/clk-lan966x.c-122-\ndrivers/clk/clk-lan966x.c:123:static int lan966x_gck_set_rate(struct clk_hw *hw,\ndrivers/clk/clk-lan966x.c-124-\t\t\t\tunsigned long rate,\n--\ndrivers/clk/clk-lan966x.c-126-{\ndrivers/clk/clk-lan966x.c:127:\tstruct lan966x_gck *gck = to_lan966x_gck(hw);\ndrivers/clk/clk-lan966x.c-128-\tu32 div, val = readl(gck-\u003ereg);\n--\ndrivers/clk/clk-lan966x.c-141-\ndrivers/clk/clk-lan966x.c:142:static unsigned long lan966x_gck_recalc_rate(struct clk_hw *hw,\ndrivers/clk/clk-lan966x.c-143-\t\t\t\t\t unsigned long parent_rate)\ndrivers/clk/clk-lan966x.c-144-{\ndrivers/clk/clk-lan966x.c:145:\tstruct lan966x_gck *gck = to_lan966x_gck(hw);\ndrivers/clk/clk-lan966x.c-146-\tu32 div, val = readl(gck-\u003ereg);\n--\ndrivers/clk/clk-lan966x.c-152-\ndrivers/clk/clk-lan966x.c:153:static int lan966x_gck_determine_rate(struct clk_hw *hw,\ndrivers/clk/clk-lan966x.c-154-\t\t\t\t struct clk_rate_request *req)\n--\ndrivers/clk/clk-lan966x.c-175-\ndrivers/clk/clk-lan966x.c:176:static u8 lan966x_gck_get_parent(struct clk_hw *hw)\ndrivers/clk/clk-lan966x.c-177-{\ndrivers/clk/clk-lan966x.c:178:\tstruct lan966x_gck *gck = to_lan966x_gck(hw);\ndrivers/clk/clk-lan966x.c-179-\tu32 val = readl(gck-\u003ereg);\n--\ndrivers/clk/clk-lan966x.c-183-\ndrivers/clk/clk-lan966x.c:184:static int lan966x_gck_set_parent(struct clk_hw *hw, u8 index)\ndrivers/clk/clk-lan966x.c-185-{\ndrivers/clk/clk-lan966x.c:186:\tstruct lan966x_gck *gck = to_lan966x_gck(hw);\ndrivers/clk/clk-lan966x.c-187-\tu32 val = readl(gck-\u003ereg);\n--\ndrivers/clk/clk-lan966x.c-195-\ndrivers/clk/clk-lan966x.c:196:static const struct clk_ops lan966x_gck_ops = {\ndrivers/clk/clk-lan966x.c:197:\t.enable = lan966x_gck_enable,\ndrivers/clk/clk-lan966x.c:198:\t.disable = lan966x_gck_disable,\ndrivers/clk/clk-lan966x.c:199:\t.set_rate = lan966x_gck_set_rate,\ndrivers/clk/clk-lan966x.c:200:\t.recalc_rate = lan966x_gck_recalc_rate,\ndrivers/clk/clk-lan966x.c:201:\t.determine_rate = lan966x_gck_determine_rate,\ndrivers/clk/clk-lan966x.c:202:\t.set_parent = lan966x_gck_set_parent,\ndrivers/clk/clk-lan966x.c:203:\t.get_parent = lan966x_gck_get_parent,\ndrivers/clk/clk-lan966x.c-204-};\ndrivers/clk/clk-lan966x.c-205-\ndrivers/clk/clk-lan966x.c:206:static struct clk_hw *lan966x_gck_clk_register(struct device *dev, int i)\ndrivers/clk/clk-lan966x.c-207-{\ndrivers/clk/clk-lan966x.c:208:\tstruct lan966x_gck *priv;\ndrivers/clk/clk-lan966x.c-209-\tint ret;\n--\ndrivers/clk/clk-lan966x.c-223-\ndrivers/clk/clk-lan966x.c:224:static int lan966x_gate_clk_register(struct device *dev,\ndrivers/clk/clk-lan966x.c:225:\t\t\t\t const struct lan966x_match_data *data,\ndrivers/clk/clk-lan966x.c-226-\t\t\t\t struct clk_hw_onecell_data *hw_data,\n--\ndrivers/clk/clk-lan966x.c-249-\ndrivers/clk/clk-lan966x.c:250:static int lan966x_clk_probe(struct platform_device *pdev)\ndrivers/clk/clk-lan966x.c-251-{\ndrivers/clk/clk-lan966x.c:252:\tconst struct lan966x_match_data *data;\ndrivers/clk/clk-lan966x.c-253-\tstruct clk_hw_onecell_data *hw_data;\n--\ndrivers/clk/clk-lan966x.c-271-\ndrivers/clk/clk-lan966x.c:272:\tinit.ops = \u0026lan966x_gck_ops;\ndrivers/clk/clk-lan966x.c-273-\n--\ndrivers/clk/clk-lan966x.c-277-\t\tinit.name = data-\u003eclk_name[i];\ndrivers/clk/clk-lan966x.c:278:\t\thw_data-\u003ehws[i] = lan966x_gck_clk_register(dev, i);\ndrivers/clk/clk-lan966x.c-279-\t\tif (IS_ERR(hw_data-\u003ehws[i])) {\n--\ndrivers/clk/clk-lan966x.c-293-\ndrivers/clk/clk-lan966x.c:294:\t\tret = lan966x_gate_clk_register(dev, data, hw_data, gate_base);\ndrivers/clk/clk-lan966x.c-295-\t\tif (ret)\n--\ndrivers/clk/clk-lan966x.c-301-\ndrivers/clk/clk-lan966x.c:302:static const struct of_device_id lan966x_clk_dt_ids[] = {\ndrivers/clk/clk-lan966x.c:303:\t{ .compatible = \"microchip,lan966x-gck\", .data = \u0026lan966x_desc },\ndrivers/clk/clk-lan966x.c-304-\t{ .compatible = \"microchip,lan9691-gck\", .data = \u0026lan969x_desc },\n--\ndrivers/clk/clk-lan966x.c-306-};\ndrivers/clk/clk-lan966x.c:307:MODULE_DEVICE_TABLE(of, lan966x_clk_dt_ids);\ndrivers/clk/clk-lan966x.c-308-\ndrivers/clk/clk-lan966x.c:309:static struct platform_driver lan966x_clk_driver = {\ndrivers/clk/clk-lan966x.c:310:\t.probe = lan966x_clk_probe,\ndrivers/clk/clk-lan966x.c-311-\t.driver = {\ndrivers/clk/clk-lan966x.c:312:\t\t.name = \"lan966x-clk\",\ndrivers/clk/clk-lan966x.c:313:\t\t.of_match_table = lan966x_clk_dt_ids,\ndrivers/clk/clk-lan966x.c-314-\t},\ndrivers/clk/clk-lan966x.c-315-};\ndrivers/clk/clk-lan966x.c:316:module_platform_driver(lan966x_clk_driver);\ndrivers/clk/clk-lan966x.c-317-\n--\ndrivers/hwmon/Kconfig=976=config SENSORS_LAN966X\n--\ndrivers/hwmon/Kconfig-985-\t This driver can also be built as a module. If so, the module\ndrivers/hwmon/Kconfig:986:\t will be called lan966x-hwmon.\ndrivers/hwmon/Kconfig-987-\n--\ndrivers/hwmon/Makefile=116=obj-$(CONFIG_SENSORS_KFAN)\t+= kfan.o\ndrivers/hwmon/Makefile:117:obj-$(CONFIG_SENSORS_LAN966X)\t+= lan966x-hwmon.o\ndrivers/hwmon/Makefile-118-obj-$(CONFIG_SENSORS_LATTEPANDA_SIGMA_EC) += lattepanda-sigma-ec.o\n--\ndrivers/hwmon/lan966x-hwmon.c=34=static const struct polynomial poly_N_to_temp = {\n--\ndrivers/hwmon/lan966x-hwmon.c-69-\ndrivers/hwmon/lan966x-hwmon.c:70:struct lan966x_hwmon {\ndrivers/hwmon/lan966x-hwmon.c-71-\tstruct regmap *regmap_pvt;\n--\ndrivers/hwmon/lan966x-hwmon.c-76-\ndrivers/hwmon/lan966x-hwmon.c:77:static int lan966x_hwmon_read_temp(struct device *dev, long *val)\ndrivers/hwmon/lan966x-hwmon.c-78-{\ndrivers/hwmon/lan966x-hwmon.c:79:\tstruct lan966x_hwmon *hwmon = dev_get_drvdata(dev);\ndrivers/hwmon/lan966x-hwmon.c-80-\tunsigned int data;\n--\ndrivers/hwmon/lan966x-hwmon.c-95-\ndrivers/hwmon/lan966x-hwmon.c:96:static int lan966x_hwmon_read_fan(struct device *dev, long *val)\ndrivers/hwmon/lan966x-hwmon.c-97-{\ndrivers/hwmon/lan966x-hwmon.c:98:\tstruct lan966x_hwmon *hwmon = dev_get_drvdata(dev);\ndrivers/hwmon/lan966x-hwmon.c-99-\tunsigned int data;\n--\ndrivers/hwmon/lan966x-hwmon.c-114-\ndrivers/hwmon/lan966x-hwmon.c:115:static int lan966x_hwmon_read_pwm(struct device *dev, long *val)\ndrivers/hwmon/lan966x-hwmon.c-116-{\ndrivers/hwmon/lan966x-hwmon.c:117:\tstruct lan966x_hwmon *hwmon = dev_get_drvdata(dev);\ndrivers/hwmon/lan966x-hwmon.c-118-\tunsigned int data;\n--\ndrivers/hwmon/lan966x-hwmon.c-129-\ndrivers/hwmon/lan966x-hwmon.c:130:static int lan966x_hwmon_read_pwm_freq(struct device *dev, long *val)\ndrivers/hwmon/lan966x-hwmon.c-131-{\ndrivers/hwmon/lan966x-hwmon.c:132:\tstruct lan966x_hwmon *hwmon = dev_get_drvdata(dev);\ndrivers/hwmon/lan966x-hwmon.c-133-\tunsigned long tmp;\n--\ndrivers/hwmon/lan966x-hwmon.c-151-\ndrivers/hwmon/lan966x-hwmon.c:152:static int lan966x_hwmon_read(struct device *dev, enum hwmon_sensor_types type,\ndrivers/hwmon/lan966x-hwmon.c-153-\t\t\t u32 attr, int channel, long *val)\n--\ndrivers/hwmon/lan966x-hwmon.c-156-\tcase hwmon_temp:\ndrivers/hwmon/lan966x-hwmon.c:157:\t\treturn lan966x_hwmon_read_temp(dev, val);\ndrivers/hwmon/lan966x-hwmon.c-158-\tcase hwmon_fan:\ndrivers/hwmon/lan966x-hwmon.c:159:\t\treturn lan966x_hwmon_read_fan(dev, val);\ndrivers/hwmon/lan966x-hwmon.c-160-\tcase hwmon_pwm:\n--\ndrivers/hwmon/lan966x-hwmon.c-162-\t\tcase hwmon_pwm_input:\ndrivers/hwmon/lan966x-hwmon.c:163:\t\t\treturn lan966x_hwmon_read_pwm(dev, val);\ndrivers/hwmon/lan966x-hwmon.c-164-\t\tcase hwmon_pwm_freq:\ndrivers/hwmon/lan966x-hwmon.c:165:\t\t\treturn lan966x_hwmon_read_pwm_freq(dev, val);\ndrivers/hwmon/lan966x-hwmon.c-166-\t\tdefault:\n--\ndrivers/hwmon/lan966x-hwmon.c-173-\ndrivers/hwmon/lan966x-hwmon.c:174:static int lan966x_hwmon_write_pwm(struct device *dev, long val)\ndrivers/hwmon/lan966x-hwmon.c-175-{\ndrivers/hwmon/lan966x-hwmon.c:176:\tstruct lan966x_hwmon *hwmon = dev_get_drvdata(dev);\ndrivers/hwmon/lan966x-hwmon.c-177-\n--\ndrivers/hwmon/lan966x-hwmon.c-185-\ndrivers/hwmon/lan966x-hwmon.c:186:static int lan966x_hwmon_write_pwm_freq(struct device *dev, long val)\ndrivers/hwmon/lan966x-hwmon.c-187-{\ndrivers/hwmon/lan966x-hwmon.c:188:\tstruct lan966x_hwmon *hwmon = dev_get_drvdata(dev);\ndrivers/hwmon/lan966x-hwmon.c-189-\n--\ndrivers/hwmon/lan966x-hwmon.c-201-\ndrivers/hwmon/lan966x-hwmon.c:202:static int lan966x_hwmon_write(struct device *dev, enum hwmon_sensor_types type,\ndrivers/hwmon/lan966x-hwmon.c-203-\t\t\t u32 attr, int channel, long val)\n--\ndrivers/hwmon/lan966x-hwmon.c-208-\t\tcase hwmon_pwm_input:\ndrivers/hwmon/lan966x-hwmon.c:209:\t\t\treturn lan966x_hwmon_write_pwm(dev, val);\ndrivers/hwmon/lan966x-hwmon.c-210-\t\tcase hwmon_pwm_freq:\ndrivers/hwmon/lan966x-hwmon.c:211:\t\t\treturn lan966x_hwmon_write_pwm_freq(dev, val);\ndrivers/hwmon/lan966x-hwmon.c-212-\t\tdefault:\n--\ndrivers/hwmon/lan966x-hwmon.c-219-\ndrivers/hwmon/lan966x-hwmon.c:220:static umode_t lan966x_hwmon_is_visible(const void *data,\ndrivers/hwmon/lan966x-hwmon.c-221-\t\t\t\t\tenum hwmon_sensor_types type,\n--\ndrivers/hwmon/lan966x-hwmon.c-261-\ndrivers/hwmon/lan966x-hwmon.c:262:static const struct hwmon_channel_info * const lan966x_hwmon_info[] = {\ndrivers/hwmon/lan966x-hwmon.c-263-\tHWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ),\n--\ndrivers/hwmon/lan966x-hwmon.c-269-\ndrivers/hwmon/lan966x-hwmon.c:270:static const struct hwmon_ops lan966x_hwmon_ops = {\ndrivers/hwmon/lan966x-hwmon.c:271:\t.is_visible = lan966x_hwmon_is_visible,\ndrivers/hwmon/lan966x-hwmon.c:272:\t.read = lan966x_hwmon_read,\ndrivers/hwmon/lan966x-hwmon.c:273:\t.write = lan966x_hwmon_write,\ndrivers/hwmon/lan966x-hwmon.c-274-};\ndrivers/hwmon/lan966x-hwmon.c-275-\ndrivers/hwmon/lan966x-hwmon.c:276:static const struct hwmon_chip_info lan966x_hwmon_chip_info = {\ndrivers/hwmon/lan966x-hwmon.c:277:\t.ops = \u0026lan966x_hwmon_ops,\ndrivers/hwmon/lan966x-hwmon.c:278:\t.info = lan966x_hwmon_info,\ndrivers/hwmon/lan966x-hwmon.c-279-};\ndrivers/hwmon/lan966x-hwmon.c-280-\ndrivers/hwmon/lan966x-hwmon.c:281:static void lan966x_hwmon_disable(void *data)\ndrivers/hwmon/lan966x-hwmon.c-282-{\ndrivers/hwmon/lan966x-hwmon.c:283:\tstruct lan966x_hwmon *hwmon = data;\ndrivers/hwmon/lan966x-hwmon.c-284-\n--\ndrivers/hwmon/lan966x-hwmon.c-289-\ndrivers/hwmon/lan966x-hwmon.c:290:static int lan966x_hwmon_enable(struct device *dev,\ndrivers/hwmon/lan966x-hwmon.c:291:\t\t\t\tstruct lan966x_hwmon *hwmon)\ndrivers/hwmon/lan966x-hwmon.c-292-{\n--\ndrivers/hwmon/lan966x-hwmon.c-313-\ndrivers/hwmon/lan966x-hwmon.c:314:\treturn devm_add_action_or_reset(dev, lan966x_hwmon_disable, hwmon);\ndrivers/hwmon/lan966x-hwmon.c-315-}\ndrivers/hwmon/lan966x-hwmon.c-316-\ndrivers/hwmon/lan966x-hwmon.c:317:static struct regmap *lan966x_init_regmap(struct platform_device *pdev,\ndrivers/hwmon/lan966x-hwmon.c-318-\t\t\t\t\t const char *name)\n--\ndrivers/hwmon/lan966x-hwmon.c-335-\ndrivers/hwmon/lan966x-hwmon.c:336:static int lan966x_hwmon_probe(struct platform_device *pdev)\ndrivers/hwmon/lan966x-hwmon.c-337-{\ndrivers/hwmon/lan966x-hwmon.c-338-\tstruct device *dev = \u0026pdev-\u003edev;\ndrivers/hwmon/lan966x-hwmon.c:339:\tstruct lan966x_hwmon *hwmon;\ndrivers/hwmon/lan966x-hwmon.c-340-\tstruct device *hwmon_dev;\n--\ndrivers/hwmon/lan966x-hwmon.c-353-\ndrivers/hwmon/lan966x-hwmon.c:354:\thwmon-\u003eregmap_pvt = lan966x_init_regmap(pdev, \"pvt\");\ndrivers/hwmon/lan966x-hwmon.c-355-\tif (IS_ERR(hwmon-\u003eregmap_pvt))\n--\ndrivers/hwmon/lan966x-hwmon.c-358-\ndrivers/hwmon/lan966x-hwmon.c:359:\thwmon-\u003eregmap_fan = lan966x_init_regmap(pdev, \"fan\");\ndrivers/hwmon/lan966x-hwmon.c-360-\tif (IS_ERR(hwmon-\u003eregmap_fan))\n--\ndrivers/hwmon/lan966x-hwmon.c-363-\ndrivers/hwmon/lan966x-hwmon.c:364:\tret = lan966x_hwmon_enable(dev, hwmon);\ndrivers/hwmon/lan966x-hwmon.c-365-\tif (ret)\n--\ndrivers/hwmon/lan966x-hwmon.c-368-\thwmon_dev = devm_hwmon_device_register_with_info(\u0026pdev-\u003edev,\ndrivers/hwmon/lan966x-hwmon.c:369:\t\t\t\t\"lan966x_hwmon\", hwmon,\ndrivers/hwmon/lan966x-hwmon.c:370:\t\t\t\t\u0026lan966x_hwmon_chip_info, NULL);\ndrivers/hwmon/lan966x-hwmon.c-371-\tif (IS_ERR(hwmon_dev))\n--\ndrivers/hwmon/lan966x-hwmon.c-377-\ndrivers/hwmon/lan966x-hwmon.c:378:static const struct of_device_id lan966x_hwmon_of_match[] = {\ndrivers/hwmon/lan966x-hwmon.c-379-\t{ .compatible = \"microchip,lan9668-hwmon\" },\n--\ndrivers/hwmon/lan966x-hwmon.c-381-};\ndrivers/hwmon/lan966x-hwmon.c:382:MODULE_DEVICE_TABLE(of, lan966x_hwmon_of_match);\ndrivers/hwmon/lan966x-hwmon.c-383-\ndrivers/hwmon/lan966x-hwmon.c:384:static struct platform_driver lan966x_hwmon_driver = {\ndrivers/hwmon/lan966x-hwmon.c:385:\t.probe = lan966x_hwmon_probe,\ndrivers/hwmon/lan966x-hwmon.c-386-\t.driver = {\ndrivers/hwmon/lan966x-hwmon.c:387:\t\t.name = \"lan966x-hwmon\",\ndrivers/hwmon/lan966x-hwmon.c:388:\t\t.of_match_table = lan966x_hwmon_of_match,\ndrivers/hwmon/lan966x-hwmon.c-389-\t},\ndrivers/hwmon/lan966x-hwmon.c-390-};\ndrivers/hwmon/lan966x-hwmon.c:391:module_platform_driver(lan966x_hwmon_driver);\ndrivers/hwmon/lan966x-hwmon.c-392-\n--\ndrivers/irqchip/Kconfig=225=config LAN966X_OIC\n--\ndrivers/irqchip/Kconfig-235-\t To compile this driver as a module, choose M here: the module\ndrivers/irqchip/Kconfig:236:\t will be called irq-lan966x-oic.\ndrivers/irqchip/Kconfig-237-\n--\ndrivers/irqchip/Makefile=116=obj-$(CONFIG_MADERA_IRQ)\t\t+= irq-madera.o\ndrivers/irqchip/Makefile:117:obj-$(CONFIG_LAN966X_OIC)\t\t+= irq-lan966x-oic.o\ndrivers/irqchip/Makefile-118-obj-$(CONFIG_LS1X_IRQ)\t\t\t+= irq-ls1x.o\n--\ndrivers/irqchip/irq-lan966x-oic.c-20-\ndrivers/irqchip/irq-lan966x-oic.c:21:struct lan966x_oic_chip_regs {\ndrivers/irqchip/irq-lan966x-oic.c-22-\tint reg_off_ena_set;\n--\ndrivers/irqchip/irq-lan966x-oic.c-28-\ndrivers/irqchip/irq-lan966x-oic.c:29:struct lan966x_oic_data {\ndrivers/irqchip/irq-lan966x-oic.c-30-\tvoid __iomem\t*regs;\n--\ndrivers/irqchip/irq-lan966x-oic.c-65-\ndrivers/irqchip/irq-lan966x-oic.c:66:static unsigned int lan966x_oic_irq_startup(struct irq_data *data)\ndrivers/irqchip/irq-lan966x-oic.c-67-{\n--\ndrivers/irqchip/irq-lan966x-oic.c-69-\tstruct irq_chip_type *ct = irq_data_get_chip_type(data);\ndrivers/irqchip/irq-lan966x-oic.c:70:\tstruct lan966x_oic_chip_regs *chip_regs = gc-\u003eprivate;\ndrivers/irqchip/irq-lan966x-oic.c-71-\tu32 map;\n--\ndrivers/irqchip/irq-lan966x-oic.c-85-\ndrivers/irqchip/irq-lan966x-oic.c:86:static void lan966x_oic_irq_shutdown(struct irq_data *data)\ndrivers/irqchip/irq-lan966x-oic.c-87-{\n--\ndrivers/irqchip/irq-lan966x-oic.c-89-\tstruct irq_chip_type *ct = irq_data_get_chip_type(data);\ndrivers/irqchip/irq-lan966x-oic.c:90:\tstruct lan966x_oic_chip_regs *chip_regs = gc-\u003eprivate;\ndrivers/irqchip/irq-lan966x-oic.c-91-\tu32 map;\n--\ndrivers/irqchip/irq-lan966x-oic.c-102-\ndrivers/irqchip/irq-lan966x-oic.c:103:static int lan966x_oic_irq_set_type(struct irq_data *data,\ndrivers/irqchip/irq-lan966x-oic.c-104-\t\t\t\t unsigned int flow_type)\n--\ndrivers/irqchip/irq-lan966x-oic.c-106-\tif (flow_type != IRQ_TYPE_LEVEL_HIGH) {\ndrivers/irqchip/irq-lan966x-oic.c:107:\t\tpr_err(\"lan966x oic doesn't support flow type %d\\n\", flow_type);\ndrivers/irqchip/irq-lan966x-oic.c-108-\t\treturn -EINVAL;\n--\ndrivers/irqchip/irq-lan966x-oic.c-113-\ndrivers/irqchip/irq-lan966x-oic.c:114:static void lan966x_oic_irq_handler_domain(struct irq_domain *d, u32 first_irq)\ndrivers/irqchip/irq-lan966x-oic.c-115-{\ndrivers/irqchip/irq-lan966x-oic.c-116-\tstruct irq_chip_generic *gc = irq_get_domain_generic_chip(d, first_irq);\ndrivers/irqchip/irq-lan966x-oic.c:117:\tstruct lan966x_oic_chip_regs *chip_regs = gc-\u003eprivate;\ndrivers/irqchip/irq-lan966x-oic.c-118-\tunsigned long ident;\n--\ndrivers/irqchip/irq-lan966x-oic.c-128-\ndrivers/irqchip/irq-lan966x-oic.c:129:static void lan966x_oic_irq_handler(struct irq_desc *desc)\ndrivers/irqchip/irq-lan966x-oic.c-130-{\n--\ndrivers/irqchip/irq-lan966x-oic.c-134-\tchained_irq_enter(chip, desc);\ndrivers/irqchip/irq-lan966x-oic.c:135:\tlan966x_oic_irq_handler_domain(d, 0);\ndrivers/irqchip/irq-lan966x-oic.c:136:\tlan966x_oic_irq_handler_domain(d, 32);\ndrivers/irqchip/irq-lan966x-oic.c:137:\tlan966x_oic_irq_handler_domain(d, 64);\ndrivers/irqchip/irq-lan966x-oic.c-138-\tchained_irq_exit(chip, desc);\n--\ndrivers/irqchip/irq-lan966x-oic.c-140-\ndrivers/irqchip/irq-lan966x-oic.c:141:static struct lan966x_oic_chip_regs lan966x_oic_chip_regs[3] = {\ndrivers/irqchip/irq-lan966x-oic.c-142-\t{\n--\ndrivers/irqchip/irq-lan966x-oic.c-162-\ndrivers/irqchip/irq-lan966x-oic.c:163:static int lan966x_oic_chip_init(struct irq_chip_generic *gc)\ndrivers/irqchip/irq-lan966x-oic.c-164-{\ndrivers/irqchip/irq-lan966x-oic.c:165:\tstruct lan966x_oic_data *lan966x_oic = gc-\u003edomain-\u003ehost_data;\ndrivers/irqchip/irq-lan966x-oic.c:166:\tstruct lan966x_oic_chip_regs *chip_regs;\ndrivers/irqchip/irq-lan966x-oic.c-167-\ndrivers/irqchip/irq-lan966x-oic.c:168:\tchip_regs = \u0026lan966x_oic_chip_regs[gc-\u003eirq_base / 32];\ndrivers/irqchip/irq-lan966x-oic.c-169-\ndrivers/irqchip/irq-lan966x-oic.c:170:\tgc-\u003ereg_base = lan966x_oic-\u003eregs;\ndrivers/irqchip/irq-lan966x-oic.c-171-\tgc-\u003echip_types[0].regs.enable = chip_regs-\u003ereg_off_ena_set;\n--\ndrivers/irqchip/irq-lan966x-oic.c-173-\tgc-\u003echip_types[0].regs.ack = chip_regs-\u003ereg_off_sticky;\ndrivers/irqchip/irq-lan966x-oic.c:174:\tgc-\u003echip_types[0].chip.irq_startup = lan966x_oic_irq_startup;\ndrivers/irqchip/irq-lan966x-oic.c:175:\tgc-\u003echip_types[0].chip.irq_shutdown = lan966x_oic_irq_shutdown;\ndrivers/irqchip/irq-lan966x-oic.c:176:\tgc-\u003echip_types[0].chip.irq_set_type = lan966x_oic_irq_set_type;\ndrivers/irqchip/irq-lan966x-oic.c-177-\tgc-\u003echip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;\n--\ndrivers/irqchip/irq-lan966x-oic.c-187-\ndrivers/irqchip/irq-lan966x-oic.c:188:static void lan966x_oic_chip_exit(struct irq_chip_generic *gc)\ndrivers/irqchip/irq-lan966x-oic.c-189-{\n--\ndrivers/irqchip/irq-lan966x-oic.c-194-\ndrivers/irqchip/irq-lan966x-oic.c:195:static int lan966x_oic_domain_init(struct irq_domain *d)\ndrivers/irqchip/irq-lan966x-oic.c-196-{\ndrivers/irqchip/irq-lan966x-oic.c:197:\tstruct lan966x_oic_data *lan966x_oic = d-\u003ehost_data;\ndrivers/irqchip/irq-lan966x-oic.c-198-\ndrivers/irqchip/irq-lan966x-oic.c:199:\tirq_set_chained_handler_and_data(lan966x_oic-\u003eirq, lan966x_oic_irq_handler, d);\ndrivers/irqchip/irq-lan966x-oic.c-200-\n--\ndrivers/irqchip/irq-lan966x-oic.c-203-\ndrivers/irqchip/irq-lan966x-oic.c:204:static void lan966x_oic_domain_exit(struct irq_domain *d)\ndrivers/irqchip/irq-lan966x-oic.c-205-{\ndrivers/irqchip/irq-lan966x-oic.c:206:\tstruct lan966x_oic_data *lan966x_oic = d-\u003ehost_data;\ndrivers/irqchip/irq-lan966x-oic.c-207-\ndrivers/irqchip/irq-lan966x-oic.c:208:\tirq_set_chained_handler_and_data(lan966x_oic-\u003eirq, NULL, NULL);\ndrivers/irqchip/irq-lan966x-oic.c-209-}\ndrivers/irqchip/irq-lan966x-oic.c-210-\ndrivers/irqchip/irq-lan966x-oic.c:211:static int lan966x_oic_probe(struct platform_device *pdev)\ndrivers/irqchip/irq-lan966x-oic.c-212-{\ndrivers/irqchip/irq-lan966x-oic.c-213-\tstruct irq_domain_chip_generic_info dgc_info = {\ndrivers/irqchip/irq-lan966x-oic.c:214:\t\t.name\t\t= \"lan966x-oic\",\ndrivers/irqchip/irq-lan966x-oic.c-215-\t\t.handler\t= handle_level_irq,\n--\ndrivers/irqchip/irq-lan966x-oic.c-217-\t\t.num_ct\t\t= 1,\ndrivers/irqchip/irq-lan966x-oic.c:218:\t\t.init\t\t= lan966x_oic_chip_init,\ndrivers/irqchip/irq-lan966x-oic.c:219:\t\t.exit\t\t= lan966x_oic_chip_exit,\ndrivers/irqchip/irq-lan966x-oic.c-220-\t};\n--\ndrivers/irqchip/irq-lan966x-oic.c-227-\t\t.dgc_info\t= \u0026dgc_info,\ndrivers/irqchip/irq-lan966x-oic.c:228:\t\t.init\t\t= lan966x_oic_domain_init,\ndrivers/irqchip/irq-lan966x-oic.c:229:\t\t.exit\t\t= lan966x_oic_domain_exit,\ndrivers/irqchip/irq-lan966x-oic.c-230-\t};\ndrivers/irqchip/irq-lan966x-oic.c:231:\tstruct lan966x_oic_data *lan966x_oic;\ndrivers/irqchip/irq-lan966x-oic.c-232-\tstruct device *dev = \u0026pdev-\u003edev;\n--\ndrivers/irqchip/irq-lan966x-oic.c-234-\ndrivers/irqchip/irq-lan966x-oic.c:235:\tlan966x_oic = devm_kmalloc(dev, sizeof(*lan966x_oic), GFP_KERNEL);\ndrivers/irqchip/irq-lan966x-oic.c:236:\tif (!lan966x_oic)\ndrivers/irqchip/irq-lan966x-oic.c-237-\t\treturn -ENOMEM;\ndrivers/irqchip/irq-lan966x-oic.c-238-\ndrivers/irqchip/irq-lan966x-oic.c:239:\tlan966x_oic-\u003eregs = devm_platform_ioremap_resource(pdev, 0);\ndrivers/irqchip/irq-lan966x-oic.c:240:\tif (IS_ERR(lan966x_oic-\u003eregs))\ndrivers/irqchip/irq-lan966x-oic.c:241:\t\treturn dev_err_probe(dev, PTR_ERR(lan966x_oic-\u003eregs),\ndrivers/irqchip/irq-lan966x-oic.c-242-\t\t\t\t \"failed to map resource\\n\");\ndrivers/irqchip/irq-lan966x-oic.c-243-\ndrivers/irqchip/irq-lan966x-oic.c:244:\tlan966x_oic-\u003eirq = platform_get_irq(pdev, 0);\ndrivers/irqchip/irq-lan966x-oic.c:245:\tif (lan966x_oic-\u003eirq \u003c 0)\ndrivers/irqchip/irq-lan966x-oic.c:246:\t\treturn dev_err_probe(dev, lan966x_oic-\u003eirq, \"failed to get the IRQ\\n\");\ndrivers/irqchip/irq-lan966x-oic.c-247-\ndrivers/irqchip/irq-lan966x-oic.c:248:\td_info.host_data = lan966x_oic;\ndrivers/irqchip/irq-lan966x-oic.c-249-\tdomain = devm_irq_domain_instantiate(dev, \u0026d_info);\n--\ndrivers/irqchip/irq-lan966x-oic.c-255-\ndrivers/irqchip/irq-lan966x-oic.c:256:static const struct of_device_id lan966x_oic_of_match[] = {\ndrivers/irqchip/irq-lan966x-oic.c:257:\t{ .compatible = \"microchip,lan966x-oic\" },\ndrivers/irqchip/irq-lan966x-oic.c-258-\t{} /* sentinel */\ndrivers/irqchip/irq-lan966x-oic.c-259-};\ndrivers/irqchip/irq-lan966x-oic.c:260:MODULE_DEVICE_TABLE(of, lan966x_oic_of_match);\ndrivers/irqchip/irq-lan966x-oic.c-261-\ndrivers/irqchip/irq-lan966x-oic.c:262:static struct platform_driver lan966x_oic_driver = {\ndrivers/irqchip/irq-lan966x-oic.c:263:\t.probe = lan966x_oic_probe,\ndrivers/irqchip/irq-lan966x-oic.c-264-\t.driver = {\ndrivers/irqchip/irq-lan966x-oic.c:265:\t\t.name = \"lan966x-oic\",\ndrivers/irqchip/irq-lan966x-oic.c:266:\t\t.of_match_table = lan966x_oic_of_match,\ndrivers/irqchip/irq-lan966x-oic.c-267-\t},\ndrivers/irqchip/irq-lan966x-oic.c-268-};\ndrivers/irqchip/irq-lan966x-oic.c:269:module_platform_driver(lan966x_oic_driver);\ndrivers/irqchip/irq-lan966x-oic.c-270-\n--\ndrivers/misc/Kconfig=614=config MCHP_LAN966X_PCI\n--\ndrivers/misc/Kconfig-628-\t - fixed-clock (COMMON_CLK)\ndrivers/misc/Kconfig:629:\t - lan966x-oic (LAN966X_OIC)\ndrivers/misc/Kconfig:630:\t - lan966x-cpu-syscon (MFD_SYSCON)\ndrivers/misc/Kconfig:631:\t - lan966x-switch-reset (RESET_MCHP_SPARX5)\ndrivers/misc/Kconfig:632:\t - lan966x-pinctrl (PINCTRL_OCELOT)\ndrivers/misc/Kconfig:633:\t - lan966x-serdes (PHY_LAN966X_SERDES)\ndrivers/misc/Kconfig:634:\t - lan966x-miim (MDIO_MSCC_MIIM)\ndrivers/misc/Kconfig:635:\t - lan966x-switch (LAN966X_SWITCH)\ndrivers/misc/Kconfig-636-\n--\ndrivers/misc/Makefile=70=obj-$(CONFIG_MARVELL_CN10K_DPI)\t+= mrvl_cn10k_dpi.o\ndrivers/misc/Makefile:71:lan966x-pci-objs\t\t:= lan966x_pci.o\ndrivers/misc/Makefile:72:lan966x-pci-objs\t\t+= lan966x_pci.dtbo.o\ndrivers/misc/Makefile:73:obj-$(CONFIG_MCHP_LAN966X_PCI)\t+= lan966x-pci.o\ndrivers/misc/Makefile-74-obj-y\t\t\t\t+= keba/\n--\ndrivers/misc/lan966x_pci.c-21-/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */\ndrivers/misc/lan966x_pci.c:22:extern char __dtbo_lan966x_pci_begin[];\ndrivers/misc/lan966x_pci.c:23:extern char __dtbo_lan966x_pci_end[];\ndrivers/misc/lan966x_pci.c-24-\n--\ndrivers/misc/lan966x_pci.c=110=static int devm_pci_dev_create_intr_ctrl(struct pci_dev *pdev)\n--\ndrivers/misc/lan966x_pci.c-120-\ndrivers/misc/lan966x_pci.c:121:struct lan966x_pci {\ndrivers/misc/lan966x_pci.c-122-\tstruct device *dev;\n--\ndrivers/misc/lan966x_pci.c-125-\ndrivers/misc/lan966x_pci.c:126:static int lan966x_pci_load_overlay(struct lan966x_pci *data)\ndrivers/misc/lan966x_pci.c-127-{\ndrivers/misc/lan966x_pci.c:128:\tu32 dtbo_size = __dtbo_lan966x_pci_end - __dtbo_lan966x_pci_begin;\ndrivers/misc/lan966x_pci.c:129:\tvoid *dtbo_start = __dtbo_lan966x_pci_begin;\ndrivers/misc/lan966x_pci.c-130-\n--\ndrivers/misc/lan966x_pci.c-133-\ndrivers/misc/lan966x_pci.c:134:static void lan966x_pci_unload_overlay(struct lan966x_pci *data)\ndrivers/misc/lan966x_pci.c-135-{\n--\ndrivers/misc/lan966x_pci.c-138-\ndrivers/misc/lan966x_pci.c:139:static int lan966x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)\ndrivers/misc/lan966x_pci.c-140-{\n\n"
} |
| 39/2 | 2026/07/13 19:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 194487 output: 30 thoughts: 756 Thoughts: **Investigating the LAN9645x Regmap Retrieval**
Okay, so I'm digging into how the `lan9645x` driver in `drivers/net/dsa/microchip/lan9645x/` is getting its regmaps, specifically within the context of the LAN966x PCI setup. I'm looking at `drivers/misc/lan966x_pci.c` and its device tree overlay `lan966x_pci.dtso`. My immediate thought is, "Wait, how is this reset controller being handled?" The DT overlay seems to define a reset controller at address `0xe200400c`, with a second register region at `0xe00c0000`.
The `lan9645x` driver, as I recall, uses `dev_get_regmap` with a resource name, as seen in `lan9645x_main.c`:
```c
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;
}
```
This method is contingent on the parent device having called `devm_regmap_init` to attach the regmap to its device structure. A likely parent device in the system might be a syscon node. However, this is where it gets tricky, because `syscon` itself doesn't use `devm_regmap_init` in the way I'd expect. `syscon` drivers use `syscon_node_to_regmap`, which uses a global list of syscon regmaps. It seems as though `dev_get_regmap` will definitely not work directly with a `syscon` parent.
Now, where are these regmaps actually being *created*? I checked the `lan9645x_main.c` again.
So, if there's no other driver in the kernel that calls `devm_regmap_init` with the appropriate names and acts as the parent of the `lan9645x` device, then the `lan9645x` driver is effectively unreachable with `dev_get_regmap`. Now, could `drivers/mfd/syscon.c` be the parent?
Looking at `syscon.c`, I see `regmap_init_mmio` is used:
```c
regmap = regmap_init_mmio(dev, base, &syscon_regmap_config);
```
But this doesn't register it via `devres`. It doesn't seem to be storing the regmap attached to the device via a name or `devm_*`. This means `dev_get_regmap` will almost certainly return NULL. I looked in the `drivers/mfd/` directory for any other drivers related to `lan9645x`, but there are no matches. I have to search the kernel for `lan9645x_resource_names` in case there's another driver that may be involved.
|
| 40/2 | 2026/07/13 19:33 | tool | grepper |
0mArgs:{
"Expression": "lan9645x_resource_names",
"PathPrefix": ""
}Results: {
"Output": "drivers/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=883=static int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-888-\tfor (int i = 0; i \u003c NUM_TARGETS; i++) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:889:\t\tresource_name = lan9645x_resource_names[i];\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-890-\t\tif (!resource_name)\n"
} |
| 41/2 | 2026/07/13 19:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 196424 output: 41 thoughts: 80 Thoughts: **Navigating the Driver Landscape** Okay, let's think this through. If the device's parent is indeed an MFD driver, I'd logically expect to find the corresponding driver code in the `drivers/mfd/` directory. But a quick check reveals there's no dedicated MFD driver specifically for the lan9645x. That's a bit of a wrinkle. Alright, what if the parent is a PCI device, which is a fairly common architecture? That feels like a plausible alternative path for the device's relationship. To investigate this, I'll turn to `drivers/misc/lan966x_pci.c`, as that sounds like it could be the relevant PCI driver. Time to see if it makes use of any of the common resource initialization functions, I'll search for "devm_regmap_init" which I've used in the past to correctly map and register devices that use a register map. That should illuminate the device's setup. |
| 42/2 | 2026/07/13 19:33 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/misc/lan966x_pci.c"
}Results: {
"error": "no matches"
} |
| 43/2 | 2026/07/13 19:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 196773 output: 43 thoughts: 33 Thoughts: Okay, here's my interpretation of that thought process, assuming I'm deeply familiar with embedded networking drivers: **Considering the Source of a Network Driver Issue** Right, so I'm looking at this problem... and my first instinct is to dig into the heart of the driver. If I'm trying to trace the cause of a network issue and figure out where it's coming from, the most likely culprit, given my experience, is the main driver file. Specifically, I'm thinking, "Could the root of this problem be residing in `drivers/net/ethernet/microchip/lan966x/lan966x_main.c`?" That's the core of the Microchip LAN966x driver, and a lot of key initialization and control logic resides there. It handles device setup, interrupt handling, and likely manages the interaction with the hardware. If something's going sideways with the network, that main file is the natural starting point for my investigation. So, it's my first suspect, and I'll start there. |
| 44/2 | 2026/07/13 19:33 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}Results: {
"error": "no matches"
} |
| 45/2 | 2026/07/13 19:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 197090 output: 31 thoughts: 118 Thoughts: **Debugging a Missing Driver Dependency** Okay, hold on a second. Something isn't clicking. If this driver relies on a `regmap` and there's no obvious driver creating it, how on earth is the probe function even supposed to succeed? It's like trying to build a house without laying the foundation! My first instinct is, let me double-check the patch series. Could the author have simply forgotten to include the Multi-Function Device (MFD) driver responsible for initializing this `regmap`? That's a classic oversight. If the MFD driver is indeed missing, the probe function is guaranteed to choke at the `dev_get_regmap` call and, bang, `-ENODEV`. That would be a simple fix if that were the case. But wait a minute... could `dev_get_regmap` potentially find regmaps that are created through `syscon`? It's conceivable, and I need to rule that out before I start digging into patch series again. I know the `syscon` framework can create register maps, but I don't recall off the top of my head how they're exposed to the driver. I will need to look into `syscon.c` to see if it makes use of `devres` to link these together. This is a crucial detail to verify. |
| 46/2 | 2026/07/13 19:33 | tool | grepper |
0mArgs:{
"Expression": "regmap",
"PathPrefix": "drivers/mfd/syscon.c"
}Results: {
"Output": "drivers/mfd/syscon.c-18-#include \u003clinux/of_address.h\u003e\ndrivers/mfd/syscon.c:19:#include \u003clinux/regmap.h\u003e\ndrivers/mfd/syscon.c-20-#include \u003clinux/reset.h\u003e\n--\ndrivers/mfd/syscon.c=27=struct syscon {\ndrivers/mfd/syscon.c-28-\tstruct device_node *np;\ndrivers/mfd/syscon.c:29:\tstruct regmap *regmap;\ndrivers/mfd/syscon.c-30-\tstruct reset_control *reset;\n--\ndrivers/mfd/syscon.c-33-\ndrivers/mfd/syscon.c:34:static const struct regmap_config syscon_regmap_config = {\ndrivers/mfd/syscon.c-35-\t.reg_bits = 32,\n--\ndrivers/mfd/syscon.c=40=static struct syscon *of_syscon_register(struct device_node *np, bool check_res)\n--\ndrivers/mfd/syscon.c-42-\tstruct clk *clk;\ndrivers/mfd/syscon.c:43:\tstruct regmap *regmap;\ndrivers/mfd/syscon.c-44-\tvoid __iomem *base;\n--\ndrivers/mfd/syscon.c-46-\tint ret;\ndrivers/mfd/syscon.c:47:\tstruct regmap_config syscon_config = syscon_regmap_config;\ndrivers/mfd/syscon.c-48-\tstruct resource res;\n--\ndrivers/mfd/syscon.c-74-\t * search for reg-io-width property in DT. If it is not provided,\ndrivers/mfd/syscon.c:75:\t * default to 4 bytes. regmap_init_mmio will return an error if values\ndrivers/mfd/syscon.c-76-\t * are invalid so there is no need to check them here.\n--\ndrivers/mfd/syscon.c-95-\t\tcase -EPROBE_DEFER:\ndrivers/mfd/syscon.c:96:\t\t\tgoto err_regmap;\ndrivers/mfd/syscon.c-97-\t\t}\n--\ndrivers/mfd/syscon.c-102-\t\tret = -EFAULT;\ndrivers/mfd/syscon.c:103:\t\tgoto err_regmap;\ndrivers/mfd/syscon.c-104-\t}\n--\ndrivers/mfd/syscon.c-108-\t\tret = -ENOMEM;\ndrivers/mfd/syscon.c:109:\t\tgoto err_regmap;\ndrivers/mfd/syscon.c-110-\t}\n--\ndrivers/mfd/syscon.c-116-\ndrivers/mfd/syscon.c:117:\tregmap = regmap_init_mmio(NULL, base, \u0026syscon_config);\ndrivers/mfd/syscon.c-118-\tkfree(syscon_config.name);\ndrivers/mfd/syscon.c:119:\tif (IS_ERR(regmap)) {\ndrivers/mfd/syscon.c:120:\t\tpr_err(\"regmap init failed\\n\");\ndrivers/mfd/syscon.c:121:\t\tret = PTR_ERR(regmap);\ndrivers/mfd/syscon.c:122:\t\tgoto err_regmap;\ndrivers/mfd/syscon.c-123-\t}\n--\ndrivers/mfd/syscon.c-132-\t\t} else {\ndrivers/mfd/syscon.c:133:\t\t\tret = regmap_mmio_attach_clk(regmap, clk);\ndrivers/mfd/syscon.c-134-\t\t\tif (ret)\n--\ndrivers/mfd/syscon.c-148-\ndrivers/mfd/syscon.c:149:\tsyscon-\u003eregmap = regmap;\ndrivers/mfd/syscon.c-150-\tsyscon-\u003enp = np;\n--\ndrivers/mfd/syscon.c-161-err_clk:\ndrivers/mfd/syscon.c:162:\tregmap_exit(regmap);\ndrivers/mfd/syscon.c:163:err_regmap:\ndrivers/mfd/syscon.c-164-\tiounmap(base);\n--\ndrivers/mfd/syscon.c-167-\ndrivers/mfd/syscon.c:168:static struct regmap *device_node_get_regmap(struct device_node *np,\ndrivers/mfd/syscon.c:169:\t\t\t\t\t bool create_regmap,\ndrivers/mfd/syscon.c-170-\t\t\t\t\t bool check_res)\n--\ndrivers/mfd/syscon.c-182-\tif (!syscon) {\ndrivers/mfd/syscon.c:183:\t\tif (create_regmap)\ndrivers/mfd/syscon.c-184-\t\t\tsyscon = of_syscon_register(np, check_res);\n--\ndrivers/mfd/syscon.c-192-\ndrivers/mfd/syscon.c:193:\treturn syscon-\u003eregmap;\ndrivers/mfd/syscon.c-194-}\n--\ndrivers/mfd/syscon.c-196-/**\ndrivers/mfd/syscon.c:197: * of_syscon_register_regmap() - Register regmap for specified device node\ndrivers/mfd/syscon.c-198- * @np: Device tree node\ndrivers/mfd/syscon.c:199: * @regmap: Pointer to regmap object\ndrivers/mfd/syscon.c-200- *\ndrivers/mfd/syscon.c:201: * Register an externally created regmap object with syscon for the specified\ndrivers/mfd/syscon.c:202: * device tree node. This regmap will then be returned to client drivers using\ndrivers/mfd/syscon.c:203: * the syscon_regmap_lookup_by_phandle() API.\ndrivers/mfd/syscon.c-204- *\n--\ndrivers/mfd/syscon.c-206- */\ndrivers/mfd/syscon.c:207:int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap)\ndrivers/mfd/syscon.c-208-{\n--\ndrivers/mfd/syscon.c-211-\ndrivers/mfd/syscon.c:212:\tif (!np || !regmap)\ndrivers/mfd/syscon.c-213-\t\treturn -EINVAL;\n--\ndrivers/mfd/syscon.c-227-\ndrivers/mfd/syscon.c:228:\tsyscon-\u003eregmap = regmap;\ndrivers/mfd/syscon.c-229-\tsyscon-\u003enp = np;\ndrivers/mfd/syscon.c-230-\ndrivers/mfd/syscon.c:231:\t/* register the regmap in syscon list */\ndrivers/mfd/syscon.c-232-\tlist_add_tail(\u0026syscon-\u003elist, \u0026syscon_list);\n--\ndrivers/mfd/syscon.c-241-}\ndrivers/mfd/syscon.c:242:EXPORT_SYMBOL_GPL(of_syscon_register_regmap);\ndrivers/mfd/syscon.c-243-\ndrivers/mfd/syscon.c-244-/**\ndrivers/mfd/syscon.c:245: * device_node_to_regmap() - Get or create a regmap for specified device node\ndrivers/mfd/syscon.c-246- * @np: Device tree node\ndrivers/mfd/syscon.c-247- *\ndrivers/mfd/syscon.c:248: * Get a regmap for the specified device node. If there's not an existing\ndrivers/mfd/syscon.c:249: * regmap, then one is instantiated. This function should not be used if the\ndrivers/mfd/syscon.c:250: * device node has a custom regmap driver or has resources (clocks, resets) to\ndrivers/mfd/syscon.c:251: * be managed. Use syscon_node_to_regmap() instead for those cases.\ndrivers/mfd/syscon.c-252- *\ndrivers/mfd/syscon.c:253: * Return: regmap ptr on success, negative error code on failure.\ndrivers/mfd/syscon.c-254- */\ndrivers/mfd/syscon.c:255:struct regmap *device_node_to_regmap(struct device_node *np)\ndrivers/mfd/syscon.c-256-{\ndrivers/mfd/syscon.c:257:\treturn device_node_get_regmap(np, true, false);\ndrivers/mfd/syscon.c-258-}\ndrivers/mfd/syscon.c:259:EXPORT_SYMBOL_GPL(device_node_to_regmap);\ndrivers/mfd/syscon.c-260-\ndrivers/mfd/syscon.c-261-/**\ndrivers/mfd/syscon.c:262: * syscon_node_to_regmap() - Get or create a regmap for specified syscon device node\ndrivers/mfd/syscon.c-263- * @np: Device tree node\ndrivers/mfd/syscon.c-264- *\ndrivers/mfd/syscon.c:265: * Get a regmap for the specified device node. If there's not an existing\ndrivers/mfd/syscon.c:266: * regmap, then one is instantiated if the node is a generic \"syscon\". This\ndrivers/mfd/syscon.c-267- * function is safe to use for a syscon registered with\ndrivers/mfd/syscon.c:268: * of_syscon_register_regmap().\ndrivers/mfd/syscon.c-269- *\ndrivers/mfd/syscon.c:270: * Return: regmap ptr on success, negative error code on failure.\ndrivers/mfd/syscon.c-271- */\ndrivers/mfd/syscon.c:272:struct regmap *syscon_node_to_regmap(struct device_node *np)\ndrivers/mfd/syscon.c-273-{\ndrivers/mfd/syscon.c:274:\treturn device_node_get_regmap(np, of_device_is_compatible(np, \"syscon\"), true);\ndrivers/mfd/syscon.c-275-}\ndrivers/mfd/syscon.c:276:EXPORT_SYMBOL_GPL(syscon_node_to_regmap);\ndrivers/mfd/syscon.c-277-\ndrivers/mfd/syscon.c:278:struct regmap *syscon_regmap_lookup_by_compatible(const char *s)\ndrivers/mfd/syscon.c-279-{\ndrivers/mfd/syscon.c-280-\tstruct device_node *syscon_np;\ndrivers/mfd/syscon.c:281:\tstruct regmap *regmap;\ndrivers/mfd/syscon.c-282-\n--\ndrivers/mfd/syscon.c-286-\ndrivers/mfd/syscon.c:287:\tregmap = syscon_node_to_regmap(syscon_np);\ndrivers/mfd/syscon.c-288-\tof_node_put(syscon_np);\ndrivers/mfd/syscon.c-289-\ndrivers/mfd/syscon.c:290:\treturn regmap;\ndrivers/mfd/syscon.c-291-}\ndrivers/mfd/syscon.c:292:EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);\ndrivers/mfd/syscon.c-293-\ndrivers/mfd/syscon.c:294:struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,\ndrivers/mfd/syscon.c-295-\t\t\t\t\tconst char *property)\n--\ndrivers/mfd/syscon.c-297-\tstruct device_node *syscon_np;\ndrivers/mfd/syscon.c:298:\tstruct regmap *regmap;\ndrivers/mfd/syscon.c-299-\n--\ndrivers/mfd/syscon.c-307-\ndrivers/mfd/syscon.c:308:\tregmap = syscon_node_to_regmap(syscon_np);\ndrivers/mfd/syscon.c-309-\n--\ndrivers/mfd/syscon.c-312-\ndrivers/mfd/syscon.c:313:\treturn regmap;\ndrivers/mfd/syscon.c-314-}\ndrivers/mfd/syscon.c:315:EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);\ndrivers/mfd/syscon.c-316-\ndrivers/mfd/syscon.c:317:struct regmap *syscon_regmap_lookup_by_phandle_args(struct device_node *np,\ndrivers/mfd/syscon.c-318-\t\t\t\t\tconst char *property,\n--\ndrivers/mfd/syscon.c-323-\tstruct of_phandle_args args;\ndrivers/mfd/syscon.c:324:\tstruct regmap *regmap;\ndrivers/mfd/syscon.c-325-\tunsigned int index;\n--\ndrivers/mfd/syscon.c-336-\ndrivers/mfd/syscon.c:337:\tregmap = syscon_node_to_regmap(syscon_np);\ndrivers/mfd/syscon.c-338-\tfor (index = 0; index \u003c arg_count; index++)\n--\ndrivers/mfd/syscon.c-341-\ndrivers/mfd/syscon.c:342:\treturn regmap;\ndrivers/mfd/syscon.c-343-}\ndrivers/mfd/syscon.c:344:EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_args);\ndrivers/mfd/syscon.c-345-\ndrivers/mfd/syscon.c-346-/*\ndrivers/mfd/syscon.c:347: * It behaves the same as syscon_regmap_lookup_by_phandle() except where\ndrivers/mfd/syscon.c:348: * there is no regmap phandle. In this case, instead of returning -ENODEV,\ndrivers/mfd/syscon.c-349- * the function returns NULL.\ndrivers/mfd/syscon.c-350- */\ndrivers/mfd/syscon.c:351:struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np,\ndrivers/mfd/syscon.c-352-\t\t\t\t\tconst char *property)\ndrivers/mfd/syscon.c-353-{\ndrivers/mfd/syscon.c:354:\tstruct regmap *regmap;\ndrivers/mfd/syscon.c-355-\ndrivers/mfd/syscon.c:356:\tregmap = syscon_regmap_lookup_by_phandle(np, property);\ndrivers/mfd/syscon.c:357:\tif (IS_ERR(regmap) \u0026\u0026 PTR_ERR(regmap) == -ENODEV)\ndrivers/mfd/syscon.c-358-\t\treturn NULL;\ndrivers/mfd/syscon.c-359-\ndrivers/mfd/syscon.c:360:\treturn regmap;\ndrivers/mfd/syscon.c-361-}\ndrivers/mfd/syscon.c:362:EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_optional);\n"
} |
| 47/2 | 2026/07/13 19:33 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 201642 output: 41 thoughts: 195 Thoughts: **Investigating syscon and Regmap Attachment** Okay, so I'm looking at how `syscon` handles its regmap interaction and it seems like it's *not* using `devres` to link the regmap to the device. That's a little unusual, I need to understand why. Hang on, isn't `dev_get_regmap` supposed to use `devres_find`? That's what I thought. If the parent device is an MFD (Multi-Function Device), then it *should* be leveraging `devm_regmap_init` or `regmap_attach_dev` to get things set up properly. I wonder if there are any examples in the driver base where they've used `regmap_attach_dev` or `devm_regmap_init` with devices like the lan966x or lan9645x. Let's do a quick search – I'll look for instances of "lan966x" combined with either "devm_regmap_init" or "regmap_attach_dev". Ah, crap, nothing jumps out. Let me take a look at the specific driver – I'm thinking specifically of `drivers/misc/lan966x_pci.c`. Okay, let's take a look. Yep, `drivers/misc/lan966x_pci.c` doesn't seem to be using `devm_regmap_init` directly. I need to go over that file again, to make sure I'm not missing something. |
| 48/2 | 2026/07/13 19:34 | tool | read-file |
0mArgs:{
"File": "drivers/misc/lan966x_pci.c",
"FirstLine": 1,
"LineCount": 100
}Results: {
"Contents": " 1:\t// SPDX-License-Identifier: GPL-2.0\n 2:\t/*\n 3:\t * Microchip LAN966x PCI driver\n 4:\t *\n 5:\t * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.\n 6:\t *\n 7:\t * Authors:\n 8:\t *\tClément Léger \u003cclement.leger@bootlin.com\u003e\n 9:\t *\tHervé Codina \u003cherve.codina@bootlin.com\u003e\n 10:\t */\n 11:\t\n 12:\t#include \u003clinux/device.h\u003e\n 13:\t#include \u003clinux/irq.h\u003e\n 14:\t#include \u003clinux/irqdomain.h\u003e\n 15:\t#include \u003clinux/module.h\u003e\n 16:\t#include \u003clinux/of_platform.h\u003e\n 17:\t#include \u003clinux/pci.h\u003e\n 18:\t#include \u003clinux/pci_ids.h\u003e\n 19:\t#include \u003clinux/slab.h\u003e\n 20:\t\n 21:\t/* Embedded dtbo symbols created by cmd_wrap_S_dtb in scripts/Makefile.lib */\n 22:\textern char __dtbo_lan966x_pci_begin[];\n 23:\textern char __dtbo_lan966x_pci_end[];\n 24:\t\n 25:\tstruct pci_dev_intr_ctrl {\n 26:\t\tstruct pci_dev *pci_dev;\n 27:\t\tstruct irq_domain *irq_domain;\n 28:\t\tint irq;\n 29:\t};\n 30:\t\n 31:\tstatic int pci_dev_irq_domain_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw)\n 32:\t{\n 33:\t\tirq_set_chip_and_handler(virq, \u0026dummy_irq_chip, handle_simple_irq);\n 34:\t\treturn 0;\n 35:\t}\n 36:\t\n 37:\tstatic const struct irq_domain_ops pci_dev_irq_domain_ops = {\n 38:\t\t.map = pci_dev_irq_domain_map,\n 39:\t\t.xlate = irq_domain_xlate_onecell,\n 40:\t};\n 41:\t\n 42:\tstatic irqreturn_t pci_dev_irq_handler(int irq, void *data)\n 43:\t{\n 44:\t\tstruct pci_dev_intr_ctrl *intr_ctrl = data;\n 45:\t\tint ret;\n 46:\t\n 47:\t\tret = generic_handle_domain_irq(intr_ctrl-\u003eirq_domain, 0);\n 48:\t\treturn ret ? IRQ_NONE : IRQ_HANDLED;\n 49:\t}\n 50:\t\n 51:\tstatic struct pci_dev_intr_ctrl *pci_dev_create_intr_ctrl(struct pci_dev *pdev)\n 52:\t{\n 53:\t\tstruct pci_dev_intr_ctrl *intr_ctrl __free(kfree) = NULL;\n 54:\t\tstruct fwnode_handle *fwnode;\n 55:\t\tint ret;\n 56:\t\n 57:\t\tfwnode = dev_fwnode(\u0026pdev-\u003edev);\n 58:\t\tif (!fwnode)\n 59:\t\t\treturn ERR_PTR(-ENODEV);\n 60:\t\n 61:\t\tintr_ctrl = kmalloc_obj(*intr_ctrl);\n 62:\t\tif (!intr_ctrl)\n 63:\t\t\treturn ERR_PTR(-ENOMEM);\n 64:\t\n 65:\t\tintr_ctrl-\u003epci_dev = pdev;\n 66:\t\n 67:\t\tintr_ctrl-\u003eirq_domain = irq_domain_create_linear(fwnode, 1, \u0026pci_dev_irq_domain_ops,\n 68:\t\t\t\t\t\t\t\t intr_ctrl);\n 69:\t\tif (!intr_ctrl-\u003eirq_domain) {\n 70:\t\t\tpci_err(pdev, \"Failed to create irqdomain\\n\");\n 71:\t\t\treturn ERR_PTR(-ENOMEM);\n 72:\t\t}\n 73:\t\n 74:\t\tret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);\n 75:\t\tif (ret \u003c 0) {\n 76:\t\t\tpci_err(pdev, \"Unable alloc irq vector (%d)\\n\", ret);\n 77:\t\t\tgoto err_remove_domain;\n 78:\t\t}\n 79:\t\tintr_ctrl-\u003eirq = pci_irq_vector(pdev, 0);\n 80:\t\tret = request_irq(intr_ctrl-\u003eirq, pci_dev_irq_handler, IRQF_SHARED,\n 81:\t\t\t\t pci_name(pdev), intr_ctrl);\n 82:\t\tif (ret) {\n 83:\t\t\tpci_err(pdev, \"Unable to request irq %d (%d)\\n\", intr_ctrl-\u003eirq, ret);\n 84:\t\t\tgoto err_free_irq_vector;\n 85:\t\t}\n 86:\t\n 87:\t\treturn_ptr(intr_ctrl);\n 88:\t\n 89:\terr_free_irq_vector:\n 90:\t\tpci_free_irq_vectors(pdev);\n 91:\terr_remove_domain:\n 92:\t\tirq_domain_remove(intr_ctrl-\u003eirq_domain);\n 93:\t\treturn ERR_PTR(ret);\n 94:\t}\n 95:\t\n 96:\tstatic void pci_dev_remove_intr_ctrl(struct pci_dev_intr_ctrl *intr_ctrl)\n 97:\t{\n 98:\t\tfree_irq(intr_ctrl-\u003eirq, intr_ctrl);\n 99:\t\tpci_free_irq_vectors(intr_ctrl-\u003epci_dev);\n 100:\t\tirq_dispose_mapping(irq_find_mapping(intr_ctrl-\u003eirq_domain, 0));\n"
} |
| 49/2 | 2026/07/13 19:34 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 203835 output: 42 thoughts: 67 Thoughts: Okay, here's my take on those thoughts, framed as my own: **Analyzing the LAN966X PCI Driver Initialization** Alright, so `lan966x_pci.c` is going to load a device tree overlay, specifically `lan966x_pci.dtso`. Makes sense – that overlay is where the device tree nodes for the PCI device are defined. It's the standard way to configure and represent this kind of hardware these days. Now, my next step is clear: I need to dig into `lan966x_pci.dtso` and examine those nodes. I want to see how the PCI device is described, what resources are allocated, how interrupts are handled, and how the driver is configured. I'm especially interested in any platform-specific customizations or anything non-standard that might be present. This overlay is the key to understanding how this driver interacts with the hardware. Let's get to it. |
| 50/2 | 2026/07/13 19:34 | tool | read-file |
0mArgs:{
"File": "drivers/misc/lan966x_pci.dtso",
"FirstLine": 1,
"LineCount": 100
}Results: {
"Contents": " 1:\t// SPDX-License-Identifier: GPL-2.0\n 2:\t/*\n 3:\t * Copyright (C) 2022 Microchip UNG\n 4:\t */\n 5:\t\n 6:\t#include \u003cdt-bindings/clock/microchip,lan966x.h\u003e\n 7:\t#include \u003cdt-bindings/gpio/gpio.h\u003e\n 8:\t#include \u003cdt-bindings/interrupt-controller/irq.h\u003e\n 9:\t#include \u003cdt-bindings/mfd/atmel-flexcom.h\u003e\n 10:\t#include \u003cdt-bindings/phy/phy-lan966x-serdes.h\u003e\n 11:\t\n 12:\t/dts-v1/;\n 13:\t/plugin/;\n 14:\t\n 15:\t/ {\n 16:\t\tfragment@0 {\n 17:\t\t\ttarget-path = \"\";\n 18:\t\n 19:\t\t\t/*\n 20:\t\t\t * These properties allow to avoid a dtc warnings.\n 21:\t\t\t * The real interrupt controller is the PCI device itself. It\n 22:\t\t\t * is the node on which the device tree overlay will be applied.\n 23:\t\t\t * This node has those properties.\n 24:\t\t\t */\n 25:\t\t\t#interrupt-cells = \u003c1\u003e;\n 26:\t\t\tinterrupt-controller;\n 27:\t\n 28:\t\t\t__overlay__ {\n 29:\t\t\t\t#address-cells = \u003c3\u003e;\n 30:\t\t\t\t#size-cells = \u003c2\u003e;\n 31:\t\n 32:\t\t\t\tcpu_clk: clock-600000000 {\n 33:\t\t\t\t\tcompatible = \"fixed-clock\";\n 34:\t\t\t\t\t#clock-cells = \u003c0\u003e;\n 35:\t\t\t\t\tclock-frequency = \u003c600000000\u003e; /* CPU clock = 600MHz */\n 36:\t\t\t\t};\n 37:\t\n 38:\t\t\t\tddr_clk: clock-30000000 {\n 39:\t\t\t\t\tcompatible = \"fixed-clock\";\n 40:\t\t\t\t\t#clock-cells = \u003c0\u003e;\n 41:\t\t\t\t\tclock-frequency = \u003c30000000\u003e; /* Fabric clock = 30MHz */\n 42:\t\t\t\t};\n 43:\t\n 44:\t\t\t\tsys_clk: clock-15625000 {\n 45:\t\t\t\t\tcompatible = \"fixed-clock\";\n 46:\t\t\t\t\t#clock-cells = \u003c0\u003e;\n 47:\t\t\t\t\tclock-frequency = \u003c15625000\u003e; /* System clock = 15.625MHz */\n 48:\t\t\t\t};\n 49:\t\n 50:\t\t\t\tpci-ep-bus@0 {\n 51:\t\t\t\t\tcompatible = \"simple-bus\";\n 52:\t\t\t\t\t#address-cells = \u003c1\u003e;\n 53:\t\t\t\t\t#size-cells = \u003c1\u003e;\n 54:\t\n 55:\t\t\t\t\t/*\n 56:\t\t\t\t\t * map @0xe2000000 (32MB) to BAR0 (CPU)\n 57:\t\t\t\t\t * map @0xe0000000 (16MB) to BAR1 (AMBA)\n 58:\t\t\t\t\t */\n 59:\t\t\t\t\tranges = \u003c0xe2000000 0x00 0x00 0x00 0x2000000\n 60:\t\t\t\t\t 0xe0000000 0x01 0x00 0x00 0x1000000\u003e;\n 61:\t\n 62:\t\t\t\t\toic: oic@e00c0120 {\n 63:\t\t\t\t\t\tcompatible = \"microchip,lan966x-oic\";\n 64:\t\t\t\t\t\t#interrupt-cells = \u003c2\u003e;\n 65:\t\t\t\t\t\tinterrupt-controller;\n 66:\t\t\t\t\t\tinterrupts = \u003c0\u003e; /* PCI INTx assigned interrupt */\n 67:\t\t\t\t\t\treg = \u003c0xe00c0120 0x190\u003e;\n 68:\t\t\t\t\t};\n 69:\t\n 70:\t\t\t\t\tcpu_ctrl: syscon@e00c0000 {\n 71:\t\t\t\t\t\tcompatible = \"microchip,lan966x-cpu-syscon\", \"syscon\";\n 72:\t\t\t\t\t\treg = \u003c0xe00c0000 0xa8\u003e;\n 73:\t\t\t\t\t};\n 74:\t\n 75:\t\t\t\t\treset: reset@e200400c {\n 76:\t\t\t\t\t\tcompatible = \"microchip,lan966x-switch-reset\";\n 77:\t\t\t\t\t\treg = \u003c0xe200400c 0x4\u003e, \u003c0xe00c0000 0xa8\u003e;\n 78:\t\t\t\t\t\treg-names = \"gcb\",\"cpu\";\n 79:\t\t\t\t\t\t#reset-cells = \u003c1\u003e;\n 80:\t\t\t\t\t\tcpu-syscon = \u003c\u0026cpu_ctrl\u003e;\n 81:\t\t\t\t\t};\n 82:\t\n 83:\t\t\t\t\tgpio: pinctrl@e2004064 {\n 84:\t\t\t\t\t\tcompatible = \"microchip,lan966x-pinctrl\";\n 85:\t\t\t\t\t\treg = \u003c0xe2004064 0xb4\u003e,\n 86:\t\t\t\t\t\t \u003c0xe2010024 0x138\u003e;\n 87:\t\t\t\t\t\tresets = \u003c\u0026reset 0\u003e;\n 88:\t\t\t\t\t\treset-names = \"switch\";\n 89:\t\t\t\t\t\tgpio-controller;\n 90:\t\t\t\t\t\t#gpio-cells = \u003c2\u003e;\n 91:\t\t\t\t\t\tgpio-ranges = \u003c\u0026gpio 0 0 78\u003e;\n 92:\t\t\t\t\t\tinterrupt-parent = \u003c\u0026oic\u003e;\n 93:\t\t\t\t\t\tinterrupt-controller;\n 94:\t\t\t\t\t\tinterrupts = \u003c17 IRQ_TYPE_LEVEL_HIGH\u003e;\n 95:\t\t\t\t\t\t#interrupt-cells = \u003c2\u003e;\n 96:\t\n 97:\t\t\t\t\t\ttod_pins: tod_pins {\n 98:\t\t\t\t\t\t\tpins = \"GPIO_36\";\n 99:\t\t\t\t\t\t\tfunction = \"ptpsync_1\";\n 100:\t\t\t\t\t\t};\n"
} |
| 51/2 | 2026/07/13 19:34 | llm | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 205690 output: 44 thoughts: 65 Thoughts: Okay, let's see what's going on here. **Deconstructing the Device Tree for the LAN966x PCI Device** Alright, so `lan966x_pci.dtso` is the key file defining the device tree configuration for this PCI device. That's the starting point. Hmm, interesting. The file's defining `switch: switch@e0000000`. Good, good... let's keep going. I'll need to dig into the rest of the contents of the file to understand exactly what's going on with this switch definition. I'm keen to see the specifics. |
| 52/2 | 2026/07/13 19:35 | tool | read-file |
0mArgs:{
"File": "drivers/misc/lan966x_pci.dtso",
"FirstLine": 101,
"LineCount": 100
}Results: {
"Contents": " 101:\t\n 102:\t\t\t\t\t\tfc0_a_pins: fcb4-i2c-pins {\n 103:\t\t\t\t\t\t\t/* RXD, TXD */\n 104:\t\t\t\t\t\t\tpins = \"GPIO_9\", \"GPIO_10\";\n 105:\t\t\t\t\t\t\tfunction = \"fc0_a\";\n 106:\t\t\t\t\t\t};\n 107:\t\n 108:\t\t\t\t\t};\n 109:\t\n 110:\t\t\t\t\tserdes: serdes@e202c000 {\n 111:\t\t\t\t\t\tcompatible = \"microchip,lan966x-serdes\";\n 112:\t\t\t\t\t\treg = \u003c0xe202c000 0x9c\u003e,\n 113:\t\t\t\t\t\t \u003c0xe2004010 0x4\u003e;\n 114:\t\t\t\t\t\t#phy-cells = \u003c2\u003e;\n 115:\t\t\t\t\t};\n 116:\t\n 117:\t\t\t\t\tmdio1: mdio@e200413c {\n 118:\t\t\t\t\t\t#address-cells = \u003c1\u003e;\n 119:\t\t\t\t\t\t#size-cells = \u003c0\u003e;\n 120:\t\t\t\t\t\tcompatible = \"microchip,lan966x-miim\";\n 121:\t\t\t\t\t\treg = \u003c0xe200413c 0x24\u003e,\n 122:\t\t\t\t\t\t \u003c0xe2010020 0x4\u003e;\n 123:\t\n 124:\t\t\t\t\t\tresets = \u003c\u0026reset 0\u003e;\n 125:\t\t\t\t\t\treset-names = \"switch\";\n 126:\t\n 127:\t\t\t\t\t\tlan966x_phy0: ethernet-lan966x_phy@1 {\n 128:\t\t\t\t\t\t\treg = \u003c1\u003e;\n 129:\t\t\t\t\t\t};\n 130:\t\n 131:\t\t\t\t\t\tlan966x_phy1: ethernet-lan966x_phy@2 {\n 132:\t\t\t\t\t\t\treg = \u003c2\u003e;\n 133:\t\t\t\t\t\t};\n 134:\t\t\t\t\t};\n 135:\t\n 136:\t\t\t\t\tswitch: switch@e0000000 {\n 137:\t\t\t\t\t\tcompatible = \"microchip,lan966x-switch\";\n 138:\t\t\t\t\t\treg = \u003c0xe0000000 0x0100000\u003e,\n 139:\t\t\t\t\t\t \u003c0xe2000000 0x0800000\u003e;\n 140:\t\t\t\t\t\treg-names = \"cpu\", \"gcb\";\n 141:\t\n 142:\t\t\t\t\t\tinterrupt-parent = \u003c\u0026oic\u003e;\n 143:\t\t\t\t\t\tinterrupts = \u003c12 IRQ_TYPE_LEVEL_HIGH\u003e,\n 144:\t\t\t\t\t\t\t \u003c9 IRQ_TYPE_LEVEL_HIGH\u003e;\n 145:\t\t\t\t\t\tinterrupt-names = \"xtr\", \"ana\";\n 146:\t\n 147:\t\t\t\t\t\tresets = \u003c\u0026reset 0\u003e;\n 148:\t\t\t\t\t\treset-names = \"switch\";\n 149:\t\n 150:\t\t\t\t\t\tpinctrl-names = \"default\";\n 151:\t\t\t\t\t\tpinctrl-0 = \u003c\u0026tod_pins\u003e;\n 152:\t\n 153:\t\t\t\t\t\tethernet-ports {\n 154:\t\t\t\t\t\t\t#address-cells = \u003c1\u003e;\n 155:\t\t\t\t\t\t\t#size-cells = \u003c0\u003e;\n 156:\t\n 157:\t\t\t\t\t\t\tport0: port@0 {\n 158:\t\t\t\t\t\t\t\tphy-handle = \u003c\u0026lan966x_phy0\u003e;\n 159:\t\n 160:\t\t\t\t\t\t\t\treg = \u003c0\u003e;\n 161:\t\t\t\t\t\t\t\tphy-mode = \"gmii\";\n 162:\t\t\t\t\t\t\t\tphys = \u003c\u0026serdes 0 CU(0)\u003e;\n 163:\t\t\t\t\t\t\t};\n 164:\t\n 165:\t\t\t\t\t\t\tport1: port@1 {\n 166:\t\t\t\t\t\t\t\tphy-handle = \u003c\u0026lan966x_phy1\u003e;\n 167:\t\n 168:\t\t\t\t\t\t\t\treg = \u003c1\u003e;\n 169:\t\t\t\t\t\t\t\tphy-mode = \"gmii\";\n 170:\t\t\t\t\t\t\t\tphys = \u003c\u0026serdes 1 CU(1)\u003e;\n 171:\t\t\t\t\t\t\t};\n 172:\t\t\t\t\t\t};\n 173:\t\t\t\t\t};\n 174:\t\t\t\t};\n 175:\t\t\t};\n 176:\t\t};\n 177:\t};\n"
} |
| 53/2 | 2026/07/13 19:35 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 207054 output: 29 thoughts: 135 Thoughts: **Investigating the Device Tree for LAN96xx Switch Compatibility** Okay, so I'm looking at `lan966x_pci.dtso` and it's defining `switch@e0000000`. The important part is that the `compatible` string is set to `"microchip,lan966x-switch"`. Right. That's for the `lan966x` series, not the `lan9645x` which is what I'm interested in. Hold on a second, didn't I see the `lan9645x` driver using `"microchip,lan96455s-switch"` as its `compatible` string? I'm pretty sure that's correct. The question then becomes: where is the device tree overlay for a PCI based LAN9645X switch? Is there a `lan9645x_pci.dtso` file that defines this? If so, I need to find it. I should be able to track this down using the build system. Let me check either the `drivers/misc/Makefile` or just browse around the `drivers/misc/` directory for any clues. Hopefully, it's defined and I can quickly spot where the correct device tree overlay is located. |
| 54/2 | 2026/07/13 19:35 | tool | grepper |
0mError:no matches Args: {
"Expression": "lan9645",
"PathPrefix": "drivers/misc/"
}Results: {
"error": "no matches"
} |
| 55/2 | 2026/07/13 19:35 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 207516 output: 26 thoughts: 178 Thoughts: **Investigating the LAN9645x Driver Probe** Okay, so there's no obvious PCI overlay for the `lan9645x`. That's the first thing that jumps out. Now I'm trying to figure out how this driver is *supposed* to be probed. It's expecting `dev_get_regmap(lan9645x->dev->parent, resource_name)` to return valid regmaps, which is a pretty standard pattern. This implies, and this is key, that there *has* to be a parent device somewhere that's creating these regmaps using something like `devm_regmap_init` and attaching them to its own device structure. Without that parent, the `lan9645x` driver is dead in the water; it simply won't probe. Hold on, could this parent device be a Multiple Function Device (MFD) driver that's *already* in the kernel and I just missed it? It's easy to overlook these things. I need to be sure. I'm going to run a quick search through the entire kernel source tree, looking for instances of `devm_regmap_init` and also for devices that might be providing that `"gcb"` or `"chip_top"` resource. Those names are a good hint. That should give me a good idea of what could be going on. |
| 56/2 | 2026/07/13 19:35 | tool | grepper |
0mArgs:{
"Expression": "\"gcb\"",
"PathPrefix": "drivers/"
}Results: {
"Output": "drivers/misc/lan966x_pci.dtso=75=\t\t\t\treset: reset@e200400c {\n--\ndrivers/misc/lan966x_pci.dtso-77-\t\t\t\t\treg = \u003c0xe200400c 0x4\u003e, \u003c0xe00c0000 0xa8\u003e;\ndrivers/misc/lan966x_pci.dtso:78:\t\t\t\t\treg-names = \"gcb\",\"cpu\";\ndrivers/misc/lan966x_pci.dtso-79-\t\t\t\t\t#reset-cells = \u003c1\u003e;\n--\ndrivers/misc/lan966x_pci.dtso=136=\t\t\t\tswitch: switch@e0000000 {\n--\ndrivers/misc/lan966x_pci.dtso-139-\t\t\t\t\t \u003c0xe2000000 0x0800000\u003e;\ndrivers/misc/lan966x_pci.dtso:140:\t\t\t\t\treg-names = \"cpu\", \"gcb\";\ndrivers/misc/lan966x_pci.dtso-141-\n--\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\",\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-12-\t[TARGET_QS] = \"qs\",\n"
} |
| 57/2 | 2026/07/13 19:35 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 208463 output: 43 thoughts: 169 Thoughts: **Investigating the LAN966X Regmap Configuration** Okay, so I'm looking at this `lan966x_pci.dtso` file and I'm seeing `reg-names = "cpu", "gcb"`. Interesting. But then, I'm cross-referencing that with how the `lan9645x_main.c` file is set up, and I realize it's expecting `dev_get_regmap` to return a regmap with the name `"gcb"`. That's the key connection. Now, a red flag popped up. If the device's parent is a platform device, I know from experience that `dev_get_regmap` doesn't always work as expected, especially if the parent's regmap came from `syscon`. I need to confirm whether that's the case here. Is the parent device configured via a `syscon`? I highly doubt this is the case. The parent device could be created by `drivers/net/ethernet/microchip/lan966x/lan966x_main.c`. Therefore, I'm going to have to dive into that specific file to confirm. I should check how the parent device is created by `drivers/net/ethernet/microchip/lan966x/lan966x_main.c` and how the regmap is created for it. I bet there's my answer. |
| 58/2 | 2026/07/13 19:35 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}Results: {
"error": "no matches"
} |
| 59/2 | 2026/07/13 19:35 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 209008 output: 26 thoughts: 71 Thoughts: **Investigating the "gcb" Regmap** Okay, so I'm trying to figure out how this `"gcb"` regmap is initialized. The first thing that pops into my head is to check if `syscon_node_to_regmap` handles its creation directly with `devm_regmap_init`. Quick check... nope, that's not how it works. Okay, that's fine. Now, I'm thinking, does *any* driver in this project even use a regmap named `"gcb"`? I need to be sure before I start down the wrong path. Alright, the next logical step is a targeted search. I'll search the code for instances of `regmap_init` or, more likely, `devm_regmap_init` (since that's the preferred method), and specifically look for any occurrences where the regmap is initialized with the name `"gcb"`. This should quickly reveal how, and if, this regmap is actually being created. Let's see what that search turns up. |
| 60/2 | 2026/07/13 19:36 | tool | grepper |
0mArgs:{
"Expression": "regmap_init",
"PathPrefix": "drivers/"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 7792 lines.\nUse more precise expression if possible.\n\ndrivers/auxdisplay/max6959.c=116=static int max6959_i2c_probe(struct i2c_client *client)\n--\ndrivers/auxdisplay/max6959.c-125-\ndrivers/auxdisplay/max6959.c:126:\tpriv-\u003eregmap = devm_regmap_init_i2c(client, \u0026max6959_regmap_config);\ndrivers/auxdisplay/max6959.c-127-\tif (IS_ERR(priv-\u003eregmap))\n--\ndrivers/base/regmap/internal.h=324=struct regmap_ram_data {\n--\ndrivers/base/regmap/internal.h-335- */\ndrivers/base/regmap/internal.h:336:struct regmap *__regmap_init_ram(struct device *dev,\ndrivers/base/regmap/internal.h-337-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/internal.h-341-\ndrivers/base/regmap/internal.h:342:#define regmap_init_ram(dev, config, data)\t\t\t\t\t\\\ndrivers/base/regmap/internal.h:343:\t__regmap_lockdep_wrapper(__regmap_init_ram, #dev, dev, config, data)\ndrivers/base/regmap/internal.h-344-\ndrivers/base/regmap/internal.h:345:struct regmap *__regmap_init_raw_ram(struct device *dev,\ndrivers/base/regmap/internal.h-346-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/internal.h-350-\ndrivers/base/regmap/internal.h:351:#define regmap_init_raw_ram(dev, config, data)\t\t\t\t\\\ndrivers/base/regmap/internal.h:352:\t__regmap_lockdep_wrapper(__regmap_init_raw_ram, #dev, dev, config, data)\ndrivers/base/regmap/internal.h-353-\n--\ndrivers/base/regmap/regmap-ac97.c=64=static const struct regmap_bus ac97_regmap_bus = {\n--\ndrivers/base/regmap/regmap-ac97.c-68-\ndrivers/base/regmap/regmap-ac97.c:69:struct regmap *__regmap_init_ac97(struct snd_ac97 *ac97,\ndrivers/base/regmap/regmap-ac97.c-70-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-ac97.c-73-{\ndrivers/base/regmap/regmap-ac97.c:74:\treturn __regmap_init(\u0026ac97-\u003edev, \u0026ac97_regmap_bus, ac97, config,\ndrivers/base/regmap/regmap-ac97.c-75-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-ac97.c-76-}\ndrivers/base/regmap/regmap-ac97.c:77:EXPORT_SYMBOL_GPL(__regmap_init_ac97);\ndrivers/base/regmap/regmap-ac97.c-78-\ndrivers/base/regmap/regmap-ac97.c:79:struct regmap *__devm_regmap_init_ac97(struct snd_ac97 *ac97,\ndrivers/base/regmap/regmap-ac97.c-80-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-ac97.c-83-{\ndrivers/base/regmap/regmap-ac97.c:84:\treturn __devm_regmap_init(\u0026ac97-\u003edev, \u0026ac97_regmap_bus, ac97, config,\ndrivers/base/regmap/regmap-ac97.c-85-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-ac97.c-86-}\ndrivers/base/regmap/regmap-ac97.c:87:EXPORT_SYMBOL_GPL(__devm_regmap_init_ac97);\ndrivers/base/regmap/regmap-ac97.c-88-\n--\ndrivers/base/regmap/regmap-fsi.c=152=static const struct regmap_bus *regmap_get_fsi_bus(struct fsi_device *fsi_dev,\n--\ndrivers/base/regmap/regmap-fsi.c-205-\ndrivers/base/regmap/regmap-fsi.c:206:struct regmap *__regmap_init_fsi(struct fsi_device *fsi_dev, const struct regmap_config *config,\ndrivers/base/regmap/regmap-fsi.c-207-\t\t\t\t struct lock_class_key *lock_key, const char *lock_name)\n--\ndrivers/base/regmap/regmap-fsi.c-213-\ndrivers/base/regmap/regmap-fsi.c:214:\treturn __regmap_init(\u0026fsi_dev-\u003edev, bus, fsi_dev-\u003eslave, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-fsi.c-215-}\ndrivers/base/regmap/regmap-fsi.c:216:EXPORT_SYMBOL_GPL(__regmap_init_fsi);\ndrivers/base/regmap/regmap-fsi.c-217-\ndrivers/base/regmap/regmap-fsi.c:218:struct regmap *__devm_regmap_init_fsi(struct fsi_device *fsi_dev,\ndrivers/base/regmap/regmap-fsi.c-219-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-fsi.c-226-\ndrivers/base/regmap/regmap-fsi.c:227:\treturn __devm_regmap_init(\u0026fsi_dev-\u003edev, bus, fsi_dev-\u003eslave, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-fsi.c-228-}\ndrivers/base/regmap/regmap-fsi.c:229:EXPORT_SYMBOL_GPL(__devm_regmap_init_fsi);\ndrivers/base/regmap/regmap-fsi.c-230-\n--\ndrivers/base/regmap/regmap-i2c.c=350=static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,\n--\ndrivers/base/regmap/regmap-i2c.c-418-\ndrivers/base/regmap/regmap-i2c.c:419:struct regmap *__regmap_init_i2c(struct i2c_client *i2c,\ndrivers/base/regmap/regmap-i2c.c-420-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-i2c.c-428-\ndrivers/base/regmap/regmap-i2c.c:429:\treturn __regmap_init(\u0026i2c-\u003edev, bus, \u0026i2c-\u003edev, config,\ndrivers/base/regmap/regmap-i2c.c-430-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-i2c.c-431-}\ndrivers/base/regmap/regmap-i2c.c:432:EXPORT_SYMBOL_GPL(__regmap_init_i2c);\ndrivers/base/regmap/regmap-i2c.c-433-\ndrivers/base/regmap/regmap-i2c.c:434:struct regmap *__devm_regmap_init_i2c(struct i2c_client *i2c,\ndrivers/base/regmap/regmap-i2c.c-435-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-i2c.c-443-\ndrivers/base/regmap/regmap-i2c.c:444:\treturn __devm_regmap_init(\u0026i2c-\u003edev, bus, \u0026i2c-\u003edev, config,\ndrivers/base/regmap/regmap-i2c.c-445-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-i2c.c-446-}\ndrivers/base/regmap/regmap-i2c.c:447:EXPORT_SYMBOL_GPL(__devm_regmap_init_i2c);\ndrivers/base/regmap/regmap-i2c.c-448-\n--\ndrivers/base/regmap/regmap-i3c.c=44=static const struct regmap_bus regmap_i3c = {\n--\ndrivers/base/regmap/regmap-i3c.c-48-\ndrivers/base/regmap/regmap-i3c.c:49:struct regmap *__regmap_init_i3c(struct i3c_device *i3c,\ndrivers/base/regmap/regmap-i3c.c-50-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-i3c.c-53-{\ndrivers/base/regmap/regmap-i3c.c:54:\treturn __regmap_init(\u0026i3c-\u003edev, \u0026regmap_i3c, \u0026i3c-\u003edev, config,\ndrivers/base/regmap/regmap-i3c.c-55-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-i3c.c-56-}\ndrivers/base/regmap/regmap-i3c.c:57:EXPORT_SYMBOL_GPL(__regmap_init_i3c);\ndrivers/base/regmap/regmap-i3c.c-58-\ndrivers/base/regmap/regmap-i3c.c:59:struct regmap *__devm_regmap_init_i3c(struct i3c_device *i3c,\ndrivers/base/regmap/regmap-i3c.c-60-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-i3c.c-63-{\ndrivers/base/regmap/regmap-i3c.c:64:\treturn __devm_regmap_init(\u0026i3c-\u003edev, \u0026regmap_i3c, \u0026i3c-\u003edev, config,\ndrivers/base/regmap/regmap-i3c.c-65-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-i3c.c-66-}\ndrivers/base/regmap/regmap-i3c.c:67:EXPORT_SYMBOL_GPL(__devm_regmap_init_i3c);\ndrivers/base/regmap/regmap-i3c.c-68-\n--\ndrivers/base/regmap/regmap-kunit.c=183=static struct regmap *gen_regmap(struct kunit *test,\n--\ndrivers/base/regmap/regmap-kunit.c-234-\ndrivers/base/regmap/regmap-kunit.c:235:\tret = regmap_init_ram(priv-\u003edev, config, *data);\ndrivers/base/regmap/regmap-kunit.c-236-\tif (IS_ERR(ret))\n--\ndrivers/base/regmap/regmap-kunit.c=1738=static struct regmap *gen_raw_regmap(struct kunit *test,\n--\ndrivers/base/regmap/regmap-kunit.c-1797-\ndrivers/base/regmap/regmap-kunit.c:1798:\tret = regmap_init_raw_ram(priv-\u003edev, config, *data);\ndrivers/base/regmap/regmap-kunit.c-1799-\tif (IS_ERR(ret))\n--\ndrivers/base/regmap/regmap-mdio.c=80=static const struct regmap_bus regmap_mdio_c45_bus = {\n--\ndrivers/base/regmap/regmap-mdio.c-84-\ndrivers/base/regmap/regmap-mdio.c:85:struct regmap *__regmap_init_mdio(struct mdio_device *mdio_dev,\ndrivers/base/regmap/regmap-mdio.c-86-\tconst struct regmap_config *config, struct lock_class_key *lock_key,\n--\ndrivers/base/regmap/regmap-mdio.c-97-\ndrivers/base/regmap/regmap-mdio.c:98:\treturn __regmap_init(\u0026mdio_dev-\u003edev, bus, mdio_dev, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-mdio.c-99-}\ndrivers/base/regmap/regmap-mdio.c:100:EXPORT_SYMBOL_GPL(__regmap_init_mdio);\ndrivers/base/regmap/regmap-mdio.c-101-\ndrivers/base/regmap/regmap-mdio.c:102:struct regmap *__devm_regmap_init_mdio(struct mdio_device *mdio_dev,\ndrivers/base/regmap/regmap-mdio.c-103-\tconst struct regmap_config *config, struct lock_class_key *lock_key,\n--\ndrivers/base/regmap/regmap-mdio.c-114-\ndrivers/base/regmap/regmap-mdio.c:115:\treturn __devm_regmap_init(\u0026mdio_dev-\u003edev, bus, mdio_dev, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-mdio.c-116-}\ndrivers/base/regmap/regmap-mdio.c:117:EXPORT_SYMBOL_GPL(__devm_regmap_init_mdio);\ndrivers/base/regmap/regmap-mdio.c-118-\n--\ndrivers/base/regmap/regmap-mmio.c=407=static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,\n--\ndrivers/base/regmap/regmap-mmio.c-554-\ndrivers/base/regmap/regmap-mmio.c:555:struct regmap *__regmap_init_mmio_clk(struct device *dev, const char *clk_id,\ndrivers/base/regmap/regmap-mmio.c-556-\t\t\t\t void __iomem *regs,\n--\ndrivers/base/regmap/regmap-mmio.c-566-\ndrivers/base/regmap/regmap-mmio.c:567:\treturn __regmap_init(dev, \u0026regmap_mmio, ctx, config,\ndrivers/base/regmap/regmap-mmio.c-568-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-mmio.c-569-}\ndrivers/base/regmap/regmap-mmio.c:570:EXPORT_SYMBOL_GPL(__regmap_init_mmio_clk);\ndrivers/base/regmap/regmap-mmio.c-571-\ndrivers/base/regmap/regmap-mmio.c:572:struct regmap *__devm_regmap_init_mmio_clk(struct device *dev,\ndrivers/base/regmap/regmap-mmio.c-573-\t\t\t\t\t const char *clk_id,\n--\ndrivers/base/regmap/regmap-mmio.c-584-\ndrivers/base/regmap/regmap-mmio.c:585:\treturn __devm_regmap_init(dev, \u0026regmap_mmio, ctx, config,\ndrivers/base/regmap/regmap-mmio.c-586-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-mmio.c-587-}\ndrivers/base/regmap/regmap-mmio.c:588:EXPORT_SYMBOL_GPL(__devm_regmap_init_mmio_clk);\ndrivers/base/regmap/regmap-mmio.c-589-\n--\ndrivers/base/regmap/regmap-ram.c=49=static const struct regmap_bus regmap_ram = {\n--\ndrivers/base/regmap/regmap-ram.c-55-\ndrivers/base/regmap/regmap-ram.c:56:struct regmap *__regmap_init_ram(struct device *dev,\ndrivers/base/regmap/regmap-ram.c-57-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-ram.c-78-\ndrivers/base/regmap/regmap-ram.c:79:\tmap = __regmap_init(dev, \u0026regmap_ram, data, config,\ndrivers/base/regmap/regmap-ram.c-80-\t\t\t lock_key, lock_name);\n--\ndrivers/base/regmap/regmap-ram.c-87-}\ndrivers/base/regmap/regmap-ram.c:88:EXPORT_SYMBOL_GPL(__regmap_init_ram);\ndrivers/base/regmap/regmap-ram.c-89-\n--\ndrivers/base/regmap/regmap-raw-ram.c=102=static const struct regmap_bus regmap_raw_ram = {\n--\ndrivers/base/regmap/regmap-raw-ram.c-109-\ndrivers/base/regmap/regmap-raw-ram.c:110:struct regmap *__regmap_init_raw_ram(struct device *dev,\ndrivers/base/regmap/regmap-raw-ram.c-111-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-raw-ram.c-135-\ndrivers/base/regmap/regmap-raw-ram.c:136:\tmap = __regmap_init(dev, \u0026regmap_raw_ram, data, config,\ndrivers/base/regmap/regmap-raw-ram.c-137-\t\t\t lock_key, lock_name);\n--\ndrivers/base/regmap/regmap-raw-ram.c-140-}\ndrivers/base/regmap/regmap-raw-ram.c:141:EXPORT_SYMBOL_GPL(__regmap_init_raw_ram);\ndrivers/base/regmap/regmap-raw-ram.c-142-\n--\ndrivers/base/regmap/regmap-sccb.c=88=static const struct regmap_bus *regmap_get_sccb_bus(struct i2c_client *i2c,\n--\ndrivers/base/regmap/regmap-sccb.c-97-\ndrivers/base/regmap/regmap-sccb.c:98:struct regmap *__regmap_init_sccb(struct i2c_client *i2c,\ndrivers/base/regmap/regmap-sccb.c-99-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-sccb.c-107-\ndrivers/base/regmap/regmap-sccb.c:108:\treturn __regmap_init(\u0026i2c-\u003edev, bus, \u0026i2c-\u003edev, config,\ndrivers/base/regmap/regmap-sccb.c-109-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-sccb.c-110-}\ndrivers/base/regmap/regmap-sccb.c:111:EXPORT_SYMBOL_GPL(__regmap_init_sccb);\ndrivers/base/regmap/regmap-sccb.c-112-\ndrivers/base/regmap/regmap-sccb.c:113:struct regmap *__devm_regmap_init_sccb(struct i2c_client *i2c,\ndrivers/base/regmap/regmap-sccb.c-114-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-sccb.c-122-\ndrivers/base/regmap/regmap-sccb.c:123:\treturn __devm_regmap_init(\u0026i2c-\u003edev, bus, \u0026i2c-\u003edev, config,\ndrivers/base/regmap/regmap-sccb.c-124-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-sccb.c-125-}\ndrivers/base/regmap/regmap-sccb.c:126:EXPORT_SYMBOL_GPL(__devm_regmap_init_sccb);\ndrivers/base/regmap/regmap-sccb.c-127-\n--\ndrivers/base/regmap/regmap-sdw-mbq.c=210=regmap_sdw_mbq_gen_context(struct device *dev,\n--\ndrivers/base/regmap/regmap-sdw-mbq.c-232-\ndrivers/base/regmap/regmap-sdw-mbq.c:233:struct regmap *__regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,\ndrivers/base/regmap/regmap-sdw-mbq.c-234-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-sdw-mbq.c-249-\ndrivers/base/regmap/regmap-sdw-mbq.c:250:\treturn __regmap_init(dev, \u0026regmap_sdw_mbq, ctx,\ndrivers/base/regmap/regmap-sdw-mbq.c-251-\t\t\t config, lock_key, lock_name);\ndrivers/base/regmap/regmap-sdw-mbq.c-252-}\ndrivers/base/regmap/regmap-sdw-mbq.c:253:EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq);\ndrivers/base/regmap/regmap-sdw-mbq.c-254-\ndrivers/base/regmap/regmap-sdw-mbq.c:255:struct regmap *__devm_regmap_init_sdw_mbq(struct device *dev, struct sdw_slave *sdw,\ndrivers/base/regmap/regmap-sdw-mbq.c-256-\t\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-sdw-mbq.c-271-\ndrivers/base/regmap/regmap-sdw-mbq.c:272:\treturn __devm_regmap_init(dev, \u0026regmap_sdw_mbq, ctx,\ndrivers/base/regmap/regmap-sdw-mbq.c-273-\t\t\t\t config, lock_key, lock_name);\ndrivers/base/regmap/regmap-sdw-mbq.c-274-}\ndrivers/base/regmap/regmap-sdw-mbq.c:275:EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);\ndrivers/base/regmap/regmap-sdw-mbq.c-276-\n--\ndrivers/base/regmap/regmap-sdw.c=53=static int regmap_sdw_config_check(const struct regmap_config *config)\n--\ndrivers/base/regmap/regmap-sdw.c-68-\ndrivers/base/regmap/regmap-sdw.c:69:struct regmap *__regmap_init_sdw(struct sdw_slave *sdw,\ndrivers/base/regmap/regmap-sdw.c-70-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-sdw.c-79-\ndrivers/base/regmap/regmap-sdw.c:80:\treturn __regmap_init(\u0026sdw-\u003edev, \u0026regmap_sdw,\ndrivers/base/regmap/regmap-sdw.c-81-\t\t\t\u0026sdw-\u003edev, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-sdw.c-82-}\ndrivers/base/regmap/regmap-sdw.c:83:EXPORT_SYMBOL_GPL(__regmap_init_sdw);\ndrivers/base/regmap/regmap-sdw.c-84-\ndrivers/base/regmap/regmap-sdw.c:85:struct regmap *__devm_regmap_init_sdw(struct sdw_slave *sdw,\ndrivers/base/regmap/regmap-sdw.c-86-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-sdw.c-95-\ndrivers/base/regmap/regmap-sdw.c:96:\treturn __devm_regmap_init(\u0026sdw-\u003edev, \u0026regmap_sdw,\ndrivers/base/regmap/regmap-sdw.c-97-\t\t\t\u0026sdw-\u003edev, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-sdw.c-98-}\ndrivers/base/regmap/regmap-sdw.c:99:EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw);\ndrivers/base/regmap/regmap-sdw.c-100-\n--\ndrivers/base/regmap/regmap-slimbus.c=32=static const struct regmap_bus *regmap_get_slimbus(struct slim_device *slim,\n--\ndrivers/base/regmap/regmap-slimbus.c-40-\ndrivers/base/regmap/regmap-slimbus.c:41:struct regmap *__regmap_init_slimbus(struct slim_device *slimbus,\ndrivers/base/regmap/regmap-slimbus.c-42-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-slimbus.c-50-\ndrivers/base/regmap/regmap-slimbus.c:51:\treturn __regmap_init(\u0026slimbus-\u003edev, bus, slimbus, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-slimbus.c-52-}\ndrivers/base/regmap/regmap-slimbus.c:53:EXPORT_SYMBOL_GPL(__regmap_init_slimbus);\ndrivers/base/regmap/regmap-slimbus.c-54-\ndrivers/base/regmap/regmap-slimbus.c:55:struct regmap *__devm_regmap_init_slimbus(struct slim_device *slimbus,\ndrivers/base/regmap/regmap-slimbus.c-56-\t\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-slimbus.c-64-\ndrivers/base/regmap/regmap-slimbus.c:65:\treturn __devm_regmap_init(\u0026slimbus-\u003edev, bus, slimbus, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-slimbus.c-66-}\ndrivers/base/regmap/regmap-slimbus.c:67:EXPORT_SYMBOL_GPL(__devm_regmap_init_slimbus);\ndrivers/base/regmap/regmap-slimbus.c-68-\n--\ndrivers/base/regmap/regmap-spi-avmm.c=656=static const struct regmap_bus regmap_spi_avmm_bus = {\n--\ndrivers/base/regmap/regmap-spi-avmm.c-666-\ndrivers/base/regmap/regmap-spi-avmm.c:667:struct regmap *__regmap_init_spi_avmm(struct spi_device *spi,\ndrivers/base/regmap/regmap-spi-avmm.c-668-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spi-avmm.c-678-\ndrivers/base/regmap/regmap-spi-avmm.c:679:\tmap = __regmap_init(\u0026spi-\u003edev, \u0026regmap_spi_avmm_bus,\ndrivers/base/regmap/regmap-spi-avmm.c-680-\t\t\t bridge, config, lock_key, lock_name);\n--\ndrivers/base/regmap/regmap-spi-avmm.c-687-}\ndrivers/base/regmap/regmap-spi-avmm.c:688:EXPORT_SYMBOL_GPL(__regmap_init_spi_avmm);\ndrivers/base/regmap/regmap-spi-avmm.c-689-\ndrivers/base/regmap/regmap-spi-avmm.c:690:struct regmap *__devm_regmap_init_spi_avmm(struct spi_device *spi,\ndrivers/base/regmap/regmap-spi-avmm.c-691-\t\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spi-avmm.c-701-\ndrivers/base/regmap/regmap-spi-avmm.c:702:\tmap = __devm_regmap_init(\u0026spi-\u003edev, \u0026regmap_spi_avmm_bus,\ndrivers/base/regmap/regmap-spi-avmm.c-703-\t\t\t\t bridge, config, lock_key, lock_name);\n--\ndrivers/base/regmap/regmap-spi-avmm.c-710-}\ndrivers/base/regmap/regmap-spi-avmm.c:711:EXPORT_SYMBOL_GPL(__devm_regmap_init_spi_avmm);\ndrivers/base/regmap/regmap-spi-avmm.c-712-\n--\ndrivers/base/regmap/regmap-spi.c=112=static const struct regmap_bus *regmap_get_spi_bus(struct spi_device *spi,\n--\ndrivers/base/regmap/regmap-spi.c-138-\ndrivers/base/regmap/regmap-spi.c:139:struct regmap *__regmap_init_spi(struct spi_device *spi,\ndrivers/base/regmap/regmap-spi.c-140-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spi.c-148-\ndrivers/base/regmap/regmap-spi.c:149:\treturn __regmap_init(\u0026spi-\u003edev, bus, \u0026spi-\u003edev, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-spi.c-150-}\ndrivers/base/regmap/regmap-spi.c:151:EXPORT_SYMBOL_GPL(__regmap_init_spi);\ndrivers/base/regmap/regmap-spi.c-152-\ndrivers/base/regmap/regmap-spi.c:153:struct regmap *__devm_regmap_init_spi(struct spi_device *spi,\ndrivers/base/regmap/regmap-spi.c-154-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spi.c-162-\ndrivers/base/regmap/regmap-spi.c:163:\treturn __devm_regmap_init(\u0026spi-\u003edev, bus, \u0026spi-\u003edev, config, lock_key, lock_name);\ndrivers/base/regmap/regmap-spi.c-164-}\ndrivers/base/regmap/regmap-spi.c:165:EXPORT_SYMBOL_GPL(__devm_regmap_init_spi);\ndrivers/base/regmap/regmap-spi.c-166-\n--\ndrivers/base/regmap/regmap-spmi.c=77=static const struct regmap_bus regmap_spmi_base = {\n--\ndrivers/base/regmap/regmap-spmi.c-84-\ndrivers/base/regmap/regmap-spmi.c:85:struct regmap *__regmap_init_spmi_base(struct spmi_device *sdev,\ndrivers/base/regmap/regmap-spmi.c-86-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spmi.c-89-{\ndrivers/base/regmap/regmap-spmi.c:90:\treturn __regmap_init(\u0026sdev-\u003edev, \u0026regmap_spmi_base, sdev, config,\ndrivers/base/regmap/regmap-spmi.c-91-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-spmi.c-92-}\ndrivers/base/regmap/regmap-spmi.c:93:EXPORT_SYMBOL_GPL(__regmap_init_spmi_base);\ndrivers/base/regmap/regmap-spmi.c-94-\ndrivers/base/regmap/regmap-spmi.c:95:struct regmap *__devm_regmap_init_spmi_base(struct spmi_device *sdev,\ndrivers/base/regmap/regmap-spmi.c-96-\t\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spmi.c-99-{\ndrivers/base/regmap/regmap-spmi.c:100:\treturn __devm_regmap_init(\u0026sdev-\u003edev, \u0026regmap_spmi_base, sdev, config,\ndrivers/base/regmap/regmap-spmi.c-101-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-spmi.c-102-}\ndrivers/base/regmap/regmap-spmi.c:103:EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_base);\ndrivers/base/regmap/regmap-spmi.c-104-\n--\ndrivers/base/regmap/regmap-spmi.c=197=static const struct regmap_bus regmap_spmi_ext = {\n--\ndrivers/base/regmap/regmap-spmi.c-204-\ndrivers/base/regmap/regmap-spmi.c:205:struct regmap *__regmap_init_spmi_ext(struct spmi_device *sdev,\ndrivers/base/regmap/regmap-spmi.c-206-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spmi.c-209-{\ndrivers/base/regmap/regmap-spmi.c:210:\treturn __regmap_init(\u0026sdev-\u003edev, \u0026regmap_spmi_ext, sdev, config,\ndrivers/base/regmap/regmap-spmi.c-211-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-spmi.c-212-}\ndrivers/base/regmap/regmap-spmi.c:213:EXPORT_SYMBOL_GPL(__regmap_init_spmi_ext);\ndrivers/base/regmap/regmap-spmi.c-214-\ndrivers/base/regmap/regmap-spmi.c:215:struct regmap *__devm_regmap_init_spmi_ext(struct spmi_device *sdev,\ndrivers/base/regmap/regmap-spmi.c-216-\t\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-spmi.c-219-{\ndrivers/base/regmap/regmap-spmi.c:220:\treturn __devm_regmap_init(\u0026sdev-\u003edev, \u0026regmap_spmi_ext, sdev, config,\ndrivers/base/regmap/regmap-spmi.c-221-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-spmi.c-222-}\ndrivers/base/regmap/regmap-spmi.c:223:EXPORT_SYMBOL_GPL(__devm_regmap_init_spmi_ext);\ndrivers/base/regmap/regmap-spmi.c-224-\n--\ndrivers/base/regmap/regmap-w1.c=190=static const struct regmap_bus *regmap_get_w1_bus(struct device *w1_dev,\n--\ndrivers/base/regmap/regmap-w1.c-204-\ndrivers/base/regmap/regmap-w1.c:205:struct regmap *__regmap_init_w1(struct device *w1_dev,\ndrivers/base/regmap/regmap-w1.c-206-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-w1.c-215-\ndrivers/base/regmap/regmap-w1.c:216:\treturn __regmap_init(w1_dev, bus, w1_dev, config,\ndrivers/base/regmap/regmap-w1.c-217-\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-w1.c-218-}\ndrivers/base/regmap/regmap-w1.c:219:EXPORT_SYMBOL_GPL(__regmap_init_w1);\ndrivers/base/regmap/regmap-w1.c-220-\ndrivers/base/regmap/regmap-w1.c:221:struct regmap *__devm_regmap_init_w1(struct device *w1_dev,\ndrivers/base/regmap/regmap-w1.c-222-\t\t\t\t const struct regmap_config *config,\n--\ndrivers/base/regmap/regmap-w1.c-231-\ndrivers/base/regmap/regmap-w1.c:232:\treturn __devm_regmap_init(w1_dev, bus, w1_dev, config,\ndrivers/base/regmap/regmap-w1.c-233-\t\t\t\t lock_key, lock_name);\ndrivers/base/regmap/regmap-w1.c-234-}\ndrivers/base/regmap/regmap-w1.c:235:EXPORT_SYMBOL_GPL(__devm_regmap_init_w1);\ndrivers/base/regmap/regmap-w1.c-236-\n--\ndrivers/base/regmap/regmap.c=675=EXPORT_SYMBOL_GPL(regmap_get_val_endian);\ndrivers/base/regmap/regmap.c-676-\ndrivers/base/regmap/regmap.c:677:struct regmap *__regmap_init(struct device *dev,\ndrivers/base/regmap/regmap.c-678-\t\t\t const struct regmap_bus *bus,\n--\ndrivers/base/regmap/regmap.c-1182-}\ndrivers/base/regmap/regmap.c:1183:EXPORT_SYMBOL_GPL(__regmap_init);\ndrivers/base/regmap/regmap.c-1184-\ndrivers/base/regmap/regmap.c=1185=static void devm_regmap_release(void *regmap)\n--\ndrivers/base/regmap/regmap.c-1189-\ndrivers/base/regmap/regmap.c:1190:struct regmap *__devm_regmap_init(struct device *dev,\ndrivers/base/regmap/regmap.c-1191-\t\t\t\t const struct regmap_bus *bus,\n--\ndrivers/base/regmap/regmap.c-1199-\ndrivers/base/regmap/regmap.c:1200:\tregmap = __regmap_init(dev, bus, bus_context, config,\ndrivers/base/regmap/regmap.c-1201-\t\t\t lock_key, lock_name);\n--\ndrivers/base/regmap/regmap.c-1210-}\ndrivers/base/regmap/regmap.c:1211:EXPORT_SYMBOL_GPL(__devm_regmap_init);\ndrivers/base/regmap/regmap.c-1212-\n--\ndrivers/base/regmap/regmap.c=3543=EXPORT_SYMBOL_GPL(regmap_parse_val);\ndrivers/base/regmap/regmap.c-3544-\ndrivers/base/regmap/regmap.c:3545:static int __init regmap_initcall(void)\ndrivers/base/regmap/regmap.c-3546-{\n--\ndrivers/base/regmap/regmap.c-3550-}\ndrivers/base/regmap/regmap.c:3551:postcore_initcall(regmap_initcall);\n--\ndrivers/bluetooth/btintel.c=881=static const struct regmap_config regmap_ibt_cfg = {\n--\ndrivers/bluetooth/btintel.c-886-\ndrivers/bluetooth/btintel.c:887:struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,\ndrivers/bluetooth/btintel.c-888-\t\t\t\t u16 opcode_write)\n--\ndrivers/bluetooth/btintel.c-902-\ndrivers/bluetooth/btintel.c:903:\treturn regmap_init(\u0026hdev-\u003edev, \u0026regmap_ibt, ctx, \u0026regmap_ibt_cfg);\ndrivers/bluetooth/btintel.c-904-}\ndrivers/bluetooth/btintel.c:905:EXPORT_SYMBOL_GPL(btintel_regmap_init);\ndrivers/bluetooth/btintel.c-906-\n--\ndrivers/bluetooth/btintel.h=271=int btintel_read_version(struct hci_dev *hdev, struct intel_version *ver);\ndrivers/bluetooth/btintel.h:272:struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read,\ndrivers/bluetooth/btintel.h-273-\t\t\t\t u16 opcode_write);\n--\ndrivers/bluetooth/btintel.h=341=static inline int btintel_read_version(struct hci_dev *hdev,\n--\ndrivers/bluetooth/btintel.h-346-\ndrivers/bluetooth/btintel.h:347:static inline struct regmap *btintel_regmap_init(struct hci_dev *hdev,\ndrivers/bluetooth/btintel.h-348-\t\t\t\t\t\t u16 opcode_read,\n--\ndrivers/bus/sunxi-rsb.c=469=static struct sunxi_rsb_ctx *regmap_sunxi_rsb_init_ctx(struct sunxi_rsb_device *rdev,\n--\ndrivers/bus/sunxi-rsb.c-492-\ndrivers/bus/sunxi-rsb.c:493:struct regmap *__devm_regmap_init_sunxi_rsb(struct sunxi_rsb_device *rdev,\ndrivers/bus/sunxi-rsb.c-494-\t\t\t\t\t const struct regmap_config *config,\n--\ndrivers/bus/sunxi-rsb.c-502-\ndrivers/bus/sunxi-rsb.c:503:\treturn __devm_regmap_init(\u0026rdev-\u003edev, \u0026regmap_sunxi_rsb, ctx, config,\ndrivers/bus/sunxi-rsb.c-504-\t\t\t\t lock_key, lock_name);\ndrivers/bus/sunxi-rsb.c-505-}\ndrivers/bus/sunxi-rsb.c:506:EXPORT_SYMBOL_GPL(__devm_regmap_init_sunxi_rsb);\ndrivers/bus/sunxi-rsb.c-507-\n--\ndrivers/bus/vexpress-config.c=60=struct vexpress_config_bridge_ops {\ndrivers/bus/vexpress-config.c:61:\tstruct regmap * (*regmap_init)(struct device *dev, void *context);\ndrivers/bus/vexpress-config.c-62-\tvoid (*regmap_exit)(struct regmap *regmap, void *context);\n--\ndrivers/bus/vexpress-config.c=122=static void vexpress_config_devres_release(struct device *dev, void *res)\n--\ndrivers/bus/vexpress-config.c-129-\ndrivers/bus/vexpress-config.c:130:struct regmap *devm_regmap_init_vexpress_config(struct device *dev)\ndrivers/bus/vexpress-config.c-131-{\n--\ndrivers/bus/vexpress-config.c-144-\ndrivers/bus/vexpress-config.c:145:\tregmap = (bridge-\u003eops-\u003eregmap_init)(dev, bridge-\u003econtext);\ndrivers/bus/vexpress-config.c-146-\tif (IS_ERR(regmap)) {\n--\ndrivers/bus/vexpress-config.c-155-}\ndrivers/bus/vexpress-config.c:156:EXPORT_SYMBOL_GPL(devm_regmap_init_vexpress_config);\ndrivers/bus/vexpress-config.c-157-\n--\ndrivers/bus/vexpress-config.c=235=static struct regmap_config vexpress_syscfg_regmap_config = {\n--\ndrivers/bus/vexpress-config.c-246-\ndrivers/bus/vexpress-config.c:247:static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,\ndrivers/bus/vexpress-config.c-248-\t\tvoid *context)\n--\ndrivers/bus/vexpress-config.c-312-\ndrivers/bus/vexpress-config.c:313:\tfunc-\u003eregmap = regmap_init(dev, NULL, func,\ndrivers/bus/vexpress-config.c-314-\t\t\t\u0026vexpress_syscfg_regmap_config);\n--\ndrivers/bus/vexpress-config.c=344=static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = {\ndrivers/bus/vexpress-config.c:345:\t.regmap_init = vexpress_syscfg_regmap_init,\ndrivers/bus/vexpress-config.c-346-\t.regmap_exit = vexpress_syscfg_regmap_exit,\n--\ndrivers/clk/actions/owl-common.c=23=static void owl_clk_set_regmap(const struct owl_clk_desc *desc,\n--\ndrivers/clk/actions/owl-common.c-37-\ndrivers/clk/actions/owl-common.c:38:int owl_clk_regmap_init(struct platform_device *pdev,\ndrivers/clk/actions/owl-common.c-39-\t\t\tstruct owl_clk_desc *desc)\n--\ndrivers/clk/actions/owl-common.c-47-\ndrivers/clk/actions/owl-common.c:48:\tregmap = devm_regmap_init_mmio(\u0026pdev-\u003edev, base, \u0026owl_regmap_config);\ndrivers/clk/actions/owl-common.c-49-\tif (IS_ERR(regmap)) {\n--\ndrivers/clk/actions/owl-common.h=34=static inline struct owl_clk_common *\n--\ndrivers/clk/actions/owl-common.h-39-\ndrivers/clk/actions/owl-common.h:40:int owl_clk_regmap_init(struct platform_device *pdev,\ndrivers/clk/actions/owl-common.h-41-\t\t\tstruct owl_clk_desc *desc);\n\n"
} |
| 61/2 | 2026/07/13 19:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 221539 output: 43 thoughts: 140 Thoughts: **Investigating the Device Tree and Regmap Usage** Okay, so I'm looking at this `lan966x_pci.dtso` file and I see something that's piquing my interest: `reg-names = "gcb","cpu"`. Then I jump over to `lan9645x_main.c` and I find that `[TARGET_GCB] = "gcb"`. This looks like a match for what I just saw in the `.dtso` file. Now, the `lan9645x_main.c` code is using `dev_get_regmap` function, specifically with the `resource_name` derived from `"gcb"`. The intriguing point for me is, If the `lan966x_pci` device is the *parent* of the device in `lan9645x_main.c`, then I need to consider if `lan966x_pci` is responsible for actually creating those regmaps. I better go back and double-check the `drivers/misc/lan966x_pci.c` source file to make sure I'm not missing anything crucial about the regmap initialization within that driver. |
| 62/2 | 2026/07/13 19:36 | tool | read-file |
0mArgs:{
"File": "drivers/misc/lan966x_pci.c",
"FirstLine": 100,
"LineCount": 100
}Results: {
"Contents": " 100:\t\tirq_dispose_mapping(irq_find_mapping(intr_ctrl-\u003eirq_domain, 0));\n 101:\t\tirq_domain_remove(intr_ctrl-\u003eirq_domain);\n 102:\t\tkfree(intr_ctrl);\n 103:\t}\n 104:\t\n 105:\tstatic void devm_pci_dev_remove_intr_ctrl(void *intr_ctrl)\n 106:\t{\n 107:\t\tpci_dev_remove_intr_ctrl(intr_ctrl);\n 108:\t}\n 109:\t\n 110:\tstatic int devm_pci_dev_create_intr_ctrl(struct pci_dev *pdev)\n 111:\t{\n 112:\t\tstruct pci_dev_intr_ctrl *intr_ctrl;\n 113:\t\n 114:\t\tintr_ctrl = pci_dev_create_intr_ctrl(pdev);\n 115:\t\tif (IS_ERR(intr_ctrl))\n 116:\t\t\treturn PTR_ERR(intr_ctrl);\n 117:\t\n 118:\t\treturn devm_add_action_or_reset(\u0026pdev-\u003edev, devm_pci_dev_remove_intr_ctrl, intr_ctrl);\n 119:\t}\n 120:\t\n 121:\tstruct lan966x_pci {\n 122:\t\tstruct device *dev;\n 123:\t\tint ovcs_id;\n 124:\t};\n 125:\t\n 126:\tstatic int lan966x_pci_load_overlay(struct lan966x_pci *data)\n 127:\t{\n 128:\t\tu32 dtbo_size = __dtbo_lan966x_pci_end - __dtbo_lan966x_pci_begin;\n 129:\t\tvoid *dtbo_start = __dtbo_lan966x_pci_begin;\n 130:\t\n 131:\t\treturn of_overlay_fdt_apply(dtbo_start, dtbo_size, \u0026data-\u003eovcs_id, dev_of_node(data-\u003edev));\n 132:\t}\n 133:\t\n 134:\tstatic void lan966x_pci_unload_overlay(struct lan966x_pci *data)\n 135:\t{\n 136:\t\tof_overlay_remove(\u0026data-\u003eovcs_id);\n 137:\t}\n 138:\t\n 139:\tstatic int lan966x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)\n 140:\t{\n 141:\t\tstruct device *dev = \u0026pdev-\u003edev;\n 142:\t\tstruct lan966x_pci *data;\n 143:\t\tint ret;\n 144:\t\n 145:\t\t/*\n 146:\t\t * On ACPI system, fwnode can point to the ACPI node.\n 147:\t\t * This driver needs an of_node to be used as the device-tree overlay\n 148:\t\t * target. This of_node should be set by the PCI core if it succeeds in\n 149:\t\t * creating it (CONFIG_PCI_DYNAMIC_OF_NODES feature).\n 150:\t\t * Check here for the validity of this of_node.\n 151:\t\t */\n 152:\t\tif (!dev_of_node(dev))\n 153:\t\t\treturn dev_err_probe(dev, -EINVAL, \"Missing of_node for device\\n\");\n 154:\t\n 155:\t\t/* Need to be done before devm_pci_dev_create_intr_ctrl.\n 156:\t\t * It allocates an IRQ and so pdev-\u003eirq is updated.\n 157:\t\t */\n 158:\t\tret = pcim_enable_device(pdev);\n 159:\t\tif (ret)\n 160:\t\t\treturn ret;\n 161:\t\n 162:\t\tret = devm_pci_dev_create_intr_ctrl(pdev);\n 163:\t\tif (ret)\n 164:\t\t\treturn ret;\n 165:\t\n 166:\t\tdata = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);\n 167:\t\tif (!data)\n 168:\t\t\treturn -ENOMEM;\n 169:\t\n 170:\t\tpci_set_drvdata(pdev, data);\n 171:\t\tdata-\u003edev = dev;\n 172:\t\n 173:\t\tret = lan966x_pci_load_overlay(data);\n 174:\t\tif (ret)\n 175:\t\t\treturn ret;\n 176:\t\n 177:\t\tpci_set_master(pdev);\n 178:\t\n 179:\t\tret = of_platform_default_populate(dev_of_node(dev), NULL, dev);\n 180:\t\tif (ret)\n 181:\t\t\tgoto err_unload_overlay;\n 182:\t\n 183:\t\treturn 0;\n 184:\t\n 185:\terr_unload_overlay:\n 186:\t\tlan966x_pci_unload_overlay(data);\n 187:\t\treturn ret;\n 188:\t}\n 189:\t\n 190:\tstatic void lan966x_pci_remove(struct pci_dev *pdev)\n 191:\t{\n 192:\t\tstruct lan966x_pci *data = pci_get_drvdata(pdev);\n 193:\t\n 194:\t\tof_platform_depopulate(data-\u003edev);\n 195:\t\n 196:\t\tlan966x_pci_unload_overlay(data);\n 197:\t}\n 198:\t\n 199:\tstatic struct pci_device_id lan966x_pci_ids[] = {\n"
} |
| 63/2 | 2026/07/13 19:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 223593 output: 47 thoughts: 106 Thoughts: **Investigating the LAN966x Register Map Initialization** Okay, so looking at `lan966x_pci.c`, it's immediately clear that this file doesn't actually *create* any register maps. It's just handling the Device Tree overlay application and calling `of_platform_default_populate`. That makes sense for the overall PCI setup. The crucial part here is that the child devices are probed *after* this call. But that raises a question. If the child devices are being probed subsequently, where exactly are *their* register maps being established? It's not immediately obvious from this initial driver file. This means I need to dig deeper. Let's switch gears and go look at `drivers/net/ethernet/microchip/lan966x/lan966x_main.c` . This should provide the answer, because it is the "main" driver that calls and configures the child devices that are associated with the PCI device. I'm going to follow the code execution flow and see how *it* obtains the register maps. That should shed light on the whole process. |
| 64/2 | 2026/07/13 19:36 | tool | grepper |
0mError:no matches Args: {
"Expression": "regmap",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/lan966x_main.c"
}Results: {
"error": "no matches"
} |
| 65/2 | 2026/07/13 19:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 224003 output: 50 thoughts: 40 Thoughts: Okay, here's my take on those thoughts, framed as my own: **Investigating the LAN966x Driver Architecture** Hmm, wait a minute... I was under the impression that the `lan966x` driver utilized a regmap approach for memory-mapped register access. That just doesn't feel right. Let me double-check that assumption. The quickest way to confirm this will be to dig into the core logic. Specifically, I need to open up `lan966x_main.c` and hunt for instances of `devm_ioremap`. That function call, or its absence, will quickly tell the tale; if it's there, then my initial hypothesis regarding direct ioremap is supported, and if not, well, I might need to re-evaluate my mental model of how this driver manages its register interactions. It’s either going to be direct memory mapping, or something more sophisticated, like an indirect register abstraction. Let's get to the code. |
| 66/2 | 2026/07/13 19:36 | tool | grepper |
0mArgs:{
"Expression": "devm_ioremap",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/lan966x_main.c"
}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"
} |
| 67/2 | 2026/07/13 19:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 224484 output: 30 thoughts: 443 Thoughts: **Investigating the `lan9645x` Driver's Register Map Acquisition** Okay, so I'm looking at the `lan966x` driver, and it's using `devm_ioremap` directly, which is straightforward. But then I'm looking at `lan9645x`, and it's using `dev_get_regmap(lan9645x->dev->parent, resource_name)`. That's where things get interesting. Why the `dev_get_regmap` approach here? Is there a hidden MFD driver lurking somewhere that creates these regmaps for it? Let's do a quick search in the `drivers/mfd/` directory; nope, no `lan9645x` to be found. Okay, let's limit the scope to `drivers/net/dsa/microchip/lan9645x/` specifically. Still nothing. Wait a minute... if there's no driver *creating* these regmaps, then `lan9645x` CAN'T actually probe successfully, can it? Could it be that these regmaps are somehow created by a `syscon` instance and `dev_get_regmap` is finding them? No, that doesn't seem right. `syscon` doesn't use `devres` to link the regmap to the device. Let me check the `syscon` initialization code... ah, yes, `regmap_init_mmio(NULL, base, &syscon_config)`. The `dev` argument is *NULL*. So `devres_find` will definitely not find it, and thus `dev_get_regmap` will fail. Wait a sec, could it be that `lan9645x` is meant to be a child of an MFD driver that's *not* in the kernel tree, or perhaps was simply omitted from the patch series? Yes, that's very plausible. I suspect the author neglected to include the necessary MFD driver responsible for creating these regmaps. Or, perhaps, maybe the regmaps are created by `syscon`, but the author mistakenly used `dev_get_regmap` instead of `syscon_regmap_lookup_by_phandle`? If that's the case, the probe will error out with `-ENODEV`, and the driver will simply never be functional. I really should check to see if there's another driver in the system that's creating the regmaps for the device. |
| 68/2 | 2026/07/13 19:36 | tool | grepper |
0mArgs:{
"Expression": "lan9645x_resource_names",
"PathPrefix": ""
}Results: {
"Output": "drivers/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=883=static int lan9645x_request_target_regmaps(struct lan9645x *lan9645x)\n--\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-888-\tfor (int i = 0; i \u003c NUM_TARGETS; i++) {\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c:889:\t\tresource_name = lan9645x_resource_names[i];\ndrivers/net/dsa/microchip/lan9645x/lan9645x_main.c-890-\t\tif (!resource_name)\n"
} |
| 69/2 | 2026/07/13 19:36 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 225862 output: 28 thoughts: 51 Thoughts: Okay, here's my interpretation of those thoughts, tailored for an expert audience, presented in the first person: **Navigating the Regmap Landscape** Right, so I'm thinking about regmap initialization, specifically, how `devm_regmap_init` interacts with the global configuration block, or `gcb`. My intuition is there's a connection, but I'm drawing a blank on the specifics. A quick search for both terms together returned nothing useful, which is odd. It suggests a more subtle interaction than I initially considered. Perhaps it’s a direct function call or via some macro that expands to the function call internally. My mind then jumped to `regmap_attach_dev`. That seems relevant. Perhaps this is the key to linking the device resource tree with the regmap, and maybe it's in here the link is forged. I need to investigate the connection, and how the driver's device structure is integrated within the initialization path. I need to refresh myself of the call chain and understand where the `gcb` is actually used. |
| 70/2 | 2026/07/13 19:36 | tool | grepper |
0mArgs:{
"Expression": "regmap_attach_dev",
"PathPrefix": "drivers/"
}Results: {
"Output": "drivers/base/regmap/regmap.c=560=static int regmap_set_name(struct regmap *map, const struct regmap_config *config)\n--\ndrivers/base/regmap/regmap.c-574-\ndrivers/base/regmap/regmap.c:575:int regmap_attach_dev(struct device *dev, struct regmap *map,\ndrivers/base/regmap/regmap.c-576-\t\t const struct regmap_config *config)\n--\ndrivers/base/regmap/regmap.c-600-}\ndrivers/base/regmap/regmap.c:601:EXPORT_SYMBOL_GPL(regmap_attach_dev);\ndrivers/base/regmap/regmap.c-602-\n--\ndrivers/base/regmap/regmap.c=677=struct regmap *__regmap_init(struct device *dev,\n--\ndrivers/base/regmap/regmap.c-1156-\tif (dev) {\ndrivers/base/regmap/regmap.c:1157:\t\tret = regmap_attach_dev(dev, map, config);\ndrivers/base/regmap/regmap.c-1158-\t\tif (ret != 0)\n--\ndrivers/mfd/max77759.c=488=static int max77759_create_i2c_subdev(struct i2c_client *client,\n--\ndrivers/mfd/max77759.c-517-\ndrivers/mfd/max77759.c:518:\tret = regmap_attach_dev(\u0026client-\u003edev, regmap, sd-\u003ecfg);\ndrivers/mfd/max77759.c-519-\tif (ret)\n--\ndrivers/mfd/qcom-pm8008.c=193=static int pm8008_probe(struct i2c_client *client)\n--\ndrivers/mfd/qcom-pm8008.c-214-\ndrivers/mfd/qcom-pm8008.c:215:\tret = regmap_attach_dev(dev, regmap2, \u0026pm8008_regmap_cfg_2);\ndrivers/mfd/qcom-pm8008.c-216-\tif (ret)\n--\ndrivers/mfd/sec-acpm.c=446=static struct regmap *sec_pmic_acpm_regmap_init(struct device *dev,\n--\ndrivers/mfd/sec-acpm.c-467-\ndrivers/mfd/sec-acpm.c:468:\t\tret = regmap_attach_dev(dev, regmap, cfg);\ndrivers/mfd/sec-acpm.c-469-\t\tif (ret)\n--\ndrivers/pinctrl/freescale/pinctrl-imx.c=700=int imx_pinctrl_probe(struct platform_device *pdev,\n--\ndrivers/pinctrl/freescale/pinctrl-imx.c-718-\t\tif (!IS_ERR(gpr))\ndrivers/pinctrl/freescale/pinctrl-imx.c:719:\t\t\tregmap_attach_dev(\u0026pdev-\u003edev, gpr, \u0026config);\ndrivers/pinctrl/freescale/pinctrl-imx.c-720-\t}\n--\ndrivers/remoteproc/imx_rproc.c=1046=static int imx_rproc_mmio_detect_mode(struct rproc *rproc)\n--\ndrivers/remoteproc/imx_rproc.c-1066-\tpriv-\u003eregmap = regmap;\ndrivers/remoteproc/imx_rproc.c:1067:\tret = regmap_attach_dev(dev, regmap, \u0026config);\ndrivers/remoteproc/imx_rproc.c-1068-\tif (ret) {\n--\ndrivers/reset/reset-imx7.c=361=static int imx7_reset_probe(struct platform_device *pdev)\n--\ndrivers/reset/reset-imx7.c-377-\t}\ndrivers/reset/reset-imx7.c:378:\tregmap_attach_dev(dev, imx7src-\u003eregmap, \u0026config);\ndrivers/reset/reset-imx7.c-379-\n"
} |
| 71/2 | 2026/07/13 19:36 | llm | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 227282 output: 36 thoughts: 1144 Thoughts: **Unreachable Driver Analysis** Okay, so I'm looking at this `lan9645x` driver, and it's immediately apparent there's a serious problem. There's no driver I can find that actually creates the register maps (`regmaps`) this driver needs. The probe function is going to fail with `-ENODEV` because `dev_get_regmap` will return `NULL` every single time. That device tree example in the patch... hang on, does that provide a clue? It shows a `reg` property, but if it has `reg`, why is it using `dev_get_regmap`? Let me re-examine the `lan9645x_request_target_regmaps` code. Right, the driver's trying to get the `regmap` from the parent device using `dev_get_regmap`. If the device tree includes the `reg` property, maybe a parent, like a System Controller (`syscon`) or a Multi-Function Device (`MFD`), is *supposed* to map the memory and create these `regmaps`. But... the MFD driver isn't included in the patch or the kernel tree as far as I can see. That means this driver just *cannot* be probed in its current state. Wait, is it possible `lan9645x` is a child of the `lan966x`? No, `lan966x` is itself a switch driver. Could the author have intended to use `devm_regmap_init_mmio` but mistakenly used `dev_get_regmap`? If so, it's a bug, and the driver is completely unreachable. Let me re-examine this `dev_get_regmap`. If the parent of this device is `NULL`, it will return null. If the parent is not NULL, then it will look for a `regmap` attached to that parent device. Since there is no driver that would attach a `regmap` with these specific names, it will always return `NULL`. The probe will *always* fail. Which also means this driver is, for all intents and purposes, unreachable. It's essentially dead code in a virtualized environment. Could `syscon` create these `regmaps` through some clever device tree configuration? No, `syscon` doesn't attach the `regmap` to the device using `devres`. It uses `regmap_init_mmio` with `dev = NULL`. So, `dev_get_regmap` will never find it. Alright, what if it's some MFD driver that's already in the kernel? I went searching for `devm_regmap_init` and `gcb`. Nothing. I searched for `regmap_attach_dev`. Still nothing related. There is no MFD driver for this device in the kernel. So, the conclusion is that the patch author probably forgot to include the MFD driver in the series, or it's floating in some other unapplied patch set. This driver *cannot* be probed; it's effectively an unreachable island in the kernel. Let me double-check how `dev_get_regmap` actually works. `devres_find` looks for a devres of type `dev_get_regmap_release`, which is added by `regmap_attach_dev` or `__devm_regmap_init`. So, the `regmap` *must* have been created by `devm_regmap_init_*` or attached by `regmap_attach_dev` on the parent device. Since there is no such driver, the probe will fail. Wait, what if the parent device is created by some generic MFD driver? Like `simple-mfd`? `simple-mfd` just populates child devices. It doesn't create regmaps. What about `syscon`? `syscon` creates a regmap, but as we saw, it doesn't attach it to the device using `devres`. Let's check `syscon.c` again. |
| 72/2 | 2026/07/13 19:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/mfd/syscon.c"
}Results: {
"error": "no matches"
} |
| 73/2 | 2026/07/13 19:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 229369 output: 38 thoughts: 1393 Thoughts: **Analyzing the LAN9645x Driver Probe** Okay, so I'm digging into this LAN9645x driver patch. The core issue seems to be how it's getting its regmaps, and that's not immediately obvious. Initially, I saw that `syscon` uses `regmap_init_mmio`, so it's not attaching it to a device. No other generic driver seems to be creating regmaps either, and `mfd-core.c` just adds child devices. Without a dedicated MFD driver to establish the 18 specific regmaps, like "gcb" or "chip_top", this driver can't probe. Then I checked the `lan966x_pci.dtso` again. The `reg-names` in the Device Tree don't seem to establish the regmaps for the driver. I remember that the `lan9645x` driver uses `dev_get_regmap(lan9645x->dev->parent, resource_name)`. So if the parent is `lan966x-pci`, does `lan966x-pci` create regmaps? Nope, I checked that already; it applies the overlay and populates the platform devices. The `lan966x-switch` uses `devm_ioremap` directly, but `lan9645x` expects `dev_get_regmap`, which means it wants an MFD parent. Because I can't find that MFD parent in the kernel, this driver is effectively unreachable. Now, let's look at the patch files again. The patch adds a bunch of files related to the LAN9645x driver, like documentation, makefiles, and the core driver files. This doesn't seem to give us any clues to how the regmaps are created. What if the regmaps are created by `tag_lan9645x.c`? No, that's a tag driver. Then, what if `lan9645x_main.c` itself does it? No, it calls `dev_get_regmap` on its `dev->parent`. If it were doing it itself, it would call `devm_regmap_init` on its own device, and it doesn't. Since it's expecting its parent to do it, it still needs an MFD driver. Since that driver isn't there, the probe will fail. Could `syscon` possibly be the parent and use `devres` to create the regmaps? I checked `syscon.c`, and it uses `regmap_init_mmio`. So, it doesn't use `devres`. Could `simple-mfd` create these regmaps? Let's check `drivers/mfd/mfd-core.c` and `drivers/mfd/simple-mfd.c` just to be sure. It looks like it doesn't. So, the conclusion is clear. The driver as it stands relies on an MFD parent that isn't present in the current kernel, rendering it unable to probe and therefore useless as it is. |
| 74/2 | 2026/07/13 19:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/mfd/simple-mfd.c"
}Results: {
"error": "no matches"
} |
| 75/2 | 2026/07/13 19:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 231499 output: 46 thoughts: 463 Thoughts: **Analyzing the LAN9645x Driver's Regmap Requirements**
Okay, let's break this down. My initial thought was that the driver is misusing `dev_get_regmap`, assuming it could pull a regmap directly from a syscon using that function, but that's not how it works. `syscon` provides `syscon_node_to_regmap`, and if a driver is using a syscon, it uses something like `syscon_regmap_lookup_by_phandle`. `dev_get_regmap` is *specifically* for regmaps that are already attached to a `struct device` via `devres`. Since the probe failed I ruled that out.
Then I considered whether the parent device might be an I2C or SPI device, and if the subsystem could be responsible for creating the regmaps. However, SPI/I2C don't magically create regmaps with names like "gcb" or "qs". No, that's not it.
The driver is *explicitly* asking for 18 different regmaps, each with a specific name. The code is blatantly clear:
```c
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;
}
```
That means the parent device *must* have 18 regmaps attached to it, each labeled with an exact name. This is a highly specific requirement. There isn't any generic driver that would do this; it *has* to be a custom Multi-Function Device (MFD) driver for the `lan9645x`.
The logical conclusion is that this driver depends on a companion MFD driver. Since the regmaps aren't showing up, that MFD driver must be missing. The next logical step would be to see if I can find that MFD driver in the kernel source. Could it be in `drivers/net/ethernet/microchip/lan966x/`? Let me search for `lan9645x_resource_names` within that directory, and see if I can locate the companion MFD driver.
|
| 76/2 | 2026/07/13 19:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "lan9645x_resource_names",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}Results: {
"error": "no matches"
} |
| 77/2 | 2026/07/13 19:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 232612 output: 43 thoughts: 31 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Investigating LAN966x Driver Initialization** Okay, so I'm digging into the LAN966x driver, specifically the Ethernet implementation. I need to understand the device initialization sequence. My immediate thought is to check how `devm_regmap_init` is being utilized within the driver. That's a critical function for managing register maps, especially in device drivers using the driver model and resource management. I want to see how the register map is being set up, initialized, and associated with the device. Examining its use will likely shed light on the register access methodology employed by the LAN966x driver. I want to understand if there are any peculiarities to its usage. What are the constraints, if any? Also, what are the implications on error handling during the initialization? Time to head to `drivers/net/ethernet/microchip/lan966x/` and take a look. |
| 78/2 | 2026/07/13 19:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "devm_regmap_init",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}Results: {
"error": "no matches"
} |
| 79/2 | 2026/07/13 19:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 232911 output: 42 thoughts: 30 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience and written in the first person: **LAN966x Regmap Integration Inquiry** Okay, so I'm looking at the LAN966x driver, specifically the `drivers/net/ethernet/microchip/lan966x/` directory. My immediate thought is about how the regmap is being handled. I need to refresh my memory on the device attachment process, so I'm immediately homing in on the `regmap_attach_dev` function. Is it being utilized here for proper register access and configuration of this Microchip Ethernet controller? I wonder about how the register access is implemented, looking at the possibilities in the code. I need to revisit the specifics of how the regmap is initialized and used within the context of the LAN966x driver to ensure efficient and correct register mapping. |
| 80/2 | 2026/07/13 19:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "regmap_attach_dev",
"PathPrefix": "drivers/net/ethernet/microchip/lan966x/"
}Results: {
"error": "no matches"
} |
| 81/2 | 2026/07/13 19:38 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 233187 output: 29 thoughts: 682 Thoughts: **Analyzing the LAN9645x Driver Initialization** Okay, so there's a problem. There's no Multi-Function Device (MFD) driver associated with this. Let me double-check the `lan9645x_probe` function to see if there's any graceful fallback if `dev_get_regmap` fails. The code directly returns `-ENODEV` if the request for the regmaps fails. No fallback, got it. I'm starting to think there might be a bug here. Could the developer have intended to use `devm_regmap_init_mmio` but accidentally used `dev_get_regmap`? If that's the case, the driver would be completely unreachable, which isn't good. Hold on, let me review the device tree example given in the patch, specifically the `reg` property. The example shows only one memory region defined. But the driver *requires* eighteen separate regmaps! That just doesn't compute. Could the parent device be mapping a larger region and creating eighteen sub-regmaps for various sub-regions? Yes, that's precisely what an MFD driver would do. But, again, there's no MFD driver. It is obvious, so the driver cannot be probed. What if the regmaps are created by `syscon` and `dev_get_regmap` *could* find them? Let's verify `dev_get_regmap`'s implementation. It looks for a `devres` of type `dev_get_regmap_release`. This `devres` is *only* added by `regmap_attach_dev` or `__devm_regmap_init`. However, `syscon` uses `regmap_init_mmio`, not `devm_regmap_init` or `regmap_attach_dev`. So `dev_get_regmap` is *never* going to find a regmap created by `syscon`. Okay, even if the parent is a `simple-mfd` and uses `syscon`, that won't work either. `syscon` doesn't attach the regmap to the device, so `dev_get_regmap` will still return NULL. Is there any other driver in the kernel that might be responsible for creating these regmaps? To be sure, I'll search the `drivers/mfd/` directory for any instances of "gcb". |
| 82/2 | 2026/07/13 19:38 | tool | grepper |
0mError:no matches Args: {
"Expression": "\"gcb\"",
"PathPrefix": "drivers/mfd/"
}Results: {
"error": "no matches"
} |
| 83/2 | 2026/07/13 19:38 | llm | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 234443 output: 39 thoughts: 656 Thoughts: **Analyzing Driver Reachability** Okay, so I'm looking at this code and it's pretty clear: there are no direct matches for the MFD driver. That means the MFD driver is definitely missing, which means the probe function is going to fail every single time. And if the probe function fails, the driver is essentially unreachable from the normal kernel paths. Therefore, my initial assessment is that `WorthFuzzing` should be `false`. But, hold on. I need to be thorough. I have to consider all possible entry points. Is there *any* other way this driver could be probed? Could `lan9645x_probe` be called from somewhere else besides the direct MFD initialization? No, it's a platform driver probe function; it's designed to be called when the platform device is found. Alright, what about syzkaller? Could syzkaller be mocking something up? Could syzkaller provide the regmaps somehow? No, that's not how it works. Syzkaller doesn't know about `dev_get_regmap` and wouldn't automatically create regmaps with these specific names for the parent devices. Syzkaller can generate device tree nodes, but it can't create an MFD driver that calls `devm_regmap_init` with those 18 specific names. Okay, let me review the patch with fresh eyes. Is there *any* other functional change in this patch besides the main driver? Ah, I see: `net/dsa/tag_lan9645x.c`. This is a DSA tag driver, so that could be reached. How is this driver registered? It uses `module_dsa_tag_driver(lan9645x_netdev_ops);`. So, it can be reached if a DSA switch *uses* it. But the only switch that uses it is `lan9645x`, which can't be probed. Wait a second... can syzkaller instantiate a *dummy* DSA switch and then *tell* it to use this tag driver? Syzkaller can create dummy DSA switches, like `dsa_loop`, but it uses `DSA_TAG_PROTO_NONE` or `DSA_TAG_PROTO_DSA`. Can syzkaller change the tag protocol of a DSA switch from userspace? Yes! There's a sysfs attribute: `/sys/class/net/<dsa_port>/dsa/tagging` that allows changing the tag protocol! Let's check if we can set `DSA_TAG_PROTO_LAN9645X` via sysfs. Ah, in `net/dsa/tag_lan9645x.c` there's: ```c MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9645X, LAN9645X_NAME); ``` If syzkaller writes "lan9645x" to `/sys/class/net/<dsa_port>/dsa/tagging`, the DSA core should try to load the module and change the tag protocol to `DSA_TAG_PROTO_LAN9645X`. If it *succeeds*, the `lan9645x_xmit` and `lan9645x_rcv` functions can be reached. So, the next step is to verify whether `dsa_loop` or any other DSA switch allows changing the tag protocol to *arbitrary* protocols. I need to check `net/dsa/dsa.c` or `net/dsa/slave.c` for any restrictions or safety checks. |
| 84/2 | 2026/07/13 19:40 | tool | grepper |
0mArgs:{
"Expression": "dsa_switch_ops",
"PathPrefix": "drivers/net/dsa/dsa_loop.c"
}Results: {
"Output": "drivers/net/dsa/dsa_loop.c=326=static void dsa_loop_phylink_get_caps(struct dsa_switch *dsa, int port,\n--\ndrivers/net/dsa/dsa_loop.c-333-\ndrivers/net/dsa/dsa_loop.c:334:static const struct dsa_switch_ops dsa_loop_driver = {\ndrivers/net/dsa/dsa_loop.c-335-\t.get_tag_protocol\t= dsa_loop_get_protocol,\n"
} |
| 85/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 236079 output: 38 thoughts: 22 Thoughts: Here's my take on those functions: **Digging into the Protocol Handling** Okay, time to get down to brass tacks and understand how we're managing the data source protocol in the loop. My initial thought is to dive into `dsa_loop_get_protocol` and `change_tag_protocol`. They're probably the linchpins of how we're extracting and modifying the communication ruleset for the Direct Source Access (DSA) loop. I need to figure out: what's the logic behind the protocol retrieval? Is it based on a hardcoded value, a configuration file, or perhaps a negotiation with the data source itself? How about the `change_tag_protocol` function? Is that a critical operation? I need to understand what it does and when it's appropriate to call it. I'm looking for the triggers, the parameters, and the implications of this protocol swap. Are there any resource-related considerations to bear in mind? Are there thread-safety concerns? Ultimately, I'm trying to determine the flexibility and robustness of this protocol management. My goal is to know whether these methods are bulletproof and ready for the complex scenarios that my team is likely to throw at it. |
| 86/2 | 2026/07/13 19:40 | tool | grepper |
0mError:no matches Args: {
"Expression": "change_tag_protocol",
"PathPrefix": "drivers/net/dsa/dsa_loop.c"
}Results: {
"error": "no matches"
} |
| 87/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 236409 output: 27 thoughts: 56 Thoughts: Okay, here's my interpretation of that thought process, assuming I'm well-versed in DSA and network switch internals: **Investigating Tag Protocol Flexibility on a DSA Switch** Alright, I'm pondering a DSA switch that *doesn't* have a `change_tag_protocol` implementation. The core question is: can I still influence or alter the tag protocol used on this device, or am I stuck with what's hardcoded? The absence of that specific function immediately raises a flag. My next move is to dive into the kernel source, specifically targeting the DSA driver code. I'll likely start with `net/dsa/port.c` and `net/dsa/slave.c`. The goal here is to hunt for the presence of a `tagging` sysfs attribute. If that's exposed, it’s a strong indication that *some* level of user control over the tagging mechanism might be available, even without a dedicated `change_tag_protocol` function. It might be limited, perhaps allowing selection from a predefined set of protocols, but it's a potential avenue for flexibility I need to investigate. So, I'm off to the source! |
| 88/2 | 2026/07/13 19:40 | tool | grepper |
0mArgs:{
"Expression": "tagging",
"PathPrefix": "net/dsa/"
}Results: {
"Output": "net/dsa/Kconfig=17=if NET_DSA\nnet/dsa/Kconfig-18-\nnet/dsa/Kconfig:19:# Drivers must select the appropriate tagging format(s)\nnet/dsa/Kconfig-20-\n--\nnet/dsa/Kconfig=27=config NET_DSA_TAG_AR9331\n--\nnet/dsa/Kconfig-29-\thelp\nnet/dsa/Kconfig:30:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-31-\t the Atheros AR9331 SoC with built-in switch.\n--\nnet/dsa/Kconfig=37=config NET_DSA_TAG_BRCM\n--\nnet/dsa/Kconfig-40-\thelp\nnet/dsa/Kconfig:41:\t Say Y if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-42-\t Broadcom switches which place the tag after the MAC source address.\n--\nnet/dsa/Kconfig=44=config NET_DSA_TAG_BRCM_LEGACY\n--\nnet/dsa/Kconfig-47-\thelp\nnet/dsa/Kconfig:48:\t Say Y if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-49-\t BCM63xx legacy switches which place the tag after the MAC source\n--\nnet/dsa/Kconfig=54=config NET_DSA_TAG_BRCM_LEGACY_FCS\n--\nnet/dsa/Kconfig-57-\thelp\nnet/dsa/Kconfig:58:\t Say Y if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-59-\t BCM53xx legacy switches which place the tag after the MAC source\n--\nnet/dsa/Kconfig=64=config NET_DSA_TAG_BRCM_PREPEND\n--\nnet/dsa/Kconfig-67-\thelp\nnet/dsa/Kconfig:68:\t Say Y if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-69-\t Broadcom switches which places the tag before the Ethernet header\n--\nnet/dsa/Kconfig=72=config NET_DSA_TAG_HELLCREEK\n--\nnet/dsa/Kconfig-74-\thelp\nnet/dsa/Kconfig:75:\t Say Y or M if you want to enable support for tagging frames\nnet/dsa/Kconfig-76-\t for the Hirschmann Hellcreek TSN switches.\n--\nnet/dsa/Kconfig=78=config NET_DSA_TAG_LAN9645X\n--\nnet/dsa/Kconfig-80-\thelp\nnet/dsa/Kconfig:81:\t Say Y or M if you want to enable NPI tagging for the Lan9645x switches.\nnet/dsa/Kconfig-82-\t In this mode, the frames over the Ethernet CPU port are prepended with\n--\nnet/dsa/Kconfig=89=config NET_DSA_TAG_GSWIP\n--\nnet/dsa/Kconfig-91-\thelp\nnet/dsa/Kconfig:92:\t Say Y or M if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-93-\t Lantiq / Intel GSWIP switches.\n--\nnet/dsa/Kconfig=98=config NET_DSA_TAG_DSA\n--\nnet/dsa/Kconfig-101-\thelp\nnet/dsa/Kconfig:102:\t Say Y or M if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-103-\t Marvell switches which use DSA headers.\n--\nnet/dsa/Kconfig=105=config NET_DSA_TAG_EDSA\n--\nnet/dsa/Kconfig-108-\thelp\nnet/dsa/Kconfig:109:\t Say Y or M if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-110-\t Marvell switches which use EtherType DSA headers.\n--\nnet/dsa/Kconfig=112=config NET_DSA_TAG_MTK\n--\nnet/dsa/Kconfig-114-\thelp\nnet/dsa/Kconfig:115:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-116-\t Mediatek switches.\n--\nnet/dsa/Kconfig=118=config NET_DSA_TAG_MXL_862XX\n--\nnet/dsa/Kconfig-120-\thelp\nnet/dsa/Kconfig:121:\t Say Y or M if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-122-\t MaxLinear MxL86252 and MxL86282 switches using their native 8-byte\nnet/dsa/Kconfig:123:\t tagging protocol.\nnet/dsa/Kconfig-124-\nnet/dsa/Kconfig=125=config NET_DSA_TAG_MXL_GSW1XX\n--\nnet/dsa/Kconfig-129-\t can be used on the CPU port of the switch.\nnet/dsa/Kconfig:130:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-131-\t MaxLinear GSW1xx switches.\n--\nnet/dsa/Kconfig=133=config NET_DSA_TAG_KSZ\n--\nnet/dsa/Kconfig-135-\thelp\nnet/dsa/Kconfig:136:\t Say Y if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-137-\t Microchip 8795/937x/9477/9893 families of switches.\n--\nnet/dsa/Kconfig=149=config NET_DSA_TAG_OCELOT\n--\nnet/dsa/Kconfig-152-\thelp\nnet/dsa/Kconfig:153:\t Say Y or M if you want to enable NPI tagging for the Ocelot switches\nnet/dsa/Kconfig-154-\t (VSC7511, VSC7512, VSC7513, VSC7514, VSC9953, VSC9959). In this mode,\n--\nnet/dsa/Kconfig=160=config NET_DSA_TAG_OCELOT_8021Q\n--\nnet/dsa/Kconfig-162-\thelp\nnet/dsa/Kconfig:163:\t Say Y or M if you want to enable support for tagging frames with a\nnet/dsa/Kconfig-164-\t custom VLAN-based header. Frames that require timestamping, such as\n--\nnet/dsa/Kconfig=170=config NET_DSA_TAG_QCA\n--\nnet/dsa/Kconfig-172-\thelp\nnet/dsa/Kconfig:173:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-174-\t the Qualcomm Atheros QCA8K switches.\n--\nnet/dsa/Kconfig=176=config NET_DSA_TAG_RTL4_A\n--\nnet/dsa/Kconfig-178-\thelp\nnet/dsa/Kconfig:179:\t Say Y or M if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-180-\t Realtek switches with 4 byte protocol A tags, such as found in\n--\nnet/dsa/Kconfig=183=config NET_DSA_TAG_RTL8_4\n--\nnet/dsa/Kconfig-185-\thelp\nnet/dsa/Kconfig:186:\t Say Y or M if you want to enable support for tagging frames for Realtek\nnet/dsa/Kconfig-187-\t switches with 8 byte protocol 4 tags, such as the Realtek RTL8365MB-VC.\n--\nnet/dsa/Kconfig=189=config NET_DSA_TAG_RZN1_A5PSW\n--\nnet/dsa/Kconfig-191-\thelp\nnet/dsa/Kconfig:192:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-193-\t Renesas RZ/N1 embedded switch that uses an 8 byte tag located after\n--\nnet/dsa/Kconfig=196=config NET_DSA_TAG_LAN9303\n--\nnet/dsa/Kconfig-198-\thelp\nnet/dsa/Kconfig:199:\t Say Y or M if you want to enable support for tagging frames for the\nnet/dsa/Kconfig-200-\t SMSC/Microchip LAN9303 family of switches.\n--\nnet/dsa/Kconfig=202=config NET_DSA_TAG_SJA1105\n--\nnet/dsa/Kconfig-205-\thelp\nnet/dsa/Kconfig:206:\t Say Y or M if you want to enable support for tagging frames with the\nnet/dsa/Kconfig:207:\t NXP SJA1105 switch family. Both the native tagging protocol (which\nnet/dsa/Kconfig:208:\t is only for link-local traffic) as well as non-native tagging (based\nnet/dsa/Kconfig-209-\t on a custom 802.1Q VLAN header) are available.\n--\nnet/dsa/Kconfig=211=config NET_DSA_TAG_TRAILER\n--\nnet/dsa/Kconfig-213-\thelp\nnet/dsa/Kconfig:214:\t Say Y or M if you want to enable support for tagging frames at\nnet/dsa/Kconfig-215-\t with a trailed. e.g. Marvell 88E6060.\n--\nnet/dsa/Kconfig=217=config NET_DSA_TAG_VSC73XX_8021Q\n--\nnet/dsa/Kconfig-219-\thelp\nnet/dsa/Kconfig:220:\t Say Y or M if you want to enable support for tagging frames with a\nnet/dsa/Kconfig-221-\t custom VLAN-based header.\n--\nnet/dsa/Kconfig=223=config NET_DSA_TAG_XRS700X\n--\nnet/dsa/Kconfig-225-\thelp\nnet/dsa/Kconfig:226:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-227-\t Arrow SpeedChips XRS700x switches that use a single byte tag trailer.\n--\nnet/dsa/Kconfig=229=config NET_DSA_TAG_YT921X\n--\nnet/dsa/Kconfig-231-\thelp\nnet/dsa/Kconfig:232:\t Say Y or M if you want to enable support for tagging frames for\nnet/dsa/Kconfig-233-\t Motorcomm YT921x switches.\n--\nnet/dsa/Makefile=10=dsa_core-y += \\\n--\nnet/dsa/Makefile-21-\nnet/dsa/Makefile:22:# tagging formats\nnet/dsa/Makefile-23-obj-$(CONFIG_NET_DSA_TAG_AR9331) += tag_ar9331.o\n--\nnet/dsa/conduit.c=312=static void dsa_conduit_ethtool_teardown(struct net_device *dev)\n--\nnet/dsa/conduit.c-322-\nnet/dsa/conduit.c:323:/* Keep the conduit always promiscuous if the tagging protocol requires that\nnet/dsa/conduit.c-324- * (garbles MAC DA) or if it doesn't support unicast filtering, case in which\n--\nnet/dsa/conduit.c=328=static void dsa_conduit_set_promiscuity(struct net_device *dev, int inc)\n--\nnet/dsa/conduit.c-339-\nnet/dsa/conduit.c:340:static ssize_t tagging_show(struct device *d, struct device_attribute *attr,\nnet/dsa/conduit.c-341-\t\t\t char *buf)\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--\nnet/dsa/conduit.c-390-\nnet/dsa/conduit.c:391:\t/* On success we no longer need the module for the old tagging protocol\nnet/dsa/conduit.c-392-\t */\n--\nnet/dsa/conduit.c-396-}\nnet/dsa/conduit.c:397:static DEVICE_ATTR_RW(tagging);\nnet/dsa/conduit.c-398-\nnet/dsa/conduit.c=399=static struct attribute *dsa_user_attrs[] = {\nnet/dsa/conduit.c:400:\t\u0026dev_attr_tagging.attr,\nnet/dsa/conduit.c-401-\tNULL\n--\nnet/dsa/conduit.c=419=int dsa_conduit_setup(struct net_device *dev, struct dsa_port *cpu_dp)\n--\nnet/dsa/conduit.c-446-\nnet/dsa/conduit.c:447:\t/* If we use a tagging format that doesn't have an ethertype\nnet/dsa/conduit.c-448-\t * field, make sure that all packets from this point on get\n--\nnet/dsa/conduit.c=474=void dsa_conduit_teardown(struct net_device *dev)\n--\nnet/dsa/conduit.c-482-\nnet/dsa/conduit.c:483:\t/* If we used a tagging format that doesn't have an ethertype\nnet/dsa/conduit.c-484-\t * field, make sure that all packets from this point get sent\n--\nnet/dsa/dsa.c=948=static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-978-\nnet/dsa/dsa.c:979:/* Since the dsa/tagging sysfs device attribute is per conduit, the assumption\nnet/dsa/dsa.c-980- * is that all DSA switches within a tree share the same tagger, otherwise\n--\nnet/dsa/dsa.c=983=int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-995-\t * traffic. The rtnl_mutex also happens to serialize concurrent\nnet/dsa/dsa.c:996:\t * attempts to change the tagging protocol. If we ever lift the IFF_UP\nnet/dsa/dsa.c-997-\t * restriction, there needs to be another mutex which serializes this.\n--\nnet/dsa/dsa.c=1129=static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp,\n--\nnet/dsa/dsa.c-1137-\t/* It is possible to stack DSA switches onto one another when that\nnet/dsa/dsa.c:1138:\t * happens the switch driver may want to know if its tagging protocol\nnet/dsa/dsa.c-1139-\t * is going to work in such a configuration.\n--\nnet/dsa/dsa.c=1155=static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *conduit,\n--\nnet/dsa/dsa.c-1167-\t\t\tdev_err(ds-\u003edev,\nnet/dsa/dsa.c:1168:\t\t\t\t\"A DSA switch tree can have only one tagging protocol\\n\");\nnet/dsa/dsa.c-1169-\t\t\treturn -EINVAL;\n--\nnet/dsa/dsa.c-1184-\t\t\tdev_warn(ds-\u003edev,\nnet/dsa/dsa.c:1185:\t\t\t\t \"Failed to find a tagging driver for protocol %s, using default\\n\",\nnet/dsa/dsa.c-1186-\t\t\t\t user_protocol);\n--\nnet/dsa/dsa.c-1204-\t\t\tdev_err(ds-\u003edev,\nnet/dsa/dsa.c:1205:\t\t\t\t\"A DSA switch tree can have only one tagging protocol\\n\");\nnet/dsa/dsa.c-1206-\n--\nnet/dsa/dsa.c-1210-\nnet/dsa/dsa.c:1211:\t\t/* In the case of multiple CPU ports per switch, the tagging\nnet/dsa/dsa.c-1212-\t\t * protocol is still reference-counted only per switch tree.\n--\nnet/dsa/tag.c-2-/*\nnet/dsa/tag.c:3: * DSA tagging protocol handling\nnet/dsa/tag.c-4- *\n--\nnet/dsa/tag.c=20=static DEFINE_MUTEX(dsa_tag_drivers_lock);\n--\nnet/dsa/tag.c-23- *\nnet/dsa/tag.c:24: * Called from dsa_switch_rcv. For now, this will only work if tagging is\nnet/dsa/tag.c-25- * enabled on the switch. Normally the MAC driver would retrieve the hardware\n--\nnet/dsa/tag.h=32=static inline struct net_device *dsa_conduit_find_user(struct net_device *dev,\n--\nnet/dsa/tag.h-47-/**\nnet/dsa/tag.h:48: * dsa_software_untag_vlan_aware_bridge: Software untagging for VLAN-aware bridge\nnet/dsa/tag.h-49- * @skb: Pointer to received socket buffer (packet)\n--\nnet/dsa/tag.h=58=static inline void dsa_software_untag_vlan_aware_bridge(struct sk_buff *skb,\n--\nnet/dsa/tag.h-77-/**\nnet/dsa/tag.h:78: * dsa_software_untag_vlan_unaware_bridge: Software untagging for VLAN-unaware bridge\nnet/dsa/tag.h-79- * @skb: Pointer to received socket buffer (packet)\n--\nnet/dsa/tag.h=104=static inline void dsa_software_untag_vlan_unaware_bridge(struct sk_buff *skb,\n--\nnet/dsa/tag.h-137-/**\nnet/dsa/tag.h:138: * dsa_software_vlan_untag: Software VLAN untagging in DSA receive path\nnet/dsa/tag.h-139- * @skb: Pointer to socket buffer (packet)\n--\nnet/dsa/tag.h=149=static inline struct sk_buff *dsa_software_vlan_untag(struct sk_buff *skb)\n--\nnet/dsa/tag.h-155-\nnet/dsa/tag.h:156:\t/* software untagging for standalone ports not yet necessary */\nnet/dsa/tag.h-157-\tif (!br)\n--\nnet/dsa/tag.h-186-\nnet/dsa/tag.h:187:/* For switches without hardware support for DSA tagging to be able\nnet/dsa/tag.h-188- * to support termination through the bridge.\n--\nnet/dsa/tag.h=322=static inline unsigned long dsa_xmit_port_mask(const struct sk_buff *skb,\n--\nnet/dsa/tag.h-339-\nnet/dsa/tag.h:340:/* Create 2 modaliases per tagging protocol, one to auto-load the module\nnet/dsa/tag.h-341- * given the ID reported by get_tag_protocol(), and the other by name.\n--\nnet/dsa/tag_8021q.c=389=static int dsa_tag_8021q_setup(struct dsa_switch *ds)\n--\nnet/dsa/tag_8021q.c-398-\t\t\tdev_err(ds-\u003edev,\nnet/dsa/tag_8021q.c:399:\t\t\t\t\"Failed to setup VLAN tagging for port %d: %pe\\n\",\nnet/dsa/tag_8021q.c-400-\t\t\t\tport, ERR_PTR(err));\n--\nnet/dsa/tag_dsa.c-2-/*\nnet/dsa/tag_dsa.c:3: * Regular and Ethertype DSA tagging\nnet/dsa/tag_dsa.c-4- * Copyright (c) 2008-2009 Marvell Semiconductor\n--\nnet/dsa/tag_lan9645x.c=205=static struct sk_buff *lan9645x_rcv(struct sk_buff *skb,\n--\nnet/dsa/tag_lan9645x.c-283-\t/* While we have REW_PORT_NO_REWRITE=0 on the NPI port, we still disable\nnet/dsa/tag_lan9645x.c:284:\t * port VLAN tagging with REW_TAG_CFG. Any classified VID, different\nnet/dsa/tag_lan9645x.c-285-\t * from a VID in the frame, will not be written to the frame, but is\n--\nnet/dsa/tag_none.c-7- * WARNING: do not use this for new switches. In case of no hardware\nnet/dsa/tag_none.c:8: * tagging support, look at tag_8021q.c instead.\nnet/dsa/tag_none.c-9- */\n--\nnet/dsa/tag_rzn1_a5psw.c-29-#define A5PSW_CTRL_DATA_FORCE_FORWARD\tBIT(0)\nnet/dsa/tag_rzn1_a5psw.c:30:/* This is both used for xmit tag and rcv tagging */\nnet/dsa/tag_rzn1_a5psw.c-31-#define A5PSW_CTRL_DATA_PORT\t\tGENMASK(3, 0)\n--\nnet/dsa/tag_sja1105.c=267=static struct sk_buff *sja1105_xmit(struct sk_buff *skb,\n--\nnet/dsa/tag_sja1105.c-277-\nnet/dsa/tag_sja1105.c:278:\t/* Transmitting management traffic does not rely upon switch tagging,\nnet/dsa/tag_sja1105.c-279-\t * but instead SPI-installed management routes. Part 2 of this\n"
} |
| 89/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 242685 output: 39 thoughts: 580 Thoughts: **Analyzing DSA Switch Tag Protocol Manipulation** Okay, so I'm digging into how we can potentially exploit this `tagging_store` functionality in `net/dsa/conduit.c`. The core idea hinges on changing the tag protocol used by a DSA switch. But, before we can even *think* about changing anything, there *has* to be a DSA switch present. Initially, I see the `lan9645x` driver, and my immediate concern is that if probing that driver, fails with `-ENODEV` in `lan9645x_request_target_regmaps`, then the system has failed to register any DSA switch. Without a registered switch, we're dead in the water, meaning no DSA ports, and thus no `/sys/class/net/<dsa_port>/dsa/tagging` attribute to even mess with. The `tag_lan9645x.c` driver is then useless. The thought then jumped to "can we use something like `dsa_loop` to create a dummy switch?" and force it into our desired configuration? I need to check whether `dsa_loop` gives us the flexibility to change the tag protocol. I dove into `net/dsa/dsa.c`, specifically `dsa_tree_change_tag_proto`. This function looks like the key. It seems to utilize `dsa_tree_notify`, which in turn, calls the switch's `change_tag_protocol` operation. That's our hook! If the switch has this operation defined, we might have a path. I checked `dsa_loop.c` and a search through that source file didn't give me any hits. `dsa_loop` does *not* implement a `change_tag_protocol` function. Alright, that's a dead end for `dsa_loop`. The next thing I'm wondering is, what *other* DSA switches might allow for this sort of tag protocol alteration? Specifically, if another switch, say `sja1105`, which *does* support changing tag protocols, is probed, can syzkaller hijack *its* tag protocol and set it to `lan9645x`? The success here depends on whether the `sja1105` driver allows switching to arbitrary protocols, or if it is restricted to some limited set of options. I'll need to investigate `sja1105_change_tag_protocol` to see if there's any such check, and determine if this is a viable approach. |
| 90/2 | 2026/07/13 19:40 | tool | grepper |
0mError:no matches Args: {
"Expression": "change_tag_protocol",
"PathPrefix": "drivers/net/dsa/sja1105/"
}Results: {
"error": "no matches"
} |
| 91/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 243873 output: 32 thoughts: 49 Thoughts: **Investigating the `change_tag_protocol` Search Results** Okay, so I was looking for the function `change_tag_protocol` within the context of the `sja1105` driver, but my search came up empty. That's not entirely surprising, but it means I need to broaden my scope. Given that this function likely deals with the network driver, and specifically a tag protocol, my next logical step is to check within the broader DSA (Distributed Switch Architecture) framework. Therefore, I'll now perform the same search, this time in the `drivers/net/dsa/` directory. This should give me a better understanding of where this function might reside, or if it even exists within this general area. I am not seeing the relevant information, so I need to expand my search. |
| 92/2 | 2026/07/13 19:40 | tool | grepper |
0mArgs:{
"Expression": "change_tag_protocol",
"PathPrefix": "drivers/net/dsa/"
}Results: {
"Output": "drivers/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"
} |
| 93/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 245254 output: 43 thoughts: 46 Thoughts: Okay, here's my interpretation of those thoughts, presented as a first-person summary, keeping in mind my expertise: **Examining Ethernet Tagging Protocol Options** Alright, so the `mv88e6xxx`, `felix`, and `rtl8365mb` drivers all implement `change_tag_protocol`. That's good to know – it gives me a certain flexibility when dealing with different hardware. My focus is immediately drawn to the `felix_change_tag_protocol` function. It's the most likely candidate, given my previous experience, so it is the starting point for my further investigation. It will require closer examination to understand the specific nuances of how `felix` handles tagging protocol modifications. |
| 94/2 | 2026/07/13 19:40 | tool | read-file |
0mArgs:{
"File": "drivers/net/dsa/ocelot/felix.c",
"FirstLine": 754,
"LineCount": 20
}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"
} |
| 95/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 245834 output: 46 thoughts: 42 Thoughts: Okay, here's my interpretation of those thoughts, summarized from an expert's perspective, presented as a personal thought process: **Network Driver Configuration Concerns** Alright, I'm looking at this driver and immediately, I'm a bit concerned. It looks like the currently supported tags are limited to `SEVILLE`, `OCELOT`, and `OCELOT_8021Q`. I'm going through my mental checklist, and I'm wondering why those specific tags are covered and what the implications are regarding broader usage. My first thought jumps to the `mv88e6xxx_change_tag_protocol` function - or its equivalent within the current code-base. Is it supported? If so, is it supported as I would expect it to be, or is it covered with a caveat? This raises some flags, considering the variety of tag protocols I routinely work with, so I need to dig deeper into the driver's full capabilities and how it handles different types of VLAN tagging. It's time to check the datasheet for the chipset and see what I'm dealing with. |
| 96/2 | 2026/07/13 19:40 | tool | read-file |
0mArgs:{
"File": "drivers/net/dsa/mv88e6xxx/chip.c",
"FirstLine": 6655,
"LineCount": 20
}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;\n"
} |
| 97/2 | 2026/07/13 19:40 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 246489 output: 49 thoughts: 29 Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience: **Analyzing Protocol Support** Okay, so I'm looking at the supported protocols, and it seems the focus is strictly on `EDSA` and `DSA`. That's a bit limiting, right off the bat. My immediate thought is, "What about the broader context? What about other potential applications and protocols the system *might* need to support down the line?" I need to understand if this is a hard limitation of the hardware, the software, or a design choice. I'm specifically thinking about a function I've worked with before, `rtl8365mb_change_tag_protocol`. Is the lack of explicit support a deliberate exclusion or an oversight? Is it handled through some other mechanism, possibly a broader API call, or even indirectly via the supported protocols? I need to dig deeper into the code and documentation to see how this function, or similar functionalities, would be implemented in this framework. The architecture here dictates how I can use protocols. |
| 98/2 | 2026/07/13 19:41 | tool | read-file |
0mArgs:{
"File": "drivers/net/dsa/realtek/rtl8365mb_main.c",
"FirstLine": 2332,
"LineCount": 20
}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\n"
} |
| 99/2 | 2026/07/13 19:41 | llm | patch-evaluator |
1mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 247151 output: 164 thoughts: 713 Thoughts: **Unreachable Code Analysis** Okay, so here's what I've got: this patch introduces a new DSA switch driver, specifically `lan9645x`, along with its associated tag driver, `tag_lan9645x.c`. My initial assessment indicates a fundamental flaw in the setup. The driver, as it's currently implemented, is a platform driver. It relies heavily on its parent device, expecting to find 18 specific `regmap`s using `dev_get_regmap`. From what I can tell, there's no corresponding Multi-Function Device (MFD) driver in the kernel that *actually* creates these required `regmap`s for the `lan9645x`. Since there's no MFD driver, `lan9645x_probe` will inevitably return `-ENODEV`, every single time. Consequently, the switch driver can't be probed, period. This, in turn, means no DSA switch of this `lan9645x` type will ever be registered. And since no `lan9645x` switch is registered, the tag driver, `tag_lan9645x.c`, is effectively orphaned; it’s never going to be used. Furthermore, the existing DSA switch infrastructure doesn’t support changing its tag protocol to `DSA_TAG_PROTO_LAN9645X`. The kernel only supports `RTL8_4` and `RTL8_4T` as tag drivers for switches. Now, I need to be absolutely certain of this. Let's double check. I did, confirming that `dev_get_regmap` can't, in any way, shape or form, access `regmap`s created by `syscon`. It uses `device_node_get_regmap`, which then calls `regmap_init_mmio(NULL, base, &syscon_config)`. The critical thing is the `dev` argument is `NULL`. And while it might try, `syscon` doesn't use `devres` to manage it's resources, thus `devres_find` will *never* find anything. Even if it did, the `regmap` would be attached to the `syscon` device, and critically, there are no named `regmap`s there to be found like “gcb”, or “qs”. The `lan9645x` driver is hardcoded to look for eighteen differently named regmaps. `syscon` only creates a single one, per device node. Therefore, even if we were somehow able to find the regmap from `syscon`, it wouldn't solve the issue. The *only* way this driver would function is if an MFD driver were present. That MFD driver would need to map the memory and, crucially, create these eighteen specific `regmap`s using `devm_regmap_init` or `regmap_attach_dev`, with these precise names. The conclusion is inescapable: Without that missing MFD parent driver, this entire added functional code is completely, utterly unreachable. It doesn’t matter if we're talking about a bare-metal environment or a virtualized setup; the result is the same. This needs a deeper look, or a new approach. I'll return `WorthFuzzing: false`, as this code, as written, is effectively dead. |
| 100/2 | 2026/07/13 19:42 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch adds a new DSA switch driver for Microchip LAN9645x. However, the driver's probe function expects its parent device to provide 18 specific regmaps (e.g., \"gcb\", \"qs\", \"chip_top\") via dev_get_regmap(). There is no MFD driver in the kernel that creates and attaches these regmaps. Without them, the probe function will always fail with -ENODEV. Consequently, the switch driver cannot be instantiated, and its associated tag driver (tag_lan9645x.c) will never be used, making the entire functional code unreachable.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch adds a new DSA switch driver for Microchip LAN9645x. However, the driver's probe function expects its parent device to provide 18 specific regmaps (e.g., \"gcb\", \"qs\", \"chip_top\") via dev_get_regmap(). There is no MFD driver in the kernel that creates and attaches these regmaps. Without them, the probe function will always fail with -ENODEV. Consequently, the switch driver cannot be instantiated, and its associated tag driver (tag_lan9645x.c) will never be used, making the entire functional code unreachable.",
"WorthFuzzing": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|