AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch removes the legacy standalone KS8995 DSA driver and migrates support for the Micrel/Microchip KS8995 / KSZ8995XA Ethernet switch into the microchip ksz8 DSA driver alongside adding a dedicated tag driver (net/dsa/tag_ks8995.c). These switches are physical hardware ASICs connected via SPI and are structurally unreachable in standard virtualized fuzzing environments (QEMU/GCE).",
  "WorthFuzzing": false
}

1/1 2026/09/09 17:26 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 0635973cea904b44d820d9f3282ea3987e830384\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Wed Sep 9 17:26:30 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml\nindex 8d4a3a9a33fcc..4ed13870ed3ac 100644\n--- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml\n+++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml\n@@ -23,6 +23,7 @@ properties:\n       - microchip,ksz8864  # 4-port version of KSZ8895 family switch\n       - microchip,ksz8873\n       - microchip,ksz8895  # 5-port version of KSZ8895 family switch\n+      - microchip,ksz8995xa\n       - microchip,ksz9477\n       - microchip,ksz9897\n       - microchip,ksz9896\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 3a19da74d00c9..7fabc2eae9afe 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -17776,6 +17776,7 @@ F:\tDocumentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml\n F:\tdrivers/net/dsa/microchip/*\n F:\tinclude/linux/dsa/ksz_common.h\n F:\tinclude/linux/platform_data/microchip-ksz.h\n+F:\tnet/dsa/tag_ks8995.c\n F:\tnet/dsa/tag_ksz.c\n \n MICROCHIP LAN743X ETHERNET DRIVER\ndiff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig\nindex 676fb7dffe14f..55a9714033a6f 100644\n--- a/drivers/net/dsa/Kconfig\n+++ b/drivers/net/dsa/Kconfig\n@@ -110,10 +110,13 @@ config NET_DSA_RZN1_A5PSW\n config NET_DSA_KS8995\n \ttristate \"Micrel KS8995 family 5-ports 10/100 Ethernet switches\"\n \tdepends on SPI\n-\tselect NET_DSA_TAG_NONE\n+\tselect NET_DSA_MICROCHIP_KSZ_COMMON\n+\tselect NET_DSA_MICROCHIP_KSZ_SPI\n \thelp\n-\t  This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet\n-\t  switches, managed over SPI.\n+\t  This is a transitional option for users who had NET_DSA_KS8995\n+\t  enabled. It automatically enables the new NET_DSA_MICROCHIP_KSZ_SPI\n+\t  driver which supersedes it. This option will be removed in a future\n+\t  kernel release.\n \n config NET_DSA_SMSC_LAN9303\n \ttristate\ndiff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile\nindex 6ceb78a755d77..9923137429f84 100644\n--- a/drivers/net/dsa/Makefile\n+++ b/drivers/net/dsa/Makefile\n@@ -2,7 +2,6 @@\n obj-$(CONFIG_NET_DSA_BCM_SF2)\t+= bcm-sf2.o\n bcm-sf2-objs\t\t\t:= bcm_sf2.o bcm_sf2_cfp.o\n obj-$(CONFIG_NET_DSA_LOOP)\t+= dsa_loop.o\n-obj-$(CONFIG_NET_DSA_KS8995) \t+= ks8995.o\n obj-$(CONFIG_NET_DSA_MT7530)\t+= mt7530.o\n obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o\n obj-$(CONFIG_NET_DSA_MT7530_MMIO) += mt7530-mmio.o\ndiff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c\ndeleted file mode 100644\nindex 77d8b842693c1..0000000000000\n--- a/drivers/net/dsa/ks8995.c\n+++ /dev/null\n@@ -1,857 +0,0 @@\n-// SPDX-License-Identifier: GPL-2.0\n-/*\n- * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches\n- *\n- * Copyright (C) 2008 Gabor Juhos \u003cjuhosg at openwrt.org\u003e\n- * Copyright (C) 2025 Linus Walleij \u003clinus.walleij@linaro.org\u003e\n- *\n- * This file was based on: drivers/spi/at25.c\n- *     Copyright (C) 2006 David Brownell\n- */\n-\n-#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n-\n-#include \u003clinux/bits.h\u003e\n-#include \u003clinux/if_bridge.h\u003e\n-#include \u003clinux/if_vlan.h\u003e\n-#include \u003clinux/types.h\u003e\n-#include \u003clinux/kernel.h\u003e\n-#include \u003clinux/module.h\u003e\n-#include \u003clinux/delay.h\u003e\n-#include \u003clinux/device.h\u003e\n-#include \u003clinux/gpio/consumer.h\u003e\n-#include \u003clinux/of.h\u003e\n-#include \u003clinux/spi/spi.h\u003e\n-#include \u003cnet/dsa.h\u003e\n-\n-#define DRV_VERSION\t\t\"0.1.1\"\n-#define DRV_DESC\t\t\"Micrel KS8995 Ethernet switch SPI driver\"\n-\n-/* ------------------------------------------------------------------------ */\n-\n-#define KS8995_REG_ID0\t\t0x00    /* Chip ID0 */\n-#define KS8995_REG_ID1\t\t0x01    /* Chip ID1 */\n-\n-#define KS8995_REG_GC0\t\t0x02    /* Global Control 0 */\n-\n-#define KS8995_GC0_P5_PHY\tBIT(3)\t/* Port 5 PHY enabled */\n-\n-#define KS8995_REG_GC1\t\t0x03    /* Global Control 1 */\n-#define KS8995_REG_GC2\t\t0x04    /* Global Control 2 */\n-\n-#define KS8995_GC2_HUGE\t\tBIT(2)\t/* Huge packet support */\n-#define KS8995_GC2_LEGAL\tBIT(1)\t/* Legal size override */\n-\n-#define KS8995_REG_GC3\t\t0x05    /* Global Control 3 */\n-#define KS8995_REG_GC4\t\t0x06    /* Global Control 4 */\n-\n-#define KS8995_GC4_10BT\t\tBIT(4)\t/* Force switch to 10Mbit */\n-#define KS8995_GC4_MII_FLOW\tBIT(5)\t/* MII full-duplex flow control enable */\n-#define KS8995_GC4_MII_HD\tBIT(6)\t/* MII half-duplex mode enable */\n-\n-#define KS8995_REG_GC5\t\t0x07    /* Global Control 5 */\n-#define KS8995_REG_GC6\t\t0x08    /* Global Control 6 */\n-#define KS8995_REG_GC7\t\t0x09    /* Global Control 7 */\n-#define KS8995_REG_GC8\t\t0x0a    /* Global Control 8 */\n-#define KS8995_REG_GC9\t\t0x0b    /* Global Control 9 */\n-\n-#define KS8995_GC9_SPECIAL\tBIT(0)\t/* Special tagging mode (DSA) */\n-\n-/* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */\n-#define KS8995_REG_PC(p, r)\t(0x10 + (0x10 * (p)) + (r)) /* Port Control */\n-#define KS8995_REG_PS(p, r)\t(0x1e + (0x10 * (p)) + (r)) /* Port Status */\n-\n-#define KS8995_REG_PC0\t\t0x00    /* Port Control 0 */\n-#define KS8995_REG_PC1\t\t0x01    /* Port Control 1 */\n-#define KS8995_REG_PC2\t\t0x02    /* Port Control 2 */\n-#define KS8995_REG_PC3\t\t0x03    /* Port Control 3 */\n-#define KS8995_REG_PC4\t\t0x04    /* Port Control 4 */\n-#define KS8995_REG_PC5\t\t0x05    /* Port Control 5 */\n-#define KS8995_REG_PC6\t\t0x06    /* Port Control 6 */\n-#define KS8995_REG_PC7\t\t0x07    /* Port Control 7 */\n-#define KS8995_REG_PC8\t\t0x08    /* Port Control 8 */\n-#define KS8995_REG_PC9\t\t0x09    /* Port Control 9 */\n-#define KS8995_REG_PC10\t\t0x0a    /* Port Control 10 */\n-#define KS8995_REG_PC11\t\t0x0b    /* Port Control 11 */\n-#define KS8995_REG_PC12\t\t0x0c    /* Port Control 12 */\n-#define KS8995_REG_PC13\t\t0x0d    /* Port Control 13 */\n-\n-#define KS8995_PC0_TAG_INS\tBIT(2)\t/* Enable tag insertion on port */\n-#define KS8995_PC0_TAG_REM\tBIT(1)\t/* Enable tag removal on port */\n-#define KS8995_PC0_PRIO_EN\tBIT(0)\t/* Enable priority handling */\n-\n-#define KS8995_PC2_TXEN\t\tBIT(2)\t/* Enable TX on port */\n-#define KS8995_PC2_RXEN\t\tBIT(1)\t/* Enable RX on port */\n-#define KS8995_PC2_LEARN_DIS\tBIT(0)\t/* Disable learning on port */\n-\n-#define KS8995_PC13_TXDIS\tBIT(6)\t/* Disable transmitter */\n-#define KS8995_PC13_PWDN\tBIT(3)\t/* Power down */\n-\n-#define KS8995_REG_TPC0\t\t0x60    /* TOS Priority Control 0 */\n-#define KS8995_REG_TPC1\t\t0x61    /* TOS Priority Control 1 */\n-#define KS8995_REG_TPC2\t\t0x62    /* TOS Priority Control 2 */\n-#define KS8995_REG_TPC3\t\t0x63    /* TOS Priority Control 3 */\n-#define KS8995_REG_TPC4\t\t0x64    /* TOS Priority Control 4 */\n-#define KS8995_REG_TPC5\t\t0x65    /* TOS Priority Control 5 */\n-#define KS8995_REG_TPC6\t\t0x66    /* TOS Priority Control 6 */\n-#define KS8995_REG_TPC7\t\t0x67    /* TOS Priority Control 7 */\n-\n-#define KS8995_REG_MAC0\t\t0x68    /* MAC address 0 */\n-#define KS8995_REG_MAC1\t\t0x69    /* MAC address 1 */\n-#define KS8995_REG_MAC2\t\t0x6a    /* MAC address 2 */\n-#define KS8995_REG_MAC3\t\t0x6b    /* MAC address 3 */\n-#define KS8995_REG_MAC4\t\t0x6c    /* MAC address 4 */\n-#define KS8995_REG_MAC5\t\t0x6d    /* MAC address 5 */\n-\n-#define KS8995_REG_IAC0\t\t0x6e    /* Indirect Access Control 0 */\n-#define KS8995_REG_IAC1\t\t0x6f    /* Indirect Access Control 0 */\n-#define KS8995_REG_IAD7\t\t0x70    /* Indirect Access Data 7 */\n-#define KS8995_REG_IAD6\t\t0x71    /* Indirect Access Data 6 */\n-#define KS8995_REG_IAD5\t\t0x72    /* Indirect Access Data 5 */\n-#define KS8995_REG_IAD4\t\t0x73    /* Indirect Access Data 4 */\n-#define KS8995_REG_IAD3\t\t0x74    /* Indirect Access Data 3 */\n-#define KS8995_REG_IAD2\t\t0x75    /* Indirect Access Data 2 */\n-#define KS8995_REG_IAD1\t\t0x76    /* Indirect Access Data 1 */\n-#define KS8995_REG_IAD0\t\t0x77    /* Indirect Access Data 0 */\n-\n-#define KSZ8864_REG_ID1\t\t0xfe\t/* Chip ID in bit 7 */\n-\n-#define KS8995_REGS_SIZE\t0x80\n-#define KSZ8864_REGS_SIZE\t0x100\n-#define KSZ8795_REGS_SIZE\t0x100\n-\n-#define ID1_CHIPID_M\t\t0xf\n-#define ID1_CHIPID_S\t\t4\n-#define ID1_REVISION_M\t\t0x7\n-#define ID1_REVISION_S\t\t1\n-#define ID1_START_SW\t\t1\t/* start the switch */\n-\n-#define FAMILY_KS8995\t\t0x95\n-#define FAMILY_KSZ8795\t\t0x87\n-#define CHIPID_M\t\t0\n-#define KS8995_CHIP_ID\t\t0x00\n-#define KSZ8864_CHIP_ID\t\t0x01\n-#define KSZ8795_CHIP_ID\t\t0x09\n-\n-#define KS8995_CMD_WRITE\t0x02U\n-#define KS8995_CMD_READ\t\t0x03U\n-\n-#define KS8995_CPU_PORT\t\t4\n-#define KS8995_NUM_PORTS\t5 /* 5 ports including the CPU port */\n-#define KS8995_RESET_DELAY\t10 /* usec */\n-\n-enum ks8995_chip_variant {\n-\tks8995,\n-\tksz8864,\n-\tksz8795,\n-\tmax_variant\n-};\n-\n-struct ks8995_chip_params {\n-\tchar *name;\n-\tint family_id;\n-\tint chip_id;\n-\tint regs_size;\n-\tint addr_width;\n-\tint addr_shift;\n-};\n-\n-static const struct ks8995_chip_params ks8995_chip[] = {\n-\t[ks8995] = {\n-\t\t.name = \"KS8995MA\",\n-\t\t.family_id = FAMILY_KS8995,\n-\t\t.chip_id = KS8995_CHIP_ID,\n-\t\t.regs_size = KS8995_REGS_SIZE,\n-\t\t.addr_width = 8,\n-\t\t.addr_shift = 0,\n-\t},\n-\t[ksz8864] = {\n-\t\t.name = \"KSZ8864RMN\",\n-\t\t.family_id = FAMILY_KS8995,\n-\t\t.chip_id = KSZ8864_CHIP_ID,\n-\t\t.regs_size = KSZ8864_REGS_SIZE,\n-\t\t.addr_width = 8,\n-\t\t.addr_shift = 0,\n-\t},\n-\t[ksz8795] = {\n-\t\t.name = \"KSZ8795CLX\",\n-\t\t.family_id = FAMILY_KSZ8795,\n-\t\t.chip_id = KSZ8795_CHIP_ID,\n-\t\t.regs_size = KSZ8795_REGS_SIZE,\n-\t\t.addr_width = 12,\n-\t\t.addr_shift = 1,\n-\t},\n-};\n-\n-struct ks8995_switch {\n-\tstruct spi_device\t*spi;\n-\tstruct device\t\t*dev;\n-\tstruct dsa_switch\t*ds;\n-\tstruct mutex\t\tlock;\n-\tstruct gpio_desc\t*reset_gpio;\n-\tstruct bin_attribute\tregs_attr;\n-\tconst struct ks8995_chip_params\t*chip;\n-\tint\t\t\trevision_id;\n-\tunsigned int max_mtu[KS8995_NUM_PORTS];\n-};\n-\n-static const struct spi_device_id ks8995_id[] = {\n-\t{\"ks8995\", ks8995},\n-\t{\"ksz8864\", ksz8864},\n-\t{\"ksz8795\", ksz8795},\n-\t{ }\n-};\n-MODULE_DEVICE_TABLE(spi, ks8995_id);\n-\n-static const struct of_device_id ks8995_spi_of_match[] = {\n-\t{ .compatible = \"micrel,ks8995\" },\n-\t{ .compatible = \"micrel,ksz8864\" },\n-\t{ .compatible = \"micrel,ksz8795\" },\n-\t{ },\n-};\n-MODULE_DEVICE_TABLE(of, ks8995_spi_of_match);\n-\n-static inline u8 get_chip_id(u8 val)\n-{\n-\treturn (val \u003e\u003e ID1_CHIPID_S) \u0026 ID1_CHIPID_M;\n-}\n-\n-static inline u8 get_chip_rev(u8 val)\n-{\n-\treturn (val \u003e\u003e ID1_REVISION_S) \u0026 ID1_REVISION_M;\n-}\n-\n-/* create_spi_cmd - create a chip specific SPI command header\n- * @ks: pointer to switch instance\n- * @cmd: SPI command for switch\n- * @address: register address for command\n- *\n- * Different chip families use different bit pattern to address the switches\n- * registers:\n- *\n- * KS8995: 8bit command + 8bit address\n- * KSZ8795: 3bit command + 12bit address + 1bit TR (?)\n- */\n-static inline __be16 create_spi_cmd(struct ks8995_switch *ks, int cmd,\n-\t\t\t\t    unsigned address)\n-{\n-\tu16 result = cmd;\n-\n-\t/* make room for address (incl. address shift) */\n-\tresult \u003c\u003c= ks-\u003echip-\u003eaddr_width + ks-\u003echip-\u003eaddr_shift;\n-\t/* add address */\n-\tresult |= address \u003c\u003c ks-\u003echip-\u003eaddr_shift;\n-\t/* SPI protocol needs big endian */\n-\treturn cpu_to_be16(result);\n-}\n-/* ------------------------------------------------------------------------ */\n-static int ks8995_read(struct ks8995_switch *ks, char *buf,\n-\t\t unsigned offset, size_t count)\n-{\n-\t__be16 cmd;\n-\tstruct spi_transfer t[2];\n-\tstruct spi_message m;\n-\tint err;\n-\n-\tcmd = create_spi_cmd(ks, KS8995_CMD_READ, offset);\n-\tspi_message_init(\u0026m);\n-\n-\tmemset(\u0026t, 0, sizeof(t));\n-\n-\tt[0].tx_buf = \u0026cmd;\n-\tt[0].len = sizeof(cmd);\n-\tspi_message_add_tail(\u0026t[0], \u0026m);\n-\n-\tt[1].rx_buf = buf;\n-\tt[1].len = count;\n-\tspi_message_add_tail(\u0026t[1], \u0026m);\n-\n-\tmutex_lock(\u0026ks-\u003elock);\n-\terr = spi_sync(ks-\u003espi, \u0026m);\n-\tmutex_unlock(\u0026ks-\u003elock);\n-\n-\treturn err ? err : count;\n-}\n-\n-static int ks8995_write(struct ks8995_switch *ks, char *buf,\n-\t\t unsigned offset, size_t count)\n-{\n-\t__be16 cmd;\n-\tstruct spi_transfer t[2];\n-\tstruct spi_message m;\n-\tint err;\n-\n-\tcmd = create_spi_cmd(ks, KS8995_CMD_WRITE, offset);\n-\tspi_message_init(\u0026m);\n-\n-\tmemset(\u0026t, 0, sizeof(t));\n-\n-\tt[0].tx_buf = \u0026cmd;\n-\tt[0].len = sizeof(cmd);\n-\tspi_message_add_tail(\u0026t[0], \u0026m);\n-\n-\tt[1].tx_buf = buf;\n-\tt[1].len = count;\n-\tspi_message_add_tail(\u0026t[1], \u0026m);\n-\n-\tmutex_lock(\u0026ks-\u003elock);\n-\terr = spi_sync(ks-\u003espi, \u0026m);\n-\tmutex_unlock(\u0026ks-\u003elock);\n-\n-\treturn err ? err : count;\n-}\n-\n-static inline int ks8995_read_reg(struct ks8995_switch *ks, u8 addr, u8 *buf)\n-{\n-\treturn ks8995_read(ks, buf, addr, 1) != 1;\n-}\n-\n-static inline int ks8995_write_reg(struct ks8995_switch *ks, u8 addr, u8 val)\n-{\n-\tchar buf = val;\n-\n-\treturn ks8995_write(ks, \u0026buf, addr, 1) != 1;\n-}\n-\n-/* ------------------------------------------------------------------------ */\n-\n-static int ks8995_stop(struct ks8995_switch *ks)\n-{\n-\treturn ks8995_write_reg(ks, KS8995_REG_ID1, 0);\n-}\n-\n-static int ks8995_start(struct ks8995_switch *ks)\n-{\n-\treturn ks8995_write_reg(ks, KS8995_REG_ID1, 1);\n-}\n-\n-static int ks8995_reset(struct ks8995_switch *ks)\n-{\n-\tint err;\n-\n-\terr = ks8995_stop(ks);\n-\tif (err)\n-\t\treturn err;\n-\n-\tudelay(KS8995_RESET_DELAY);\n-\n-\treturn ks8995_start(ks);\n-}\n-\n-/* ks8995_get_revision - get chip revision\n- * @ks: pointer to switch instance\n- *\n- * Verify chip family and id and get chip revision.\n- */\n-static int ks8995_get_revision(struct ks8995_switch *ks)\n-{\n-\tint err;\n-\tu8 id0, id1, ksz8864_id;\n-\n-\t/* read family id */\n-\terr = ks8995_read_reg(ks, KS8995_REG_ID0, \u0026id0);\n-\tif (err) {\n-\t\terr = -EIO;\n-\t\tgoto err_out;\n-\t}\n-\n-\t/* verify family id */\n-\tif (id0 != ks-\u003echip-\u003efamily_id) {\n-\t\tdev_err(\u0026ks-\u003espi-\u003edev, \"chip family id mismatch: expected 0x%02x but 0x%02x read\\n\",\n-\t\t\tks-\u003echip-\u003efamily_id, id0);\n-\t\terr = -ENODEV;\n-\t\tgoto err_out;\n-\t}\n-\n-\tswitch (ks-\u003echip-\u003efamily_id) {\n-\tcase FAMILY_KS8995:\n-\t\t/* try reading chip id at CHIP ID1 */\n-\t\terr = ks8995_read_reg(ks, KS8995_REG_ID1, \u0026id1);\n-\t\tif (err) {\n-\t\t\terr = -EIO;\n-\t\t\tgoto err_out;\n-\t\t}\n-\n-\t\t/* verify chip id */\n-\t\tif ((get_chip_id(id1) == CHIPID_M) \u0026\u0026\n-\t\t    (get_chip_id(id1) == ks-\u003echip-\u003echip_id)) {\n-\t\t\t/* KS8995MA */\n-\t\t\tks-\u003erevision_id = get_chip_rev(id1);\n-\t\t} else if (get_chip_id(id1) != CHIPID_M) {\n-\t\t\t/* KSZ8864RMN */\n-\t\t\terr = ks8995_read_reg(ks, KS8995_REG_ID1, \u0026ksz8864_id);\n-\t\t\tif (err) {\n-\t\t\t\terr = -EIO;\n-\t\t\t\tgoto err_out;\n-\t\t\t}\n-\n-\t\t\tif ((ksz8864_id \u0026 0x80) \u0026\u0026\n-\t\t\t    (ks-\u003echip-\u003echip_id == KSZ8864_CHIP_ID)) {\n-\t\t\t\tks-\u003erevision_id = get_chip_rev(id1);\n-\t\t\t}\n-\n-\t\t} else {\n-\t\t\tdev_err(\u0026ks-\u003espi-\u003edev, \"unsupported chip id for KS8995 family: 0x%02x\\n\",\n-\t\t\t\tid1);\n-\t\t\terr = -ENODEV;\n-\t\t}\n-\t\tbreak;\n-\tcase FAMILY_KSZ8795:\n-\t\t/* try reading chip id at CHIP ID1 */\n-\t\terr = ks8995_read_reg(ks, KS8995_REG_ID1, \u0026id1);\n-\t\tif (err) {\n-\t\t\terr = -EIO;\n-\t\t\tgoto err_out;\n-\t\t}\n-\n-\t\tif (get_chip_id(id1) == ks-\u003echip-\u003echip_id) {\n-\t\t\tks-\u003erevision_id = get_chip_rev(id1);\n-\t\t} else {\n-\t\t\tdev_err(\u0026ks-\u003espi-\u003edev, \"unsupported chip id for KSZ8795 family: 0x%02x\\n\",\n-\t\t\t\tid1);\n-\t\t\terr = -ENODEV;\n-\t\t}\n-\t\tbreak;\n-\tdefault:\n-\t\tdev_err(\u0026ks-\u003espi-\u003edev, \"unsupported family id: 0x%02x\\n\", id0);\n-\t\terr = -ENODEV;\n-\t\tbreak;\n-\t}\n-err_out:\n-\treturn err;\n-}\n-\n-static int ks8995_check_config(struct ks8995_switch *ks)\n-{\n-\tint ret;\n-\tu8 val;\n-\n-\tret = ks8995_read_reg(ks, KS8995_REG_GC0, \u0026val);\n-\tif (ret) {\n-\t\tdev_err(ks-\u003edev, \"failed to read KS8995_REG_GC0\\n\");\n-\t\treturn ret;\n-\t}\n-\n-\tdev_dbg(ks-\u003edev, \"port 5 PHY %senabled\\n\",\n-\t\t(val \u0026 KS8995_GC0_P5_PHY) ? \"\" : \"not \");\n-\n-\tval |= KS8995_GC0_P5_PHY;\n-\tret = ks8995_write_reg(ks, KS8995_REG_GC0, val);\n-\tif (ret)\n-\t\tdev_err(ks-\u003edev, \"failed to set KS8995_REG_GC0\\n\");\n-\n-\tdev_dbg(ks-\u003edev, \"set KS8995_REG_GC0 to 0x%02x\\n\", val);\n-\n-\treturn 0;\n-}\n-\n-static void\n-ks8995_mac_config(struct phylink_config *config, unsigned int mode,\n-\t\t  const struct phylink_link_state *state)\n-{\n-}\n-\n-static void\n-ks8995_mac_link_up(struct phylink_config *config, struct phy_device *phydev,\n-\t\t   unsigned int mode, phy_interface_t interface,\n-\t\t   int speed, int duplex, bool tx_pause, bool rx_pause)\n-{\n-\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n-\tstruct ks8995_switch *ks = dp-\u003eds-\u003epriv;\n-\tint port = dp-\u003eindex;\n-\tint ret;\n-\tu8 val;\n-\n-\t/* Allow forcing the mode on the fixed CPU port, no autonegotiation.\n-\t * We assume autonegotiation works on the PHY-facing ports.\n-\t */\n-\tif (port != KS8995_CPU_PORT)\n-\t\treturn;\n-\n-\tdev_dbg(ks-\u003edev, \"MAC link up on CPU port (%d)\\n\", port);\n-\n-\tret = ks8995_read_reg(ks, KS8995_REG_GC4, \u0026val);\n-\tif (ret) {\n-\t\tdev_err(ks-\u003edev, \"failed to read KS8995_REG_GC4\\n\");\n-\t\treturn;\n-\t}\n-\n-\t/* Conjure port config */\n-\tswitch (speed) {\n-\tcase SPEED_10:\n-\t\tdev_dbg(ks-\u003edev, \"set switch MII to 100Mbit mode\\n\");\n-\t\tval |= KS8995_GC4_10BT;\n-\t\tbreak;\n-\tcase SPEED_100:\n-\tdefault:\n-\t\tdev_dbg(ks-\u003edev, \"set switch MII to 100Mbit mode\\n\");\n-\t\tval \u0026= ~KS8995_GC4_10BT;\n-\t\tbreak;\n-\t}\n-\n-\tif (duplex == DUPLEX_HALF) {\n-\t\tdev_dbg(ks-\u003edev, \"set switch MII to half duplex\\n\");\n-\t\tval |= KS8995_GC4_MII_HD;\n-\t} else {\n-\t\tdev_dbg(ks-\u003edev, \"set switch MII to full duplex\\n\");\n-\t\tval \u0026= ~KS8995_GC4_MII_HD;\n-\t}\n-\n-\tdev_dbg(ks-\u003edev, \"set KS8995_REG_GC4 to %02x\\n\", val);\n-\n-\t/* Enable the CPU port */\n-\tret = ks8995_write_reg(ks, KS8995_REG_GC4, val);\n-\tif (ret)\n-\t\tdev_err(ks-\u003edev, \"failed to set KS8995_REG_GC4\\n\");\n-}\n-\n-static void\n-ks8995_mac_link_down(struct phylink_config *config, unsigned int mode,\n-\t\t     phy_interface_t interface)\n-{\n-\tstruct dsa_port *dp = dsa_phylink_to_port(config);\n-\tstruct ks8995_switch *ks = dp-\u003eds-\u003epriv;\n-\tint port = dp-\u003eindex;\n-\n-\tif (port != KS8995_CPU_PORT)\n-\t\treturn;\n-\n-\tdev_dbg(ks-\u003edev, \"MAC link down on CPU port (%d)\\n\", port);\n-\n-\t/* Disable the CPU port */\n-}\n-\n-static const struct phylink_mac_ops ks8995_phylink_mac_ops = {\n-\t.mac_config = ks8995_mac_config,\n-\t.mac_link_up = ks8995_mac_link_up,\n-\t.mac_link_down = ks8995_mac_link_down,\n-};\n-\n-static enum\n-dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds,\n-\t\t\t\t\t int port,\n-\t\t\t\t\t enum dsa_tag_protocol mp)\n-{\n-\t/* This switch actually uses the 6 byte KS8995 protocol */\n-\treturn DSA_TAG_PROTO_NONE;\n-}\n-\n-static int ks8995_setup(struct dsa_switch *ds)\n-{\n-\treturn 0;\n-}\n-\n-static int ks8995_port_enable(struct dsa_switch *ds, int port,\n-\t\t\t      struct phy_device *phy)\n-{\n-\tstruct ks8995_switch *ks = ds-\u003epriv;\n-\n-\tdev_dbg(ks-\u003edev, \"enable port %d\\n\", port);\n-\n-\treturn 0;\n-}\n-\n-static void ks8995_port_disable(struct dsa_switch *ds, int port)\n-{\n-\tstruct ks8995_switch *ks = ds-\u003epriv;\n-\n-\tdev_dbg(ks-\u003edev, \"disable port %d\\n\", port);\n-}\n-\n-static int ks8995_port_pre_bridge_flags(struct dsa_switch *ds, int port,\n-\t\t\t\t\tstruct switchdev_brport_flags flags,\n-\t\t\t\t\tstruct netlink_ext_ack *extack)\n-{\n-\t/* We support enabling/disabling learning */\n-\tif (flags.mask \u0026 ~(BR_LEARNING))\n-\t\treturn -EINVAL;\n-\n-\treturn 0;\n-}\n-\n-static int ks8995_port_bridge_flags(struct dsa_switch *ds, int port,\n-\t\t\t\t    struct switchdev_brport_flags flags,\n-\t\t\t\t    struct netlink_ext_ack *extack)\n-{\n-\tstruct ks8995_switch *ks = ds-\u003epriv;\n-\tint ret;\n-\tu8 val;\n-\n-\tif (flags.mask \u0026 BR_LEARNING) {\n-\t\tret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), \u0026val);\n-\t\tif (ret) {\n-\t\t\tdev_err(ks-\u003edev, \"failed to read KS8995_REG_PC2 on port %d\\n\", port);\n-\t\t\treturn ret;\n-\t\t}\n-\n-\t\tif (flags.val \u0026 BR_LEARNING)\n-\t\t\tval \u0026= ~KS8995_PC2_LEARN_DIS;\n-\t\telse\n-\t\t\tval |= KS8995_PC2_LEARN_DIS;\n-\n-\t\tret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val);\n-\t\tif (ret) {\n-\t\t\tdev_err(ks-\u003edev, \"failed to write KS8995_REG_PC2 on port %d\\n\", port);\n-\t\t\treturn ret;\n-\t\t}\n-\t}\n-\n-\treturn 0;\n-}\n-\n-static void ks8995_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)\n-{\n-\tstruct ks8995_switch *ks = ds-\u003epriv;\n-\tint ret;\n-\tu8 val;\n-\n-\tret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), \u0026val);\n-\tif (ret) {\n-\t\tdev_err(ks-\u003edev, \"failed to read KS8995_REG_PC2 on port %d\\n\", port);\n-\t\treturn;\n-\t}\n-\n-\t/* Set the bits for the different STP states in accordance with\n-\t * the datasheet, pages 36-37 \"Spanning tree support\".\n-\t */\n-\tswitch (state) {\n-\tcase BR_STATE_DISABLED:\n-\tcase BR_STATE_BLOCKING:\n-\tcase BR_STATE_LISTENING:\n-\t\tval \u0026= ~KS8995_PC2_TXEN;\n-\t\tval \u0026= ~KS8995_PC2_RXEN;\n-\t\tval |= KS8995_PC2_LEARN_DIS;\n-\t\tbreak;\n-\tcase BR_STATE_LEARNING:\n-\t\tval \u0026= ~KS8995_PC2_TXEN;\n-\t\tval \u0026= ~KS8995_PC2_RXEN;\n-\t\tval \u0026= ~KS8995_PC2_LEARN_DIS;\n-\t\tbreak;\n-\tcase BR_STATE_FORWARDING:\n-\t\tval |= KS8995_PC2_TXEN;\n-\t\tval |= KS8995_PC2_RXEN;\n-\t\tval \u0026= ~KS8995_PC2_LEARN_DIS;\n-\t\tbreak;\n-\tdefault:\n-\t\tdev_err(ks-\u003edev, \"unknown bridge state requested\\n\");\n-\t\treturn;\n-\t}\n-\n-\tret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val);\n-\tif (ret) {\n-\t\tdev_err(ks-\u003edev, \"failed to write KS8995_REG_PC2 on port %d\\n\", port);\n-\t\treturn;\n-\t}\n-\n-\tdev_dbg(ks-\u003edev, \"set KS8995_REG_PC2 for port %d to %02x\\n\", port, val);\n-}\n-\n-static void ks8995_phylink_get_caps(struct dsa_switch *dsa, int port,\n-\t\t\t\t    struct phylink_config *config)\n-{\n-\tunsigned long *interfaces = config-\u003esupported_interfaces;\n-\n-\tif (port == KS8995_CPU_PORT)\n-\t\t__set_bit(PHY_INTERFACE_MODE_MII, interfaces);\n-\n-\tif (port \u003c= 3) {\n-\t\t/* Internal PHYs */\n-\t\t__set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);\n-\t\t/* phylib default */\n-\t\t__set_bit(PHY_INTERFACE_MODE_MII, interfaces);\n-\t}\n-\n-\tconfig-\u003emac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;\n-}\n-\n-/* Huge packet support up to 1916 byte packages \"inclusive\"\n- * which means that tags are included. If the bit is not set\n- * it is 1536 bytes \"inclusive\". We present the length without\n- * tags or ethernet headers. The setting affects all ports.\n- */\n-static int ks8995_change_mtu(struct dsa_switch *ds, int port, int new_mtu)\n-{\n-\tstruct ks8995_switch *ks = ds-\u003epriv;\n-\tunsigned int max_mtu;\n-\tint ret;\n-\tu8 val;\n-\tint i;\n-\n-\tks-\u003emax_mtu[port] = new_mtu;\n-\n-\t/* Roof out the MTU for the entire switch to the greatest\n-\t * common denominator: the biggest set for any one port will\n-\t * be the biggest MTU for the switch.\n-\t */\n-\tmax_mtu = ETH_DATA_LEN;\n-\tfor (i = 0; i \u003c KS8995_NUM_PORTS; i++) {\n-\t\tif (ks-\u003emax_mtu[i] \u003e max_mtu)\n-\t\t\tmax_mtu = ks-\u003emax_mtu[i];\n-\t}\n-\n-\t/* Translate to layer 2 size.\n-\t * Add ethernet and (possible) VLAN headers, and checksum to the size.\n-\t * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes.\n-\t */\n-\tmax_mtu += VLAN_ETH_HLEN;\n-\tmax_mtu += ETH_FCS_LEN;\n-\n-\tret = ks8995_read_reg(ks, KS8995_REG_GC2, \u0026val);\n-\tif (ret) {\n-\t\tdev_err(ks-\u003edev, \"failed to read KS8995_REG_GC2\\n\");\n-\t\treturn ret;\n-\t}\n-\n-\tif (max_mtu \u003c= 1522) {\n-\t\tval \u0026= ~KS8995_GC2_HUGE;\n-\t\tval \u0026= ~KS8995_GC2_LEGAL;\n-\t} else if (max_mtu \u003e 1522 \u0026\u0026 max_mtu \u003c= 1536) {\n-\t\t/* This accepts packets up to 1536 bytes */\n-\t\tval \u0026= ~KS8995_GC2_HUGE;\n-\t\tval |= KS8995_GC2_LEGAL;\n-\t} else {\n-\t\t/* This accepts packets up to 1916 bytes */\n-\t\tval |= KS8995_GC2_HUGE;\n-\t\tval |= KS8995_GC2_LEGAL;\n-\t}\n-\n-\tdev_dbg(ks-\u003edev, \"new max MTU %d bytes (inclusive)\\n\", max_mtu);\n-\n-\tret = ks8995_write_reg(ks, KS8995_REG_GC2, val);\n-\tif (ret)\n-\t\tdev_err(ks-\u003edev, \"failed to set KS8995_REG_GC2\\n\");\n-\n-\treturn ret;\n-}\n-\n-static int ks8995_get_max_mtu(struct dsa_switch *ds, int port)\n-{\n-\treturn 1916 - ETH_HLEN - ETH_FCS_LEN;\n-}\n-\n-static const struct dsa_switch_ops ks8995_ds_ops = {\n-\t.get_tag_protocol = ks8995_get_tag_protocol,\n-\t.setup = ks8995_setup,\n-\t.port_pre_bridge_flags = ks8995_port_pre_bridge_flags,\n-\t.port_bridge_flags = ks8995_port_bridge_flags,\n-\t.port_enable = ks8995_port_enable,\n-\t.port_disable = ks8995_port_disable,\n-\t.port_stp_state_set = ks8995_port_stp_state_set,\n-\t.port_change_mtu = ks8995_change_mtu,\n-\t.port_max_mtu = ks8995_get_max_mtu,\n-\t.phylink_get_caps = ks8995_phylink_get_caps,\n-};\n-\n-/* ------------------------------------------------------------------------ */\n-static int ks8995_probe(struct spi_device *spi)\n-{\n-\tstruct ks8995_switch *ks;\n-\tint err;\n-\tint variant = spi_get_device_id(spi)-\u003edriver_data;\n-\n-\tif (variant \u003e= max_variant) {\n-\t\tdev_err(\u0026spi-\u003edev, \"bad chip variant %d\\n\", variant);\n-\t\treturn -ENODEV;\n-\t}\n-\n-\tks = devm_kzalloc(\u0026spi-\u003edev, sizeof(*ks), GFP_KERNEL);\n-\tif (!ks)\n-\t\treturn -ENOMEM;\n-\n-\tmutex_init(\u0026ks-\u003elock);\n-\tks-\u003espi = spi;\n-\tks-\u003edev = \u0026spi-\u003edev;\n-\tks-\u003echip = \u0026ks8995_chip[variant];\n-\n-\tks-\u003ereset_gpio = devm_gpiod_get_optional(\u0026spi-\u003edev, \"reset\",\n-\t\t\t\t\t\t GPIOD_OUT_HIGH);\n-\terr = PTR_ERR_OR_ZERO(ks-\u003ereset_gpio);\n-\tif (err) {\n-\t\tdev_err(\u0026spi-\u003edev,\n-\t\t\t\"failed to get reset gpio: %d\\n\", err);\n-\t\treturn err;\n-\t}\n-\n-\terr = gpiod_set_consumer_name(ks-\u003ereset_gpio, \"switch-reset\");\n-\tif (err)\n-\t\treturn err;\n-\n-\tif (ks-\u003ereset_gpio) {\n-\t\t/*\n-\t\t * If a reset line was obtained, wait for 100us after\n-\t\t * de-asserting RESET before accessing any registers, see\n-\t\t * the KS8995MA datasheet, page 44.\n-\t\t */\n-\t\tgpiod_set_value_cansleep(ks-\u003ereset_gpio, 0);\n-\t\tudelay(100);\n-\t}\n-\n-\tspi_set_drvdata(spi, ks);\n-\n-\tspi-\u003emode = SPI_MODE_0;\n-\tspi-\u003ebits_per_word = 8;\n-\terr = spi_setup(spi);\n-\tif (err) {\n-\t\tdev_err(\u0026spi-\u003edev, \"spi_setup failed, err=%d\\n\", err);\n-\t\treturn err;\n-\t}\n-\n-\terr = ks8995_get_revision(ks);\n-\tif (err)\n-\t\treturn err;\n-\n-\terr = ks8995_reset(ks);\n-\tif (err)\n-\t\treturn err;\n-\n-\tdev_info(\u0026spi-\u003edev, \"%s device found, Chip ID:%x, Revision:%x\\n\",\n-\t\t ks-\u003echip-\u003ename, ks-\u003echip-\u003echip_id, ks-\u003erevision_id);\n-\n-\terr = ks8995_check_config(ks);\n-\tif (err)\n-\t\treturn err;\n-\n-\tks-\u003eds = devm_kzalloc(\u0026spi-\u003edev, sizeof(*ks-\u003eds), GFP_KERNEL);\n-\tif (!ks-\u003eds)\n-\t\treturn -ENOMEM;\n-\n-\tks-\u003eds-\u003edev = \u0026spi-\u003edev;\n-\tks-\u003eds-\u003enum_ports = KS8995_NUM_PORTS;\n-\tks-\u003eds-\u003eops = \u0026ks8995_ds_ops;\n-\tks-\u003eds-\u003ephylink_mac_ops = \u0026ks8995_phylink_mac_ops;\n-\tks-\u003eds-\u003epriv = ks;\n-\n-\terr = dsa_register_switch(ks-\u003eds);\n-\tif (err)\n-\t\treturn dev_err_probe(\u0026spi-\u003edev, err,\n-\t\t\t\t     \"unable to register DSA switch\\n\");\n-\n-\treturn 0;\n-}\n-\n-static void ks8995_remove(struct spi_device *spi)\n-{\n-\tstruct ks8995_switch *ks = spi_get_drvdata(spi);\n-\n-\tdsa_unregister_switch(ks-\u003eds);\n-\t/* assert reset */\n-\tgpiod_set_value_cansleep(ks-\u003ereset_gpio, 1);\n-}\n-\n-/* ------------------------------------------------------------------------ */\n-static struct spi_driver ks8995_driver = {\n-\t.driver = {\n-\t\t.name\t    = \"spi-ks8995\",\n-\t\t.of_match_table = ks8995_spi_of_match,\n-\t},\n-\t.probe\t  = ks8995_probe,\n-\t.remove\t  = ks8995_remove,\n-\t.id_table = ks8995_id,\n-};\n-\n-module_spi_driver(ks8995_driver);\n-\n-MODULE_DESCRIPTION(DRV_DESC);\n-MODULE_VERSION(DRV_VERSION);\n-MODULE_AUTHOR(\"Gabor Juhos \u003cjuhosg at openwrt.org\u003e\");\n-MODULE_LICENSE(\"GPL v2\");\ndiff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig\nindex c71d3fd5dfeb8..75c9b2114afd3 100644\n--- a/drivers/net/dsa/microchip/Kconfig\n+++ b/drivers/net/dsa/microchip/Kconfig\n@@ -2,6 +2,7 @@\n menuconfig NET_DSA_MICROCHIP_KSZ_COMMON\n \ttristate \"Microchip KSZ8XXX/KSZ9XXX/LAN937X series switch support\"\n \tdepends on NET_DSA\n+\tselect NET_DSA_TAG_KS8995\n \tselect NET_DSA_TAG_KSZ\n \tselect NET_DSA_TAG_NONE\n \tselect NET_IEEE8021Q_HELPERS\ndiff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c\nindex 941ae9f66f70b..c3871d5d6d367 100644\n--- a/drivers/net/dsa/microchip/ksz8.c\n+++ b/drivers/net/dsa/microchip/ksz8.c\n@@ -3,6 +3,7 @@\n  * Microchip KSZ8XXX series switch driver\n  *\n  * It supports the following switches:\n+ * - KSZ8995XA (the oldest ancestor)\n  * - KSZ8463\n  * - KSZ8863, KSZ8873 aka KSZ88X3\n  * - KSZ8895, KSZ8864 aka KSZ8895 family\n@@ -20,6 +21,7 @@\n #include \u003clinux/export.h\u003e\n #include \u003clinux/gpio/consumer.h\u003e\n #include \u003clinux/if_vlan.h\u003e\n+#include \u003clinux/iopoll.h\u003e\n #include \u003clinux/kernel.h\u003e\n #include \u003clinux/module.h\u003e\n #include \u003clinux/platform_data/microchip-ksz.h\u003e\n@@ -253,7 +255,35 @@ static int ksz8463_reset_switch(struct ksz_device *dev)\n \n static int ksz8_reset_switch(struct ksz_device *dev)\n {\n-\tif (ksz_is_ksz88x3(dev)) {\n+\tif (ksz_is_ksz8995xa(dev)) {\n+\t\tunsigned int port, reg, val;\n+\t\tint ret;\n+\n+\t\t/* The KSZ8995XA switch itself cannot be reset by software, but\n+\t\t * often boot loaders have fun with ports, so reset them. This\n+\t\t * reset bit is self-clearing.\n+\t\t */\n+\t\tfor (port = 0; port \u003c dev-\u003einfo-\u003eport_cnt; port++) {\n+\t\t\tret = ksz_prmw8(dev, port, REG_PORT_STATUS_3,\n+\t\t\t\t\tPORT_PHY_SOFT_RESET,\n+\t\t\t\t\tPORT_PHY_SOFT_RESET);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n+\t\t/* IEEE 802.3 allows up to 500 ms for a PHY reset. */\n+\t\tfor (port = 0; port \u003c dev-\u003einfo-\u003eport_cnt; port++) {\n+\t\t\treg = dev-\u003edev_ops-\u003eget_port_addr(port, REG_PORT_STATUS_3);\n+\t\t\tret = regmap_read_poll_timeout(ksz_regmap_8(dev), reg, val,\n+\t\t\t\t\t\t       !(val \u0026 PORT_PHY_SOFT_RESET),\n+\t\t\t\t\t\t       1000, 600000);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n+\t\t/* Some PHYs need additional settling time after reset. */\n+\t\tusleep_range(1000, 2000);\n+\t} else if (ksz_is_ksz88x3(dev)) {\n \t\t/* reset switch */\n \t\tksz_cfg(dev, KSZ8863_REG_SW_RESET,\n \t\t\tKSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true);\n@@ -269,6 +299,31 @@ static int ksz8_reset_switch(struct ksz_device *dev)\n \treturn 0;\n }\n \n+static int ksz8995xa_change_mtu(struct dsa_switch *ds, int port, int mtu)\n+{\n+\tstruct ksz_device *dev = ds-\u003epriv;\n+\tint frame_size;\n+\tu8 ctrl2 = 0;\n+\n+\tif (!dsa_is_cpu_port(dev-\u003eds, port))\n+\t\treturn 0;\n+\n+\tframe_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;\n+\n+\t/* The legal packet size bit polarity documented in the KSZ8995XA\n+\t * manual appears to be wrong. Practical tests show that the same\n+\t * semantics as the other switches are correct; using the documented\n+\t * polarity makes the switch hang on big packets.\n+\t */\n+\tif (frame_size \u003c= KSZ8995XA_LEGAL_PACKET_SIZE)\n+\t\tctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE;\n+\telse if (frame_size \u003e KSZ8863_NORMAL_PACKET_SIZE)\n+\t\tctrl2 |= KSZ8863_HUGE_PACKET_ENABLE;\n+\n+\treturn ksz_rmw8(dev, REG_SW_CTRL_2, KSZ8863_LEGAL_PACKET_ENABLE |\n+\t\t\tKSZ8863_HUGE_PACKET_ENABLE, ctrl2);\n+}\n+\n static int ksz88xx_change_mtu(struct dsa_switch *ds, int port, int mtu)\n {\n \tstruct ksz_device *dev = ds-\u003epriv;\n@@ -325,8 +380,8 @@ static int ksz88xx_max_mtu(struct dsa_switch *ds, int port)\n \n static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)\n {\n-\tu8 mask_4q, mask_2q;\n-\tu8 reg_4q, reg_2q;\n+\tu8 mask_4q = 0, mask_2q;\n+\tu8 reg_4q = 0, reg_2q;\n \tu8 data_4q = 0;\n \tu8 data_2q = 0;\n \tint ret;\n@@ -352,6 +407,10 @@ static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)\n \t\tmask_2q = KSZ8873_PORT_2QUEUE_SPLIT_EN;\n \t\treg_4q = P1CR1;\n \t\treg_2q = P1CR1 + 1;\n+\t} else if (ksz_is_ksz8995xa(dev)) {\n+\t\t/* This switch has no 4way split support */\n+\t\tmask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;\n+\t\treg_2q = REG_PORT_CTRL_0;\n \t} else {\n \t\tmask_4q = KSZ8795_PORT_4QUEUE_SPLIT_EN;\n \t\tmask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;\n@@ -373,9 +432,11 @@ static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)\n \telse if (queues == 2)\n \t\tdata_2q = mask_2q;\n \n-\tret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);\n-\tif (ret)\n-\t\treturn ret;\n+\tif (mask_4q) {\n+\t\tret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n \n \treturn ksz_prmw8(dev, port, reg_2q, mask_2q, data_2q);\n }\n@@ -970,6 +1031,10 @@ static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)\n \tif (reg_val \u0026 PORT_MDIX_STATUS)\n \t\t*val |= KSZ886X_CTRL_MDIX_STAT;\n \n+\t/* KSZ8995XA has no fancy features in register 0xA */\n+\tif (ksz_is_ksz8995xa(dev))\n+\t\treturn 0;\n+\n \tret = ksz_pread8(dev, port, REG_PORT_LINK_MD_CTRL, \u0026reg_val);\n \tif (ret \u003c 0)\n \t\treturn ret;\n@@ -1068,8 +1133,10 @@ static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val)\n \tif (ctrl \u0026 PORT_FORCE_FULL_DUPLEX)\n \t\t*val |= BMCR_FULLDPLX;\n \n-\tif (speed \u0026 PORT_HP_MDIX)\n-\t\t*val |= KSZ886X_BMCR_HP_MDIX;\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\tif (speed \u0026 PORT_HP_MDIX)\n+\t\t\t*val |= KSZ886X_BMCR_HP_MDIX;\n+\t}\n \n \tif (restart \u0026 PORT_FORCE_MDIX)\n \t\t*val |= KSZ886X_BMCR_FORCE_MDI;\n@@ -1164,6 +1231,9 @@ static int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)\n \t\t\tdata |= LPA_LPACK;\n \t\tbreak;\n \tcase PHY_REG_LINK_MD:\n+\t\tif (ksz_is_ksz8995xa(dev))\n+\t\t\treturn -EOPNOTSUPP;\n+\n \t\tret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, \u0026val1);\n \t\tif (ret)\n \t\t\treturn ret;\n@@ -1307,13 +1377,15 @@ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val)\n \tif (val \u0026 BMCR_RESET)\n \t\treturn 0;\n \n-\tspeed = 0;\n-\tif (val \u0026 KSZ886X_BMCR_HP_MDIX)\n-\t\tspeed |= PORT_HP_MDIX;\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\tspeed = 0;\n+\t\tif (val \u0026 KSZ886X_BMCR_HP_MDIX)\n+\t\t\tspeed |= PORT_HP_MDIX;\n \n-\tret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed);\n-\tif (ret)\n-\t\treturn ret;\n+\t\tret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n \n \tctrl = 0;\n \tif (ksz_is_ksz88x3(dev)) {\n@@ -1423,11 +1495,17 @@ static int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)\n \t\t}\n \t\tbreak;\n \tcase PHY_REG_LINK_MD:\n+\t\tif (ksz_is_ksz8995xa(dev))\n+\t\t\treturn -EOPNOTSUPP;\n+\n \t\tif (val \u0026 PHY_START_CABLE_DIAG)\n \t\t\tksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);\n \t\tbreak;\n \n \tcase PHY_REG_PHY_CTRL:\n+\t\tif (ksz_is_ksz8995xa(dev))\n+\t\t\treturn -EOPNOTSUPP;\n+\n \t\tret = ksz8_w_phy_ctrl(dev, p, val);\n \t\tif (ret)\n \t\t\treturn ret;\n@@ -2043,12 +2121,14 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)\n \n \tksz8_port_queue_split(dev, port, dev-\u003einfo-\u003enum_tx_queues);\n \n-\t/* replace priority */\n-\toffset = P_802_1P_CTRL;\n-\tif (ksz_is_ksz8463(dev))\n-\t\toffset = P1CR2;\n-\tksz_port_cfg(dev, port, offset,\n-\t\t     masks[PORT_802_1P_REMAPPING], false);\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\t/* replace priority */\n+\t\toffset = P_802_1P_CTRL;\n+\t\tif (ksz_is_ksz8463(dev))\n+\t\t\toffset = P1CR2;\n+\t\tksz_port_cfg(dev, port, offset,\n+\t\t\t     masks[PORT_802_1P_REMAPPING], false);\n+\t}\n \n \tif (cpu_port)\n \t\tmember = dsa_user_ports(ds);\n@@ -2057,6 +2137,21 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)\n \n \tksz8_cfg_port_member(dev, port, member);\n \n+\tif (ksz_is_ksz8995xa(dev)) {\n+\t\t/* Use VID 0 to identify untagged frames in the special tag */\n+\t\tksz_pwrite16(dev, port, REG_PORT_CTRL_VID, 0);\n+\n+\t\t/* The KSZ8995XA has a special tag format in the front of the frame\n+\t\t * that need to be inserted by the CPU and then removed by each\n+\t\t * port. PORT_REMOVE_TAG simply means \"remove tags coming from the\n+\t\t * CPU port\" it does not affect ingress packets.\n+\t\t */\n+\t\tif (cpu_port)\n+\t\t\tksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_INSERT_TAG, true);\n+\t\telse\n+\t\t\tksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_REMOVE_TAG, true);\n+\t}\n+\n \t/* Disable all WoL options by default. Otherwise\n \t * ksz_switch_macaddr_get/put logic will not work properly.\n \t * CPU port 4 has no WoL functionality.\n@@ -2073,6 +2168,7 @@ static int ksz8_dsa_port_setup(struct dsa_switch *ds, int port)\n \t\treturn 0;\n \n \tksz8_port_setup(dev, port, false);\n+\n \treturn ksz_dcb_init_port(dev, port);\n }\n \n@@ -2147,7 +2243,9 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)\n \tmasks = dev-\u003einfo-\u003emasks;\n \tregs = dev-\u003einfo-\u003eregs;\n \n-\tksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);\n+\t/* KSZ8995XA uses a tag in the header instead of the tail */\n+\tif (!ksz_is_ksz8995xa(dev))\n+\t\tksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);\n \n \tksz8_port_setup(dev, dev-\u003ecpu_port, true);\n \n@@ -2323,6 +2421,10 @@ static int ksz8_enable_stp_addr(struct ksz_device *dev)\n {\n \tstruct alu_struct alu;\n \n+\t/* KSZ8995XA lacks STP */\n+\tif (ksz_is_ksz8995xa(dev))\n+\t\treturn 0;\n+\n \t/* Setup STP address for STP operation. */\n \tmemset(\u0026alu, 0, sizeof(alu));\n \tether_addr_copy(alu.mac, eth_stp_addr);\n@@ -2650,13 +2752,17 @@ static int ksz8_setup(struct dsa_switch *ds)\n \tstruct ksz_port *p;\n \tconst u16 *regs;\n \tint i, ret;\n+\tu8 val;\n \n \tregs = dev-\u003einfo-\u003eregs;\n \n-\tdev-\u003evlan_cache = devm_kcalloc(dev-\u003edev, sizeof(struct vlan_table),\n-\t\t\t\t       dev-\u003einfo-\u003enum_vlans, GFP_KERNEL);\n-\tif (!dev-\u003evlan_cache)\n-\t\treturn -ENOMEM;\n+\t/* KSZ8995XA has no SW controlled VLAN handling */\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\tdev-\u003evlan_cache = devm_kcalloc(dev-\u003edev, sizeof(struct vlan_table),\n+\t\t\t\t\t       dev-\u003einfo-\u003enum_vlans, GFP_KERNEL);\n+\t\tif (!dev-\u003evlan_cache)\n+\t\t\treturn -ENOMEM;\n+\t}\n \n \tret = ksz8_reset_switch(dev);\n \tif (ret) {\n@@ -2685,19 +2791,22 @@ static int ksz8_setup(struct dsa_switch *ds)\n \n \tksz_init_mib_timer(dev);\n \n-\tds-\u003econfigure_vlan_while_not_filtering = false;\n \tds-\u003edscp_prio_mapping_is_global = true;\n \tds-\u003emtu_enforcement_ingress = true;\n \n-\t/* We rely on software untagging on the CPU port, so that we\n-\t * can support both tagged and untagged VLANs\n-\t */\n-\tds-\u003euntag_bridge_pvid = true;\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\tds-\u003econfigure_vlan_while_not_filtering = false;\n \n-\t/* VLAN filtering is partly controlled by the global VLAN\n-\t * Enable flag\n-\t */\n-\tds-\u003evlan_filtering_is_global = true;\n+\t\t/* We rely on software untagging on the CPU port, so that we\n+\t\t * can support both tagged and untagged VLANs\n+\t\t */\n+\t\tds-\u003euntag_bridge_pvid = true;\n+\n+\t\t/* VLAN filtering is partly controlled by the global VLAN\n+\t\t * Enable flag\n+\t\t */\n+\t\tds-\u003evlan_filtering_is_global = true;\n+\t}\n \n \t/* Enable automatic fast aging when link changed detected. */\n \tksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);\n@@ -2711,9 +2820,10 @@ static int ksz8_setup(struct dsa_switch *ds)\n \t * Make sure unicast VLAN boundary is set as default and\n \t * enable no excessive collision drop.\n \t */\n-\tret = ksz_rmw8(dev, REG_SW_CTRL_2,\n-\t\t       UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,\n-\t\t       UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);\n+\tval = NO_EXC_COLLISION_DROP;\n+\tif (!ksz_is_ksz8995xa(dev))\n+\t\tval |= UNICAST_VLAN_BOUNDARY;\n+\tret = ksz_rmw8(dev, REG_SW_CTRL_2, val, val);\n \tif (ret)\n \t\treturn ret;\n \n@@ -2721,11 +2831,15 @@ static int ksz8_setup(struct dsa_switch *ds)\n \n \tksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);\n \n-\tif (!ksz_is_ksz88x3(dev))\n+\tif (ksz_is_ksz8995xa(dev))\n+\t\tksz_cfg(dev, REG_SW_CTRL_9, SW_SPECIAL_TAG, true);\n+\telse if (!ksz_is_ksz88x3(dev))\n \t\tksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);\n \n-\tfor (i = 0; i \u003c (dev-\u003einfo-\u003enum_vlans / 4); i++)\n-\t\tksz8_r_vlan_entries(dev, i);\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\tfor (i = 0; i \u003c (dev-\u003einfo-\u003enum_vlans / 4); i++)\n+\t\t\tksz8_r_vlan_entries(dev, i);\n+\t}\n \n \t/* Make sure PME (WoL) is not enabled. If requested, it will\n \t * be enabled by ksz_wol_pre_shutdown(). Otherwise, some PMICs\n@@ -2976,6 +3090,13 @@ static int ksz8_switch_init(struct ksz_device *dev)\n \treturn 0;\n }\n \n+static enum dsa_tag_protocol ksz8995xa_get_tag_protocol(struct dsa_switch *ds,\n+\t\t\t\t\t\t\tint port,\n+\t\t\t\t\t\t\tenum dsa_tag_protocol mp)\n+{\n+\treturn DSA_TAG_PROTO_KS8995;\n+}\n+\n static enum dsa_tag_protocol ksz8463_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 mp)\n@@ -3072,6 +3193,16 @@ const struct phylink_mac_ops ksz8_phylink_mac_ops = {\n \t.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,\n };\n \n+/*\n+ * The KS(Z)8995XA has no indirect access, meaning no MIB counters,\n+ * no FDB access, and no VLAN handling.\n+ */\n+const struct ksz_dev_ops ksz8995xa_dev_ops = {\n+\t.get_port_addr = ksz8_get_port_addr,\n+\t.cfg_port_member = ksz8_cfg_port_member,\n+\t.init = ksz8_switch_init,\n+};\n+\n const struct ksz_dev_ops ksz8463_dev_ops = {\n \t.get_port_addr = ksz8463_get_port_addr,\n \t.cfg_port_member = ksz8_cfg_port_member,\n@@ -3111,6 +3242,38 @@ const struct ksz_dev_ops ksz88xx_dev_ops = {\n \t.pme_pwrite8 = ksz8_pme_pwrite8,\n };\n \n+/*\n+ * Restricted operations for KSZ8995XA, so many things are not supported\n+ * by this old switch that we need diet DSA operations.\n+ */\n+const struct dsa_switch_ops ksz8995xa_switch_ops = {\n+\t.get_tag_protocol\t= ksz8995xa_get_tag_protocol,\n+\t.setup\t\t\t= ksz8_setup,\n+\t.teardown\t\t= ksz_teardown,\n+\t.phy_read\t\t= ksz8_phy_read16,\n+\t.phy_write\t\t= ksz8_phy_write16,\n+\t.phylink_get_caps\t= ksz8_phylink_get_caps,\n+\t.port_setup\t\t= ksz8_dsa_port_setup,\n+\t.port_bridge_join\t= ksz_port_bridge_join,\n+\t.port_bridge_leave\t= ksz_port_bridge_leave,\n+\t.port_set_mac_address\t= ksz_port_set_mac_address,\n+\t.port_stp_state_set\t= ksz_port_stp_state_set,\n+\t.port_pre_bridge_flags\t= ksz_port_pre_bridge_flags,\n+\t.port_bridge_flags\t= ksz_port_bridge_flags,\n+\t.port_fast_age\t\t= ksz8_flush_dyn_mac_table,\n+\t.port_mirror_add\t= ksz8_port_mirror_add,\n+\t.port_mirror_del\t= ksz8_port_mirror_del,\n+\t.port_change_mtu\t= ksz8995xa_change_mtu,\n+\t.port_max_mtu\t\t= ksz88xx_max_mtu,\n+\t.port_get_default_prio\t= ksz_port_get_default_prio,\n+\t.port_set_default_prio\t= ksz_port_set_default_prio,\n+\t.port_get_dscp_prio\t= ksz_port_get_dscp_prio,\n+\t.port_add_dscp_prio\t= ksz_port_add_dscp_prio,\n+\t.port_del_dscp_prio\t= ksz_port_del_dscp_prio,\n+\t.port_get_apptrust\t= ksz_port_get_apptrust,\n+\t.port_set_apptrust\t= ksz_port_set_apptrust,\n+};\n+\n const struct dsa_switch_ops ksz8463_switch_ops = {\n \t.get_tag_protocol\t= ksz8463_get_tag_protocol,\n \t.connect_tag_protocol   = ksz8463_connect_tag_protocol,\ndiff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h\nindex bc371cc26c6f1..9b37c56c9617e 100644\n--- a/drivers/net/dsa/microchip/ksz8.h\n+++ b/drivers/net/dsa/microchip/ksz8.h\n@@ -12,11 +12,13 @@\n #include \u003cnet/dsa.h\u003e\n #include \"ksz_common.h\"\n \n+extern const struct ksz_dev_ops ksz8995xa_dev_ops;\n extern const struct ksz_dev_ops ksz8463_dev_ops;\n extern const struct ksz_dev_ops ksz87xx_dev_ops;\n extern const struct ksz_dev_ops ksz88xx_dev_ops;\n extern const struct phylink_mac_ops ksz88x3_phylink_mac_ops;\n extern const struct phylink_mac_ops ksz8_phylink_mac_ops;\n+extern const struct dsa_switch_ops ksz8995xa_switch_ops;\n extern const struct dsa_switch_ops ksz8463_switch_ops;\n extern const struct dsa_switch_ops ksz87xx_switch_ops;\n extern const struct dsa_switch_ops ksz88xx_switch_ops;\ndiff --git a/drivers/net/dsa/microchip/ksz8_reg.h b/drivers/net/dsa/microchip/ksz8_reg.h\nindex 6bc511da1f7dd..f858bce84bfd4 100644\n--- a/drivers/net/dsa/microchip/ksz8_reg.h\n+++ b/drivers/net/dsa/microchip/ksz8_reg.h\n@@ -95,6 +95,8 @@\n #define SW_LED_LINK_ACT_DUPLEX\t\t2\n #define SW_LED_LINK_DUPLEX\t\t3\n \n+#define SW_SPECIAL_TAG\t\t\tBIT(0) /* KSZ8995XA only */\n+\n #define REG_SW_CTRL_10\t\t\t0x0C\n \n #define SW_PASS_PAUSE\t\t\tBIT(0)\ndiff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c\nindex 1a9d6f83a0232..6c15ac97a7e3f 100644\n--- a/drivers/net/dsa/microchip/ksz_common.c\n+++ b/drivers/net/dsa/microchip/ksz_common.c\n@@ -446,6 +446,20 @@ static const u8 ksz8895_shifts[] = {\n \t[DYNAMIC_MAC_SRC_PORT]\t\t= 24,\n };\n \n+static const u16 ksz8995xa_regs[] = {\n+\t[REG_SW_MAC_ADDR]\t\t= 0x68,\n+\t[P_FORCE_CTRL]\t\t\t= 0x0C,\n+\t[P_LINK_STATUS]\t\t\t= 0x0E,\n+\t[P_LOCAL_CTRL]\t\t\t= 0x0C,\n+\t[P_NEG_RESTART_CTRL]\t\t= 0x0D,\n+\t[P_REMOTE_STATUS]\t\t= 0x0E,\n+\t[P_SPEED_STATUS]\t\t= 0x09,\n+\t[P_STP_CTRL]\t\t\t= 0x02,\n+\t[S_START_CTRL]\t\t\t= 0x01,\n+\t[S_BROADCAST_CTRL]\t\t= 0x06,\n+\t[S_MULTICAST_CTRL]\t\t= 0x04,\n+};\n+\n static const u16 ksz9477_regs[] = {\n \t[REG_SW_MAC_ADDR]\t\t= 0x0302,\n \t[P_STP_CTRL]\t\t\t= 0x0B04,\n@@ -1377,6 +1391,21 @@ const struct ksz_chip_data ksz_switch_chips[] = {\n \t\t.internal_phy = {true, true, true, true, false},\n \t},\n \n+\t[KSZ8995XA] = {\n+\t\t.chip_id = KSZ8995XA_CHIP_ID, /* Also known as KS8995XA */\n+\t\t.dev_name = \"KSZ8995XA\",\n+\t\t.cpu_ports = 0x10,\t/* can be configured as cpu port */\n+\t\t.port_cnt = 5,\t\t/* total cpu and user ports */\n+\t\t.num_tx_queues = 2,\t/* low/hi priority queues, no more */\n+\t\t.num_ipms = 2,\n+\t\t.ops = \u0026ksz8995xa_dev_ops,\n+\t\t.switch_ops = \u0026ksz8995xa_switch_ops,\n+\t\t.phylink_mac_ops = \u0026ksz88x3_phylink_mac_ops,\n+\t\t.regs = ksz8995xa_regs,\n+\t\t.supports_mii = {true, true, true, true, true},\n+\t\t.internal_phy = {true, true, true, true, false},\n+\t},\n+\n \t[KSZ9477] = {\n \t\t.chip_id = KSZ9477_CHIP_ID,\n \t\t.dev_name = \"KSZ9477\",\n@@ -2649,6 +2678,10 @@ void ksz_init_mib_timer(struct ksz_device *dev)\n {\n \tint i;\n \n+\t/* KSZ8995XA lacks MiB features */\n+\tif (ksz_is_ksz8995xa(dev))\n+\t\treturn;\n+\n \tINIT_DELAYED_WORK(\u0026dev-\u003emib_read, ksz_mib_read_work);\n \n \tfor (i = 0; i \u003c dev-\u003einfo-\u003eport_cnt; i++) {\n@@ -2944,11 +2977,15 @@ static int ksz_switch_detect(struct ksz_device *dev)\n \t\t\treturn -ENODEV;\n \t\tbreak;\n \tcase KSZ8895_FAMILY_ID:\n-\t\tif (id2 == KSZ8895_CHIP_ID_95 ||\n-\t\t    id2 == KSZ8895_CHIP_ID_95R)\n+\t\tif (id2 == KSZ8895_CHIP_ID_95XA) {\n+\t\t\tdev-\u003echip_id = KSZ8995XA_CHIP_ID;\n+\t\t\tbreak;\n+\t\t} else if (id2 == KSZ8895_CHIP_ID_95 ||\n+\t\t\t   id2 == KSZ8895_CHIP_ID_95R) {\n \t\t\tdev-\u003echip_id = KSZ8895_CHIP_ID;\n-\t\telse\n+\t\t} else {\n \t\t\treturn -ENODEV;\n+\t\t}\n \t\tret = ksz_read8(dev, REG_KSZ8864_CHIP_ID, \u0026id4);\n \t\tif (ret)\n \t\t\treturn ret;\n@@ -4029,11 +4066,13 @@ int ksz_switch_register(struct ksz_device *dev)\n \tif (ret)\n \t\treturn ret;\n \n-\t/* Read MIB counters every 30 seconds to avoid overflow. */\n-\tdev-\u003emib_read_interval = msecs_to_jiffies(5000);\n+\tif (!ksz_is_ksz8995xa(dev)) {\n+\t\t/* Read MIB counters every 30 seconds to avoid overflow. */\n+\t\tdev-\u003emib_read_interval = msecs_to_jiffies(5000);\n \n-\t/* Start the MIB timer. */\n-\tschedule_delayed_work(\u0026dev-\u003emib_read, 0);\n+\t\t/* Start the MIB timer. */\n+\t\tschedule_delayed_work(\u0026dev-\u003emib_read, 0);\n+\t}\n \n \treturn ret;\n }\ndiff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h\nindex cbe98494578c3..93be74f7a2658 100644\n--- a/drivers/net/dsa/microchip/ksz_common.h\n+++ b/drivers/net/dsa/microchip/ksz_common.h\n@@ -281,6 +281,7 @@ enum ksz_model {\n \tKSZ88X3,\n \tKSZ8864,\n \tKSZ8895,\n+\tKSZ8995XA,\n \tKSZ9477,\n \tKSZ9896,\n \tKSZ9897,\n@@ -789,7 +790,13 @@ static inline bool ksz_is_ksz88x3(struct ksz_device *dev)\n static inline bool ksz_is_8895_family(struct ksz_device *dev)\n {\n \treturn dev-\u003echip_id == KSZ8895_CHIP_ID ||\n-\t       dev-\u003echip_id == KSZ8864_CHIP_ID;\n+\t       dev-\u003echip_id == KSZ8864_CHIP_ID ||\n+\t       dev-\u003echip_id == KSZ8995XA_CHIP_ID;\n+}\n+\n+static inline bool ksz_is_ksz8995xa(struct ksz_device *dev)\n+{\n+\treturn dev-\u003echip_id == KSZ8995XA_CHIP_ID;\n }\n \n static inline bool is_ksz8(struct ksz_device *dev)\n@@ -860,6 +867,7 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port)\n #define KSZ87_CHIP_ID_94\t\t0x6\n #define KSZ87_CHIP_ID_95\t\t0x9\n #define KSZ88_CHIP_ID_63\t\t0x3\n+#define KSZ8895_CHIP_ID_95XA\t\t0x0\n #define KSZ8895_CHIP_ID_95\t\t0x4\n #define KSZ8895_CHIP_ID_95R\t\t0x6\n \n@@ -923,6 +931,7 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port)\n #define KSZ8863_HUGE_PACKET_SIZE\t1916\n #define KSZ8863_NORMAL_PACKET_SIZE\t1536\n #define KSZ8_LEGAL_PACKET_SIZE\t\t1518\n+#define KSZ8995XA_LEGAL_PACKET_SIZE\t1522\n #define KSZ9477_MAX_FRAME_SIZE\t\t9000\n \n #define KSZ8873_REG_GLOBAL_CTRL_12\t0x0e\ndiff --git a/drivers/net/dsa/microchip/ksz_dcb.c b/drivers/net/dsa/microchip/ksz_dcb.c\nindex 7131c5caac547..968de88e8ddd3 100644\n--- a/drivers/net/dsa/microchip/ksz_dcb.c\n+++ b/drivers/net/dsa/microchip/ksz_dcb.c\n@@ -20,10 +20,12 @@\n #define KSZ8_PORT_DIFFSERV_ENABLE\t\tBIT(6)\n #define KSZ8_PORT_802_1P_ENABLE\t\t\tBIT(5)\n #define KSZ8_PORT_BASED_PRIO_M\t\t\tGENMASK(4, 3)\n+#define KSZ8995XA_PORT_BASED_PRIO\t\tBIT(4)\n \n #define KSZ8463_REG_TOS_DSCP_CTRL\t\t0x16\n #define KSZ88X3_REG_TOS_DSCP_CTRL\t\t0x60\n #define KSZ8765_REG_TOS_DSCP_CTRL\t\t0x90\n+#define KSZ8995XA_REG_TOS_DSCP_CTRL_7\t\t0x67\n \n #define KSZ9477_REG_SW_MAC_TOS_CTRL\t\t0x033e\n #define KSZ9477_SW_TOS_DSCP_REMAP\t\tBIT(0)\n@@ -98,8 +100,11 @@ static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,\n {\n \tif (is_ksz8(dev)) {\n \t\t*reg = KSZ8_REG_PORT_1_CTRL_0;\n-\t\t*mask = KSZ8_PORT_BASED_PRIO_M;\n-\t\t*shift = __bf_shf(KSZ8_PORT_BASED_PRIO_M);\n+\t\tif (ksz_is_ksz8995xa(dev))\n+\t\t\t*mask = KSZ8995XA_PORT_BASED_PRIO;\n+\t\telse\n+\t\t\t*mask = KSZ8_PORT_BASED_PRIO_M;\n+\t\t*shift = __bf_shf(*mask);\n \t\tif (ksz_is_ksz8463(dev))\n \t\t\t*reg = KSZ8463_REG_PORT_1_CTRL_0;\n \t} else {\n@@ -112,31 +117,45 @@ static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,\n /**\n  * ksz_get_dscp_prio_reg - Retrieves the DSCP-to-priority-mapping register\n  * @dev: Pointer to the KSZ switch device structure\n+ * @dscp: DSCP value for which to retrieve the register\n  * @reg: Pointer to the register address to be set\n- * @per_reg: Pointer to the number of DSCP values per register\n  * @mask: Pointer to the mask to be set\n+ * @shift: Pointer to the bit shift to be set\n  *\n- * This function retrieves the DSCP to priority mapping register, the number of\n- * DSCP values per register, and the mask to be set.\n+ * This function retrieves the register, mask and shift for a DSCP to priority\n+ * mapping entry.\n  */\n-static void ksz_get_dscp_prio_reg(struct ksz_device *dev, int *reg,\n-\t\t\t\t  int *per_reg, u8 *mask)\n+static void ksz_get_dscp_prio_reg(struct ksz_device *dev, u8 dscp, int *reg,\n+\t\t\t\t  u8 *mask, int *shift)\n {\n+\tint per_reg;\n+\n+\tif (ksz_is_ksz8995xa(dev)) {\n+\t\t/* KSZ8995XA stores DSCP groups in descending register order. */\n+\t\t*reg = KSZ8995XA_REG_TOS_DSCP_CTRL_7 - dscp / 8;\n+\t\t*mask = BIT(0);\n+\t\t*shift = dscp % 8;\n+\t\treturn;\n+\t}\n+\n \tif (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev)) {\n \t\t*reg = KSZ8765_REG_TOS_DSCP_CTRL;\n-\t\t*per_reg = 4;\n+\t\tper_reg = 4;\n \t\t*mask = GENMASK(1, 0);\n \t} else if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) {\n \t\t*reg = KSZ88X3_REG_TOS_DSCP_CTRL;\n-\t\t*per_reg = 4;\n+\t\tper_reg = 4;\n \t\t*mask = GENMASK(1, 0);\n \t\tif (ksz_is_ksz8463(dev))\n \t\t\t*reg = KSZ8463_REG_TOS_DSCP_CTRL;\n \t} else {\n \t\t*reg = KSZ9477_REG_DIFFSERV_PRIO_MAP;\n-\t\t*per_reg = 2;\n+\t\tper_reg = 2;\n \t\t*mask = GENMASK(2, 0);\n \t}\n+\n+\t*reg += dscp / per_reg;\n+\t*shift = (dscp % per_reg) * (8 / per_reg);\n }\n \n /**\n@@ -236,10 +255,10 @@ int ksz_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio)\n int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)\n {\n \tstruct ksz_device *dev = ds-\u003epriv;\n-\tint reg, per_reg, ret, shift;\n+\tint reg, ret, shift;\n \tu8 data, mask;\n \n-\tksz_get_dscp_prio_reg(dev, \u0026reg, \u0026per_reg, \u0026mask);\n+\tksz_get_dscp_prio_reg(dev, dscp, \u0026reg, \u0026mask, \u0026shift);\n \n \t/* If DSCP remapping is disabled, DSCP bits 3-5 are used as Internal\n \t * Priority Map (IPM)\n@@ -260,13 +279,10 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)\n \t/* In case DSCP remapping is enabled, we need to write the DSCP to\n \t * priority mapping table.\n \t */\n-\treg += dscp / per_reg;\n \tret = ksz_read8(dev, reg, \u0026data);\n \tif (ret)\n \t\treturn ret;\n \n-\tshift = (dscp % per_reg) * (8 / per_reg);\n-\n \treturn (data \u003e\u003e shift) \u0026 mask;\n }\n \n@@ -283,15 +299,12 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)\n  */\n static int ksz_set_global_dscp_entry(struct ksz_device *dev, u8 dscp, u8 ipm)\n {\n-\tint reg, per_reg, shift;\n+\tint reg, shift;\n \tu8 mask;\n \n-\tksz_get_dscp_prio_reg(dev, \u0026reg, \u0026per_reg, \u0026mask);\n-\n-\tshift = (dscp % per_reg) * (8 / per_reg);\n+\tksz_get_dscp_prio_reg(dev, dscp, \u0026reg, \u0026mask, \u0026shift);\n \n-\treturn ksz_rmw8(dev, reg + (dscp / per_reg), mask \u003c\u003c shift,\n-\t\t\tipm \u003c\u003c shift);\n+\treturn ksz_rmw8(dev, reg, mask \u003c\u003c shift, ipm \u003c\u003c shift);\n }\n \n /**\ndiff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c\nindex 373e9054947cb..e3bb9e604186d 100644\n--- a/drivers/net/dsa/microchip/ksz_spi.c\n+++ b/drivers/net/dsa/microchip/ksz_spi.c\n@@ -161,7 +161,8 @@ static int ksz_spi_probe(struct spi_device *spi)\n \t\t chip-\u003echip_id == KSZ8794_CHIP_ID ||\n \t\t chip-\u003echip_id == KSZ8765_CHIP_ID)\n \t\tregmap_config = ksz8795_regmap_config;\n-\telse if (chip-\u003echip_id == KSZ8895_CHIP_ID ||\n+\telse if (chip-\u003echip_id == KSZ8995XA_CHIP_ID ||\n+\t\t chip-\u003echip_id == KSZ8895_CHIP_ID ||\n \t\t chip-\u003echip_id == KSZ8864_CHIP_ID)\n \t\tregmap_config = ksz8863_regmap_config;\n \telse\n@@ -185,7 +186,10 @@ static int ksz_spi_probe(struct spi_device *spi)\n \t\tdev-\u003epdata = spi-\u003edev.platform_data;\n \n \t/* setup spi */\n-\tspi-\u003emode = SPI_MODE_3;\n+\tif (chip-\u003echip_id == KSZ8995XA_CHIP_ID)\n+\t\tspi-\u003emode = SPI_MODE_0;\n+\telse\n+\t\tspi-\u003emode = SPI_MODE_3;\n \tret = spi_setup(spi);\n \tif (ret)\n \t\treturn ret;\n@@ -224,6 +228,25 @@ static void ksz_spi_shutdown(struct spi_device *spi)\n }\n \n static const struct of_device_id ksz_dt_ids[] = {\n+\t/*\n+\t * Legacy Micrel bindings. In 2015 Microchip acquired\n+\t * Micrel which is the originator of the KSZ series, and\n+\t * devices branded for Micrel already existed, as well as\n+\t * some device tree bindings. These two products are identical\n+\t * to the same Microchip products.\n+\t */\n+\t{\n+\t\t.compatible = \"micrel,ksz8864\",\n+\t\t.data = \u0026ksz_switch_chips[KSZ8864]\n+\t},\n+\t{\n+\t\t.compatible = \"micrel,ksz8795\",\n+\t\t.data = \u0026ksz_switch_chips[KSZ8795]\n+\t},\n+\t{\n+\t\t.compatible = \"micrel,ks8995\",\n+\t\t.data = \u0026ksz_switch_chips[KSZ8995XA]\n+\t},\n \t{\n \t\t.compatible = \"microchip,ksz8463\",\n \t\t.data = \u0026ksz_switch_chips[KSZ8463]\n@@ -256,6 +279,10 @@ static const struct of_device_id ksz_dt_ids[] = {\n \t\t.compatible = \"microchip,ksz8895\",\n \t\t.data = \u0026ksz_switch_chips[KSZ8895]\n \t},\n+\t{\n+\t\t.compatible = \"microchip,ksz8995xa\",\n+\t\t.data = \u0026ksz_switch_chips[KSZ8995XA]\n+\t},\n \t{\n \t\t.compatible = \"microchip,ksz9477\",\n \t\t.data = \u0026ksz_switch_chips[KSZ9477]\n@@ -317,6 +344,7 @@ static const struct of_device_id ksz_dt_ids[] = {\n MODULE_DEVICE_TABLE(of, ksz_dt_ids);\n \n static const struct spi_device_id ksz_spi_ids[] = {\n+\t{ \"ks8995\" },\n \t{ \"ksz8463\" },\n \t{ \"ksz8765\" },\n \t{ \"ksz8794\" },\n@@ -325,6 +353,7 @@ static const struct spi_device_id ksz_spi_ids[] = {\n \t{ \"ksz8864\" },\n \t{ \"ksz8873\" },\n \t{ \"ksz8895\" },\n+\t{ \"ksz8995xa\" },\n \t{ \"ksz9477\" },\n \t{ \"ksz9896\" },\n \t{ \"ksz9897\" },\ndiff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h\nindex 028781ad40593..d8eddd21c3c7d 100644\n--- a/include/linux/platform_data/microchip-ksz.h\n+++ b/include/linux/platform_data/microchip-ksz.h\n@@ -31,6 +31,7 @@ enum ksz_chip_id {\n \tKSZ88X3_CHIP_ID = 0x8830,\n \tKSZ8864_CHIP_ID = 0x8864,\n \tKSZ8895_CHIP_ID = 0x8895,\n+\tKSZ8995XA_CHIP_ID = 0x8995,\n \tKSZ9477_CHIP_ID = 0x00947700,\n \tKSZ9896_CHIP_ID = 0x00989600,\n \tKSZ9897_CHIP_ID = 0x00989700,\ndiff --git a/include/net/dsa.h b/include/net/dsa.h\nindex 7507d632e7c6d..5d12191b6f6f5 100644\n--- a/include/net/dsa.h\n+++ b/include/net/dsa.h\n@@ -61,6 +61,7 @@ struct tc_action;\n #define DSA_TAG_PROTO_NETC_VALUE\t\t33\n #define DSA_TAG_PROTO_KSZ8463_VALUE\t\t34\n #define DSA_TAG_PROTO_MT7628_VALUE\t\t35\n+#define DSA_TAG_PROTO_KS8995_VALUE\t\t36\n \n enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_NONE\t\t= DSA_TAG_PROTO_NONE_VALUE,\n@@ -99,6 +100,7 @@ enum dsa_tag_protocol {\n \tDSA_TAG_PROTO_NETC\t\t= DSA_TAG_PROTO_NETC_VALUE,\n \tDSA_TAG_PROTO_KSZ8463\t\t= DSA_TAG_PROTO_KSZ8463_VALUE,\n \tDSA_TAG_PROTO_MT7628\t\t= DSA_TAG_PROTO_MT7628_VALUE,\n+\tDSA_TAG_PROTO_KS8995\t\t= DSA_TAG_PROTO_KS8995_VALUE,\n };\n \n struct dsa_switch;\ndiff --git a/net/dsa/Kconfig b/net/dsa/Kconfig\nindex 23b4b74004ed5..4f44bf3ede238 100644\n--- a/net/dsa/Kconfig\n+++ b/net/dsa/Kconfig\n@@ -125,6 +125,12 @@ config NET_DSA_TAG_MXL_GSW1XX\n \t  Say Y or M if you want to enable support for tagging frames for\n \t  MaxLinear GSW1xx switches.\n \n+config NET_DSA_TAG_KS8995\n+\ttristate \"Tag driver for Micrel KS8995 switch\"\n+\thelp\n+\t  Say Y if you want to enable support for tagging frames for the\n+\t  Micrel KS8995 switch.\n+\n config NET_DSA_TAG_KSZ\n \ttristate \"Tag driver for Microchip 8795/937x/9477/9893 families of switches\"\n \thelp\ndiff --git a/net/dsa/Makefile b/net/dsa/Makefile\nindex d15bcf5c68f02..1f9cc30e99886 100644\n--- a/net/dsa/Makefile\n+++ b/net/dsa/Makefile\n@@ -25,6 +25,7 @@ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o\n obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o\n 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_KS8995) += tag_ks8995.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_MT7628) += tag_mt7628.o\ndiff --git a/net/dsa/tag_ks8995.c b/net/dsa/tag_ks8995.c\nnew file mode 100644\nindex 0000000000000..f6ef1ef1891fd\n--- /dev/null\n+++ b/net/dsa/tag_ks8995.c\n@@ -0,0 +1,145 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/*\n+ * Copyright (C) 2026 Linus Walleij \u003clinusw@kernel.org\u003e\n+ */\n+#include \u003clinux/etherdevice.h\u003e\n+#include \u003clinux/log2.h\u003e\n+#include \u003clinux/list.h\u003e\n+#include \u003clinux/net.h\u003e\n+#include \u003clinux/slab.h\u003e\n+\n+#include \"tag.h\"\n+\n+/* The Micrel KS8995XA / Microchip KSZ8995XA Special Tag Packet ID (STPID)\n+ * pushes its tag in a modified VLAN (802.1Q) tag.\n+ * -----------------------------------------------------------\n+ * | MAC DA | MAC SA | 2 bytes tag | 2 bytes TCI | EtherType |\n+ * -----------------------------------------------------------\n+ * The tag is: 0x8100 |= BIT(port), ports 0,1,2,3\n+ */\n+\n+#define KS8995_NAME \"ks8995\"\n+\n+#define KS8995M_STPID_STD\tGENMASK(15, 4)\n+#define KS8995M_STPID_PORTMASK\tGENMASK(3, 0)\n+#define KS8995M_STPID(portmask)\thtons(ETH_P_8021Q | FIELD_PREP(KS8995M_STPID_PORTMASK, portmask))\n+\n+static struct sk_buff *ks8995_xmit(struct sk_buff *skb, struct net_device *dev)\n+{\n+\tstruct vlan_ethhdr *hdr;\n+\tu16 portmask;\n+\n+\t/* Prepare the special KS8995 tags */\n+\tportmask = dsa_xmit_port_mask(skb, dev);\n+\n+\t/* The switch expects the special tag at offset 12. Move any hardware\n+\t * accelerated VLAN tag into the payload so the conduit cannot insert\n+\t * it outside the special tag.\n+\t */\n+\tif (unlikely(skb_vlan_tag_present(skb))) {\n+\t\tskb = __vlan_hwaccel_push_inside(skb);\n+\t\tif (!skb)\n+\t\t\treturn NULL;\n+\t}\n+\n+\t/* Always add a distinct outer tag. The user port removes this field on\n+\t * egress, so reusing an existing 802.1Q tag would consume that VLAN tag.\n+\t */\n+\tskb = vlan_insert_tag(skb, KS8995M_STPID(portmask), 0);\n+\t/* vlan_insert_tag() drops the skb on failure */\n+\tif (!skb)\n+\t\treturn NULL;\n+\thdr = skb_vlan_eth_hdr(skb);\n+\tnetdev_dbg(dev, \"%s: inserted VLAN TAG %04x TCI %04x\\n\",\n+\t\t   __func__, ntohs(hdr-\u003eh_vlan_proto),\n+\t\t   ntohs(hdr-\u003eh_vlan_TCI));\n+\n+\treturn skb;\n+}\n+\n+static struct sk_buff *ks8995_rcv(struct sk_buff *skb, struct net_device *dev)\n+{\n+\tint portmask;\n+\tint port;\n+\tu16 etype;\n+\n+\t/* We are expecting all received packets to have a mangled VLAN\n+\t * TPID, so drop anything else. Because of the non-standard TPID,\n+\t * don't even bother looking for a tag in the hwaccel area.\n+\t *\n+\t * We have to inspect the ethertype directly because skb-\u003eprotocol\n+\t * will contain garbage.\n+\t */\n+\tetype = ntohs(*(__be16 *)dsa_etype_header_pos_rx(skb));\n+\tif ((etype \u0026 KS8995M_STPID_STD) != ETH_P_8021Q) {\n+\t\tnetdev_dbg(dev, \"%s: dropped ethertype 0x%04x\\n\",\n+\t\t\t   __func__, etype);\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\n+\tportmask = FIELD_GET(KS8995M_STPID_PORTMASK, etype);\n+\tif (unlikely(!is_power_of_2(portmask))) {\n+\t\tnetdev_dbg(dev, \"%s: dropped invalid port mask 0x%04x\\n\",\n+\t\t\t   __func__, portmask);\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\tport = ilog2(portmask);\n+\n+\tnetdev_dbg(dev, \"%s: received ethertype %04x\\n\",\n+\t\t   __func__, etype);\n+\n+\t/* Move the custom DSA+VLAN tag into the hwaccel area and strip\n+\t * it from the skb head\n+\t */\n+\tskb = skb_vlan_untag(skb);\n+\tif (!skb) {\n+\t\t/* skb_vlan_untag drops the skb on failure */\n+\t\tif (net_ratelimit())\n+\t\t\tnetdev_err(dev, \"%s: unable to untag skb\\n\", __func__);\n+\t\treturn NULL;\n+\t}\n+\n+\tnetdev_dbg(dev, \"%s: etype %04x portmask %04x (%d)\\n\",\n+\t\t   __func__, etype, portmask, port);\n+\tskb-\u003edev = dsa_conduit_find_user(dev, 0, port);\n+\tif (!skb-\u003edev) {\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* skb_vlan_untag() moved the special tag's TCI into the hardware-\n+\t * accelerated VLAN metadata. The switch preserves the TCI of tagged\n+\t * frames, but inserts the ingress port's default tag for untagged frames.\n+\t * Since the driver programs the default tag to 0, a zero TCI identifies\n+\t * an originally untagged frame. Preserve every non-zero TCI as an\n+\t * 802.1Q tag, including VID 0 frames with PCP or DEI set.\n+\t */\n+\tif (!skb-\u003evlan_tci) {\n+\t\tnetdev_dbg(dev, \"%s: clear VLAN tag from frame\\n\", __func__);\n+\t\t__vlan_hwaccel_clear_tag(skb);\n+\t} else {\n+\t\tskb-\u003evlan_proto = htons(ETH_P_8021Q);\n+\t\tnetdev_dbg(dev, \"%s: vlan_tci = 0x%04x VLAN frame\\n\",\n+\t\t\t   __func__, skb-\u003evlan_tci);\n+\t}\n+\n+\tdsa_default_offload_fwd_mark(skb);\n+\n+\treturn skb;\n+}\n+\n+static const struct dsa_device_ops ks8995_netdev_ops = {\n+\t.name = KS8995_NAME,\n+\t.proto\t= DSA_TAG_PROTO_KS8995,\n+\t.xmit = ks8995_xmit,\n+\t.rcv = ks8995_rcv,\n+\t.needed_headroom = VLAN_HLEN,\n+};\n+\n+MODULE_DESCRIPTION(\"DSA tag driver for Micrel KS8995 family of switches\");\n+MODULE_LICENSE(\"GPL\");\n+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KS8995, KS8995_NAME);\n+\n+module_dsa_tag_driver(ks8995_netdev_ops);\n"
}

