AI Trajectory


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

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "KMSANReasoning": "",
  "NeedsKMSAN": false,
  "Reasoning": "The patch series replaces the standalone Micrel KS8995 SPI driver with support in the Microchip KSZ switch driver (drivers/net/dsa/microchip/) and adds the corresponding DSA tag driver (net/dsa/tag_ks8995.c). These drivers interface with physical Micrel/Microchip KS8995/KSZ8995XA hardware over SPI and cannot be instantiated or reached in standard virtualized fuzzing environments (like QEMU/GCE) without physical hardware.",
  "WorthFuzzing": false
}

1/1 2026/09/01 03:56 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 7cbdd022714ea510258cce8afe95a2cfe56dcca3\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Tue Sep 1 03:56:04 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..f9272d1b7bf47 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@@ -253,7 +254,17 @@ 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;\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\tksz_port_cfg(dev, port, REG_PORT_STATUS_3,\n+\t\t\t\t     PORT_PHY_SOFT_RESET, true);\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 +280,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 +361,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 +388,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 +413,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 +1012,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 +1114,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 +1212,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 +1358,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 +1476,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@@ -1672,7 +1731,7 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag,\n {\n \tstruct ksz_device *dev = ds-\u003epriv;\n \n-\tif (ksz_is_ksz88x3(dev))\n+\tif (ksz_is_ksz88x3(dev) || ksz_is_ksz8995xa(dev))\n \t\treturn -ENOTSUPP;\n \n \t/* Discard packets with VID not enabled on the switch */\n@@ -2043,12 +2102,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 +2118,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 +2149,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 +2224,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 +2402,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 +2733,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@@ -2711,9 +2798,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 +2809,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 +3068,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 +3171,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 +3220,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..bd99699aae02b 100644\n--- a/drivers/net/dsa/microchip/ksz8_reg.h\n+++ b/drivers/net/dsa/microchip/ksz8_reg.h\n@@ -30,6 +30,11 @@\n #define KSZ88X3_REG_FVID_AND_HOST_MODE  0xC6\n #define KSZ88X3_PORT3_RMII_CLK_INTERNAL BIT(3)\n \n+#define REG_SW_ID_0\t\t\t0x00\n+#define REG_SW_ID_1\t\t\t0x01\n+\n+#define SW_START_SWITCH\t\t\tBIT(0)\n+\n #define REG_SW_CTRL_0\t\t\t0x02\n \n #define SW_NEW_BACKOFF\t\t\tBIT(7)\n@@ -95,6 +100,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..2c55014246e5f 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{ \"ksz8995\" },\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..6bd5f1015c265\n--- /dev/null\n+++ b/net/dsa/tag_ks8995.c\n@@ -0,0 +1,141 @@\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/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+\thdr = skb_vlan_eth_hdr(skb);\n+\tif (hdr-\u003eh_vlan_proto != htons(ETH_P_8021Q)) {\n+\t\tskb = vlan_insert_tag(skb, KS8995M_STPID(portmask), 0);\n+\t\t/* vlan_insert_tag() drops the skb on failure */\n+\t\tif (!skb)\n+\t\t\treturn NULL;\n+\t\thdr = skb_vlan_eth_hdr(skb);\n+\t\tnetdev_dbg(dev, \"%s: inserted VLAN TAG %04x TCI %04x\\n\",\n+\t\t\t   __func__, hdr-\u003eh_vlan_proto, hdr-\u003eh_vlan_TCI);\n+\t} else {\n+\t\t/* VLAN tag already exists in skb head, modify it in place */\n+\t\thdr = vlan_eth_hdr(skb);\n+\t\thdr-\u003eh_vlan_proto = KS8995M_STPID(portmask);\n+\t\tnetdev_dbg(dev, \"%s: modified VLAN TAG %04x\\n\",\n+\t\t\t   __func__, hdr-\u003eh_vlan_proto);\n+\t}\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+\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+\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\tnetdev_err(dev, \"%s: unable to untag skb\\n\", __func__);\n+\t\treturn NULL;\n+\t}\n+\n+\tportmask = FIELD_GET(KS8995M_STPID_PORTMASK, etype);\n+\tnetdev_dbg(dev, \"%s: etype %04x portmask %04x (%d)\\n\",\n+\t\t   __func__, etype, portmask, ilog2(portmask));\n+\tskb-\u003edev = dsa_conduit_find_user(dev, 0, ilog2(portmask));\n+\tif (!skb-\u003edev) {\n+\t\tkfree_skb(skb);\n+\t\treturn NULL;\n+\t}\n+\n+\t/* Preserve the VLAN tag if it contains a non-zero VID which is not\n+\t * identical to 0x001, or PCP, and restore its TPID to the standard\n+\t * value.\n+\t *\n+\t * If this is just an ordinary inbound package the datasheet claims\n+\t * it will \"replace null VID with ingress port VID\", which means\n+\t * VID set to 1: 0x8101 0001 for port 0 or 0x8102 0001 for port 1.\n+\t * So in the DSA driver we will set the default port VID to 0 so\n+\t * we can properly detect non-VLAN frames.\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/01 03:56 agent patch-evaluator
1m Model:
core

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch series replaces the standalone Micrel KS8995 SPI driver with support in the Microchip KSZ switch driver (drivers/net/dsa/microchip/) and adds the corresponding DSA tag driver (net/dsa/tag_ks8995.c). These drivers interface with physical Micrel/Microchip KS8995/KSZ8995XA hardware over SPI and cannot be instantiated or reached in standard virtualized fuzzing environments (like QEMU/GCE) without physical hardware.",
  "WorthFuzzing": false
}

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

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

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

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

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


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

Prompt:
For your convenience, here is the diff of the changes:
commit 7cbdd022714ea510258cce8afe95a2cfe56dcca3
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Sep 1 03:56:04 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..f9272d1b7bf47 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
@@ -253,7 +254,17 @@ 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;
+
+		/* 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++)
+			ksz_port_cfg(dev, port, REG_PORT_STATUS_3,
+				     PORT_PHY_SOFT_RESET, true);
+	} 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 +280,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 +361,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 +388,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 +413,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 +1012,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 +1114,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 +1212,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 +1358,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 +1476,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;
@@ -1672,7 +1731,7 @@ static int ksz8_port_vlan_filtering(struct dsa_switch *ds, int port, bool flag,
 {
 	struct ksz_device *dev = ds->priv;
 
-	if (ksz_is_ksz88x3(dev))
+	if (ksz_is_ksz88x3(dev) || ksz_is_ksz8995xa(dev))
 		return -ENOTSUPP;
 
 	/* Discard packets with VID not enabled on the switch */
@@ -2043,12 +2102,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 +2118,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 +2149,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 +2224,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 +2402,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 +2733,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) {
@@ -2711,9 +2798,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 +2809,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 +3068,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 +3171,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 +3220,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..bd99699aae02b 100644
--- a/drivers/net/dsa/microchip/ksz8_reg.h
+++ b/drivers/net/dsa/microchip/ksz8_reg.h
@@ -30,6 +30,11 @@
 #define KSZ88X3_REG_FVID_AND_HOST_MODE  0xC6
 #define KSZ88X3_PORT3_RMII_CLK_INTERNAL BIT(3)
 
+#define REG_SW_ID_0			0x00
+#define REG_SW_ID_1			0x01
+
+#define SW_START_SWITCH			BIT(0)
+
 #define REG_SW_CTRL_0			0x02
 
 #define SW_NEW_BACKOFF			BIT(7)
@@ -95,6 +100,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..2c55014246e5f 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" },
+	{ "ksz8995" },
 	{ "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..6bd5f1015c265
--- /dev/null
+++ b/net/dsa/tag_ks8995.c
@@ -0,0 +1,141 @@
+// 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/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;
+	}
+
+	hdr = skb_vlan_eth_hdr(skb);
+	if (hdr->h_vlan_proto != htons(ETH_P_8021Q)) {
+		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__, hdr->h_vlan_proto, hdr->h_vlan_TCI);
+	} else {
+		/* VLAN tag already exists in skb head, modify it in place */
+		hdr = vlan_eth_hdr(skb);
+		hdr->h_vlan_proto = KS8995M_STPID(portmask);
+		netdev_dbg(dev, "%s: modified VLAN TAG %04x\n",
+			   __func__, hdr->h_vlan_proto);
+	}
+
+	return skb;
+}
+
+static struct sk_buff *ks8995_rcv(struct sk_buff *skb, struct net_device *dev)
+{
+	int portmask;
+	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;
+	}
+	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 */
+		netdev_err(dev, "%s: unable to untag skb\n", __func__);
+		return NULL;
+	}
+
+	portmask = FIELD_GET(KS8995M_STPID_PORTMASK, etype);
+	netdev_dbg(dev, "%s: etype %04x portmask %04x (%d)\n",
+		   __func__, etype, portmask, ilog2(portmask));
+	skb->dev = dsa_conduit_find_user(dev, 0, ilog2(portmask));
+	if (!skb->dev) {
+		kfree_skb(skb);
+		return NULL;
+	}
+
+	/* Preserve the VLAN tag if it contains a non-zero VID which is not
+	 * identical to 0x001, or PCP, and restore its TPID to the standard
+	 * value.
+	 *
+	 * If this is just an ordinary inbound package the datasheet claims
+	 * it will "replace null VID with ingress port VID", which means
+	 * VID set to 1: 0x8101 0001 for port 0 or 0x8102 0001 for port 1.
+	 * So in the DSA driver we will set the default port VID to 0 so
+	 * we can properly detect non-VLAN frames.
+	 */
+	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/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 29319
							output: 30
							thoughts: 667
						

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

Okay, so I'm looking at this commit: `syz-cluster: applied patch under review`. My initial thought is to dive into the patch series and understand what it does. It looks like:

1.  It's removing an older DSA driver (`drivers/net/dsa/ks8995.c`). Alright, that's housekeeping.
2.  It's updating the `drivers/net/dsa/microchip/` code to support the KS8995/KSZ8995XA switch. Fine, consolidation and modernization. This involves changes across several files (`ksz_common.c`, `ksz8.c`, etc.).
3.  A new DSA tagging driver is being added (`net/dsa/tag_ks8995.c`). Crucial.
4.  And there are the usual Kconfig, Makefile, binding, and header updates that always come with these types of changes.

Now, the important question, is this worth fuzzing? Can syzkaller or QEMU even *reach* these DSA tag drivers and switch components? My mind goes immediately to, "Can this be tested in a virtualized environment?". I need to understand the reachability of these DSA components. Can I utilize the `dsa_loop` to test them? How do these tag drivers actually work, are they accessible from userspace or packet sockets?

I need to quickly assess how DSA tagging drivers work in the broader picture. My next step will be to search the kernel source for how these tag drivers interact with the DSA framework.

And I need to go back to the original prompt, to make sure I'm following the explicit criteria for determining fuzzing-worthiness: documentation, logging, constants, unreachable code paths, vendor-specific hardware, teardown callbacks. I have to stay focused.

