| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/15 07:10 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The modified code is confined to the Texas Instruments ICSSG PRU Ethernet driver (drivers/net/ethernet/ti/icssg/), which depends on CONFIG_ARCH_K3 (an ARM64-specific SoC architecture). This driver is structurally unreachable on the target amd64 architecture and additionally requires physical TI K3 PRU-ICSSG SoC hardware and firmware that are not emulated in standard virtualized fuzzing environments.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/15 07:10 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit e5f4ff56d149701f654d0741f581455253114fea\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Tue Sep 15 07:10:21 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile\nindex f4276c9a77620..d19bcd25c9d07 100644\n--- a/drivers/net/ethernet/ti/Makefile\n+++ b/drivers/net/ethernet/ti/Makefile\n@@ -46,6 +46,7 @@ icssg-y := icssg/icssg_common.o \\\n \t icssg/icssg_config.o \\\n \t icssg/icssg_mii_cfg.o \\\n \t icssg/icssg_stats.o \\\n-\t icssg/icssg_ethtool.o\n+\t icssg/icssg_ethtool.o \\\n+\t icssg/icssg_qos.o\n \n obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c\nindex 4a7d1a6f470b1..d59eef61e7012 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_common.c\n+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c\n@@ -1754,6 +1754,7 @@ void prueth_netdev_exit(struct prueth *prueth,\n \n \tnetif_napi_del(\u0026emac-\u003enapi_rx);\n \n+\tmutex_destroy(\u0026emac-\u003eqos.iet.fpe_lock);\n \tpruss_release_mem_region(prueth-\u003epruss, \u0026emac-\u003edram);\n \tfree_netdev(emac-\u003endev);\n \tprueth-\u003eemac[mac] = NULL;\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h\nindex 60d69744ffae2..1ac202f855ed4 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_config.h\n+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h\n@@ -323,13 +323,4 @@ struct prueth_fdb_slot {\n \tu8 fid;\n \tu8 fid_c2;\n } __packed;\n-\n-enum icssg_ietfpe_verify_states {\n-\tICSSG_IETFPE_STATE_UNKNOWN = 0,\n-\tICSSG_IETFPE_STATE_INITIAL,\n-\tICSSG_IETFPE_STATE_VERIFYING,\n-\tICSSG_IETFPE_STATE_SUCCEEDED,\n-\tICSSG_IETFPE_STATE_FAILED,\n-\tICSSG_IETFPE_STATE_DISABLED\n-};\n #endif /* __NET_TI_ICSSG_CONFIG_H */\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c\nindex b715af21d23ac..dc25361afe989 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c\n+++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c\n@@ -74,7 +74,8 @@ static int emac_get_sset_count(struct net_device *ndev, int stringset)\n \t\tif (emac-\u003eprueth-\u003epa_stats)\n \t\t\treturn ICSSG_NUM_ETHTOOL_STATS;\n \t\telse\n-\t\t\treturn ICSSG_NUM_ETHTOOL_STATS - ICSSG_NUM_PA_STATS;\n+\t\t\treturn ICSSG_NUM_ETHTOOL_STATS -\n+\t\t\t (ICSSG_NUM_PA_STATS - ICSSG_NUM_PA_STANDARD_STATS);\n \tdefault:\n \t\treturn -EOPNOTSUPP;\n \t}\n@@ -93,7 +94,8 @@ static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)\n \t\t\t\tethtool_puts(\u0026p, icssg_all_miig_stats[i].name);\n \t\tif (emac-\u003eprueth-\u003epa_stats)\n \t\t\tfor (i = 0; i \u003c ARRAY_SIZE(icssg_all_pa_stats); i++)\n-\t\t\t\tethtool_puts(\u0026p, icssg_all_pa_stats[i].name);\n+\t\t\t\tif (!icssg_all_pa_stats[i].standard_stats)\n+\t\t\t\t\tethtool_puts(\u0026p, icssg_all_pa_stats[i].name);\n \t\tbreak;\n \tdefault:\n \t\tbreak;\n@@ -114,7 +116,8 @@ static void emac_get_ethtool_stats(struct net_device *ndev,\n \n \tif (emac-\u003eprueth-\u003epa_stats)\n \t\tfor (i = 0; i \u003c ARRAY_SIZE(icssg_all_pa_stats); i++)\n-\t\t\t*(data++) = emac-\u003epa_stats[i];\n+\t\t\tif (!icssg_all_pa_stats[i].standard_stats)\n+\t\t\t\t*(data++) = emac-\u003epa_stats[i];\n }\n \n static int emac_get_ts_info(struct net_device *ndev,\n@@ -294,6 +297,126 @@ static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue,\n \treturn 0;\n }\n \n+static int emac_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tenum icssg_ietfpe_verify_states verify_status;\n+\n+\tif (emac-\u003eis_sr1)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tmutex_lock(\u0026iet-\u003efpe_lock);\n+\tstate-\u003etx_enabled = iet-\u003efpe_enabled;\n+\tstate-\u003etx_min_frag_size = iet-\u003etx_min_frag_size;\n+\tstate-\u003everify_enabled = iet-\u003emac_verify_configure;\n+\tstate-\u003everify_time = iet-\u003everify_time_ms;\n+\tstate-\u003etx_active = iet-\u003efpe_active;\n+\tverify_status = iet-\u003everify_status;\n+\tmutex_unlock(\u0026iet-\u003efpe_lock);\n+\n+\tstate-\u003erx_min_frag_size = ETH_ZLEN;\n+\tstate-\u003epmac_enabled = true;\n+\n+\tswitch (verify_status) {\n+\tcase ICSSG_IETFPE_STATE_DISABLED:\n+\t\tstate-\u003everify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;\n+\t\tbreak;\n+\tcase ICSSG_IETFPE_STATE_INITIAL:\n+\t\tstate-\u003everify_status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;\n+\t\tbreak;\n+\tcase ICSSG_IETFPE_STATE_VERIFYING:\n+\t\tstate-\u003everify_status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;\n+\t\tbreak;\n+\tcase ICSSG_IETFPE_STATE_SUCCEEDED:\n+\t\tstate-\u003everify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;\n+\t\tbreak;\n+\tcase ICSSG_IETFPE_STATE_FAILED:\n+\t\tstate-\u003everify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;\n+\t\tbreak;\n+\tdefault:\n+\t\tstate-\u003everify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;\n+\t\tbreak;\n+\t}\n+\n+\t/* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime\n+\t * variable has a range between 1 and 128 ms inclusive. Limit to that.\n+\t */\n+\tstate-\u003emax_verify_time = ETHTOOL_MM_MAX_VERIFY_TIME_MS;\n+\n+\treturn 0;\n+}\n+\n+static int emac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,\n+\t\t struct netlink_ext_ack *extack)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tu32 old_verify_time_ms, old_tx_min_frag_size;\n+\tbool old_fpe_enabled, old_mac_verify_configure;\n+\tint err;\n+\n+\tif (emac-\u003eis_sr1)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tif (!cfg-\u003epmac_enabled) {\n+\t\tNL_SET_ERR_MSG_MOD(extack, \"preemptible MAC is always enabled\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tmutex_lock(\u0026iet-\u003efpe_lock);\n+\told_verify_time_ms = iet-\u003everify_time_ms;\n+\told_tx_min_frag_size = iet-\u003etx_min_frag_size;\n+\told_fpe_enabled = iet-\u003efpe_enabled;\n+\told_mac_verify_configure = iet-\u003emac_verify_configure;\n+\n+\tiet-\u003everify_time_ms = cfg-\u003everify_time;\n+\tiet-\u003etx_min_frag_size = cfg-\u003etx_min_frag_size;\n+\tiet-\u003efpe_enabled = cfg-\u003etx_enabled;\n+\tiet-\u003emac_verify_configure = cfg-\u003everify_enabled;\n+\terr = icssg_config_ietfpe(ndev, cfg-\u003etx_enabled);\n+\tif (err) {\n+\t\t/* icssg_config_ietfpe's fallback path already cleared fpe_active.\n+\t\t * Restore all config fields so get_mm() reports the configuration\n+\t\t * that is actually reflected in hardware.\n+\t\t */\n+\t\tiet-\u003everify_time_ms = old_verify_time_ms;\n+\t\tiet-\u003etx_min_frag_size = old_tx_min_frag_size;\n+\t\tiet-\u003efpe_enabled = old_fpe_enabled;\n+\t\tiet-\u003emac_verify_configure = old_mac_verify_configure;\n+\t}\n+\tmutex_unlock(\u0026iet-\u003efpe_lock);\n+\n+\treturn err;\n+}\n+\n+static void emac_get_mm_stats(struct net_device *ndev,\n+\t\t\t struct ethtool_mm_stats *s)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\n+\tif (emac-\u003eis_sr1)\n+\t\treturn;\n+\n+\tif (!emac-\u003eprueth-\u003epa_stats)\n+\t\treturn;\n+\n+\temac_update_hardware_stats(emac);\n+\n+\t/* Hold stats_lock to prevent icssg_stats_work_handler from updating\n+\t * pa_stats[] between reads, which could yield a torn u64 value on\n+\t * 32-bit architectures.\n+\t */\n+\tspin_lock(\u0026emac-\u003eprueth-\u003estats_lock);\n+\t/* MACMergeHoldCount stats is not tracked by the firmware */\n+\ts-\u003eMACMergeFrameAssOkCount = emac_get_stat_by_name(emac, \"FW_PREEMPT_ASSEMBLY_OK\");\n+\ts-\u003eMACMergeFrameAssErrorCount = emac_get_stat_by_name(emac, \"FW_PREEMPT_ASSEMBLY_ERR\");\n+\ts-\u003eMACMergeFragCountRx = emac_get_stat_by_name(emac, \"FW_PREEMPT_FRAG_CNT_RX\");\n+\ts-\u003eMACMergeFragCountTx = emac_get_stat_by_name(emac, \"FW_PREEMPT_FRAG_CNT_TX\");\n+\ts-\u003eMACMergeFrameSmdErrorCount = emac_get_stat_by_name(emac, \"FW_PREEMPT_BAD_FRAG\");\n+\tspin_unlock(\u0026emac-\u003eprueth-\u003estats_lock);\n+}\n+\n const struct ethtool_ops icssg_ethtool_ops = {\n \t.get_drvinfo = emac_get_drvinfo,\n \t.get_msglevel = emac_get_msglevel,\n@@ -317,5 +440,8 @@ const struct ethtool_ops icssg_ethtool_ops = {\n \t.set_eee = emac_set_eee,\n \t.nway_reset = emac_nway_reset,\n \t.get_rmon_stats = emac_get_rmon_stats,\n+\t.get_mm = emac_get_mm,\n+\t.set_mm = emac_set_mm,\n+\t.get_mm_stats = emac_get_mm_stats,\n };\n EXPORT_SYMBOL_GPL(icssg_ethtool_ops);\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c\nindex 591be5c8056b4..283be27a240e9 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c\n+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c\n@@ -357,11 +357,11 @@ static void emac_adjust_link(struct net_device *ndev)\n \t\t}\n \t\tif (!emac-\u003elink) {\n \t\t\tnew_state = true;\n-\t\t\temac-\u003elink = 1;\n+\t\t\tWRITE_ONCE(emac-\u003elink, 1);\n \t\t}\n \t} else if (emac-\u003elink) {\n \t\tnew_state = true;\n-\t\temac-\u003elink = 0;\n+\t\tWRITE_ONCE(emac-\u003elink, 0);\n \n \t\t/* f/w should support 100 \u0026 1000 */\n \t\temac-\u003espeed = SPEED_1000;\n@@ -392,6 +392,8 @@ static void emac_adjust_link(struct net_device *ndev)\n \t\t} else {\n \t\t\ticssg_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);\n \t\t}\n+\n+\t\ticssg_qos_link_state_update(ndev);\n \t}\n \n \tif (emac-\u003elink) {\n@@ -1652,6 +1654,7 @@ static const struct net_device_ops emac_netdev_ops = {\n \t.ndo_hwtstamp_get = icssg_ndo_get_ts_config,\n \t.ndo_hwtstamp_set = icssg_ndo_set_ts_config,\n \t.ndo_xsk_wakeup = prueth_xsk_wakeup,\n+\t.ndo_setup_tc = icssg_qos_ndo_setup_tc,\n };\n \n static int prueth_netdev_init(struct prueth *prueth,\n@@ -1686,6 +1689,8 @@ static int prueth_netdev_init(struct prueth *prueth,\n \n \tINIT_DELAYED_WORK(\u0026emac-\u003estats_work, icssg_stats_work_handler);\n \n+\ticssg_qos_init(ndev);\n+\n \tret = pruss_request_mem_region(prueth-\u003epruss,\n \t\t\t\t port == PRUETH_PORT_MII0 ?\n \t\t\t\t PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,\n@@ -1793,6 +1798,7 @@ static int prueth_netdev_init(struct prueth *prueth,\n free:\n \tpruss_release_mem_region(prueth-\u003epruss, \u0026emac-\u003edram);\n free_ndev:\n+\tmutex_destroy(\u0026emac-\u003eqos.iet.fpe_lock);\n \temac-\u003endev = NULL;\n \tprueth-\u003eemac[mac] = NULL;\n \tfree_netdev(ndev);\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h\nindex df93d15c5b786..ad9061408050e 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h\n+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h\n@@ -44,10 +44,12 @@\n #include \"icssg_config.h\"\n #include \"icss_iep.h\"\n #include \"icssg_switch_map.h\"\n+#include \"icssg_qos.h\"\n+#include \"icssg_stats.h\"\n \n-#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN)\n-#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN)\n-#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN)\n+#define PRUETH_MAX_MTU\t\t(2000 - ETH_HLEN - ETH_FCS_LEN)\n+#define PRUETH_MIN_PKT_SIZE\t(VLAN_ETH_ZLEN)\n+#define PRUETH_MAX_PKT_SIZE\t(PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN)\n \n #define ICSS_SLICE0\t0\n #define ICSS_SLICE1\t1\n@@ -57,12 +59,16 @@\n \n #define ICSSG_MAX_RFLOWS\t8\t/* per slice */\n \n-#define ICSSG_NUM_PA_STATS\t32\n-#define ICSSG_NUM_MIIG_STATS\t60\n+#define ICSSG_NUM_PA_STATS\tARRAY_SIZE(icssg_all_pa_stats)\n+#define ICSSG_NUM_MIIG_STATS\tARRAY_SIZE(icssg_all_miig_stats)\n /* Number of ICSSG related stats */\n #define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)\n+/* MIIG stats with standard uAPI equivalents (excluded from ethtool -S) */\n #define ICSSG_NUM_STANDARD_STATS 31\n-#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)\n+/* PA stats with standard uAPI equivalents, exposed via get_mm_stats only */\n+#define ICSSG_NUM_PA_STANDARD_STATS 5\n+#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS - \\\n+\t\t\t\t ICSSG_NUM_PA_STANDARD_STATS)\n \n #define IEP_DEFAULT_CYCLE_TIME_NS\t1000000\t/* 1 ms */\n \n@@ -254,6 +260,7 @@ struct prueth_emac {\n \tstruct bpf_prog *xdp_prog;\n \tstruct xdp_attachment_info xdpi;\n \tint xsk_qid;\n+\tstruct prueth_qos qos;\n };\n \n /* The buf includes headroom compatible with both skb and xdpf */\n@@ -458,7 +465,7 @@ int emac_fdb_flow_id_updated(struct prueth_emac *emac);\n \n void icssg_stats_work_handler(struct work_struct *work);\n void emac_update_hardware_stats(struct prueth_emac *emac);\n-int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);\n+u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);\n \n /* Common functions */\n void prueth_cleanup_rx_chns(struct prueth_emac *emac,\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.c b/drivers/net/ethernet/ti/icssg/icssg_qos.c\nnew file mode 100644\nindex 0000000000000..27a953d981538\n--- /dev/null\n+++ b/drivers/net/ethernet/ti/icssg/icssg_qos.c\n@@ -0,0 +1,305 @@\n+// SPDX-License-Identifier: GPL-2.0\n+/* Texas Instruments ICSSG PRUETH QoS submodule\n+ * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/\n+ */\n+\n+#include \"icssg_prueth.h\"\n+#include \"icssg_switch_map.h\"\n+\n+static void icssg_iet_set_preempt_mask(struct prueth_emac *emac)\n+{\n+\tvoid __iomem *config = emac-\u003edram.va + ICSSG_CONFIG_OFFSET;\n+\tstruct prueth_qos_mqprio *p_mqprio = \u0026emac-\u003eqos.mqprio;\n+\tstruct tc_mqprio_qopt *qopt = \u0026p_mqprio-\u003eqopt;\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tint prempt_mask = 0, i;\n+\tu8 tc, num_tc;\n+\n+\tif (!iet-\u003epreemptible_tcs)\n+\t\tgoto reset_hw;\n+\n+\tif (iet-\u003efpe_active) {\n+\t\t/* Reset all Q_MAP entries first to clear any stale preemptible\n+\t\t * entries from a prior wider TC mapping.\n+\t\t */\n+\t\tfor (i = 0; i \u003c ICSSG_MAX_TC_QUEUES; i++)\n+\t\t\twriteb(0, config + EXPRESS_PRE_EMPTIVE_Q_MAP + i);\n+\n+\t\t/* Configure queues for user requested preemptible tc map */\n+\t\tnum_tc = p_mqprio-\u003eqopt.num_tc;\n+\t\tfor (tc = 0; tc \u003c num_tc; tc++) {\n+\t\t\t/* check if the tc is preemptive or not */\n+\t\t\tif (iet-\u003epreemptible_tcs \u0026 BIT(tc)) {\n+\t\t\t\t/* Set the queues as preemptive queues */\n+\t\t\t\tfor (i = qopt-\u003eoffset[tc]; i \u003c qopt-\u003eoffset[tc] + qopt-\u003ecount[tc]; i++) {\n+\t\t\t\t\twriteb(BIT(4),\n+\t\t\t\t\t config + EXPRESS_PRE_EMPTIVE_Q_MAP + i);\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\t/* Accumulate express queue bits for the mask */\n+\t\t\t\tfor (i = qopt-\u003eoffset[tc]; i \u003c qopt-\u003eoffset[tc] + qopt-\u003ecount[tc]; i++)\n+\t\t\t\t\tprempt_mask |= BIT(i);\n+\t\t\t}\n+\t\t}\n+\t\twriteb(prempt_mask, config + EXPRESS_PRE_EMPTIVE_Q_MASK);\n+\t\treturn;\n+\t}\n+\n+reset_hw:\n+\t/* Reset to default: all queues as express */\n+\tfor (i = 0; i \u003c ICSSG_MAX_TC_QUEUES; i++)\n+\t\twriteb(0, config + EXPRESS_PRE_EMPTIVE_Q_MAP + i);\n+\twriteb(ICSSG_EXPRESS_Q_MASK_ALL, config + EXPRESS_PRE_EMPTIVE_Q_MASK);\n+}\n+\n+static int icssg_iet_verify_wait(struct prueth_emac *emac)\n+{\n+\tvoid __iomem *config = emac-\u003edram.va + ICSSG_CONFIG_OFFSET;\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tunsigned long delay_us, timeout_us;\n+\tu32 status;\n+\tint ret;\n+\n+\tdelay_us = iet-\u003everify_time_ms * 1000;\n+\ttimeout_us = delay_us * ICSSG_IET_VERIFY_ATTEMPTS;\n+\n+\tret = readb_poll_timeout(config + PRE_EMPTION_VERIFY_STATUS,\n+\t\t\t\t status,\n+\t\t\t\t status == ICSSG_IETFPE_STATE_SUCCEEDED ||\n+\t\t\t\t status == ICSSG_IETFPE_STATE_FAILED,\n+\t\t\t\t delay_us,\n+\t\t\t\t timeout_us);\n+\n+\tiet-\u003everify_status = status;\n+\tif (!ret \u0026\u0026 status == ICSSG_IETFPE_STATE_FAILED)\n+\t\treturn -EIO;\n+\treturn ret;\n+}\n+\n+/* Direct synchronous configuration of IET FPE.\n+ * Caller must hold iet-\u003efpe_lock.\n+ */\n+int icssg_config_ietfpe(struct net_device *ndev, bool enable)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\tvoid __iomem *config = emac-\u003edram.va + ICSSG_CONFIG_OFFSET;\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tint ret;\n+\tu8 val;\n+\n+\tlockdep_assert_held(\u0026iet-\u003efpe_lock);\n+\n+\tif (!READ_ONCE(emac-\u003elink)) {\n+\t\tnetdev_dbg(ndev, \"cannot change IET/FPE state when interface is down\\n\");\n+\t\treturn 0;\n+\t}\n+\n+\t/* Update FPE Tx enable bit (PRE_EMPTION_ENABLE_TX) if\n+\t * fpe_enabled is set to enable MM in Tx direction\n+\t */\n+\twriteb(enable ? 1 : 0, config + PRE_EMPTION_ENABLE_TX);\n+\twritew(iet-\u003etx_min_frag_size + ETH_FCS_LEN,\n+\t config + PRE_EMPTION_ADD_FRAG_SIZE_LOCAL);\n+\n+\t/* If FPE is to be enabled, first configure MAC Verify state\n+\t * machine in firmware as firmware kicks the Verify process\n+\t * as soon as ICSSG_EMAC_PORT_PREMPT_TX_ENABLE command is\n+\t * received.\n+\t */\n+\tif (enable \u0026\u0026 iet-\u003emac_verify_configure) {\n+\t\twriteb(1, config + PRE_EMPTION_ENABLE_VERIFY);\n+\t\twritel(iet-\u003everify_time_ms, config + PRE_EMPTION_VERIFY_TIME);\n+\t} else {\n+\t\twriteb(0, config + PRE_EMPTION_ENABLE_VERIFY);\n+\t\tiet-\u003everify_status = ICSSG_IETFPE_STATE_DISABLED;\n+\t}\n+\n+\t/* Send command to enable FPE Tx side. Rx is always enabled */\n+\tret = icssg_set_port_state(emac,\n+\t\t\t\t enable ? ICSSG_EMAC_PORT_PREMPT_TX_ENABLE :\n+\t\t\t\t\t ICSSG_EMAC_PORT_PREMPT_TX_DISABLE);\n+\tif (ret) {\n+\t\tnetdev_err(ndev, \"TX preempt %s command failed\\n\",\n+\t\t\t str_enable_disable(enable));\n+\t\tgoto fallback;\n+\t}\n+\n+\tif (enable \u0026\u0026 iet-\u003emac_verify_configure) {\n+\t\tret = icssg_iet_verify_wait(emac);\n+\t\tif (ret) {\n+\t\t\tnetdev_err(ndev, \"MAC Merge verification failed: %s\\n\",\n+\t\t\t\t iet-\u003everify_status == ICSSG_IETFPE_STATE_FAILED ?\n+\t\t\t\t \"link partner rejected\" : \"timeout\");\n+\t\t\tgoto disable_tx;\n+\t\t}\n+\t} else if (enable) {\n+\t\t/* Give firmware some time to update\n+\t\t * PRE_EMPTION_ACTIVE_TX state\n+\t\t */\n+\t\tusleep_range(100, 200);\n+\t}\n+\n+\tif (enable) {\n+\t\tval = readb(config + PRE_EMPTION_ACTIVE_TX);\n+\t\tif (val != 1) {\n+\t\t\tnetdev_err(ndev,\n+\t\t\t\t \"Firmware fails to activate IET/FPE\\n\");\n+\t\t\tret = -EIO;\n+\t\t\tgoto disable_tx;\n+\t\t}\n+\t\tiet-\u003efpe_active = true;\n+\t} else {\n+\t\tiet-\u003efpe_active = false;\n+\t}\n+\n+\ticssg_iet_set_preempt_mask(emac);\n+\tnetdev_dbg(ndev, \"IET FPE %s successfully\\n\",\n+\t\t str_enable_disable(enable));\n+\treturn 0;\n+\n+disable_tx:\n+\ticssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE);\n+fallback:\n+\twriteb(0, config + PRE_EMPTION_ENABLE_TX);\n+\twriteb(0, config + PRE_EMPTION_ENABLE_VERIFY);\n+\tiet-\u003everify_status = ICSSG_IETFPE_STATE_DISABLED;\n+\tiet-\u003efpe_active = false;\n+\ticssg_iet_set_preempt_mask(emac);\n+\treturn ret;\n+}\n+\n+void icssg_qos_init(struct net_device *ndev)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\n+\tmutex_init(\u0026iet-\u003efpe_lock);\n+\t/* Set default values to prevent garbage values during .get_mm() */\n+\tiet-\u003everify_time_ms = ICSSG_IET_MAX_VERIFY_TIME;\n+\tiet-\u003etx_min_frag_size = ETH_ZLEN;\n+}\n+EXPORT_SYMBOL_GPL(icssg_qos_init);\n+\n+static int icssg_iet_change_preemptible_tcs(struct prueth_emac *emac)\n+{\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tint ret;\n+\n+\tmutex_lock(\u0026iet-\u003efpe_lock);\n+\tif (!iet-\u003efpe_enabled \u0026\u0026 !iet-\u003epreemptible_tcs) {\n+\t\tmutex_unlock(\u0026iet-\u003efpe_lock);\n+\t\treturn 0;\n+\t}\n+\tret = icssg_config_ietfpe(emac-\u003endev, iet-\u003efpe_enabled);\n+\tmutex_unlock(\u0026iet-\u003efpe_lock);\n+\n+\treturn ret;\n+}\n+\n+static int emac_tc_query_caps(struct net_device *ndev, void *type_data)\n+{\n+\tstruct tc_query_caps_base *base = type_data;\n+\n+\tswitch (base-\u003etype) {\n+\tcase TC_SETUP_QDISC_MQPRIO: {\n+\t\tstruct tc_mqprio_caps *caps = base-\u003ecaps;\n+\n+\t\tcaps-\u003evalidate_queue_counts = true;\n+\t\treturn 0;\n+\t}\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+}\n+\n+static int emac_tc_setup_mqprio(struct net_device *ndev, void *type_data)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\tstruct prueth_qos_mqprio *p_mqprio = \u0026emac-\u003eqos.mqprio;\n+\tstruct tc_mqprio_qopt_offload *mqprio = type_data;\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tstruct tc_mqprio_qopt *qopt = \u0026mqprio-\u003eqopt;\n+\tint tc, offset, count;\n+\n+\t/* Validate parameters */\n+\tif (qopt-\u003enum_tc \u003e ICSSG_MAX_TC_QUEUES) {\n+\t\tnetdev_err(ndev, \"Number of traffic classes (%u) exceeds hardware limit\\n\",\n+\t\t\t qopt-\u003enum_tc);\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tif (mqprio-\u003eflags \u0026 TC_MQPRIO_F_SHAPER) {\n+\t\tnetdev_err(ndev, \"traffic shaping is not supported\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tif (mqprio-\u003eflags \u0026 (TC_MQPRIO_F_MIN_RATE | TC_MQPRIO_F_MAX_RATE)) {\n+\t\tnetdev_err(ndev, \"per-queue rate limiting is not supported\\n\");\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+\n+\tif (!qopt-\u003enum_tc) {\n+\t\tnetdev_reset_tc(ndev);\n+\t} else {\n+\t\tnetdev_set_num_tc(ndev, qopt-\u003enum_tc);\n+\n+\t\tfor (tc = 0; tc \u003c qopt-\u003enum_tc; tc++) {\n+\t\t\tcount = qopt-\u003ecount[tc];\n+\t\t\toffset = qopt-\u003eoffset[tc];\n+\t\t\tnetdev_set_tc_queue(ndev, tc, count, offset);\n+\t\t}\n+\t}\n+\n+\tmutex_lock(\u0026iet-\u003efpe_lock);\n+\tif (!qopt-\u003enum_tc) {\n+\t\tiet-\u003epreemptible_tcs = 0;\n+\t} else {\n+\t\tmemcpy(\u0026p_mqprio-\u003eqopt, qopt, sizeof(*qopt));\n+\t\tiet-\u003epreemptible_tcs = mqprio-\u003epreemptible_tcs;\n+\t}\n+\tmutex_unlock(\u0026iet-\u003efpe_lock);\n+\n+\tnetdev_dbg(ndev, \"dev-\u003enum_tc %u dev-\u003ereal_num_tx_queues %u\\n\",\n+\t\t ndev-\u003enum_tc, ndev-\u003ereal_num_tx_queues);\n+\n+\treturn icssg_iet_change_preemptible_tcs(emac);\n+}\n+\n+int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,\n+\t\t\t void *type_data)\n+{\n+\tswitch (type) {\n+\tcase TC_QUERY_CAPS:\n+\t\treturn emac_tc_query_caps(ndev, type_data);\n+\tcase TC_SETUP_QDISC_MQPRIO:\n+\t\treturn emac_tc_setup_mqprio(ndev, type_data);\n+\tdefault:\n+\t\treturn -EOPNOTSUPP;\n+\t}\n+}\n+EXPORT_SYMBOL_GPL(icssg_qos_ndo_setup_tc);\n+\n+void icssg_qos_link_state_update(struct net_device *ndev)\n+{\n+\tstruct prueth_emac *emac = netdev_priv(ndev);\n+\tstruct prueth_qos_iet *iet = \u0026emac-\u003eqos.iet;\n+\tint ret;\n+\n+\tif (!READ_ONCE(emac-\u003elink)) {\n+\t\t/* Clear FPE active state on link-down so get_mm() reports\n+\t\t * accurate tx_active and verify_status while link is down.\n+\t\t */\n+\t\tmutex_lock(\u0026iet-\u003efpe_lock);\n+\t\tiet-\u003efpe_active = false;\n+\t\tiet-\u003everify_status = ICSSG_IETFPE_STATE_DISABLED;\n+\t\ticssg_iet_set_preempt_mask(emac);\n+\t\tmutex_unlock(\u0026iet-\u003efpe_lock);\n+\t\treturn;\n+\t}\n+\n+\tret = icssg_iet_change_preemptible_tcs(emac);\n+\tif (ret)\n+\t\tnetdev_dbg(ndev, \"IET FPE %s failed\\n\",\n+\t\t\t str_enable_disable(iet-\u003efpe_enabled));\n+}\n+EXPORT_SYMBOL_GPL(icssg_qos_link_state_update);\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.h b/drivers/net/ethernet/ti/icssg/icssg_qos.h\nnew file mode 100644\nindex 0000000000000..e826ce4bcfd96\n--- /dev/null\n+++ b/drivers/net/ethernet/ti/icssg/icssg_qos.h\n@@ -0,0 +1,68 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+/* Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/\n+ */\n+\n+#ifndef __NET_TI_ICSSG_QOS_H\n+#define __NET_TI_ICSSG_QOS_H\n+\n+#include \u003clinux/atomic.h\u003e\n+#include \u003clinux/netdevice.h\u003e\n+#include \u003cnet/pkt_sched.h\u003e\n+\n+#define ICSSG_MAX_TC_QUEUES\t\t\t8\n+#define ICSSG_EXPRESS_Q_MASK_ALL\t\t0xFF\n+#define ICSSG_IET_MAX_VERIFY_TIME\t\t128\n+#define ICSSG_IET_MIN_VERIFY_TIME\t\t1\n+#define ICSSG_IET_VERIFY_ATTEMPTS\t\t3\n+\n+/**\n+ * enum icssg_ietfpe_verify_states - status of MM Verify returned by firmware\n+ * @ICSSG_IETFPE_STATE_UNKNOWN:\n+ *\tverification status is unknown\n+ * @ICSSG_IETFPE_STATE_INITIAL:\n+ *\tFirmware returns this if verify state diagram is idle\n+ * @ICSSG_IETFPE_STATE_VERIFYING:\n+ *\tFirmware returns this if verification is ongoing\n+ * @ICSSG_IETFPE_STATE_SUCCEEDED:\n+ *\tFirmware returns this if verify state diagram completes verification\n+ * @ICSSG_IETFPE_STATE_FAILED:\n+ *\tFirmware returns this if verify state diagram fails during verification\n+ * @ICSSG_IETFPE_STATE_DISABLED:\n+ *\tverification is disabled by the driver\n+ */\n+enum icssg_ietfpe_verify_states {\n+\tICSSG_IETFPE_STATE_UNKNOWN = 0,\n+\tICSSG_IETFPE_STATE_INITIAL,\n+\tICSSG_IETFPE_STATE_VERIFYING,\n+\tICSSG_IETFPE_STATE_SUCCEEDED,\n+\tICSSG_IETFPE_STATE_FAILED,\n+\tICSSG_IETFPE_STATE_DISABLED\n+};\n+\n+struct prueth_qos_mqprio {\n+\tstruct tc_mqprio_qopt qopt;\n+};\n+\n+struct prueth_qos_iet {\n+\tbool fpe_enabled;\n+\tbool mac_verify_configure;\n+\tu32 tx_min_frag_size;\n+\tu32 verify_time_ms;\n+\tbool fpe_active;\n+\tenum icssg_ietfpe_verify_states verify_status;\n+\t/* fpe mutex protects all FPE operations for synchronization */\n+\tstruct mutex fpe_lock;\n+\tu8 preemptible_tcs;\n+};\n+\n+struct prueth_qos {\n+\tstruct prueth_qos_iet iet;\n+\tstruct prueth_qos_mqprio mqprio;\n+};\n+\n+void icssg_qos_init(struct net_device *ndev);\n+void icssg_qos_link_state_update(struct net_device *ndev);\n+int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,\n+\t\t\t void *type_data);\n+int icssg_config_ietfpe(struct net_device *ndev, bool enable);\n+#endif /* __NET_TI_ICSSG_QOS_H */\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c\nindex 7159baa0155cf..cfdb6f5dc5da1 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c\n+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c\n@@ -74,7 +74,7 @@ void icssg_stats_work_handler(struct work_struct *work)\n }\n EXPORT_SYMBOL_GPL(icssg_stats_work_handler);\n \n-int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)\n+u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)\n {\n \tint i;\n \n@@ -91,5 +91,5 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)\n \t}\n \n \tnetdev_err(emac-\u003endev, \"Invalid stats %s\\n\", stat_name);\n-\treturn -EINVAL;\n+\treturn 0;\n }\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h\nindex 5ec0b38e0c67d..b86da8da23a18 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h\n+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h\n@@ -8,8 +8,6 @@\n #ifndef __NET_TI_ICSSG_STATS_H\n #define __NET_TI_ICSSG_STATS_H\n \n-#include \"icssg_prueth.h\"\n-\n #define STATS_TIME_LIMIT_1G_MS 25000 /* 25 seconds @ 1G */\n \n struct miig_stats_regs {\n@@ -155,50 +153,60 @@ static const struct icssg_miig_stats icssg_all_miig_stats[] = {\n \tICSSG_MIIG_STATS(tx_bytes, true),\n };\n \n-#define ICSSG_PA_STATS(field)\t\\\n-{\t\t\t\t\\\n-\t#field,\t\t\t\\\n-\tfield,\t\t\t\\\n+#define ICSSG_PA_STATS(field, std)\t\\\n+{\t\t\t\t\t\\\n+\t#field,\t\t\t\t\\\n+\tfield,\t\t\t\t\\\n+\tstd,\t\t\t\t\\\n }\n \n struct icssg_pa_stats {\n \tchar name[ETH_GSTRING_LEN];\n \tu32 offset;\n+\tbool standard_stats;\n };\n \n static const struct icssg_pa_stats icssg_all_pa_stats[] = {\n-\tICSSG_PA_STATS(FW_RTU_PKT_DROP),\n-\tICSSG_PA_STATS(FW_Q0_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q1_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q2_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q3_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q4_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q5_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q6_OVERFLOW),\n-\tICSSG_PA_STATS(FW_Q7_OVERFLOW),\n-\tICSSG_PA_STATS(FW_DROPPED_PKT),\n-\tICSSG_PA_STATS(FW_RX_ERROR),\n-\tICSSG_PA_STATS(FW_RX_DS_INVALID),\n-\tICSSG_PA_STATS(FW_TX_DROPPED_PACKET),\n-\tICSSG_PA_STATS(FW_TX_TS_DROPPED_PACKET),\n-\tICSSG_PA_STATS(FW_INF_PORT_DISABLED),\n-\tICSSG_PA_STATS(FW_INF_SAV),\n-\tICSSG_PA_STATS(FW_INF_SA_DL),\n-\tICSSG_PA_STATS(FW_INF_PORT_BLOCKED),\n-\tICSSG_PA_STATS(FW_INF_DROP_TAGGED),\n-\tICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED),\n-\tICSSG_PA_STATS(FW_INF_DROP_NOTAG),\n-\tICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER),\n-\tICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR),\n-\tICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF),\n-\tICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF),\n-\tICSSG_PA_STATS(FW_RX_EXP_FRAG_Q_DROP),\n-\tICSSG_PA_STATS(FW_RX_FIFO_OVERRUN),\n-\tICSSG_PA_STATS(FW_CUT_THR_PKT),\n-\tICSSG_PA_STATS(FW_HOST_RX_PKT_CNT),\n-\tICSSG_PA_STATS(FW_HOST_TX_PKT_CNT),\n-\tICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW),\n-\tICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW),\n+\tICSSG_PA_STATS(FW_RTU_PKT_DROP, false),\n+\tICSSG_PA_STATS(FW_Q0_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q1_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q2_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q3_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q4_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q5_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q6_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_Q7_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_DROPPED_PKT, false),\n+\tICSSG_PA_STATS(FW_RX_ERROR, false),\n+\tICSSG_PA_STATS(FW_RX_DS_INVALID, false),\n+\tICSSG_PA_STATS(FW_TX_DROPPED_PACKET, false),\n+\tICSSG_PA_STATS(FW_TX_TS_DROPPED_PACKET, false),\n+\tICSSG_PA_STATS(FW_INF_PORT_DISABLED, false),\n+\tICSSG_PA_STATS(FW_INF_SAV, false),\n+\tICSSG_PA_STATS(FW_INF_SA_DL, false),\n+\tICSSG_PA_STATS(FW_INF_PORT_BLOCKED, false),\n+\tICSSG_PA_STATS(FW_INF_DROP_TAGGED, false),\n+\tICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED, false),\n+\tICSSG_PA_STATS(FW_INF_DROP_NOTAG, false),\n+\tICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER, false),\n+\t/* MAC Merge counters: exposed via .get_mm_stats standard uAPI,\n+\t * not duplicated in the private ethtool -S table.\n+\t */\n+\tICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG, true),\n+\tICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR, true),\n+\tICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX, true),\n+\tICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK, true),\n+\tICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX, true),\n+\tICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR, false),\n+\tICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF, false),\n+\tICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF, false),\n+\tICSSG_PA_STATS(FW_RX_EXP_FRAG_Q_DROP, false),\n+\tICSSG_PA_STATS(FW_RX_FIFO_OVERRUN, false),\n+\tICSSG_PA_STATS(FW_CUT_THR_PKT, false),\n+\tICSSG_PA_STATS(FW_HOST_RX_PKT_CNT, false),\n+\tICSSG_PA_STATS(FW_HOST_TX_PKT_CNT, false),\n+\tICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW, false),\n+\tICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW, false),\n };\n \n #endif /* __NET_TI_ICSSG_STATS_H */\ndiff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h\nindex 7e053b8af3ece..855fd4ed0b3f6 100644\n--- a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h\n+++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h\n@@ -256,6 +256,11 @@\n #define FW_INF_DROP_PRIOTAGGED\t\t0x0148\n #define FW_INF_DROP_NOTAG\t\t0x0150\n #define FW_INF_DROP_NOTMEMBER\t\t0x0158\n+#define FW_PREEMPT_BAD_FRAG\t\t0x0160\n+#define FW_PREEMPT_ASSEMBLY_ERR\t\t0x0168\n+#define FW_PREEMPT_FRAG_CNT_TX\t\t0x0170\n+#define FW_PREEMPT_ASSEMBLY_OK\t\t0x0178\n+#define FW_PREEMPT_FRAG_CNT_RX\t\t0x0180\n #define FW_RX_EOF_SHORT_FRMERR\t\t0x0188\n #define FW_RX_B0_DROP_EARLY_EOF\t\t0x0190\n #define FW_TX_JUMBO_FRM_CUTOFF\t\t0x0198\n"
} |
| 2/1 | 2026/09/15 07:10 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The modified code is confined to the Texas Instruments ICSSG PRU Ethernet driver (drivers/net/ethernet/ti/icssg/), which depends on CONFIG_ARCH_K3 (an ARM64-specific SoC architecture). This driver is structurally unreachable on the target amd64 architecture and additionally requires physical TI K3 PRU-ICSSG SoC hardware and firmware that are not emulated in standard virtualized fuzzing environments.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit e5f4ff56d149701f654d0741f581455253114fea
Author: syz-cluster <triage@syzkaller.com>
Date: Tue Sep 15 07:10:21 2026 +0000
syz-cluster: applied patch under review
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index f4276c9a77620..d19bcd25c9d07 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -46,6 +46,7 @@ icssg-y := icssg/icssg_common.o \
icssg/icssg_config.o \
icssg/icssg_mii_cfg.o \
icssg/icssg_stats.o \
- icssg/icssg_ethtool.o
+ icssg/icssg_ethtool.o \
+ icssg/icssg_qos.o
obj-$(CONFIG_TI_ICSS_IEP) += icssg/icss_iep.o
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index 4a7d1a6f470b1..d59eef61e7012 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -1754,6 +1754,7 @@ void prueth_netdev_exit(struct prueth *prueth,
netif_napi_del(&emac->napi_rx);
+ mutex_destroy(&emac->qos.iet.fpe_lock);
pruss_release_mem_region(prueth->pruss, &emac->dram);
free_netdev(emac->ndev);
prueth->emac[mac] = NULL;
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h
index 60d69744ffae2..1ac202f855ed4 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_config.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_config.h
@@ -323,13 +323,4 @@ struct prueth_fdb_slot {
u8 fid;
u8 fid_c2;
} __packed;
-
-enum icssg_ietfpe_verify_states {
- ICSSG_IETFPE_STATE_UNKNOWN = 0,
- ICSSG_IETFPE_STATE_INITIAL,
- ICSSG_IETFPE_STATE_VERIFYING,
- ICSSG_IETFPE_STATE_SUCCEEDED,
- ICSSG_IETFPE_STATE_FAILED,
- ICSSG_IETFPE_STATE_DISABLED
-};
#endif /* __NET_TI_ICSSG_CONFIG_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
index b715af21d23ac..dc25361afe989 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
@@ -74,7 +74,8 @@ static int emac_get_sset_count(struct net_device *ndev, int stringset)
if (emac->prueth->pa_stats)
return ICSSG_NUM_ETHTOOL_STATS;
else
- return ICSSG_NUM_ETHTOOL_STATS - ICSSG_NUM_PA_STATS;
+ return ICSSG_NUM_ETHTOOL_STATS -
+ (ICSSG_NUM_PA_STATS - ICSSG_NUM_PA_STANDARD_STATS);
default:
return -EOPNOTSUPP;
}
@@ -93,7 +94,8 @@ static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
ethtool_puts(&p, icssg_all_miig_stats[i].name);
if (emac->prueth->pa_stats)
for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
- ethtool_puts(&p, icssg_all_pa_stats[i].name);
+ if (!icssg_all_pa_stats[i].standard_stats)
+ ethtool_puts(&p, icssg_all_pa_stats[i].name);
break;
default:
break;
@@ -114,7 +116,8 @@ static void emac_get_ethtool_stats(struct net_device *ndev,
if (emac->prueth->pa_stats)
for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
- *(data++) = emac->pa_stats[i];
+ if (!icssg_all_pa_stats[i].standard_stats)
+ *(data++) = emac->pa_stats[i];
}
static int emac_get_ts_info(struct net_device *ndev,
@@ -294,6 +297,126 @@ static int emac_set_per_queue_coalesce(struct net_device *ndev, u32 queue,
return 0;
}
+static int emac_get_mm(struct net_device *ndev, struct ethtool_mm_state *state)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ enum icssg_ietfpe_verify_states verify_status;
+
+ if (emac->is_sr1)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&iet->fpe_lock);
+ state->tx_enabled = iet->fpe_enabled;
+ state->tx_min_frag_size = iet->tx_min_frag_size;
+ state->verify_enabled = iet->mac_verify_configure;
+ state->verify_time = iet->verify_time_ms;
+ state->tx_active = iet->fpe_active;
+ verify_status = iet->verify_status;
+ mutex_unlock(&iet->fpe_lock);
+
+ state->rx_min_frag_size = ETH_ZLEN;
+ state->pmac_enabled = true;
+
+ switch (verify_status) {
+ case ICSSG_IETFPE_STATE_DISABLED:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_DISABLED;
+ break;
+ case ICSSG_IETFPE_STATE_INITIAL:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_INITIAL;
+ break;
+ case ICSSG_IETFPE_STATE_VERIFYING:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING;
+ break;
+ case ICSSG_IETFPE_STATE_SUCCEEDED:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED;
+ break;
+ case ICSSG_IETFPE_STATE_FAILED:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_FAILED;
+ break;
+ default:
+ state->verify_status = ETHTOOL_MM_VERIFY_STATUS_UNKNOWN;
+ break;
+ }
+
+ /* 802.3-2018 clause 30.14.1.6, says that the aMACMergeVerifyTime
+ * variable has a range between 1 and 128 ms inclusive. Limit to that.
+ */
+ state->max_verify_time = ETHTOOL_MM_MAX_VERIFY_TIME_MS;
+
+ return 0;
+}
+
+static int emac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg,
+ struct netlink_ext_ack *extack)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ u32 old_verify_time_ms, old_tx_min_frag_size;
+ bool old_fpe_enabled, old_mac_verify_configure;
+ int err;
+
+ if (emac->is_sr1)
+ return -EOPNOTSUPP;
+
+ if (!cfg->pmac_enabled) {
+ NL_SET_ERR_MSG_MOD(extack, "preemptible MAC is always enabled");
+ return -EOPNOTSUPP;
+ }
+
+ mutex_lock(&iet->fpe_lock);
+ old_verify_time_ms = iet->verify_time_ms;
+ old_tx_min_frag_size = iet->tx_min_frag_size;
+ old_fpe_enabled = iet->fpe_enabled;
+ old_mac_verify_configure = iet->mac_verify_configure;
+
+ iet->verify_time_ms = cfg->verify_time;
+ iet->tx_min_frag_size = cfg->tx_min_frag_size;
+ iet->fpe_enabled = cfg->tx_enabled;
+ iet->mac_verify_configure = cfg->verify_enabled;
+ err = icssg_config_ietfpe(ndev, cfg->tx_enabled);
+ if (err) {
+ /* icssg_config_ietfpe's fallback path already cleared fpe_active.
+ * Restore all config fields so get_mm() reports the configuration
+ * that is actually reflected in hardware.
+ */
+ iet->verify_time_ms = old_verify_time_ms;
+ iet->tx_min_frag_size = old_tx_min_frag_size;
+ iet->fpe_enabled = old_fpe_enabled;
+ iet->mac_verify_configure = old_mac_verify_configure;
+ }
+ mutex_unlock(&iet->fpe_lock);
+
+ return err;
+}
+
+static void emac_get_mm_stats(struct net_device *ndev,
+ struct ethtool_mm_stats *s)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+
+ if (emac->is_sr1)
+ return;
+
+ if (!emac->prueth->pa_stats)
+ return;
+
+ emac_update_hardware_stats(emac);
+
+ /* Hold stats_lock to prevent icssg_stats_work_handler from updating
+ * pa_stats[] between reads, which could yield a torn u64 value on
+ * 32-bit architectures.
+ */
+ spin_lock(&emac->prueth->stats_lock);
+ /* MACMergeHoldCount stats is not tracked by the firmware */
+ s->MACMergeFrameAssOkCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_OK");
+ s->MACMergeFrameAssErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_ASSEMBLY_ERR");
+ s->MACMergeFragCountRx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_RX");
+ s->MACMergeFragCountTx = emac_get_stat_by_name(emac, "FW_PREEMPT_FRAG_CNT_TX");
+ s->MACMergeFrameSmdErrorCount = emac_get_stat_by_name(emac, "FW_PREEMPT_BAD_FRAG");
+ spin_unlock(&emac->prueth->stats_lock);
+}
+
const struct ethtool_ops icssg_ethtool_ops = {
.get_drvinfo = emac_get_drvinfo,
.get_msglevel = emac_get_msglevel,
@@ -317,5 +440,8 @@ const struct ethtool_ops icssg_ethtool_ops = {
.set_eee = emac_set_eee,
.nway_reset = emac_nway_reset,
.get_rmon_stats = emac_get_rmon_stats,
+ .get_mm = emac_get_mm,
+ .set_mm = emac_set_mm,
+ .get_mm_stats = emac_get_mm_stats,
};
EXPORT_SYMBOL_GPL(icssg_ethtool_ops);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 591be5c8056b4..283be27a240e9 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -357,11 +357,11 @@ static void emac_adjust_link(struct net_device *ndev)
}
if (!emac->link) {
new_state = true;
- emac->link = 1;
+ WRITE_ONCE(emac->link, 1);
}
} else if (emac->link) {
new_state = true;
- emac->link = 0;
+ WRITE_ONCE(emac->link, 0);
/* f/w should support 100 & 1000 */
emac->speed = SPEED_1000;
@@ -392,6 +392,8 @@ static void emac_adjust_link(struct net_device *ndev)
} else {
icssg_set_port_state(emac, ICSSG_EMAC_PORT_DISABLE);
}
+
+ icssg_qos_link_state_update(ndev);
}
if (emac->link) {
@@ -1652,6 +1654,7 @@ static const struct net_device_ops emac_netdev_ops = {
.ndo_hwtstamp_get = icssg_ndo_get_ts_config,
.ndo_hwtstamp_set = icssg_ndo_set_ts_config,
.ndo_xsk_wakeup = prueth_xsk_wakeup,
+ .ndo_setup_tc = icssg_qos_ndo_setup_tc,
};
static int prueth_netdev_init(struct prueth *prueth,
@@ -1686,6 +1689,8 @@ static int prueth_netdev_init(struct prueth *prueth,
INIT_DELAYED_WORK(&emac->stats_work, icssg_stats_work_handler);
+ icssg_qos_init(ndev);
+
ret = pruss_request_mem_region(prueth->pruss,
port == PRUETH_PORT_MII0 ?
PRUSS_MEM_DRAM0 : PRUSS_MEM_DRAM1,
@@ -1793,6 +1798,7 @@ static int prueth_netdev_init(struct prueth *prueth,
free:
pruss_release_mem_region(prueth->pruss, &emac->dram);
free_ndev:
+ mutex_destroy(&emac->qos.iet.fpe_lock);
emac->ndev = NULL;
prueth->emac[mac] = NULL;
free_netdev(ndev);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index df93d15c5b786..ad9061408050e 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -44,10 +44,12 @@
#include "icssg_config.h"
#include "icss_iep.h"
#include "icssg_switch_map.h"
+#include "icssg_qos.h"
+#include "icssg_stats.h"
-#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN)
-#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN)
-#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN)
+#define PRUETH_MAX_MTU (2000 - ETH_HLEN - ETH_FCS_LEN)
+#define PRUETH_MIN_PKT_SIZE (VLAN_ETH_ZLEN)
+#define PRUETH_MAX_PKT_SIZE (PRUETH_MAX_MTU + ETH_HLEN + ETH_FCS_LEN)
#define ICSS_SLICE0 0
#define ICSS_SLICE1 1
@@ -57,12 +59,16 @@
#define ICSSG_MAX_RFLOWS 8 /* per slice */
-#define ICSSG_NUM_PA_STATS 32
-#define ICSSG_NUM_MIIG_STATS 60
+#define ICSSG_NUM_PA_STATS ARRAY_SIZE(icssg_all_pa_stats)
+#define ICSSG_NUM_MIIG_STATS ARRAY_SIZE(icssg_all_miig_stats)
/* Number of ICSSG related stats */
#define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
+/* MIIG stats with standard uAPI equivalents (excluded from ethtool -S) */
#define ICSSG_NUM_STANDARD_STATS 31
-#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
+/* PA stats with standard uAPI equivalents, exposed via get_mm_stats only */
+#define ICSSG_NUM_PA_STANDARD_STATS 5
+#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS - \
+ ICSSG_NUM_PA_STANDARD_STATS)
#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */
@@ -254,6 +260,7 @@ struct prueth_emac {
struct bpf_prog *xdp_prog;
struct xdp_attachment_info xdpi;
int xsk_qid;
+ struct prueth_qos qos;
};
/* The buf includes headroom compatible with both skb and xdpf */
@@ -458,7 +465,7 @@ int emac_fdb_flow_id_updated(struct prueth_emac *emac);
void icssg_stats_work_handler(struct work_struct *work);
void emac_update_hardware_stats(struct prueth_emac *emac);
-int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);
+u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name);
/* Common functions */
void prueth_cleanup_rx_chns(struct prueth_emac *emac,
diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.c b/drivers/net/ethernet/ti/icssg/icssg_qos.c
new file mode 100644
index 0000000000000..27a953d981538
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_qos.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Texas Instruments ICSSG PRUETH QoS submodule
+ * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#include "icssg_prueth.h"
+#include "icssg_switch_map.h"
+
+static void icssg_iet_set_preempt_mask(struct prueth_emac *emac)
+{
+ void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
+ struct prueth_qos_mqprio *p_mqprio = &emac->qos.mqprio;
+ struct tc_mqprio_qopt *qopt = &p_mqprio->qopt;
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ int prempt_mask = 0, i;
+ u8 tc, num_tc;
+
+ if (!iet->preemptible_tcs)
+ goto reset_hw;
+
+ if (iet->fpe_active) {
+ /* Reset all Q_MAP entries first to clear any stale preemptible
+ * entries from a prior wider TC mapping.
+ */
+ for (i = 0; i < ICSSG_MAX_TC_QUEUES; i++)
+ writeb(0, config + EXPRESS_PRE_EMPTIVE_Q_MAP + i);
+
+ /* Configure queues for user requested preemptible tc map */
+ num_tc = p_mqprio->qopt.num_tc;
+ for (tc = 0; tc < num_tc; tc++) {
+ /* check if the tc is preemptive or not */
+ if (iet->preemptible_tcs & BIT(tc)) {
+ /* Set the queues as preemptive queues */
+ for (i = qopt->offset[tc]; i < qopt->offset[tc] + qopt->count[tc]; i++) {
+ writeb(BIT(4),
+ config + EXPRESS_PRE_EMPTIVE_Q_MAP + i);
+ }
+ } else {
+ /* Accumulate express queue bits for the mask */
+ for (i = qopt->offset[tc]; i < qopt->offset[tc] + qopt->count[tc]; i++)
+ prempt_mask |= BIT(i);
+ }
+ }
+ writeb(prempt_mask, config + EXPRESS_PRE_EMPTIVE_Q_MASK);
+ return;
+ }
+
+reset_hw:
+ /* Reset to default: all queues as express */
+ for (i = 0; i < ICSSG_MAX_TC_QUEUES; i++)
+ writeb(0, config + EXPRESS_PRE_EMPTIVE_Q_MAP + i);
+ writeb(ICSSG_EXPRESS_Q_MASK_ALL, config + EXPRESS_PRE_EMPTIVE_Q_MASK);
+}
+
+static int icssg_iet_verify_wait(struct prueth_emac *emac)
+{
+ void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ unsigned long delay_us, timeout_us;
+ u32 status;
+ int ret;
+
+ delay_us = iet->verify_time_ms * 1000;
+ timeout_us = delay_us * ICSSG_IET_VERIFY_ATTEMPTS;
+
+ ret = readb_poll_timeout(config + PRE_EMPTION_VERIFY_STATUS,
+ status,
+ status == ICSSG_IETFPE_STATE_SUCCEEDED ||
+ status == ICSSG_IETFPE_STATE_FAILED,
+ delay_us,
+ timeout_us);
+
+ iet->verify_status = status;
+ if (!ret && status == ICSSG_IETFPE_STATE_FAILED)
+ return -EIO;
+ return ret;
+}
+
+/* Direct synchronous configuration of IET FPE.
+ * Caller must hold iet->fpe_lock.
+ */
+int icssg_config_ietfpe(struct net_device *ndev, bool enable)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ void __iomem *config = emac->dram.va + ICSSG_CONFIG_OFFSET;
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ int ret;
+ u8 val;
+
+ lockdep_assert_held(&iet->fpe_lock);
+
+ if (!READ_ONCE(emac->link)) {
+ netdev_dbg(ndev, "cannot change IET/FPE state when interface is down\n");
+ return 0;
+ }
+
+ /* Update FPE Tx enable bit (PRE_EMPTION_ENABLE_TX) if
+ * fpe_enabled is set to enable MM in Tx direction
+ */
+ writeb(enable ? 1 : 0, config + PRE_EMPTION_ENABLE_TX);
+ writew(iet->tx_min_frag_size + ETH_FCS_LEN,
+ config + PRE_EMPTION_ADD_FRAG_SIZE_LOCAL);
+
+ /* If FPE is to be enabled, first configure MAC Verify state
+ * machine in firmware as firmware kicks the Verify process
+ * as soon as ICSSG_EMAC_PORT_PREMPT_TX_ENABLE command is
+ * received.
+ */
+ if (enable && iet->mac_verify_configure) {
+ writeb(1, config + PRE_EMPTION_ENABLE_VERIFY);
+ writel(iet->verify_time_ms, config + PRE_EMPTION_VERIFY_TIME);
+ } else {
+ writeb(0, config + PRE_EMPTION_ENABLE_VERIFY);
+ iet->verify_status = ICSSG_IETFPE_STATE_DISABLED;
+ }
+
+ /* Send command to enable FPE Tx side. Rx is always enabled */
+ ret = icssg_set_port_state(emac,
+ enable ? ICSSG_EMAC_PORT_PREMPT_TX_ENABLE :
+ ICSSG_EMAC_PORT_PREMPT_TX_DISABLE);
+ if (ret) {
+ netdev_err(ndev, "TX preempt %s command failed\n",
+ str_enable_disable(enable));
+ goto fallback;
+ }
+
+ if (enable && iet->mac_verify_configure) {
+ ret = icssg_iet_verify_wait(emac);
+ if (ret) {
+ netdev_err(ndev, "MAC Merge verification failed: %s\n",
+ iet->verify_status == ICSSG_IETFPE_STATE_FAILED ?
+ "link partner rejected" : "timeout");
+ goto disable_tx;
+ }
+ } else if (enable) {
+ /* Give firmware some time to update
+ * PRE_EMPTION_ACTIVE_TX state
+ */
+ usleep_range(100, 200);
+ }
+
+ if (enable) {
+ val = readb(config + PRE_EMPTION_ACTIVE_TX);
+ if (val != 1) {
+ netdev_err(ndev,
+ "Firmware fails to activate IET/FPE\n");
+ ret = -EIO;
+ goto disable_tx;
+ }
+ iet->fpe_active = true;
+ } else {
+ iet->fpe_active = false;
+ }
+
+ icssg_iet_set_preempt_mask(emac);
+ netdev_dbg(ndev, "IET FPE %s successfully\n",
+ str_enable_disable(enable));
+ return 0;
+
+disable_tx:
+ icssg_set_port_state(emac, ICSSG_EMAC_PORT_PREMPT_TX_DISABLE);
+fallback:
+ writeb(0, config + PRE_EMPTION_ENABLE_TX);
+ writeb(0, config + PRE_EMPTION_ENABLE_VERIFY);
+ iet->verify_status = ICSSG_IETFPE_STATE_DISABLED;
+ iet->fpe_active = false;
+ icssg_iet_set_preempt_mask(emac);
+ return ret;
+}
+
+void icssg_qos_init(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+
+ mutex_init(&iet->fpe_lock);
+ /* Set default values to prevent garbage values during .get_mm() */
+ iet->verify_time_ms = ICSSG_IET_MAX_VERIFY_TIME;
+ iet->tx_min_frag_size = ETH_ZLEN;
+}
+EXPORT_SYMBOL_GPL(icssg_qos_init);
+
+static int icssg_iet_change_preemptible_tcs(struct prueth_emac *emac)
+{
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ int ret;
+
+ mutex_lock(&iet->fpe_lock);
+ if (!iet->fpe_enabled && !iet->preemptible_tcs) {
+ mutex_unlock(&iet->fpe_lock);
+ return 0;
+ }
+ ret = icssg_config_ietfpe(emac->ndev, iet->fpe_enabled);
+ mutex_unlock(&iet->fpe_lock);
+
+ return ret;
+}
+
+static int emac_tc_query_caps(struct net_device *ndev, void *type_data)
+{
+ struct tc_query_caps_base *base = type_data;
+
+ switch (base->type) {
+ case TC_SETUP_QDISC_MQPRIO: {
+ struct tc_mqprio_caps *caps = base->caps;
+
+ caps->validate_queue_counts = true;
+ return 0;
+ }
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int emac_tc_setup_mqprio(struct net_device *ndev, void *type_data)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth_qos_mqprio *p_mqprio = &emac->qos.mqprio;
+ struct tc_mqprio_qopt_offload *mqprio = type_data;
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ struct tc_mqprio_qopt *qopt = &mqprio->qopt;
+ int tc, offset, count;
+
+ /* Validate parameters */
+ if (qopt->num_tc > ICSSG_MAX_TC_QUEUES) {
+ netdev_err(ndev, "Number of traffic classes (%u) exceeds hardware limit\n",
+ qopt->num_tc);
+ return -EOPNOTSUPP;
+ }
+
+ if (mqprio->flags & TC_MQPRIO_F_SHAPER) {
+ netdev_err(ndev, "traffic shaping is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (mqprio->flags & (TC_MQPRIO_F_MIN_RATE | TC_MQPRIO_F_MAX_RATE)) {
+ netdev_err(ndev, "per-queue rate limiting is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (!qopt->num_tc) {
+ netdev_reset_tc(ndev);
+ } else {
+ netdev_set_num_tc(ndev, qopt->num_tc);
+
+ for (tc = 0; tc < qopt->num_tc; tc++) {
+ count = qopt->count[tc];
+ offset = qopt->offset[tc];
+ netdev_set_tc_queue(ndev, tc, count, offset);
+ }
+ }
+
+ mutex_lock(&iet->fpe_lock);
+ if (!qopt->num_tc) {
+ iet->preemptible_tcs = 0;
+ } else {
+ memcpy(&p_mqprio->qopt, qopt, sizeof(*qopt));
+ iet->preemptible_tcs = mqprio->preemptible_tcs;
+ }
+ mutex_unlock(&iet->fpe_lock);
+
+ netdev_dbg(ndev, "dev->num_tc %u dev->real_num_tx_queues %u\n",
+ ndev->num_tc, ndev->real_num_tx_queues);
+
+ return icssg_iet_change_preemptible_tcs(emac);
+}
+
+int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void *type_data)
+{
+ switch (type) {
+ case TC_QUERY_CAPS:
+ return emac_tc_query_caps(ndev, type_data);
+ case TC_SETUP_QDISC_MQPRIO:
+ return emac_tc_setup_mqprio(ndev, type_data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+EXPORT_SYMBOL_GPL(icssg_qos_ndo_setup_tc);
+
+void icssg_qos_link_state_update(struct net_device *ndev)
+{
+ struct prueth_emac *emac = netdev_priv(ndev);
+ struct prueth_qos_iet *iet = &emac->qos.iet;
+ int ret;
+
+ if (!READ_ONCE(emac->link)) {
+ /* Clear FPE active state on link-down so get_mm() reports
+ * accurate tx_active and verify_status while link is down.
+ */
+ mutex_lock(&iet->fpe_lock);
+ iet->fpe_active = false;
+ iet->verify_status = ICSSG_IETFPE_STATE_DISABLED;
+ icssg_iet_set_preempt_mask(emac);
+ mutex_unlock(&iet->fpe_lock);
+ return;
+ }
+
+ ret = icssg_iet_change_preemptible_tcs(emac);
+ if (ret)
+ netdev_dbg(ndev, "IET FPE %s failed\n",
+ str_enable_disable(iet->fpe_enabled));
+}
+EXPORT_SYMBOL_GPL(icssg_qos_link_state_update);
diff --git a/drivers/net/ethernet/ti/icssg/icssg_qos.h b/drivers/net/ethernet/ti/icssg/icssg_qos.h
new file mode 100644
index 0000000000000..e826ce4bcfd96
--- /dev/null
+++ b/drivers/net/ethernet/ti/icssg/icssg_qos.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+#ifndef __NET_TI_ICSSG_QOS_H
+#define __NET_TI_ICSSG_QOS_H
+
+#include <linux/atomic.h>
+#include <linux/netdevice.h>
+#include <net/pkt_sched.h>
+
+#define ICSSG_MAX_TC_QUEUES 8
+#define ICSSG_EXPRESS_Q_MASK_ALL 0xFF
+#define ICSSG_IET_MAX_VERIFY_TIME 128
+#define ICSSG_IET_MIN_VERIFY_TIME 1
+#define ICSSG_IET_VERIFY_ATTEMPTS 3
+
+/**
+ * enum icssg_ietfpe_verify_states - status of MM Verify returned by firmware
+ * @ICSSG_IETFPE_STATE_UNKNOWN:
+ * verification status is unknown
+ * @ICSSG_IETFPE_STATE_INITIAL:
+ * Firmware returns this if verify state diagram is idle
+ * @ICSSG_IETFPE_STATE_VERIFYING:
+ * Firmware returns this if verification is ongoing
+ * @ICSSG_IETFPE_STATE_SUCCEEDED:
+ * Firmware returns this if verify state diagram completes verification
+ * @ICSSG_IETFPE_STATE_FAILED:
+ * Firmware returns this if verify state diagram fails during verification
+ * @ICSSG_IETFPE_STATE_DISABLED:
+ * verification is disabled by the driver
+ */
+enum icssg_ietfpe_verify_states {
+ ICSSG_IETFPE_STATE_UNKNOWN = 0,
+ ICSSG_IETFPE_STATE_INITIAL,
+ ICSSG_IETFPE_STATE_VERIFYING,
+ ICSSG_IETFPE_STATE_SUCCEEDED,
+ ICSSG_IETFPE_STATE_FAILED,
+ ICSSG_IETFPE_STATE_DISABLED
+};
+
+struct prueth_qos_mqprio {
+ struct tc_mqprio_qopt qopt;
+};
+
+struct prueth_qos_iet {
+ bool fpe_enabled;
+ bool mac_verify_configure;
+ u32 tx_min_frag_size;
+ u32 verify_time_ms;
+ bool fpe_active;
+ enum icssg_ietfpe_verify_states verify_status;
+ /* fpe mutex protects all FPE operations for synchronization */
+ struct mutex fpe_lock;
+ u8 preemptible_tcs;
+};
+
+struct prueth_qos {
+ struct prueth_qos_iet iet;
+ struct prueth_qos_mqprio mqprio;
+};
+
+void icssg_qos_init(struct net_device *ndev);
+void icssg_qos_link_state_update(struct net_device *ndev);
+int icssg_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
+ void *type_data);
+int icssg_config_ietfpe(struct net_device *ndev, bool enable);
+#endif /* __NET_TI_ICSSG_QOS_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
index 7159baa0155cf..cfdb6f5dc5da1 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -74,7 +74,7 @@ void icssg_stats_work_handler(struct work_struct *work)
}
EXPORT_SYMBOL_GPL(icssg_stats_work_handler);
-int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
+u64 emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
{
int i;
@@ -91,5 +91,5 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
}
netdev_err(emac->ndev, "Invalid stats %s\n", stat_name);
- return -EINVAL;
+ return 0;
}
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index 5ec0b38e0c67d..b86da8da23a18 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -8,8 +8,6 @@
#ifndef __NET_TI_ICSSG_STATS_H
#define __NET_TI_ICSSG_STATS_H
-#include "icssg_prueth.h"
-
#define STATS_TIME_LIMIT_1G_MS 25000 /* 25 seconds @ 1G */
struct miig_stats_regs {
@@ -155,50 +153,60 @@ static const struct icssg_miig_stats icssg_all_miig_stats[] = {
ICSSG_MIIG_STATS(tx_bytes, true),
};
-#define ICSSG_PA_STATS(field) \
-{ \
- #field, \
- field, \
+#define ICSSG_PA_STATS(field, std) \
+{ \
+ #field, \
+ field, \
+ std, \
}
struct icssg_pa_stats {
char name[ETH_GSTRING_LEN];
u32 offset;
+ bool standard_stats;
};
static const struct icssg_pa_stats icssg_all_pa_stats[] = {
- ICSSG_PA_STATS(FW_RTU_PKT_DROP),
- ICSSG_PA_STATS(FW_Q0_OVERFLOW),
- ICSSG_PA_STATS(FW_Q1_OVERFLOW),
- ICSSG_PA_STATS(FW_Q2_OVERFLOW),
- ICSSG_PA_STATS(FW_Q3_OVERFLOW),
- ICSSG_PA_STATS(FW_Q4_OVERFLOW),
- ICSSG_PA_STATS(FW_Q5_OVERFLOW),
- ICSSG_PA_STATS(FW_Q6_OVERFLOW),
- ICSSG_PA_STATS(FW_Q7_OVERFLOW),
- ICSSG_PA_STATS(FW_DROPPED_PKT),
- ICSSG_PA_STATS(FW_RX_ERROR),
- ICSSG_PA_STATS(FW_RX_DS_INVALID),
- ICSSG_PA_STATS(FW_TX_DROPPED_PACKET),
- ICSSG_PA_STATS(FW_TX_TS_DROPPED_PACKET),
- ICSSG_PA_STATS(FW_INF_PORT_DISABLED),
- ICSSG_PA_STATS(FW_INF_SAV),
- ICSSG_PA_STATS(FW_INF_SA_DL),
- ICSSG_PA_STATS(FW_INF_PORT_BLOCKED),
- ICSSG_PA_STATS(FW_INF_DROP_TAGGED),
- ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED),
- ICSSG_PA_STATS(FW_INF_DROP_NOTAG),
- ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER),
- ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR),
- ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF),
- ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF),
- ICSSG_PA_STATS(FW_RX_EXP_FRAG_Q_DROP),
- ICSSG_PA_STATS(FW_RX_FIFO_OVERRUN),
- ICSSG_PA_STATS(FW_CUT_THR_PKT),
- ICSSG_PA_STATS(FW_HOST_RX_PKT_CNT),
- ICSSG_PA_STATS(FW_HOST_TX_PKT_CNT),
- ICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW),
- ICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW),
+ ICSSG_PA_STATS(FW_RTU_PKT_DROP, false),
+ ICSSG_PA_STATS(FW_Q0_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q1_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q2_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q3_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q4_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q5_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q6_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_Q7_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_DROPPED_PKT, false),
+ ICSSG_PA_STATS(FW_RX_ERROR, false),
+ ICSSG_PA_STATS(FW_RX_DS_INVALID, false),
+ ICSSG_PA_STATS(FW_TX_DROPPED_PACKET, false),
+ ICSSG_PA_STATS(FW_TX_TS_DROPPED_PACKET, false),
+ ICSSG_PA_STATS(FW_INF_PORT_DISABLED, false),
+ ICSSG_PA_STATS(FW_INF_SAV, false),
+ ICSSG_PA_STATS(FW_INF_SA_DL, false),
+ ICSSG_PA_STATS(FW_INF_PORT_BLOCKED, false),
+ ICSSG_PA_STATS(FW_INF_DROP_TAGGED, false),
+ ICSSG_PA_STATS(FW_INF_DROP_PRIOTAGGED, false),
+ ICSSG_PA_STATS(FW_INF_DROP_NOTAG, false),
+ ICSSG_PA_STATS(FW_INF_DROP_NOTMEMBER, false),
+ /* MAC Merge counters: exposed via .get_mm_stats standard uAPI,
+ * not duplicated in the private ethtool -S table.
+ */
+ ICSSG_PA_STATS(FW_PREEMPT_BAD_FRAG, true),
+ ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_ERR, true),
+ ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_TX, true),
+ ICSSG_PA_STATS(FW_PREEMPT_ASSEMBLY_OK, true),
+ ICSSG_PA_STATS(FW_PREEMPT_FRAG_CNT_RX, true),
+ ICSSG_PA_STATS(FW_RX_EOF_SHORT_FRMERR, false),
+ ICSSG_PA_STATS(FW_RX_B0_DROP_EARLY_EOF, false),
+ ICSSG_PA_STATS(FW_TX_JUMBO_FRM_CUTOFF, false),
+ ICSSG_PA_STATS(FW_RX_EXP_FRAG_Q_DROP, false),
+ ICSSG_PA_STATS(FW_RX_FIFO_OVERRUN, false),
+ ICSSG_PA_STATS(FW_CUT_THR_PKT, false),
+ ICSSG_PA_STATS(FW_HOST_RX_PKT_CNT, false),
+ ICSSG_PA_STATS(FW_HOST_TX_PKT_CNT, false),
+ ICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW, false),
+ ICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW, false),
};
#endif /* __NET_TI_ICSSG_STATS_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
index 7e053b8af3ece..855fd4ed0b3f6 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
@@ -256,6 +256,11 @@
#define FW_INF_DROP_PRIOTAGGED 0x0148
#define FW_INF_DROP_NOTAG 0x0150
#define FW_INF_DROP_NOTMEMBER 0x0158
+#define FW_PREEMPT_BAD_FRAG 0x0160
+#define FW_PREEMPT_ASSEMBLY_ERR 0x0168
+#define FW_PREEMPT_FRAG_CNT_TX 0x0170
+#define FW_PREEMPT_ASSEMBLY_OK 0x0178
+#define FW_PREEMPT_FRAG_CNT_RX 0x0180
#define FW_RX_EOF_SHORT_FRMERR 0x0188
#define FW_RX_B0_DROP_EARLY_EOF 0x0190
#define FW_TX_JUMBO_FRM_CUTOFF 0x0198
|
| 3/2 | 2026/09/15 07:10 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 15505 output: 36 thoughts: 398 Thoughts: **Initial Assessment of the ICSSG Patch Series** Okay, so this patch series is digging into the `drivers/net/ethernet/ti/icssg/` directory. That's a good place to start, given my expertise in this area. Specifically, it's hitting the `Makefile`, common code, the config header, and then a slew of files related to ethtool, PRU Ethernet (which is *very* interesting), QoS, statistics, and switch mapping. My immediate thought is, "Right, let's see what TI's ICSSG is all about." Is it a commonly used or well-understood block? Can I reproduce this in my lab? The target architecture is amd64, that is good, so I will have to ensure that my environment is amd64 compatible. This means I'll need to think about standard virtualized environments – like QEMU or syzkaller – to see if I can even *access* the relevant hardware or emulate it for testing and debugging. Right, ICSSG... let's jog my memory. Ah, yes! "Texas Instruments ICSSG PRUETH." That's the PRU Ethernet Gigabit subsystem on TI Sitara and Jacinto SoCs, like the AM654x or AM64x. Now, it's becoming more clear. Next step will be digging into the Kconfig to understand the broader context. |
| 4/2 | 2026/09/15 07:10 | tool | grepper |
0mArgs:{
"Expression": "TI_ICSSG_PRUETH",
"PathPrefix": "drivers/net/ethernet/ti"
}Results: {
"Output": "drivers/net/ethernet/ti/Kconfig=169=config TLAN\n--\ndrivers/net/ethernet/ti/Kconfig-185-\ndrivers/net/ethernet/ti/Kconfig:186:config TI_ICSSG_PRUETH\ndrivers/net/ethernet/ti/Kconfig-187-\ttristate \"TI Gigabit PRU Ethernet driver\"\n--\ndrivers/net/ethernet/ti/Kconfig-203-\ndrivers/net/ethernet/ti/Kconfig:204:config TI_ICSSG_PRUETH_SR1\ndrivers/net/ethernet/ti/Kconfig-205-\ttristate \"TI Gigabit PRU SR1.0 Ethernet driver\"\n--\ndrivers/net/ethernet/ti/Makefile=35=obj-$(CONFIG_TI_K3_AM65_CPTS) += am65-cpts.o\ndrivers/net/ethernet/ti/Makefile-36-\ndrivers/net/ethernet/ti/Makefile:37:obj-$(CONFIG_TI_ICSSG_PRUETH) += icssg-prueth.o icssg.o\ndrivers/net/ethernet/ti/Makefile-38-icssg-prueth-y := icssg/icssg_prueth.o icssg/icssg_switchdev.o\ndrivers/net/ethernet/ti/Makefile-39-\ndrivers/net/ethernet/ti/Makefile:40:obj-$(CONFIG_TI_ICSSG_PRUETH_SR1) += icssg-prueth-sr1.o icssg.o\ndrivers/net/ethernet/ti/Makefile-41-icssg-prueth-sr1-y := icssg/icssg_prueth_sr1.o\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h-7-\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h:8:#ifndef __NET_TI_ICSSG_PRUETH_H\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h:9:#define __NET_TI_ICSSG_PRUETH_H\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h-10-\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h=529=static inline bool prueth_xdp_is_enabled(struct prueth_emac *emac)\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h-533-\ndrivers/net/ethernet/ti/icssg/icssg_prueth.h:534:#endif /* __NET_TI_ICSSG_PRUETH_H */\n"
} |
| 5/2 | 2026/09/15 07:10 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 16949 output: 39 thoughts: 24 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Examining the TI Ethernet Driver Configuration** Okay, so I'm diving into the TI Ethernet driver configuration, specifically at `drivers/net/ethernet/ti/Kconfig`, around line 186. My initial hunch is that something interesting is happening there, likely related to a feature gate, dependency check, or a configuration option that's causing me some head-scratching. I'm probably looking for the condition that enables or disables some functionality, perhaps related to a specific hardware variant, power management feature, or a debug setting. The line number suggests it could be a dependency on another component. Alternatively, it could be a complex nested `if` structure controlling multiple options. Time to dig in and see what's actually going on. I'm expecting to either find the root of an issue, or simply understand how a particular feature is enabled in this driver. |
| 6/2 | 2026/09/15 07:10 | tool | read-file |
0mArgs:{
"File": "drivers/net/ethernet/ti/Kconfig",
"FirstLine": 180,
"LineCount": 40
}Results: {
"Contents": " 180:\t\n 181:\t\t To compile this driver as a module, choose M here. The module\n 182:\t\t will be called tlan.\n 183:\t\n 184:\t\t Please email feedback to \u003ctorben.mathiasen@compaq.com\u003e.\n 185:\t\n 186:\tconfig TI_ICSSG_PRUETH\n 187:\t\ttristate \"TI Gigabit PRU Ethernet driver\"\n 188:\t\tselect PHYLIB\n 189:\t\tselect TI_ICSS_IEP\n 190:\t\tselect TI_K3_CPPI_DESC_POOL\n 191:\t\tdepends on PRU_REMOTEPROC\n 192:\t\tdepends on NET_SWITCHDEV\n 193:\t\tdepends on ARCH_K3 \u0026\u0026 OF \u0026\u0026 TI_K3_UDMA_GLUE_LAYER\n 194:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n 195:\t\tdepends on HSR || !HSR\n 196:\t\thelp\n 197:\t\t Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.\n 198:\t\t This subsystem is available starting with the AM65 platform.\n 199:\t\n 200:\t\t This driver requires firmware binaries which will run on the PRUs\n 201:\t\t to support the Ethernet operation. Currently, it supports Ethernet\n 202:\t\t with 1G and 100M link speed.\n 203:\t\n 204:\tconfig TI_ICSSG_PRUETH_SR1\n 205:\t\ttristate \"TI Gigabit PRU SR1.0 Ethernet driver\"\n 206:\t\tselect PHYLIB\n 207:\t\tselect TI_ICSS_IEP\n 208:\t\tselect TI_K3_CPPI_DESC_POOL\n 209:\t\tselect PAGE_POOL\n 210:\t\tdepends on PRU_REMOTEPROC\n 211:\t\tdepends on NET_SWITCHDEV\n 212:\t\tdepends on ARCH_K3 \u0026\u0026 OF \u0026\u0026 TI_K3_UDMA_GLUE_LAYER\n 213:\t\tdepends on PTP_1588_CLOCK_OPTIONAL\n 214:\t\thelp\n 215:\t\t Support dual Gigabit Ethernet ports over the ICSSG PRU Subsystem.\n 216:\t\t This subsystem is available on the AM65 SR1.0 platform.\n 217:\t\n 218:\t\t This driver requires firmware binaries which will run on the PRUs\n 219:\t\t to support the Ethernet operation. Currently, it supports Ethernet\n"
} |
| 7/2 | 2026/09/15 07:10 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 17873 output: 19 thoughts: 74 Thoughts: **Examining the Kernel Configuration** Okay, here we go. I see this configuration option, `config TI_ICSSG_PRUETH`, and immediately my expert eye scans for the dependencies. `depends on ARCH_K3 && OF && TI_K3_UDMA_GLUE_LAYER` and `depends on PRU_REMOTEPROC`. Ah, `ARCH_K3`...that's the key. I recognize most of those but I need to quickly refresh my memory on what `ARCH_K3` signifies in this context. It always helps to know the architecture before I make any decisions about its configuration. Let's trace this and see exactly where `ARCH_K3` is defined to get the full picture. Time to dive into the codebase and get some clarity. |
| 8/2 | 2026/09/15 07:10 | tool | grepper |
0mArgs:{
"Expression": "config ARCH_K3"
}Results: {
"Output": "arch/arm64/Kconfig.platforms=143=config ARCH_EXYNOS\n--\narch/arm64/Kconfig.platforms-155-\narch/arm64/Kconfig.platforms:156:config ARCH_K3\narch/arm64/Kconfig.platforms-157-\tbool \"Texas Instruments Inc. K3 multicore SoC architecture\"\n"
} |
| 9/2 | 2026/09/15 07:10 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 18236 output: 37 thoughts: 590 Thoughts: **My Analysis of the `ARCH_K3` and `TI_ICSSG_PRUETH` Modules for Fuzzing Eligibility** Okay, so `ARCH_K3` is clearly an ARM64 specific SoC architecture, specifically from Texas Instruments. I confirmed this by finding it defined in `arch/arm64/Kconfig.platforms`. My target architecture, however, is amd64. Therefore, I need to check if these modules are even remotely buildable or relevant to an amd64 environment. The negative criteria state I should return `WorthFuzzing=false` if the code falls into several categories, including "Code paths exclusive to architectures other than the target architecture" and "Structurally unreachable hardware." Let's see if either `ARCH_K3` or `TI_ICSSG_PRUETH` can be enabled or even compiled on amd64. It's quickly apparent that `ARCH_K3` is strictly tied to `arch/arm64` through the `Kconfig.platforms` file. That's a strong indicator. Now for `TI_ICSSG_PRUETH`. I looked at `drivers/net/ethernet/ti/Kconfig` to determine if there's any conditional compilation. As expected, `TI_ICSSG_PRUETH` depends on `ARCH_K3` and several other ARM64 and TI-specific dependencies. Importantly, I did *not* find `|| COMPILE_TEST`, which would have provided a path for building this driver for testing purposes even if the hardware isn't present. Furthermore, this driver is explicitly a platform driver for a TI K3 SoC PRU Ethernet controller. It's designed to interface with the Programmable Real-Time Unit (PRU) hardware present on TI K3 SoCs. To be extra certain, I need to verify that its probe function is tied to a platform device, likely within the `icssg_prueth.c` driver source itself. I'll need to confirm that it's tightly coupled to the underlying hardware. Since this is an Ethernet controller, it needs to be connected, and that isn't connected to a regular amd64 system. Therefore, because this code is exclusive to the ARM64 architecture and specific hardware, and not buildable, I'm confident in concluding that it's structurally unreachable in my amd64 environment. I should return `WorthFuzzing=false`. |
| 10/2 | 2026/09/15 07:11 | tool | grepper |
0mArgs:{
"Expression": "module_platform_driver",
"PathPrefix": "drivers/net/ethernet/ti/icssg"
}Results: {
"Output": "drivers/net/ethernet/ti/icssg/icss_iep.c=1095=static struct platform_driver icss_iep_driver = {\n--\ndrivers/net/ethernet/ti/icssg/icss_iep.c-1101-};\ndrivers/net/ethernet/ti/icssg/icss_iep.c:1102:module_platform_driver(icss_iep_driver);\ndrivers/net/ethernet/ti/icssg/icss_iep.c-1103-\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth.c=2582=static struct platform_driver prueth_driver = {\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth.c-2590-};\ndrivers/net/ethernet/ti/icssg/icssg_prueth.c:2591:module_platform_driver(prueth_driver);\ndrivers/net/ethernet/ti/icssg/icssg_prueth.c-2592-\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c=1228=static struct platform_driver prueth_driver = {\n--\ndrivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c-1236-};\ndrivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c:1237:module_platform_driver(prueth_driver);\ndrivers/net/ethernet/ti/icssg/icssg_prueth_sr1.c-1238-\n"
} |
| 11/2 | 2026/09/15 07:11 | llm | patch-evaluator |
0mModel:gemini-3.8-flash Args: null Results: null Tokens: input: 19828 output: 121 thoughts: 566 Thoughts: **My Assessment of WorthFuzzing for TI_ICSSG_PRUETH** Okay, after examining the code and the context, I've determined that `TI_ICSSG_PRUETH` is definitely not worth fuzzing in our current setup. Here's my reasoning, and it's pretty straightforward: First, this is a very specific platform driver, the `prueth_driver`, designed for the TI K3 SoC's PRU ethernet subsystem. This means it intrinsically depends on TI's proprietary hardware – the PRU-ICSSG subsystem, the remoteproc framework for the PRUs, and the K3 UDMA glue logic. This is not something that can be emulated reliably, or even at all, in a standard QEMU environment, or any standard QEMU environment. QEMU simply doesn't simulate the PRU-ICSSG or K3 UDMA hardware components. Secondly, and this is the clincher, the driver has a built-in dependency on `ARCH_K3`. This is an architecture option found in the `arm64/Kconfig.platforms` file. Since we're targeting the `amd64` architecture, this driver is *structurally unreachable* on the target. It's impossible to even compile it in for the `amd64` architecture, making any fuzzing efforts completely futile. Looking at the instructions in Section 2, this clearly falls under two of the "Return WorthFuzzing=false" categories: "Structurally unreachable hardware" and "Code paths exclusive to architectures other than the target architecture." The architecture exclusivity is obvious due to the `ARCH_K3` dependency. The hardware unreachability is evident because we're talking about a platform-specific driver that needs specialized TI hardware that's not present or emulated in our target QEMU instances. Therefore, `WorthFuzzing = false`, no `EnableConfigs` are needed, and no `FocusSymbols` are relevant. Let's call `set-results`. |
| 12/2 | 2026/09/15 07:11 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The modified code is confined to the Texas Instruments ICSSG PRU Ethernet driver (drivers/net/ethernet/ti/icssg/), which depends on CONFIG_ARCH_K3 (an ARM64-specific SoC architecture). This driver is structurally unreachable on the target amd64 architecture and additionally requires physical TI K3 PRU-ICSSG SoC hardware and firmware that are not emulated in standard virtualized fuzzing environments.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The modified code is confined to the Texas Instruments ICSSG PRU Ethernet driver (drivers/net/ethernet/ti/icssg/), which depends on CONFIG_ARCH_K3 (an ARM64-specific SoC architecture). This driver is structurally unreachable on the target amd64 architecture and additionally requires physical TI K3 PRU-ICSSG SoC hardware and firmware that are not emulated in standard virtualized fuzzing environments.",
"WorthFuzzing": false
} |
| 13/1 | 2026/09/15 07:11 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|