2/1 2026/09/09 17:26 agent patch-evaluator
1m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch removes the legacy standalone KS8995 DSA driver and migrates support for the Micrel/Microchip KS8995 / KSZ8995XA Ethernet switch into the microchip ksz8 DSA driver alongside adding a dedicated tag driver (net/dsa/tag_ks8995.c). These switches are physical hardware ASICs connected via SPI and are structurally unreachable in standard virtualized fuzzing environments (QEMU/GCE).",
  "WorthFuzzing": false
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 0635973cea904b44d820d9f3282ea3987e830384
Author: syz-cluster <triage@syzkaller.com>
Date:   Wed Sep 9 17:26:30 2026 +0000

    syz-cluster: applied patch under review

diff --git a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
index 8d4a3a9a33fcc..4ed13870ed3ac 100644
--- a/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
+++ b/Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml
@@ -23,6 +23,7 @@ properties:
       - microchip,ksz8864  # 4-port version of KSZ8895 family switch
       - microchip,ksz8873
       - microchip,ksz8895  # 5-port version of KSZ8895 family switch
+      - microchip,ksz8995xa
       - microchip,ksz9477
       - microchip,ksz9897
       - microchip,ksz9896
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a19da74d00c9..7fabc2eae9afe 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17776,6 +17776,7 @@ F:	Documentation/devicetree/bindings/net/dsa/microchip,lan937x.yaml
 F:	drivers/net/dsa/microchip/*
 F:	include/linux/dsa/ksz_common.h
 F:	include/linux/platform_data/microchip-ksz.h
+F:	net/dsa/tag_ks8995.c
 F:	net/dsa/tag_ksz.c
 
 MICROCHIP LAN743X ETHERNET DRIVER
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index 676fb7dffe14f..55a9714033a6f 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -110,10 +110,13 @@ config NET_DSA_RZN1_A5PSW
 config NET_DSA_KS8995
 	tristate "Micrel KS8995 family 5-ports 10/100 Ethernet switches"
 	depends on SPI
-	select NET_DSA_TAG_NONE
+	select NET_DSA_MICROCHIP_KSZ_COMMON
+	select NET_DSA_MICROCHIP_KSZ_SPI
 	help
-	  This driver supports the Micrel KS8995 family of 10/100 Mbit ethernet
-	  switches, managed over SPI.
+	  This is a transitional option for users who had NET_DSA_KS8995
+	  enabled. It automatically enables the new NET_DSA_MICROCHIP_KSZ_SPI
+	  driver which supersedes it. This option will be removed in a future
+	  kernel release.
 
 config NET_DSA_SMSC_LAN9303
 	tristate
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index 6ceb78a755d77..9923137429f84 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -2,7 +2,6 @@
 obj-$(CONFIG_NET_DSA_BCM_SF2)	+= bcm-sf2.o
 bcm-sf2-objs			:= bcm_sf2.o bcm_sf2_cfp.o
 obj-$(CONFIG_NET_DSA_LOOP)	+= dsa_loop.o
-obj-$(CONFIG_NET_DSA_KS8995) 	+= ks8995.o
 obj-$(CONFIG_NET_DSA_MT7530)	+= mt7530.o
 obj-$(CONFIG_NET_DSA_MT7530_MDIO) += mt7530-mdio.o
 obj-$(CONFIG_NET_DSA_MT7530_MMIO) += mt7530-mmio.o
diff --git a/drivers/net/dsa/ks8995.c b/drivers/net/dsa/ks8995.c
deleted file mode 100644
index 77d8b842693c1..0000000000000
--- a/drivers/net/dsa/ks8995.c
+++ /dev/null
@@ -1,857 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches
- *
- * Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
- * Copyright (C) 2025 Linus Walleij <linus.walleij@linaro.org>
- *
- * This file was based on: drivers/spi/at25.c
- *     Copyright (C) 2006 David Brownell
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/bits.h>
-#include <linux/if_bridge.h>
-#include <linux/if_vlan.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/of.h>
-#include <linux/spi/spi.h>
-#include <net/dsa.h>
-
-#define DRV_VERSION		"0.1.1"
-#define DRV_DESC		"Micrel KS8995 Ethernet switch SPI driver"
-
-/* ------------------------------------------------------------------------ */
-
-#define KS8995_REG_ID0		0x00    /* Chip ID0 */
-#define KS8995_REG_ID1		0x01    /* Chip ID1 */
-
-#define KS8995_REG_GC0		0x02    /* Global Control 0 */
-
-#define KS8995_GC0_P5_PHY	BIT(3)	/* Port 5 PHY enabled */
-
-#define KS8995_REG_GC1		0x03    /* Global Control 1 */
-#define KS8995_REG_GC2		0x04    /* Global Control 2 */
-
-#define KS8995_GC2_HUGE		BIT(2)	/* Huge packet support */
-#define KS8995_GC2_LEGAL	BIT(1)	/* Legal size override */
-
-#define KS8995_REG_GC3		0x05    /* Global Control 3 */
-#define KS8995_REG_GC4		0x06    /* Global Control 4 */
-
-#define KS8995_GC4_10BT		BIT(4)	/* Force switch to 10Mbit */
-#define KS8995_GC4_MII_FLOW	BIT(5)	/* MII full-duplex flow control enable */
-#define KS8995_GC4_MII_HD	BIT(6)	/* MII half-duplex mode enable */
-
-#define KS8995_REG_GC5		0x07    /* Global Control 5 */
-#define KS8995_REG_GC6		0x08    /* Global Control 6 */
-#define KS8995_REG_GC7		0x09    /* Global Control 7 */
-#define KS8995_REG_GC8		0x0a    /* Global Control 8 */
-#define KS8995_REG_GC9		0x0b    /* Global Control 9 */
-
-#define KS8995_GC9_SPECIAL	BIT(0)	/* Special tagging mode (DSA) */
-
-/* In DSA the ports 1-4 are numbered 0-3 and the CPU port is port 4 */
-#define KS8995_REG_PC(p, r)	(0x10 + (0x10 * (p)) + (r)) /* Port Control */
-#define KS8995_REG_PS(p, r)	(0x1e + (0x10 * (p)) + (r)) /* Port Status */
-
-#define KS8995_REG_PC0		0x00    /* Port Control 0 */
-#define KS8995_REG_PC1		0x01    /* Port Control 1 */
-#define KS8995_REG_PC2		0x02    /* Port Control 2 */
-#define KS8995_REG_PC3		0x03    /* Port Control 3 */
-#define KS8995_REG_PC4		0x04    /* Port Control 4 */
-#define KS8995_REG_PC5		0x05    /* Port Control 5 */
-#define KS8995_REG_PC6		0x06    /* Port Control 6 */
-#define KS8995_REG_PC7		0x07    /* Port Control 7 */
-#define KS8995_REG_PC8		0x08    /* Port Control 8 */
-#define KS8995_REG_PC9		0x09    /* Port Control 9 */
-#define KS8995_REG_PC10		0x0a    /* Port Control 10 */
-#define KS8995_REG_PC11		0x0b    /* Port Control 11 */
-#define KS8995_REG_PC12		0x0c    /* Port Control 12 */
-#define KS8995_REG_PC13		0x0d    /* Port Control 13 */
-
-#define KS8995_PC0_TAG_INS	BIT(2)	/* Enable tag insertion on port */
-#define KS8995_PC0_TAG_REM	BIT(1)	/* Enable tag removal on port */
-#define KS8995_PC0_PRIO_EN	BIT(0)	/* Enable priority handling */
-
-#define KS8995_PC2_TXEN		BIT(2)	/* Enable TX on port */
-#define KS8995_PC2_RXEN		BIT(1)	/* Enable RX on port */
-#define KS8995_PC2_LEARN_DIS	BIT(0)	/* Disable learning on port */
-
-#define KS8995_PC13_TXDIS	BIT(6)	/* Disable transmitter */
-#define KS8995_PC13_PWDN	BIT(3)	/* Power down */
-
-#define KS8995_REG_TPC0		0x60    /* TOS Priority Control 0 */
-#define KS8995_REG_TPC1		0x61    /* TOS Priority Control 1 */
-#define KS8995_REG_TPC2		0x62    /* TOS Priority Control 2 */
-#define KS8995_REG_TPC3		0x63    /* TOS Priority Control 3 */
-#define KS8995_REG_TPC4		0x64    /* TOS Priority Control 4 */
-#define KS8995_REG_TPC5		0x65    /* TOS Priority Control 5 */
-#define KS8995_REG_TPC6		0x66    /* TOS Priority Control 6 */
-#define KS8995_REG_TPC7		0x67    /* TOS Priority Control 7 */
-
-#define KS8995_REG_MAC0		0x68    /* MAC address 0 */
-#define KS8995_REG_MAC1		0x69    /* MAC address 1 */
-#define KS8995_REG_MAC2		0x6a    /* MAC address 2 */
-#define KS8995_REG_MAC3		0x6b    /* MAC address 3 */
-#define KS8995_REG_MAC4		0x6c    /* MAC address 4 */
-#define KS8995_REG_MAC5		0x6d    /* MAC address 5 */
-
-#define KS8995_REG_IAC0		0x6e    /* Indirect Access Control 0 */
-#define KS8995_REG_IAC1		0x6f    /* Indirect Access Control 0 */
-#define KS8995_REG_IAD7		0x70    /* Indirect Access Data 7 */
-#define KS8995_REG_IAD6		0x71    /* Indirect Access Data 6 */
-#define KS8995_REG_IAD5		0x72    /* Indirect Access Data 5 */
-#define KS8995_REG_IAD4		0x73    /* Indirect Access Data 4 */
-#define KS8995_REG_IAD3		0x74    /* Indirect Access Data 3 */
-#define KS8995_REG_IAD2		0x75    /* Indirect Access Data 2 */
-#define KS8995_REG_IAD1		0x76    /* Indirect Access Data 1 */
-#define KS8995_REG_IAD0		0x77    /* Indirect Access Data 0 */
-
-#define KSZ8864_REG_ID1		0xfe	/* Chip ID in bit 7 */
-
-#define KS8995_REGS_SIZE	0x80
-#define KSZ8864_REGS_SIZE	0x100
-#define KSZ8795_REGS_SIZE	0x100
-
-#define ID1_CHIPID_M		0xf
-#define ID1_CHIPID_S		4
-#define ID1_REVISION_M		0x7
-#define ID1_REVISION_S		1
-#define ID1_START_SW		1	/* start the switch */
-
-#define FAMILY_KS8995		0x95
-#define FAMILY_KSZ8795		0x87
-#define CHIPID_M		0
-#define KS8995_CHIP_ID		0x00
-#define KSZ8864_CHIP_ID		0x01
-#define KSZ8795_CHIP_ID		0x09
-
-#define KS8995_CMD_WRITE	0x02U
-#define KS8995_CMD_READ		0x03U
-
-#define KS8995_CPU_PORT		4
-#define KS8995_NUM_PORTS	5 /* 5 ports including the CPU port */
-#define KS8995_RESET_DELAY	10 /* usec */
-
-enum ks8995_chip_variant {
-	ks8995,
-	ksz8864,
-	ksz8795,
-	max_variant
-};
-
-struct ks8995_chip_params {
-	char *name;
-	int family_id;
-	int chip_id;
-	int regs_size;
-	int addr_width;
-	int addr_shift;
-};
-
-static const struct ks8995_chip_params ks8995_chip[] = {
-	[ks8995] = {
-		.name = "KS8995MA",
-		.family_id = FAMILY_KS8995,
-		.chip_id = KS8995_CHIP_ID,
-		.regs_size = KS8995_REGS_SIZE,
-		.addr_width = 8,
-		.addr_shift = 0,
-	},
-	[ksz8864] = {
-		.name = "KSZ8864RMN",
-		.family_id = FAMILY_KS8995,
-		.chip_id = KSZ8864_CHIP_ID,
-		.regs_size = KSZ8864_REGS_SIZE,
-		.addr_width = 8,
-		.addr_shift = 0,
-	},
-	[ksz8795] = {
-		.name = "KSZ8795CLX",
-		.family_id = FAMILY_KSZ8795,
-		.chip_id = KSZ8795_CHIP_ID,
-		.regs_size = KSZ8795_REGS_SIZE,
-		.addr_width = 12,
-		.addr_shift = 1,
-	},
-};
-
-struct ks8995_switch {
-	struct spi_device	*spi;
-	struct device		*dev;
-	struct dsa_switch	*ds;
-	struct mutex		lock;
-	struct gpio_desc	*reset_gpio;
-	struct bin_attribute	regs_attr;
-	const struct ks8995_chip_params	*chip;
-	int			revision_id;
-	unsigned int max_mtu[KS8995_NUM_PORTS];
-};
-
-static const struct spi_device_id ks8995_id[] = {
-	{"ks8995", ks8995},
-	{"ksz8864", ksz8864},
-	{"ksz8795", ksz8795},
-	{ }
-};
-MODULE_DEVICE_TABLE(spi, ks8995_id);
-
-static const struct of_device_id ks8995_spi_of_match[] = {
-	{ .compatible = "micrel,ks8995" },
-	{ .compatible = "micrel,ksz8864" },
-	{ .compatible = "micrel,ksz8795" },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, ks8995_spi_of_match);
-
-static inline u8 get_chip_id(u8 val)
-{
-	return (val >> ID1_CHIPID_S) & ID1_CHIPID_M;
-}
-
-static inline u8 get_chip_rev(u8 val)
-{
-	return (val >> ID1_REVISION_S) & ID1_REVISION_M;
-}
-
-/* create_spi_cmd - create a chip specific SPI command header
- * @ks: pointer to switch instance
- * @cmd: SPI command for switch
- * @address: register address for command
- *
- * Different chip families use different bit pattern to address the switches
- * registers:
- *
- * KS8995: 8bit command + 8bit address
- * KSZ8795: 3bit command + 12bit address + 1bit TR (?)
- */
-static inline __be16 create_spi_cmd(struct ks8995_switch *ks, int cmd,
-				    unsigned address)
-{
-	u16 result = cmd;
-
-	/* make room for address (incl. address shift) */
-	result <<= ks->chip->addr_width + ks->chip->addr_shift;
-	/* add address */
-	result |= address << ks->chip->addr_shift;
-	/* SPI protocol needs big endian */
-	return cpu_to_be16(result);
-}
-/* ------------------------------------------------------------------------ */
-static int ks8995_read(struct ks8995_switch *ks, char *buf,
-		 unsigned offset, size_t count)
-{
-	__be16 cmd;
-	struct spi_transfer t[2];
-	struct spi_message m;
-	int err;
-
-	cmd = create_spi_cmd(ks, KS8995_CMD_READ, offset);
-	spi_message_init(&m);
-
-	memset(&t, 0, sizeof(t));
-
-	t[0].tx_buf = &cmd;
-	t[0].len = sizeof(cmd);
-	spi_message_add_tail(&t[0], &m);
-
-	t[1].rx_buf = buf;
-	t[1].len = count;
-	spi_message_add_tail(&t[1], &m);
-
-	mutex_lock(&ks->lock);
-	err = spi_sync(ks->spi, &m);
-	mutex_unlock(&ks->lock);
-
-	return err ? err : count;
-}
-
-static int ks8995_write(struct ks8995_switch *ks, char *buf,
-		 unsigned offset, size_t count)
-{
-	__be16 cmd;
-	struct spi_transfer t[2];
-	struct spi_message m;
-	int err;
-
-	cmd = create_spi_cmd(ks, KS8995_CMD_WRITE, offset);
-	spi_message_init(&m);
-
-	memset(&t, 0, sizeof(t));
-
-	t[0].tx_buf = &cmd;
-	t[0].len = sizeof(cmd);
-	spi_message_add_tail(&t[0], &m);
-
-	t[1].tx_buf = buf;
-	t[1].len = count;
-	spi_message_add_tail(&t[1], &m);
-
-	mutex_lock(&ks->lock);
-	err = spi_sync(ks->spi, &m);
-	mutex_unlock(&ks->lock);
-
-	return err ? err : count;
-}
-
-static inline int ks8995_read_reg(struct ks8995_switch *ks, u8 addr, u8 *buf)
-{
-	return ks8995_read(ks, buf, addr, 1) != 1;
-}
-
-static inline int ks8995_write_reg(struct ks8995_switch *ks, u8 addr, u8 val)
-{
-	char buf = val;
-
-	return ks8995_write(ks, &buf, addr, 1) != 1;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int ks8995_stop(struct ks8995_switch *ks)
-{
-	return ks8995_write_reg(ks, KS8995_REG_ID1, 0);
-}
-
-static int ks8995_start(struct ks8995_switch *ks)
-{
-	return ks8995_write_reg(ks, KS8995_REG_ID1, 1);
-}
-
-static int ks8995_reset(struct ks8995_switch *ks)
-{
-	int err;
-
-	err = ks8995_stop(ks);
-	if (err)
-		return err;
-
-	udelay(KS8995_RESET_DELAY);
-
-	return ks8995_start(ks);
-}
-
-/* ks8995_get_revision - get chip revision
- * @ks: pointer to switch instance
- *
- * Verify chip family and id and get chip revision.
- */
-static int ks8995_get_revision(struct ks8995_switch *ks)
-{
-	int err;
-	u8 id0, id1, ksz8864_id;
-
-	/* read family id */
-	err = ks8995_read_reg(ks, KS8995_REG_ID0, &id0);
-	if (err) {
-		err = -EIO;
-		goto err_out;
-	}
-
-	/* verify family id */
-	if (id0 != ks->chip->family_id) {
-		dev_err(&ks->spi->dev, "chip family id mismatch: expected 0x%02x but 0x%02x read\n",
-			ks->chip->family_id, id0);
-		err = -ENODEV;
-		goto err_out;
-	}
-
-	switch (ks->chip->family_id) {
-	case FAMILY_KS8995:
-		/* try reading chip id at CHIP ID1 */
-		err = ks8995_read_reg(ks, KS8995_REG_ID1, &id1);
-		if (err) {
-			err = -EIO;
-			goto err_out;
-		}
-
-		/* verify chip id */
-		if ((get_chip_id(id1) == CHIPID_M) &&
-		    (get_chip_id(id1) == ks->chip->chip_id)) {
-			/* KS8995MA */
-			ks->revision_id = get_chip_rev(id1);
-		} else if (get_chip_id(id1) != CHIPID_M) {
-			/* KSZ8864RMN */
-			err = ks8995_read_reg(ks, KS8995_REG_ID1, &ksz8864_id);
-			if (err) {
-				err = -EIO;
-				goto err_out;
-			}
-
-			if ((ksz8864_id & 0x80) &&
-			    (ks->chip->chip_id == KSZ8864_CHIP_ID)) {
-				ks->revision_id = get_chip_rev(id1);
-			}
-
-		} else {
-			dev_err(&ks->spi->dev, "unsupported chip id for KS8995 family: 0x%02x\n",
-				id1);
-			err = -ENODEV;
-		}
-		break;
-	case FAMILY_KSZ8795:
-		/* try reading chip id at CHIP ID1 */
-		err = ks8995_read_reg(ks, KS8995_REG_ID1, &id1);
-		if (err) {
-			err = -EIO;
-			goto err_out;
-		}
-
-		if (get_chip_id(id1) == ks->chip->chip_id) {
-			ks->revision_id = get_chip_rev(id1);
-		} else {
-			dev_err(&ks->spi->dev, "unsupported chip id for KSZ8795 family: 0x%02x\n",
-				id1);
-			err = -ENODEV;
-		}
-		break;
-	default:
-		dev_err(&ks->spi->dev, "unsupported family id: 0x%02x\n", id0);
-		err = -ENODEV;
-		break;
-	}
-err_out:
-	return err;
-}
-
-static int ks8995_check_config(struct ks8995_switch *ks)
-{
-	int ret;
-	u8 val;
-
-	ret = ks8995_read_reg(ks, KS8995_REG_GC0, &val);
-	if (ret) {
-		dev_err(ks->dev, "failed to read KS8995_REG_GC0\n");
-		return ret;
-	}
-
-	dev_dbg(ks->dev, "port 5 PHY %senabled\n",
-		(val & KS8995_GC0_P5_PHY) ? "" : "not ");
-
-	val |= KS8995_GC0_P5_PHY;
-	ret = ks8995_write_reg(ks, KS8995_REG_GC0, val);
-	if (ret)
-		dev_err(ks->dev, "failed to set KS8995_REG_GC0\n");
-
-	dev_dbg(ks->dev, "set KS8995_REG_GC0 to 0x%02x\n", val);
-
-	return 0;
-}
-
-static void
-ks8995_mac_config(struct phylink_config *config, unsigned int mode,
-		  const struct phylink_link_state *state)
-{
-}
-
-static void
-ks8995_mac_link_up(struct phylink_config *config, struct phy_device *phydev,
-		   unsigned int mode, phy_interface_t interface,
-		   int speed, int duplex, bool tx_pause, bool rx_pause)
-{
-	struct dsa_port *dp = dsa_phylink_to_port(config);
-	struct ks8995_switch *ks = dp->ds->priv;
-	int port = dp->index;
-	int ret;
-	u8 val;
-
-	/* Allow forcing the mode on the fixed CPU port, no autonegotiation.
-	 * We assume autonegotiation works on the PHY-facing ports.
-	 */
-	if (port != KS8995_CPU_PORT)
-		return;
-
-	dev_dbg(ks->dev, "MAC link up on CPU port (%d)\n", port);
-
-	ret = ks8995_read_reg(ks, KS8995_REG_GC4, &val);
-	if (ret) {
-		dev_err(ks->dev, "failed to read KS8995_REG_GC4\n");
-		return;
-	}
-
-	/* Conjure port config */
-	switch (speed) {
-	case SPEED_10:
-		dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n");
-		val |= KS8995_GC4_10BT;
-		break;
-	case SPEED_100:
-	default:
-		dev_dbg(ks->dev, "set switch MII to 100Mbit mode\n");
-		val &= ~KS8995_GC4_10BT;
-		break;
-	}
-
-	if (duplex == DUPLEX_HALF) {
-		dev_dbg(ks->dev, "set switch MII to half duplex\n");
-		val |= KS8995_GC4_MII_HD;
-	} else {
-		dev_dbg(ks->dev, "set switch MII to full duplex\n");
-		val &= ~KS8995_GC4_MII_HD;
-	}
-
-	dev_dbg(ks->dev, "set KS8995_REG_GC4 to %02x\n", val);
-
-	/* Enable the CPU port */
-	ret = ks8995_write_reg(ks, KS8995_REG_GC4, val);
-	if (ret)
-		dev_err(ks->dev, "failed to set KS8995_REG_GC4\n");
-}
-
-static void
-ks8995_mac_link_down(struct phylink_config *config, unsigned int mode,
-		     phy_interface_t interface)
-{
-	struct dsa_port *dp = dsa_phylink_to_port(config);
-	struct ks8995_switch *ks = dp->ds->priv;
-	int port = dp->index;
-
-	if (port != KS8995_CPU_PORT)
-		return;
-
-	dev_dbg(ks->dev, "MAC link down on CPU port (%d)\n", port);
-
-	/* Disable the CPU port */
-}
-
-static const struct phylink_mac_ops ks8995_phylink_mac_ops = {
-	.mac_config = ks8995_mac_config,
-	.mac_link_up = ks8995_mac_link_up,
-	.mac_link_down = ks8995_mac_link_down,
-};
-
-static enum
-dsa_tag_protocol ks8995_get_tag_protocol(struct dsa_switch *ds,
-					 int port,
-					 enum dsa_tag_protocol mp)
-{
-	/* This switch actually uses the 6 byte KS8995 protocol */
-	return DSA_TAG_PROTO_NONE;
-}
-
-static int ks8995_setup(struct dsa_switch *ds)
-{
-	return 0;
-}
-
-static int ks8995_port_enable(struct dsa_switch *ds, int port,
-			      struct phy_device *phy)
-{
-	struct ks8995_switch *ks = ds->priv;
-
-	dev_dbg(ks->dev, "enable port %d\n", port);
-
-	return 0;
-}
-
-static void ks8995_port_disable(struct dsa_switch *ds, int port)
-{
-	struct ks8995_switch *ks = ds->priv;
-
-	dev_dbg(ks->dev, "disable port %d\n", port);
-}
-
-static int ks8995_port_pre_bridge_flags(struct dsa_switch *ds, int port,
-					struct switchdev_brport_flags flags,
-					struct netlink_ext_ack *extack)
-{
-	/* We support enabling/disabling learning */
-	if (flags.mask & ~(BR_LEARNING))
-		return -EINVAL;
-
-	return 0;
-}
-
-static int ks8995_port_bridge_flags(struct dsa_switch *ds, int port,
-				    struct switchdev_brport_flags flags,
-				    struct netlink_ext_ack *extack)
-{
-	struct ks8995_switch *ks = ds->priv;
-	int ret;
-	u8 val;
-
-	if (flags.mask & BR_LEARNING) {
-		ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val);
-		if (ret) {
-			dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port);
-			return ret;
-		}
-
-		if (flags.val & BR_LEARNING)
-			val &= ~KS8995_PC2_LEARN_DIS;
-		else
-			val |= KS8995_PC2_LEARN_DIS;
-
-		ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val);
-		if (ret) {
-			dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port);
-			return ret;
-		}
-	}
-
-	return 0;
-}
-
-static void ks8995_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
-{
-	struct ks8995_switch *ks = ds->priv;
-	int ret;
-	u8 val;
-
-	ret = ks8995_read_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), &val);
-	if (ret) {
-		dev_err(ks->dev, "failed to read KS8995_REG_PC2 on port %d\n", port);
-		return;
-	}
-
-	/* Set the bits for the different STP states in accordance with
-	 * the datasheet, pages 36-37 "Spanning tree support".
-	 */
-	switch (state) {
-	case BR_STATE_DISABLED:
-	case BR_STATE_BLOCKING:
-	case BR_STATE_LISTENING:
-		val &= ~KS8995_PC2_TXEN;
-		val &= ~KS8995_PC2_RXEN;
-		val |= KS8995_PC2_LEARN_DIS;
-		break;
-	case BR_STATE_LEARNING:
-		val &= ~KS8995_PC2_TXEN;
-		val &= ~KS8995_PC2_RXEN;
-		val &= ~KS8995_PC2_LEARN_DIS;
-		break;
-	case BR_STATE_FORWARDING:
-		val |= KS8995_PC2_TXEN;
-		val |= KS8995_PC2_RXEN;
-		val &= ~KS8995_PC2_LEARN_DIS;
-		break;
-	default:
-		dev_err(ks->dev, "unknown bridge state requested\n");
-		return;
-	}
-
-	ret = ks8995_write_reg(ks, KS8995_REG_PC(port, KS8995_REG_PC2), val);
-	if (ret) {
-		dev_err(ks->dev, "failed to write KS8995_REG_PC2 on port %d\n", port);
-		return;
-	}
-
-	dev_dbg(ks->dev, "set KS8995_REG_PC2 for port %d to %02x\n", port, val);
-}
-
-static void ks8995_phylink_get_caps(struct dsa_switch *dsa, int port,
-				    struct phylink_config *config)
-{
-	unsigned long *interfaces = config->supported_interfaces;
-
-	if (port == KS8995_CPU_PORT)
-		__set_bit(PHY_INTERFACE_MODE_MII, interfaces);
-
-	if (port <= 3) {
-		/* Internal PHYs */
-		__set_bit(PHY_INTERFACE_MODE_INTERNAL, interfaces);
-		/* phylib default */
-		__set_bit(PHY_INTERFACE_MODE_MII, interfaces);
-	}
-
-	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
-}
-
-/* Huge packet support up to 1916 byte packages "inclusive"
- * which means that tags are included. If the bit is not set
- * it is 1536 bytes "inclusive". We present the length without
- * tags or ethernet headers. The setting affects all ports.
- */
-static int ks8995_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
-{
-	struct ks8995_switch *ks = ds->priv;
-	unsigned int max_mtu;
-	int ret;
-	u8 val;
-	int i;
-
-	ks->max_mtu[port] = new_mtu;
-
-	/* Roof out the MTU for the entire switch to the greatest
-	 * common denominator: the biggest set for any one port will
-	 * be the biggest MTU for the switch.
-	 */
-	max_mtu = ETH_DATA_LEN;
-	for (i = 0; i < KS8995_NUM_PORTS; i++) {
-		if (ks->max_mtu[i] > max_mtu)
-			max_mtu = ks->max_mtu[i];
-	}
-
-	/* Translate to layer 2 size.
-	 * Add ethernet and (possible) VLAN headers, and checksum to the size.
-	 * For ETH_DATA_LEN (1500 bytes) this will add up to 1522 bytes.
-	 */
-	max_mtu += VLAN_ETH_HLEN;
-	max_mtu += ETH_FCS_LEN;
-
-	ret = ks8995_read_reg(ks, KS8995_REG_GC2, &val);
-	if (ret) {
-		dev_err(ks->dev, "failed to read KS8995_REG_GC2\n");
-		return ret;
-	}
-
-	if (max_mtu <= 1522) {
-		val &= ~KS8995_GC2_HUGE;
-		val &= ~KS8995_GC2_LEGAL;
-	} else if (max_mtu > 1522 && max_mtu <= 1536) {
-		/* This accepts packets up to 1536 bytes */
-		val &= ~KS8995_GC2_HUGE;
-		val |= KS8995_GC2_LEGAL;
-	} else {
-		/* This accepts packets up to 1916 bytes */
-		val |= KS8995_GC2_HUGE;
-		val |= KS8995_GC2_LEGAL;
-	}
-
-	dev_dbg(ks->dev, "new max MTU %d bytes (inclusive)\n", max_mtu);
-
-	ret = ks8995_write_reg(ks, KS8995_REG_GC2, val);
-	if (ret)
-		dev_err(ks->dev, "failed to set KS8995_REG_GC2\n");
-
-	return ret;
-}
-
-static int ks8995_get_max_mtu(struct dsa_switch *ds, int port)
-{
-	return 1916 - ETH_HLEN - ETH_FCS_LEN;
-}
-
-static const struct dsa_switch_ops ks8995_ds_ops = {
-	.get_tag_protocol = ks8995_get_tag_protocol,
-	.setup = ks8995_setup,
-	.port_pre_bridge_flags = ks8995_port_pre_bridge_flags,
-	.port_bridge_flags = ks8995_port_bridge_flags,
-	.port_enable = ks8995_port_enable,
-	.port_disable = ks8995_port_disable,
-	.port_stp_state_set = ks8995_port_stp_state_set,
-	.port_change_mtu = ks8995_change_mtu,
-	.port_max_mtu = ks8995_get_max_mtu,
-	.phylink_get_caps = ks8995_phylink_get_caps,
-};
-
-/* ------------------------------------------------------------------------ */
-static int ks8995_probe(struct spi_device *spi)
-{
-	struct ks8995_switch *ks;
-	int err;
-	int variant = spi_get_device_id(spi)->driver_data;
-
-	if (variant >= max_variant) {
-		dev_err(&spi->dev, "bad chip variant %d\n", variant);
-		return -ENODEV;
-	}
-
-	ks = devm_kzalloc(&spi->dev, sizeof(*ks), GFP_KERNEL);
-	if (!ks)
-		return -ENOMEM;
-
-	mutex_init(&ks->lock);
-	ks->spi = spi;
-	ks->dev = &spi->dev;
-	ks->chip = &ks8995_chip[variant];
-
-	ks->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
-						 GPIOD_OUT_HIGH);
-	err = PTR_ERR_OR_ZERO(ks->reset_gpio);
-	if (err) {
-		dev_err(&spi->dev,
-			"failed to get reset gpio: %d\n", err);
-		return err;
-	}
-
-	err = gpiod_set_consumer_name(ks->reset_gpio, "switch-reset");
-	if (err)
-		return err;
-
-	if (ks->reset_gpio) {
-		/*
-		 * If a reset line was obtained, wait for 100us after
-		 * de-asserting RESET before accessing any registers, see
-		 * the KS8995MA datasheet, page 44.
-		 */
-		gpiod_set_value_cansleep(ks->reset_gpio, 0);
-		udelay(100);
-	}
-
-	spi_set_drvdata(spi, ks);
-
-	spi->mode = SPI_MODE_0;
-	spi->bits_per_word = 8;
-	err = spi_setup(spi);
-	if (err) {
-		dev_err(&spi->dev, "spi_setup failed, err=%d\n", err);
-		return err;
-	}
-
-	err = ks8995_get_revision(ks);
-	if (err)
-		return err;
-
-	err = ks8995_reset(ks);
-	if (err)
-		return err;
-
-	dev_info(&spi->dev, "%s device found, Chip ID:%x, Revision:%x\n",
-		 ks->chip->name, ks->chip->chip_id, ks->revision_id);
-
-	err = ks8995_check_config(ks);
-	if (err)
-		return err;
-
-	ks->ds = devm_kzalloc(&spi->dev, sizeof(*ks->ds), GFP_KERNEL);
-	if (!ks->ds)
-		return -ENOMEM;
-
-	ks->ds->dev = &spi->dev;
-	ks->ds->num_ports = KS8995_NUM_PORTS;
-	ks->ds->ops = &ks8995_ds_ops;
-	ks->ds->phylink_mac_ops = &ks8995_phylink_mac_ops;
-	ks->ds->priv = ks;
-
-	err = dsa_register_switch(ks->ds);
-	if (err)
-		return dev_err_probe(&spi->dev, err,
-				     "unable to register DSA switch\n");
-
-	return 0;
-}
-
-static void ks8995_remove(struct spi_device *spi)
-{
-	struct ks8995_switch *ks = spi_get_drvdata(spi);
-
-	dsa_unregister_switch(ks->ds);
-	/* assert reset */
-	gpiod_set_value_cansleep(ks->reset_gpio, 1);
-}
-
-/* ------------------------------------------------------------------------ */
-static struct spi_driver ks8995_driver = {
-	.driver = {
-		.name	    = "spi-ks8995",
-		.of_match_table = ks8995_spi_of_match,
-	},
-	.probe	  = ks8995_probe,
-	.remove	  = ks8995_remove,
-	.id_table = ks8995_id,
-};
-
-module_spi_driver(ks8995_driver);
-
-MODULE_DESCRIPTION(DRV_DESC);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/dsa/microchip/Kconfig b/drivers/net/dsa/microchip/Kconfig
index c71d3fd5dfeb8..75c9b2114afd3 100644
--- a/drivers/net/dsa/microchip/Kconfig
+++ b/drivers/net/dsa/microchip/Kconfig
@@ -2,6 +2,7 @@
 menuconfig NET_DSA_MICROCHIP_KSZ_COMMON
 	tristate "Microchip KSZ8XXX/KSZ9XXX/LAN937X series switch support"
 	depends on NET_DSA