Wait, are DSA tag drivers accessible? I need to figure out if I can select and test these tag protocols through `dsa_loop`, or mock devices. I'll need to grep for `tag_` or DSA tag drivers in the kernel and investigate how DSA switches and tag drivers function. This is key. I need to understand if there is a realistic way to exercise this code in a fuzzing context.



4/2 2026/09/01 03:56 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=129=static const struct dsa_device_ops ks8995_netdev_ops = {\nnet/dsa/tag_ks8995.c-130-\t.name = KS8995_NAME,\nnet/dsa/tag_ks8995.c:131:\t.proto\t= DSA_TAG_PROTO_KS8995,\nnet/dsa/tag_ks8995.c-132-\t.xmit = ks8995_xmit,\n--\nnet/dsa/tag_ks8995.c=138=MODULE_LICENSE(\"GPL\");\nnet/dsa/tag_ks8995.c:139:MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KS8995, KS8995_NAME);\nnet/dsa/tag_ks8995.c-140-\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/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 39767
							output: 30
							thoughts: 51
						

Thoughts:
Here's my take on those initial thoughts:

**Exploring DSA Loopback Functionality**

Okay, so I'm diving into the DSA switch architecture, specifically focusing on how the loopback functionality is implemented. My immediate goal is to understand the interplay between DSA switches and the use of mock or virtual environments for testing and development. I need a clear picture of how these components are connected.

My first thought is to take a look at the code. I think grepping for something like `dsa_loop` is probably a solid starting point. This should lead me straight to the relevant files, likely somewhere within the `drivers/net/dsa` directory. I'm guessing `dsa_loop.c` or something similarly named will hold the key, but a broader grep will catch anything that is related. I'm expecting this to give me the nuts and bolts of how the loopback is configured, triggered, and handled by the system. Then I can piece together how this integrates with the other DSA components and virtual setups.



6/2 2026/09/01 03:56 tool grepper
0m Args:
{
  "Expression": "dsa_loop",
  "PathPrefix": "drivers/net/dsa"
}

Results:
{
  "Output": "drivers/net/dsa/Makefile=3=bcm-sf2-objs\t\t\t:= bcm_sf2.o bcm_sf2_cfp.o\ndrivers/net/dsa/Makefile:4:obj-$(CONFIG_NET_DSA_LOOP)\t+= dsa_loop.o\ndrivers/net/dsa/Makefile-5-obj-$(CONFIG_NET_DSA_MT7530)\t+= mt7530.o\n--\ndrivers/net/dsa/dsa_loop.c-24-\ndrivers/net/dsa/dsa_loop.c:25:struct dsa_loop_vlan {\ndrivers/net/dsa/dsa_loop.c-26-\tu16 members;\n--\ndrivers/net/dsa/dsa_loop.c-29-\ndrivers/net/dsa/dsa_loop.c:30:struct dsa_loop_mib_entry {\ndrivers/net/dsa/dsa_loop.c-31-\tchar name[ETH_GSTRING_LEN];\n--\ndrivers/net/dsa/dsa_loop.c-34-\ndrivers/net/dsa/dsa_loop.c:35:enum dsa_loop_mib_counters {\ndrivers/net/dsa/dsa_loop.c-36-\tDSA_LOOP_PHY_READ_OK,\n--\ndrivers/net/dsa/dsa_loop.c-42-\ndrivers/net/dsa/dsa_loop.c:43:struct dsa_loop_port {\ndrivers/net/dsa/dsa_loop.c:44:\tstruct dsa_loop_mib_entry mib[__DSA_LOOP_CNT_MAX];\ndrivers/net/dsa/dsa_loop.c-45-\tu16 pvid;\n--\ndrivers/net/dsa/dsa_loop.c-48-\ndrivers/net/dsa/dsa_loop.c:49:struct dsa_loop_priv {\ndrivers/net/dsa/dsa_loop.c-50-\tstruct mii_bus\t*bus;\ndrivers/net/dsa/dsa_loop.c-51-\tunsigned int\tport_base;\ndrivers/net/dsa/dsa_loop.c:52:\tstruct dsa_loop_vlan vlans[VLAN_N_VID];\ndrivers/net/dsa/dsa_loop.c-53-\tstruct net_device *netdev;\ndrivers/net/dsa/dsa_loop.c:54:\tstruct dsa_loop_port ports[DSA_MAX_PORTS];\ndrivers/net/dsa/dsa_loop.c-55-};\ndrivers/net/dsa/dsa_loop.c-56-\ndrivers/net/dsa/dsa_loop.c:57:struct dsa_loop_pdata {\ndrivers/net/dsa/dsa_loop.c-58-\t/* Must be first, such that dsa_register_switch() can access this\n--\ndrivers/net/dsa/dsa_loop.c-66-\ndrivers/net/dsa/dsa_loop.c:67:static struct dsa_loop_mib_entry dsa_loop_mibs[] = {\ndrivers/net/dsa/dsa_loop.c-68-\t[DSA_LOOP_PHY_READ_OK]\t= { \"phy_read_ok\", },\n--\ndrivers/net/dsa/dsa_loop.c=75=static struct mdio_device *switch_mdiodev;\ndrivers/net/dsa/dsa_loop.c-76-\ndrivers/net/dsa/dsa_loop.c:77:enum dsa_loop_devlink_resource_id {\ndrivers/net/dsa/dsa_loop.c-78-\tDSA_LOOP_DEVLINK_PARAM_ID_NONE,  /* DEVLINK_RESOURCE_ID_PARENT_TOP */\n--\ndrivers/net/dsa/dsa_loop.c-81-\ndrivers/net/dsa/dsa_loop.c:82:static u64 dsa_loop_devlink_vtu_get(void *priv)\ndrivers/net/dsa/dsa_loop.c-83-{\ndrivers/net/dsa/dsa_loop.c:84:\tstruct dsa_loop_priv *ps = priv;\ndrivers/net/dsa/dsa_loop.c-85-\tunsigned int i, count = 0;\ndrivers/net/dsa/dsa_loop.c:86:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-87-\n--\ndrivers/net/dsa/dsa_loop.c-96-\ndrivers/net/dsa/dsa_loop.c:97:static int dsa_loop_setup_devlink_resources(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-98-{\ndrivers/net/dsa/dsa_loop.c-99-\tstruct devlink_resource_size_params size_params;\ndrivers/net/dsa/dsa_loop.c:100:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-101-\tint err;\n--\ndrivers/net/dsa/dsa_loop.c-115-\t\t\t\t\t      DSA_LOOP_DEVLINK_PARAM_ID_VTU,\ndrivers/net/dsa/dsa_loop.c:116:\t\t\t\t\t      dsa_loop_devlink_vtu_get, ps);\ndrivers/net/dsa/dsa_loop.c-117-\n--\ndrivers/net/dsa/dsa_loop.c-124-\ndrivers/net/dsa/dsa_loop.c:125:static enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/dsa_loop.c-126-\t\t\t\t\t\t   int port,\n--\ndrivers/net/dsa/dsa_loop.c-133-\ndrivers/net/dsa/dsa_loop.c:134:static int dsa_loop_setup(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-135-{\ndrivers/net/dsa/dsa_loop.c:136:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-137-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-139-\tfor (i = 0; i \u003c ds-\u003enum_ports; i++)\ndrivers/net/dsa/dsa_loop.c:140:\t\tmemcpy(ps-\u003eports[i].mib, dsa_loop_mibs,\ndrivers/net/dsa/dsa_loop.c:141:\t\t       sizeof(dsa_loop_mibs));\ndrivers/net/dsa/dsa_loop.c-142-\n--\ndrivers/net/dsa/dsa_loop.c-144-\ndrivers/net/dsa/dsa_loop.c:145:\treturn dsa_loop_setup_devlink_resources(ds);\ndrivers/net/dsa/dsa_loop.c-146-}\ndrivers/net/dsa/dsa_loop.c-147-\ndrivers/net/dsa/dsa_loop.c:148:static void dsa_loop_teardown(struct dsa_switch *ds)\ndrivers/net/dsa/dsa_loop.c-149-{\n--\ndrivers/net/dsa/dsa_loop.c-152-\ndrivers/net/dsa/dsa_loop.c:153:static int dsa_loop_get_sset_count(struct dsa_switch *ds, int port, int sset)\ndrivers/net/dsa/dsa_loop.c-154-{\n--\ndrivers/net/dsa/dsa_loop.c-160-\ndrivers/net/dsa/dsa_loop.c:161:static void dsa_loop_get_strings(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-162-\t\t\t\t u32 stringset, uint8_t *data)\ndrivers/net/dsa/dsa_loop.c-163-{\ndrivers/net/dsa/dsa_loop.c:164:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-165-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-173-\ndrivers/net/dsa/dsa_loop.c:174:static void dsa_loop_get_ethtool_stats(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-175-\t\t\t\t       uint64_t *data)\ndrivers/net/dsa/dsa_loop.c-176-{\ndrivers/net/dsa/dsa_loop.c:177:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-178-\tunsigned int i;\n--\ndrivers/net/dsa/dsa_loop.c-183-\ndrivers/net/dsa/dsa_loop.c:184:static int dsa_loop_phy_read(struct dsa_switch *ds, int port, int regnum)\ndrivers/net/dsa/dsa_loop.c-185-{\ndrivers/net/dsa/dsa_loop.c:186:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-187-\tstruct mii_bus *bus = ps-\u003ebus;\n--\ndrivers/net/dsa/dsa_loop.c-198-\ndrivers/net/dsa/dsa_loop.c:199:static int dsa_loop_phy_write(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-200-\t\t\t      int regnum, u16 value)\ndrivers/net/dsa/dsa_loop.c-201-{\ndrivers/net/dsa/dsa_loop.c:202:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-203-\tstruct mii_bus *bus = ps-\u003ebus;\n--\ndrivers/net/dsa/dsa_loop.c-214-\ndrivers/net/dsa/dsa_loop.c:215:static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-216-\t\t\t\t     struct dsa_bridge bridge,\n--\ndrivers/net/dsa/dsa_loop.c-225-\ndrivers/net/dsa/dsa_loop.c:226:static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-227-\t\t\t\t       struct dsa_bridge bridge)\n--\ndrivers/net/dsa/dsa_loop.c-232-\ndrivers/net/dsa/dsa_loop.c:233:static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-234-\t\t\t\t\tu8 state)\n--\ndrivers/net/dsa/dsa_loop.c-239-\ndrivers/net/dsa/dsa_loop.c:240:static int dsa_loop_port_vlan_filtering(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-241-\t\t\t\t\tbool vlan_filtering,\n--\ndrivers/net/dsa/dsa_loop.c-249-\ndrivers/net/dsa/dsa_loop.c:250:static int dsa_loop_port_vlan_add(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-251-\t\t\t\t  const struct switchdev_obj_port_vlan *vlan,\n--\ndrivers/net/dsa/dsa_loop.c-255-\tbool pvid = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_PVID;\ndrivers/net/dsa/dsa_loop.c:256:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-257-\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:258:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-259-\n--\ndrivers/net/dsa/dsa_loop.c-282-\ndrivers/net/dsa/dsa_loop.c:283:static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-284-\t\t\t\t  const struct switchdev_obj_port_vlan *vlan)\n--\ndrivers/net/dsa/dsa_loop.c-286-\tbool untagged = vlan-\u003eflags \u0026 BRIDGE_VLAN_INFO_UNTAGGED;\ndrivers/net/dsa/dsa_loop.c:287:\tstruct dsa_loop_priv *ps = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-288-\tu16 pvid = ps-\u003eports[port].pvid;\ndrivers/net/dsa/dsa_loop.c-289-\tstruct mii_bus *bus = ps-\u003ebus;\ndrivers/net/dsa/dsa_loop.c:290:\tstruct dsa_loop_vlan *vl;\ndrivers/net/dsa/dsa_loop.c-291-\n--\ndrivers/net/dsa/dsa_loop.c-310-\ndrivers/net/dsa/dsa_loop.c:311:static int dsa_loop_port_change_mtu(struct dsa_switch *ds, int port,\ndrivers/net/dsa/dsa_loop.c-312-\t\t\t\t    int new_mtu)\ndrivers/net/dsa/dsa_loop.c-313-{\ndrivers/net/dsa/dsa_loop.c:314:\tstruct dsa_loop_priv *priv = ds-\u003epriv;\ndrivers/net/dsa/dsa_loop.c-315-\n--\ndrivers/net/dsa/dsa_loop.c-320-\ndrivers/net/dsa/dsa_loop.c:321:static int dsa_loop_port_max_mtu(struct dsa_switch *ds, int port)\ndrivers/net/dsa/dsa_loop.c-322-{\n--\ndrivers/net/dsa/dsa_loop.c-325-\ndrivers/net/dsa/dsa_loop.c:326:static void dsa_loop_phylink_get_caps(struct dsa_switch *dsa, int port,\ndrivers/net/dsa/dsa_loop.c-327-\t\t\t\t      struct phylink_config *config)\n--\ndrivers/net/dsa/dsa_loop.c-333-\ndrivers/net/dsa/dsa_loop.c:334:static const struct dsa_switch_ops dsa_loop_driver = {\ndrivers/net/dsa/dsa_loop.c:335:\t.get_tag_protocol\t= dsa_loop_get_protocol,\ndrivers/net/dsa/dsa_loop.c:336:\t.setup\t\t\t= dsa_loop_setup,\ndrivers/net/dsa/dsa_loop.c:337:\t.teardown\t\t= dsa_loop_teardown,\ndrivers/net/dsa/dsa_loop.c:338:\t.get_strings\t\t= dsa_loop_get_strings,\ndrivers/net/dsa/dsa_loop.c:339:\t.get_ethtool_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:340:\t.get_sset_count\t\t= dsa_loop_get_sset_count,\ndrivers/net/dsa/dsa_loop.c:341:\t.get_ethtool_phy_stats\t= dsa_loop_get_ethtool_stats,\ndrivers/net/dsa/dsa_loop.c:342:\t.phy_read\t\t= dsa_loop_phy_read,\ndrivers/net/dsa/dsa_loop.c:343:\t.phy_write\t\t= dsa_loop_phy_write,\ndrivers/net/dsa/dsa_loop.c:344:\t.port_bridge_join\t= dsa_loop_port_bridge_join,\ndrivers/net/dsa/dsa_loop.c:345:\t.port_bridge_leave\t= dsa_loop_port_bridge_leave,\ndrivers/net/dsa/dsa_loop.c:346:\t.port_stp_state_set\t= dsa_loop_port_stp_state_set,\ndrivers/net/dsa/dsa_loop.c:347:\t.port_vlan_filtering\t= dsa_loop_port_vlan_filtering,\ndrivers/net/dsa/dsa_loop.c:348:\t.port_vlan_add\t\t= dsa_loop_port_vlan_add,\ndrivers/net/dsa/dsa_loop.c:349:\t.port_vlan_del\t\t= dsa_loop_port_vlan_del,\ndrivers/net/dsa/dsa_loop.c:350:\t.port_change_mtu\t= dsa_loop_port_change_mtu,\ndrivers/net/dsa/dsa_loop.c:351:\t.port_max_mtu\t\t= dsa_loop_port_max_mtu,\ndrivers/net/dsa/dsa_loop.c:352:\t.phylink_get_caps\t= dsa_loop_phylink_get_caps,\ndrivers/net/dsa/dsa_loop.c-353-};\ndrivers/net/dsa/dsa_loop.c-354-\ndrivers/net/dsa/dsa_loop.c:355:static int dsa_loop_drv_probe(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-356-{\ndrivers/net/dsa/dsa_loop.c:357:\tstruct dsa_loop_pdata *pdata = mdiodev-\u003edev.platform_data;\ndrivers/net/dsa/dsa_loop.c:358:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c-359-\tstruct dsa_switch *ds;\n--\ndrivers/net/dsa/dsa_loop.c-382-\tds-\u003edev = \u0026mdiodev-\u003edev;\ndrivers/net/dsa/dsa_loop.c:383:\tds-\u003eops = \u0026dsa_loop_driver;\ndrivers/net/dsa/dsa_loop.c-384-\tds-\u003epriv = ps;\n--\ndrivers/net/dsa/dsa_loop.c-396-\ndrivers/net/dsa/dsa_loop.c:397:static void dsa_loop_drv_remove(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-398-{\ndrivers/net/dsa/dsa_loop.c-399-\tstruct dsa_switch *ds = dev_get_drvdata(\u0026mdiodev-\u003edev);\ndrivers/net/dsa/dsa_loop.c:400:\tstruct dsa_loop_priv *ps;\ndrivers/net/dsa/dsa_loop.c-401-\n--\ndrivers/net/dsa/dsa_loop.c-410-\ndrivers/net/dsa/dsa_loop.c:411:static void dsa_loop_drv_shutdown(struct mdio_device *mdiodev)\ndrivers/net/dsa/dsa_loop.c-412-{\n--\ndrivers/net/dsa/dsa_loop.c-422-\ndrivers/net/dsa/dsa_loop.c:423:static struct mdio_driver dsa_loop_drv = {\ndrivers/net/dsa/dsa_loop.c-424-\t.mdiodrv.driver\t= {\n--\ndrivers/net/dsa/dsa_loop.c-426-\t},\ndrivers/net/dsa/dsa_loop.c:427:\t.probe\t= dsa_loop_drv_probe,\ndrivers/net/dsa/dsa_loop.c:428:\t.remove\t= dsa_loop_drv_remove,\ndrivers/net/dsa/dsa_loop.c:429:\t.shutdown = dsa_loop_drv_shutdown,\ndrivers/net/dsa/dsa_loop.c-430-};\ndrivers/net/dsa/dsa_loop.c-431-\ndrivers/net/dsa/dsa_loop.c:432:static int dsa_loop_bus_match(struct device *dev,\ndrivers/net/dsa/dsa_loop.c-433-\t\t\t      const struct device_driver *drv)\ndrivers/net/dsa/dsa_loop.c-434-{\ndrivers/net/dsa/dsa_loop.c:435:\treturn drv == \u0026dsa_loop_drv.mdiodrv.driver;\ndrivers/net/dsa/dsa_loop.c-436-}\ndrivers/net/dsa/dsa_loop.c-437-\ndrivers/net/dsa/dsa_loop.c:438:static void dsa_loop_phydevs_unregister(void)\ndrivers/net/dsa/dsa_loop.c-439-{\n--\ndrivers/net/dsa/dsa_loop.c-445-\ndrivers/net/dsa/dsa_loop.c:446:static int __init dsa_loop_create_switch_mdiodev(void)\ndrivers/net/dsa/dsa_loop.c-447-{\ndrivers/net/dsa/dsa_loop.c:448:\tstatic struct dsa_loop_pdata dsa_loop_pdata = {\ndrivers/net/dsa/dsa_loop.c-449-\t\t.cd = {\n--\ndrivers/net/dsa/dsa_loop.c-470-\ndrivers/net/dsa/dsa_loop.c:471:\tswitch_mdiodev-\u003ebus_match = dsa_loop_bus_match;\ndrivers/net/dsa/dsa_loop.c:472:\tswitch_mdiodev-\u003edev.platform_data = \u0026dsa_loop_pdata;\ndrivers/net/dsa/dsa_loop.c-473-\n--\ndrivers/net/dsa/dsa_loop.c-481-\ndrivers/net/dsa/dsa_loop.c:482:static int __init dsa_loop_init(void)\ndrivers/net/dsa/dsa_loop.c-483-{\n--\ndrivers/net/dsa/dsa_loop.c-486-\ndrivers/net/dsa/dsa_loop.c:487:\tret = dsa_loop_create_switch_mdiodev();\ndrivers/net/dsa/dsa_loop.c-488-\tif (ret)\n--\ndrivers/net/dsa/dsa_loop.c-493-\ndrivers/net/dsa/dsa_loop.c:494:\tret = mdio_driver_register(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c-495-\tif (ret) {\ndrivers/net/dsa/dsa_loop.c:496:\t\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c-497-\t\tmdio_device_remove(switch_mdiodev);\n--\ndrivers/net/dsa/dsa_loop.c-502-}\ndrivers/net/dsa/dsa_loop.c:503:module_init(dsa_loop_init);\ndrivers/net/dsa/dsa_loop.c-504-\ndrivers/net/dsa/dsa_loop.c:505:static void __exit dsa_loop_exit(void)\ndrivers/net/dsa/dsa_loop.c-506-{\ndrivers/net/dsa/dsa_loop.c:507:\tmdio_driver_unregister(\u0026dsa_loop_drv);\ndrivers/net/dsa/dsa_loop.c:508:\tdsa_loop_phydevs_unregister();\ndrivers/net/dsa/dsa_loop.c-509-\tmdio_device_remove(switch_mdiodev);\n--\ndrivers/net/dsa/dsa_loop.c-511-}\ndrivers/net/dsa/dsa_loop.c:512:module_exit(dsa_loop_exit);\ndrivers/net/dsa/dsa_loop.c-513-\n"
}

7/2 2026/09/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 46604
							output: 41
							thoughts: 53
						

Thoughts:
Here's my take on those lines of code:

**Analyzing the `dsa_loop_get_protocol` Function**

Okay, so I'm diving into the `dsa_loop_get_protocol` function, specifically within `dsa_loop.c`. Let me just pull up those lines, 120-135, from the file in the `drivers/net/dsa` directory. Right, got it. From a quick glance, I'm guessing this function is responsible for determining the network protocol used on a DSA loop device. I'll need to see how it interacts with the underlying hardware, if at all. It might involve checking registers or interpreting some sort of configuration. I'll have to see if it's returning a standard ethertype or something more device-specific. Let me analyze that code... I'm guessing it probably uses that to return some form of protocol type, probably something like `ETH_P_8021Q` or similar. I'll have to see if it makes some assumptions. This is typical of a DSA driver setup. Let's see how they handle the `dsa_loop` devices.



8/2 2026/09/01 03:56 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/dsa_loop.c",
  "FirstLine": 120,
  "LineCount": 20
}

Results:
{
  "Contents": " 120:\tout:\n 121:\t\tdsa_devlink_resources_unregister(ds);\n 122:\t\treturn err;\n 123:\t}\n 124:\t\n 125:\tstatic enum dsa_tag_protocol dsa_loop_get_protocol(struct dsa_switch *ds,\n 126:\t\t\t\t\t\t\t   int port,\n 127:\t\t\t\t\t\t\t   enum dsa_tag_protocol mp)\n 128:\t{\n 129:\t\tdev_dbg(ds-\u003edev, \"%s: port: %d\\n\", __func__, port);\n 130:\t\n 131:\t\treturn DSA_TAG_PROTO_NONE;\n 132:\t}\n 133:\t\n 134:\tstatic int dsa_loop_setup(struct dsa_switch *ds)\n 135:\t{\n 136:\t\tstruct dsa_loop_priv *ps = ds-\u003epriv;\n 137:\t\tunsigned int i;\n 138:\t\n 139:\t\tfor (i = 0; i \u003c ds-\u003enum_ports; i++)\n"
}

9/2 2026/09/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 47245
							output: 40
							thoughts: 89
						

Thoughts:
Okay, here's my summary, framed as my internal thought process:

**Investigating Dynamic DSA Tag Protocol Management**

Alright, let's dive into this DSA tagging situation. My first thought is, how flexible *are* these tagging protocols? Can we actually modify or configure them dynamically at runtime? Are there mechanisms like devlink, netlink, sysfs, or ioctl that offer the hooks we need for this kind of manipulation? Or, is it more about finding a way to *invoke* specific DSA tag protocol drivers on the fly? That's the core question.

To get a handle on the codebase, I'm going to start with a targeted search. I'll need to dig into the `net/dsa/` and perhaps even parts of `net/core/` directories, because DSA is so intertwined with core networking. I'll specifically look for definitions like `DSA_TAG_PROTO_`, which I'm betting are macros related to different tag protocol types. Also, I'll search for references to `dsa_tag_driver`, that seems likely to hold the structures or functions for different tag drivers. Finally, I'll need to check the data structure, `dsa_device_ops`, to understand how device-specific operations related to the DSA framework can be changed. These are the key identifiers I expect to find and they'll probably lead me to the dynamic setting methods, or at least to the correct starting point for digging further.



10/2 2026/09/01 03:56 tool grepper
0m Args:
{
  "Expression": "change_tag_protocol|dsa_tree_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=873=static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-879-\nnet/dsa/switch.c:880:\tif (!ds-\u003eops-\u003echange_tag_protocol)\nnet/dsa/switch.c-881-\t\treturn -EOPNOTSUPP;\n--\nnet/dsa/switch.c-884-\nnet/dsa/switch.c:885:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/switch.c-886-\tif (err)\n--\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"
}

11/2 2026/09/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 48651
							output: 37
							thoughts: 41
						

Thoughts:
Here's my take on the `tagging_store` function in `net/dsa/conduit.c`, as though it's my own thought process:

**Diving into `tagging_store`**

Alright, let's dissect this `tagging_store` function within `net/dsa/conduit.c`. I know this DSA conduit code like the back of my hand, so I'm keen to see what's happening here. My initial thought is to figure out how they're handling the tagging mechanism within this specific context. Is it using VLANs, some proprietary header, or something else entirely? The name itself screams "tagging," but specifics are key. Let me start by actually reading the code and seeing what I'm looking at.



12/2 2026/09/01 03:56 tool read-file
0m Args:
{
  "File": "net/dsa/conduit.c",
  "FirstLine": 345,
  "LineCount": 50
}

Results:
{
  "Contents": " 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"
}

13/2 2026/09/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 49671
							output: 34
							thoughts: 73
						

Thoughts:
**My Initial Assessment of the Tagging Protocol Change**

Okay, so `tagging_store` offers a way to tweak the tagging protocol on a DSA conduit netdevice using sysfs, specifically the `/sys/class/net/<conduit>/dsa/tagging` interface. That’s a potentially useful capability! But hold on... before I get carried away, I need to consider a key dependency. Does this functionality hinge on a specific callback within the switch driver? I'm pretty sure it does. It probably requires the driver to expose a `change_tag_protocol` callback function to handle this kind of request.

Time to verify that assumption. Let me immediately check the implementation of `dsa_tree_change_tag_proto`. That should tell the tale.



14/2 2026/09/01 03:56 tool grepper
0m Args:
{
  "Expression": "dsa_tree_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=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.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=873=static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\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"
}

15/2 2026/09/01 03:56 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 50422
							output: 36
							thoughts: 38
						

Thoughts:
Okay, here's my interpretation of those thoughts, summarized from my perspective as someone familiar with networking and DSA (Distributed Switch Architecture):

**Examining Tagging Protocol Changes in DSA Switches**

Alright, I need to dive into the code related to changing the tagging protocol for DSA switches. Specifically, I'm going to look at `net/dsa/switch.c: dsa_switch_change_tag_proto` and `dsa_tree_change_tag_proto`. These are the functions responsible for managing how frames are tagged and untagged as they traverse the switch fabric. My focus will be on understanding how the protocol is switched or modified. I will likely be looking for the implications of these changes, the conditions that trigger them, and the procedures involved in updating the hardware or software to reflect the new tagging scheme. I expect this will involve updates to internal data structures, potential reconfiguration of the switch's forwarding tables, and possibly, signaling requirements for the underlying switch hardware. This should be an interesting peek into how DSA handles these crucial low-level details.



16/2 2026/09/01 03:57 tool read-file
0m Args:
{
  "File": "net/dsa/switch.c",
  "FirstLine": 870,
  "LineCount": 40
}

Results:
{
  "Contents": " 870:\t\treturn 0;\n 871:\t}\n 872:\t\n 873:\tstatic int dsa_switch_change_tag_proto(struct dsa_switch *ds,\n 874:\t\t\t\t\t       struct dsa_notifier_tag_proto_info *info)\n 875:\t{\n 876:\t\tconst struct dsa_device_ops *tag_ops = info-\u003etag_ops;\n 877:\t\tstruct dsa_port *dp, *cpu_dp;\n 878:\t\tint err;\n 879:\t\n 880:\t\tif (!ds-\u003eops-\u003echange_tag_protocol)\n 881:\t\t\treturn -EOPNOTSUPP;\n 882:\t\n 883:\t\tASSERT_RTNL();\n 884:\t\n 885:\t\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\n 886:\t\tif (err)\n 887:\t\t\treturn err;\n 888:\t\n 889:\t\tdsa_switch_for_each_cpu_port(cpu_dp, ds)\n 890:\t\t\tdsa_port_set_tag_protocol(cpu_dp, tag_ops);\n 891:\t\n 892:\t\t/* Now that changing the tag protocol can no longer fail, let's update\n 893:\t\t * the remaining bits which are \"duplicated for faster access\", and the\n 894:\t\t * bits that depend on the tagger, such as the MTU.\n 895:\t\t */\n 896:\t\tdsa_switch_for_each_user_port(dp, ds) {\n 897:\t\t\tstruct net_device *user = dp-\u003euser;\n 898:\t\n 899:\t\t\tdsa_user_setup_tagger(user);\n 900:\t\n 901:\t\t\t/* rtnl_mutex is held in dsa_tree_change_tag_proto */\n 902:\t\t\tdsa_user_change_mtu(user, user-\u003emtu);\n 903:\t\t}\n 904:\t\n 905:\t\treturn 0;\n 906:\t}\n 907:\t\n 908:\t/* We use the same cross-chip notifiers to inform both the tagger side, as well\n 909:\t * as the switch side, of connection and disconnection events.\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 51340
							output: 34
							thoughts: 16
						

Thoughts:
Okay, let's break this down.

**Investigating `change_tag_protocol` Implementation**

Right, so I need to figure out precisely which components or modules are responsible for implementing the `change_tag_protocol` function or method. I'm going to quickly identify which classes or objects define, inherit, or override this particular functionality. This involves a precise code search, probably using a sophisticated IDE search or a grep command with some careful filtering. I’ll be looking for actual *implementations*, not just declarations or function signatures. I need to understand the practical code that runs when this protocol is, in fact, changed. My goal is a concise list or overview of those implementations for further inspection. Time to dig in.



18/2 2026/09/01 03:57 tool grepper
0m Args:
{
  "Expression": "\\.change_tag_protocol\\b",
  "PathPrefix": "drivers/net/dsa"
}

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

19/2 2026/09/01 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 52077
							output: 47
							thoughts: 72
						

Thoughts:
**Examining Switch Compatibility**

Okay, hold on a minute. Before I proceed further, I need to clarify something crucial: Can *any* switch utilize the `ks8995` functionality? It's essential to understand the potential scope and limitations here. I need to be absolutely certain.

Let's quickly take a look at the known switch types that come to mind: `felix`, `mv88e6xxx`, and `rtl8365mb`. Now, let's drill down deeper. My instinct tells me to check the `felix_change_tag_protocol` and `mv88e6xxx_change_tag_protocol` functions – those are probably the best places to see how each switch handles this sort of thing. I need to see exactly what those functions support. I need to figure out how these switches interact with this feature.



20/2 2026/09/01 03:57 tool grepper
0m Args:
{
  "Expression": "mv88e6xxx_change_tag_protocol|felix_change_tag_protocol",
  "PathPrefix": "drivers/net/dsa"
}

Results:
{
  "Output": "drivers/net/dsa/mv88e6xxx/chip.c=6646=static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-6654-\ndrivers/net/dsa/mv88e6xxx/chip.c:6655:static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/mv88e6xxx/chip.c-6656-\t\t\t\t\t enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=7187=static const struct dsa_switch_ops mv88e6xxx_switch_ops = {\ndrivers/net/dsa/mv88e6xxx/chip.c-7188-\t.get_tag_protocol\t= mv88e6xxx_get_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c:7189:\t.change_tag_protocol\t= mv88e6xxx_change_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c-7190-\t.setup\t\t\t= mv88e6xxx_setup,\n--\ndrivers/net/dsa/ocelot/felix.c=732=felix_tag_proto_setup_shared(struct dsa_switch *ds,\n--\ndrivers/net/dsa/ocelot/felix.c-753- */\ndrivers/net/dsa/ocelot/felix.c:754:static int felix_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/ocelot/felix.c-755-\t\t\t\t     enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/ocelot/felix.c=1696=static int felix_setup(struct dsa_switch *ds)\n--\ndrivers/net/dsa/ocelot/felix.c-1751-\t */\ndrivers/net/dsa/ocelot/felix.c:1752:\tfelix_change_tag_protocol(ds, felix-\u003etag_proto);\ndrivers/net/dsa/ocelot/felix.c-1753-\n--\ndrivers/net/dsa/ocelot/felix.c=2306=static const struct dsa_switch_ops felix_switch_ops = {\ndrivers/net/dsa/ocelot/felix.c-2307-\t.get_tag_protocol\t\t= felix_get_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c:2308:\t.change_tag_protocol\t\t= felix_change_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c-2309-\t.connect_tag_protocol\t\t= felix_connect_tag_protocol,\n"
}

21/2 2026/09/01 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 53157
							output: 46
							thoughts: 62
						

Thoughts:
Here's my thinking process:

**Diving into Tag Protocol Changes in DSA Drivers**

Okay, so I need to understand how the tag protocol gets switched within these DSA drivers. My first step is to focus on the `mv88e6xxx` and `felix` driver implementations specifically. I'm going to investigate what the functions `mv88e6xxx_change_tag_protocol` and `felix_change_tag_protocol` are doing. I'll need to see how they're handling that tag protocol change.

To do that, I'm going to go straight to the code. I know that `drivers/net/dsa/mv88e6xxx/chip.c` will be the best place to start, as I can find the details of the driver's implementation. I'm especially interested in the section around line 6655, as that could be where the tag protocol modification takes place. I expect to find some logic there to understand how these drivers handle the protocol changes. I'll focus on these two functions and the context of the surrounding code.



22/2 2026/09/01 03:57 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/mv88e6xxx/chip.c",
  "FirstLine": 6650,
  "LineCount": 30
}

Results:
{
  "Contents": "6650:\t\tstruct mv88e6xxx_chip *chip = ds-\u003epriv;\n6651:\t\n6652:\t\treturn chip-\u003etag_protocol;\n6653:\t}\n6654:\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;\n6679:\t\t}\n"
}

23/2 2026/09/01 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 53953
							output: 35
							thoughts: 674
						

Thoughts:
**My Assessment of the KSZ8995XA Driver's Fuzzing Potential**

Okay, so the KSZ8995XA switch uniquely uses `DSA_TAG_PROTO_KS8995`. Now, the critical question is, how is this thing instantiated and probed in the kernel? I need to figure out if it's an SPI device. Let's start by looking at `ksz_spi.c` and `ksz_common.c` within the DSA Microchip driver directory. I need to understand the typical DSA switch instantiation process in Linux. It's usually through Device Tree, platform data, or SPI board info, or potentially ACPI.

Now, considering fuzzing, especially within virtualized environments like QEMU and syzkaller, can we even *reach* this thing without real SPI hardware? This is the core issue. Does syzkaller offer SPI fuzzing capabilities or mock SPI devices, or does it, by default, skip SPI, I2C, and MDIO drivers unless there's a virtual bus available? I need to check the syzkaller documentation on what kind of devices are worth fuzzing.

Let's see: modifications to documentation, Kconfig files, decorative changes, and changes to constants that don't alter execution flow are not interesting. Similarly, unreachable code paths in virtualized environments – those are out. Vendor-specific PCIe switch drivers that rely on physical hardware are also ignored, as are `.remove`, `.shutdown`, and `pci_unregister_driver` callbacks.

So, the key questions remain: Can SPI drivers in general (and specifically `net/dsa/tag_ks8995.c` and `drivers/net/dsa/microchip/`) be reached in virtualized environments like GCE or QEMU? Can SPI devices be instantiated or *emulated* in QEMU? Does it require physical hardware or rely on Device Tree overlays? Is `tag_ks8995.c` or `ksz_spi.c` even instantiated in the QEMU fuzzing environment? I should explore related areas like `dsa_loop`, mock DSA devices, `spi-nor`, `spi-tle62x0`, or whether SPI controller emulation is available. I need to determine if syzkaller has experience fuzzing other DSA switches or SPI drivers. Finally, I should perform a thorough search within the kernel for any instances of mock or emulated SPI controllers, or anything resembling a DSA mock implementation. This will help determine if this area is even considered fuzzable in this environment.



24/2 2026/09/01 03:57 tool grepper
0m Args:
{
  "Expression": "spi_register_board_info|spi_board_info",
  "PathPrefix": "drivers/"
}

Results:
{
  "Output": "drivers/fpga/dfl-n3000-nios.c=296=static int n3000_nios_init_done_check(struct n3000_nios *nn)\n--\ndrivers/fpga/dfl-n3000-nios.c-322-\t * SPI bus. So the driver doesn't error out, it continues to create the\ndrivers/fpga/dfl-n3000-nios.c:323:\t * spi controller device and spi_board_info for BMC.\ndrivers/fpga/dfl-n3000-nios.c-324-\t */\n--\ndrivers/fpga/dfl-n3000-nios.c-396-\t\t * driver doesn't error out, it continues to create the spi\ndrivers/fpga/dfl-n3000-nios.c:397:\t\t * controller device and spi_board_info for BMC.\ndrivers/fpga/dfl-n3000-nios.c-398-\t\t */\n--\ndrivers/fpga/dfl-n3000-nios.c-407-\ndrivers/fpga/dfl-n3000-nios.c:408:static struct spi_board_info m10_n3000_info = {\ndrivers/fpga/dfl-n3000-nios.c-409-\t.modalias = \"m10-n3000\",\n--\ndrivers/hwmon/ads7871.c-6- *\ndrivers/hwmon/ads7871.c:7: *\tYou need to have something like this in struct spi_board_info\ndrivers/hwmon/ads7871.c-8- *\t{\n--\ndrivers/media/pci/mgb4/mgb4_core.c=161=static int init_spi(struct mgb4_dev *mgbdev, u32 devid)\n--\ndrivers/media/pci/mgb4/mgb4_core.c-176-\t};\ndrivers/media/pci/mgb4/mgb4_core.c:177:\tstruct spi_board_info spi_info = {\ndrivers/media/pci/mgb4/mgb4_core.c-178-\t\t.max_speed_hz = 10000000,\n--\ndrivers/media/pci/netup_unidvb/netup_unidvb_spi.c=55=static struct flash_platform_data spi_flash_data = {\n--\ndrivers/media/pci/netup_unidvb/netup_unidvb_spi.c-60-\ndrivers/media/pci/netup_unidvb/netup_unidvb_spi.c:61:static struct spi_board_info netup_spi_board = {\ndrivers/media/pci/netup_unidvb/netup_unidvb_spi.c-62-\t.modalias = \"m25p128\",\n--\ndrivers/media/usb/msi2500/msi2500.c=1176=static int msi2500_probe(struct usb_interface *intf,\n--\ndrivers/media/usb/msi2500/msi2500.c-1182-\tint ret;\ndrivers/media/usb/msi2500/msi2500.c:1183:\tstatic struct spi_board_info board_info = {\ndrivers/media/usb/msi2500/msi2500.c-1184-\t\t.modalias\t\t= \"msi001\",\n--\ndrivers/media/v4l2-core/v4l2-spi.c=36=struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,\ndrivers/media/v4l2-core/v4l2-spi.c-37-\t\t\t\t\tstruct spi_controller *ctlr,\ndrivers/media/v4l2-core/v4l2-spi.c:38:\t\t\t\t\tstruct spi_board_info *info)\ndrivers/media/v4l2-core/v4l2-spi.c-39-{\n--\ndrivers/mfd/timberdale.c=116=static const struct mc33880_platform_data timberdale_mc33880_platform_data = {\n--\ndrivers/mfd/timberdale.c-119-\ndrivers/mfd/timberdale.c:120:static struct spi_board_info timberdale_spi_16bit_board_info[] = {\ndrivers/mfd/timberdale.c-121-\t{\n--\ndrivers/mfd/timberdale.c-129-\ndrivers/mfd/timberdale.c:130:static struct spi_board_info timberdale_spi_8bit_board_info[] = {\ndrivers/mfd/timberdale.c-131-\t{\n--\ndrivers/misc/eeprom/digsy_mtc_eeprom.c=52=static struct gpiod_lookup_table eeprom_spi_gpiod_table = {\n--\ndrivers/misc/eeprom/digsy_mtc_eeprom.c-68-\ndrivers/misc/eeprom/digsy_mtc_eeprom.c:69:static struct spi_board_info digsy_mtc_eeprom_info[] __initdata = {\ndrivers/misc/eeprom/digsy_mtc_eeprom.c-70-\t{\n--\ndrivers/misc/eeprom/digsy_mtc_eeprom.c=79=static int __init digsy_mtc_eeprom_devices_init(void)\n--\ndrivers/misc/eeprom/digsy_mtc_eeprom.c-83-\tgpiod_add_lookup_table(\u0026eeprom_spi_gpiod_table);\ndrivers/misc/eeprom/digsy_mtc_eeprom.c:84:\tspi_register_board_info(digsy_mtc_eeprom_info,\ndrivers/misc/eeprom/digsy_mtc_eeprom.c-85-\t\t\t\tARRAY_SIZE(digsy_mtc_eeprom_info));\n--\ndrivers/misc/keba/cp500.c=219=static const struct flash_platform_data cp500_m25p16 = {\n--\ndrivers/misc/keba/cp500.c-224-};\ndrivers/misc/keba/cp500.c:225:static struct spi_board_info cp500_spi_info[] = {\ndrivers/misc/keba/cp500.c-226-\t{       /* system FPGA configuration bitstream flash */\n--\ndrivers/platform/x86/x86-android-tablets/core.c=236=static __init int x86_instantiate_spi_dev(const struct x86_dev_info *dev_info, int idx)\n--\ndrivers/platform/x86/x86-android-tablets/core.c-238-\tconst struct x86_spi_dev_info *spi_dev_info = \u0026dev_info-\u003espi_dev_info[idx];\ndrivers/platform/x86/x86-android-tablets/core.c:239:\tstruct spi_board_info board_info = spi_dev_info-\u003eboard_info;\ndrivers/platform/x86/x86-android-tablets/core.c-240-\tstruct spi_controller *controller;\n--\ndrivers/platform/x86/x86-android-tablets/x86-android-tablets.h=58=struct x86_spi_dev_info {\ndrivers/platform/x86/x86-android-tablets/x86-android-tablets.h:59:\tstruct spi_board_info board_info;\ndrivers/platform/x86/x86-android-tablets/x86-android-tablets.h-60-\tchar *ctrl_path;\n--\ndrivers/ptp/ptp_ocp.c=541=static struct ocp_resource ocp_fb_resource[] = {\n--\ndrivers/ptp/ptp_ocp.c-737-\t\t\t\t.force_irq = true,\ndrivers/ptp/ptp_ocp.c:738:\t\t\t\t.devices = \u0026(struct spi_board_info) {\ndrivers/ptp/ptp_ocp.c-739-\t\t\t\t\t.modalias = \"spi-nor\",\n--\ndrivers/ptp/ptp_ocp.c=782=static struct ocp_resource ocp_art_resource[] = {\n--\ndrivers/ptp/ptp_ocp.c-862-\t\t\t\t.num_devices = 1,\ndrivers/ptp/ptp_ocp.c:863:\t\t\t\t.devices = \u0026(struct spi_board_info) {\ndrivers/ptp/ptp_ocp.c-864-\t\t\t\t\t.modalias = \"spi-nor\",\n--\ndrivers/ptp/ptp_ocp.c=909=static struct ocp_resource ocp_adva_resource[] = {\n--\ndrivers/ptp/ptp_ocp.c-1027-\t\t\t\t.num_devices = 1,\ndrivers/ptp/ptp_ocp.c:1028:\t\t\t\t.devices = \u0026(struct spi_board_info) {\ndrivers/ptp/ptp_ocp.c-1029-\t\t\t\t\t.modalias = \"spi-nor\",\n--\ndrivers/ptp/ptp_ocp.c=1074=static struct ocp_resource ocp_adva_x1_resource[] = {\n--\ndrivers/ptp/ptp_ocp.c-1238-\t\t\t\t.force_irq = true,\ndrivers/ptp/ptp_ocp.c:1239:\t\t\t\t.devices = \u0026(struct spi_board_info) {\ndrivers/ptp/ptp_ocp.c-1240-\t\t\t\t\t.modalias = \"spi-nor\",\n--\ndrivers/rtc/rtc-pcf2123.c-16- *\ndrivers/rtc/rtc-pcf2123.c:17: * static struct spi_board_info ek_spi_devices[] = {\ndrivers/rtc/rtc-pcf2123.c-18- *\t...\n--\ndrivers/spi/Kconfig=487=config SPI_GPIO\n--\ndrivers/spi/Kconfig-494-\t  slaves connected to a bus using this driver are configured as usual,\ndrivers/spi/Kconfig:495:\t  except that the spi_board_info.controller_data holds the GPIO number\ndrivers/spi/Kconfig-496-\t  for the chipselect used by this controller driver.\n--\ndrivers/spi/spi-altera-dfl.c=124=static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)\ndrivers/spi/spi-altera-dfl.c-125-{\ndrivers/spi/spi-altera-dfl.c:126:\tstruct spi_board_info board_info = { 0 };\ndrivers/spi/spi-altera-dfl.c-127-\tstruct device *dev = \u0026dfl_dev-\u003edev;\n--\ndrivers/spi/spi-butterfly.c=49=struct butterfly {\n--\ndrivers/spi/spi-butterfly.c-59-\tstruct spi_device\t*butterfly;\ndrivers/spi/spi-butterfly.c:60:\tstruct spi_board_info\tinfo[2];\ndrivers/spi/spi-butterfly.c-61-\n--\ndrivers/spi/spi-ch341.c=125=static int ch341_enable_pins(struct ch341_spi_dev *ch341, bool enable)\n--\ndrivers/spi/spi-ch341.c-136-\ndrivers/spi/spi-ch341.c:137:static struct spi_board_info chip = {\ndrivers/spi/spi-ch341.c-138-\t.modalias = \"spi-ch341a\",\n--\ndrivers/spi/spi-cs42l43.c=44=static const unsigned int cs42l43_clock_divs[] = {\n--\ndrivers/spi/spi-cs42l43.c-47-\ndrivers/spi/spi-cs42l43.c:48:static struct spi_board_info amp_info_template = {\ndrivers/spi/spi-cs42l43.c-49-\t.modalias\t\t= \"cs35l56\",\n--\ndrivers/spi/spi-cs42l43.c=247=static struct fwnode_handle *cs42l43_find_xu_node(struct fwnode_handle *fwnode)\n--\ndrivers/spi/spi-cs42l43.c-273-\ndrivers/spi/spi-cs42l43.c:274:static struct spi_board_info *cs42l43_create_bridge_amp(struct cs42l43_spi *priv,\ndrivers/spi/spi-cs42l43.c-275-\t\t\t\t\t\t\tconst char * const name,\n--\ndrivers/spi/spi-cs42l43.c-279-\tstruct software_node *swnode;\ndrivers/spi/spi-cs42l43.c:280:\tstruct spi_board_info *info;\ndrivers/spi/spi-cs42l43.c-281-\n--\ndrivers/spi/spi-cs42l43.c=312=static int cs42l43_spi_probe(struct platform_device *pdev)\n--\ndrivers/spi/spi-cs42l43.c-415-\tif (nsidecars) {\ndrivers/spi/spi-cs42l43.c:416:\t\tstruct spi_board_info *ampl_info;\ndrivers/spi/spi-cs42l43.c:417:\t\tstruct spi_board_info *ampr_info;\ndrivers/spi/spi-cs42l43.c-418-\n--\ndrivers/spi/spi-intel.c=1375=static int intel_spi_populate_chip(struct intel_spi *ispi)\n--\ndrivers/spi/spi-intel.c-1378-\tstruct mtd_partition *parts;\ndrivers/spi/spi-intel.c:1379:\tstruct spi_board_info chip;\ndrivers/spi/spi-intel.c-1380-\tint ret;\n--\ndrivers/spi/spi-kspi2.c=310=static int kspi2_register_devices(struct kspi2 *kspi)\ndrivers/spi/spi-kspi2.c-311-{\ndrivers/spi/spi-kspi2.c:312:\tstruct spi_board_info *info = kspi-\u003eauxdev-\u003einfo;\ndrivers/spi/spi-kspi2.c-313-\tint i;\n--\ndrivers/spi/spi-lm70llp.c=70=struct spi_lm70llp {\n--\ndrivers/spi/spi-lm70llp.c-74-\tstruct spi_device\t*spidev_lm70;\ndrivers/spi/spi-lm70llp.c:75:\tstruct spi_board_info\tinfo;\ndrivers/spi/spi-lm70llp.c-76-\t//struct device\t\t*dev;\n--\ndrivers/spi/spi-pl022.c=1590=static int pl022_setup(struct spi_device *spi)\n--\ndrivers/spi/spi-pl022.c-1641-\t\t\tchip_info = \u0026pl022_default_chip_info;\ndrivers/spi/spi-pl022.c:1642:\t\t\t/* spi_board_info.controller_data not is supplied */\ndrivers/spi/spi-pl022.c-1643-\t\t\tdev_dbg(\u0026spi-\u003edev,\n--\ndrivers/spi/spi.c=717=struct boardinfo {\ndrivers/spi/spi.c-718-\tstruct list_head\tlist;\ndrivers/spi/spi.c:719:\tstruct spi_board_info\tboard_info;\ndrivers/spi/spi.c-720-};\n--\ndrivers/spi/spi.c=979=EXPORT_SYMBOL_GPL(spi_add_device);\n--\ndrivers/spi/spi.c-988- * after board init creates the hard-wired devices.  Some development\ndrivers/spi/spi.c:989: * platforms may not be able to use spi_register_board_info though, and\ndrivers/spi/spi.c-990- * this is exported so that for example a USB or parport based adapter\n--\ndrivers/spi/spi.c=995=struct spi_device *spi_new_device(struct spi_controller *ctlr,\ndrivers/spi/spi.c:996:\t\t\t\t  struct spi_board_info *chip)\ndrivers/spi/spi.c-997-{\n--\ndrivers/spi/spi.c=1081=static void spi_match_controller_to_boardinfo(struct spi_controller *ctlr,\ndrivers/spi/spi.c:1082:\t\t\t\t\t      struct spi_board_info *bi)\ndrivers/spi/spi.c-1083-{\n--\ndrivers/spi/spi.c-1095-/**\ndrivers/spi/spi.c:1096: * spi_register_board_info - register SPI devices for a given board\ndrivers/spi/spi.c-1097- * @info: array of chip descriptors\n--\ndrivers/spi/spi.c-1115- */\ndrivers/spi/spi.c:1116:int spi_register_board_info(struct spi_board_info const *info, unsigned n)\ndrivers/spi/spi.c-1117-{\n--\ndrivers/staging/greybus/spilib.c=441=static int gb_spi_setup_device(struct gb_spilib *spi, u8 cs)\n--\ndrivers/staging/greybus/spilib.c-445-\tstruct gb_spi_device_config_response response;\ndrivers/staging/greybus/spilib.c:446:\tstruct spi_board_info spi_board = { {0} };\ndrivers/staging/greybus/spilib.c-447-\tstruct spi_device *spidev;\n"
}

25/2 2026/09/01 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 59873
							output: 19
							thoughts: 933
						

Thoughts:
**Fuzzing Feasibility Analysis: Microchip KSZ Driver Update**

Okay, let's break this down. First, I need to understand the scope of this patch. It looks like it's touching a significant chunk of the Microchip KSZ driver code within the DSA (Distributed Switch Architecture) framework. Specifically, it's modifying:

1.  Documentation for the KSZ devices.
2.  The `MAINTAINERS` file (always good to know).
3.  Kconfig and Makefiles related to the driver.
4.  The core KSZ8 driver code and related header files.
5.  Common KSZ functions and SPI implementation.
6.  The `include/linux/platform_data/microchip-ksz.h` header.
7.  DSA core include files.
8.  Potentially, there are now two KSZ8 drivers.
9. `net/dsa/tag_ks8995.c`

Now, the critical question: is this worth fuzzing? I need to apply the fuzzing guidelines. Let me see... the guidelines say to skip patches that primarily involve documentation, Kconfig changes, decorative logging, changes to numeric constants/macros, or unreachable code paths in virtualized environments like QEMU.

Looking at the file list, the documentation and Kconfig files are minor concerns. However, the DSA core files are important and therefore, will be relevant to consider for fuzzing.

My primary concern now is whether the `tag_ks8995.c` code is reachable in a typical QEMU setup. This looks like a DSA tag driver for handling KS8995-specific packets. The fact that it's packet handling (xmit/rcv) is a good sign for fuzzing. To reach it, a network device must be bound to `DSA_TAG_PROTO_KS8995`. Now, the tricky bit: how does this binding happen? It seems like it's either through probing a switch that returns `DSA_TAG_PROTO_KS8995` or a switch that can *change* its tag protocol to it.

The primary concern I have is whether the new code path added is reachable in a typical virtualized environment. The driver uses SPI. So, the question now is whether the switch driver, likely `ksz_spi.c` or the new KSZ8 driver, can be emulated in QEMU. Let me scan the existing DSA drivers to determine whether any support a function call that accepts `DSA_TAG_PROTO_KS8995`. If I can get that far, I believe this is definitely worth fuzzing.



26/2 2026/09/01 03:57 tool grepper
0m Args:
{
  "Expression": "change_tag_protocol"
}

Results:
{
  "Output": "Documentation/networking/dsa/dsa.rst=606=Switch configuration\n--\nDocumentation/networking/dsa/dsa.rst-615-\nDocumentation/networking/dsa/dsa.rst:616:- ``change_tag_protocol``: when the default tagging protocol has compatibility\nDocumentation/networking/dsa/dsa.rst-617-  problems with the conduit or other issues, the driver may support changing it\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=6646=static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds,\n--\ndrivers/net/dsa/mv88e6xxx/chip.c-6654-\ndrivers/net/dsa/mv88e6xxx/chip.c:6655:static int mv88e6xxx_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/mv88e6xxx/chip.c-6656-\t\t\t\t\t enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/mv88e6xxx/chip.c=7187=static const struct dsa_switch_ops mv88e6xxx_switch_ops = {\ndrivers/net/dsa/mv88e6xxx/chip.c-7188-\t.get_tag_protocol\t= mv88e6xxx_get_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c:7189:\t.change_tag_protocol\t= mv88e6xxx_change_tag_protocol,\ndrivers/net/dsa/mv88e6xxx/chip.c-7190-\t.setup\t\t\t= mv88e6xxx_setup,\n--\ndrivers/net/dsa/ocelot/felix.c=732=felix_tag_proto_setup_shared(struct dsa_switch *ds,\n--\ndrivers/net/dsa/ocelot/felix.c-753- */\ndrivers/net/dsa/ocelot/felix.c:754:static int felix_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/ocelot/felix.c-755-\t\t\t\t     enum dsa_tag_protocol proto)\n--\ndrivers/net/dsa/ocelot/felix.c=1696=static int felix_setup(struct dsa_switch *ds)\n--\ndrivers/net/dsa/ocelot/felix.c-1751-\t */\ndrivers/net/dsa/ocelot/felix.c:1752:\tfelix_change_tag_protocol(ds, felix-\u003etag_proto);\ndrivers/net/dsa/ocelot/felix.c-1753-\n--\ndrivers/net/dsa/ocelot/felix.c=2306=static const struct dsa_switch_ops felix_switch_ops = {\ndrivers/net/dsa/ocelot/felix.c-2307-\t.get_tag_protocol\t\t= felix_get_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c:2308:\t.change_tag_protocol\t\t= felix_change_tag_protocol,\ndrivers/net/dsa/ocelot/felix.c-2309-\t.connect_tag_protocol\t\t= felix_connect_tag_protocol,\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c=2891=static int rtl8365mb_cpu_config(struct realtek_priv *priv)\n--\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2919-\ndrivers/net/dsa/realtek/rtl8365mb_main.c:2920:static int rtl8365mb_change_tag_protocol(struct dsa_switch *ds,\ndrivers/net/dsa/realtek/rtl8365mb_main.c-2921-\t\t\t\t\t enum dsa_tag_protocol proto)\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--\ninclude/net/dsa.h=866=struct dsa_switch_ops {\n--\ninclude/net/dsa.h-870-\t * mandatory. Switches which can operate using multiple tagging\ninclude/net/dsa.h:871:\t * protocols should implement @change_tag_protocol and report in\ninclude/net/dsa.h-872-\t * @get_tag_protocol the tagger in current use.\n--\ninclude/net/dsa.h-876-\t\t\t\t\t\t  enum dsa_tag_protocol mprot);\ninclude/net/dsa.h:877:\tint\t(*change_tag_protocol)(struct dsa_switch *ds,\ninclude/net/dsa.h-878-\t\t\t\t       enum dsa_tag_protocol proto);\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=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/switch.c=873=static int dsa_switch_change_tag_proto(struct dsa_switch *ds,\n--\nnet/dsa/switch.c-879-\nnet/dsa/switch.c:880:\tif (!ds-\u003eops-\u003echange_tag_protocol)\nnet/dsa/switch.c-881-\t\treturn -EOPNOTSUPP;\n--\nnet/dsa/switch.c-884-\nnet/dsa/switch.c:885:\terr = ds-\u003eops-\u003echange_tag_protocol(ds, tag_ops-\u003eproto);\nnet/dsa/switch.c-886-\tif (err)\n"
}

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

Args:
null

Results:
null

Tokens:
							input: 63342
							output: 26
							thoughts: 353
						

Thoughts:
**My Assessment of the KSZ8995XA Integration**

Okay, let's dive into this. First, I need to verify how the `DSA_TAG_PROTO_KS8995` protocol is handled. I'll start by checking `rtl8365mb_change_tag_protocol` and `felix_change_tag_protocol`. Right, neither of them seem to explicitly support it. This is a bit concerning. And, this KSZ8995XA switch is specifically an external SPI-based hardware switch – it's mentioned as such in the `ksz_spi.c` and `spi-ks8995` files.

Ah, yes, the KSZ8995XA is a discrete, physical chip from Microchip. It's a 5-port 10/100 Ethernet switch that communicates via an SPI management interface.

Now, a critical question arises: can we even emulate or virtualize this setup effectively in a standard QEMU environment or within a cloud-based instance, like a GCE environment?

Here's the problem: neither standard QEMU nor GCE's x86_64 or arm64 environments seem to emulate the KSZ8995/KS8995 SPI hardware. Furthermore, there's no standard SPI bus exposed with Device Tree support in the typical x86 QEMU setup or GCE.

The next thought is whether a userspace approach is possible for SPI, similar to how we can instantiate I2C devices via `/sys/bus/i2c/devices/i2c-X/new_device`. I need to check if SPI has a similar userspace instantiation mechanism, perhaps some `/sys/` interface or something similar. Let's dig into `drivers/spi/spi.c` to look for a `new_device` function or related sysfs attributes.



28/2 2026/09/01 03:57 tool grepper
0m Args:
{
  "Expression": "new_device",
  "PathPrefix": "drivers/spi"
}

Results:
{
  "Output": "drivers/spi/spi-altera-dfl.c=124=static int dfl_spi_altera_probe(struct dfl_device *dfl_dev)\n--\ndrivers/spi/spi-altera-dfl.c-174-\ndrivers/spi/spi-altera-dfl.c:175:\tif (!spi_new_device(host, \u0026board_info)) {\ndrivers/spi/spi-altera-dfl.c-176-\t\tdev_err(dev, \"%s failed to create SPI device: %s\\n\",\n--\ndrivers/spi/spi-altera-platform.c=35=static int altera_spi_probe(struct platform_device *pdev)\n--\ndrivers/spi/spi-altera-platform.c-116-\t\tfor (i = 0; i \u003c pdata-\u003enum_devices; i++) {\ndrivers/spi/spi-altera-platform.c:117:\t\t\tif (!spi_new_device(host, pdata-\u003edevices + i))\ndrivers/spi/spi-altera-platform.c-118-\t\t\t\tdev_warn(\u0026pdev-\u003edev,\n--\ndrivers/spi/spi-butterfly.c=176=static void butterfly_attach(struct parport *p)\n--\ndrivers/spi/spi-butterfly.c-265-\tpp-\u003einfo[0].controller_data = pp;\ndrivers/spi/spi-butterfly.c:266:\tpp-\u003edataflash = spi_new_device(pp-\u003ebitbang.ctlr, \u0026pp-\u003einfo[0]);\ndrivers/spi/spi-butterfly.c-267-\tif (pp-\u003edataflash)\n--\ndrivers/spi/spi-ch341.c=141=static int ch341_probe(struct usb_interface *intf,\n--\ndrivers/spi/spi-ch341.c-206-\ndrivers/spi/spi-ch341.c:207:\tch341-\u003espidev = spi_new_device(ctrl, \u0026chip);\ndrivers/spi/spi-ch341.c-208-\tif (!ch341-\u003espidev) {\n--\ndrivers/spi/spi-cs42l43.c=312=static int cs42l43_spi_probe(struct platform_device *pdev)\n--\ndrivers/spi/spi-cs42l43.c-426-\ndrivers/spi/spi-cs42l43.c:427:\t\tif (!spi_new_device(priv-\u003ectlr, ampl_info))\ndrivers/spi/spi-cs42l43.c-428-\t\t\treturn dev_err_probe(priv-\u003edev, -ENODEV,\n--\ndrivers/spi/spi-cs42l43.c-430-\ndrivers/spi/spi-cs42l43.c:431:\t\tif (!spi_new_device(priv-\u003ectlr, ampr_info))\ndrivers/spi/spi-cs42l43.c-432-\t\t\treturn dev_err_probe(priv-\u003edev, -ENODEV,\n--\ndrivers/spi/spi-intel.c=1375=static int intel_spi_populate_chip(struct intel_spi *ispi)\n--\ndrivers/spi/spi-intel.c-1401-\ndrivers/spi/spi-intel.c:1402:\tif (!spi_new_device(ispi-\u003ehost, \u0026chip))\ndrivers/spi/spi-intel.c-1403-\t\treturn -ENODEV;\n--\ndrivers/spi/spi-intel.c-1430-\ndrivers/spi/spi-intel.c:1431:\tif (!spi_new_device(ispi-\u003ehost, \u0026chip))\ndrivers/spi/spi-intel.c-1432-\t\treturn -ENODEV;\n--\ndrivers/spi/spi-kspi2.c=310=static int kspi2_register_devices(struct kspi2 *kspi)\n--\ndrivers/spi/spi-kspi2.c-316-\tfor (i = 0; i \u003c kspi-\u003eauxdev-\u003einfo_size; i++) {\ndrivers/spi/spi-kspi2.c:317:\t\tstruct spi_device *device = spi_new_device(kspi-\u003ehost, \u0026info[i]);\ndrivers/spi/spi-kspi2.c-318-\n--\ndrivers/spi/spi-lm70llp.c=188=static void spi_lm70llp_attach(struct parport *p)\n--\ndrivers/spi/spi-lm70llp.c-266-\tpp-\u003einfo.controller_data = pp;\ndrivers/spi/spi-lm70llp.c:267:\tpp-\u003espidev_lm70 = spi_new_device(pp-\u003ebitbang.ctlr, \u0026pp-\u003einfo);\ndrivers/spi/spi-lm70llp.c-268-\tif (pp-\u003espidev_lm70)\n--\ndrivers/spi/spi-lm70llp.c-271-\telse {\ndrivers/spi/spi-lm70llp.c:272:\t\tdev_warn(\u0026pd-\u003edev, \"spi_new_device failed\\n\");\ndrivers/spi/spi-lm70llp.c-273-\t\tstatus = -ENODEV;\n--\ndrivers/spi/spi-xilinx.c=402=static int xilinx_spi_probe(struct platform_device *pdev)\n--\ndrivers/spi/spi-xilinx.c-509-\t\tfor (i = 0; i \u003c pdata-\u003enum_devices; i++)\ndrivers/spi/spi-xilinx.c:510:\t\t\tspi_new_device(host, pdata-\u003edevices + i);\ndrivers/spi/spi-xilinx.c-511-\t}\n--\ndrivers/spi/spi.c=297=static const struct attribute_group spi_controller_statistics_group = {\n--\ndrivers/spi/spi.c-304-/*\ndrivers/spi/spi.c:305: * new_device_store - instantiate a new SPI device from userspace\ndrivers/spi/spi.c-306- *\n--\ndrivers/spi/spi.c-309- * Examples:\ndrivers/spi/spi.c:310: *   echo spidev 0 \u003e new_device\ndrivers/spi/spi.c:311: *   echo spidev 0 10000000 \u003e new_device\ndrivers/spi/spi.c:312: *   echo spidev 0 10000000 3 \u003e new_device\ndrivers/spi/spi.c-313- */\ndrivers/spi/spi.c=314=static ssize_t\ndrivers/spi/spi.c:315:new_device_store(struct device *dev, struct device_attribute *attr,\ndrivers/spi/spi.c-316-\t\t const char *buf, size_t count)\n--\ndrivers/spi/spi.c-329-\tif (!blank) {\ndrivers/spi/spi.c:330:\t\tdev_err(dev, \"new_device: Missing parameters\\n\");\ndrivers/spi/spi.c-331-\t\treturn -EINVAL;\n--\ndrivers/spi/spi.c-334-\tif (blank == buf || blank - buf \u003e SPI_NAME_SIZE - 1) {\ndrivers/spi/spi.c:335:\t\tdev_err(dev, \"new_device: Invalid device name\\n\");\ndrivers/spi/spi.c-336-\t\treturn -EINVAL;\n--\ndrivers/spi/spi.c-348-\tif (sscanf(++blank, \"%u %u %u\", \u0026chip_select, \u0026max_speed_hz, \u0026mode) \u003c 1) {\ndrivers/spi/spi.c:349:\t\tdev_err(dev, \"new_device: Can't parse chip select\\n\");\ndrivers/spi/spi.c-350-\t\treturn -EINVAL;\n--\ndrivers/spi/spi.c-359-\tif (chip_select \u003e U8_MAX || chip_select \u003e= ctlr-\u003enum_chipselect) {\ndrivers/spi/spi.c:360:\t\tdev_err(dev, \"new_device: Chip select %u out of range (num_chipselect=%u)\\n\",\ndrivers/spi/spi.c-361-\t\t\tchip_select, ctlr-\u003enum_chipselect);\n--\ndrivers/spi/spi.c-372-\tif (mode \u0026 ~(u32)SPI_MODE_USER_MASK) {\ndrivers/spi/spi.c:373:\t\tdev_err(dev, \"new_device: Invalid mode bits 0x%x\\n\",\ndrivers/spi/spi.c-374-\t\t\tmode \u0026 ~(u32)SPI_MODE_USER_MASK);\n--\ndrivers/spi/spi.c-401-\t/*\ndrivers/spi/spi.c:402:\t * spi_unregister_controller() removes the new_device/delete_device\ndrivers/spi/spi.c-403-\t * sysfs group before taking add_lock, so kernfs_drain() has already\n--\ndrivers/spi/spi.c-421-\ndrivers/spi/spi.c:422:\tdev_info(dev, \"new_device: Instantiated device %s at CS%u\\n\",\ndrivers/spi/spi.c-423-\t\t modalias, chip_select);\n--\ndrivers/spi/spi.c-425-}\ndrivers/spi/spi.c:426:static DEVICE_ATTR_IGNORE_LOCKDEP(new_device, 0200, NULL, new_device_store);\ndrivers/spi/spi.c-427-\n--\ndrivers/spi/spi.c=471=static struct attribute *spi_controller_userspace_attrs[] = {\ndrivers/spi/spi.c:472:\t\u0026dev_attr_new_device.attr,\ndrivers/spi/spi.c-473-\t\u0026dev_attr_delete_device.attr,\n--\ndrivers/spi/spi.c=477=static const struct attribute_group spi_controller_userspace_group = {\n--\ndrivers/spi/spi.c-484- * spi_controller_userspace_group is registered manually for host controllers\ndrivers/spi/spi.c:485: * at the end of spi_register_controller() so new_device/delete_device only\ndrivers/spi/spi.c-486- * appear after DT/ACPI children and the queue are set up.\n--\ndrivers/spi/spi.c=979=EXPORT_SYMBOL_GPL(spi_add_device);\n--\ndrivers/spi/spi.c-981-/**\ndrivers/spi/spi.c:982: * spi_new_device - instantiate one new SPI device\ndrivers/spi/spi.c-983- * @ctlr: Controller to which device is connected\n--\ndrivers/spi/spi.c-994- */\ndrivers/spi/spi.c:995:struct spi_device *spi_new_device(struct spi_controller *ctlr,\ndrivers/spi/spi.c-996-\t\t\t\t  struct spi_board_info *chip)\n--\ndrivers/spi/spi.c-1050-}\ndrivers/spi/spi.c:1051:EXPORT_SYMBOL_GPL(spi_new_device);\ndrivers/spi/spi.c-1052-\n--\ndrivers/spi/spi.c=1081=static void spi_match_controller_to_boardinfo(struct spi_controller *ctlr,\n--\ndrivers/spi/spi.c-1088-\ndrivers/spi/spi.c:1089:\tdev = spi_new_device(ctlr, bi);\ndrivers/spi/spi.c-1090-\tif (!dev)\n--\ndrivers/spi/spi.c=3652=int spi_register_controller(struct spi_controller *ctlr)\n--\ndrivers/spi/spi.c-3757-\t/*\ndrivers/spi/spi.c:3758:\t * Register the new_device/delete_device sysfs interface as the\ndrivers/spi/spi.c-3759-\t * final step of host controller bringup, only after the queue,\n--\ndrivers/spi/spi.c=3838=void spi_unregister_controller(struct spi_controller *ctlr)\n--\ndrivers/spi/spi.c-3843-\t/*\ndrivers/spi/spi.c:3844:\t * Drain in-flight new_device/delete_device sysfs stores and\ndrivers/spi/spi.c-3845-\t * prevent new ones from starting.  Must happen before we take\n"
}

29/2 2026/09/01 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 67309
							output: 43
							thoughts: 105
						

Thoughts:
**My Initial Thoughts on SPI Controller Device Instantiation**

Okay, so I'm seeing that, yes, the SPI controllers do have `new_device` show up in sysfs, which is expected. But the question is: If we're creating this SPI device with `new_device`, what *actually* happens during the probe routine? What's the dance it does?

I need to dive into the code. Specifically, I'm thinking about `ksz_spi_probe` in `drivers/net/dsa/microchip/ksz_spi.c`. I should also check out how `ksz_switch_register` in `ksz_common.c` fits into all this. Let me start by getting a handle on `drivers/net/dsa/microchip/ksz_spi.c` and see how this all shakes out.



30/2 2026/09/01 03:57 tool read-file
0m Args:
{
  "File": "drivers/net/dsa/microchip/ksz_spi.c",
  "FirstLine": 140,
  "LineCount": 70
}

Results:
{
  "Contents": " 140:\t\tconst struct ksz_chip_data *chip;\n 141:\t\tstruct device *ddev = \u0026spi-\u003edev;\n 142:\t\tstruct regmap_config rc;\n 143:\t\tstruct ksz_device *dev;\n 144:\t\tint i, ret = 0;\n 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"
}

31/2 2026/09/01 03:57 llm patch-evaluator
0m Model:
gemini-3.7-flash

Args:
null

Results:
null

Tokens:
							input: 68794
							output: 142
							thoughts: 2017
						

Thoughts:
**Analysis of the KSZ8995XA Ethernet Switch Driver Patch for Fuzzing Eligibility**

Okay, let's break this down. My initial thought is to examine `chip = device_get_match_data(ddev);`. If we're dealing with a `new_device_store` instantiation, `device_get_match_data` is going to return NULL. It uses OF/ACPI match tables or software_node, not `spi_device_id`. So, `ksz_spi_probe` immediately returns `-EINVAL`. Even if that weren't the case, `ksz_switch_register` relies on SPI communication to detect the hardware. It's reading registers like `REG_SW_ID_0`. If there's no physical switch on the SPI bus, the read fails or returns junk data, resulting in `-ENODEV` from `ksz_switch_detect`. And remember, a DSA switch needs a DSA device tree binding to register with DSA and create net devices.

Now, what about the DSA tag driver itself, `tag_ks8995.c`? It uses `module_dsa_tag_driver(ks8995_netdev_ops);`. `ks8995_netdev_ops` has `.proto = DSA_TAG_PROTO_KS8995`, and `.xmit = ks8995_xmit`, `.rcv = ks8995_rcv`. The critical question is whether `ks8995_xmit` or `ks8995_rcv` can even *be* executed if the switch driver isn't registered/probed in QEMU. Is there another way to call `ks8995_xmit` / `ks8995_rcv` or to set the tag protocol?

I checked `dsa_loop`.  `dsa_loop` uses `DSA_TAG_PROTO_NONE`. The `dsa_loop_driver` doesn't define `.change_tag_protocol`. So, writing to `/sys/class/net/<conduit>/dsa/tagging` with `ks8995` on a `dsa_loop` conduit, `dsa_switch_change_tag_proto(ds, ...)` is called which calls the underlying `.change_tag_protocol` function. Since `dsa_loop` doesn't define that function, it returns `-EOPNOTSUPP`.

I then looked at the other switches that *do* implement `.change_tag_protocol`. None of them support `DSA_TAG_PROTO_KS8995`.  The only switch that uses `DSA_TAG_PROTO_KS8995` is the `KSZ8995XA` in `drivers/net/dsa/microchip/` (`ksz8995xa_switch_ops`). And the KSZ8995XA is an *external* physical SPI Ethernet switch requiring hardware.

Now let's review the fuzzing exclusion rules.  "Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim)." That's the key. Are there *any* software emulated KSZ8995XA or SPI DSA switches in standard QEMU or the kernel? No. QEMU does *not* emulate these switches. The DSA switch drivers (e.g., `ksz8.c`, `ksz_common.c`, `tag_ks8995.c`, `ksz_spi.c`) all require communicating with physical Ethernet switch ASICs via SPI/I2C/MDIO/MMIO. Without the physical chip responding over SPI, the driver won't probe/initialize, DSA netdevs will not be created, rendering the driver code and tagger code inaccessible in a virtualized QEMU environment.

Let's do a final check:
1.  `Documentation/devicetree/bindings/net/dsa/microchip,ksz.yaml` -> Documentation
2.  `MAINTAINERS` -> Maintainers file
3.  `drivers/net/dsa/Kconfig`, `drivers/net/dsa/Makefile` -> deleted `ks8995.c`
4.  `drivers/net/dsa/ks8995.c` -> deleted old driver file
5.  `drivers/net/dsa/microchip/Kconfig`
6.  `drivers/net/dsa/microchip/ksz8.c`, `ksz8.h`, `ksz8_reg.


32/2 2026/09/01 03:57 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch series replaces the standalone Micrel KS8995 SPI driver with support in the Microchip KSZ switch driver (drivers/net/dsa/microchip/) and adds the corresponding DSA tag driver (net/dsa/tag_ks8995.c). These drivers interface with physical Micrel/Microchip KS8995/KSZ8995XA hardware over SPI and cannot be instantiated or reached in standard virtualized fuzzing environments (like QEMU/GCE) without physical hardware.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch series replaces the standalone Micrel KS8995 SPI driver with support in the Microchip KSZ switch driver (drivers/net/dsa/microchip/) and adds the corresponding DSA tag driver (net/dsa/tag_ks8995.c). These drivers interface with physical Micrel/Microchip KS8995/KSZ8995XA hardware over SPI and cannot be instantiated or reached in standard virtualized fuzzing environments (like QEMU/GCE) without physical hardware.",
  "WorthFuzzing": false
}

33/1 2026/09/01 03:57 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)