+	select NET_DSA_TAG_KS8995
 	select NET_DSA_TAG_KSZ
 	select NET_DSA_TAG_NONE
 	select NET_IEEE8021Q_HELPERS
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
index 941ae9f66f70b..c3871d5d6d367 100644
--- a/drivers/net/dsa/microchip/ksz8.c
+++ b/drivers/net/dsa/microchip/ksz8.c
@@ -3,6 +3,7 @@
  * Microchip KSZ8XXX series switch driver
  *
  * It supports the following switches:
+ * - KSZ8995XA (the oldest ancestor)
  * - KSZ8463
  * - KSZ8863, KSZ8873 aka KSZ88X3
  * - KSZ8895, KSZ8864 aka KSZ8895 family
@@ -20,6 +21,7 @@
 #include <linux/export.h>
 #include <linux/gpio/consumer.h>
 #include <linux/if_vlan.h>
+#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_data/microchip-ksz.h>
@@ -253,7 +255,35 @@ static int ksz8463_reset_switch(struct ksz_device *dev)
 
 static int ksz8_reset_switch(struct ksz_device *dev)
 {
-	if (ksz_is_ksz88x3(dev)) {
+	if (ksz_is_ksz8995xa(dev)) {
+		unsigned int port, reg, val;
+		int ret;
+
+		/* The KSZ8995XA switch itself cannot be reset by software, but
+		 * often boot loaders have fun with ports, so reset them. This
+		 * reset bit is self-clearing.
+		 */
+		for (port = 0; port < dev->info->port_cnt; port++) {
+			ret = ksz_prmw8(dev, port, REG_PORT_STATUS_3,
+					PORT_PHY_SOFT_RESET,
+					PORT_PHY_SOFT_RESET);
+			if (ret)
+				return ret;
+		}
+
+		/* IEEE 802.3 allows up to 500 ms for a PHY reset. */
+		for (port = 0; port < dev->info->port_cnt; port++) {
+			reg = dev->dev_ops->get_port_addr(port, REG_PORT_STATUS_3);
+			ret = regmap_read_poll_timeout(ksz_regmap_8(dev), reg, val,
+						       !(val & PORT_PHY_SOFT_RESET),
+						       1000, 600000);
+			if (ret)
+				return ret;
+		}
+
+		/* Some PHYs need additional settling time after reset. */
+		usleep_range(1000, 2000);
+	} else if (ksz_is_ksz88x3(dev)) {
 		/* reset switch */
 		ksz_cfg(dev, KSZ8863_REG_SW_RESET,
 			KSZ8863_GLOBAL_SOFTWARE_RESET | KSZ8863_PCS_RESET, true);
@@ -269,6 +299,31 @@ static int ksz8_reset_switch(struct ksz_device *dev)
 	return 0;
 }
 
+static int ksz8995xa_change_mtu(struct dsa_switch *ds, int port, int mtu)
+{
+	struct ksz_device *dev = ds->priv;
+	int frame_size;
+	u8 ctrl2 = 0;
+
+	if (!dsa_is_cpu_port(dev->ds, port))
+		return 0;
+
+	frame_size = mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
+
+	/* The legal packet size bit polarity documented in the KSZ8995XA
+	 * manual appears to be wrong. Practical tests show that the same
+	 * semantics as the other switches are correct; using the documented
+	 * polarity makes the switch hang on big packets.
+	 */
+	if (frame_size <= KSZ8995XA_LEGAL_PACKET_SIZE)
+		ctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE;
+	else if (frame_size > KSZ8863_NORMAL_PACKET_SIZE)
+		ctrl2 |= KSZ8863_HUGE_PACKET_ENABLE;
+
+	return ksz_rmw8(dev, REG_SW_CTRL_2, KSZ8863_LEGAL_PACKET_ENABLE |
+			KSZ8863_HUGE_PACKET_ENABLE, ctrl2);
+}
+
 static int ksz88xx_change_mtu(struct dsa_switch *ds, int port, int mtu)
 {
 	struct ksz_device *dev = ds->priv;
@@ -325,8 +380,8 @@ static int ksz88xx_max_mtu(struct dsa_switch *ds, int port)
 
 static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
 {
-	u8 mask_4q, mask_2q;
-	u8 reg_4q, reg_2q;
+	u8 mask_4q = 0, mask_2q;
+	u8 reg_4q = 0, reg_2q;
 	u8 data_4q = 0;
 	u8 data_2q = 0;
 	int ret;
@@ -352,6 +407,10 @@ static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
 		mask_2q = KSZ8873_PORT_2QUEUE_SPLIT_EN;
 		reg_4q = P1CR1;
 		reg_2q = P1CR1 + 1;
+	} else if (ksz_is_ksz8995xa(dev)) {
+		/* This switch has no 4way split support */
+		mask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;
+		reg_2q = REG_PORT_CTRL_0;
 	} else {
 		mask_4q = KSZ8795_PORT_4QUEUE_SPLIT_EN;
 		mask_2q = KSZ8795_PORT_2QUEUE_SPLIT_EN;
@@ -373,9 +432,11 @@ static int ksz8_port_queue_split(struct ksz_device *dev, int port, int queues)
 	else if (queues == 2)
 		data_2q = mask_2q;
 
-	ret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);
-	if (ret)
-		return ret;
+	if (mask_4q) {
+		ret = ksz_prmw8(dev, port, reg_4q, mask_4q, data_4q);
+		if (ret)
+			return ret;
+	}
 
 	return ksz_prmw8(dev, port, reg_2q, mask_2q, data_2q);
 }
@@ -970,6 +1031,10 @@ static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)
 	if (reg_val & PORT_MDIX_STATUS)
 		*val |= KSZ886X_CTRL_MDIX_STAT;
 
+	/* KSZ8995XA has no fancy features in register 0xA */
+	if (ksz_is_ksz8995xa(dev))
+		return 0;
+
 	ret = ksz_pread8(dev, port, REG_PORT_LINK_MD_CTRL, &reg_val);
 	if (ret < 0)
 		return ret;
@@ -1068,8 +1133,10 @@ static int ksz8_r_phy_bmcr(struct ksz_device *dev, u16 port, u16 *val)
 	if (ctrl & PORT_FORCE_FULL_DUPLEX)
 		*val |= BMCR_FULLDPLX;
 
-	if (speed & PORT_HP_MDIX)
-		*val |= KSZ886X_BMCR_HP_MDIX;
+	if (!ksz_is_ksz8995xa(dev)) {
+		if (speed & PORT_HP_MDIX)
+			*val |= KSZ886X_BMCR_HP_MDIX;
+	}
 
 	if (restart & PORT_FORCE_MDIX)
 		*val |= KSZ886X_BMCR_FORCE_MDI;
@@ -1164,6 +1231,9 @@ static int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
 			data |= LPA_LPACK;
 		break;
 	case PHY_REG_LINK_MD:
+		if (ksz_is_ksz8995xa(dev))
+			return -EOPNOTSUPP;
+
 		ret = ksz_pread8(dev, p, REG_PORT_LINK_MD_CTRL, &val1);
 		if (ret)
 			return ret;
@@ -1307,13 +1377,15 @@ static int ksz8_w_phy_bmcr(struct ksz_device *dev, u16 port, u16 val)
 	if (val & BMCR_RESET)
 		return 0;
 
-	speed = 0;
-	if (val & KSZ886X_BMCR_HP_MDIX)
-		speed |= PORT_HP_MDIX;
+	if (!ksz_is_ksz8995xa(dev)) {
+		speed = 0;
+		if (val & KSZ886X_BMCR_HP_MDIX)
+			speed |= PORT_HP_MDIX;
 
-	ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed);
-	if (ret)
-		return ret;
+		ret = ksz_prmw8(dev, port, regs[P_SPEED_STATUS], PORT_HP_MDIX, speed);
+		if (ret)
+			return ret;
+	}
 
 	ctrl = 0;
 	if (ksz_is_ksz88x3(dev)) {
@@ -1423,11 +1495,17 @@ static int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
 		}
 		break;
 	case PHY_REG_LINK_MD:
+		if (ksz_is_ksz8995xa(dev))
+			return -EOPNOTSUPP;
+
 		if (val & PHY_START_CABLE_DIAG)
 			ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
 		break;
 
 	case PHY_REG_PHY_CTRL:
+		if (ksz_is_ksz8995xa(dev))
+			return -EOPNOTSUPP;
+
 		ret = ksz8_w_phy_ctrl(dev, p, val);
 		if (ret)
 			return ret;
@@ -2043,12 +2121,14 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 
 	ksz8_port_queue_split(dev, port, dev->info->num_tx_queues);
 
-	/* replace priority */
-	offset = P_802_1P_CTRL;
-	if (ksz_is_ksz8463(dev))
-		offset = P1CR2;
-	ksz_port_cfg(dev, port, offset,
-		     masks[PORT_802_1P_REMAPPING], false);
+	if (!ksz_is_ksz8995xa(dev)) {
+		/* replace priority */
+		offset = P_802_1P_CTRL;
+		if (ksz_is_ksz8463(dev))
+			offset = P1CR2;
+		ksz_port_cfg(dev, port, offset,
+			     masks[PORT_802_1P_REMAPPING], false);
+	}
 
 	if (cpu_port)
 		member = dsa_user_ports(ds);
@@ -2057,6 +2137,21 @@ static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)
 
 	ksz8_cfg_port_member(dev, port, member);
 
+	if (ksz_is_ksz8995xa(dev)) {
+		/* Use VID 0 to identify untagged frames in the special tag */
+		ksz_pwrite16(dev, port, REG_PORT_CTRL_VID, 0);
+
+		/* The KSZ8995XA has a special tag format in the front of the frame
+		 * that need to be inserted by the CPU and then removed by each
+		 * port. PORT_REMOVE_TAG simply means "remove tags coming from the
+		 * CPU port" it does not affect ingress packets.
+		 */
+		if (cpu_port)
+			ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_INSERT_TAG, true);
+		else
+			ksz_port_cfg(dev, port, REG_PORT_CTRL_0, PORT_REMOVE_TAG, true);
+	}
+
 	/* Disable all WoL options by default. Otherwise
 	 * ksz_switch_macaddr_get/put logic will not work properly.
 	 * CPU port 4 has no WoL functionality.
@@ -2073,6 +2168,7 @@ static int ksz8_dsa_port_setup(struct dsa_switch *ds, int port)
 		return 0;
 
 	ksz8_port_setup(dev, port, false);
+
 	return ksz_dcb_init_port(dev, port);
 }
 
@@ -2147,7 +2243,9 @@ static void ksz8_config_cpu_port(struct dsa_switch *ds)
 	masks = dev->info->masks;
 	regs = dev->info->regs;
 
-	ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
+	/* KSZ8995XA uses a tag in the header instead of the tail */
+	if (!ksz_is_ksz8995xa(dev))
+		ksz_cfg(dev, regs[S_TAIL_TAG_CTRL], masks[SW_TAIL_TAG_ENABLE], true);
 
 	ksz8_port_setup(dev, dev->cpu_port, true);
 
@@ -2323,6 +2421,10 @@ static int ksz8_enable_stp_addr(struct ksz_device *dev)
 {
 	struct alu_struct alu;
 
+	/* KSZ8995XA lacks STP */
+	if (ksz_is_ksz8995xa(dev))
+		return 0;
+
 	/* Setup STP address for STP operation. */
 	memset(&alu, 0, sizeof(alu));
 	ether_addr_copy(alu.mac, eth_stp_addr);
@@ -2650,13 +2752,17 @@ static int ksz8_setup(struct dsa_switch *ds)
 	struct ksz_port *p;
 	const u16 *regs;
 	int i, ret;
+	u8 val;
 
 	regs = dev->info->regs;
 
-	dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
-				       dev->info->num_vlans, GFP_KERNEL);
-	if (!dev->vlan_cache)
-		return -ENOMEM;
+	/* KSZ8995XA has no SW controlled VLAN handling */
+	if (!ksz_is_ksz8995xa(dev)) {
+		dev->vlan_cache = devm_kcalloc(dev->dev, sizeof(struct vlan_table),
+					       dev->info->num_vlans, GFP_KERNEL);
+		if (!dev->vlan_cache)
+			return -ENOMEM;
+	}
 
 	ret = ksz8_reset_switch(dev);
 	if (ret) {
@@ -2685,19 +2791,22 @@ static int ksz8_setup(struct dsa_switch *ds)
 
 	ksz_init_mib_timer(dev);
 
-	ds->configure_vlan_while_not_filtering = false;
 	ds->dscp_prio_mapping_is_global = true;
 	ds->mtu_enforcement_ingress = true;
 
-	/* We rely on software untagging on the CPU port, so that we
-	 * can support both tagged and untagged VLANs
-	 */
-	ds->untag_bridge_pvid = true;
+	if (!ksz_is_ksz8995xa(dev)) {
+		ds->configure_vlan_while_not_filtering = false;
 
-	/* VLAN filtering is partly controlled by the global VLAN
-	 * Enable flag
-	 */
-	ds->vlan_filtering_is_global = true;
+		/* We rely on software untagging on the CPU port, so that we
+		 * can support both tagged and untagged VLANs
+		 */
+		ds->untag_bridge_pvid = true;
+
+		/* VLAN filtering is partly controlled by the global VLAN
+		 * Enable flag
+		 */
+		ds->vlan_filtering_is_global = true;
+	}
 
 	/* Enable automatic fast aging when link changed detected. */
 	ksz_cfg(dev, S_LINK_AGING_CTRL, SW_LINK_AUTO_AGING, true);
@@ -2711,9 +2820,10 @@ static int ksz8_setup(struct dsa_switch *ds)
 	 * Make sure unicast VLAN boundary is set as default and
 	 * enable no excessive collision drop.
 	 */
-	ret = ksz_rmw8(dev, REG_SW_CTRL_2,
-		       UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP,
-		       UNICAST_VLAN_BOUNDARY | NO_EXC_COLLISION_DROP);
+	val = NO_EXC_COLLISION_DROP;
+	if (!ksz_is_ksz8995xa(dev))
+		val |= UNICAST_VLAN_BOUNDARY;
+	ret = ksz_rmw8(dev, REG_SW_CTRL_2, val, val);
 	if (ret)
 		return ret;
 
@@ -2721,11 +2831,15 @@ static int ksz8_setup(struct dsa_switch *ds)
 
 	ksz_cfg(dev, S_MIRROR_CTRL, SW_MIRROR_RX_TX, false);
 
-	if (!ksz_is_ksz88x3(dev))
+	if (ksz_is_ksz8995xa(dev))
+		ksz_cfg(dev, REG_SW_CTRL_9, SW_SPECIAL_TAG, true);
+	else if (!ksz_is_ksz88x3(dev))
 		ksz_cfg(dev, REG_SW_CTRL_19, SW_INS_TAG_ENABLE, true);
 
-	for (i = 0; i < (dev->info->num_vlans / 4); i++)
-		ksz8_r_vlan_entries(dev, i);
+	if (!ksz_is_ksz8995xa(dev)) {
+		for (i = 0; i < (dev->info->num_vlans / 4); i++)
+			ksz8_r_vlan_entries(dev, i);
+	}
 
 	/* Make sure PME (WoL) is not enabled. If requested, it will
 	 * be enabled by ksz_wol_pre_shutdown(). Otherwise, some PMICs
@@ -2976,6 +3090,13 @@ static int ksz8_switch_init(struct ksz_device *dev)
 	return 0;
 }
 
+static enum dsa_tag_protocol ksz8995xa_get_tag_protocol(struct dsa_switch *ds,
+							int port,
+							enum dsa_tag_protocol mp)
+{
+	return DSA_TAG_PROTO_KS8995;
+}
+
 static enum dsa_tag_protocol ksz8463_get_tag_protocol(struct dsa_switch *ds,
 						      int port,
 						      enum dsa_tag_protocol mp)
@@ -3072,6 +3193,16 @@ const struct phylink_mac_ops ksz8_phylink_mac_ops = {
 	.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
 };
 
+/*
+ * The KS(Z)8995XA has no indirect access, meaning no MIB counters,
+ * no FDB access, and no VLAN handling.
+ */
+const struct ksz_dev_ops ksz8995xa_dev_ops = {
+	.get_port_addr = ksz8_get_port_addr,
+	.cfg_port_member = ksz8_cfg_port_member,
+	.init = ksz8_switch_init,
+};
+
 const struct ksz_dev_ops ksz8463_dev_ops = {
 	.get_port_addr = ksz8463_get_port_addr,
 	.cfg_port_member = ksz8_cfg_port_member,
@@ -3111,6 +3242,38 @@ const struct ksz_dev_ops ksz88xx_dev_ops = {
 	.pme_pwrite8 = ksz8_pme_pwrite8,
 };
 
+/*
+ * Restricted operations for KSZ8995XA, so many things are not supported
+ * by this old switch that we need diet DSA operations.
+ */
+const struct dsa_switch_ops ksz8995xa_switch_ops = {
+	.get_tag_protocol	= ksz8995xa_get_tag_protocol,
+	.setup			= ksz8_setup,
+	.teardown		= ksz_teardown,
+	.phy_read		= ksz8_phy_read16,
+	.phy_write		= ksz8_phy_write16,
+	.phylink_get_caps	= ksz8_phylink_get_caps,
+	.port_setup		= ksz8_dsa_port_setup,
+	.port_bridge_join	= ksz_port_bridge_join,
+	.port_bridge_leave	= ksz_port_bridge_leave,
+	.port_set_mac_address	= ksz_port_set_mac_address,
+	.port_stp_state_set	= ksz_port_stp_state_set,
+	.port_pre_bridge_flags	= ksz_port_pre_bridge_flags,
+	.port_bridge_flags	= ksz_port_bridge_flags,
+	.port_fast_age		= ksz8_flush_dyn_mac_table,
+	.port_mirror_add	= ksz8_port_mirror_add,
+	.port_mirror_del	= ksz8_port_mirror_del,
+	.port_change_mtu	= ksz8995xa_change_mtu,
+	.port_max_mtu		= ksz88xx_max_mtu,
+	.port_get_default_prio	= ksz_port_get_default_prio,
+	.port_set_default_prio	= ksz_port_set_default_prio,
+	.port_get_dscp_prio	= ksz_port_get_dscp_prio,
+	.port_add_dscp_prio	= ksz_port_add_dscp_prio,
+	.port_del_dscp_prio	= ksz_port_del_dscp_prio,
+	.port_get_apptrust	= ksz_port_get_apptrust,
+	.port_set_apptrust	= ksz_port_set_apptrust,
+};
+
 const struct dsa_switch_ops ksz8463_switch_ops = {
 	.get_tag_protocol	= ksz8463_get_tag_protocol,
 	.connect_tag_protocol   = ksz8463_connect_tag_protocol,
diff --git a/drivers/net/dsa/microchip/ksz8.h b/drivers/net/dsa/microchip/ksz8.h
index bc371cc26c6f1..9b37c56c9617e 100644
--- a/drivers/net/dsa/microchip/ksz8.h
+++ b/drivers/net/dsa/microchip/ksz8.h
@@ -12,11 +12,13 @@
 #include <net/dsa.h>
 #include "ksz_common.h"
 
+extern const struct ksz_dev_ops ksz8995xa_dev_ops;
 extern const struct ksz_dev_ops ksz8463_dev_ops;
 extern const struct ksz_dev_ops ksz87xx_dev_ops;
 extern const struct ksz_dev_ops ksz88xx_dev_ops;
 extern const struct phylink_mac_ops ksz88x3_phylink_mac_ops;
 extern const struct phylink_mac_ops ksz8_phylink_mac_ops;
+extern const struct dsa_switch_ops ksz8995xa_switch_ops;
 extern const struct dsa_switch_ops ksz8463_switch_ops;
 extern const struct dsa_switch_ops ksz87xx_switch_ops;
 extern const struct dsa_switch_ops ksz88xx_switch_ops;
diff --git a/drivers/net/dsa/microchip/ksz8_reg.h b/drivers/net/dsa/microchip/ksz8_reg.h
index 6bc511da1f7dd..f858bce84bfd4 100644
--- a/drivers/net/dsa/microchip/ksz8_reg.h
+++ b/drivers/net/dsa/microchip/ksz8_reg.h
@@ -95,6 +95,8 @@
 #define SW_LED_LINK_ACT_DUPLEX		2
 #define SW_LED_LINK_DUPLEX		3
 
+#define SW_SPECIAL_TAG			BIT(0) /* KSZ8995XA only */
+
 #define REG_SW_CTRL_10			0x0C
 
 #define SW_PASS_PAUSE			BIT(0)
diff --git a/drivers/net/dsa/microchip/ksz_common.c b/drivers/net/dsa/microchip/ksz_common.c
index 1a9d6f83a0232..6c15ac97a7e3f 100644
--- a/drivers/net/dsa/microchip/ksz_common.c
+++ b/drivers/net/dsa/microchip/ksz_common.c
@@ -446,6 +446,20 @@ static const u8 ksz8895_shifts[] = {
 	[DYNAMIC_MAC_SRC_PORT]		= 24,
 };
 
+static const u16 ksz8995xa_regs[] = {
+	[REG_SW_MAC_ADDR]		= 0x68,
+	[P_FORCE_CTRL]			= 0x0C,
+	[P_LINK_STATUS]			= 0x0E,
+	[P_LOCAL_CTRL]			= 0x0C,
+	[P_NEG_RESTART_CTRL]		= 0x0D,
+	[P_REMOTE_STATUS]		= 0x0E,
+	[P_SPEED_STATUS]		= 0x09,
+	[P_STP_CTRL]			= 0x02,
+	[S_START_CTRL]			= 0x01,
+	[S_BROADCAST_CTRL]		= 0x06,
+	[S_MULTICAST_CTRL]		= 0x04,
+};
+
 static const u16 ksz9477_regs[] = {
 	[REG_SW_MAC_ADDR]		= 0x0302,
 	[P_STP_CTRL]			= 0x0B04,
@@ -1377,6 +1391,21 @@ const struct ksz_chip_data ksz_switch_chips[] = {
 		.internal_phy = {true, true, true, true, false},
 	},
 
+	[KSZ8995XA] = {
+		.chip_id = KSZ8995XA_CHIP_ID, /* Also known as KS8995XA */
+		.dev_name = "KSZ8995XA",
+		.cpu_ports = 0x10,	/* can be configured as cpu port */
+		.port_cnt = 5,		/* total cpu and user ports */
+		.num_tx_queues = 2,	/* low/hi priority queues, no more */
+		.num_ipms = 2,
+		.ops = &ksz8995xa_dev_ops,
+		.switch_ops = &ksz8995xa_switch_ops,
+		.phylink_mac_ops = &ksz88x3_phylink_mac_ops,
+		.regs = ksz8995xa_regs,
+		.supports_mii = {true, true, true, true, true},
+		.internal_phy = {true, true, true, true, false},
+	},
+
 	[KSZ9477] = {
 		.chip_id = KSZ9477_CHIP_ID,
 		.dev_name = "KSZ9477",
@@ -2649,6 +2678,10 @@ void ksz_init_mib_timer(struct ksz_device *dev)
 {
 	int i;
 
+	/* KSZ8995XA lacks MiB features */
+	if (ksz_is_ksz8995xa(dev))
+		return;
+
 	INIT_DELAYED_WORK(&dev->mib_read, ksz_mib_read_work);
 
 	for (i = 0; i < dev->info->port_cnt; i++) {
@@ -2944,11 +2977,15 @@ static int ksz_switch_detect(struct ksz_device *dev)
 			return -ENODEV;
 		break;
 	case KSZ8895_FAMILY_ID:
-		if (id2 == KSZ8895_CHIP_ID_95 ||
-		    id2 == KSZ8895_CHIP_ID_95R)
+		if (id2 == KSZ8895_CHIP_ID_95XA) {
+			dev->chip_id = KSZ8995XA_CHIP_ID;
+			break;
+		} else if (id2 == KSZ8895_CHIP_ID_95 ||
+			   id2 == KSZ8895_CHIP_ID_95R) {
 			dev->chip_id = KSZ8895_CHIP_ID;
-		else
+		} else {
 			return -ENODEV;
+		}
 		ret = ksz_read8(dev, REG_KSZ8864_CHIP_ID, &id4);
 		if (ret)
 			return ret;
@@ -4029,11 +4066,13 @@ int ksz_switch_register(struct ksz_device *dev)
 	if (ret)
 		return ret;
 
-	/* Read MIB counters every 30 seconds to avoid overflow. */
-	dev->mib_read_interval = msecs_to_jiffies(5000);
+	if (!ksz_is_ksz8995xa(dev)) {
+		/* Read MIB counters every 30 seconds to avoid overflow. */
+		dev->mib_read_interval = msecs_to_jiffies(5000);
 
-	/* Start the MIB timer. */
-	schedule_delayed_work(&dev->mib_read, 0);
+		/* Start the MIB timer. */
+		schedule_delayed_work(&dev->mib_read, 0);
+	}
 
 	return ret;
 }
diff --git a/drivers/net/dsa/microchip/ksz_common.h b/drivers/net/dsa/microchip/ksz_common.h
index cbe98494578c3..93be74f7a2658 100644
--- a/drivers/net/dsa/microchip/ksz_common.h
+++ b/drivers/net/dsa/microchip/ksz_common.h
@@ -281,6 +281,7 @@ enum ksz_model {
 	KSZ88X3,
 	KSZ8864,
 	KSZ8895,
+	KSZ8995XA,
 	KSZ9477,
 	KSZ9896,
 	KSZ9897,
@@ -789,7 +790,13 @@ static inline bool ksz_is_ksz88x3(struct ksz_device *dev)
 static inline bool ksz_is_8895_family(struct ksz_device *dev)
 {
 	return dev->chip_id == KSZ8895_CHIP_ID ||
-	       dev->chip_id == KSZ8864_CHIP_ID;
+	       dev->chip_id == KSZ8864_CHIP_ID ||
+	       dev->chip_id == KSZ8995XA_CHIP_ID;
+}
+
+static inline bool ksz_is_ksz8995xa(struct ksz_device *dev)
+{
+	return dev->chip_id == KSZ8995XA_CHIP_ID;
 }
 
 static inline bool is_ksz8(struct ksz_device *dev)
@@ -860,6 +867,7 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port)
 #define KSZ87_CHIP_ID_94		0x6
 #define KSZ87_CHIP_ID_95		0x9
 #define KSZ88_CHIP_ID_63		0x3
+#define KSZ8895_CHIP_ID_95XA		0x0
 #define KSZ8895_CHIP_ID_95		0x4
 #define KSZ8895_CHIP_ID_95R		0x6
 
@@ -923,6 +931,7 @@ static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port)
 #define KSZ8863_HUGE_PACKET_SIZE	1916
 #define KSZ8863_NORMAL_PACKET_SIZE	1536
 #define KSZ8_LEGAL_PACKET_SIZE		1518
+#define KSZ8995XA_LEGAL_PACKET_SIZE	1522
 #define KSZ9477_MAX_FRAME_SIZE		9000
 
 #define KSZ8873_REG_GLOBAL_CTRL_12	0x0e
diff --git a/drivers/net/dsa/microchip/ksz_dcb.c b/drivers/net/dsa/microchip/ksz_dcb.c
index 7131c5caac547..968de88e8ddd3 100644
--- a/drivers/net/dsa/microchip/ksz_dcb.c
+++ b/drivers/net/dsa/microchip/ksz_dcb.c
@@ -20,10 +20,12 @@
 #define KSZ8_PORT_DIFFSERV_ENABLE		BIT(6)
 #define KSZ8_PORT_802_1P_ENABLE			BIT(5)
 #define KSZ8_PORT_BASED_PRIO_M			GENMASK(4, 3)
+#define KSZ8995XA_PORT_BASED_PRIO		BIT(4)
 
 #define KSZ8463_REG_TOS_DSCP_CTRL		0x16
 #define KSZ88X3_REG_TOS_DSCP_CTRL		0x60
 #define KSZ8765_REG_TOS_DSCP_CTRL		0x90
+#define KSZ8995XA_REG_TOS_DSCP_CTRL_7		0x67
 
 #define KSZ9477_REG_SW_MAC_TOS_CTRL		0x033e
 #define KSZ9477_SW_TOS_DSCP_REMAP		BIT(0)
@@ -98,8 +100,11 @@ static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,
 {
 	if (is_ksz8(dev)) {
 		*reg = KSZ8_REG_PORT_1_CTRL_0;
-		*mask = KSZ8_PORT_BASED_PRIO_M;
-		*shift = __bf_shf(KSZ8_PORT_BASED_PRIO_M);
+		if (ksz_is_ksz8995xa(dev))
+			*mask = KSZ8995XA_PORT_BASED_PRIO;
+		else
+			*mask = KSZ8_PORT_BASED_PRIO_M;
+		*shift = __bf_shf(*mask);
 		if (ksz_is_ksz8463(dev))
 			*reg = KSZ8463_REG_PORT_1_CTRL_0;
 	} else {
@@ -112,31 +117,45 @@ static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,
 /**
  * ksz_get_dscp_prio_reg - Retrieves the DSCP-to-priority-mapping register
  * @dev: Pointer to the KSZ switch device structure
+ * @dscp: DSCP value for which to retrieve the register
  * @reg: Pointer to the register address to be set
- * @per_reg: Pointer to the number of DSCP values per register
  * @mask: Pointer to the mask to be set
+ * @shift: Pointer to the bit shift to be set
  *
- * This function retrieves the DSCP to priority mapping register, the number of
- * DSCP values per register, and the mask to be set.
+ * This function retrieves the register, mask and shift for a DSCP to priority
+ * mapping entry.
  */
-static void ksz_get_dscp_prio_reg(struct ksz_device *dev, int *reg,
-				  int *per_reg, u8 *mask)
+static void ksz_get_dscp_prio_reg(struct ksz_device *dev, u8 dscp, int *reg,
+				  u8 *mask, int *shift)
 {
+	int per_reg;
+
+	if (ksz_is_ksz8995xa(dev)) {
+		/* KSZ8995XA stores DSCP groups in descending register order. */
+		*reg = KSZ8995XA_REG_TOS_DSCP_CTRL_7 - dscp / 8;
+		*mask = BIT(0);
+		*shift = dscp % 8;
+		return;
+	}
+
 	if (ksz_is_ksz87xx(dev) || ksz_is_8895_family(dev)) {
 		*reg = KSZ8765_REG_TOS_DSCP_CTRL;
-		*per_reg = 4;
+		per_reg = 4;
 		*mask = GENMASK(1, 0);
 	} else if (ksz_is_ksz88x3(dev) || ksz_is_ksz8463(dev)) {
 		*reg = KSZ88X3_REG_TOS_DSCP_CTRL;
-		*per_reg = 4;
+		per_reg = 4;
 		*mask = GENMASK(1, 0);
 		if (ksz_is_ksz8463(dev))
 			*reg = KSZ8463_REG_TOS_DSCP_CTRL;
 	} else {
 		*reg = KSZ9477_REG_DIFFSERV_PRIO_MAP;
-		*per_reg = 2;
+		per_reg = 2;
 		*mask = GENMASK(2, 0);
 	}
+
+	*reg += dscp / per_reg;
+	*shift = (dscp % per_reg) * (8 / per_reg);
 }
 
 /**
@@ -236,10 +255,10 @@ int ksz_port_set_default_prio(struct dsa_switch *ds, int port, u8 prio)
 int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
 {
 	struct ksz_device *dev = ds->priv;
-	int reg, per_reg, ret, shift;
+	int reg, ret, shift;
 	u8 data, mask;
 
-	ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);
+	ksz_get_dscp_prio_reg(dev, dscp, &reg, &mask, &shift);
 
 	/* If DSCP remapping is disabled, DSCP bits 3-5 are used as Internal
 	 * Priority Map (IPM)
@@ -260,13 +279,10 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
 	/* In case DSCP remapping is enabled, we need to write the DSCP to
 	 * priority mapping table.
 	 */
-	reg += dscp / per_reg;
 	ret = ksz_read8(dev, reg, &data);
 	if (ret)
 		return ret;
 
-	shift = (dscp % per_reg) * (8 / per_reg);
-
 	return (data >> shift) & mask;
 }
 
@@ -283,15 +299,12 @@ int ksz_port_get_dscp_prio(struct dsa_switch *ds, int port, u8 dscp)
  */
 static int ksz_set_global_dscp_entry(struct ksz_device *dev, u8 dscp, u8 ipm)
 {
-	int reg, per_reg, shift;
+	int reg, shift;
 	u8 mask;
 
-	ksz_get_dscp_prio_reg(dev, &reg, &per_reg, &mask);
-
-	shift = (dscp % per_reg) * (8 / per_reg);
+	ksz_get_dscp_prio_reg(dev, dscp, &reg, &mask, &shift);
 
-	return ksz_rmw8(dev, reg + (dscp / per_reg), mask << shift,
-			ipm << shift);
+	return ksz_rmw8(dev, reg, mask << shift, ipm << shift);
 }
 
 /**
diff --git a/drivers/net/dsa/microchip/ksz_spi.c b/drivers/net/dsa/microchip/ksz_spi.c
index 373e9054947cb..e3bb9e604186d 100644
--- a/drivers/net/dsa/microchip/ksz_spi.c
+++ b/drivers/net/dsa/microchip/ksz_spi.c
@@ -161,7 +161,8 @@ static int ksz_spi_probe(struct spi_device *spi)
 		 chip->chip_id == KSZ8794_CHIP_ID ||
 		 chip->chip_id == KSZ8765_CHIP_ID)
 		regmap_config = ksz8795_regmap_config;
-	else if (chip->chip_id == KSZ8895_CHIP_ID ||
+	else if (chip->chip_id == KSZ8995XA_CHIP_ID ||
+		 chip->chip_id == KSZ8895_CHIP_ID ||
 		 chip->chip_id == KSZ8864_CHIP_ID)
 		regmap_config = ksz8863_regmap_config;
 	else
@@ -185,7 +186,10 @@ static int ksz_spi_probe(struct spi_device *spi)
 		dev->pdata = spi->dev.platform_data;
 
 	/* setup spi */
-	spi->mode = SPI_MODE_3;
+	if (chip->chip_id == KSZ8995XA_CHIP_ID)
+		spi->mode = SPI_MODE_0;
+	else
+		spi->mode = SPI_MODE_3;
 	ret = spi_setup(spi);
 	if (ret)
 		return ret;
@@ -224,6 +228,25 @@ static void ksz_spi_shutdown(struct spi_device *spi)
 }
 
 static const struct of_device_id ksz_dt_ids[] = {
+	/*
+	 * Legacy Micrel bindings. In 2015 Microchip acquired
+	 * Micrel which is the originator of the KSZ series, and
+	 * devices branded for Micrel already existed, as well as
+	 * some device tree bindings. These two products are identical
+	 * to the same Microchip products.
+	 */
+	{
+		.compatible = "micrel,ksz8864",
+		.data = &ksz_switch_chips[KSZ8864]
+	},
+	{
+		.compatible = "micrel,ksz8795",
+		.data = &ksz_switch_chips[KSZ8795]
+	},
+	{
+		.compatible = "micrel,ks8995",
+		.data = &ksz_switch_chips[KSZ8995XA]
+	},
 	{
 		.compatible = "microchip,ksz8463",
 		.data = &ksz_switch_chips[KSZ8463]
@@ -256,6 +279,10 @@ static const struct of_device_id ksz_dt_ids[] = {
 		.compatible = "microchip,ksz8895",
 		.data = &ksz_switch_chips[KSZ8895]
 	},
+	{
+		.compatible = "microchip,ksz8995xa",
+		.data = &ksz_switch_chips[KSZ8995XA]
+	},
 	{
 		.compatible = "microchip,ksz9477",
 		.data = &ksz_switch_chips[KSZ9477]
@@ -317,6 +344,7 @@ static const struct of_device_id ksz_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, ksz_dt_ids);
 
 static const struct spi_device_id ksz_spi_ids[] = {
+	{ "ks8995" },
 	{ "ksz8463" },
 	{ "ksz8765" },
 	{ "ksz8794" },
@@ -325,6 +353,7 @@ static const struct spi_device_id ksz_spi_ids[] = {
 	{ "ksz8864" },
 	{ "ksz8873" },
 	{ "ksz8895" },
+	{ "ksz8995xa" },
 	{ "ksz9477" },
 	{ "ksz9896" },
 	{ "ksz9897" },
diff --git a/include/linux/platform_data/microchip-ksz.h b/include/linux/platform_data/microchip-ksz.h
index 028781ad40593..d8eddd21c3c7d 100644
--- a/include/linux/platform_data/microchip-ksz.h
+++ b/include/linux/platform_data/microchip-ksz.h
@@ -31,6 +31,7 @@ enum ksz_chip_id {
 	KSZ88X3_CHIP_ID = 0x8830,
 	KSZ8864_CHIP_ID = 0x8864,
 	KSZ8895_CHIP_ID = 0x8895,
+	KSZ8995XA_CHIP_ID = 0x8995,
 	KSZ9477_CHIP_ID = 0x00947700,
 	KSZ9896_CHIP_ID = 0x00989600,
 	KSZ9897_CHIP_ID = 0x00989700,
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 7507d632e7c6d..5d12191b6f6f5 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -61,6 +61,7 @@ struct tc_action;
 #define DSA_TAG_PROTO_NETC_VALUE		33
 #define DSA_TAG_PROTO_KSZ8463_VALUE		34
 #define DSA_TAG_PROTO_MT7628_VALUE		35
+#define DSA_TAG_PROTO_KS8995_VALUE		36
 
 enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NONE		= DSA_TAG_PROTO_NONE_VALUE,
@@ -99,6 +100,7 @@ enum dsa_tag_protocol {
 	DSA_TAG_PROTO_NETC		= DSA_TAG_PROTO_NETC_VALUE,
 	DSA_TAG_PROTO_KSZ8463		= DSA_TAG_PROTO_KSZ8463_VALUE,
 	DSA_TAG_PROTO_MT7628		= DSA_TAG_PROTO_MT7628_VALUE,
+	DSA_TAG_PROTO_KS8995		= DSA_TAG_PROTO_KS8995_VALUE,
 };
 
 struct dsa_switch;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 23b4b74004ed5..4f44bf3ede238 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -125,6 +125,12 @@ config NET_DSA_TAG_MXL_GSW1XX
 	  Say Y or M if you want to enable support for tagging frames for
 	  MaxLinear GSW1xx switches.
 
+config NET_DSA_TAG_KS8995
+	tristate "Tag driver for Micrel KS8995 switch"
+	help
+	  Say Y if you want to enable support for tagging frames for the
+	  Micrel KS8995 switch.
+
 config NET_DSA_TAG_KSZ
 	tristate "Tag driver for Microchip 8795/937x/9477/9893 families of switches"
 	help
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index d15bcf5c68f02..1f9cc30e99886 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_NET_DSA_TAG_BRCM_COMMON) += tag_brcm.o
 obj-$(CONFIG_NET_DSA_TAG_DSA_COMMON) += tag_dsa.o
 obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
 obj-$(CONFIG_NET_DSA_TAG_HELLCREEK) += tag_hellcreek.o
+obj-$(CONFIG_NET_DSA_TAG_KS8995) += tag_ks8995.o
 obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
 obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
 obj-$(CONFIG_NET_DSA_TAG_MT7628) += tag_mt7628.o
diff --git a/net/dsa/tag_ks8995.c b/net/dsa/tag_ks8995.c
new file mode 100644
index 0000000000000..f6ef1ef1891fd
--- /dev/null
+++ b/net/dsa/tag_ks8995.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Linus Walleij <linusw@kernel.org>
+ */
+#include <linux/etherdevice.h>
+#include <linux/log2.h>
+#include <linux/list.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+
+#include "tag.h"
+
+/* The Micrel KS8995XA / Microchip KSZ8995XA Special Tag Packet ID (STPID)
+ * pushes its tag in a modified VLAN (802.1Q) tag.
+ * -----------------------------------------------------------
+ * | MAC DA | MAC SA | 2 bytes tag | 2 bytes TCI | EtherType |
+ * -----------------------------------------------------------
+ * The tag is: 0x8100 |= BIT(port), ports 0,1,2,3
+ */
+
+#define KS8995_NAME "ks8995"
+
+#define KS8995M_STPID_STD	GENMASK(15, 4)
+#define KS8995M_STPID_PORTMASK	GENMASK(3, 0)
+#define KS8995M_STPID(portmask)	htons(ETH_P_8021Q | FIELD_PREP(KS8995M_STPID_PORTMASK, portmask))
+
+static struct sk_buff *ks8995_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vlan_ethhdr *hdr;
+	u16 portmask;
+
+	/* Prepare the special KS8995 tags */
+	portmask = dsa_xmit_port_mask(skb, dev);
+
+	/* The switch expects the special tag at offset 12. Move any hardware
+	 * accelerated VLAN tag into the payload so the conduit cannot insert
+	 * it outside the special tag.
+	 */
+	if (unlikely(skb_vlan_tag_present(skb))) {
+		skb = __vlan_hwaccel_push_inside(skb);
+		if (!skb)
+			return NULL;
+	}
+
+	/* Always add a distinct outer tag. The user port removes this field on
+	 * egress, so reusing an existing 802.1Q tag would consume that VLAN tag.
+	 */
+	skb = vlan_insert_tag(skb, KS8995M_STPID(portmask), 0);
+	/* vlan_insert_tag() drops the skb on failure */
+	if (!skb)
+		return NULL;
+	hdr = skb_vlan_eth_hdr(skb);
+	netdev_dbg(dev, "%s: inserted VLAN TAG %04x TCI %04x\n",
+		   __func__, ntohs(hdr->h_vlan_proto),
+		   ntohs(hdr->h_vlan_TCI));
+
+	return skb;
+}
+
+static struct sk_buff *ks8995_rcv(struct sk_buff *skb, struct net_device *dev)
+{
+	int portmask;
+	int port;
+	u16 etype;
+
+	/* We are expecting all received packets to have a mangled VLAN
+	 * TPID, so drop anything else. Because of the non-standard TPID,
+	 * don't even bother looking for a tag in the hwaccel area.
+	 *
+	 * We have to inspect the ethertype directly because skb->protocol
+	 * will contain garbage.
+	 */
+	etype = ntohs(*(__be16 *)dsa_etype_header_pos_rx(skb));
+	if ((etype & KS8995M_STPID_STD) != ETH_P_8021Q) {
+		netdev_dbg(dev, "%s: dropped ethertype 0x%04x\n",
+			   __func__, etype);
+		kfree_skb(skb);
+		return NULL;
+	}
+
+	portmask = FIELD_GET(KS8995M_STPID_PORTMASK, etype);
+	if (unlikely(!is_power_of_2(portmask))) {
+		netdev_dbg(dev, "%s: dropped invalid port mask 0x%04x\n",
+			   __func__, portmask);
+		kfree_skb(skb);
+		return NULL;
+	}
+	port = ilog2(portmask);
+
+	netdev_dbg(dev, "%s: received ethertype %04x\n",
+		   __func__, etype);
+
+	/* Move the custom DSA+VLAN tag into the hwaccel area and strip
+	 * it from the skb head
+	 */
+	skb = skb_vlan_untag(skb);
+	if (!skb) {
+		/* skb_vlan_untag drops the skb on failure */
+		if (net_ratelimit())
+			netdev_err(dev, "%s: unable to untag skb\n", __func__);
+		return NULL;
+	}
+
+	netdev_dbg(dev, "%s: etype %04x portmask %04x (%d)\n",
+		   __func__, etype, portmask, port);
+	skb->dev = dsa_conduit_find_user(dev, 0, port);
+	if (!skb->dev) {
+		kfree_skb(skb);
+		return NULL;
+	}
+
+	/* skb_vlan_untag() moved the special tag's TCI into the hardware-
+	 * accelerated VLAN metadata. The switch preserves the TCI of tagged
+	 * frames, but inserts the ingress port's default tag for untagged frames.
+	 * Since the driver programs the default tag to 0, a zero TCI identifies
+	 * an originally untagged frame. Preserve every non-zero TCI as an
+	 * 802.1Q tag, including VID 0 frames with PCP or DEI set.
+	 */
+	if (!skb->vlan_tci) {
+		netdev_dbg(dev, "%s: clear VLAN tag from frame\n", __func__);
+		__vlan_hwaccel_clear_tag(skb);
+	} else {
+		skb->vlan_proto = htons(ETH_P_8021Q);
+		netdev_dbg(dev, "%s: vlan_tci = 0x%04x VLAN frame\n",
+			   __func__, skb->vlan_tci);
+	}
+
+	dsa_default_offload_fwd_mark(skb);
+
+	return skb;
+}
+
+static const struct dsa_device_ops ks8995_netdev_ops = {
+	.name = KS8995_NAME,
+	.proto	= DSA_TAG_PROTO_KS8995,
+	.xmit = ks8995_xmit,
+	.rcv = ks8995_rcv,
+	.needed_headroom = VLAN_HLEN,
+};
+
+MODULE_DESCRIPTION("DSA tag driver for Micrel KS8995 family of switches");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KS8995, KS8995_NAME);
+
+module_dsa_tag_driver(ks8995_netdev_ops);

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

Args:
null

Results:
null

Tokens:
							input: 30517
							output: 30
							thoughts: 506
						

Thoughts:
**Analyzing this Patch Series for Fuzzing Potential**

Okay, let's dive into this patch series and see if it's worth our time to throw syzkaller at it. The first thing I'm doing is a quick review of the touched files: Documentation, MAINTAINERS, Kconfig files, Makefiles, and a bunch of files related to the Microchip KSZ8 and KS8995 switch drivers, including header files and common code. I see `drivers/net/dsa/ks8995.c` is deleted which is interesting, and there's a new file, `net/dsa/tag_ks8995.c`.

Hold on... this looks like a migration of the KS8995/KSZ8995XA switch support from its own driver into the Microchip sub-directory, and a new DSA tag driver is added! This is the key. Now, the big question is: can we actually get at these DSA tag drivers with syzkaller in a standard virtualized environment like QEMU or GCE? That's what I really need to understand.

How does DSA tagging actually work? I need to figure out if we can fuzz these protocols or reach them at all. Can we instantiate DSA tag protocol drivers and fuzz them using things like the DSA loop, mock netdev, DSA conduit, mock DSA switch setup, or even directly inject packets using user sockets? I need to do some searching to understand how DSA and the DSA tagging protocols work within the kernel before I can make a decision about fuzzing this series. There's potential here, but I need to understand the attack surface.



4/2 2026/09/09 17:26 tool grepper
0m Args:
{
  "Expression": "DSA_TAG_PROTO_",
  "PathPrefix": "net/dsa"
}

Results:
{
  "Output": "net/dsa/dsa.c=1129=static enum dsa_tag_protocol dsa_get_tag_protocol(struct dsa_port *dp,\n--\nnet/dsa/dsa.c-1131-{\nnet/dsa/dsa.c:1132:\tenum dsa_tag_protocol tag_protocol = DSA_TAG_PROTO_NONE;\nnet/dsa/dsa.c-1133-\tstruct dsa_switch *mds, *ds = dp-\u003eds;\n--\nnet/dsa/dsa.c-1145-\t\ttag_protocol = mds-\u003eops-\u003eget_tag_protocol(mds, mdp_upstream,\nnet/dsa/dsa.c:1146:\t\t\t\t\t\t\t  DSA_TAG_PROTO_NONE);\nnet/dsa/dsa.c-1147-\t}\n--\nnet/dsa/tag_ar9331.c=90=static const struct dsa_device_ops ar9331_netdev_ops = {\nnet/dsa/tag_ar9331.c-91-\t.name\t= AR9331_NAME,\nnet/dsa/tag_ar9331.c:92:\t.proto\t= DSA_TAG_PROTO_AR9331,\nnet/dsa/tag_ar9331.c-93-\t.xmit\t= ar9331_tag_xmit,\n--\nnet/dsa/tag_ar9331.c=99=MODULE_LICENSE(\"GPL v2\");\nnet/dsa/tag_ar9331.c:100:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_AR9331, AR9331_NAME);\nnet/dsa/tag_ar9331.c-101-module_dsa_tag_driver(ar9331_netdev_ops);\n--\nnet/dsa/tag_brcm.c=89=static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb,\n--\nnet/dsa/tag_brcm.c-136- * -----------------------------------\nnet/dsa/tag_brcm.c:137: * | MAC DA | MAC SA | 4b tag | Type | DSA_TAG_PROTO_BRCM\nnet/dsa/tag_brcm.c-138- * -----------------------------------\nnet/dsa/tag_brcm.c-139- * -----------------------------------\nnet/dsa/tag_brcm.c:140: * | 4b tag | MAC DA | MAC SA | Type | DSA_TAG_PROTO_BRCM_PREPEND\nnet/dsa/tag_brcm.c-141- * -----------------------------------\n--\nnet/dsa/tag_brcm.c=217=static const struct dsa_device_ops brcm_netdev_ops = {\nnet/dsa/tag_brcm.c-218-\t.name\t= BRCM_NAME,\nnet/dsa/tag_brcm.c:219:\t.proto\t= DSA_TAG_PROTO_BRCM,\nnet/dsa/tag_brcm.c-220-\t.xmit\t= brcm_tag_xmit,\n--\nnet/dsa/tag_brcm.c=225=DSA_TAG_DRIVER(brcm_netdev_ops);\nnet/dsa/tag_brcm.c:226:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM, BRCM_NAME);\nnet/dsa/tag_brcm.c-227-#endif\n--\nnet/dsa/tag_brcm.c=311=static const struct dsa_device_ops brcm_legacy_netdev_ops = {\nnet/dsa/tag_brcm.c-312-\t.name = BRCM_LEGACY_NAME,\nnet/dsa/tag_brcm.c:313:\t.proto = DSA_TAG_PROTO_BRCM_LEGACY,\nnet/dsa/tag_brcm.c-314-\t.xmit = brcm_leg_tag_xmit,\n--\nnet/dsa/tag_brcm.c=319=DSA_TAG_DRIVER(brcm_legacy_netdev_ops);\nnet/dsa/tag_brcm.c:320:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY, BRCM_LEGACY_NAME);\nnet/dsa/tag_brcm.c-321-#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY */\n--\nnet/dsa/tag_brcm.c=370=static const struct dsa_device_ops brcm_legacy_fcs_netdev_ops = {\nnet/dsa/tag_brcm.c-371-\t.name = BRCM_LEGACY_FCS_NAME,\nnet/dsa/tag_brcm.c:372:\t.proto = DSA_TAG_PROTO_BRCM_LEGACY_FCS,\nnet/dsa/tag_brcm.c-373-\t.xmit = brcm_leg_fcs_tag_xmit,\n--\nnet/dsa/tag_brcm.c=378=DSA_TAG_DRIVER(brcm_legacy_fcs_netdev_ops);\nnet/dsa/tag_brcm.c:379:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_LEGACY_FCS, BRCM_LEGACY_FCS_NAME);\nnet/dsa/tag_brcm.c-380-#endif /* CONFIG_NET_DSA_TAG_BRCM_LEGACY_FCS */\n--\nnet/dsa/tag_brcm.c=397=static const struct dsa_device_ops brcm_prepend_netdev_ops = {\nnet/dsa/tag_brcm.c-398-\t.name\t= BRCM_PREPEND_NAME,\nnet/dsa/tag_brcm.c:399:\t.proto\t= DSA_TAG_PROTO_BRCM_PREPEND,\nnet/dsa/tag_brcm.c-400-\t.xmit\t= brcm_tag_xmit_prepend,\n--\nnet/dsa/tag_brcm.c=405=DSA_TAG_DRIVER(brcm_prepend_netdev_ops);\nnet/dsa/tag_brcm.c:406:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_BRCM_PREPEND, BRCM_PREPEND_NAME);\nnet/dsa/tag_brcm.c-407-#endif\n--\nnet/dsa/tag_dsa.c=351=static const struct dsa_device_ops dsa_netdev_ops = {\nnet/dsa/tag_dsa.c-352-\t.name\t  = DSA_NAME,\nnet/dsa/tag_dsa.c:353:\t.proto\t  = DSA_TAG_PROTO_DSA,\nnet/dsa/tag_dsa.c-354-\t.xmit\t  = dsa_xmit,\n--\nnet/dsa/tag_dsa.c=359=DSA_TAG_DRIVER(dsa_netdev_ops);\nnet/dsa/tag_dsa.c:360:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_DSA, DSA_NAME);\nnet/dsa/tag_dsa.c-361-#endif\t/* CONFIG_NET_DSA_TAG_DSA */\n--\nnet/dsa/tag_dsa.c=395=static const struct dsa_device_ops edsa_netdev_ops = {\nnet/dsa/tag_dsa.c-396-\t.name\t  = EDSA_NAME,\nnet/dsa/tag_dsa.c:397:\t.proto\t  = DSA_TAG_PROTO_EDSA,\nnet/dsa/tag_dsa.c-398-\t.xmit\t  = edsa_xmit,\n--\nnet/dsa/tag_dsa.c=403=DSA_TAG_DRIVER(edsa_netdev_ops);\nnet/dsa/tag_dsa.c:404:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_EDSA, EDSA_NAME);\nnet/dsa/tag_dsa.c-405-#endif\t/* CONFIG_NET_DSA_TAG_EDSA */\n--\nnet/dsa/tag_gswip.c=104=static const struct dsa_device_ops gswip_netdev_ops = {\nnet/dsa/tag_gswip.c-105-\t.name = GSWIP_NAME,\nnet/dsa/tag_gswip.c:106:\t.proto\t= DSA_TAG_PROTO_GSWIP,\nnet/dsa/tag_gswip.c-107-\t.xmit = gswip_tag_xmit,\n--\nnet/dsa/tag_gswip.c=113=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_gswip.c:114:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_GSWIP, GSWIP_NAME);\nnet/dsa/tag_gswip.c-115-\n--\nnet/dsa/tag_hellcreek.c=66=static const struct dsa_device_ops hellcreek_netdev_ops = {\nnet/dsa/tag_hellcreek.c-67-\t.name\t  = HELLCREEK_NAME,\nnet/dsa/tag_hellcreek.c:68:\t.proto\t  = DSA_TAG_PROTO_HELLCREEK,\nnet/dsa/tag_hellcreek.c-69-\t.xmit\t  = hellcreek_xmit,\n--\nnet/dsa/tag_hellcreek.c=75=MODULE_LICENSE(\"Dual MIT/GPL\");\nnet/dsa/tag_hellcreek.c:76:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_HELLCREEK, HELLCREEK_NAME);\nnet/dsa/tag_hellcreek.c-77-\n--\nnet/dsa/tag_ks8995.c=133=static const struct dsa_device_ops ks8995_netdev_ops = {\nnet/dsa/tag_ks8995.c-134-\t.name = KS8995_NAME,\nnet/dsa/tag_ks8995.c:135:\t.proto\t= DSA_TAG_PROTO_KS8995,\nnet/dsa/tag_ks8995.c-136-\t.xmit = ks8995_xmit,\n--\nnet/dsa/tag_ks8995.c=142=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_ks8995.c:143:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KS8995, KS8995_NAME);\nnet/dsa/tag_ks8995.c-144-\n--\nnet/dsa/tag_ksz.c=309=static const struct dsa_device_ops ksz9477_netdev_ops = {\nnet/dsa/tag_ksz.c-310-\t.name\t= KSZ9477_NAME,\nnet/dsa/tag_ksz.c:311:\t.proto\t= DSA_TAG_PROTO_KSZ9477,\nnet/dsa/tag_ksz.c-312-\t.xmit\t= ksz9477_xmit,\n--\nnet/dsa/tag_ksz.c=319=DSA_TAG_DRIVER(ksz9477_netdev_ops);\nnet/dsa/tag_ksz.c:320:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9477, KSZ9477_NAME);\nnet/dsa/tag_ksz.c-321-\n--\nnet/dsa/tag_ksz.c=361=static const struct dsa_device_ops ksz8795_netdev_ops = {\nnet/dsa/tag_ksz.c-362-\t.name\t= KSZ8795_NAME,\nnet/dsa/tag_ksz.c:363:\t.proto\t= DSA_TAG_PROTO_KSZ8795,\nnet/dsa/tag_ksz.c-364-\t.xmit\t= ksz8795_xmit,\n--\nnet/dsa/tag_ksz.c=369=DSA_TAG_DRIVER(ksz8795_netdev_ops);\nnet/dsa/tag_ksz.c:370:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME);\nnet/dsa/tag_ksz.c-371-\n--\nnet/dsa/tag_ksz.c=387=static const struct dsa_device_ops ksz9893_netdev_ops = {\nnet/dsa/tag_ksz.c-388-\t.name\t= KSZ9893_NAME,\nnet/dsa/tag_ksz.c:389:\t.proto\t= DSA_TAG_PROTO_KSZ9893,\nnet/dsa/tag_ksz.c-390-\t.xmit\t= ksz9893_xmit,\n--\nnet/dsa/tag_ksz.c=397=DSA_TAG_DRIVER(ksz9893_netdev_ops);\nnet/dsa/tag_ksz.c:398:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893, KSZ9893_NAME);\nnet/dsa/tag_ksz.c-399-\n--\nnet/dsa/tag_ksz.c=451=static const struct dsa_device_ops ksz8463_netdev_ops = {\nnet/dsa/tag_ksz.c-452-\t.name\t= KSZ8463_NAME,\nnet/dsa/tag_ksz.c:453:\t.proto\t= DSA_TAG_PROTO_KSZ8463,\nnet/dsa/tag_ksz.c-454-\t.xmit\t= ksz8463_xmit,\n--\nnet/dsa/tag_ksz.c=461=DSA_TAG_DRIVER(ksz8463_netdev_ops);\nnet/dsa/tag_ksz.c:462:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8463, KSZ8463_NAME);\nnet/dsa/tag_ksz.c-463-\n--\nnet/dsa/tag_ksz.c=522=static const struct dsa_device_ops lan937x_netdev_ops = {\nnet/dsa/tag_ksz.c-523-\t.name\t= LAN937X_NAME,\nnet/dsa/tag_ksz.c:524:\t.proto\t= DSA_TAG_PROTO_LAN937X,\nnet/dsa/tag_ksz.c-525-\t.xmit\t= lan937x_xmit,\n--\nnet/dsa/tag_ksz.c=532=DSA_TAG_DRIVER(lan937x_netdev_ops);\nnet/dsa/tag_ksz.c:533:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN937X, LAN937X_NAME);\nnet/dsa/tag_ksz.c-534-\n--\nnet/dsa/tag_lan9303.c=116=static const struct dsa_device_ops lan9303_netdev_ops = {\nnet/dsa/tag_lan9303.c-117-\t.name = LAN9303_NAME,\nnet/dsa/tag_lan9303.c:118:\t.proto\t= DSA_TAG_PROTO_LAN9303,\nnet/dsa/tag_lan9303.c-119-\t.xmit = lan9303_xmit,\n--\nnet/dsa/tag_lan9303.c=125=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_lan9303.c:126:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9303, LAN9303_NAME);\nnet/dsa/tag_lan9303.c-127-\n--\nnet/dsa/tag_mt7628.c=81=static const struct dsa_device_ops mt7628_tag_ops = {\nnet/dsa/tag_mt7628.c-82-\t.name = MT7628_TAG_NAME,\nnet/dsa/tag_mt7628.c:83:\t.proto = DSA_TAG_PROTO_MT7628,\nnet/dsa/tag_mt7628.c-84-\t.xmit = mt7628_tag_xmit,\n--\nnet/dsa/tag_mt7628.c=89=module_dsa_tag_driver(mt7628_tag_ops);\nnet/dsa/tag_mt7628.c-90-\nnet/dsa/tag_mt7628.c:91:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MT7628, MT7628_TAG_NAME);\nnet/dsa/tag_mt7628.c-92-MODULE_DESCRIPTION(\"DSA tag driver for MT7628 switch\");\n--\nnet/dsa/tag_mtk.c=102=static const struct dsa_device_ops mtk_netdev_ops = {\nnet/dsa/tag_mtk.c-103-\t.name\t\t= MTK_NAME,\nnet/dsa/tag_mtk.c:104:\t.proto\t\t= DSA_TAG_PROTO_MTK,\nnet/dsa/tag_mtk.c-105-\t.xmit\t\t= mtk_tag_xmit,\n--\nnet/dsa/tag_mtk.c=111=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_mtk.c:112:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MTK, MTK_NAME);\nnet/dsa/tag_mtk.c-113-\n--\nnet/dsa/tag_mxl-gsw1xx.c=108=static const struct dsa_device_ops gsw1xx_netdev_ops = {\nnet/dsa/tag_mxl-gsw1xx.c-109-\t.name\t\t\t= GSW1XX_TAG_NAME,\nnet/dsa/tag_mxl-gsw1xx.c:110:\t.proto\t\t\t= DSA_TAG_PROTO_MXL_GSW1XX,\nnet/dsa/tag_mxl-gsw1xx.c-111-\t.xmit\t\t\t= gsw1xx_tag_xmit,\n--\nnet/dsa/tag_mxl-gsw1xx.c=117=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_mxl-gsw1xx.c:118:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL_GSW1XX, GSW1XX_TAG_NAME);\nnet/dsa/tag_mxl-gsw1xx.c-119-\n--\nnet/dsa/tag_mxl862xx.c=104=static const struct dsa_device_ops mxl862_netdev_ops = {\nnet/dsa/tag_mxl862xx.c-105-\t.name = MXL862_NAME,\nnet/dsa/tag_mxl862xx.c:106:\t.proto = DSA_TAG_PROTO_MXL862,\nnet/dsa/tag_mxl862xx.c-107-\t.xmit = mxl862_tag_xmit,\n--\nnet/dsa/tag_mxl862xx.c-111-\nnet/dsa/tag_mxl862xx.c:112:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_MXL862, MXL862_NAME);\nnet/dsa/tag_mxl862xx.c-113-MODULE_DESCRIPTION(\"DSA tag driver for MaxLinear MxL862xx switches\");\n--\nnet/dsa/tag_netc.c=203=static const struct dsa_device_ops netc_netdev_ops = {\nnet/dsa/tag_netc.c-204-\t.name\t\t\t= NETC_NAME,\nnet/dsa/tag_netc.c:205:\t.proto\t\t\t= DSA_TAG_PROTO_NETC,\nnet/dsa/tag_netc.c-206-\t.xmit\t\t\t= netc_xmit,\n--\nnet/dsa/tag_netc.c=213=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_netc.c-214-\nnet/dsa/tag_netc.c:215:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NETC, NETC_NAME);\nnet/dsa/tag_netc.c-216-module_dsa_tag_driver(netc_netdev_ops);\n--\nnet/dsa/tag_none.c=22=static const struct dsa_device_ops none_ops = {\nnet/dsa/tag_none.c-23-\t.name\t= NONE_NAME,\nnet/dsa/tag_none.c:24:\t.proto\t= DSA_TAG_PROTO_NONE,\nnet/dsa/tag_none.c-25-\t.xmit\t= dsa_user_notag_xmit,\n--\nnet/dsa/tag_none.c=28=module_dsa_tag_driver(none_ops);\nnet/dsa/tag_none.c:29:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_NONE, NONE_NAME);\nnet/dsa/tag_none.c-30-MODULE_DESCRIPTION(\"DSA no-op tag driver\");\n--\nnet/dsa/tag_ocelot.c=156=static const struct dsa_device_ops ocelot_netdev_ops = {\nnet/dsa/tag_ocelot.c-157-\t.name\t\t\t= OCELOT_NAME,\nnet/dsa/tag_ocelot.c:158:\t.proto\t\t\t= DSA_TAG_PROTO_OCELOT,\nnet/dsa/tag_ocelot.c-159-\t.xmit\t\t\t= ocelot_xmit,\n--\nnet/dsa/tag_ocelot.c=165=DSA_TAG_DRIVER(ocelot_netdev_ops);\nnet/dsa/tag_ocelot.c:166:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT, OCELOT_NAME);\nnet/dsa/tag_ocelot.c-167-\nnet/dsa/tag_ocelot.c=168=static const struct dsa_device_ops seville_netdev_ops = {\nnet/dsa/tag_ocelot.c-169-\t.name\t\t\t= SEVILLE_NAME,\nnet/dsa/tag_ocelot.c:170:\t.proto\t\t\t= DSA_TAG_PROTO_SEVILLE,\nnet/dsa/tag_ocelot.c-171-\t.xmit\t\t\t= seville_xmit,\n--\nnet/dsa/tag_ocelot.c=177=DSA_TAG_DRIVER(seville_netdev_ops);\nnet/dsa/tag_ocelot.c:178:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SEVILLE, SEVILLE_NAME);\nnet/dsa/tag_ocelot.c-179-\n--\nnet/dsa/tag_ocelot_8021q.c=131=static const struct dsa_device_ops ocelot_8021q_netdev_ops = {\nnet/dsa/tag_ocelot_8021q.c-132-\t.name\t\t\t= OCELOT_8021Q_NAME,\nnet/dsa/tag_ocelot_8021q.c:133:\t.proto\t\t\t= DSA_TAG_PROTO_OCELOT_8021Q,\nnet/dsa/tag_ocelot_8021q.c-134-\t.xmit\t\t\t= ocelot_xmit,\n--\nnet/dsa/tag_ocelot_8021q.c=143=MODULE_LICENSE(\"GPL v2\");\nnet/dsa/tag_ocelot_8021q.c:144:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT_8021Q, OCELOT_8021Q_NAME);\nnet/dsa/tag_ocelot_8021q.c-145-\n--\nnet/dsa/tag_qca.c=118=static const struct dsa_device_ops qca_netdev_ops = {\nnet/dsa/tag_qca.c-119-\t.name\t= QCA_NAME,\nnet/dsa/tag_qca.c:120:\t.proto\t= DSA_TAG_PROTO_QCA,\nnet/dsa/tag_qca.c-121-\t.connect = qca_tag_connect,\n--\nnet/dsa/tag_qca.c=130=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_qca.c:131:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_QCA, QCA_NAME);\nnet/dsa/tag_qca.c-132-\n--\nnet/dsa/tag_rtl4_a.c=119=static const struct dsa_device_ops rtl4a_netdev_ops = {\nnet/dsa/tag_rtl4_a.c-120-\t.name\t= RTL4_A_NAME,\nnet/dsa/tag_rtl4_a.c:121:\t.proto\t= DSA_TAG_PROTO_RTL4_A,\nnet/dsa/tag_rtl4_a.c-122-\t.xmit\t= rtl4a_tag_xmit,\n--\nnet/dsa/tag_rtl4_a.c=129=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_rtl4_a.c:130:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL4_A, RTL4_A_NAME);\n--\nnet/dsa/tag_rtl8_4.c=246=static const struct dsa_device_ops rtl8_4_netdev_ops = {\nnet/dsa/tag_rtl8_4.c-247-\t.name = \"rtl8_4\",\nnet/dsa/tag_rtl8_4.c:248:\t.proto = DSA_TAG_PROTO_RTL8_4,\nnet/dsa/tag_rtl8_4.c-249-\t.xmit = rtl8_4_tag_xmit,\n--\nnet/dsa/tag_rtl8_4.c=254=DSA_TAG_DRIVER(rtl8_4_netdev_ops);\nnet/dsa/tag_rtl8_4.c-255-\nnet/dsa/tag_rtl8_4.c:256:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4, RTL8_4_NAME);\nnet/dsa/tag_rtl8_4.c-257-\n--\nnet/dsa/tag_rtl8_4.c=259=static const struct dsa_device_ops rtl8_4t_netdev_ops = {\nnet/dsa/tag_rtl8_4.c-260-\t.name = \"rtl8_4t\",\nnet/dsa/tag_rtl8_4.c:261:\t.proto = DSA_TAG_PROTO_RTL8_4T,\nnet/dsa/tag_rtl8_4.c-262-\t.xmit = rtl8_4t_tag_xmit,\n--\nnet/dsa/tag_rtl8_4.c=267=DSA_TAG_DRIVER(rtl8_4t_netdev_ops);\nnet/dsa/tag_rtl8_4.c-268-\nnet/dsa/tag_rtl8_4.c:269:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4T, RTL8_4T_NAME);\nnet/dsa/tag_rtl8_4.c-270-\n--\nnet/dsa/tag_rzn1_a5psw.c=108=static const struct dsa_device_ops a5psw_netdev_ops = {\nnet/dsa/tag_rzn1_a5psw.c-109-\t.name\t= A5PSW_NAME,\nnet/dsa/tag_rzn1_a5psw.c:110:\t.proto\t= DSA_TAG_PROTO_RZN1_A5PSW,\nnet/dsa/tag_rzn1_a5psw.c-111-\t.xmit\t= a5psw_tag_xmit,\n--\nnet/dsa/tag_rzn1_a5psw.c=117=MODULE_LICENSE(\"GPL v2\");\nnet/dsa/tag_rzn1_a5psw.c:118:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_A5PSW, A5PSW_NAME);\nnet/dsa/tag_rzn1_a5psw.c-119-module_dsa_tag_driver(a5psw_netdev_ops);\n--\nnet/dsa/tag_sja1105.c=736=static const struct dsa_device_ops sja1105_netdev_ops = {\nnet/dsa/tag_sja1105.c-737-\t.name = SJA1105_NAME,\nnet/dsa/tag_sja1105.c:738:\t.proto = DSA_TAG_PROTO_SJA1105,\nnet/dsa/tag_sja1105.c-739-\t.xmit = sja1105_xmit,\n--\nnet/dsa/tag_sja1105.c=748=DSA_TAG_DRIVER(sja1105_netdev_ops);\nnet/dsa/tag_sja1105.c:749:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SJA1105, SJA1105_NAME);\nnet/dsa/tag_sja1105.c-750-\nnet/dsa/tag_sja1105.c=751=static const struct dsa_device_ops sja1110_netdev_ops = {\nnet/dsa/tag_sja1105.c-752-\t.name = SJA1110_NAME,\nnet/dsa/tag_sja1105.c:753:\t.proto = DSA_TAG_PROTO_SJA1110,\nnet/dsa/tag_sja1105.c-754-\t.xmit = sja1110_xmit,\n--\nnet/dsa/tag_sja1105.c=763=DSA_TAG_DRIVER(sja1110_netdev_ops);\nnet/dsa/tag_sja1105.c:764:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_SJA1110, SJA1110_NAME);\nnet/dsa/tag_sja1105.c-765-\n--\nnet/dsa/tag_trailer.c=61=static const struct dsa_device_ops trailer_netdev_ops = {\nnet/dsa/tag_trailer.c-62-\t.name\t= TRAILER_NAME,\nnet/dsa/tag_trailer.c:63:\t.proto\t= DSA_TAG_PROTO_TRAILER,\nnet/dsa/tag_trailer.c-64-\t.xmit\t= trailer_xmit,\n--\nnet/dsa/tag_trailer.c=70=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_trailer.c:71:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_TRAILER, TRAILER_NAME);\nnet/dsa/tag_trailer.c-72-\n--\nnet/dsa/tag_vsc73xx_8021q.c=56=static const struct dsa_device_ops vsc73xx_8021q_netdev_ops = {\nnet/dsa/tag_vsc73xx_8021q.c-57-\t.name\t\t\t= VSC73XX_8021Q_NAME,\nnet/dsa/tag_vsc73xx_8021q.c:58:\t.proto\t\t\t= DSA_TAG_PROTO_VSC73XX_8021Q,\nnet/dsa/tag_vsc73xx_8021q.c-59-\t.xmit\t\t\t= vsc73xx_xmit,\n--\nnet/dsa/tag_vsc73xx_8021q.c=66=MODULE_DESCRIPTION(\"DSA tag driver for VSC73XX family of switches, using VLAN\");\nnet/dsa/tag_vsc73xx_8021q.c:67:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_VSC73XX_8021Q, VSC73XX_8021Q_NAME);\nnet/dsa/tag_vsc73xx_8021q.c-68-\n--\nnet/dsa/tag_xrs700x.c=55=static const struct dsa_device_ops xrs700x_netdev_ops = {\nnet/dsa/tag_xrs700x.c-56-\t.name\t= XRS700X_NAME,\nnet/dsa/tag_xrs700x.c:57:\t.proto\t= DSA_TAG_PROTO_XRS700X,\nnet/dsa/tag_xrs700x.c-58-\t.xmit\t= xrs700x_xmit,\n--\nnet/dsa/tag_xrs700x.c=64=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_xrs700x.c:65:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_XRS700X, XRS700X_NAME);\nnet/dsa/tag_xrs700x.c-66-\n--\nnet/dsa/tag_yt921x.c=161=static const struct dsa_device_ops yt921x_netdev_ops = {\nnet/dsa/tag_yt921x.c-162-\t.name\t= YT921X_TAG_NAME,\nnet/dsa/tag_yt921x.c:163:\t.proto\t= DSA_TAG_PROTO_YT921X,\nnet/dsa/tag_yt921x.c-164-\t.xmit\t= yt921x_tag_xmit,\n--\nnet/dsa/tag_yt921x.c=170=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_yt921x.c:171:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_YT921X, YT921X_TAG_NAME);\nnet/dsa/tag_yt921x.c-172-\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 40668
							output: 29
							thoughts: 138
						

Thoughts:
**Fuzzing DSA Tag Drivers and Switches**

Okay, so I'm thinking about fuzzing these DSA components. The core question is: can we actually *reach* DSA tag drivers or DSA switches within a typical fuzzing setup? That's the real challenge. First, let's focus on those DSA tag drivers. How do they actually get invoked in the first place? My mind is running through the different scenarios.

A DSA switch registers and connects to a conduit netdevice – that's one avenue. Then there's the `dsa_loop` driver, which seems like a promising testbed. It essentially creates a mock DSA switch using a fixed PHY/MDIO bus. Or, perhaps, users modify the tagging protocol through Netlink, sysfs, RTNL, or the DSA conduit itself.

Hmm, I need to investigate a bit deeper now. Let's see how the DSA tagging protocol can be manipulated. I need to understand how `dsa_loop` functions more thoroughly, and whether something like `DSA_TAG_PROTO_KS8995` would be a usable target in my tests. This will inform how I craft my fuzzing approach to get to these drivers.



6/2 2026/09/09 17:26 tool grepper
0m Args:
{
  "Expression": "change_tag_proto",
  "PathPrefix": "net/dsa"
}

Results:
{
  "Output": "net/dsa/conduit.c=350=static ssize_t tagging_store(struct device *d, struct device_attribute *attr,\n--\nnet/dsa/conduit.c-380-\nnet/dsa/conduit.c:381:\terr = dsa_tree_change_tag_proto(cpu_dp-\u003eds-\u003edst, new_tag_ops,\nnet/dsa/conduit.c-382-\t\t\t\t\told_tag_ops);\n--\nnet/dsa/dsa.c=570=static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds)\n--\nnet/dsa/dsa.c-579-\trtnl_lock();\nnet/dsa/dsa.c:580:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/dsa.c-581-\trtnl_unlock();\n--\nnet/dsa/dsa.c=948=static int dsa_tree_bind_tag_proto(struct dsa_switch_tree *dst,\n--\nnet/dsa/dsa.c-982- */\nnet/dsa/dsa.c:983:int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\nnet/dsa/dsa.c-984-\t\t\t      const struct dsa_device_ops *tag_ops,\n--\nnet/dsa/dsa.c=1155=static int dsa_port_parse_cpu(struct dsa_port *dp, struct net_device *conduit,\n--\nnet/dsa/dsa.c-1176-\tif (user_protocol) {\nnet/dsa/dsa.c:1177:\t\tif (!ds-\u003eops-\u003echange_tag_protocol) {\nnet/dsa/dsa.c-1178-\t\t\tdev_err(ds-\u003edev, \"Tag protocol cannot be modified\\n\");\n--\nnet/dsa/dsa.c-1230-\t * dsa_switch_setup_tag_protocol once .setup has run and the\nnet/dsa/dsa.c:1231:\t * driver is ready to accept calls to .change_tag_protocol. If\nnet/dsa/dsa.c-1232-\t * the driver does not support the custom protocol at that\n--\nnet/dsa/dsa.h=24=struct net_device *dsa_tree_find_first_conduit(struct dsa_switch_tree *dst);\nnet/dsa/dsa.h:25:int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,\nnet/dsa/dsa.h-26-\t\t\t      const struct dsa_device_ops *tag_ops,\n--\nnet/dsa/switch.c=853=static int dsa_switch_host_vlan_del(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-872-\nnet/dsa/switch.c:873:static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\nnet/dsa/switch.c-874-\t\t\t\t       struct dsa_notifier_tag_proto_info *info)\n--\nnet/dsa/switch.c-879-\nnet/dsa/switch.c:880:\tif (!ds-\u003eops-\u003echange_tag_protocol)\nnet/dsa/switch.c-881-\t\treturn -EOPNOTSUPP;\n--\nnet/dsa/switch.c-884-\nnet/dsa/switch.c:885:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/switch.c-886-\tif (err)\n--\nnet/dsa/switch.c-900-\nnet/dsa/switch.c:901:\t\t/* rtnl_mutex is held in dsa_tree_change_tag_proto */\nnet/dsa/switch.c-902-\t\tdsa_user_change_mtu(user, user-\u003emtu);\n--\nnet/dsa/switch.c=974=static int dsa_switch_event(struct notifier_block *nb,\n--\nnet/dsa/switch.c-1044-\tcase DSA_NOTIFIER_TAG_PROTO:\nnet/dsa/switch.c:1045:\t\terr = dsa_switch_change_tag_proto(ds, info);\nnet/dsa/switch.c-1046-\t\tbreak;\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 42248
							output: 34
							thoughts: 35
						

Thoughts:
Okay, let's break this down.

**Investigating the DSA Loop Driver's Tag Protocol Capabilities**

Alright, I'm trying to figure something out about the `dsa_loop` driver. My initial thought is, "Can the `dsa_loop` driver actually modify the tag protocol of frames?". That's the core question here. To get a definite answer, I know I need to dig into the source code. Specifically, the place to start looking is the implementation of the driver itself: `drivers/net/dsa/dsa_loop.c`. I need to inspect that file to understand if any logic exists to handle or manipulate frame tagging. This is where the truth lies, and where I'll find my answer.



8/2 2026/09/09 17:26 tool grepper
0m Args:
{
  "Expression": ".*",
  "PathPrefix": "drivers/net/dsa/dsa_loop.c"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 516 lines.\nUse more precise expression if possible.\n\ndrivers/net/dsa/dsa_loop.c:1:// SPDX-License-Identifier: GPL-2.0-or-later\ndrivers/net/dsa/dsa_loop.c:2:/*\ndrivers/net/dsa/dsa_loop.c:3: * Distributed Switch Architecture loopback driver\ndrivers/net/dsa/dsa_loop.c:4: *\ndrivers/net/dsa/dsa_loop.c:5: * Copyright (C) 2016, Florian Fainelli \u003cf.fainelli@gmail.com\u003e\ndrivers/net/dsa/dsa_loop.c:6: */\ndrivers/net/dsa/dsa_loop.c:7:\ndrivers/net/dsa/dsa_loop.c:8:#include \u003clinux/platform_device.h\u003e\ndrivers/net/dsa/dsa_loop.c:9:#include \u003clinux/netdevice.h\u003e\ndrivers/net/dsa/dsa_loop.c:10:#include \u003clinux/phy.h\u003e\ndrivers/net/dsa/dsa_loop.c:11:#include \u003clinux/phy_fixed.h\u003e\ndrivers/net/dsa/dsa_loop.c:12:#include \u003clinux/export.h\u003e\ndrivers/net/dsa/dsa_loop.c:13:#include \u003clinux/ethtool.h\u003e\ndrivers/net/dsa/dsa_loop.c:14:#include \u003clinux/workqueue.h\u003e\ndrivers/net/dsa/dsa_loop.c:15:#include \u003clinux/module.h\u003e\ndrivers/net/dsa/dsa_loop.c:16:#include \u003clinux/if_bridge.h\u003e\ndrivers/net/dsa/dsa_loop.c:17:#include \u003clinux/if_vlan.h\u003e\ndrivers/net/dsa/dsa_loop.c:18:#include \u003clinux/types.h\u003e\ndrivers/net/dsa/dsa_loop.c:19:#include \u003cnet/dsa.h\u003e\ndrivers/net/dsa/dsa_loop.c:20:\ndrivers/net/dsa/dsa_loop.c:21:#define DSA_LOOP_NUM_PORTS\t6\ndrivers/net/dsa/dsa_loop.c:22:#define DSA_LOOP_CPU_PORT\t(DSA_LOOP_NUM_PORTS - 1)\ndrivers/net/dsa/dsa_loop.c:23:#define NUM_FIXED_PHYS\t\t(DSA_LOOP_NUM_PORTS - 2)\ndrivers/net/dsa/dsa_loop.c:24:\ndrivers/net/dsa/dsa_loop.c:25:struct dsa_loop_vlan {\ndrivers/net/dsa/dsa_loop.c:26:\tu16 members;\ndrivers/net/dsa/dsa_loop.c:27:\tu16 untagged;\ndrivers/net/dsa/dsa_loop.c:28:};\ndrivers/net/dsa/dsa_loop.c:29:\ndrivers/net/dsa/dsa_loop.c:30:struct dsa_loop_mib_entry {\ndrivers/net/dsa/dsa_loop.c:31:\tchar name[ETH_GSTRING_LEN];\ndrivers/net/dsa/dsa_loop.c:32:\tunsigned long val;\ndrivers/net/dsa/dsa_loop.c:33:};\ndrivers/net/dsa/dsa_loop.c:34:\ndrivers/net/dsa/dsa_loop.c:35:enum dsa_loop_mib_counters {\ndrivers/net/dsa/dsa_loop.c:36:\tDSA_LOOP_PHY_READ_OK,\ndrivers/net/dsa/dsa_loop.c:37:\tDSA_LOOP_PHY_READ_ERR,\ndrivers/net/dsa/dsa_loop.c:38:\tDSA_LOOP_PHY_WRITE_OK,\ndrivers/net/dsa/dsa_loop.c:39:\tDSA_LOOP_PHY_WRITE_ERR,\ndrivers/net/dsa/dsa_loop.c:40:\t__DSA_LOOP_CNT_MAX,\ndrivers/net/dsa/dsa_loop.c:41:};\ndrivers/net/dsa/dsa_loop.c:42:\ndrivers/net/dsa/dsa_loop.c:43:struct dsa_loop_port {\ndrivers/net/dsa/dsa_loop.c:44:\tstruct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX];\ndrivers/net/dsa/dsa_loop.c:45:\tu16 pvid;\ndrivers/net/dsa/dsa_loop.c:46:\tint mtu;\ndrivers/net/dsa/dsa_loop.c:47:};\ndrivers/net/dsa/dsa_loop.c:48:\ndrivers/net/dsa/dsa_loop.c:49:struct dsa_loop_priv {\ndrivers/net/dsa/dsa_loop.c:50:\tstruct mii_bus\t*bus;\ndrivers/net/dsa/dsa_loop.c:51:\tunsigned int\tport_base;\ndrivers/net/dsa/dsa_loop.c:52:\tstruct dsa_loop_vlan vlans[VLAN_N_VID];\ndrivers/net/dsa/dsa_loop.c:53:\tstruct net_device *netdev;\ndrivers/net/dsa/dsa_loop.c:54:\tstruct dsa_loop_port ports[DSA_MAX_PORTS];\ndrivers/net/dsa/dsa_loop.c:55:};\ndrivers/net/dsa/dsa_loop.c:56:\ndrivers/net/dsa/dsa_loop.c:57:struct dsa_loop_pdata {\ndrivers/net/dsa/dsa_loop.c:58:\t/* Must be first, such that dsa_register_switch() can access this\ndrivers/net/dsa/dsa_loop.c:59:\t * without gory pointer manipulations\ndrivers/net/dsa/dsa_loop.c:60:\t */\ndrivers/net/dsa/dsa_loop.c:61:\tstruct dsa_chip_data cd;\ndrivers/net/dsa/dsa_loop.c:62:\tconst char *name;\ndrivers/net/dsa/dsa_loop.c:63:\tunsigned int enabled_ports;\ndrivers/net/dsa/dsa_loop.c:64:\tconst char *netdev;\ndrivers/net/dsa/dsa_loop.c:65:};\ndrivers/net/dsa/dsa_loop.c:66:\ndrivers/net/dsa/dsa_loop.c:67:static struct dsa_loop_mib_entry dsa_loop_mibs[] = {\ndrivers/net/dsa/dsa_loop.c:68:\t[DSA_LOOP_PHY_READ_OK]\t= { \"phy_read_ok\", },\ndrivers/net/dsa/dsa_loop.c:69:\t[DSA_LOOP_PHY_READ_ERR]\t= { \"phy_read_err\", },\ndrivers/net/dsa/dsa_loop.c:70:\t[DSA_LOOP_PHY_WRITE_OK] = { \"phy_write_ok\", },\ndrivers/net/dsa/dsa_loop.c:71:\t[DSA_LOOP_PHY_WRITE_ERR] = { \"phy_write_err\", },\ndrivers/net/dsa/dsa_loop.c:72:};\ndrivers/net/dsa/dsa_loop.c:73:\ndrivers/net/dsa/dsa_loop.c:74:static struct phy_device *phydevs[PHY_MAX_ADDR];\ndrivers/net/dsa/dsa_loop.c:75:static struct mdio_device *switch_mdiodev;\ndrivers/net/dsa/dsa_loop.c:76:\ndrivers/net/dsa/dsa_loop.c:77:enum dsa_loop_devlink_resource_id {\ndrivers/net/dsa/dsa_loop.c:78:\tDSA_LOOP_DEVLINK_PARAM_ID_NONE,  /* DEVLINK_RESOURCE_ID_PARENT_TOP */\ndrivers/net/dsa/dsa_loop.c:79:\tDSA_LOOP_DEVLINK_PARAM_ID_VTU,\ndrivers/net/dsa/dsa_loop.c:80:};\ndrivers/net/dsa/dsa_loop.c:81:\ndrivers/net/dsa/dsa_loop.c:82:static u64 dsa_loop_devlink_vtu_get(void *priv)\ndrivers/net/dsa/dsa_loop.c:83:{\ndrivers/net/dsa/dsa_loop.c:84:\tstruct dsa_loop_priv *ps = priv;\ndrivers/net/dsa/dsa_loop.c:85:\tunsigned int i, count = 0;\ndrivers/net/dsa/dsa_loop.c:86:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c:87:\ndrivers/net/dsa/dsa_loop.c:88:\tfor (i = 0; i \u003c ARRAY_SIZE(ps-\u003evlans); i++) {\ndrivers/net/dsa/dsa_loop.c:89:\t\tvl = \u0026ps-\u003evlans[i];\ndrivers/net/dsa/dsa_loop.c:90:\t\tif (vl-\u003emembers)\ndrivers/net/dsa/dsa_loop.c:91:\t\t\tcount++;\ndrivers/net/dsa/dsa_loop.c:92:\t}\ndrivers/net/dsa/dsa_loop.c:93:\ndrivers/net/dsa/dsa_loop.c:94:\treturn count;\ndrivers/net/dsa/dsa_loop.c:95:}\ndrivers/net/dsa/dsa_loop.c:96:\ndrivers/net/dsa/dsa_loop.c:97:static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c:98:{\ndrivers/net/dsa/dsa_loop.c:99:\tstruct devlink_resource_size_params size_params;\ndrivers/net/dsa/dsa_loop.c:100:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:101:\tint err;\ndrivers/net/dsa/dsa_loop.c:102:\ndrivers/net/dsa/dsa_loop.c:103:\tdevlink_resource_size_params_init(\u0026size_params, ARRAY_SIZE(ps-\u003evlans),\ndrivers/net/dsa/dsa_loop.c:104:\t\t\t\t\t  ARRAY_SIZE(ps-\u003evlans),\ndrivers/net/dsa/dsa_loop.c:105:\t\t\t\t\t  1, DEVLINK_RESOURCE_UNIT_ENTRY);\ndrivers/net/dsa/dsa_loop.c:106:\ndrivers/net/dsa/dsa_loop.c:107:\terr = dsa_devlink_resource_register(ds, \"VTU\", ARRAY_SIZE(ps-\u003evlans),\ndrivers/net/dsa/dsa_loop.c:108:\t\t\t\t\t    DSA_LOOP_DEVLINK_PARAM_ID_VTU,\ndrivers/net/dsa/dsa_loop.c:109:\t\t\t\t\t    DEVLINK_RESOURCE_ID_PARENT_TOP,\ndrivers/net/dsa/dsa_loop.c:110:\t\t\t\t\t    \u0026size_params);\ndrivers/net/dsa/dsa_loop.c:111:\tif (err)\ndrivers/net/dsa/dsa_loop.c:112:\t\tgoto out;\ndrivers/net/dsa/dsa_loop.c:113:\ndrivers/net/dsa/dsa_loop.c:114:\tdsa_devlink_resource_occ_get_register(ds,\ndrivers/net/dsa/dsa_loop.c:115:\t\t\t\t\t      DSA_LOOP_DEVLINK_PARAM_ID_VTU,\ndrivers/net/dsa/dsa_loop.c:116:\t\t\t\t\t      dsa_loop_devlink_vtu_get, ps);\ndrivers/net/dsa/dsa_loop.c:117:\ndrivers/net/dsa/dsa_loop.c:118:\treturn 0;\ndrivers/net/dsa/dsa_loop.c:119:\ndrivers/net/dsa/dsa_loop.c:120:out:\ndrivers/net/dsa/dsa_loop.c:121:\tdsa_devlink_resources_unregister(ds);\ndrivers/net/dsa/dsa_loop.c:122:\treturn err;\ndrivers/net/dsa/dsa_loop.c:123:}\ndrivers/net/dsa/dsa_loop.c:124:\ndrivers/net/dsa/dsa_loop.c:125:static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/dsa_loop.c:126:\t\t\t\t\t\t   int port,\ndrivers/net/dsa/dsa_loop.c:127:\t\t\t\t\t\t   enum dsa_tag_protocol mp)\ndrivers/net/dsa/dsa_loop.c:128:{\ndrivers/net/dsa/dsa_loop.c:129:\tdev_dbg(ds-\u003edev, \"%s: port: %d\\n\", __func__, port);\ndrivers/net/dsa/dsa_loop.c:130:\ndrivers/net/dsa/dsa_loop.c:131:\treturn DSA_TAG_PROTO_NONE;\ndrivers/net/dsa/dsa_loop.c:132:}\ndrivers/net/dsa/dsa_loop.c:133:\ndrivers/net/dsa/dsa_loop.c:134:static int dsa_loop_setup(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c:135:{\ndrivers/net/dsa/dsa_loop.c:136:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:137:\tunsigned int i;\ndrivers/net/dsa/dsa_loop.c:138:\ndrivers/net/dsa/dsa_loop.c:139:\tfor (i = 0; i \u003c ds-\u003enum_ports; i++)\ndrivers/net/dsa/dsa_loop.c:140:\t\tmemcpy(ps-\u003eports[i].mib, dsa_loop_mibs,\ndrivers/net/dsa/dsa_loop.c:141:\t\t       sizeof(dsa_loop_mibs));\ndrivers/net/dsa/dsa_loop.c:142:\ndrivers/net/dsa/dsa_loop.c:143:\tdev_dbg(ds-\u003edev, \"%s\\n\", __func__);\ndrivers/net/dsa/dsa_loop.c:144:\ndrivers/net/dsa/dsa_loop.c:145:\treturn dsa_loop_setup_devlink_resources(ds);\ndrivers/net/dsa/dsa_loop.c:146:}\ndrivers/net/dsa/dsa_loop.c:147:\ndrivers/net/dsa/dsa_loop.c:148:static void dsa_loop_teardown(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c:149:{\ndrivers/net/dsa/dsa_loop.c:150:\tdsa_devlink_resources_unregister(ds);\ndrivers/net/dsa/dsa_loop.c:151:}\ndrivers/net/dsa/dsa_loop.c:152:\ndrivers/net/dsa/dsa_loop.c:153:static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)\ndrivers/net/dsa/dsa_loop.c:154:{\ndrivers/net/dsa/dsa_loop.c:155:\tif (sset != ETH_SS_STATS \u0026\u0026 sset != ETH_SS_PHY_STATS)\ndrivers/net/dsa/dsa_loop.c:156:\t\treturn 0;\ndrivers/net/dsa/dsa_loop.c:157:\ndrivers/net/dsa/dsa_loop.c:158:\treturn __DSA_LOOP_CNT_MAX;\ndrivers/net/dsa/dsa_loop.c:159:}\ndrivers/net/dsa/dsa_loop.c:160:\ndrivers/net/dsa/dsa_loop.c:161:static void dsa_loop_get_strings(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:162:\t\t\t\t u32 stringset, uint8_t *data)\ndrivers/net/dsa/dsa_loop.c:163:{\ndrivers/net/dsa/dsa_loop.c:164:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:165:\tunsigned int i;\ndrivers/net/dsa/dsa_loop.c:166:\ndrivers/net/dsa/dsa_loop.c:167:\tif (stringset != ETH_SS_STATS \u0026\u0026 stringset != ETH_SS_PHY_STATS)\ndrivers/net/dsa/dsa_loop.c:168:\t\treturn;\ndrivers/net/dsa/dsa_loop.c:169:\ndrivers/net/dsa/dsa_loop.c:170:\tfor (i = 0; i \u003c __DSA_LOOP_CNT_MAX; i++)\ndrivers/net/dsa/dsa_loop.c:171:\t\tethtool_puts(\u0026data, ps-\u003eports[port].mib[i].name);\ndrivers/net/dsa/dsa_loop.c:172:}\ndrivers/net/dsa/dsa_loop.c:173:\ndrivers/net/dsa/dsa_loop.c:174:static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:175:\t\t\t\t       uint64_t *data)\ndrivers/net/dsa/dsa_loop.c:176:{\ndrivers/net/dsa/dsa_loop.c:177:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:178:\tunsigned int i;\ndrivers/net/dsa/dsa_loop.c:179:\ndrivers/net/dsa/dsa_loop.c:180:\tfor (i = 0; i \u003c __DSA_LOOP_CNT_MAX; i++)\ndrivers/net/dsa/dsa_loop.c:181:\t\tdata[i] = ps-\u003eports[port].mib[i].val;\ndrivers/net/dsa/dsa_loop.c:182:}\ndrivers/net/dsa/dsa_loop.c:183:\ndrivers/net/dsa/dsa_loop.c:184:static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum)\ndrivers/net/dsa/dsa_loop.c:185:{\ndrivers/net/dsa/dsa_loop.c:186:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:187:\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:188:\tint ret;\ndrivers/net/dsa/dsa_loop.c:189:\ndrivers/net/dsa/dsa_loop.c:190:\tret = mdiobus_read_nested(bus, ps-\u003eport_base + port, regnum);\ndrivers/net/dsa/dsa_loop.c:191:\tif (ret \u003c 0)\ndrivers/net/dsa/dsa_loop.c:192:\t\tps-\u003eports[port].mib[DSA_LOOP_PHY_READ_ERR].val++;\ndrivers/net/dsa/dsa_loop.c:193:\telse\ndrivers/net/dsa/dsa_loop.c:194:\t\tps-\u003eports[port].mib[DSA_LOOP_PHY_READ_OK].val++;\ndrivers/net/dsa/dsa_loop.c:195:\ndrivers/net/dsa/dsa_loop.c:196:\treturn ret;\ndrivers/net/dsa/dsa_loop.c:197:}\ndrivers/net/dsa/dsa_loop.c:198:\ndrivers/net/dsa/dsa_loop.c:199:static int dsa_loop_phy_write(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:200:\t\t\t      int regnum, u16 value)\ndrivers/net/dsa/dsa_loop.c:201:{\ndrivers/net/dsa/dsa_loop.c:202:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:203:\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:204:\tint ret;\ndrivers/net/dsa/dsa_loop.c:205:\ndrivers/net/dsa/dsa_loop.c:206:\tret = mdiobus_write_nested(bus, ps-\u003eport_base + port, regnum, value);\ndrivers/net/dsa/dsa_loop.c:207:\tif (ret \u003c 0)\ndrivers/net/dsa/dsa_loop.c:208:\t\tps-\u003eports[port].mib[DSA_LOOP_PHY_WRITE_ERR].val++;\ndrivers/net/dsa/dsa_loop.c:209:\telse\ndrivers/net/dsa/dsa_loop.c:210:\t\tps-\u003eports[port].mib[DSA_LOOP_PHY_WRITE_OK].val++;\ndrivers/net/dsa/dsa_loop.c:211:\ndrivers/net/dsa/dsa_loop.c:212:\treturn ret;\ndrivers/net/dsa/dsa_loop.c:213:}\ndrivers/net/dsa/dsa_loop.c:214:\ndrivers/net/dsa/dsa_loop.c:215:static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:216:\t\t\t\t     struct dsa_bridge bridge,\ndrivers/net/dsa/dsa_loop.c:217:\t\t\t\t     bool *tx_fwd_offload,\ndrivers/net/dsa/dsa_loop.c:218:\t\t\t\t     struct netlink_ext_ack *extack)\ndrivers/net/dsa/dsa_loop.c:219:{\ndrivers/net/dsa/dsa_loop.c:220:\tdev_dbg(ds-\u003edev, \"%s: port: %d, bridge: %s\\n\",\ndrivers/net/dsa/dsa_loop.c:221:\t\t__func__, port, bridge.dev-\u003ename);\ndrivers/net/dsa/dsa_loop.c:222:\ndrivers/net/dsa/dsa_loop.c:223:\treturn 0;\ndrivers/net/dsa/dsa_loop.c:224:}\ndrivers/net/dsa/dsa_loop.c:225:\ndrivers/net/dsa/dsa_loop.c:226:static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:227:\t\t\t\t       struct dsa_bridge bridge)\ndrivers/net/dsa/dsa_loop.c:228:{\ndrivers/net/dsa/dsa_loop.c:229:\tdev_dbg(ds-\u003edev, \"%s: port: %d, bridge: %s\\n\",\ndrivers/net/dsa/dsa_loop.c:230:\t\t__func__, port, bridge.dev-\u003ename);\ndrivers/net/dsa/dsa_loop.c:231:}\ndrivers/net/dsa/dsa_loop.c:232:\ndrivers/net/dsa/dsa_loop.c:233:static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:234:\t\t\t\t\tu8 state)\ndrivers/net/dsa/dsa_loop.c:235:{\ndrivers/net/dsa/dsa_loop.c:236:\tdev_dbg(ds-\u003edev, \"%s: port: %d, state: %d\\n\",\ndrivers/net/dsa/dsa_loop.c:237:\t\t__func__, port, state);\ndrivers/net/dsa/dsa_loop.c:238:}\ndrivers/net/dsa/dsa_loop.c:239:\ndrivers/net/dsa/dsa_loop.c:240:static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:241:\t\t\t\t\tbool vlan_filtering,\ndrivers/net/dsa/dsa_loop.c:242:\t\t\t\t\tstruct netlink_ext_ack *extack)\ndrivers/net/dsa/dsa_loop.c:243:{\ndrivers/net/dsa/dsa_loop.c:244:\tdev_dbg(ds-\u003edev, \"%s: port: %d, vlan_filtering: %d\\n\",\ndrivers/net/dsa/dsa_loop.c:245:\t\t__func__, port, vlan_filtering);\ndrivers/net/dsa/dsa_loop.c:246:\ndrivers/net/dsa/dsa_loop.c:247:\treturn 0;\ndrivers/net/dsa/dsa_loop.c:248:}\ndrivers/net/dsa/dsa_loop.c:249:\ndrivers/net/dsa/dsa_loop.c:250:static int dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:251:\t\t\t\t  const struct switchdev_obj_port_vlan *vlan,\ndrivers/net/dsa/dsa_loop.c:252:\t\t\t\t  struct netlink_ext_ack *extack)\ndrivers/net/dsa/dsa_loop.c:253:{\ndrivers/net/dsa/dsa_loop.c:254:\tbool untagged = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_UNTAGGED;\ndrivers/net/dsa/dsa_loop.c:255:\tbool pvid = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_PVID;\ndrivers/net/dsa/dsa_loop.c:256:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:257:\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:258:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c:259:\ndrivers/net/dsa/dsa_loop.c:260:\tif (vlan-\u003evid \u003e= ARRAY_SIZE(ps-\u003evlans))\ndrivers/net/dsa/dsa_loop.c:261:\t\treturn -ERANGE;\ndrivers/net/dsa/dsa_loop.c:262:\ndrivers/net/dsa/dsa_loop.c:263:\t/* Just do a sleeping operation to make lockdep checks effective */\ndrivers/net/dsa/dsa_loop.c:264:\tmdiobus_read(bus, ps-\u003eport_base + port, MII_BMSR);\ndrivers/net/dsa/dsa_loop.c:265:\ndrivers/net/dsa/dsa_loop.c:266:\tvl = \u0026ps-\u003evlans[vlan-\u003evid];\ndrivers/net/dsa/dsa_loop.c:267:\ndrivers/net/dsa/dsa_loop.c:268:\tvl-\u003emembers |= BIT(port);\ndrivers/net/dsa/dsa_loop.c:269:\tif (untagged)\ndrivers/net/dsa/dsa_loop.c:270:\t\tvl-\u003euntagged |= BIT(port);\ndrivers/net/dsa/dsa_loop.c:271:\telse\ndrivers/net/dsa/dsa_loop.c:272:\t\tvl-\u003euntagged \u0026= ~BIT(port);\ndrivers/net/dsa/dsa_loop.c:273:\ndrivers/net/dsa/dsa_loop.c:274:\tdev_dbg(ds-\u003edev, \"%s: port: %d vlan: %d, %stagged, pvid: %d\\n\",\ndrivers/net/dsa/dsa_loop.c:275:\t\t__func__, port, vlan-\u003evid, untagged ? \"un\" : \"\", pvid);\ndrivers/net/dsa/dsa_loop.c:276:\ndrivers/net/dsa/dsa_loop.c:277:\tif (pvid)\ndrivers/net/dsa/dsa_loop.c:278:\t\tps-\u003eports[port].pvid = vlan-\u003evid;\ndrivers/net/dsa/dsa_loop.c:279:\ndrivers/net/dsa/dsa_loop.c:280:\treturn 0;\ndrivers/net/dsa/dsa_loop.c:281:}\ndrivers/net/dsa/dsa_loop.c:282:\ndrivers/net/dsa/dsa_loop.c:283:static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:284:\t\t\t\t  const struct switchdev_obj_port_vlan *vlan)\ndrivers/net/dsa/dsa_loop.c:285:{\ndrivers/net/dsa/dsa_loop.c:286:\tbool untagged = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_UNTAGGED;\ndrivers/net/dsa/dsa_loop.c:287:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:288:\tu16 pvid = ps-\u003eports[port].pvid;\ndrivers/net/dsa/dsa_loop.c:289:\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:290:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c:291:\ndrivers/net/dsa/dsa_loop.c:292:\t/* Just do a sleeping operation to make lockdep checks effective */\ndrivers/net/dsa/dsa_loop.c:293:\tmdiobus_read(bus, ps-\u003eport_base + port, MII_BMSR);\ndrivers/net/dsa/dsa_loop.c:294:\ndrivers/net/dsa/dsa_loop.c:295:\tvl = \u0026ps-\u003evlans[vlan-\u003evid];\ndrivers/net/dsa/dsa_loop.c:296:\ndrivers/net/dsa/dsa_loop.c:297:\tvl-\u003emembers \u0026= ~BIT(port);\ndrivers/net/dsa/dsa_loop.c:298:\tif (untagged)\ndrivers/net/dsa/dsa_loop.c:299:\t\tvl-\u003euntagged \u0026= ~BIT(port);\ndrivers/net/dsa/dsa_loop.c:300:\ndrivers/net/dsa/dsa_loop.c:301:\tif (pvid == vlan-\u003evid)\ndrivers/net/dsa/dsa_loop.c:302:\t\tpvid = 1;\ndrivers/net/dsa/dsa_loop.c:303:\ndrivers/net/dsa/dsa_loop.c:304:\tdev_dbg(ds-\u003edev, \"%s: port: %d vlan: %d, %stagged, pvid: %d\\n\",\ndrivers/net/dsa/dsa_loop.c:305:\t\t__func__, port, vlan-\u003evid, untagged ? \"un\" : \"\", pvid);\ndrivers/net/dsa/dsa_loop.c:306:\tps-\u003eports[port].pvid = pvid;\ndrivers/net/dsa/dsa_loop.c:307:\ndrivers/net/dsa/dsa_loop.c:308:\treturn 0;\ndrivers/net/dsa/dsa_loop.c:309:}\ndrivers/net/dsa/dsa_loop.c:310:\ndrivers/net/dsa/dsa_loop.c:311:static int dsa_loop_port_change_mtu(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c:312:\t\t\t\t    int new_mtu)\ndrivers/net/dsa/dsa_loop.c:313:{\ndrivers/net/dsa/dsa_loop.c:314:\tstruct dsa_loop_priv *priv = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:315:\ndrivers/net/dsa/dsa_loop.c:316:\tpriv-\u003eports[port].mtu = new_mtu;\ndrivers/net/dsa/dsa_loop.c:317:\ndrivers/net/dsa/dsa_loop.c:318:\treturn 0;\ndrivers/net/dsa/dsa_loop.c:319:}\ndrivers/net/dsa/dsa_loop.c:320:\ndrivers/net/dsa/dsa_loop.c:321:static int dsa_loop_port_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/dsa_loop.c:322:{\ndrivers/net/dsa/dsa_loop.c:323:\treturn ETH_MAX_MTU;\ndrivers/net/dsa/dsa_loop.c:324:}\ndrivers/net/dsa/dsa_loop.c:325:\ndrivers/net/dsa/dsa_loop.c:326:static void dsa_loop_phylink_get_caps(struct dsa_switch *dsa, int port,\ndrivers/net/dsa/dsa_loop.c:327:\t\t\t\t      struct phylink_config *config)\ndrivers/net/dsa/dsa_loop.c:328:{\ndrivers/net/dsa/dsa_loop.c:329:\tbitmap_fill(config-\u003esupported_interfaces, PHY_INTERFACE_MODE_MAX);\ndrivers/net/dsa/dsa_loop.c:330:\t__clear_bit(PHY_INTERFACE_MODE_NA, config-\u003esupported_interfaces);\ndrivers/net/dsa/dsa_loop.c:331:\tconfig-\u003emac_capabilities = ~0;\ndrivers/net/dsa/dsa_loop.c:332:}\ndrivers/net/dsa/dsa_loop.c:333:\ndrivers/net/dsa/dsa_loop.c:334:static const struct dsa_switch_ops dsa_loop_driver = {\ndrivers/net/dsa/dsa_loop.c:335:\t.get_tag_protocol\t= dsa_loop_get_protocol,\ndrivers/net/dsa/dsa_loop.c:336:\t.setup\t\t\t= dsa_loop_setup,\ndrivers/net/dsa/dsa_loop.c:337:\t.teardown\t\t= dsa_loop_teardown,\ndrivers/net/dsa/dsa_loop.c:338:\t.get_strings\t\t= dsa_loop_get_strings,\ndrivers/net/dsa/dsa_loop.c:339:\t.get_ethtool_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:340:\t.get_sset_count\t\t= dsa_loop_get_sset_count,\ndrivers/net/dsa/dsa_loop.c:341:\t.get_ethtool_phy_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:342:\t.phy_read\t\t= dsa_loop_phy_read,\ndrivers/net/dsa/dsa_loop.c:343:\t.phy_write\t\t= dsa_loop_phy_write,\ndrivers/net/dsa/dsa_loop.c:344:\t.port_bridge_join\t= dsa_loop_port_bridge_join,\ndrivers/net/dsa/dsa_loop.c:345:\t.port_bridge_leave\t= dsa_loop_port_bridge_leave,\ndrivers/net/dsa/dsa_loop.c:346:\t.port_stp_state_set\t= dsa_loop_port_stp_state_set,\ndrivers/net/dsa/dsa_loop.c:347:\t.port_vlan_filtering\t= dsa_loop_port_vlan_filtering,\ndrivers/net/dsa/dsa_loop.c:348:\t.port_vlan_add\t\t= dsa_loop_port_vlan_add,\ndrivers/net/dsa/dsa_loop.c:349:\t.port_vlan_del\t\t= dsa_loop_port_vlan_del,\ndrivers/net/dsa/dsa_loop.c:350:\t.port_change_mtu\t= dsa_loop_port_change_mtu,\ndrivers/net/dsa/dsa_loop.c:351:\t.port_max_mtu\t\t= dsa_loop_port_max_mtu,\ndrivers/net/dsa/dsa_loop.c:352:\t.phylink_get_caps\t= dsa_loop_phylink_get_caps,\ndrivers/net/dsa/dsa_loop.c:353:};\ndrivers/net/dsa/dsa_loop.c:354:\ndrivers/net/dsa/dsa_loop.c:355:static int dsa_loop_drv_probe(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c:356:{\ndrivers/net/dsa/dsa_loop.c:357:\tstruct dsa_loop_pdata *pdata = mdiodev-\u003edev.platform_data;\ndrivers/net/dsa/dsa_loop.c:358:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c:359:\tstruct dsa_switch *ds;\ndrivers/net/dsa/dsa_loop.c:360:\tint ret;\ndrivers/net/dsa/dsa_loop.c:361:\ndrivers/net/dsa/dsa_loop.c:362:\tif (!pdata)\ndrivers/net/dsa/dsa_loop.c:363:\t\treturn -ENODEV;\ndrivers/net/dsa/dsa_loop.c:364:\ndrivers/net/dsa/dsa_loop.c:365:\tds = devm_kzalloc(\u0026mdiodev-\u003edev, sizeof(*ds), GFP_KERNEL);\ndrivers/net/dsa/dsa_loop.c:366:\tif (!ds)\ndrivers/net/dsa/dsa_loop.c:367:\t\treturn -ENOMEM;\ndrivers/net/dsa/dsa_loop.c:368:\ndrivers/net/dsa/dsa_loop.c:369:\tds-\u003edev = \u0026mdiodev-\u003edev;\ndrivers/net/dsa/dsa_loop.c:370:\tds-\u003enum_ports = DSA_LOOP_NUM_PORTS;\ndrivers/net/dsa/dsa_loop.c:371:\ndrivers/net/dsa/dsa_loop.c:372:\tps = devm_kzalloc(\u0026mdiodev-\u003edev, sizeof(*ps), GFP_KERNEL);\ndrivers/net/dsa/dsa_loop.c:373:\tif (!ps)\ndrivers/net/dsa/dsa_loop.c:374:\t\treturn -ENOMEM;\ndrivers/net/dsa/dsa_loop.c:375:\ndrivers/net/dsa/dsa_loop.c:376:\tps-\u003enetdev = dev_get_by_name(\u0026init_net, pdata-\u003enetdev);\ndrivers/net/dsa/dsa_loop.c:377:\tif (!ps-\u003enetdev)\ndrivers/net/dsa/dsa_loop.c:378:\t\treturn -EPROBE_DEFER;\ndrivers/net/dsa/dsa_loop.c:379:\ndrivers/net/dsa/dsa_loop.c:380:\tpdata-\u003ecd.netdev[DSA_LOOP_CPU_PORT] = \u0026ps-\u003enetdev-\u003edev;\ndrivers/net/dsa/dsa_loop.c:381:\ndrivers/net/dsa/dsa_loop.c:382:\tds-\u003edev = \u0026mdiodev-\u003edev;\ndrivers/net/dsa/dsa_loop.c:383:\tds-\u003eops = \u0026dsa_loop_driver;\ndrivers/net/dsa/dsa_loop.c:384:\tds-\u003epriv = ps;\ndrivers/net/dsa/dsa_loop.c:385:\tps-\u003ebus = mdiodev-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:386:\ndrivers/net/dsa/dsa_loop.c:387:\tdev_set_drvdata(\u0026mdiodev-\u003edev, ds);\ndrivers/net/dsa/dsa_loop.c:388:\ndrivers/net/dsa/dsa_loop.c:389:\tret = dsa_register_switch(ds);\ndrivers/net/dsa/dsa_loop.c:390:\tif (!ret)\ndrivers/net/dsa/dsa_loop.c:391:\t\tdev_info(\u0026mdiodev-\u003edev, \"%s: 0x%0x\\n\",\ndrivers/net/dsa/dsa_loop.c:392:\t\t\t pdata-\u003ename, pdata-\u003eenabled_ports);\ndrivers/net/dsa/dsa_loop.c:393:\ndrivers/net/dsa/dsa_loop.c:394:\treturn ret;\ndrivers/net/dsa/dsa_loop.c:395:}\ndrivers/net/dsa/dsa_loop.c:396:\ndrivers/net/dsa/dsa_loop.c:397:static void dsa_loop_drv_remove(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c:398:{\ndrivers/net/dsa/dsa_loop.c:399:\tstruct dsa_switch *ds = dev_get_drvdata(\u0026mdiodev-\u003edev);\ndrivers/net/dsa/dsa_loop.c:400:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c:401:\ndrivers/net/dsa/dsa_loop.c:402:\tif (!ds)\ndrivers/net/dsa/dsa_loop.c:403:\t\treturn;\ndrivers/net/dsa/dsa_loop.c:404:\ndrivers/net/dsa/dsa_loop.c:405:\tps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c:406:\ndrivers/net/dsa/dsa_loop.c:407:\tdsa_unregister_switch(ds);\ndrivers/net/dsa/dsa_loop.c:408:\tdev_put(ps-\u003enetdev);\ndrivers/net/dsa/dsa_loop.c:409:}\ndrivers/net/dsa/dsa_loop.c:410:\ndrivers/net/dsa/dsa_loop.c:411:static void dsa_loop_drv_shutdown(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c:412:{\ndrivers/net/dsa/dsa_loop.c:413:\tstruct dsa_switch *ds = dev_get_drvdata(\u0026mdiodev-\u003edev);\ndrivers/net/dsa/dsa_loop.c:414:\ndrivers/net/dsa/dsa_loop.c:415:\tif (!ds)\ndrivers/net/dsa/dsa_loop.c:416:\t\treturn;\ndrivers/net/dsa/dsa_loop.c:417:\ndrivers/net/dsa/dsa_loop.c:418:\tdsa_switch_shutdown(ds);\ndrivers/net/dsa/dsa_loop.c:419:\ndrivers/net/dsa/dsa_loop.c:420:\tdev_set_drvdata(\u0026mdiodev-\u003edev, NULL);\ndrivers/net/dsa/dsa_loop.c:421:}\ndrivers/net/dsa/dsa_loop.c:422:\ndrivers/net/dsa/dsa_loop.c:423:static struct mdio_driver dsa_loop_drv = {\ndrivers/net/dsa/dsa_loop.c:424:\t.mdiodrv.driver\t= {\ndrivers/net/dsa/dsa_loop.c:425:\t\t.name\t= \"dsa-loop\",\ndrivers/net/dsa/dsa_loop.c:426:\t},\ndrivers/net/dsa/dsa_loop.c:427:\t.probe\t= dsa_loop_drv_probe,\ndrivers/net/dsa/dsa_loop.c:428:\t.remove\t= dsa_loop_drv_remove,\ndrivers/net/dsa/dsa_loop.c:429:\t.shutdown = dsa_loop_drv_shutdown,\ndrivers/net/dsa/dsa_loop.c:430:};\ndrivers/net/dsa/dsa_loop.c:431:\ndrivers/net/dsa/dsa_loop.c:432:static int dsa_loop_bus_match(struct device *dev,\ndrivers/net/dsa/dsa_loop.c:433:\t\t\t      const struct device_driver *drv)\ndrivers/net/dsa/dsa_loop.c:434:{\ndrivers/net/dsa/dsa_loop.c:435:\treturn drv == \u0026dsa_loop_drv.mdiodrv.driver;\ndrivers/net/dsa/dsa_loop.c:436:}\ndrivers/net/dsa/dsa_loop.c:437:\ndrivers/net/dsa/dsa_loop.c:438:static void dsa_loop_phydevs_unregister(void)\ndrivers/net/dsa/dsa_loop.c:439:{\ndrivers/net/dsa/dsa_loop.c:440:\tfor (int i = 0; i \u003c NUM_FIXED_PHYS; i++) {\ndrivers/net/dsa/dsa_loop.c:441:\t\tif (!IS_ERR(phydevs[i]))\ndrivers/net/dsa/dsa_loop.c:442:\t\t\tfixed_phy_unregister(phydevs[i]);\ndrivers/net/dsa/dsa_loop.c:443:\t}\ndrivers/net/dsa/dsa_loop.c:444:}\ndrivers/net/dsa/dsa_loop.c:445:\ndrivers/net/dsa/dsa_loop.c:446:static int __init dsa_loop_create_switch_mdiodev(void)\ndrivers/net/dsa/dsa_loop.c:447:{\ndrivers/net/dsa/dsa_loop.c:448:\tstatic struct dsa_loop_pdata dsa_loop_pdata = {\ndrivers/net/dsa/dsa_loop.c:449:\t\t.cd = {\ndrivers/net/dsa/dsa_loop.c:450:\t\t\t.port_names[0] = \"lan1\",\ndrivers/net/dsa/dsa_loop.c:451:\t\t\t.port_names[1] = \"lan2\",\ndrivers/net/dsa/dsa_loop.c:452:\t\t\t.port_names[2] = \"lan3\",\ndrivers/net/dsa/dsa_loop.c:453:\t\t\t.port_names[3] = \"lan4\",\ndrivers/net/dsa/dsa_loop.c:454:\t\t\t.port_names[DSA_LOOP_CPU_PORT] = \"cpu\",\ndrivers/net/dsa/dsa_loop.c:455:\t\t},\ndrivers/net/dsa/dsa_loop.c:456:\t\t.name = \"DSA mockup driver\",\ndrivers/net/dsa/dsa_loop.c:457:\t\t.enabled_ports = 0x1f,\ndrivers/net/dsa/dsa_loop.c:458:\t\t.netdev = \"eth0\",\ndrivers/net/dsa/dsa_loop.c:459:\t};\ndrivers/net/dsa/dsa_loop.c:460:\tstruct mii_bus *bus;\ndrivers/net/dsa/dsa_loop.c:461:\tint ret = -ENODEV;\ndrivers/net/dsa/dsa_loop.c:462:\ndrivers/net/dsa/dsa_loop.c:463:\tbus = mdio_find_bus(\"fixed-0\");\ndrivers/net/dsa/dsa_loop.c:464:\tif (WARN_ON(!bus))\ndrivers/net/dsa/dsa_loop.c:465:\t\treturn ret;\ndrivers/net/dsa/dsa_loop.c:466:\ndrivers/net/dsa/dsa_loop.c:467:\tswitch_mdiodev = mdio_device_create(bus, 31);\ndrivers/net/dsa/dsa_loop.c:468:\tif (IS_ERR(switch_mdiodev))\ndrivers/net/dsa/dsa_loop.c:469:\t\tgoto out;\ndrivers/net/dsa/dsa_loop.c:470:\ndrivers/net/dsa/dsa_loop.c:471:\tswitch_mdiodev-\u003ebus_match = dsa_loop_bus_match;\ndrivers/net/dsa/dsa_loop.c:472:\tswitch_mdiodev-\u003edev.platform_data = \u0026dsa_loop_pdata;\ndrivers/net/dsa/dsa_loop.c:473:\ndrivers/net/dsa/dsa_loop.c:474:\tret = mdio_device_register(switch_mdiodev);\ndrivers/net/dsa/dsa_loop.c:475:\tif (ret)\ndrivers/net/dsa/dsa_loop.c:476:\t\tmdio_device_free(switch_mdiodev);\ndrivers/net/dsa/dsa_loop.c:477:out:\ndrivers/net/dsa/dsa_loop.c:478:\tput_device(\u0026bus-\u003edev);\ndrivers/net/dsa/dsa_loop.c:479:\treturn ret;\ndrivers/net/dsa/dsa_loop.c:480:}\ndrivers/net/dsa/dsa_loop.c:481:\ndrivers/net/dsa/dsa_loop.c:482:static int __init dsa_loop_init(void)\ndrivers/net/dsa/dsa_loop.c:483:{\ndrivers/net/dsa/dsa_loop.c:484:\tunsigned int i;\ndrivers/net/dsa/dsa_loop.c:485:\tint ret;\ndrivers/net/dsa/dsa_loop.c:486:\ndrivers/net/dsa/dsa_loop.c:487:\tret = dsa_loop_create_switch_mdiodev();\ndrivers/net/dsa/dsa_loop.c:488:\tif (ret)\ndrivers/net/dsa/dsa_loop.c:489:\t\treturn ret;\ndrivers/net/dsa/dsa_loop.c:490:\ndrivers/net/dsa/dsa_loop.c:491:\tfor (i = 0; i \u003c NUM_FIXED_PHYS; i++)\ndrivers/net/dsa/dsa_loop.c:492:\t\tphydevs[i] = fixed_phy_register_100fd();\ndrivers/net/dsa/dsa_loop.c:493:\ndrivers/net/dsa/dsa_loop.c:494:\tret = mdio_driver_register(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c:495:\tif (ret) {\ndrivers/net/dsa/dsa_loop.c:496:\t\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c:497:\t\tmdio_device_remove(switch_mdiodev);\ndrivers/net/dsa/dsa_loop.c:498:\t\tmdio_device_free(switch_mdiodev);\ndrivers/net/dsa/dsa_loop.c:499:\t}\ndrivers/net/dsa/dsa_loop.c:500:\n\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 56463
							output: 25
							thoughts: 83
						

Thoughts:
**Analyzing DSA Tag Protocol Usage**

Okay, let's break this down. My initial observation is that the `dsa_loop` driver is coded to work with `DSA_TAG_PROTO_NONE`, and crucially, the `dsa_loop_driver` structure doesn't include a `.change_tag_protocol` function pointer. That's point one.

Now I need to understand what other switches are actually *using* the `DSA_TAG_PROTO_KS8995` protocol. That's the key question, the central point I'm trying to illuminate.

Time to search through the kernel sources for instances where `DSA_TAG_PROTO_KS8995` is referenced. That search will tell me which hardware or driver modules are employing that particular tag protocol. My experience tells me that is the next logical step in getting this sorted.



10/2 2026/09/09 17:26 tool grepper
0m Args:
{
  "Expression": "DSA_TAG_PROTO_KS8995"
}

Results:
{
  "Output": "drivers/net/dsa/microchip/ksz8.c=3093=static enum dsa_tag_protocol ksz8995xa_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/microchip/ksz8.c-3096-{\ndrivers/net/dsa/microchip/ksz8.c:3097:\treturn DSA_TAG_PROTO_KS8995;\ndrivers/net/dsa/microchip/ksz8.c-3098-}\n--\ninclude/net/dsa.h=26=struct tc_action;\n--\ninclude/net/dsa.h-63-#define DSA_TAG_PROTO_MT7628_VALUE\t\t35\ninclude/net/dsa.h:64:#define DSA_TAG_PROTO_KS8995_VALUE\t\t36\ninclude/net/dsa.h-65-\ninclude/net/dsa.h=66=enum dsa_tag_protocol {\n--\ninclude/net/dsa.h-102-\tDSA_TAG_PROTO_MT7628\t\t= DSA_TAG_PROTO_MT7628_VALUE,\ninclude/net/dsa.h:103:\tDSA_TAG_PROTO_KS8995\t\t= DSA_TAG_PROTO_KS8995_VALUE,\ninclude/net/dsa.h-104-};\n--\nnet/dsa/tag_ks8995.c=133=static const struct dsa_device_ops ks8995_netdev_ops = {\nnet/dsa/tag_ks8995.c-134-\t.name = KS8995_NAME,\nnet/dsa/tag_ks8995.c:135:\t.proto\t= DSA_TAG_PROTO_KS8995,\nnet/dsa/tag_ks8995.c-136-\t.xmit = ks8995_xmit,\n--\nnet/dsa/tag_ks8995.c=142=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_ks8995.c:143:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KS8995, KS8995_NAME);\nnet/dsa/tag_ks8995.c-144-\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 57360
							output: 42
							thoughts: 139
						

Thoughts:
**Investigating the KSZ8995XA Tagging Protocol**

Okay, so I'm looking at `ksz8995xa_get_tag_protocol` within `drivers/net/dsa/microchip/ksz8.c`. It's using `DSA_TAG_PROTO_KS8995`, which tells me it's handling the KSZ8995 tagging protocol. But how is the `ksz8` device actually being probed and initialized in the first place? I need to figure out the driver instantiation path.

My initial thought is to check `drivers/net/dsa/microchip/ksz_spi.c`, `ksz_i2c.c`, and potentially `ksz9477_i2c.c` as they seem like obvious candidates, and I should also consider SPI devices. So, the next step is to examine those files. Let's see where those `.c` files are actually *used* and probed within the system. I need to trace back from those files to see how the KSZ8 device is being detected and set up. That's where I need to start.



12/2 2026/09/09 17:26 tool grepper
0m Args:
{
  "Expression": "module_spi_driver|module_i2c_driver",
  "PathPrefix": "drivers/net/dsa/microchip"
}

Results:
{
  "Output": "drivers/net/dsa/microchip/ksz9477_i2c.c=133=static struct i2c_driver ksz9477_i2c_driver = {\n--\ndrivers/net/dsa/microchip/ksz9477_i2c.c-144-\ndrivers/net/dsa/microchip/ksz9477_i2c.c:145:module_i2c_driver(ksz9477_i2c_driver);\ndrivers/net/dsa/microchip/ksz9477_i2c.c-146-\n--\ndrivers/net/dsa/microchip/ksz_spi.c=378=static struct spi_driver ksz_spi_driver = {\n--\ndrivers/net/dsa/microchip/ksz_spi.c-389-\ndrivers/net/dsa/microchip/ksz_spi.c:390:module_spi_driver(ksz_spi_driver);\ndrivers/net/dsa/microchip/ksz_spi.c-391-\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 58063
							output: 37
							thoughts: 221
						

Thoughts:
**Investigating Potential Fuzzing Targets in the Kernel's DSA Subsystem**

Okay, so I'm looking at this `ksz_spi_driver`, which is, as I recall, an SPI driver designed for a hardware SPI bus – not a standard QEMU or GCE emulated one unless you've got a specific SPI board and devicetree setup. But the real question is, could this interact with other DSA components, or is it more of a standalone module? Hmm, then there's `tag_ks8995.c`, which brings up an interesting angle: can we fuzz, load, or utilize these *tag* drivers in some way? How would syzkaller even interact with those DSA tag drivers or the DSA conduits?

Right, let's see, can syzkaller be configured to fiddle with the DSA tag protocol, or can we write to the tagging attribute on the netdev sysfs? That's the key. Okay, let me dive into `net/dsa/conduit.c`. Ah, here it is: `static ssize_t tagging_store(struct device *d, struct device_attribute *attr, ...` and it calls `dsa_tree_change_tag_proto`. Yes! This is promising! That `tagging_store` function in `net/dsa/conduit.c` needs a closer look. That's where we might find the vulnerability, or at least a crucial entry point for fuzzing.



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

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

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

Args:
null

Results:
null

Tokens:
							input: 59568
							output: 37
							thoughts: 132
						

Thoughts:
**Analyzing the Tagging Store**

Okay, here's what I'm seeing: I need to take a close look at this `tagging_store` component. My primary concern is that with a DSA conduit established, perhaps through something like a `dsa_loop`, we've got a potential vulnerability. It looks like a user or, even worse, a fuzzer could potentially manipulate the tagging protocol by writing directly to `/sys/class/net/<conduit>/dsa/tagging`. This allows them to switch to *any* registered tag driver, from seemingly innocuous ones like `ks8995` and `none` – though "none" might be quite problematic in certain contexts – to potentially more exotic ones, which brings up all sorts of security issues.

Hold on a second, let's back up a step. I need to understand the impact of the function `dsa_tree_change_tag_proto`. What's really going on under the hood when `dsa_tree_change_tag_proto(dst, new_tag_ops, old_tag_ops)` is invoked? The core problem lies in the fact that an attacker could leverage this function to bypass the integrity and isolation designed in DSA by leveraging this function. I need to trace this function path in more detail. This has the potential to lead to some critical system instability or security exploits.



16/2 2026/09/09 17:26 tool read-file
0m Args:
{
  "File": "net/dsa/dsa.c",
  "FirstLine": 980,
  "LineCount": 60
}

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

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

Args:
null

Results:
null

Tokens:
							input: 60979
							output: 20
							thoughts: 254
						

Thoughts:
**Analyzing the Tag Protocol Change in DSA**

Okay, let's break this down. So, `dsa_tree_change_tag_proto` is notifying the tree, specifically with `info.tag_ops = tag_ops;` and then calling `dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info)`. My immediate thought is to trace the execution path from there, specifically into `dsa_switch_change_tag_proto(ds, info)`. I see the `tag_ops` being passed in, as expected.

Now, a quick scan reveals a crucial check: `if (!ds->ops->change_tag_protocol) return -EOPNOTSUPP;`. That's the key. If the switch doesn't implement a `.change_tag_protocol` function in its `ops` structure, we get an "operation not supported" error. Makes sense. But this prompts the critical question: which switches *do* implement this? Time for a quick grep through the codebase to identify the implementations.



18/2 2026/09/09 17:27 tool grepper
0m Args:
{
  "Expression": "\\.change_tag_protocol"
}

Results:
{
  "Output": "drivers/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=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=3285=static const struct dsa_switch_ops rtl8365mb_switch_ops = {\ndrivers/net/dsa/realtek/rtl8365mb_main.c-3286-\t.get_tag_protocol = rtl8365mb_get_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c:3287:\t.change_tag_protocol = rtl8365mb_change_tag_protocol,\ndrivers/net/dsa/realtek/rtl8365mb_main.c-3288-\t.setup = rtl8365mb_setup,\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-1230-\t * dsa_switch_setup_tag_protocol once .setup has run and the\nnet/dsa/dsa.c:1231:\t * driver is ready to accept calls to .change_tag_protocol. If\nnet/dsa/dsa.c-1232-\t * the driver does not support the custom protocol at that\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 62158
							output: 26
							thoughts: 59
						

Thoughts:
**Analyzing Network Switch Driver Compatibility**

Okay, let's break this down. My mind immediately jumps to a few key areas: `mv88e6xxx`, `felix`, and `rtl8365mb_main`. Right now, I'm focusing on the first, `mv88e6xxx`. The most immediate question is this: what tag protocols are supported by the `mv88e6xxx_change_tag_protocol` function? Understanding the range of protocols it handles is crucial for any configuration or debugging I might need to do. It's the first thing I need to investigate.



20/2 2026/09/09 17:27 tool grepper
0m Args:
{
  "Expression": "mv88e6xxx_change_tag_protocol"
}

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"
}

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

Args:
null

Results:
null

Tokens:
							input: 62723
							output: 46
							thoughts: 20
						

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

**Diving into the Tag Protocol Change**

Okay, time to get my hands dirty. I need to take a look at the `mv88e6xxx_change_tag_protocol` implementation. This is where the core logic resides for modifying the VLAN tagging behavior on this switch. I'm especially interested in how it handles the different protocols, and what the potential edge cases or gotchas might be. Are there any known issues with specific configurations? I'll be looking for things like race conditions, potential memory corruption, and how it handles different hardware versions. Specifically, I'll be trying to understand the control flow, the data structures it manipulates, and any assumptions it makes about the underlying hardware.



22/2 2026/09/09 17:27 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/mv88e6xxx/chip.c",
  "FirstLine": 6654,
  "LineCount": 25
}

Results:
{
  "Contents": "6654:\t\n6655:\tstatic int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,\n6656:\t\t\t\t\t\t enum dsa_tag_protocol proto)\n6657:\t{\n6658:\t\tstruct mv88e6xxx_chip *chip = ds-\u003epriv;\n6659:\t\tenum dsa_tag_protocol old_protocol;\n6660:\t\tstruct dsa_port *cpu_dp;\n6661:\t\tint err;\n6662:\t\n6663:\t\tswitch (proto) {\n6664:\t\tcase DSA_TAG_PROTO_EDSA:\n6665:\t\t\tswitch (chip-\u003einfo-\u003eedsa_support) {\n6666:\t\t\tcase MV88E6XXX_EDSA_UNSUPPORTED:\n6667:\t\t\t\treturn -EPROTONOSUPPORT;\n6668:\t\t\tcase MV88E6XXX_EDSA_UNDOCUMENTED:\n6669:\t\t\t\tdev_warn(chip-\u003edev, \"Relying on undocumented EDSA tagging behavior\\n\");\n6670:\t\t\t\tfallthrough;\n6671:\t\t\tcase MV88E6XXX_EDSA_SUPPORTED:\n6672:\t\t\t\tbreak;\n6673:\t\t\t}\n6674:\t\t\tbreak;\n6675:\t\tcase DSA_TAG_PROTO_DSA:\n6676:\t\t\tbreak;\n6677:\t\tdefault:\n6678:\t\t\treturn -EPROTONOSUPPORT;\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 63346
							output: 43
							thoughts: 197
						

Thoughts:
**My Investigation into the KSZ8995XA Driver Implementation**

Okay, so I'm focusing on this `ksz8995xa` switch, specifically regarding its SPI hardware interface. The key thing that jumps out is the use of `DSA_TAG_PROTO_KS8995`. I need to ensure this is the *only* place it's used. Let's quickly verify that `felix` and `rtl8365mb_main` and anything else touching `change_tag_protocol` aren't also somehow using this. Good, `felix` is limited to ocelot variants and `rtl8365mb_main` is using different protocols.

Now, I need to understand the lifecycle of the `KSZ8995XA`. How is this device used? How is it probed by the kernel? I need to check how the system *finds* and *instantiates* it. Are there any virtual buses or drivers that might be involved in binding to, or creating an instance of, `KSZ8995XA`? I should examine anything related to the `ksz_spi` driver, or `ksz8.c` even, for clues.

Specifically, how does `ksz_spi` probe? It's essential to understand the probing sequence for this thing. Time to dive into `ksz_spi.c`. That's where the heart of the matter lies.



24/2 2026/09/09 17:27 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/microchip/ksz_spi.c",
  "FirstLine": 145,
  "LineCount": 85
}

Results:
{
  "Contents": " 145:\t\n 146:\t\tchip = device_get_match_data(ddev);\n 147:\t\tif (!chip)\n 148:\t\t\treturn -EINVAL;\n 149:\t\n 150:\t\tdev = ksz_switch_alloc(\u0026spi-\u003edev, chip, spi);\n 151:\t\tif (!dev)\n 152:\t\t\treturn -ENOMEM;\n 153:\t\n 154:\t\t/* Save chip id to do special initialization when probing. */\n 155:\t\tdev-\u003echip_id = chip-\u003echip_id;\n 156:\t\tif (chip-\u003echip_id == KSZ88X3_CHIP_ID)\n 157:\t\t\tregmap_config = ksz8863_regmap_config;\n 158:\t\telse if (chip-\u003echip_id == KSZ8463_CHIP_ID)\n 159:\t\t\tregmap_config = ksz8463_regmap_config;\n 160:\t\telse if (chip-\u003echip_id == KSZ8795_CHIP_ID ||\n 161:\t\t\t chip-\u003echip_id == KSZ8794_CHIP_ID ||\n 162:\t\t\t chip-\u003echip_id == KSZ8765_CHIP_ID)\n 163:\t\t\tregmap_config = ksz8795_regmap_config;\n 164:\t\telse if (chip-\u003echip_id == KSZ8995XA_CHIP_ID ||\n 165:\t\t\t chip-\u003echip_id == KSZ8895_CHIP_ID ||\n 166:\t\t\t chip-\u003echip_id == KSZ8864_CHIP_ID)\n 167:\t\t\tregmap_config = ksz8863_regmap_config;\n 168:\t\telse\n 169:\t\t\tregmap_config = ksz9477_regmap_config;\n 170:\t\n 171:\t\tfor (i = 0; i \u003c __KSZ_NUM_REGMAPS; i++) {\n 172:\t\t\trc = regmap_config[i];\n 173:\t\t\trc.lock_arg = \u0026dev-\u003eregmap_mutex;\n 174:\t\t\trc.wr_table = chip-\u003ewr_table;\n 175:\t\t\trc.rd_table = chip-\u003erd_table;\n 176:\t\t\tdev-\u003eregmap[i] = devm_regmap_init_spi(spi, \u0026rc);\n 177:\t\n 178:\t\t\tif (IS_ERR(dev-\u003eregmap[i])) {\n 179:\t\t\t\treturn dev_err_probe(\u0026spi-\u003edev, PTR_ERR(dev-\u003eregmap[i]),\n 180:\t\t\t\t\t\t     \"Failed to initialize regmap%i\\n\",\n 181:\t\t\t\t\t\t     regmap_config[i].val_bits);\n 182:\t\t\t}\n 183:\t\t}\n 184:\t\n 185:\t\tif (spi-\u003edev.platform_data)\n 186:\t\t\tdev-\u003epdata = spi-\u003edev.platform_data;\n 187:\t\n 188:\t\t/* setup spi */\n 189:\t\tif (chip-\u003echip_id == KSZ8995XA_CHIP_ID)\n 190:\t\t\tspi-\u003emode = SPI_MODE_0;\n 191:\t\telse\n 192:\t\t\tspi-\u003emode = SPI_MODE_3;\n 193:\t\tret = spi_setup(spi);\n 194:\t\tif (ret)\n 195:\t\t\treturn ret;\n 196:\t\n 197:\t\tdev-\u003eirq = spi-\u003eirq;\n 198:\t\n 199:\t\tret = ksz_switch_register(dev);\n 200:\t\n 201:\t\t/* Main DSA driver may not be started yet. */\n 202:\t\tif (ret)\n 203:\t\t\treturn ret;\n 204:\t\n 205:\t\tspi_set_drvdata(spi, dev);\n 206:\t\n 207:\t\treturn 0;\n 208:\t}\n 209:\t\n 210:\tstatic void ksz_spi_remove(struct spi_device *spi)\n 211:\t{\n 212:\t\tstruct ksz_device *dev = spi_get_drvdata(spi);\n 213:\t\n 214:\t\tif (dev)\n 215:\t\t\tksz_switch_remove(dev);\n 216:\t}\n 217:\t\n 218:\tstatic void ksz_spi_shutdown(struct spi_device *spi)\n 219:\t{\n 220:\t\tstruct ksz_device *dev = spi_get_drvdata(spi);\n 221:\t\n 222:\t\tif (!dev)\n 223:\t\t\treturn;\n 224:\t\n 225:\t\tksz_switch_shutdown(dev);\n 226:\t\n 227:\t\tspi_set_drvdata(spi, NULL);\n 228:\t}\n 229:\t\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 65216
							output: 30
							thoughts: 392
						

Thoughts:
**My Assessment of Emulating KSZ Network Devices in Standard Fuzzing Environments**

Okay, let's break this down. First, `ksz_spi` looks like an SPI device driver, and the immediate question that comes to mind is whether we can effectively emulate or instantiate SPI devices in a standard fuzzing setup like QEMU x86_64 or syzkaller on amd64. Can we actually *create* these SPI devices virtually for fuzzing?

The first snag is that x86_64 QEMU, in its standard configuration, doesn't natively expose SPI masters in a way that would allow us to instantiate KSZ switches or leverage Device Tree SPI nodes in a useful way. There aren't standard SPI controllers on x86 platforms and, practically speaking, there are no available microchip switch devices on SPI emulated within the standard QEMU environment. This is a dead end, at least initially.

Alright, what about `ksz_i2c.c`? A quick check reveals that it's not even applicable, since it only supports the KSZ9477/8863/8873, and not the KSZ8995XA that I'm interested in. And even if it did support my targets, QEMU still lacks these i2c devices in its standard builds. This route is also blocked.

Hmm, what about the DSA tag protocol driver in `net/dsa/tag_ks8995.c`? This seems promising. The main question here is: can we actually *register*, *load*, or call these DSA tag drivers during our fuzzing operations? Let's analyze.

I see `module_dsa_tag_driver(ks8995_netdev_ops);`. When the `tag_ks8995.ko` (or built-in equivalent) initializes, it registers `ks8995_netdev_ops` into `dsa_tag_drivers_list`. Now I need to figure out where `dsa_tag_drivers_list` or `dsa_find_tagger_by_name` are *actually* used. I need to dive into `net/dsa/tag.c` or wherever the DSA taggers are managed to understand the calling flow and potential attack surface. This looks like the most likely path forward.



26/2 2026/09/09 17:27 tool grepper
0m Args:
{
  "Expression": "dsa_tag_driver",
  "PathPrefix": "net/dsa"
}

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

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

Args:
null

Results:
null

Tokens:
							input: 73754
							output: 21
							thoughts: 246
						

Thoughts:
**Investigating DSA Switch Driver Instantiation for KSZ8995XA in Syzkaller**

Okay, so I'm trying to figure out the instantiation process for DSA switches, specifically how it relates to `DSA_TAG_PROTO_KS8995`. My immediate thought is, can a DSA switch driver using that tag protocol even be probed within a QEMU environment under Syzkaller? That's the real question here.

First, I need to know which devices actually *use* `DSA_TAG_PROTO_KS8995`. Quick check… Ah, right, it's the `ksz8995xa`, as defined in `ksz8.c`. Alright, so the next step is how is the `ksz8995xa` created? I'll quickly look up the usage of `KSZ8995XA` in the kernel.

Looks like it's primarily used in `drivers/net/dsa/microchip/ksz_spi.c`. From what I see here, it's associated with SPI device IDs, like `"microchip,ksz8995xa"`, `"micrel,ks8995"`, `"ks8995"`, and `"ksz8995xa"`. These are all SPI device IDs.

Just to be thorough, I should scan the whole codebase for any other instances of `KSZ8995XA`. Gotta cover all my bases to understand its creation and usage fully.



28/2 2026/09/09 17:27 tool grepper
0m Args:
{
  "Expression": "KSZ8995XA"
}

Results:
{
  "Output": "drivers/net/dsa/microchip/ksz8.c-5- * It supports the following switches:\ndrivers/net/dsa/microchip/ksz8.c:6: * - KSZ8995XA (the oldest ancestor)\ndrivers/net/dsa/microchip/ksz8.c-7- * - KSZ8463\n--\ndrivers/net/dsa/microchip/ksz8.c=256=static int ksz8_reset_switch(struct ksz_device *dev)\n--\ndrivers/net/dsa/microchip/ksz8.c-261-\ndrivers/net/dsa/microchip/ksz8.c:262:\t\t/* The KSZ8995XA switch itself cannot be reset by software, but\ndrivers/net/dsa/microchip/ksz8.c-263-\t\t * often boot loaders have fun with ports, so reset them. This\n--\ndrivers/net/dsa/microchip/ksz8.c=302=static int ksz8995xa_change_mtu(struct dsa_switch *ds, int port, int mtu)\n--\ndrivers/net/dsa/microchip/ksz8.c-312-\ndrivers/net/dsa/microchip/ksz8.c:313:\t/* The legal packet size bit polarity documented in the KSZ8995XA\ndrivers/net/dsa/microchip/ksz8.c-314-\t * manual appears to be wrong. Practical tests show that the same\n--\ndrivers/net/dsa/microchip/ksz8.c-317-\t */\ndrivers/net/dsa/microchip/ksz8.c:318:\tif (frame_size \u003c= KSZ8995XA_LEGAL_PACKET_SIZE)\ndrivers/net/dsa/microchip/ksz8.c-319-\t\tctrl2 |= KSZ8863_LEGAL_PACKET_ENABLE;\n--\ndrivers/net/dsa/microchip/ksz8.c=1019=static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)\n--\ndrivers/net/dsa/microchip/ksz8.c-1033-\ndrivers/net/dsa/microchip/ksz8.c:1034:\t/* KSZ8995XA has no fancy features in register 0xA */\ndrivers/net/dsa/microchip/ksz8.c-1035-\tif (ksz_is_ksz8995xa(dev))\n--\ndrivers/net/dsa/microchip/ksz8.c=2106=static void ksz8_port_setup(struct ksz_device *dev, int port, bool cpu_port)\n--\ndrivers/net/dsa/microchip/ksz8.c-2143-\ndrivers/net/dsa/microchip/ksz8.c:2144:\t\t/* The KSZ8995XA has a special tag format in the front of the frame\ndrivers/net/dsa/microchip/ksz8.c-2145-\t\t * that need to be inserted by the CPU and then removed by each\n--\ndrivers/net/dsa/microchip/ksz8.c=2234=static void ksz8_config_cpu_port(struct dsa_switch *ds)\n--\ndrivers/net/dsa/microchip/ksz8.c-2245-\ndrivers/net/dsa/microchip/ksz8.c:2246:\t/* KSZ8995XA uses a tag in the header instead of the tail */\ndrivers/net/dsa/microchip/ksz8.c-2247-\tif (!ksz_is_ksz8995xa(dev))\n--\ndrivers/net/dsa/microchip/ksz8.c=2420=static int ksz8_enable_stp_addr(struct ksz_device *dev)\n--\ndrivers/net/dsa/microchip/ksz8.c-2423-\ndrivers/net/dsa/microchip/ksz8.c:2424:\t/* KSZ8995XA lacks STP */\ndrivers/net/dsa/microchip/ksz8.c-2425-\tif (ksz_is_ksz8995xa(dev))\n--\ndrivers/net/dsa/microchip/ksz8.c=2747=static int ksz8_setup(struct dsa_switch *ds)\n--\ndrivers/net/dsa/microchip/ksz8.c-2758-\ndrivers/net/dsa/microchip/ksz8.c:2759:\t/* KSZ8995XA has no SW controlled VLAN handling */\ndrivers/net/dsa/microchip/ksz8.c-2760-\tif (!ksz_is_ksz8995xa(dev)) {\n--\ndrivers/net/dsa/microchip/ksz8.c=3231=const struct ksz_dev_ops ksz88xx_dev_ops = {\n--\ndrivers/net/dsa/microchip/ksz8.c-3245-/*\ndrivers/net/dsa/microchip/ksz8.c:3246: * Restricted operations for KSZ8995XA, so many things are not supported\ndrivers/net/dsa/microchip/ksz8.c-3247- * by this old switch that we need diet DSA operations.\n--\ndrivers/net/dsa/microchip/ksz8_reg.h-97-\ndrivers/net/dsa/microchip/ksz8_reg.h:98:#define SW_SPECIAL_TAG\t\t\tBIT(0) /* KSZ8995XA only */\ndrivers/net/dsa/microchip/ksz8_reg.h-99-\n--\ndrivers/net/dsa/microchip/ksz_common.c=1155=const struct ksz_chip_data ksz_switch_chips[] = {\n--\ndrivers/net/dsa/microchip/ksz_common.c-1393-\ndrivers/net/dsa/microchip/ksz_common.c:1394:\t[KSZ8995XA] = {\ndrivers/net/dsa/microchip/ksz_common.c:1395:\t\t.chip_id = KSZ8995XA_CHIP_ID, /* Also known as KS8995XA */\ndrivers/net/dsa/microchip/ksz_common.c:1396:\t\t.dev_name = \"KSZ8995XA\",\ndrivers/net/dsa/microchip/ksz_common.c-1397-\t\t.cpu_ports = 0x10,\t/* can be configured as cpu port */\n--\ndrivers/net/dsa/microchip/ksz_common.c=2677=void ksz_init_mib_timer(struct ksz_device *dev)\n--\ndrivers/net/dsa/microchip/ksz_common.c-2680-\ndrivers/net/dsa/microchip/ksz_common.c:2681:\t/* KSZ8995XA lacks MiB features */\ndrivers/net/dsa/microchip/ksz_common.c-2682-\tif (ksz_is_ksz8995xa(dev))\n--\ndrivers/net/dsa/microchip/ksz_common.c=2939=static int ksz_switch_detect(struct ksz_device *dev)\n--\ndrivers/net/dsa/microchip/ksz_common.c-2980-\t\tif (id2 == KSZ8895_CHIP_ID_95XA) {\ndrivers/net/dsa/microchip/ksz_common.c:2981:\t\t\tdev-\u003echip_id = KSZ8995XA_CHIP_ID;\ndrivers/net/dsa/microchip/ksz_common.c-2982-\t\t\tbreak;\n--\ndrivers/net/dsa/microchip/ksz_common.h=274=enum ksz_model {\n--\ndrivers/net/dsa/microchip/ksz_common.h-283-\tKSZ8895,\ndrivers/net/dsa/microchip/ksz_common.h:284:\tKSZ8995XA,\ndrivers/net/dsa/microchip/ksz_common.h-285-\tKSZ9477,\n--\ndrivers/net/dsa/microchip/ksz_common.h=790=static inline bool ksz_is_8895_family(struct ksz_device *dev)\n--\ndrivers/net/dsa/microchip/ksz_common.h-793-\t       dev-\u003echip_id == KSZ8864_CHIP_ID ||\ndrivers/net/dsa/microchip/ksz_common.h:794:\t       dev-\u003echip_id == KSZ8995XA_CHIP_ID;\ndrivers/net/dsa/microchip/ksz_common.h-795-}\n--\ndrivers/net/dsa/microchip/ksz_common.h=797=static inline bool ksz_is_ksz8995xa(struct ksz_device *dev)\ndrivers/net/dsa/microchip/ksz_common.h-798-{\ndrivers/net/dsa/microchip/ksz_common.h:799:\treturn dev-\u003echip_id == KSZ8995XA_CHIP_ID;\ndrivers/net/dsa/microchip/ksz_common.h-800-}\n--\ndrivers/net/dsa/microchip/ksz_common.h=844=static inline bool ksz_is_sgmii_port(struct ksz_device *dev, int port)\n--\ndrivers/net/dsa/microchip/ksz_common.h-933-#define KSZ8_LEGAL_PACKET_SIZE\t\t1518\ndrivers/net/dsa/microchip/ksz_common.h:934:#define KSZ8995XA_LEGAL_PACKET_SIZE\t1522\ndrivers/net/dsa/microchip/ksz_common.h-935-#define KSZ9477_MAX_FRAME_SIZE\t\t9000\n--\ndrivers/net/dsa/microchip/ksz_dcb.c-22-#define KSZ8_PORT_BASED_PRIO_M\t\t\tGENMASK(4, 3)\ndrivers/net/dsa/microchip/ksz_dcb.c:23:#define KSZ8995XA_PORT_BASED_PRIO\t\tBIT(4)\ndrivers/net/dsa/microchip/ksz_dcb.c-24-\n--\ndrivers/net/dsa/microchip/ksz_dcb.c-27-#define KSZ8765_REG_TOS_DSCP_CTRL\t\t0x90\ndrivers/net/dsa/microchip/ksz_dcb.c:28:#define KSZ8995XA_REG_TOS_DSCP_CTRL_7\t\t0x67\ndrivers/net/dsa/microchip/ksz_dcb.c-29-\n--\ndrivers/net/dsa/microchip/ksz_dcb.c=98=static void ksz_get_default_port_prio_reg(struct ksz_device *dev, int *reg,\n--\ndrivers/net/dsa/microchip/ksz_dcb.c-103-\t\tif (ksz_is_ksz8995xa(dev))\ndrivers/net/dsa/microchip/ksz_dcb.c:104:\t\t\t*mask = KSZ8995XA_PORT_BASED_PRIO;\ndrivers/net/dsa/microchip/ksz_dcb.c-105-\t\telse\n--\ndrivers/net/dsa/microchip/ksz_dcb.c=128=static void ksz_get_dscp_prio_reg(struct ksz_device *dev, u8 dscp, int *reg,\n--\ndrivers/net/dsa/microchip/ksz_dcb.c-133-\tif (ksz_is_ksz8995xa(dev)) {\ndrivers/net/dsa/microchip/ksz_dcb.c:134:\t\t/* KSZ8995XA stores DSCP groups in descending register order. */\ndrivers/net/dsa/microchip/ksz_dcb.c:135:\t\t*reg = KSZ8995XA_REG_TOS_DSCP_CTRL_7 - dscp / 8;\ndrivers/net/dsa/microchip/ksz_dcb.c-136-\t\t*mask = BIT(0);\n--\ndrivers/net/dsa/microchip/ksz_spi.c=137=static int ksz_spi_probe(struct spi_device *spi)\n--\ndrivers/net/dsa/microchip/ksz_spi.c-163-\t\tregmap_config = ksz8795_regmap_config;\ndrivers/net/dsa/microchip/ksz_spi.c:164:\telse if (chip-\u003echip_id == KSZ8995XA_CHIP_ID ||\ndrivers/net/dsa/microchip/ksz_spi.c-165-\t\t chip-\u003echip_id == KSZ8895_CHIP_ID ||\n--\ndrivers/net/dsa/microchip/ksz_spi.c-188-\t/* setup spi */\ndrivers/net/dsa/microchip/ksz_spi.c:189:\tif (chip-\u003echip_id == KSZ8995XA_CHIP_ID)\ndrivers/net/dsa/microchip/ksz_spi.c-190-\t\tspi-\u003emode = SPI_MODE_0;\n--\ndrivers/net/dsa/microchip/ksz_spi.c=230=static const struct of_device_id ksz_dt_ids[] = {\n--\ndrivers/net/dsa/microchip/ksz_spi.c-247-\t\t.compatible = \"micrel,ks8995\",\ndrivers/net/dsa/microchip/ksz_spi.c:248:\t\t.data = \u0026ksz_switch_chips[KSZ8995XA]\ndrivers/net/dsa/microchip/ksz_spi.c-249-\t},\n--\ndrivers/net/dsa/microchip/ksz_spi.c-283-\t\t.compatible = \"microchip,ksz8995xa\",\ndrivers/net/dsa/microchip/ksz_spi.c:284:\t\t.data = \u0026ksz_switch_chips[KSZ8995XA]\ndrivers/net/dsa/microchip/ksz_spi.c-285-\t},\n--\ninclude/linux/platform_data/microchip-ksz.h=25=enum ksz_chip_id {\n--\ninclude/linux/platform_data/microchip-ksz.h-33-\tKSZ8895_CHIP_ID = 0x8895,\ninclude/linux/platform_data/microchip-ksz.h:34:\tKSZ8995XA_CHIP_ID = 0x8995,\ninclude/linux/platform_data/microchip-ksz.h-35-\tKSZ9477_CHIP_ID = 0x00947700,\n--\nnet/dsa/tag_ks8995.c-12-\nnet/dsa/tag_ks8995.c:13:/* The Micrel KS8995XA / Microchip KSZ8995XA Special Tag Packet ID (STPID)\nnet/dsa/tag_ks8995.c-14- * pushes its tag in a modified VLAN (802.1Q) tag.\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 78227
							output: 130
							thoughts: 1721
						

Thoughts:
**Fuzzing Decision for Microchip KS8995/KSZ8995XA Ethernet Switch Driver**

Okay, let's break this down systematically. First, I need to ensure that the code modifications in this patch are actually *reachable* in a fuzzing environment. The instructions are clear: if the code is structurally unreachable, it's a no-go for fuzzing.

My initial thought is to check whether the KS8995/KSZ8995XA or Microchip DSA switch drivers can be reached without physical SPI hardware. I see that the KS8995XA driver is an SPI driver (`ksz_spi_driver`). There's no PCI, USB, or virtual bus for this, meaning it *requires* an SPI device probe. I know that in standard QEMU/GCE x86_64 setups, there isn't an SPI bus controller configured with KS8995/KSZ8995XA devices in either ACPI or devicetree.

I have to carefully evaluate the reachability of `net/dsa/tag_ks8995.c`, I'll check if a virtual device can use `tag_ks8995`. My quick check shows that `dsa_loop` uses `DSA_TAG_PROTO_NONE` and doesn't implement `.change_tag_protocol`. Looking at the other switch drivers implementing `.change_tag_protocol`, it seems that, the tag protocol `.change_tag_protocol` can only be set to `DSA_TAG_PROTO_KS8995` by `ksz8995xa_get_tag_protocol` in `ksz8.c` (under `ksz_spi_driver`). This means the `ks8995_xmit` and `ks8995_rcv` functions within `net/dsa/tag_ks8995.c` will not be called unless a KSZ8995XA switch is instantiated and attached to a conduit. Since a KSZ8995XA switch is a physical ethernet switch ASIC that communicates over SPI and therefore, requires SPI physical hardware to probe. In a standard setup, this is not possible.

Now, let me do a quick sanity check of the rest of the patch to confirm. I'll quickly review the diff again to determine what's going on. I can see a variety of files are modified, including DT bindings docs, the MAINTAINERS file, and Kconfig/Makefile changes, along with deletions and additions within the driver code. Specifically, the patch adds KSZ8995XA support to the `ksz8` SPI switch driver, adds register definitions, and logic for KSZ switches.

Let me double-check the modifications in `ksz_common.c` and `ksz_dcb.c`. After a quick scan, it looks like these changes are primarily focused on the KSZ series switches, which are physical Ethernet switch chips (KSZ8463, KSZ8795, etc.) connected over SPI/I2C/MDIO. These are not emulated in standard QEMU or GCE virtual environments.

Now, let's go back to the negative criteria. The instructions explicitly state that structurally unreachable hardware, such as vendor-specific PCIe switches, SmartNICs, or drivers requiring physical ASICs, are *not* to be fuzzed. My decision hinges on reachability. The KS8995/KSZ8995XA switches require physical SPI hardware. They are structurally unreachable in my target environments.

**Therefore, WorthFuzzing = false.**

Now to fill out the parameters for `set-results`.

-   `WorthFuzzing`: false
-   `Reasoning`: The patch modifies/replaces the driver for Micrel/Microchip KS8995/KSZ8995XA Ethernet switch chips and introduces a corresponding DSA tagging protocol driver. These switches are physical SPI ASICs that are structurally unreachable in standard QEMU/GCE virtualized environments.
-   `FocusSymbols`: []
-   `EnableConfigs`: []

Let's call `set-results`.



30/2 2026/09/09 17:27 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch removes the legacy standalone KS8995 DSA driver and migrates support for the Micrel/Microchip KS8995 / KSZ8995XA Ethernet switch into the microchip ksz8 DSA driver alongside adding a dedicated tag driver (net/dsa/tag_ks8995.c). These switches are physical hardware ASICs connected via SPI and are structurally unreachable in standard virtualized fuzzing environments (QEMU/GCE).",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch removes the legacy standalone KS8995 DSA driver and migrates support for the Micrel/Microchip KS8995 / KSZ8995XA Ethernet switch into the microchip ksz8 DSA driver alongside adding a dedicated tag driver (net/dsa/tag_ks8995.c). These switches are physical hardware ASICs connected via SPI and are structurally unreachable in standard virtualized fuzzing environments (QEMU/GCE).",
  "WorthFuzzing": false
}

31/1 2026/09/09 17:27 action If
0m Args:
{
  "WorthFuzzing": false
}

Results:
null

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